Files
gstack/.github/workflows/skill-docs.yml
T
Garry TanandClaude Fable 5 e2904be7a4 fix(ci): least-privilege permissions + fork-safe concurrency keys
- evals.yml / evals-periodic.yml evals jobs: explicit contents:read +
  packages:read (container-image pull) and persist-credentials:false —
  the jobs that execute PR-authored code with three provider API keys
  ran on the repo-default token grant with the token written into
  .git/config
- permissions blocks for the 4 workflows that had none (skill-docs,
  make-pdf-gate, windows-free-tests, windows-setup-e2e)
- fork-safe concurrency keys: actionlint, skill-docs, make-pdf-gate,
  windows-setup-e2e switch from head_ref to PR-number keying — a bare
  branch name carries no fork prefix, so same-name branches from two
  forks shared one group and cancelled each other's runs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 04:39:36 +00:00

59 lines
2.6 KiB
YAML

name: Skill Docs Freshness
# push is main-only: a push to a PR branch already fires the pull_request run;
# the unrestricted push trigger double-ran every PR commit.
on:
push:
branches: [main]
pull_request:
# Cancel superseded runs for the same branch (matches evals.yml,
# windows-free-tests.yml, etc.). head_ref is set on pull_request; ref_name is
# the fallback for push so a rapid push series doesn't pile up stale runs.
concurrency:
# PR-number keyed (run_id fallback for push/dispatch): a bare branch name
# carries no fork prefix, so same-name branches from two forks would share
# one group and cancel each other's runs (same rationale as free-tests.yml).
group: skill-docs-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
# The job only reads the checkout and runs the generator — no token writes.
permissions:
contents: read
jobs:
check-freshness:
runs-on: ubicloud-standard-2
steps:
- uses: actions/checkout@v7
- uses: oven-sh/setup-bun@v2
- run: bun install
# One generation pass for ALL 10 hosts. gen-skill-docs --host all
# hard-fails on any per-host generation error (scripts/gen-skill-docs.ts
# aggregates failures and exits non-zero), so every host is gated on
# "generates cleanly." Known limitation, on purpose: the 9 gitignored
# host outputs (.agents/, .factory/, .kiro/, ...) are NOT byte-freshness
# checked — `git diff` on ignored untracked paths is always empty (the
# previous per-host `git diff -- .agents/` gates could never fail for
# exactly that reason). Byte-freshness is enforced only for tracked
# output (the Claude SKILL.md files), which the two steps below cover.
- name: Generate all host skill docs
run: bun run gen:skill-docs --host all
- name: Verify tracked skill docs are fresh
run: |
git diff --exit-code || {
echo "Generated SKILL.md files are stale. Run: bun run gen:skill-docs --host all"
exit 1
}
# git diff misses NEW untracked files (e.g. a freshly added skill whose
# generated SKILL.md was never committed). Fail on any untracked stray
# the generator produced outside the gitignored host dirs.
- name: Verify no untracked generated files
run: |
STRAYS=$(git status --porcelain --untracked-files=all | grep '^??' || true)
if [ -n "$STRAYS" ]; then
echo "Generator produced untracked files that are neither committed nor gitignored:"
echo "$STRAYS"
echo "Commit them (bun run gen:skill-docs --host all) or gitignore them."
exit 1
fi