autojanet/skills/azure-pipeline-ansible/SKILL.md
Zoë cc74ad0bd0
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
fix: use library/ Harbor project, add skills, fix pipeline secrets
- .woodpecker.yaml: image paths -> library/autojanet-{agent,dispatcher}
- .woodpecker.yaml: secret names RS_HARBOR_USER / RS_HARBOR_PASS (global)
- container/Dockerfile: restore COPY skills/, skills/ populated from opencode config
- skills/: 84 opencode skills bundled into image
- k8s/manifests: update image refs to library/
2026-05-30 15:43:14 -07:00

4.8 KiB

name description
azure-pipeline-ansible Extends azure-devops-pipeline for Ansible playbook runs. Handles syntax check, galaxy install, vault passwords, SSH key injection, check mode on nonprod, and dynamic AWS EC2 inventory. Always load azure-devops-pipeline first.

What I add

Type-specific steps for Ansible pipelines. Merge these into the skeleton from azure-devops-pipeline.

Additional required inputs — ask the user

  1. Playbook path — e.g. playbooks/site.yml
  2. Inventory sourcestatic | dynamic-aws-ec2
  3. Ansible Vault in useyes | no
  4. ADO secret variable name for vault password — if vault in use, e.g. ANSIBLE_VAULT_PASSWORD
  5. ADO secret variable name for SSH private key — e.g. ANSIBLE_SSH_KEY
  6. Ansible version to pin — e.g. 9.2.0
  7. Run --check mode on nonprod before real applyyes (default) | no

Lint stage steps

- script: |
    pip install "ansible==$(ANSIBLE_VERSION)" ansible-lint
    ansible-lint <playbook-path> --profile production    
  displayName: "Lint — ansible-lint"
  env:
    ANSIBLE_VERSION: <ansible-version>

Security scan stage steps

- script: |
    pip install "ansible==$(ANSIBLE_VERSION)" ansible-lint
    ansible-lint <playbook-path> --profile security \
      --sarif-file ansible-lint-security.sarif || true
    ansible-galaxy install -r requirements.yml --force    
  displayName: "Security scan — ansible-lint security profile"
  env:
    ANSIBLE_VERSION: <ansible-version>
- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: ansible-lint-security.sarif
    artifactName: security-scan
  displayName: "Publish scan results"

Build stage steps

- script: |
    pip install "ansible==$(ANSIBLE_VERSION)"
    [ -f requirements.yml ] && ansible-galaxy install -r requirements.yml || true
    ansible-playbook <playbook-path> --syntax-check -i <inventory-file>    
  displayName: "Validate — syntax check and galaxy install"
  env:
    ANSIBLE_VERSION: <ansible-version>

Note: for dynamic-aws-ec2 inventory, replace -i <inventory-file> with -i aws_ec2.yml and ensure aws_ec2.yml exists in the repo with the amazon.aws.aws_ec2 plugin configured.

Deploy stage steps

Step order — always emit in this order

  1. Write SSH key to temp file
  2. Write vault password to temp file (if vault in use)
  3. Check mode run (nonprod only, if enabled)
  4. Real playbook run
  5. Clean up SSH key (condition: always)
  6. Clean up vault password (condition: always)

SSH key injection (always include)

- script: |
    echo "$(ANSIBLE_SSH_KEY)" > /tmp/ansible_ssh_key
    chmod 600 /tmp/ansible_ssh_key    
  displayName: "Inject SSH key"
  env:
    ANSIBLE_SSH_KEY: $(ANSIBLE_SSH_KEY)

Vault password file (include only if vault in use)

- script: |
    echo "$(ANSIBLE_VAULT_PASSWORD)" > /tmp/vault_pass
    chmod 600 /tmp/vault_pass    
  displayName: "Write vault password file"
  env:
    ANSIBLE_VAULT_PASSWORD: $(ANSIBLE_VAULT_PASSWORD)

Check mode run (nonprod only, if enabled)

- script: |
    VAULT_ARGS=""
    [ -f /tmp/vault_pass ] && VAULT_ARGS="--vault-password-file /tmp/vault_pass"
    ansible-playbook <playbook-path> \
      -i <inventory> \
      --check \
      --diff \
      --private-key /tmp/ansible_ssh_key \
      $VAULT_ARGS    
  displayName: "Dry run — check mode"

Real run

- script: |
    VAULT_ARGS=""
    [ -f /tmp/vault_pass ] && VAULT_ARGS="--vault-password-file /tmp/vault_pass"
    ansible-playbook <playbook-path> \
      -i <inventory> \
      --diff \
      --private-key /tmp/ansible_ssh_key \
      $VAULT_ARGS    
  displayName: "Apply playbook"

Cleanup (always at end of deploy steps — condition: always())

- script: rm -f /tmp/ansible_ssh_key
  displayName: "Clean up SSH key"
  condition: always()

- script: rm -f /tmp/vault_pass
  displayName: "Clean up vault password file"
  condition: always()

Hard rules for Ansible

  • Always pin Ansible version with quoted pip specifier "ansible==$(ANSIBLE_VERSION)" — never use latest, unquoted == may fail in some shells
  • Always clean up SSH key and vault password files with condition: always() — they must be removed even if the playbook fails
  • Always include --diff on real runs so changes are visible in pipeline logs
  • SSH key file permissions must be 600 — Ansible refuses keys with broader permissions
  • Use shell variable expansion (VAULT_ARGS="") rather than subshell substitution in the step script to avoid bash syntax issues in ADO agents
  • For dynamic inventory, AWS credentials come from the OIDC service connection environment — same pattern as Lambda
  • requirements.yml must exist in the repo if galaxy install step is included; if uncertain, wrap with [ -f requirements.yml ] && ansible-galaxy install -r requirements.yml || true