Conformance Check Failure
Check ID: SEC-005
Severity: HIGH
Category: Security
Problem Description
scripts/check-safe-outputs-conformance.sh flagged 14 files under actions/setup/js/ for supporting a target-repo/targetRepo/target_repo field without a matching allowlist check (allowed.*[Rr]epos|validateTargetRepo|checkAllowedRepo). The safe-outputs specification (Section on Cross-Repository Validation, docs/src/content/docs/specs/safe-outputs-specification.md around line 648) states: "All handlers with target-repo parameter validate against allowlists; operations to non-allowlisted repos are rejected with E004."
Investigation shows all 14 matches come from the internal work-queue "Claim adapter" subsystem (not the user-facing cross-repo safe outputs like create_issue's resolveTargetRepoConfig/allowedRepos, which already pass this check). Two distinct root causes were found:
-
Checker false-positive on test fixtures — 5 of the 14 files are self-contained Node test scripts (using node:assert/strict) that just happen to be named *_checks.cjs instead of *_test.cjs / *.test.cjs, so the script's test-file exclusion ([[ "$handler" =~ test ]]) misses them:
actions/setup/js/work_queue_claim_adapter_checks.cjs
actions/setup/js/work_queue_delivery_proof_checks.cjs
actions/setup/js/work_queue_git_tree_adapter_checks.cjs
actions/setup/js/work_queue_graphql_adapter_checks.cjs
actions/setup/js/work_queue_script_preparation_checks.cjs
-
Genuinely production code using a different authorization mechanism — the remaining 9 files read adapter["target-repo"] after it has already been validated once, upstream, in actions/setup/js/work_queue_claim_adapters.cjs (closed() + a regex check at line 119: "Trusted Claim adapter requires a fixed repository scope"), and every write is additionally gated at effect-time by assertClaimAuthorized() (actions/setup/js/work_queue_claim_scope.cjs:180), which requires a per-Claim authorization proof:
actions/setup/js/finish_work_queue_claim.cjs:111
actions/setup/js/work_queue_claim_adapters.cjs:115,119,142
actions/setup/js/work_queue_code_scanning.cjs:32
actions/setup/js/work_queue_delivery.cjs:399
actions/setup/js/work_queue_git_tree_adapter.cjs:128
actions/setup/js/work_queue_graphql_adapter.cjs:114,118,119
actions/setup/js/work_queue_prepare_claim_adapter.cjs:30,36
actions/setup/js/work_queue_rest_adapter.cjs:94,95,97
actions/setup/js/work_queue_upload_assets.cjs:34
It is not yet confirmed whether this fixed-scope-regex + per-Claim-proof mechanism is an equivalent (or stronger) substitute for the "allowlist" the spec describes, or whether it is a genuine gap — e.g. if adapter["target-repo"] can ever be populated from multiple possible values rather than one build-time-fixed string, the spec's allowlist/E004-rejection requirement would not be satisfied.
Affected Components
- Files: see checklist below
- Script:
scripts/check-safe-outputs-conformance.sh (check_cross_repo, SEC-005, lines 173-198)
- Spec:
docs/src/content/docs/specs/safe-outputs-specification.md (Cross-Repository Validation, ~line 648, ~line 665)
🔍 Current vs Expected Behavior
Current Behavior
- The checker's test-file skip (
[[ "$handler" =~ test ]]) does not match the *_checks.cjs naming convention used by several Node test scripts in this directory, so they are scanned as if they were production handlers.
- Production work-queue Claim adapter files consume a
target-repo value without any helper matching allowed.*[Rr]epos|validateTargetRepo|checkAllowedRepo, so the checker cannot confirm an allowlist exists, even though a single-fixed-repo regex check and a separate proof-based authorization call (assertClaimAuthorized) are present.
Expected Behavior
- Test-only
.cjs files should be excluded from SEC-005 scanning (either by broadening the script's skip pattern, or by renaming/annotating these fixtures).
- Production handlers with a
target-repo parameter should either demonstrably enforce an allowlist consistent with Section 9.4 of the spec (rejecting non-allowlisted repos with E004), or carry a documented @safe-outputs-exempt SEC-005 annotation explaining why the existing fixed-scope + per-Claim-authorization mechanism already satisfies that intent.
Remediation Steps
This task can be assigned to a Copilot coding agent with the following steps:
- Fix
scripts/check-safe-outputs-conformance.sh's test-file exclusion in check_cross_repo (and ideally the other check functions sharing the same pattern) to also match _checks.cjs-style test fixtures, so files like work_queue_claim_adapter_checks.cjs are not scanned as production handlers.
- For each of the 9 genuine production files listed above, determine whether
adapter["target-repo"] can ever resolve to more than one build-time-fixed value per adapter instance:
- If the value is always a single build-time-fixed, regex-validated string (i.e. functionally an allowlist of one, already enforced in
work_queue_claim_adapters.cjs), add a @safe-outputs-exempt SEC-005 annotation to each file with a one-line justification referencing work_queue_claim_adapters.cjs:119 and assertClaimAuthorized.
- If any handler can resolve
target-repo from more than one possible value at runtime without going through that fixed-scope validation, add an explicit allowlist check (matching the spec's E004 rejection behavior) for that handler instead of an exemption.
Verification
After remediation, verify the fix by running:
bash scripts/check-safe-outputs-conformance.sh
The check SEC-005 should pass without errors (either via legitimate allowlist enforcement or documented, justified exemptions).
References
- Safe Outputs Specification: docs/src/content/docs/specs/safe-outputs-specification.md
- Conformance Checker: scripts/check-safe-outputs-conformance.sh
- Run ID: 37890341772
- Date: 2026-10-09
Generated by ✅ Daily Safe Outputs Conformance Checker · claude · agent · 107.7 AIC · ⊞ 5.2K · ◷
Conformance Check Failure
Check ID: SEC-005
Severity: HIGH
Category: Security
Problem Description
scripts/check-safe-outputs-conformance.shflagged 14 files underactions/setup/js/for supporting atarget-repo/targetRepo/target_repofield without a matching allowlist check (allowed.*[Rr]epos|validateTargetRepo|checkAllowedRepo). The safe-outputs specification (Section on Cross-Repository Validation,docs/src/content/docs/specs/safe-outputs-specification.mdaround line 648) states: "All handlers withtarget-repoparameter validate against allowlists; operations to non-allowlisted repos are rejected with E004."Investigation shows all 14 matches come from the internal work-queue "Claim adapter" subsystem (not the user-facing cross-repo safe outputs like
create_issue'sresolveTargetRepoConfig/allowedRepos, which already pass this check). Two distinct root causes were found:Checker false-positive on test fixtures — 5 of the 14 files are self-contained Node test scripts (using
node:assert/strict) that just happen to be named*_checks.cjsinstead of*_test.cjs/*.test.cjs, so the script's test-file exclusion ([[ "$handler" =~ test ]]) misses them:actions/setup/js/work_queue_claim_adapter_checks.cjsactions/setup/js/work_queue_delivery_proof_checks.cjsactions/setup/js/work_queue_git_tree_adapter_checks.cjsactions/setup/js/work_queue_graphql_adapter_checks.cjsactions/setup/js/work_queue_script_preparation_checks.cjsGenuinely production code using a different authorization mechanism — the remaining 9 files read
adapter["target-repo"]after it has already been validated once, upstream, inactions/setup/js/work_queue_claim_adapters.cjs(closed()+ a regex check at line 119:"Trusted Claim adapter requires a fixed repository scope"), and every write is additionally gated at effect-time byassertClaimAuthorized()(actions/setup/js/work_queue_claim_scope.cjs:180), which requires a per-Claim authorization proof:actions/setup/js/finish_work_queue_claim.cjs:111actions/setup/js/work_queue_claim_adapters.cjs:115,119,142actions/setup/js/work_queue_code_scanning.cjs:32actions/setup/js/work_queue_delivery.cjs:399actions/setup/js/work_queue_git_tree_adapter.cjs:128actions/setup/js/work_queue_graphql_adapter.cjs:114,118,119actions/setup/js/work_queue_prepare_claim_adapter.cjs:30,36actions/setup/js/work_queue_rest_adapter.cjs:94,95,97actions/setup/js/work_queue_upload_assets.cjs:34It is not yet confirmed whether this fixed-scope-regex + per-Claim-proof mechanism is an equivalent (or stronger) substitute for the "allowlist" the spec describes, or whether it is a genuine gap — e.g. if
adapter["target-repo"]can ever be populated from multiple possible values rather than one build-time-fixed string, the spec's allowlist/E004-rejection requirement would not be satisfied.Affected Components
scripts/check-safe-outputs-conformance.sh(check_cross_repo, SEC-005, lines 173-198)docs/src/content/docs/specs/safe-outputs-specification.md(Cross-Repository Validation, ~line 648, ~line 665)🔍 Current vs Expected Behavior
Current Behavior
[[ "$handler" =~ test ]]) does not match the*_checks.cjsnaming convention used by several Node test scripts in this directory, so they are scanned as if they were production handlers.target-repovalue without any helper matchingallowed.*[Rr]epos|validateTargetRepo|checkAllowedRepo, so the checker cannot confirm an allowlist exists, even though a single-fixed-repo regex check and a separate proof-based authorization call (assertClaimAuthorized) are present.Expected Behavior
.cjsfiles should be excluded from SEC-005 scanning (either by broadening the script's skip pattern, or by renaming/annotating these fixtures).target-repoparameter should either demonstrably enforce an allowlist consistent with Section 9.4 of the spec (rejecting non-allowlisted repos with E004), or carry a documented@safe-outputs-exempt SEC-005annotation explaining why the existing fixed-scope + per-Claim-authorization mechanism already satisfies that intent.Remediation Steps
This task can be assigned to a Copilot coding agent with the following steps:
scripts/check-safe-outputs-conformance.sh's test-file exclusion incheck_cross_repo(and ideally the other check functions sharing the same pattern) to also match_checks.cjs-style test fixtures, so files likework_queue_claim_adapter_checks.cjsare not scanned as production handlers.adapter["target-repo"]can ever resolve to more than one build-time-fixed value per adapter instance:actions/setup/js/finish_work_queue_claim.cjsactions/setup/js/work_queue_claim_adapters.cjsactions/setup/js/work_queue_code_scanning.cjsactions/setup/js/work_queue_delivery.cjsactions/setup/js/work_queue_git_tree_adapter.cjsactions/setup/js/work_queue_graphql_adapter.cjsactions/setup/js/work_queue_prepare_claim_adapter.cjsactions/setup/js/work_queue_rest_adapter.cjsactions/setup/js/work_queue_upload_assets.cjswork_queue_claim_adapters.cjs), add a@safe-outputs-exempt SEC-005annotation to each file with a one-line justification referencingwork_queue_claim_adapters.cjs:119andassertClaimAuthorized.target-repofrom more than one possible value at runtime without going through that fixed-scope validation, add an explicit allowlist check (matching the spec's E004 rejection behavior) for that handler instead of an exemption.Verification
After remediation, verify the fix by running:
The check SEC-005 should pass without errors (either via legitimate allowlist enforcement or documented, justified exemptions).
References