Skip to content

ci: harden release and review boundaries - #306

Merged
conorbronsdon merged 1 commit into
mainfrom
hardening/release-boundary
Sep 14, 2026
Merged

conorbronsdon merged 1 commit into
mainfrom
hardening/release-boundary

Conversation

@conorbronsdon

Copy link
Copy Markdown
Owner

Summary

  • put a read-only preflight before GitHub and npm publication
  • bind release jobs to the protected release environment and retain every queued release run
  • make the detector job eligible as an always-reported required check
  • require pinned GitHub-owned Actions, add monthly Action updates, and remove persisted checkout credentials
  • add private vulnerability reporting guidance and a tested recovery procedure

The security-policy text incorporates the useful part of #276 and preserves Sharad's contribution in the commit trailer. The code-of-conduct contact decision remains separate.

Validation

  • npm test
  • npm run self-scan:check
  • node scripts/verify-release-versions.test.js (17 passed)
  • git diff HEAD^ --check
  • new prose passes avoid-ai-writing-gate at threshold 6
  • exact-SHA review at 1c3681aba0140d833067342658587d97b6020bc1: Astra clean; OpenCode Go MiMo and Luna findings checked against the files; Hermes/Inkling and OpenCode Muse free passes completed

Setup failures, not counted as reviews: two stalled Claude Opus 5 attempts;
OpenCode Go Grok timeout/no-final, Muse Go HTTP 403, Kimi output exhaustion, and
Qwen timeout. The required private lane fell back to the completed Go reviews.

Rollout prerequisites

Already active before merge:

  • release environment restricted to main
  • private vulnerability reporting and vulnerability alerts
  • GitHub-owned Actions allowlist with full-SHA pinning required
  • read-only default workflow tokens; Actions cannot approve pull requests

After CI passes, this PR will be merged before the main ruleset and immutable-release policy are enabled. npm trusted publishing still needs its publisher entry bound to the release environment.

Changelog exemption: CI, repository policy, and maintainer documentation only; no user-facing detector, package, or compatibility change.

Co-authored-by: Sharad <sharadvc@users.noreply.github.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Harden release publication and required-check boundaries

⚙️ Configuration changes 📝 Documentation ✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Adds read-only preflight and protected, serialized GitHub and npm publication stages.
• Makes detector CI universally reportable and hardens checkout credentials and Action maintenance.
• Documents private vulnerability reporting and immutable release recovery.
Diagram

sequenceDiagram
  actor M as Maintainer
  participant G as GitHub Trigger
  participant P as Read-only Preflight
  participant E as Release Environment
  participant R as GitHub Releases
  participant N as npm Registry
  M->>G: Merge or dispatch
  G->>P: Validate exact commit
  P-->>G: Verified version
  G->>E: Enter protected boundary
  E->>R: Check or create release
  R-->>E: Confirm release tag
  E->>N: Publish with provenance
Loading
High-Level Assessment

The staged least-privilege approach is appropriate: validate once without write or OIDC authority, then gate both publication jobs through the protected environment. A single privileged job would enlarge the credential boundary, while separate independently triggered publication workflows would complicate commit and version consistency during recovery.

Files changed (8) +109 / -35

Documentation (4) +45 / -0
CONTRIBUTING.mdDirect maintainers to release recovery guidance +3/-0

Direct maintainers to release recovery guidance

• Instructs maintainers to use the documented recovery procedure rather than moving tags or reusing published versions.

CONTRIBUTING.md

SECURITY.mdDefine private vulnerability reporting policy +18/-0

Define private vulnerability reporting policy

• Documents supported versions, directs undisclosed vulnerabilities to GitHub private reporting, and lists useful report details and priority risk categories.

SECURITY.md

SUPPORT.mdRoute security reports away from public issues +3/-0

Route security reports away from public issues

• Points vulnerability reporters to the security policy and GitHub private vulnerability reporting instead of the public issue tracker.

SUPPORT.md

releasing.mdDocument immutable release recovery +21/-0

Document immutable release recovery

• Explains the preflight and queueing model, then defines recovery paths for npm publication and preflight failures. It prohibits moving release tags or reusing registry versions.

docs/releasing.md

Other (4) +64 / -35
dependabot.ymlSchedule grouped GitHub Action updates +10/-0

Schedule grouped GitHub Action updates

• Adds monthly Dependabot checks for GitHub Actions and groups all Action updates into a single update set.

.github/dependabot.yml

detector-test.ymlReport detector CI on every pull request +2/-18

Report detector CI on every pull request

• Removes pull-request path filtering so the detector job always reports and can safely become a required check. Push filtering remains unchanged.

.github/workflows/detector-test.yml

promo-drift.ymlDisable persisted checkout credentials +2/-0

Disable persisted checkout credentials

• Prevents the promotion-drift checkout from retaining GitHub credentials after repository checkout.

.github/workflows/promo-drift.yml

release.ymlGate publication behind read-only preflight +50/-17

Gate publication behind read-only preflight

• Splits release validation from privileged publication, routes publishing through the protected release environment, and retains serialized queued runs. It also disables persisted checkout credentials and passes the verified version into both publication stages.

.github/workflows/release.yml

@conorbronsdon
conorbronsdon merged commit 989af19 into main Sep 14, 2026
4 checks passed
@conorbronsdon
conorbronsdon deleted the hardening/release-boundary branch September 14, 2026 05:53
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Automated releases stop running 🐞 Bug ≡ Correctness
Description
concurrency.queue is not a supported GitHub Actions workflow property, so the new queue: max
entry makes release.yml fail workflow validation. Every changelog push and recovery dispatch
reaches this invalid top-level configuration before preflight, leaving both GitHub and npm
publication jobs unable to start.
Code

.github/workflows/release.yml[30]

+  queue: max
Evidence
The added property appears inside the release workflow's concurrency mapping, while the repository's
working concurrency mappings contain only the supported group and cancel-in-progress properties.
The new recovery guide explicitly depends on queue: max, confirming that the invalid field is
intended to control release execution rather than being inert documentation.

.github/workflows/release.yml[15-31]
.github/workflows/corpus-fetch.yml[18-20]
docs/releasing.md[7-9]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The release workflow declares unsupported `concurrency.queue` syntax, causing workflow validation to fail before any release job starts.

## Fix Focus Areas
- .github/workflows/release.yml[15-31]
- docs/releasing.md[7-9]

## Recommended Fix
Remove `queue: max` and retain only supported concurrency properties. Update the workflow comments and recovery documentation so they do not claim that GitHub retains every pending run; if retaining every release trigger is mandatory, implement a supported durable queueing mechanism instead of an unknown concurrency property.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 13/18, lines 144/200; both must reach the floor). Router rationale: This security-sensitive CI/release hardening changes multiple independent workflow paths, permissions, concurrency, publication gating, and recovery behavior, creating a dense set of easy-to-miss defects with broad release-impacting blast radius.

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

# publish, or leave a GitHub release standing with nothing published against it.
concurrency:
group: release
queue: max

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Automated releases stop running 🐞 Bug ≡ Correctness

concurrency.queue is not a supported GitHub Actions workflow property, so the new queue: max
entry makes release.yml fail workflow validation. Every changelog push and recovery dispatch
reaches this invalid top-level configuration before preflight, leaving both GitHub and npm
publication jobs unable to start.
Agent Prompt
## Issue description
The release workflow declares unsupported `concurrency.queue` syntax, causing workflow validation to fail before any release job starts.

## Fix Focus Areas
- .github/workflows/release.yml[15-31]
- docs/releasing.md[7-9]

## Recommended Fix
Remove `queue: max` and retain only supported concurrency properties. Update the workflow comments and recovery documentation so they do not claim that GitHub retains every pending run; if retaining every release trigger is mandatory, implement a supported durable queueing mechanism instead of an unknown concurrency property.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

conorbronsdon added a commit to dchaudhari7177/avoid-ai-writing that referenced this pull request Sep 14, 2026
- validate: conorbronsdon#305 stopped stripping an AI tracker that sits directly before
  bold markers, an em/en dash, or an ellipsis, reporting url-missing
  (e.g. **https://x.com/p?utm_source=chatgpt.com** -> **https://x.com/p**).
- rewrite-eval-opencode: an `opencode export` spawn failure threw
  "Cannot read properties of undefined (reading 'trim')" and hid the real
  error; route it through requireCommand like the other calls.
- detector CI: since conorbronsdon#306 releases trigger only on package.json changes, so
  a release PR that forgets package.json merged green and never released.
  Run verify-release-versions.js on every PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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