autojanet/skills/azure-devops-pipeline/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

180 lines
5.6 KiB
Markdown

---
name: azure-devops-pipeline
description: Generates Azure DevOps pipeline YAML using EKS-Pool with nonprod auto-deploy and prod manual approval gate. Always load this skill first, then load the type-specific skill before generating any YAML.
---
## What I do
Guide the generation of a complete `azure-pipelines.yml` file for a self-hosted EKS-Pool Azure DevOps agent pool. I define all shared standards. You MUST also load the appropriate type skill before generating YAML:
- Lambda deployments → load `azure-pipeline-lambda`
- Ansible playbooks → load `azure-pipeline-ansible`
- Docker builds → load `azure-pipeline-docker`
## IMPORTANT — do not generate YAML without loading a type skill
STOP. Before generating any pipeline YAML, you MUST load the type skill that matches the requested pipeline type:
- `azure-pipeline-lambda` for Lambda
- `azure-pipeline-ansible` for Ansible
- `azure-pipeline-docker` for Docker
Generate nothing until that skill is loaded.
## Required inputs — ask the user for these before generating
1. **Service/repo name** — used in display names and tags
2. **Pipeline type**`lambda` | `ansible` | `docker`
3. **Target tier**`nonprod` | `prod`
4. **Trigger branch** — branch that triggers auto-deploy (default: `main`)
5. **Secret sources** — which are in use: `ADO variable groups` | `AWS SSM/Secrets Manager` | `Vault/OpenBao` (can be multiple)
6. **ADO variable group name(s)** — if ADO variable groups selected
## Pipeline skeleton — always use this structure
```yaml
trigger:
branches:
include:
- <trigger-branch>
pool: EKS-Pool
stages:
- stage: Lint
displayName: "Lint"
jobs:
- job: Lint
pool: EKS-Pool
timeoutInMinutes: 30
continueOnError: false
steps: [] # type skill fills this in
- stage: SecurityScan
displayName: "Security Scan"
dependsOn: Lint
condition: succeeded()
jobs:
- job: SecurityScan
pool: EKS-Pool
timeoutInMinutes: 30
continueOnError: false
steps: [] # type skill fills this in
- stage: Build
displayName: "Build"
dependsOn: SecurityScan
condition: succeeded()
jobs:
- job: Build
pool: EKS-Pool
timeoutInMinutes: 30
continueOnError: false
steps: [] # type skill fills this in
- stage: DeployNonprod
displayName: "Deploy — Nonprod"
dependsOn: Build
condition: succeeded()
jobs:
- deployment: DeployNonprod
displayName: "Deploy to Nonprod"
pool: EKS-Pool
timeoutInMinutes: 30
environment: nonprod
strategy:
runOnce:
deploy:
steps: [] # type skill fills this in
- stage: DeployProd
displayName: "Deploy — Prod"
dependsOn: DeployNonprod
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/<trigger-branch>'))
jobs:
- deployment: DeployProd
displayName: "Deploy to Prod"
pool: EKS-Pool
timeoutInMinutes: 30
environment: prod # manual approval gate configured in ADO environment settings
strategy:
runOnce:
deploy:
steps: [] # type skill fills this in + git tag step below
```
## Prod tier pipelines
When `target tier` is `prod`, omit `DeployNonprod` entirely. The pipeline contains only `Lint``SecurityScan``Build``DeployProd` with the manual approval gate.
When `target tier` is `nonprod`, omit `DeployProd` entirely.
## Git tagging on prod deploy
Add this as the final step inside `DeployProd`'s steps (prod tier only):
```yaml
- script: |
git config user.email "azdo-pipeline@$(System.TeamProject)"
git config user.name "Azure DevOps Pipeline"
git remote set-url origin "https://x-token:$(System.AccessToken)@$(echo $BUILD_REPOSITORY_URI | sed 's|https://||')"
git tag $(Build.BuildNumber) $(Build.SourceVersion)
git push origin $(Build.BuildNumber)
displayName: "Tag commit with build number"
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
BUILD_REPOSITORY_URI: $(Build.Repository.Uri)
```
## Secret handling patterns
Emit the correct block(s) based on declared secret sources:
### ADO variable groups
```yaml
variables:
- group: <variable-group-name>
```
Reference values as `$(VAR_NAME)` throughout the pipeline.
### AWS SSM Parameter Store
```yaml
- script: |
VALUE=$(aws ssm get-parameter \
--name "/myapp/mykey" \
--with-decryption \
--query "Parameter.Value" \
--output text)
echo "##vso[task.setvariable variable=MY_VAR;issecret=true]$VALUE"
displayName: "Fetch secret from SSM"
```
### AWS Secrets Manager
```yaml
- script: |
VALUE=$(aws secretsmanager get-secret-value \
--secret-id "myapp/mykey" \
--query "SecretString" \
--output text)
echo "##vso[task.setvariable variable=MY_VAR;issecret=true]$VALUE"
displayName: "Fetch secret from Secrets Manager"
```
### Vault / OpenBao
```yaml
- script: |
VALUE=$(vault kv get -field=mykey secret/myapp/mykey)
echo "##vso[task.setvariable variable=MY_VAR;issecret=true]$VALUE"
displayName: "Fetch secret from Vault"
env:
VAULT_ADDR: $(VAULT_ADDR)
VAULT_TOKEN: $(VAULT_TOKEN)
```
## Hard rules — always follow these
- `pool: EKS-Pool` on every job — no exceptions
- `timeoutInMinutes: 30` on every job
- `continueOnError: false` at **job level** on every job (not step level). Step-level `continueOnError` may be omitted.
- No secrets hardcoded in YAML — all via variable groups or runtime fetch
- Every stage and job has a `displayName:` set
- `pool: EKS-Pool` must appear at job level, not stage level, to ensure it applies correctly