Skip to content

Pin privileged release actions and document custody - #166

Draft
gontzess wants to merge 12 commits into
mainfrom
steve.gontzes/gf16-action-allowlist
Draft

gontzess wants to merge 12 commits into
mainfrom
steve.gontzes/gf16-action-allowlist

Conversation

@gontzess

@gontzess gontzess commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Why

Use immutable action revisions for release jobs and make credential custody explicit.

Scope and drift ownership

Review and organization Actions policy own action drift. This change adds no per-repository action lint. The final source diff is the workflow change plus a short custody table; the existing locked-tools integrity tests remain untouched.

What

  • Keep all surviving remote action references SHA-pinned, including first-party checkout and registry OIDC steps. Local composite actions still come from the checkout at job.workflow_sha.
  • Retain main's masci/datadog@93a16378298f4e1980f13f6b412c0b8e66b96185 without a bump, with its exact event configuration and latest-attempt annotation plumbing.
  • Keep DATADOG_API_KEY step-scoped through with: api-key, notification-step continue-on-error: true, and the five-minute job timeout. Notification is event-only.
  • Document the retained actions and custody below. No organization policy or credential configuration is changed by this PR.

Action custody

Action SHA Which job Custody
actions/checkout fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 All jobs except notify-release-failure; locked-tools gon checkout Job-scoped GITHUB_TOKEN; persist-credentials: false.
actions/github-script f28e40c7f34bde8b3046d885e986cb6290c5673b record-registry-api Job OIDC credentials; masked registry-audience token output.
sigstore/cosign-installer 398d4b0eeef1380460a10c8013a76f728fb906ac goreleaser-binaries, goreleaser-windows, goreleaser-docker, publish-release-manifest, verify-release Tool bootstrap in OIDC-enabled jobs; no explicit secret input.
apple-actions/import-codesign-certs 253ddeeac23f2bdad1646faac5c8c2832e800071 goreleaser-binaries Step inputs APPLE_SIGNING_KEY_P12 and APPLE_SIGNING_KEY_P12_PASSWORD.
aws-actions/configure-aws-credentials 61815dcd50bd041e203e49132bacad1fd04d2708 goreleaser-binaries, goreleaser-windows, goreleaser-docker, publish-release-manifest, verify-release Exchanges job OIDC for scoped AWS role credentials.
aws-actions/amazon-ecr-login 03f1aad4c6c7ffd436567f42f9384779290529bd goreleaser-docker, verify-release Job AWS credentials; registry authentication for publishing or pulling.
docker/setup-qemu-action c7c53464625b32c7a7e944ae62b3e17d2b600130 goreleaser-docker Digest-pinned binfmt setup in an OIDC-enabled job; no explicit secret input.
masci/datadog 93a16378298f4e1980f13f6b412c0b8e66b96185 notify-release-failure DATADOG_API_KEY (Datadog org write key), only step with: api-key; non-signing, notification only. Best-effort (continue-on-error: true), five-minute job; event-only. Re-pin review: diff the action's tag-to-SHA source; re-pinning is manual (no Renovate tracking exists for workflow SHAs).

Custody describes explicit inputs, not the absence of ambient job permissions. Re-pinning is manual: reviewers diff the action's tag-to-SHA source; no Renovate tracking exists for workflow SHAs.

Evidence

  • make test-scripts: PASS without the removed action-checking files or target hook (native PowerShell checks unavailable/skipped).
  • GOTOOLCHAIN=local go test ./... and GOTOOLCHAIN=local go vet ./...: PASS.
  • make workflow-validate and git diff --check: PASS.
  • The strip leaves release.yaml and scripts/test-tool-integrity.py byte-for-byte unchanged from the preceding revision; all pins and notification controls are preserved.

Rollout limits

Draft only. These local checks do not establish deployed organization Actions policy or live Datadog delivery. Review the immutable action revisions and evaluate live release/delivery evidence separately before rollout. No merge, deployment, secret creation or rotation is performed by this PR.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit e20da1ce6e99

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: full
View review run

Review Summary

The PR SHA-pins the remaining tag-referenced actions in release.yaml: checkout, apple codesign, configure-aws-credentials, ECR login, setup-qemu and github-script. Each pinned SHA exists in its upstream repository. masci/datadog is replaced with jq-built JSON sent by curl, with continue-on-error and || true. The PR also adds scripts/check-release-actions.py, a third-party allowlist and offline tests run by make test-scripts. CI installs the Python yq that load_yaml needs, so the script's JSON parsing works. I scanned the full diff for security and correctness. No repo-local criteria loaded, so the base criteria applied. Passing annotations through env instead of interpolating them into the action input also removes an expression-injection surface. Not covered: whether each SHA matches the tag in its trailing comment, and live Datadog delivery (the PR also says this is untested).

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) .github/workflows/release.yaml:1872-1883: neither Datadog curl call has a connect or total timeout, and notify-release-failure has no timeout-minutes. A stalled endpoint could keep the job running up to the 6-hour default.
  • New (confidence: medium) scripts/check-release-actions.py:66-74: the policy only checks job["steps"]. Job-level reusable-workflow uses:, container: and services: images in credential-bearing jobs are never checked, but docs/release-workflow.md says unknown container actions "fail closed".
  • New (confidence: low) scripts/check-release-actions.py:51: step.get("with", {}) returns None when a step has an empty with: key, and settings.get(...) then raises AttributeError instead of reporting a policy error. Use step.get("with") or {}. Also, the comment at release.yaml:1842 about the "events YAML block scalar" is now stale.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` (or similar) to both Datadog curl calls in the "Send Datadog event on failure" step, and/or add a small `timeout-minutes` to the notify-release-failure job, so a hung Datadog API cannot hold the job open for the 6-hour default.
- Around line 1842: Update or remove the comment about multi-line output breaking the "events YAML block scalar"; the masci/datadog action is gone and the text is now JSON-encoded by jq.

In `scripts/check-release-actions.py`:
- Around line 66-74: In check_workflow, for in-scope jobs also reject (or require SHA/digest pinning for) job-level `uses:` (reusable workflows), `container:` images, and `services:` images, and add negative tests in scripts/test-release-actions.py. Otherwise make the docs claim about container actions failing closed explicitly apply only to step-level `docker://` references.
- Around line 51: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker with AttributeError.

Comment thread .github/workflows/release.yaml Outdated
curl --fail-with-body --silent --show-error \
-H "DD-API-KEY: $DATADOG_API_KEY" -H "Content-Type: application/json" \
--data-binary "@$RUNNER_TEMP/release-failure-event.json" \
https://api.us3.datadoghq.com/api/v1/events || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion (confidence: medium): Neither Datadog curl call sets --connect-timeout or --max-time, and notify-release-failure has no timeout-minutes. A stalled Datadog endpoint could hold the failure job open until the 6-hour default. Add something like --connect-timeout 10 --max-time 30 (or a small job timeout), since || true already keeps the step best-effort.

Comment thread scripts/check-release-actions.py Outdated
if name in PRIVILEGED_JOBS or oidc or "secrets." in json.dumps(job):
errors.extend(check_steps(job.get("steps", []), name))
errors.extend(check_local_bootstrap(job.get("steps", []), name))
return errors

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion (confidence: medium): The policy only looks at job["steps"]. A credential-bearing job that calls a reusable workflow (job-level uses:), or that sets container:/services: images, passes the check without review. The docs say unknown container actions "fail closed", but that only holds for step-level docker:// references. Consider rejecting job-level uses/container/services (or requiring a SHA/digest pin for them) for jobs in scope.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 8f7776895d6f

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: full
View review run

Review Summary

The PR SHA-pins the remaining tag-referenced actions in release.yaml: checkout, apple codesign, configure-aws-credentials, ECR login, setup-qemu and github-script. Each pinned SHA exists in its upstream repository. masci/datadog is replaced with jq-built JSON sent by curl, with continue-on-error and || true. The PR also adds scripts/check-release-actions.py, a third-party allowlist and offline tests run by make test-scripts. CI installs the Python yq that load_yaml needs, so the script's JSON parsing works. I scanned the full diff for security and correctness. No repo-local criteria loaded, so the base criteria applied. Passing annotations through env instead of interpolating them into the action input also removes an expression-injection surface. Not covered: whether each SHA matches the tag in its trailing comment, and live Datadog delivery (the PR also says this is untested).

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) .github/workflows/release.yaml:1872-1883: neither Datadog curl call has a connect or total timeout, and notify-release-failure has no timeout-minutes. A stalled endpoint could keep the job running up to the 6-hour default.
  • New (confidence: medium) scripts/check-release-actions.py:66-74: the policy only checks job["steps"]. Job-level reusable-workflow uses:, container: and services: images in credential-bearing jobs are never checked, but docs/release-workflow.md says unknown container actions "fail closed".
  • New (confidence: low) scripts/check-release-actions.py:51: step.get("with", {}) returns None when a step has an empty with: key, and settings.get(...) then raises AttributeError instead of reporting a policy error. Use step.get("with") or {}. Also, the comment at release.yaml:1842 about the "events YAML block scalar" is now stale.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` (or similar) to both Datadog curl calls in the "Send Datadog event on failure" step, and/or add a small `timeout-minutes` to the notify-release-failure job, so a hung Datadog API cannot hold the job open for the 6-hour default.
- Around line 1842: Update or remove the comment about multi-line output breaking the "events YAML block scalar"; the masci/datadog action is gone and the text is now JSON-encoded by jq.

In `scripts/check-release-actions.py`:
- Around line 66-74: In check_workflow, for in-scope jobs also reject (or require SHA/digest pinning for) job-level `uses:` (reusable workflows), `container:` images, and `services:` images, and add negative tests in scripts/test-release-actions.py. Otherwise make the docs claim about container actions failing closed explicitly apply only to step-level `docker://` references.
- Around line 51: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker with AttributeError.

Reviewed commit: e20da1ce6e99

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 8f7776895d6f

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 4 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since e20da1c
View review run

Review Summary

The new commit makes three changes to scripts/check-release-actions.py:

  • First-party matching: it now accepts sub-path actions such as actions/cache/restore, rejecting . and .. path parts.
  • Job discovery: it now treats jobs as credential-bearing when they have job-level secrets: (including inherit) or when workflow-level env references a secret.
  • Reusable workflows: a job-level uses: is now checked against the allowlist and SHA-pin rule.

Tests cover the new cases. I scanned the full PR diff (release.yaml, Makefile, docs, checker, tests, allowlist) for security and correctness and found no blocking issues. No repo-local criteria loaded, so only the base criteria were applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) scripts/check-release-actions.py:74: discovery matches only the literal secrets.. A new job using secrets['X'] or toJSON(secrets) gets credentials without being detected, so its actions skip the allowlist check.
  • Prior — still present (confidence: medium) .github/workflows/release.yaml:1872-1883: neither Datadog curl call sets --connect-timeout/--max-time, and notify-release-failure has no timeout-minutes. A stalled endpoint can hold the job open for up to the 6-hour default.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:74-76: job-level reusable-workflow uses: is now checked, but job container: and services: images in credential-bearing jobs are still not. Meanwhile docs/release-workflow.md:289 says container actions "fail closed".
  • Prior — still present (confidence: low) scripts/check-release-actions.py:54: step.get("with", {}) returns None for an empty with: key, so settings.get(...) raises AttributeError instead of reporting a policy error. Separately, the comment at release.yaml:1842 about the "events YAML block scalar" is out of date now that the Datadog action has been removed.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 74: Detecting credential-bearing jobs via the substring "secrets." misses index syntax (secrets['X']) and toJSON(secrets). Use a word-boundary regex such as re.search(r"\bsecrets\b", json.dumps(job)) (and the same for workflow env), and add a negative test in scripts/test-release-actions.py.
- Around line 74-76: For in-scope jobs, also reject or require digest pinning for job-level `container:` and `services:` images, and add negative tests. Otherwise, narrow the "container actions fail closed" claim in docs/release-workflow.md (line ~289) to step-level docker:// references.
- Around line 54: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker.

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` to both Datadog curl calls, and/or add a small `timeout-minutes` to the notify-release-failure job.
- Around line 1842: Update the out-of-date comment about the "events YAML block scalar", since the event payload is now built with jq.

Comment thread scripts/check-release-actions.py Outdated
oidc = permissions == "write-all" or (
isinstance(permissions, dict) and permissions.get("id-token") == "write")
inherited_secret = "secrets." in json.dumps(workflow.get("env", {}))
if name in PRIVILEGED_JOBS or oidc or job.get("secrets") or inherited_secret or "secrets." in json.dumps(job):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Dynamic discovery only matches the substring secrets.. A new job that references a secret through index syntax (${{ secrets['TOKEN'] }}) or through toJSON(secrets) holds credentials but isn't detected, so its actions skip the allowlist check. Consider matching on \bsecrets\b (e.g. re.search(r"\bsecrets\b", json.dumps(job))) and adding a negative test. (confidence: medium)

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit afabc5806792

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 4 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since e20da1c
View review run

Review Summary

The new commit makes three changes to scripts/check-release-actions.py:

  • First-party matching: it now accepts sub-path actions such as actions/cache/restore, rejecting . and .. path parts.
  • Job discovery: it now treats jobs as credential-bearing when they have job-level secrets: (including inherit) or when workflow-level env references a secret.
  • Reusable workflows: a job-level uses: is now checked against the allowlist and SHA-pin rule.

Tests cover the new cases. I scanned the full PR diff (release.yaml, Makefile, docs, checker, tests, allowlist) for security and correctness and found no blocking issues. No repo-local criteria loaded, so only the base criteria were applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) scripts/check-release-actions.py:74: discovery matches only the literal secrets.. A new job using secrets['X'] or toJSON(secrets) gets credentials without being detected, so its actions skip the allowlist check.
  • Prior — still present (confidence: medium) .github/workflows/release.yaml:1872-1883: neither Datadog curl call sets --connect-timeout/--max-time, and notify-release-failure has no timeout-minutes. A stalled endpoint can hold the job open for up to the 6-hour default.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:74-76: job-level reusable-workflow uses: is now checked, but job container: and services: images in credential-bearing jobs are still not. Meanwhile docs/release-workflow.md:289 says container actions "fail closed".
  • Prior — still present (confidence: low) scripts/check-release-actions.py:54: step.get("with", {}) returns None for an empty with: key, so settings.get(...) raises AttributeError instead of reporting a policy error. Separately, the comment at release.yaml:1842 about the "events YAML block scalar" is out of date now that the Datadog action has been removed.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 74: Detecting credential-bearing jobs via the substring "secrets." misses index syntax (secrets['X']) and toJSON(secrets). Use a word-boundary regex such as re.search(r"\bsecrets\b", json.dumps(job)) (and the same for workflow env), and add a negative test in scripts/test-release-actions.py.
- Around line 74-76: For in-scope jobs, also reject or require digest pinning for job-level `container:` and `services:` images, and add negative tests. Otherwise, narrow the "container actions fail closed" claim in docs/release-workflow.md (line ~289) to step-level docker:// references.
- Around line 54: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker.

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` to both Datadog curl calls, and/or add a small `timeout-minutes` to the notify-release-failure job.
- Around line 1842: Update the out-of-date comment about the "events YAML block scalar", since the event payload is now built with jq.

Reviewed commit: 8f7776895d6f

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit afabc5806792

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 8f77768
View review run

Review Summary

The new commit replaces substring matching for secrets. in check-release-actions.py with a recursive references_secrets() helper. The helper matches the bare secrets context with a word-boundary regex across workflow env and every job value. Tests now cover secrets['X'], a multi-line index and toJSON(secrets). The incremental artifact was complete (not partial), and I also scanned the full PR diff (release.yaml, Makefile, docs, checker, tests, allowlist) for security and correctness issues. No repo-local criteria loaded, so I applied only the base criteria. The new matcher can over-match, for example on step names that contain the word "secrets". That only widens which jobs get checked, so it fails safe and I didn't flag it.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) .github/workflows/release.yaml:1872-1883: neither Datadog curl call sets --connect-timeout/--max-time (the call at line 330 does), and notify-release-failure (line 1775) has no timeout-minutes. A stalled endpoint could keep the job open until the 6-hour default.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:85-87: job-level container: and services: images in credential-bearing jobs are still not checked. docs/release-workflow.md:289 still says container actions "fail closed", which is true only for step-level docker:// references.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:54: when a step has an empty with: key, step.get("with", {}) returns None, so settings.get(...) raises AttributeError instead of reporting a policy error. Also, the comment at release.yaml:1842 about the "events YAML block scalar" is out of date now that the Datadog action has been removed.

Resolved prior findings

  • Fixed: secret discovery matched only secrets.. scripts/check-release-actions.py:67-75 now matches \bsecrets\b recursively, and line 84-85 applies it to workflow env and the whole job. scripts/test-release-actions.py:44-46 adds negative tests for index syntax, a multi-line index and toJSON(secrets).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` to both Datadog curl calls, and/or add a small `timeout-minutes` (e.g. 5) to the notify-release-failure job at line ~1775.
- Around line 1842: Update or remove the out-of-date comment about the "events YAML block scalar"; the Datadog action it referred to has been removed.

In `scripts/check-release-actions.py`:
- Around line 85-87: For in-scope jobs, also reject (or require digest pinning for) job-level `container:` and `services:` images, and add negative tests. Otherwise, narrow the "container actions fail closed" claim in docs/release-workflow.md (line ~289) to step-level docker:// references.
- Around line 54: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 56442bdf6a8d

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 8f77768
View review run

Review Summary

The new commit replaces substring matching for secrets. in check-release-actions.py with a recursive references_secrets() helper. The helper matches the bare secrets context with a word-boundary regex across workflow env and every job value. Tests now cover secrets['X'], a multi-line index and toJSON(secrets). The incremental artifact was complete (not partial), and I also scanned the full PR diff (release.yaml, Makefile, docs, checker, tests, allowlist) for security and correctness issues. No repo-local criteria loaded, so I applied only the base criteria. The new matcher can over-match, for example on step names that contain the word "secrets". That only widens which jobs get checked, so it fails safe and I didn't flag it.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) .github/workflows/release.yaml:1872-1883: neither Datadog curl call sets --connect-timeout/--max-time (the call at line 330 does), and notify-release-failure (line 1775) has no timeout-minutes. A stalled endpoint could keep the job open until the 6-hour default.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:85-87: job-level container: and services: images in credential-bearing jobs are still not checked. docs/release-workflow.md:289 still says container actions "fail closed", which is true only for step-level docker:// references.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:54: when a step has an empty with: key, step.get("with", {}) returns None, so settings.get(...) raises AttributeError instead of reporting a policy error. Also, the comment at release.yaml:1842 about the "events YAML block scalar" is out of date now that the Datadog action has been removed.

Resolved prior findings

  • Fixed: secret discovery matched only secrets.. scripts/check-release-actions.py:67-75 now matches \bsecrets\b recursively, and line 84-85 applies it to workflow env and the whole job. scripts/test-release-actions.py:44-46 adds negative tests for index syntax, a multi-line index and toJSON(secrets).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` to both Datadog curl calls, and/or add a small `timeout-minutes` (e.g. 5) to the notify-release-failure job at line ~1775.
- Around line 1842: Update or remove the out-of-date comment about the "events YAML block scalar"; the Datadog action it referred to has been removed.

In `scripts/check-release-actions.py`:
- Around line 85-87: For in-scope jobs, also reject (or require digest pinning for) job-level `container:` and `services:` images, and add negative tests. Otherwise, narrow the "container actions fail closed" claim in docs/release-workflow.md (line ~289) to step-level docker:// references.
- Around line 54: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker.

Reviewed commit: afabc5806792

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 56442bdf6a8d

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since afabc58
View review run

Review Summary

The new commit changes only documentation. It adds a notify-release-failure section to docs/release-workflow.md, which describes the curl-based Datadog event, the new failure-count metric, and the best-effort behavior. It also removes the outdated sentence that said the Datadog action is commit-pinned. Both match the current release.yaml:1853-1883. The full PR diff was scanned for security and correctness. The PR enforces allowlisted, SHA-pinned actions in privileged and credential-bearing jobs, requires an immutable workflow checkout before local composite actions run, and replaces the Datadog action with curl. No repo-local criteria loaded, so the base criteria were applied. The incremental diff is complete: nothing was dropped or truncated.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) .github/workflows/release.yaml:1872-1883: Neither Datadog curl call sets --connect-timeout/--max-time, although the call at line 330 does. The notify-release-failure job (line 1775) also has no timeout-minutes. A stalled endpoint could keep the job open until GitHub's 6-hour default timeout.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:78-87: check_workflow does not check job-level container: and services: images in credential-bearing jobs. docs/release-workflow.md:297 still says "container actions fail closed", which is true only for step-level docker:// references.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:54: If a step has an empty with: key, step.get("with", {}) returns None, and settings.get(...) then raises AttributeError instead of reporting a policy error. Separately, the comment at release.yaml:1842 about the "events YAML block scalar" is out of date now that the Datadog action has been removed.

Resolved prior findings

  • Fixed: Secret discovery used to match only secrets.. scripts/check-release-actions.py:67-75 now matches \bsecrets\b recursively (covering index syntax and toJSON(secrets)), and lines 83-85 apply it to workflow env and to the whole job.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` to both Datadog curl calls. Also consider adding `timeout-minutes: 5` to the notify-release-failure job (around line 1775).
- Around line 1842: Update or remove the comment about the "events YAML block scalar". The Datadog action is gone, and the payload is now built with jq.

In `scripts/check-release-actions.py`:
- Around line 78-87: For in-scope jobs, reject job-level `container:` and `services:` images (or require them to be digest-pinned), and add negative tests for both. If you don't, narrow the "container actions fail closed" claim in docs/release-workflow.md (around line 297) to step-level docker:// references.
- Around line 54: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 32533b43dbdf

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since afabc58
View review run

Review Summary

The new commit changes only documentation. It adds a notify-release-failure section to docs/release-workflow.md, which describes the curl-based Datadog event, the new failure-count metric, and the best-effort behavior. It also removes the outdated sentence that said the Datadog action is commit-pinned. Both match the current release.yaml:1853-1883. The full PR diff was scanned for security and correctness. The PR enforces allowlisted, SHA-pinned actions in privileged and credential-bearing jobs, requires an immutable workflow checkout before local composite actions run, and replaces the Datadog action with curl. No repo-local criteria loaded, so the base criteria were applied. The incremental diff is complete: nothing was dropped or truncated.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) .github/workflows/release.yaml:1872-1883: Neither Datadog curl call sets --connect-timeout/--max-time, although the call at line 330 does. The notify-release-failure job (line 1775) also has no timeout-minutes. A stalled endpoint could keep the job open until GitHub's 6-hour default timeout.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:78-87: check_workflow does not check job-level container: and services: images in credential-bearing jobs. docs/release-workflow.md:297 still says "container actions fail closed", which is true only for step-level docker:// references.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:54: If a step has an empty with: key, step.get("with", {}) returns None, and settings.get(...) then raises AttributeError instead of reporting a policy error. Separately, the comment at release.yaml:1842 about the "events YAML block scalar" is out of date now that the Datadog action has been removed.

Resolved prior findings

  • Fixed: Secret discovery used to match only secrets.. scripts/check-release-actions.py:67-75 now matches \bsecrets\b recursively (covering index syntax and toJSON(secrets)), and lines 83-85 apply it to workflow env and to the whole job.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `.github/workflows/release.yaml`:
- Around line 1872-1883: Add `--connect-timeout 10 --max-time 30` to both Datadog curl calls. Also consider adding `timeout-minutes: 5` to the notify-release-failure job (around line 1775).
- Around line 1842: Update or remove the comment about the "events YAML block scalar". The Datadog action is gone, and the payload is now built with jq.

In `scripts/check-release-actions.py`:
- Around line 78-87: For in-scope jobs, reject job-level `container:` and `services:` images (or require them to be digest-pinned), and add negative tests for both. If you don't, narrow the "container actions fail closed" claim in docs/release-workflow.md (around line 297) to step-level docker:// references.
- Around line 54: Use `settings = step.get("with") or {}` so a step with an empty `with:` key does not crash the checker.

Reviewed commit: 56442bdf6a8d

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 32533b43dbdf

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 56442bd
View review run

Review Summary

The PR pins every remote action in release.yaml to a full commit SHA. It adds a third-party allowlist (tools/privileged-actions.txt) and a CI checker (scripts/check-release-actions.py, run by make test-scripts), and replaces the Datadog action with best-effort curl calls. The new commits in this push:

  • add --connect-timeout 10 --max-time 30 to both Datadog calls and timeout-minutes: 5 to notify-release-failure;
  • make check_local_bootstrap report empty or non-mapping with: blocks instead of crashing;
  • reset bootstrap readiness when a later checkout targets _workflows (paths are normalized);
  • fix the stale YAML block-scalar comment, and narrow the docs so they no longer claim job-level container:/services: are covered.

New tests cover each of these. I scanned the full PR diff for security and correctness issues, and the incremental metadata reports no dropped or truncated paths. No repo-local criteria loaded, so only the base criteria applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) scripts/check-release-actions.py:68: The overwrite guard resets ready only when the checkout path normalizes to exactly _workflows. A later checkout into the workspace root (no path, ., or a ${{ github.workspace }} expression) can replace _workflows/.github/actions/* without being flagged. actions/checkout clears a root that is not a git repo before it fetches.

Resolved prior findings

  • Fixed: Secret discovery that matched only secrets.. references_secrets (scripts/check-release-actions.py:77-85) now matches \bsecrets\b recursively, and check_workflow applies it to the workflow env and the whole job (line 95).
  • Fixed (earlier summary items, checked against current code):
    • Datadog curl timeouts and the job timeout: release.yaml:1792,1873,1881.
    • Crash on an empty with:: check-release-actions.py:55-61, with a test in test_empty_or_non_mapping_inputs_fail_cleanly.
    • Stale block-scalar comment: release.yaml:1843.
  • Addressed by documentation: The job-level container:/services: gap. docs/release-workflow.md:297-299 now states the checker covers only step-level docker:// and defers job-level coverage.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 64-74: The `_workflows` overwrite guard only resets `ready` when `os.path.normpath(path) == "_workflows"`. A later `actions/checkout` with no path, `path: .`, or a `${{ ... }}` expression targets the workspace root. That root is not a git repo, so checkout clears it and can replace `_workflows/.github/actions/*` with untrusted content. Treat a checkout as invalidating the verified bootstrap when its normalized path is `_workflows`, `.`, empty, a path component that is a prefix of `_workflows`, or contains `${{`. Add negative tests in `scripts/test-release-actions.py` for the no-path and `path: .` cases.

Comment thread scripts/check-release-actions.py Outdated
errors.append(f"{location}: checkout path must be a string")
ready = False
continue
if os.path.normpath(path) == "_workflows":

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion (confidence: medium): The overwrite guard only fires when normpath(path) == "_workflows". A later checkout into an ancestor directory is not caught. With no path, or with path: . or path: ${{ github.workspace }}, the checkout targets the workspace root, which is not a git repo, so actions/checkout clears it and fetches the new repo. If that repo contains _workflows/.github/actions/ca-trust-guard/action.yml, it replaces the verified local action while ready stays True. Consider treating any checkout whose normalized path is _workflows, an ancestor of it (., empty), or a ${{ }} expression as one that resets ready.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit ae409b76973a

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 56442bd
View review run

Review Summary

The PR pins every remote action in release.yaml to a full commit SHA. It adds a third-party allowlist (tools/privileged-actions.txt) and a CI checker (scripts/check-release-actions.py, run by make test-scripts), and replaces the Datadog action with best-effort curl calls. The new commits in this push:

  • add --connect-timeout 10 --max-time 30 to both Datadog calls and timeout-minutes: 5 to notify-release-failure;
  • make check_local_bootstrap report empty or non-mapping with: blocks instead of crashing;
  • reset bootstrap readiness when a later checkout targets _workflows (paths are normalized);
  • fix the stale YAML block-scalar comment, and narrow the docs so they no longer claim job-level container:/services: are covered.

New tests cover each of these. I scanned the full PR diff for security and correctness issues, and the incremental metadata reports no dropped or truncated paths. No repo-local criteria loaded, so only the base criteria applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: medium) scripts/check-release-actions.py:68: The overwrite guard resets ready only when the checkout path normalizes to exactly _workflows. A later checkout into the workspace root (no path, ., or a ${{ github.workspace }} expression) can replace _workflows/.github/actions/* without being flagged. actions/checkout clears a root that is not a git repo before it fetches.

Resolved prior findings

  • Fixed: Secret discovery that matched only secrets.. references_secrets (scripts/check-release-actions.py:77-85) now matches \bsecrets\b recursively, and check_workflow applies it to the workflow env and the whole job (line 95).
  • Fixed (earlier summary items, checked against current code):
    • Datadog curl timeouts and the job timeout: release.yaml:1792,1873,1881.
    • Crash on an empty with:: check-release-actions.py:55-61, with a test in test_empty_or_non_mapping_inputs_fail_cleanly.
    • Stale block-scalar comment: release.yaml:1843.
  • Addressed by documentation: The job-level container:/services: gap. docs/release-workflow.md:297-299 now states the checker covers only step-level docker:// and defers job-level coverage.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 64-74: The `_workflows` overwrite guard only resets `ready` when `os.path.normpath(path) == "_workflows"`. A later `actions/checkout` with no path, `path: .`, or a `${{ ... }}` expression targets the workspace root. That root is not a git repo, so checkout clears it and can replace `_workflows/.github/actions/*` with untrusted content. Treat a checkout as invalidating the verified bootstrap when its normalized path is `_workflows`, `.`, empty, a path component that is a prefix of `_workflows`, or contains `${{`. Add negative tests in `scripts/test-release-actions.py` for the no-path and `path: .` cases.

Reviewed commit: 32533b43dbdf

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit ae409b76973a

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 32533b4
View review run

Review Summary

The new commit makes the _workflows overwrite guard in check_local_bootstrap stricter. A later actions/checkout now marks the pinned bootstrap as invalid if its path is missing, empty, ., _workflows or anything under it, a .. escape, an absolute path, or a ${{ }} expression. The commit also adds negative subtests for each of those cases. I scanned the full PR diff for security and correctness: SHA pins, the curl-based Datadog reporting with its timeouts, and the checker and its tests. I found no blocking issues. No repo-local criteria loaded, so only the base criteria were applied. The incremental artifact was complete, with no dropped paths and no truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: low) scripts/check-release-actions.py:68-70: The path normalization follows POSIX rules only. goreleaser-windows runs on windows-latest, so a checkout path like _workflows\.github, .\ or C:\... would get past the overwrite guard. Exploiting this requires a reviewed change to release.yaml, so it is a hardening gap rather than a live hole.

Resolved prior findings

  • Fixed: secret discovery matched only secrets. (prior thread). references_secrets (scripts/check-release-actions.py:82-90) now matches \bsecrets\b recursively. This covers index syntax and toJSON(secrets). Line 100 applies it to the whole job and to the workflow-level env.
  • Fixed: the overwrite guard missed root and path-escape checkouts (earlier summary finding). scripts/check-release-actions.py:68-70 now covers these cases, and the new subtests in scripts/test-release-actions.py:76-84 cover the missing-path, ., empty, .., absolute and expression cases.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 68-70: The `_workflows` overwrite guard normalizes checkout paths with POSIX `os.path.normpath`. The goreleaser-windows job runs on windows-latest, where paths such as `_workflows\.github`, `.\` or `C:\x` would overwrite the verified tree without resetting `ready`. Before normalizing, replace backslashes with `/`, and also treat drive-letter paths (regex `^[A-Za-z]:`) as absolute. Add matching subtests in `scripts/test-release-actions.py` `test_later_checkout_cannot_overwrite_verified_workflows`.

Comment thread scripts/check-release-actions.py Outdated
Comment on lines +68 to +70
rel = os.path.normpath(str(path or "."))
if (rel in (".", "_workflows") or rel.startswith("_workflows/")
or rel.startswith("..") or os.path.isabs(rel) or "${{" in str(path)):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion (confidence: low): os.path.normpath uses POSIX rules here, but goreleaser-windows runs on windows-latest. On that runner a checkout path such as _workflows\.github, .\, or C:\... would still overwrite the verified tree, yet none of those values trip this guard. Consider normalizing with path.replace("\\", "/") before normpath, and also treating drive-letter paths as absolute.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit ae409b76973a

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 32533b4
View review run

Review Summary

The new commit makes the _workflows overwrite guard in check_local_bootstrap stricter. A later actions/checkout now marks the pinned bootstrap as invalid if its path is missing, empty, ., _workflows or anything under it, a .. escape, an absolute path, or a ${{ }} expression. The commit also adds negative subtests for each of those cases. I scanned the full PR diff for security and correctness: SHA pins, the curl-based Datadog reporting with its timeouts, and the checker and its tests. I found no blocking issues. No repo-local criteria loaded, so only the base criteria were applied. The incremental artifact was complete, with no dropped paths and no truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: low) scripts/check-release-actions.py:68-70: The path normalization follows POSIX rules only. goreleaser-windows runs on windows-latest, so a checkout path like _workflows\.github, .\ or C:\... would get past the overwrite guard. Exploiting this requires a reviewed change to release.yaml, so it is a hardening gap rather than a live hole.

Resolved prior findings

  • Fixed: secret discovery matched only secrets. (prior thread). references_secrets (scripts/check-release-actions.py:82-90) now matches \bsecrets\b recursively. This covers index syntax and toJSON(secrets). Line 100 applies it to the whole job and to the workflow-level env.
  • Fixed: the overwrite guard missed root and path-escape checkouts (earlier summary finding). scripts/check-release-actions.py:68-70 now covers these cases, and the new subtests in scripts/test-release-actions.py:76-84 cover the missing-path, ., empty, .., absolute and expression cases.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 68-70: The `_workflows` overwrite guard normalizes checkout paths with POSIX `os.path.normpath`. The goreleaser-windows job runs on windows-latest, where paths such as `_workflows\.github`, `.\` or `C:\x` would overwrite the verified tree without resetting `ready`. Before normalizing, replace backslashes with `/`, and also treat drive-letter paths (regex `^[A-Za-z]:`) as absolute. Add matching subtests in `scripts/test-release-actions.py` `test_later_checkout_cannot_overwrite_verified_workflows`.

Reviewed commit: ae409b76973a

@github-actions github-actions 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.

No blocking issues found — see the full review report

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit a72f2907254d

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: full
View review run

Review Summary

This PR pins every remote uses: in release.yaml to a 40-character SHA. I checked every reference, and all of them are pinned now. It adds scripts/check-release-actions.py, which runs in CI through make test-scripts (using the apt-installed kislyuk yq set up in ci.yaml). The checker enforces a third-party allowlist plus SHA pins in the listed privileged jobs and in any job that has OIDC or references secrets. It also requires an immutable _workflows checkout before local composites run, and it checks the two composite implementations. The masci/datadog action is replaced by jq-built JSON sent with curl. These calls use timeouts, || true, and continue-on-error, so a reporting failure can't fail the job. The event fields stay the same; the only change to the payload source is that the repository field now comes from github.repository, which has the same value. I scanned the full PR diff for security and correctness issues. No repo-local criteria loaded, so I applied the base criteria only.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: low) scripts/check-release-actions.py:69-71: The _workflows overwrite guard uses POSIX os.path.normpath. On the windows-latest job, paths like _workflows\.github, .\ or C:\x get past it. Exploiting this needs a reviewed edit to release.yaml, so it's a hardening gap.
  • New (confidence: medium) scripts/check-release-actions.py:101: Non-credential jobs such as determine-workflows-ref and release-preflight are only checked if they gain OIDC or a secret reference. They can't leak credentials, but they also run local composites from _workflows, so a mutable action or checkout added there would pass CI unnoticed. Consider adding them to PRIVILEGED_JOBS, or applying check_steps to every job.

Resolved prior findings

  • Fixed: secret discovery used to match only secrets.. references_secrets (scripts/check-release-actions.py:83-91) now matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). Line 101 applies it to the job and to the workflow-level env, and scripts/test-release-actions.py:42-56 covers these cases.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 69-71: The checkout-path overwrite guard normalizes with POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Before normalizing, replace backslashes with "/", and treat drive-letter paths (regex ^[A-Za-z]:) as absolute, so that `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these paths to test_later_checkout_cannot_overwrite_verified_workflows in scripts/test-release-actions.py.
- Around line 101: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked, even though they run local composites from `_workflows`. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in them cannot drift.

Reviewed commit: ae409b76973a

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit a72f2907254d

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since ae409b7
View review run

Review Summary

The new commit only changes wording. It rewrites the continue-on-error comment on the Datadog step (.github/workflows/release.yaml:1853) and the matching paragraph in docs/release-workflow.md:153-154 to say reporting is best-effort; behavior is unchanged.

I also re-scanned the full PR diff for security and correctness. It covers SHA pins for every remaining remote action, the tools/privileged-actions.txt allowlist, scripts/check-release-actions.py (run against the real repo by scripts/test-release-actions.py:29 through make test-scripts in ci.yaml), and the curl replacement for the Datadog action. The curl replacement passes untrusted values through env and jq --arg with no shell or expression interpolation, sets connect and total timeouts, and keeps the existing event fields. No new issues were found. No repo-local criteria loaded, so only the base criteria were applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: low) scripts/check-release-actions.py:68-70: The checkout-path overwrite guard uses POSIX os.path.normpath. On the windows-latest job, paths like _workflows\.github, .\ or C:\x still get past it. Exploiting this needs a reviewed edit to release.yaml, so it is a hardening gap. The PR body explicitly defers this as a shared-parity follow-up.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: Jobs without credentials, such as determine-workflows-ref and release-preflight, are only checked if they gain OIDC or a secret reference. They also run local composites from _workflows, so an unpinned action or checkout added to them would still pass CI.

Resolved prior findings

  • Fixed: the secrets.-substring discovery thread (outdated). references_secrets (scripts/check-release-actions.py:82-90) now matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). Line 99-100 applies it to the job and to the workflow-level env.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 68-70: The checkout-path overwrite guard normalizes with POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Before normalizing, replace backslashes with "/", and treat drive-letter paths (regex ^[A-Za-z]:) as absolute, so that `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these paths to the overwrite tests in scripts/test-release-actions.py.
- Around line 100: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked, even though they run local composites from `_workflows`. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in them cannot drift.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 9742d3dd7052

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since ae409b7
View review run

Review Summary

The new commit only changes wording. It rewrites the continue-on-error comment on the Datadog step (.github/workflows/release.yaml:1853) and the matching paragraph in docs/release-workflow.md:153-154 to say reporting is best-effort; behavior is unchanged.

I also re-scanned the full PR diff for security and correctness. It covers SHA pins for every remaining remote action, the tools/privileged-actions.txt allowlist, scripts/check-release-actions.py (run against the real repo by scripts/test-release-actions.py:29 through make test-scripts in ci.yaml), and the curl replacement for the Datadog action. The curl replacement passes untrusted values through env and jq --arg with no shell or expression interpolation, sets connect and total timeouts, and keeps the existing event fields. No new issues were found. No repo-local criteria loaded, so only the base criteria were applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: low) scripts/check-release-actions.py:68-70: The checkout-path overwrite guard uses POSIX os.path.normpath. On the windows-latest job, paths like _workflows\.github, .\ or C:\x still get past it. Exploiting this needs a reviewed edit to release.yaml, so it is a hardening gap. The PR body explicitly defers this as a shared-parity follow-up.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: Jobs without credentials, such as determine-workflows-ref and release-preflight, are only checked if they gain OIDC or a secret reference. They also run local composites from _workflows, so an unpinned action or checkout added to them would still pass CI.

Resolved prior findings

  • Fixed: the secrets.-substring discovery thread (outdated). references_secrets (scripts/check-release-actions.py:82-90) now matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). Line 99-100 applies it to the job and to the workflow-level env.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 68-70: The checkout-path overwrite guard normalizes with POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Before normalizing, replace backslashes with "/", and treat drive-letter paths (regex ^[A-Za-z]:) as absolute, so that `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these paths to the overwrite tests in scripts/test-release-actions.py.
- Around line 100: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked, even though they run local composites from `_workflows`. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in them cannot drift.

Reviewed commit: a72f2907254d

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 9742d3dd7052

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since a72f290
View review run

Review Summary

The new commits drop the curl-based Datadog event and failure-count metric and restore main's masci/datadog@93a16378… step. I diffed the step against main: the with: block and annotation plumbing match exactly. The only changes in that job against main are the added timeout-minutes: 5 and step-level continue-on-error: true.

To admit the action, check_steps now also accepts an exact owner/repo@sha allowlist row (scripts/check-release-actions.py:43). An exact row cannot allowlist other refs of that repo, because name never contains @. The tests confirm this: v1 and other SHAs of masci/datadog are still rejected. The curl fixture tests were replaced with key-custody and negative-control checks, which rely on the existing top-level env: and the CI-installed Python yq.

I scanned the full PR diff (SHA pins, Makefile hook, docs, checker, and tests) for security and correctness and found no new issues. No repo-local criteria loaded, so only the base criteria applied. Incremental metadata reports no dropped or truncated paths.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: low) scripts/check-release-actions.py:68-70: The checkout-path guard normalizes with POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Paths like _workflows\.github, .\ or C:\x therefore are not treated as overwriting the workflow checkout. This is a hardening gap, since exploiting it needs a reviewed release.yaml edit.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: Jobs without credentials (determine-workflows-ref, release-preflight) are only checked if they gain OIDC or a secret reference. An unpinned action added to them would pass CI.

Resolved prior findings

  • Fixed: the outdated thread about secrets.-substring discovery. references_secrets (scripts/check-release-actions.py:82-90) matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). It is applied to both the job and the workflow env at lines 99-100.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 68-70: The checkout-path overwrite guard uses POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Before normalizing, replace backslashes with "/", and treat drive-letter paths (^[A-Za-z]:) as absolute, so that `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these cases to scripts/test-release-actions.py.
- Around line 100: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked, although they run local composites from `_workflows`. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in them cannot drift.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit d20de4fb801b

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since a72f290
View review run

Review Summary

The new commits drop the curl-based Datadog event and failure-count metric and restore main's masci/datadog@93a16378… step. I diffed the step against main: the with: block and annotation plumbing match exactly. The only changes in that job against main are the added timeout-minutes: 5 and step-level continue-on-error: true.

To admit the action, check_steps now also accepts an exact owner/repo@sha allowlist row (scripts/check-release-actions.py:43). An exact row cannot allowlist other refs of that repo, because name never contains @. The tests confirm this: v1 and other SHAs of masci/datadog are still rejected. The curl fixture tests were replaced with key-custody and negative-control checks, which rely on the existing top-level env: and the CI-installed Python yq.

I scanned the full PR diff (SHA pins, Makefile hook, docs, checker, and tests) for security and correctness and found no new issues. No repo-local criteria loaded, so only the base criteria applied. Incremental metadata reports no dropped or truncated paths.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: low) scripts/check-release-actions.py:68-70: The checkout-path guard normalizes with POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Paths like _workflows\.github, .\ or C:\x therefore are not treated as overwriting the workflow checkout. This is a hardening gap, since exploiting it needs a reviewed release.yaml edit.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: Jobs without credentials (determine-workflows-ref, release-preflight) are only checked if they gain OIDC or a secret reference. An unpinned action added to them would pass CI.

Resolved prior findings

  • Fixed: the outdated thread about secrets.-substring discovery. references_secrets (scripts/check-release-actions.py:82-90) matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). It is applied to both the job and the workflow env at lines 99-100.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 68-70: The checkout-path overwrite guard uses POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Before normalizing, replace backslashes with "/", and treat drive-letter paths (^[A-Za-z]:) as absolute, so that `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these cases to scripts/test-release-actions.py.
- Around line 100: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked, although they run local composites from `_workflows`. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in them cannot drift.

Reviewed commit: 9742d3dd7052

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit d20de4fb801b

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 9742d3d
View review run

Review Summary

The PR pins every remote action in release.yaml to a full commit SHA and adds tools/privileged-actions.txt as a third-party allowlist. It adds scripts/check-release-actions.py, run by make test-scripts, which checks privileged and credential-bearing jobs plus the two local composite actions. A preceding pinned _workflows checkout is required before local actions run. The Datadog notification step is now best-effort with a 5-minute job timeout.

This push (d20de4f) changes one line of docs/release-workflow.md. The masci/datadog re-pin note now says re-pinning is manual, with no Renovate tracking for workflow SHAs. That is accurate: renovate.json enabledManagers contains only dockerfile and custom.regex. The incremental artifact was complete (no dropped paths, no truncation).

I scanned the full PR diff for security and correctness and found no blocking issues. No repo-local criteria loaded, so only the base criteria were applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: high, low impact) tools/privileged-actions.txt:10: The re-pin comment still says "Renovate PRs are not auto-merged". That contradicts the doc line this push corrected, since Renovate does not track action SHAs. scripts/test-release-actions.py:150 still asserts renovate.json automerge as if it protected this pin. It does not protect it.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:68: The checkout-path overwrite guard uses POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Paths such as _workflows\.github, .\ or C:\x are therefore not treated as overwriting the workflow checkout. This is hardening only: exploiting it needs a reviewed release.yaml edit. The code is unchanged in this push.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: Jobs without credentials (determine-workflows-ref, release-preflight) are checked only if they gain OIDC or a secret reference. An unpinned action added to them would pass CI. The code is unchanged in this push.

Resolved prior findings

  • The outdated thread about secrets.-substring discovery is fixed. references_secrets (scripts/check-release-actions.py:82-90) matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). It is applied to both the job and the workflow env (line 99-100), and tests cover it (scripts/test-release-actions.py test_new_credential_jobs_cannot_escape_inventory).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `tools/privileged-actions.txt`:
- Around line 10: The comment says "Renovate PRs are not auto-merged", but Renovate does not track action SHAs (renovate.json enabledManagers has no github-actions). Reword it to match docs/release-workflow.md: "Re-pin review: diff the action's tag-to-SHA source; re-pinning is manual (no Renovate tracking for workflow SHAs)."

In `scripts/test-release-actions.py`:
- Around line 150: The assertion that renovate.json automerge is false does not protect the masci/datadog pin. Remove it, or replace it with a check that renovate.json does not enable the github-actions manager, if that is the intended invariant.

In `scripts/check-release-actions.py`:
- Around line 68: Before normalizing the checkout path, replace backslashes with "/" and treat drive-letter paths (^[A-Za-z]:) as absolute. Then `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these cases to scripts/test-release-actions.py.
- Around line 100: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in those jobs cannot drift.

Comment thread tools/privileged-actions.txt Outdated
docker/setup-qemu-action
docker/setup-buildx-action
# Notification only; custody: DATADOG_API_KEY (Datadog org write key, non-signing).
# Re-pin review: diff the action's tag-to-SHA source; Renovate PRs are not auto-merged.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: This push changed the docs to say re-pinning is manual and no Renovate tracking exists for workflow SHAs. That matches renovate.json, whose enabledManagers has no github-actions. This comment still says "Renovate PRs are not auto-merged", which suggests Renovate opens re-pin PRs. Reword it to match the docs, e.g. "re-pinning is manual (no Renovate tracking for workflow SHAs)".

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 253c7f4718df

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 3 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 9742d3d
View review run

Review Summary

The PR pins every remote action in release.yaml to a full commit SHA and adds tools/privileged-actions.txt as a third-party allowlist. It adds scripts/check-release-actions.py, run by make test-scripts, which checks privileged and credential-bearing jobs plus the two local composite actions. A preceding pinned _workflows checkout is required before local actions run. The Datadog notification step is now best-effort with a 5-minute job timeout.

This push (d20de4f) changes one line of docs/release-workflow.md. The masci/datadog re-pin note now says re-pinning is manual, with no Renovate tracking for workflow SHAs. That is accurate: renovate.json enabledManagers contains only dockerfile and custom.regex. The incremental artifact was complete (no dropped paths, no truncation).

I scanned the full PR diff for security and correctness and found no blocking issues. No repo-local criteria loaded, so only the base criteria were applied.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: high, low impact) tools/privileged-actions.txt:10: The re-pin comment still says "Renovate PRs are not auto-merged". That contradicts the doc line this push corrected, since Renovate does not track action SHAs. scripts/test-release-actions.py:150 still asserts renovate.json automerge as if it protected this pin. It does not protect it.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:68: The checkout-path overwrite guard uses POSIX os.path.normpath, but goreleaser-windows runs on windows-latest. Paths such as _workflows\.github, .\ or C:\x are therefore not treated as overwriting the workflow checkout. This is hardening only: exploiting it needs a reviewed release.yaml edit. The code is unchanged in this push.
  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: Jobs without credentials (determine-workflows-ref, release-preflight) are checked only if they gain OIDC or a secret reference. An unpinned action added to them would pass CI. The code is unchanged in this push.

Resolved prior findings

  • The outdated thread about secrets.-substring discovery is fixed. references_secrets (scripts/check-release-actions.py:82-90) matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). It is applied to both the job and the workflow env (line 99-100), and tests cover it (scripts/test-release-actions.py test_new_credential_jobs_cannot_escape_inventory).
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `tools/privileged-actions.txt`:
- Around line 10: The comment says "Renovate PRs are not auto-merged", but Renovate does not track action SHAs (renovate.json enabledManagers has no github-actions). Reword it to match docs/release-workflow.md: "Re-pin review: diff the action's tag-to-SHA source; re-pinning is manual (no Renovate tracking for workflow SHAs)."

In `scripts/test-release-actions.py`:
- Around line 150: The assertion that renovate.json automerge is false does not protect the masci/datadog pin. Remove it, or replace it with a check that renovate.json does not enable the github-actions manager, if that is the intended invariant.

In `scripts/check-release-actions.py`:
- Around line 68: Before normalizing the checkout path, replace backslashes with "/" and treat drive-letter paths (^[A-Za-z]:) as absolute. Then `_workflows\.github`, `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these cases to scripts/test-release-actions.py.
- Around line 100: Jobs without OIDC or secrets (determine-workflows-ref, release-preflight) are not checked. Either add them to PRIVILEGED_JOBS or run check_steps/check_local_bootstrap on every job, so action pinning in those jobs cannot drift.

Reviewed commit: d20de4fb801b

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 253c7f4718df

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since d20de4f
View review run

Review Summary

This PR pins every remote action in release.yaml to a full commit SHA and adds a reviewed third-party allowlist (tools/privileged-actions.txt). It also adds scripts/check-release-actions.py, which applies that policy to the privileged jobs, to any job that has OIDC or references secrets, and to both local composite actions.

The new commit only touches documentation and tests:

  • It rewrites the masci/datadog re-pin comment to say re-pinning is manual.
  • It removes the renovate.json automerge assertion from the notification test.

I scanned the full PR diff for security and correctness, including every changed uses: pin, the permission and secret discovery, and the notification job's continue-on-error and timeout-minutes. No repo-local criteria were loaded, so only the base criteria applied. The incremental artifact is complete: no dropped paths and no truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: The policy only checks a job if it is in PRIVILEGED_JOBS or gains OIDC or a secret reference. Credential-free jobs such as determine-workflows-ref and release-preflight are never checked, so an unpinned action added to them would still pass CI. Hardening only; the code is unchanged in this push.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:68: The checkout-path overwrite guard uses POSIX os.path.normpath, but goreleaser-windows runs on Windows. Paths such as _workflows\.github, .\ or C:\x therefore don't reset readiness. The PR body defers this as a shared follow-up, and it is unchanged in this push.

Resolved prior findings

  • Fixed: the stale "Renovate PRs are not auto-merged" re-pin comment. tools/privileged-actions.txt:10 now says re-pinning is manual, matching docs/release-workflow.md:159. The misleading renovate.json automerge assertion was removed from scripts/test-release-actions.py (around line 150). The unrelated automerge check in scripts/test-check-image-locks.py:162 is correctly left in place.
  • Fixed: secret discovery used to match only the secrets. substring. references_secrets (scripts/check-release-actions.py:82-90) now matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). It is applied to both the workflow-level and job-level values (lines 99-100) and has tests.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 100: Jobs that are not in PRIVILEGED_JOBS and have no OIDC or secret
  reference (for example determine-workflows-ref and release-preflight) skip
  check_steps entirely, so an unpinned or unallowlisted action added to them passes CI.
  Run check_steps on every job in release.yaml, or at least require full-SHA pins for
  all jobs. Add a negative test in scripts/test-release-actions.py.
- Around line 68: Before normalizing the checkout path, replace backslashes with "/"
  and treat drive-letter paths (^[A-Za-z]:) as absolute. Then `_workflows\.github`,
  `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these
  cases to scripts/test-release-actions.py.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit cb85b31c557b

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since d20de4f
View review run

Review Summary

This PR pins every remote action in release.yaml to a full commit SHA and adds a reviewed third-party allowlist (tools/privileged-actions.txt). It also adds scripts/check-release-actions.py, which applies that policy to the privileged jobs, to any job that has OIDC or references secrets, and to both local composite actions.

The new commit only touches documentation and tests:

  • It rewrites the masci/datadog re-pin comment to say re-pinning is manual.
  • It removes the renovate.json automerge assertion from the notification test.

I scanned the full PR diff for security and correctness, including every changed uses: pin, the permission and secret discovery, and the notification job's continue-on-error and timeout-minutes. No repo-local criteria were loaded, so only the base criteria applied. The incremental artifact is complete: no dropped paths and no truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • Prior — still present (confidence: medium) scripts/check-release-actions.py:100: The policy only checks a job if it is in PRIVILEGED_JOBS or gains OIDC or a secret reference. Credential-free jobs such as determine-workflows-ref and release-preflight are never checked, so an unpinned action added to them would still pass CI. Hardening only; the code is unchanged in this push.
  • Prior — still present (confidence: low) scripts/check-release-actions.py:68: The checkout-path overwrite guard uses POSIX os.path.normpath, but goreleaser-windows runs on Windows. Paths such as _workflows\.github, .\ or C:\x therefore don't reset readiness. The PR body defers this as a shared follow-up, and it is unchanged in this push.

Resolved prior findings

  • Fixed: the stale "Renovate PRs are not auto-merged" re-pin comment. tools/privileged-actions.txt:10 now says re-pinning is manual, matching docs/release-workflow.md:159. The misleading renovate.json automerge assertion was removed from scripts/test-release-actions.py (around line 150). The unrelated automerge check in scripts/test-check-image-locks.py:162 is correctly left in place.
  • Fixed: secret discovery used to match only the secrets. substring. references_secrets (scripts/check-release-actions.py:82-90) now matches \bsecrets\b recursively, which covers index syntax and toJSON(secrets). It is applied to both the workflow-level and job-level values (lines 99-100) and has tests.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `scripts/check-release-actions.py`:
- Around line 100: Jobs that are not in PRIVILEGED_JOBS and have no OIDC or secret
  reference (for example determine-workflows-ref and release-preflight) skip
  check_steps entirely, so an unpinned or unallowlisted action added to them passes CI.
  Run check_steps on every job in release.yaml, or at least require full-SHA pins for
  all jobs. Add a negative test in scripts/test-release-actions.py.
- Around line 68: Before normalizing the checkout path, replace backslashes with "/"
  and treat drive-letter paths (^[A-Za-z]:) as absolute. Then `_workflows\.github`,
  `.\` and `C:\x` reset `ready` unless they are the exact pinned checkout. Add these
  cases to scripts/test-release-actions.py.

Reviewed commit: 253c7f4718df

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit cb85b31c557b

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 253c7f4
View review run

Review Summary

The new commit cb85b31 removes the policy checker, the allowlist file, its tests, and the make test-scripts entry, and rewrites the docs as a single custody table. Against main, the PR now does three things in release.yaml:

  • Replaces every mutable @vN action ref with a commit SHA.
  • Adds timeout-minutes: 5 to notify-release-failure.
  • Adds continue-on-error: true to the Datadog step.

I checked all seven new SHAs against upstream. Each one matches the commit its # vN comment names, including the annotated configure-aws-credentials v5 tag (dereferenced to 61815dc). Every uses: in release.yaml and the local composites is now SHA-pinned or local. I scanned the full PR diff for security and correctness issues. No repo-local criteria loaded, so I applied only the base criteria. The incremental artifact is complete, with no dropped paths or truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: high) The PR's stated purpose doesn't match the diff. The title and body still claim CI enforcement ("make action-policy drift fail repository CI", check-release-actions.py PASS, negative controls). This push deleted that checker, so nothing stops a future unpinned action from merging. Update the title and description, or restore the enforcement. Inline comment on docs/release-workflow.md:281.
  • New (confidence: medium) docs/release-workflow.md:293: "event-only (added metric removed)" refers to a metric that existed only partway through this PR. Main has none, so the note confuses readers of the merged docs.

Resolved prior findings

  • Obsolete: the secrets. substring discovery thread on scripts/check-release-actions.py. Two summary-only notes on the same file are also obsolete: credential-free jobs going unchecked, and POSIX normpath on Windows. This push deleted the checker entirely; the replacement is static SHA pins in .github/workflows/release.yaml.
  • Obsolete: the Renovate re-pin wording thread on tools/privileged-actions.txt. The file is deleted. The surviving text at docs/release-workflow.md:293 says re-pinning is manual, which matches renovate.json.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In the PR title and description:
- The latest commit deleted scripts/check-release-actions.py, scripts/test-release-actions.py and tools/privileged-actions.txt, and removed the test from the Makefile. The PR now only SHA-pins actions in .github/workflows/release.yaml, adds a 5-minute timeout and continue-on-error to the Datadog notification, and adds a custody table to docs/release-workflow.md. Rewrite the title (e.g. "Pin release workflow actions to commit SHAs") and the body so they no longer claim a CI-enforced allowlist, checker evidence, or negative controls. Alternatively, restore the checker if enforcement is still intended.

In `docs/release-workflow.md`:
- Around line 293: Remove the parenthetical "(added metric removed)". No failure-count metric exists on main or in the merged workflow; keep only "event-only".

@gontzess gontzess changed the title Enforce pinned action allowlist in privileged release jobs Pin privileged release actions and document custody Oct 22, 2026
Comment thread docs/release-workflow.md

### Pinned Release Action Custody

Review and organization Actions policy own action drift. Custody below describes

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion (confidence: high): This push deleted scripts/check-release-actions.py, tools/privileged-actions.txt and scripts/test-release-actions.py, and dropped the test from make test-scripts. Repository CI no longer enforces the pins. The PR title ("Enforce pinned action allowlist") and body ("make action-policy drift fail repository CI", the evidence list, the negative controls) still describe that checker. Please update the title and description to match what this PR does now: one-time SHA pins plus documentation, with drift left to review and org Actions policy.

Comment thread docs/release-workflow.md Outdated
| aws-actions/configure-aws-credentials | `61815dcd50bd041e203e49132bacad1fd04d2708` | goreleaser-binaries, goreleaser-windows, goreleaser-docker, publish-release-manifest, verify-release | Exchanges job OIDC for scoped AWS role credentials. |
| aws-actions/amazon-ecr-login | `03f1aad4c6c7ffd436567f42f9384779290529bd` | goreleaser-docker, verify-release | Job AWS credentials; registry authentication for publishing or pulling. |
| docker/setup-qemu-action | `c7c53464625b32c7a7e944ae62b3e17d2b600130` | goreleaser-docker | Digest-pinned binfmt setup in an OIDC-enabled job; no explicit secret input. |
| masci/datadog | `93a16378298f4e1980f13f6b412c0b8e66b96185` | notify-release-failure | `DATADOG_API_KEY` (Datadog org write key), only step `with: api-key`; non-signing, notification only. Best-effort (`continue-on-error: true`), five-minute job; event-only (added metric removed). Re-pin review: diff the action's tag-to-SHA source; re-pinning is manual (no Renovate tracking exists for workflow SHAs). |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion (confidence: medium): "event-only (added metric removed)" describes an intermediate state of this PR. Neither main nor the merged workflow has a failure-count metric, so readers of the merged docs won't know what this refers to. Consider shortening it to "event-only".

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 6583b6511131

General PR Review: Enforce pinned action allowlist in privileged release jobs

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since 253c7f4
View review run

Review Summary

The new commit cb85b31 removes the policy checker, the allowlist file, its tests, and the make test-scripts entry, and rewrites the docs as a single custody table. Against main, the PR now does three things in release.yaml:

  • Replaces every mutable @vN action ref with a commit SHA.
  • Adds timeout-minutes: 5 to notify-release-failure.
  • Adds continue-on-error: true to the Datadog step.

I checked all seven new SHAs against upstream. Each one matches the commit its # vN comment names, including the annotated configure-aws-credentials v5 tag (dereferenced to 61815dc). Every uses: in release.yaml and the local composites is now SHA-pinned or local. I scanned the full PR diff for security and correctness issues. No repo-local criteria loaded, so I applied only the base criteria. The incremental artifact is complete, with no dropped paths or truncation.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • New (confidence: high) The PR's stated purpose doesn't match the diff. The title and body still claim CI enforcement ("make action-policy drift fail repository CI", check-release-actions.py PASS, negative controls). This push deleted that checker, so nothing stops a future unpinned action from merging. Update the title and description, or restore the enforcement. Inline comment on docs/release-workflow.md:281.
  • New (confidence: medium) docs/release-workflow.md:293: "event-only (added metric removed)" refers to a metric that existed only partway through this PR. Main has none, so the note confuses readers of the merged docs.

Resolved prior findings

  • Obsolete: the secrets. substring discovery thread on scripts/check-release-actions.py. Two summary-only notes on the same file are also obsolete: credential-free jobs going unchecked, and POSIX normpath on Windows. This push deleted the checker entirely; the replacement is static SHA pins in .github/workflows/release.yaml.
  • Obsolete: the Renovate re-pin wording thread on tools/privileged-actions.txt. The file is deleted. The surviving text at docs/release-workflow.md:293 says re-pinning is manual, which matches renovate.json.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In the PR title and description:
- The latest commit deleted scripts/check-release-actions.py, scripts/test-release-actions.py and tools/privileged-actions.txt, and removed the test from the Makefile. The PR now only SHA-pins actions in .github/workflows/release.yaml, adds a 5-minute timeout and continue-on-error to the Datadog notification, and adds a custody table to docs/release-workflow.md. Rewrite the title (e.g. "Pin release workflow actions to commit SHAs") and the body so they no longer claim a CI-enforced allowlist, checker evidence, or negative controls. Alternatively, restore the checker if enforcement is still intended.

In `docs/release-workflow.md`:
- Around line 293: Remove the parenthetical "(added metric removed)". No failure-count metric exists on main or in the merged workflow; keep only "event-only".

Reviewed commit: cb85b31c557b

@github-actions github-actions 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.

No blocking issues found — see the full review report

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Superseded — see the current review report for commit 6583b6511131

General PR Review: Pin privileged release actions and document custody

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since cb85b31
View review run

Review Summary

The PR does three things. It swaps every remaining mutable @vN remote action ref in .github/workflows/release.yaml for a 40-char commit SHA, which covers checkout, configure-aws-credentials, amazon-ecr-login, import-codesign-certs, setup-qemu, and github-script. It adds timeout-minutes: 5 to notify-release-failure and continue-on-error: true to the Datadog step. It adds a custody table to docs/release-workflow.md.

The new commit only rewords the Datadog row of that table: it drops "(added metric removed)" and leaves "event-only".

I scanned the full PR diff for security and correctness. Every uses: in release.yaml is either SHA-pinned or a local ./_workflows/... composite. The table's job and custody claims match the workflow: every checkout sets persist-credentials: false, and cosign-installer runs in exactly the five jobs listed. No repo-local criteria loaded, so only the base criteria were applied.

Coverage gap: I checked that each pin is well-formed and placed where the table says. I did not independently confirm that each SHA matches the upstream tag in its trailing comment.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

Resolved prior findings

  • Fixed: the intent-vs-diff mismatch. The title and body no longer claim CI enforcement. The body now says "This change adds no per-repository action lint" and that review and org Actions policy own drift, which matches the diff and docs/release-workflow.md:281-282.

  • Fixed: the stale "(added metric removed)" wording. docs/release-workflow.md:293 now reads "event-only".

  • Obsolete: both outdated threads, plus the related summary-only notes, are moot:

    • the secrets. substring discovery thread on scripts/check-release-actions.py
    • the Renovate re-pin thread on tools/privileged-actions.txt

    Both files were deleted. Static SHA pins in release.yaml replace them, and docs/release-workflow.md:293 says re-pinning is manual.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

General PR Review: Pin privileged release actions and document custody

Blocking Issues: 0 | Suggestions: 0 | Threads Resolved: 0
Criteria: Criteria status: none loaded - .claude/skills/ci-review.md was not found at trusted base ad85b5b02764.
Review mode: incremental since cb85b31
View review run

Review Summary

The PR does three things. It swaps every remaining mutable @vN remote action ref in .github/workflows/release.yaml for a 40-char commit SHA, which covers checkout, configure-aws-credentials, amazon-ecr-login, import-codesign-certs, setup-qemu, and github-script. It adds timeout-minutes: 5 to notify-release-failure and continue-on-error: true to the Datadog step. It adds a custody table to docs/release-workflow.md.

The new commit only rewords the Datadog row of that table: it drops "(added metric removed)" and leaves "event-only".

I scanned the full PR diff for security and correctness. Every uses: in release.yaml is either SHA-pinned or a local ./_workflows/... composite. The table's job and custody claims match the workflow: every checkout sets persist-credentials: false, and cosign-installer runs in exactly the five jobs listed. No repo-local criteria loaded, so only the base criteria were applied.

Coverage gap: I checked that each pin is well-formed and placed where the table says. I did not independently confirm that each SHA matches the upstream tag in its trailing comment.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

None.

Resolved prior findings

  • Fixed: the intent-vs-diff mismatch. The title and body no longer claim CI enforcement. The body now says "This change adds no per-repository action lint" and that review and org Actions policy own drift, which matches the diff and docs/release-workflow.md:281-282.

  • Fixed: the stale "(added metric removed)" wording. docs/release-workflow.md:293 now reads "event-only".

  • Obsolete: both outdated threads, plus the related summary-only notes, are moot:

    • the secrets. substring discovery thread on scripts/check-release-actions.py
    • the Renovate re-pin thread on tools/privileged-actions.txt

    Both files were deleted. Static SHA pins in release.yaml replace them, and docs/release-workflow.md:293 says re-pinning is manual.


Reviewed commit: 6583b6511131

@github-actions github-actions 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.

No blocking issues found — see the full review report

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.

1 participant