Skip to content

ops: tighten workflow token permissions (Scorecard PR B)#144

Merged
amavashev merged 2 commits into
mainfrom
ops/tighten-workflow-permissions
May 2, 2026
Merged

ops: tighten workflow token permissions (Scorecard PR B)#144
amavashev merged 2 commits into
mainfrom
ops/tighten-workflow-permissions

Conversation

@amavashev
Copy link
Copy Markdown
Collaborator

Companion to #143 (SHA pinning). Addresses the second of two quick wins flagged in the first OpenSSF Scorecard scanToken-Permissions: 0/10.

What changed

Adds top-level `permissions: read-all` to every workflow and demotes blanket write scopes to the job level where they're actually needed.

Workflow Change
`dependabot-auto-merge.yml` Top-level `read-all`; `contents:write` + `pull-requests:write` moved to `automerge` job (only place that needs them)
`nightly-benchmark.yml` Top-level `read-all` added; `benchmark` job retains `contents:write` to commit `history.jsonl` to the `benchmark-data` branch
`nightly-property-tests.yml` Top-level `read-all` added (job already had `contents:read`)
`nightly-soak-test.yml` Top-level `read-all` added (job already had `contents:read`)
`pr-container-scan.yml` Top-level dropped to `read-all`; `security-events:write` moved to `scan` job (only step that needs it is the Trivy SARIF upload)
`release.yml` Top-level `read-all` added; per-job permissions on `benchmark-gate`, `build-and-push`, `smoke-test-published` unchanged (each already had the minimum scope it needs)

`ci.yml` and `scorecard.yml` already follow this pattern — no changes needed.

Score impact

Combined with #143, expected to move cycles-server's Scorecard from 6.1 → ~8.0 on the next scheduled scan (Mon 06:00 UTC) or manual trigger via `gh workflow run scorecard.yml`.

Specific check movements:

Merge order with #143

Both PRs touch the same workflow files but on different lines (this PR adds `permissions:` blocks; #143 changes `uses:` lines). They should auto-merge cleanly. Merge #143 first if you want the cleanest history; merge this first and #143 will rebase trivially.

Test plan

  • CI runs green on this PR (no functional change to what each workflow does)
  • After both PRs merge, manually trigger `scorecard.yml` and verify Token-Permissions ≥ 9 and Pinned-Dependencies ≥ 9 in https://scorecard.dev/viewer/?uri=github.com/runcycles/cycles-server
  • Verify `dependabot-auto-merge` still works on the next Dependabot PR (most-likely-to-break change since job-level perms are subtle)

… scopes)

Addresses the second of two quick wins flagged in the first OpenSSF
Scorecard scan (Token-Permissions: 0/10). Adds top-level
'permissions: read-all' to every workflow and demotes blanket write
scopes to job-level where they are actually needed.

Per-workflow changes:
- dependabot-auto-merge.yml: top-level read-all; contents:write +
  pull-requests:write moved to the automerge job (only place that needs
  them, to enable PR auto-merge for patch updates)
- nightly-benchmark.yml: top-level read-all added; benchmark job
  retains contents:write to commit history.jsonl to benchmark-data
  branch
- nightly-property-tests.yml: top-level read-all added (job already
  had contents:read)
- nightly-soak-test.yml: top-level read-all added (job already had
  contents:read)
- pr-container-scan.yml: top-level dropped to read-all; security-events:
  write moved to the scan job (only step needing it is the Trivy SARIF
  upload)
- release.yml: top-level read-all added; per-job permissions on
  benchmark-gate, build-and-push, and smoke-test-published unchanged
  (each already declared the minimum scope it needs)

Combined with PR #143 (SHA pinning), this should move cycles-server's
Scorecard from 6.1 to ~8.0 on the next scheduled scan.
amavashev added a commit that referenced this pull request May 2, 2026
The Trivy scan triggered by PR #143 / #144 flagged 13 CVEs all in one
package: gnutls 3.8.12-r0 (Alpine). The blocker is CVE-2026-33845 (HIGH,
DoS via DTLS zero-length fragment); 12 other gnutls CVEs (1 MEDIUM,
1 LOW, 10 UNKNOWN) all resolve via the same 3.8.13-r0 bump.

Root cause: Dockerfile uses `eclipse-temurin:21-jre-alpine` (a moving
tag). A fresh pull picks up whatever Alpine patch level the temurin
maintainers last built against; until temurin rebuilds, we ship the
older Alpine. `apk upgrade --no-cache` closes that window at build time.

Why `apk upgrade --no-cache` over `.trivyignore`:
- Vuln is real, fixable, and the fix is mechanical
- Same one-line pattern catches future Alpine patches (e.g. when openssl
  or libxml2 ships a CVE fix), not just this one
- Stays within the current Alpine major — patch-level updates only

Side effect: builds gain ~30s on the first build after a base-image
change while apk re-pulls; subsequent rebuilds re-use the layer.

This PR unblocks #143 (SHA pinning) and #144 (workflow permissions) —
both currently failing the same Trivy scan because they touch the
pr-container-scan workflow file (path filter triggers the scan). After
this merges and those branches rebase onto main, both should pass.
@amavashev amavashev enabled auto-merge (squash) May 2, 2026 20:35
@amavashev amavashev merged commit 1d3693f into main May 2, 2026
8 checks passed
amavashev added a commit to runcycles/cycles-client-python that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Rewrites the canonical
dependabot-auto-merge.yml top-level write block into top-level read-all
+ per-job writes. Addresses Token-Permissions criterion from OpenSSF
Scorecard.
amavashev added a commit to runcycles/cycles-client-typescript that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Addresses Token-Permissions
criterion from OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-client-rust that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Addresses Token-Permissions
criterion from OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-spring-boot-starter that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Adds top-level read-all to
publish.yaml; rewrites dependabot-auto-merge.yml. Addresses
Token-Permissions criterion from OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-mcp-server that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Addresses Token-Permissions
criterion from OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-server-admin that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Adds top-level read-all to
nightly-audit-soak.yml, nightly-property-tests.yml, release.yml; rewrites
dependabot-auto-merge.yml. Addresses Token-Permissions criterion from
OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-server-events that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Adds top-level read-all to
claude-code-review.yml, claude.yml, release.yml; rewrites
dependabot-auto-merge.yml. Addresses Token-Permissions criterion from
OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-protocol that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Addresses Token-Permissions
criterion from OpenSSF Scorecard.
amavashev added a commit to runcycles/.github that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Adds top-level read-all to
ci-java.yml and ci-python.yml (reusable workflows consumed by every
SDK/service repo); rewrites dependabot-auto-merge.yml. Addresses
Token-Permissions criterion from OpenSSF Scorecard.
amavashev added a commit to runcycles/cycles-dashboard that referenced this pull request May 2, 2026
Same pattern as runcycles/cycles-server#144. Adds top-level read-all to
e2e.yml, release.yml; rewrites dependabot-auto-merge.yml. Addresses
Token-Permissions criterion from OpenSSF Scorecard.
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