Skip to content

fix(ci): grant Scorecard's called workflow contents:read (last startup_failure)#294

Merged
hyperpolymath merged 1 commit into
mainfrom
ci/scorecard-perms
Jul 21, 2026
Merged

fix(ci): grant Scorecard's called workflow contents:read (last startup_failure)#294
hyperpolymath merged 1 commit into
mainfrom
ci/scorecard-perms

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Two independent fixes, both measured on main after #293 landed.

1 · Scorecards supply-chain security — the last startup_failure

Re-pinning scorecard-reusable in #293 did not fix it. That is the useful result: it proves the stale pin was never the cause.

The real cause is the caller's permission block:

jobs:
  analysis:
    permissions:
      security-events: write
      id-token: write        # <- `contents` omitted

Declaring permissions: at job level sets every unlisted scope to none, and a called workflow can never hold more than the calling job grants it. scorecard-reusable declares top-level permissions: contents: read and its first step is actions/checkout — so it was being handed contents: none. The call died at startup with zero jobs, which is exactly why there is no log to read and why it looked inscrutable.

Confirmed against the green sibling. boj-server-cartridges' scorecard.yml lists all three — contents: read, security-events: write, id-token: write — and its runs succeed. This one omitted the first.

This is root cause (A) of the estate's two startup_failure shapes — reusable permission escalation — and is unrelated to BROKEN-M1, which was the other.

2 · Revert pages.yml / pages-deploy.yml checkout to the v4 SHA

#293 pinned these to de0fac2e (v6.0.2). On reflection that shipped an unvalidated version change:

  • Both workflows are push: [main]-only — no pull_request — so no PR can exercise them. The bump's first execution is on main.
  • pages.yml is this repo's only container job (idris2-pack) and has never completed a run. checkout v6 requires node24 injected into the container; whether that works against this image is precisely what could not be observed.

11d5960a is exactly what actions/checkout@v4 resolves to today, so this is a pure pin — the linter only requires a full-length SHA, not a particular version. A considered v4 → v6 bump belongs in a change where it can be watched.

Verification

  • 0 of 94 uses: unpinned (scanning both the bare and - uses: forms — the latter is invisible to the standards linter)
  • all three files parse as YAML

State of main after #293

Governance is SUCCESS — all 9 jobs green, the two that were red are fixed. Remaining red on main:

Check Cause Fixed by
Scorecards supply-chain security contents: none to the called workflow this PR
deploy (Cloudflare) CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID absent from repo secrets — confirmed in the log: "necessary to set a CLOUDFLARE_API_TOKEN environment variable" needs a human: add secrets or retire the workflow
SonarQube SONAR_TOKEN exists but HTTP 403; the SonarCloud project itself is fine (badge endpoint 200), so the token is expired/wrong-scope needs a human: regenerate in SonarCloud

🤖 Generated with Claude Code

…oven checkout bump

Two independent CI fixes, both measured on main after #293.

1. `Scorecards supply-chain security` -- the last startup_failure

Re-pinning scorecard-reusable in #293 did NOT fix it, which proves the
pin was never the cause. Root cause is the caller's permission block:

    jobs:
      analysis:
        permissions:
          security-events: write
          id-token: write        # <- contents omitted

Declaring `permissions:` at job level sets every UNLISTED scope to
`none`, and a called workflow can never hold more than the calling job
grants it. scorecard-reusable declares top-level `permissions: contents:
read` and its first step is actions/checkout, so it was being handed
`contents: none` -- the call died at startup with zero jobs, which is why
there is no log to read.

Confirmed against the green sibling: boj-server-cartridges' scorecard.yml
lists all three (`contents: read`, `security-events: write`,
`id-token: write`) and its runs succeed. Adding `contents: read` here.

This is root cause (A) from the estate's two startup_failure shapes --
reusable permission escalation -- not BROKEN-M1.

2. Revert pages.yml/pages-deploy.yml checkout to the v4 SHA

#293 pinned these to de0fac2e (v6.0.2). Both workflows are
`push: [main]`-only, so no PR could exercise them, and pages.yml is this
repo's only container job (idris2-pack) and has never completed a run --
checkout v6 needs node24 injected into the container, which is precisely
what could not be observed. 11d5960a is exactly what `actions/checkout@v4`
resolves to today, so this is a pure pin: the linter only requires a
full-length SHA, not a particular version. A considered v4 -> v6 bump
belongs in a change where it can be watched.

Verified: 0 of 94 `uses:` unpinned; all three files parse as YAML.
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 215 issues detected

Severity Count
🔴 Critical 15
🟠 High 134
🟡 Medium 66

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Issue in build.yml",
    "type": "missing_timeout_minutes",
    "file": "build.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in pages-deploy.yml",
    "type": "missing_timeout_minutes",
    "file": "pages-deploy.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in push-email-notify.yml",
    "type": "missing_timeout_minutes",
    "file": "push-email-notify.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Issue in instant-sync.yml",
    "type": "secret_action_without_presence_gate",
    "file": "instant-sync.yml",
    "action": "peter-evans/repository-dispatch",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in codeql.yml",
    "type": "codeql_missing_actions_language",
    "file": "codeql.yml",
    "action": "flag",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/hesiod-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath
hyperpolymath marked this pull request as ready for review July 21, 2026 14:52
@hyperpolymath
hyperpolymath merged commit 2dbed8b into main Jul 21, 2026
50 of 51 checks passed
@hyperpolymath
hyperpolymath deleted the ci/scorecard-perms branch July 21, 2026 14:52
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