Skip to content

Reusable Dependabot action-pin-comment sync workflow - #8

Merged
jeremy merged 2 commits into
mainfrom
ci/dependabot-sync-actions-comments
Jul 27, 2026
Merged

Reusable Dependabot action-pin-comment sync workflow#8
jeremy merged 2 commits into
mainfrom
ci/dependabot-sync-actions-comments

Conversation

@jeremy

@jeremy jeremy commented Jul 27, 2026

Copy link
Copy Markdown
Member

What

Ports openclaw-basecamp's hardened dependabot-sync-actions-comments automation as a reusable workflow, for thin SHA-pinned callers in basecamp-sdk, basecamp-cli, hey-cli, fizzy-cli, and cli.

Dependabot's github-actions updater bumps SHA pins but can't rewrite the # vX.Y.Z comment on lines that carry a second trailing comment (e.g. a # zizmor: ignore[...] suppression), so those comments go stale on every actions-group bump (latest instance: basecamp-sdk#454, fixed by hand in basecamp-sdk#458). zizmor ≥1.26 no longer parses compound comments as version comments either, so the audit can't catch or fix them.

Security model (unchanged from openclaw-basecamp)

The naive push-triggered form (basecamp-mcp-server lineage) had two fatal flaws surfaced in basecamp-sdk#458 review: it executes the freshly-bumped, unreviewed checkout action with a write token, and GITHUB_TOKEN cannot push workflow-file changes at all (openclaw-basecamp hit this live and moved to a deploy key in openclaw-basecamp@54c96d3e). This model instead:

  • workflow_run from the default branch — only reviewed code executes; the Dependabot head branch is fetched as data, never executed (no checkout into an executing context, no uses: steps from it)
  • Exact gates — same-repo Dependabot-actored pull_request CI runs on dependabot/github_actions/* only; exactly one open PR, base = default branch, head still at the audited SHA, authored by app/dependabot (or, in e2e proof mode, a draft PR by the dispatcher on an e2e-proof-* branch)
  • Diff guard — every staged diff line must be a SHA-pinned uses: line; the updater script separately asserts changes are confined to the version token
  • Lease push via dedicated write deploy key (SYNC_ACTIONS_DEPLOY_KEY in each caller repo) — compare-and-swap --force-with-lease pinned to the audited head SHA; GitHub's SSH host keys pinned from the authenticated API
  • Per-branch concurrency group — repos whose PR CI produces multiple workflow_run completions (hey-cli has two workflows both named "CI") serialize instead of racing the lease
  • CI re-dispatch as fallback only + held-run approval scoped to the exact pushed commit

Reusable-workflow adaptation

The one structural change from openclaw: the updater script can't be fetched via git show $GITHUB_SHA:... (that's the caller's commit here), and job_workflow_sha exists only as an OIDC claim, not in the github context. Instead the script is embedded in the workflow heredoc, so the caller's SHA pin covers it byte for byte with no runtime fetch, no mutable ref, and no extra permissions. scripts/sync-action-pin-comments.mjs (byte-identical copy of openclaw's, sha1 5acb3555) remains the reviewable, tested source of truth:

  • openclaw's vitest suite ported to zero-dependency node --test (20 tests)
  • scripts/check-embedded-sync.sh fails CI if the embedded copy drifts from the file
  • Verified locally: YAML-parsing the run block and executing it materializes a byte-identical script; the drift gate fails on a 1-line mutation

Caller inputs cover the per-repo differences: ci-workflow-name (Test/CI), default-branch (fizzy-cli is master), dispatch-workflows (fallback list).

Verification

  • actionlint and zizmor 1.28.0: clean
  • node --test "scripts/*.test.mjs": 20/20 pass
  • Guard + gate logic is byte-for-byte openclaw's, which has validated end-to-end on live Dependabot PRs (openclaw-basecamp#152/#153)
  • Runtime validation planned on the next github_actions bump in a caller repo (basecamp-cli#566 is a candidate)

Caller PRs + deploy-key provisioning follow once this merges and pins can point at the mainline SHA.

Dependabot's github-actions updater bumps SHA pins but cannot rewrite the
# vX.Y.Z comment on lines that carry a second trailing comment (e.g. a
zizmor suppression), so those comments go stale on every actions-group
bump across our repos.

Port openclaw-basecamp's hardened comment-sync automation as a reusable
workflow: callers trigger it via workflow_run after CI completes on a
Dependabot actions branch; it runs only trusted default-branch code,
fetches the head branch as data (never executes it), rewrites stale
version comments with an embedded zero-dependency updater script, proves
the diff touches nothing but pinned uses lines, and pushes behind a
compare-and-swap lease with a dedicated write deploy key (App tokens,
GITHUB_TOKEN included, cannot push workflow-file changes; SSH deploy
keys are exempt — openclaw-basecamp@54c96d3e).

The updater script is embedded in the workflow heredoc so the caller's
SHA pin covers it byte for byte; scripts/sync-action-pin-comments.mjs
(verbatim from openclaw-basecamp) is the tested source of truth, with
the vitest suite ported to node --test and a CI drift gate asserting the
embedded copy matches.
Copilot AI review requested due to automatic review settings July 27, 2026 19:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 51c7df4123

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/sync-action-pin-comments.mjs

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports the hardened “Dependabot action-pin-comment sync” automation into this repo as a reusable workflow, including an embedded updater script (covered by the caller’s SHA pin) plus CI checks to ensure the embedded copy never drifts from the tested source.

Changes:

  • Add sync-action-pin-comments.mjs core+CLI script to rewrite stale # vX.Y.Z comments on SHA-pinned uses: lines while preserving trailing annotations byte-for-byte.
  • Add a reusable workflow (dependabot-sync-actions-comments.yml) that runs on reviewed code paths and pushes fixes behind strict PR gates + an SSH deploy-key lease push.
  • Add tests and CI drift protection (node --test suite + embedded-script equivalence check).

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
scripts/sync-action-pin-comments.mjs Zero-dependency updater that computes safe, token-only edits for pinned uses: version comments.
scripts/sync-action-pin-comments.test.mjs node:test suite validating parsing, tag selection, edit planning, and token-only diff guard behavior.
scripts/check-embedded-sync.sh CI guard that extracts the embedded heredoc script and diffs it against the source script to prevent drift.
.github/workflows/dependabot-sync-actions-comments.yml Reusable hardened workflow that gates eligible Dependabot PRs and performs a leased deploy-key push of comment fixes.
.github/workflows/ci.yml Adds a job to run the script tests and embedded-script drift check in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/ci.yml
zizmor's secrets-outside-env audit (regular-persona in the 1.23.x this
repo's pinned zizmor-action resolves) flagged the repo-scoped secret —
and the environment model is better anyway, matching our zero
repo-scoped-secrets practice: the SYNC_ACTIONS_DEPLOY_KEY lives in each
caller's dependabot-sync environment whose deployment branch policy
allows only the default branch, so no other workflow (and no non-default
ref) can read it. Environment secrets cannot be forwarded explicitly to
a reusable workflow, so callers switch to secrets: inherit and the job
declares the environment itself.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

.github/workflows/dependabot-sync-actions-comments.yml:81

  • environment: dependabot-sync in a reusable workflow cannot load environment secrets from the caller repository; environment secrets are scoped to the repository that defines the reusable workflow. As a result, the deploy key described in the comment will not be available from caller repos and the push step will fail. Prefer passing SYNC_ACTIONS_DEPLOY_KEY as a normal repo/org secret via workflow_call secrets (and drop the environment here), or keep this workflow non-reusable if environment-only scoping is a hard requirement.
    # The write deploy key lives in the caller repo's `dependabot-sync`
    # environment, whose deployment branch policy is restricted to the default
    # branch: only default-branch runs of this job can read it, and no other
    # workflow in the repo can. Callers pass `secrets: inherit` — environment
    # secrets cannot be forwarded explicitly; they resolve only when the
    # running job declares the environment.
    environment: dependabot-sync

Comment thread .github/workflows/dependabot-sync-actions-comments.yml
jeremy added a commit to basecamp/cli that referenced this pull request Jul 27, 2026
* ci: sync Dependabot action pin comments via reusable workflow

Thin caller for basecamp/.github's dependabot-sync-actions-comments
reusable workflow (basecamp/.github#8): after CI completes on a
Dependabot github_actions branch, trusted default-branch code fixes any
stale pin version comments and pushes back behind a compare-and-swap
lease, using the write deploy key scoped to this repo's dependabot-sync
environment (deployment branches: default branch only).

* chore(actions): sync seed workflow pin comments

One-time catch-up: the ref-version-mismatch audit is online, so upstream
tag moves since the last CI run left 33 stale version comments in the
seed templates (zizmor --fix=all, with the two cache-poisoning ignore
annotations it clobbers restored by hand). Seed templates stay manually
maintained; the new sync workflow covers only .github/workflows.

* deps: bump golang.org/x/sys to v0.44.0

Clears CVE-2026-39824 (integer overflow in NewNTUnicodeString,
golang.org/x/sys/windows) flagged by the Trivy gate. Indirect
dependency; go build ./... verified.

* ci: filter workflow_run to dependabot branches at the trigger

Review feedback: the job-level if only skips the job after the run is
created; a trigger-level branches filter stops runs from being created
for non-Dependabot branches at all. The if stays as defense-in-depth.
jeremy added a commit to basecamp/basecamp-cli that referenced this pull request Jul 27, 2026
* ci: sync Dependabot action pin comments via reusable workflow

Thin caller for basecamp/.github's dependabot-sync-actions-comments
reusable workflow (basecamp/.github#8): after CI completes on a
Dependabot github_actions branch, trusted default-branch code fixes any
stale pin version comments and pushes back behind a compare-and-swap
lease, using the write deploy key scoped to this repo's dependabot-sync
environment (deployment branches: default branch only).

* chore(actions): sync action pin comments

One-time catch-up applying what the new sync workflow will maintain
automatically: version comments on SHA-pinned uses lines whose trailing
zizmor annotations prevented Dependabot from rewriting them.

* ci: filter workflow_run to dependabot branches at the trigger

Review feedback: the job-level if only skips the job after the run is
created; a trigger-level branches filter stops runs from being created
for non-Dependabot branches at all. The if stays as defense-in-depth.
jeremy added a commit to basecamp/fizzy-cli that referenced this pull request Jul 27, 2026
* ci: sync Dependabot action pin comments via reusable workflow

Thin caller for basecamp/.github's dependabot-sync-actions-comments
reusable workflow (basecamp/.github#8): after CI completes on a
Dependabot github_actions branch, trusted default-branch code fixes any
stale pin version comments and pushes back behind a compare-and-swap
lease, using the write deploy key scoped to this repo's dependabot-sync
environment (deployment branches: default branch only).

Also adds workflow_dispatch to test.yml and security.yml so the reusable
workflow's CI-dispatch fallback can re-run checks on the pushed head.

* chore(actions): sync action pin comments

One-time catch-up applying what the new sync workflow will maintain
automatically: version comments on SHA-pinned uses lines whose trailing
zizmor annotations prevented Dependabot from rewriting them.

* ci: filter workflow_run to dependabot branches at the trigger

Review feedback: the job-level if only skips the job after the run is
created; a trigger-level branches filter stops runs from being created
for non-Dependabot branches at all. The if stays as defense-in-depth.
jeremy added a commit to basecamp/basecamp-sdk that referenced this pull request Jul 27, 2026
* CI: sync Dependabot action pin comments via reusable workflow

Thin caller for basecamp/.github's dependabot-sync-actions-comments
reusable workflow (basecamp/.github#8): after CI completes on a
Dependabot github_actions branch, trusted default-branch code fixes any
stale pin version comments and pushes back behind a compare-and-swap
lease, using the write deploy key scoped to this repo's dependabot-sync
environment (deployment branches: main only).

Replaces the push-triggered port withdrawn from #458: that lineage
executed the freshly-bumped unreviewed checkout action with a write
token, and GITHUB_TOKEN cannot push workflow-file changes at all.

* CI: filter workflow_run to dependabot branches at the trigger

Review feedback: the job-level if only skips the job after the run is
created; a trigger-level branches filter stops runs from being created
for non-Dependabot branches at all. The if stays as defense-in-depth.

* CI: re-pin dependabot-sync reusable workflow past the dispatch fallback

basecamp/.github#10 removed the CI-dispatch fallback (Codex P1 on
fizzy-cli#189: dispatching branch workflows executes unreviewed action
pins outside the Dependabot sandbox); the workflow now verifies CI
started on the pushed head and warns a maintainer if not.
jeremy added a commit to basecamp/hey-cli that referenced this pull request Jul 27, 2026
* ci: sync Dependabot action pin comments via reusable workflow

Thin caller for basecamp/.github's dependabot-sync-actions-comments
reusable workflow (basecamp/.github#8): after CI completes on a
Dependabot github_actions branch, trusted default-branch code fixes any
stale pin version comments and pushes back behind a compare-and-swap
lease, using the write deploy key scoped to this repo's dependabot-sync
environment (deployment branches: default branch only).

Also adds workflow_dispatch to test.yml and security.yml so the reusable
workflow's CI-dispatch fallback can re-run checks on the pushed head.

* ci: filter workflow_run to dependabot branches; give test.yml a unique name

Review feedback (Copilot + Codex): a trigger-level branches filter stops
workflow runs from being created for non-Dependabot branches (the
job-level if only skips the job after the fact), and ci.yml and test.yml
both being named CI made the workflow_run anchor fire twice per head and
the ci-workflow-name detection ambiguous. test.yml becomes Test
(matching basecamp-cli and cli); required status checks are job-name
contexts (test, lint, security, race-check) so the rename does not
affect the main-gate ruleset. Consolidating ci.yml vs test.yml overlap
is left as a follow-up.

* deps: require Go 1.26.2

Clears the nine stdlib vulnerabilities govulncheck flags in go1.26.1
(GO-2026-4866 et al., all fixed in 1.26.2). The workflows resolve the
toolchain from go.mod, so this moves CI and local builds together.

* ci: re-pin dependabot-sync reusable workflow past the dispatch fallback

basecamp/.github#10 removed the CI-dispatch fallback (Codex P1 on
fizzy-cli#189: dispatching branch workflows executes unreviewed action
pins outside the Dependabot sandbox); the workflow now verifies CI
started on the pushed head and warns a maintainer if not.

* deps: require Go 1.26.5

1.26.2 was not enough: govulncheck flags stdlib vulnerabilities fixed
across 1.26.3–1.26.5 (GO-2026-5856 in crypto/tls et al.). 1.26.5 is the
newest patch release, clearing all five remaining findings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants