Skill v1.0.1
currentLLM-judged scan90/100+1 new
version: "1.0.1" name: ci-cd description: > CI/CD integration for gh-infra in GitHub Actions: plan each pull request and post the plan as a comment, apply on merge, scheduled drift detection with notification, --changed-since and --detailed-exitcode, self-managed vs central-management layouts, and which token each needs.
CI/CD Integration
Use this skill when the user wants GitHub Actions workflows around gh-infra.
Recommended Setup
Three workflows; full YAML in references/workflows.md. Copy them and change only the paths and the secret name.
| Workflow | Trigger | Command | |
|---|---|---|---|
| Plan on pull request | pull_request | gh infra plan <paths> --changed-since origin/${{ github.base_ref }} --detailed-exitcode -o markdown > plan.md, then gh pr comment --body-file plan.md --edit-last --create-if-none | |
| Apply on merge | push to main, workflow_dispatch | gh infra apply <paths> --changed-since "$BEFORE" --auto-approve; without --changed-since when github.event.before is empty or all zeros | |
| Drift detection | schedule, workflow_dispatch | gh infra plan <paths> --detailed-exitcode -o markdown > plan.md (no --changed-since), notify on exit 2 |
Optional fourth: pull changes made on GitHub into the manifests on a schedule with gh infra import --into=<path> --auto-approve and open a pull request (also in workflows.md).
Use the three unless the user wants less. Drift detection is also the safety net for apply runs that failed: a failed apply --changed-since is not retried by the next push.
Rules For Every Workflow
- install the extension:
- run: gh extension install babarot/gh-infraafteractions/checkout, withGH_TOKENset at job level - pass every manifest directory to one command:
gh infra plan ./repos/ ./files/. One exit status, and cross-manifest validation (shared PR branch) covers all of them. Do not run one command per directory: with--detailed-exitcodethe first exits 2 and the second never runs --changed-sinceneeds the ref in the checkout:actions/checkoutwithfetch-depth: 0--auto-approveonapply(andimport --into) in CI; the prompt needs a TTY- capture exit codes instead of letting the step fail:
... --detailed-exitcode ... || echo "code=$?" >> "$GITHUB_OUTPUT", thenif: steps.plan.outputs.code == '1'->exit 1. Exit 0 no changes (also when--changed-sinceselected nothing), 1 error (wins over changes; also bad ref, no manifests), 2 changes --ciis deprecated (exits 1 for changes and errors alike); use--detailed-exitcode, andNO_COLOR=1for plain output- pull request workflow:
permissions: pull-requests: write; skip PRs from forks (if: github.event.pull_request.head.repo.full_name == github.repository) since they get no secrets and a read-only token; never suggestpull_request_targetfor this (it runs the fork's manifests with your token); guard the comment with[ -s plan.md ](empty when the plan failed early) paths:filters must include directories read throughsource:/patches:(e.g.templates/**), or a template-only change does not trigger the workflow. Withoutpaths:,--changed-sincealready makes unrelated runs free. Apaths:-filtered workflow cannot be a required check- FileSet commit messages can link the trigger:
env: GH_INFRA_SOURCE_URL: ${{ github.event.head_commit.url }}on the apply job, used as<% if .Source.URL %>Source: <% .Source.URL %><% end %>
Tokens
- plan/apply read only what a manifest sets, so grant only the permissions for that (fine-grained PAT or GitHub App token, stored as e.g.
GH_INFRA_TOKEN, passed asGH_TOKEN): - repository settings (description, topics, features, merge strategy, visibility): plan needs Metadata (+ Contents: read for merge commit messages / auto-merge / pull requests), apply needs Administration: write
- branch protection, Actions settings, release immutability, vulnerability alerts, automated security fixes: Administration read (plan) / write (apply)
- rulesets, private vulnerability reporting: plan with Metadata, apply needs Administration: write
- labels, milestones: Issues; secrets: Secrets; variables: Variables; File/FileSet: Contents (+ Pull requests for
via: pull_request) - a managed setting the token cannot read fails that repository in plan (
cannot read secrets of org/repo (the token needs the Secrets permission)); it is not compared as empty. On GitHub Free private repos, managed rulesets fail with GitHub's "Upgrade to GitHub Pro" message - the workflow's
GITHUB_TOKENcannot have Administration and cannot reach other repositories: for its own repo it can plan and apply labels, milestones (issues: write) and File / FileSet (contents: write), not repository settings - comments and issues created by the workflow itself can use
GH_TOKEN: ${{ github.token }}on that step - never use a broad classic PAT
Layouts
- Self-managed (
.github/infra.yamlin each repo): references/self-managed.md - Central (one config repo with
repos/,files/): references/central.md
gh-infra reads only top-level *.yaml / *.yml in each directory argument.