feat(standards-sync): add targets filter and narrow the App token - #56
Conversation
Track B activation groundwork: a `targets` input narrows a run to an exact-match allowlist of manifest repos (pilot + staged rollout), the plan log iterates the built matrix so it always shows the filtered set, and the minted App token is scoped to contents/pull-requests write only (resolves the zizmor github-app finding). Header note updated now that the App secrets exist and the standards caller is landing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GbDWhcUtduCejgi7mcbMfy
|
Claude finished @kyle-sexton's task in 1m 40s —— View job PR Review
Overall this is a clean, well-reasoned change. The filter logic is correct, the security posture improves, and the CLAUDE.md least-privilege principle is respected. A few notes below, ranging from one real concern to minor observations. Filter logic — correctThe set-subtraction expression is sound: select(strenv(only) == "" or ([.repo] - (strenv(only) | split(",")) | length) == 0)
No shell-injection risk
Finding 1 — Raw user input echoed into the workflow annotation (cosmetic, not a vulnerability)echo "::error::targets filter '$TARGETS' matches no manifest target"
echo "::error::targets filter '$only' matches no manifest target"Finding 2 — Double-comma edge case produces a spurious empty-string entry (harmless)
Finding 3 —
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 27175d6d2c
ℹ️ 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".
|
Claude finished @kyle-sexton's task in 2m 42s —— View job PR Review
This is a clean, well-reasoned two-commit change. The filter logic is sound, the Codex P2 finding is fully addressed, and the security posture improves. A few observations below. Filter logic — correctThe yq set-subtraction expression is the right approach: select(strenv(only) == "" or ([.repo] - (strenv(only) | split(",")) | length) == 0)
Codex P2 fully addressed by commit
|
A typo in one of several filter entries silently dropped that repo from a staged rollout while the rest synced. Validate the full allowlist against the manifest and fail naming the unknown entries (Codex review). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GbDWhcUtduCejgi7mcbMfy
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 08f5bd2. Configure here.
There was a problem hiding this comment.
Stale comment
Risk: medium. Cursor Bugbot reported 1 unresolved finding (comma-only targets bypass validation) and the Bugbot check finished as skipped, so I am not approving. Human review is needed; no reviewers were assigned because no suitable non-author reviewers are available in this repository.
Sent by Cursor Approval Agent: Pull Request Router and Approver
|
Claude finished @kyle-sexton's task in 1m 56s —— View job PR Review
This is a clean, complete implementation across three commits. The two prior reviews covered the original feature commit and the Codex P2 fix; the third commit ( Normalization pipeline is correctonly="$(tr -d '[:space:]' <<<"$TARGETS" | tr -s ',' | sed 's/^,//; s/,$//')"The three-stage pipe handles every degenerate input correctly: All-comma/all-space guard (commit
|
Normalize the allowlist (squeeze/trim commas after space-stripping) so split never yields empty tokens, and hard-error when a non-empty filter normalizes to nothing (e.g. ",,") instead of green-planning zero targets (Cursor review). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GbDWhcUtduCejgi7mcbMfy
#109) ## Summary Closes decision #56 (Decisions Log: https://claude.ai/code/artifact/232ecdce-8316-4880-8c0a-dc3c7dcf3a63). **Corrected premise:** the decision assumed 3 rolling-maintenance-issue workflows, each with a different dedup mechanism. Empirically there are **4**: `link-check.yml`, `queue-monitor-liveness.yml`, and `tool-version-drift-check.yml` all used the *same* title-search dedup (`gh issue list --search 'in:title "..."'`), while only `pulumi-version-drift-check.yml` already used an embedded-HTML-marker. The intent (converge on the marker mechanism) still holds — it's a 3-file port to the 4th file's existing pattern, not "each different." ## Why markers over title search Title search breaks on a retitled issue (the search string no longer matches) and can false-positive-match an unrelated issue that happens to share title text. A marker embedded in the issue body is exact and survives a retitle — the same reasoning `pulumi-version-drift-check.yml` already documents for its own mechanism. ## Implementation Ported all 3 to marker-based lookup, inlined per file (not a shared composite action). I could not confirm from GitHub's docs, and found no existing precedent in this repo, that a reusable workflow's `uses: ./.github/actions/...` reference resolves against its own repo when called cross-repo — rather than build on unverified behavior for something that gates real issue-tracking, I inlined the lookup logic directly in each file, matching `pulumi-version-drift-check.yml`'s own single-script style. - `link-check.yml`: marker prepended to lychee's generated report file before it's passed to `create-issue-from-file`. - `queue-monitor-liveness.yml`, `tool-version-drift-check.yml`: marker added as the first line of their existing hand-built issue-body heredocs. Each workflow's own marker is scoped to it (`<!-- ci-workflows:<workflow-name>:v1:active -->`), consistent with `pulumi-version-drift-check.yml`'s naming. Search is scoped `state=open`, matching the original title-search's scoping. `pulumi-version-drift-check.yml` can safely search `state=all` only because it swaps its marker to a `:resolved` sentinel on close; none of these 3 do that, so `state=all` would keep matching a closed issue's stale `:active` marker on every later run. ## Verification - `zizmor` on all 3 modified files: no findings (3 suppressed, matching repo baseline). - `actionlint`: clean on `link-check.yml` and `queue-monitor-liveness.yml`. `tool-version-drift-check.yml` hangs locally in this environment — confirmed **pre-existing**, reproduces identically against the unmodified file on `main`, unrelated to this change. Repo's own hosted CI actionlint will validate it on this PR. - No behavior change to what each workflow actually checks — only the tracking-issue lookup mechanism changed. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>



Summary
Track B activation groundwork for the config-distribution engine (follows #50):
targetsinput — comma-separated exact-match allowlist of manifest repos (empty = all). This is the pilot / staged-rollout control: the first real sync runs against a single target without touching the manifest. Exact membership via yq set subtraction — no substring matching (github-iacalone matches nothing and fails the run). Spaces are stripped soa, banda,bfilter alike; a filter matching no target is a hard error (typo protection).permission-contents: write+permission-pull-requests: writeon the mint step, so the token carries only what the sync needs even if the installation ever has wider grants. Resolves the zizmorgithub-appfinding (local zizmor v1.26.1 now clean on this file).standards, and the SHA-pinned caller lands next.Verification
Filter expression exercised locally with yq v4.53.3 against the live
standardsmanifest: empty filter → all 4 targets; exact repo → 1; substring → 0 (errors); spaced pair → 2. actionlint + zizmor clean locally.🤖 Generated with Claude Code
https://claude.ai/code/session_01GbDWhcUtduCejgi7mcbMfy
Note
Medium Risk
Changes cross-repo sync scope and GitHub App token permissions; mistakes in the targets filter are guarded by hard errors, but a misconfigured allowlist could still limit or block intended rollouts.
Overview
Adds a
targetsworkflow_callinput so callers can run a staged rollout against a comma-separated, exact-match allowlist of manifest repos (empty = all). The plan job normalizes the filter, builds the matrix with yq set subtraction (no substring matches), and fails the run on junk filters or unknown repo names so typos cannot silently skip one repo while others sync.The distribution plan log now walks the built matrix instead of every manifest target, so dry-run output matches what the sync job will execute when filtered.
On real syncs,
actions/create-github-app-tokennow setspermission-contents: writeandpermission-pull-requests: writeso minted tokens only carry branch/PR permissions even if the App installation is broader. Header comments are updated to reflect activation gating via caller + secrets rather than a draft “not active” note.Reviewed by Cursor Bugbot for commit ad6a93e. Bugbot is set up for automated code reviews on this repo. Configure here.