Skip to content

Latest commit

 

History

History
500 lines (427 loc) · 28.3 KB

RELEASING.md

File metadata and controls

500 lines (427 loc) · 28.3 KB

Releasing Codex Security

GitHub Releases is the canonical changelog. Under the current process, each new release combines a short, reviewed summary with an expandable categorized list of merged pull requests. Historical releases may contain generated notes only. The release tag and npm package use the same stable version: npm-vX.Y.Z and @openai/codex-security@X.Y.Z. Releases whose source includes the GitHub Action also publish a companion action-vX.Y.Z GitHub Release, which installs that exact CLI version. The npm release contains the package archive and canonical changelog. The Action release contains its manifest and SBOM, links to that changelog, and lists the full distribution commit SHA for consumers to pin.

Pull request titles and categories

Pull request titles must follow this form:

<type>[optional scope][!]: <description>

Use a lowercase type beginning with a letter and containing only letters, digits, and hyphens. Use a lowercase scope when present. Start the description with a non-whitespace character and do not leave trailing whitespace. Examples:

feat(cli): add component scan planning
fix(windows): preserve Unicode paths
docs: explain scan cost limits
feat(sdk)!: remove the legacy result field

The title controls the generated release category:

Title Release category
Any type with ! Breaking changes
feat Features
fix Fixes
docs Documentation
chore(release), release, test Excluded
Any other type Other changes

Use chore(release) for release preparation and test for test-only changes. The legacy release type remains supported. Use these only for changes that do not affect package users. A maintainer can apply skip-release-notes to exclude another internal change. That manual label takes precedence over the title category.

Dependency updates

Dependabot checks npm packages, Python test dependencies, and GitHub Actions daily, including weekends. OpenAI dependencies have no release cooldown; other releases must be at least seven days old. Security updates do not wait for the version-update cooldown. Updates still require review and passing CI; nothing is merged automatically.

Keep @openai/codex and @openai/codex-sdk on the same exact version across the TypeScript SDK, MCP app, and triage evals in evals/triage-finding. Dependabot groups their updates across all three projects, and the SDK tests reject mismatched pins or multiple locked SDK versions. The evals override Promptfoo's transitive Codex SDK to the direct SDK dependency so it follows the same update.

Each pnpm project applies the same seven-day age policy to newly resolved dependencies, including transitive packages, with openai and @openai/* exempt. Committed lockfiles remain installable. The existing Socket release checks remain in place.

The production dependency audit is a blocking step in CI package builds and npm release validation. pnpm --dir sdk/typescript run audit:prod checks the locked production graph at the existing high-severity threshold. High or critical advisories and audit service failures stop publication. Resolve dependency advisories with dependency and lockfile updates; retry service failures once the audit service is available.

Version policy before 1.0

While the package is on 0.x, ordinary changes, including features, use a patch release. Breaking changes use a minor release and reset the patch to zero. For example, changes after 0.1.23 propose 0.1.24, or 0.2.0 if any included change is breaking. The category of a feature remains Features; the category does not imply a minor version bump.

The release PR updater recognizes breaking changes from a ! in a Conventional Commit title, a BREAKING CHANGE: or BREAKING-CHANGE: footer, or the breaking-change label. skip-release-notes affects visibility, not version impact. All merges and direct commits after the release boundary count toward the next version, including documentation and internal changes. Review this policy before enabling automation for 1.x.

Rolling release PRs

node-release-pr runs after pushes to main and can be dispatched manually. Newer pushes can replace pending pushes. Manual runs keep their own place. Previews and writes share one queue so a preview sees a consistent proposal. It defaults to a read-only preview. It does not merge, tag, publish, or change the existing publication gates.

The updater opens one ready-for-review proposal on release/next-<base-version> once a change reaches main after the current package version. It recomputes the proposal's version from all changes since that package version first reached main. Squash-merge release PRs, as required by this repository's enabled merge method, so the whole proposal lands as one release boundary commit. Generated PR titles and commit subjects use chore(release): X.Y.Z, matching the proposed package version. Confirm the squash commit subject uses the current PR title when merging. A later breaking change updates the version and title on the same PR. Each update incorporates the latest main and appends a commit; the updater never force-pushes. A concurrent commit causes it to reread and retry. It requests Codex review when the proposal files change. Updates that only incorporate main keep CI current without repeating the same proposal review, even when the earlier request names an older commit. New suggestions for human-owned notes still appear in a comment. Before merging the proposal, check CI and request a final Codex review if the last review targets an older head.

The proposal updates the SDK version and the Action version in github-action/package.json and github-action/package-lock.json together. The Action's runtime dependency and lockfile keep an already published CLI baseline until npm publishes the proposed version. This development baseline does not necessarily track the latest CLI release. Release packaging then updates that pin and lockfile to the verified publication. This lets release PRs run CI while the next npm version is still unavailable; node-ci also tests the Action against the packed CLI candidate before publication.

The standalone workflow in examples/github-actions/codex-security.yml also pins CODEX_SECURITY_VERSION to the proposed release version. Only that value changes; other workflow content comes from the latest main. After the release PR merges, this example can reference the new version before npm publication finishes. Wait for publication before using that pin.

After updating an existing release branch and its title, the updater waits briefly if GitHub still shows the exact commit it just replaced. A different head or a newer main stops that review handoff; the next updater can use the current branches. If GitHub still has not exposed the updated PR head, manually rerun the updater with dry_run disabled after the PR catches up. This allows any deferred review request or note suggestions to be posted. Verify review on the current head before merging the proposal.

When the release version merges, the updater waits for another change to reach main before opening the next proposal. An empty release cycle returns action: "unchanged" without creating a branch or PR. Publication of the previous version still has to complete and pass the verification steps below.

The updater leaves another open chore(release): or legacy release: PR targeting main, including a manually prepared release, untouched and does not open a duplicate. Finish or close that PR before enabling the new flow. Closing an automated proposal pauses its cycle; reopen it to resume. Retargeting it away from main also pauses updates; restore its main base before resuming. Both ready proposals and existing drafts receive updates. Existing drafts can be marked ready without pausing the updater. Review the current head before merging if main has advanced. The updater rechecks pause conditions before advancing the branch. Changes to other files on the release branch, to package fields other than the version, or to the standalone example beyond its CLI version also pause the updater so those edits cannot be lost. These intentional pauses return action: "held" and leave the workflow successful. Preserve or merge the additional changes, then rerun the updater to resume.

Editing the release notes

The committed .github/release-notes.md is authoritative. The updater drafts highlights from merged titles and lists marked breaking changes for migration review; it does not infer migration instructions from source code. Review and refine these suggestions before releasing.

Keep the published notes easy to scan:

  • Start with a short overview and the main user-facing highlights. Use bold topic labels to make the bullets easy to skim. Put secondary improvements in a <details> block when they would crowd out upgrade guidance.
  • Keep breaking changes and required upgrade actions visible. Long migration procedures can go in a clearly named <details> block under the relevant upgrade note. Keep code fences, tables, and lists intact.
  • Keep each prose paragraph or list item on one source line. GitHub Releases renders source newlines as visible breaks, including those before links. The release-note Prettier override uses proseWrap: "never", and the SDK format check includes this file.
  • Leave the complete PR inventory to the publisher. It appends the generated notes, contributor credits, and comparison link in an All changes disclosure after the reviewed summary. Releases without a reviewed summary keep their generated notes visible.

Preview both the release list and the individual release in GitHub. Check paragraph flow, inline links, tables, code examples, and expanded details. Edits to an already published release do not change its immutable tagged source; rerunning publication uses that tagged summary again.

  • Edit the highlights or upgrade notes on the release PR branch. Keep the surrounding release-section comments if you want to retain section boundaries. The bot refreshes a section only while it matches the last generated draft. An edit or deletion makes that section human-owned, and later updates preserve it. Custom prose outside the sections is preserved.
  • Later suggestions appear in a new bot comment on the same PR. They do not replace human-owned notes. The bot updates the version header and PR title but never rewrites the PR description. Review version-specific links in human-owned prose when the proposed version changes.
  • .github/release-pr-state.json records the cycle and section ownership. To explicitly regenerate a section, add "reset": true to that section's state entry. The next run consumes the reset and resumes automatic updates. Restore any damaged section markers before resetting. Do not delete the state file to reset ownership. A section with missing ownership metadata is preserved until explicitly reset; missing state does not authorize replacing manual notes.
  • Deleting the notes file is preserved too. Restore reviewed notes, or explicitly reset the sections, before merging; publication requires the versioned notes file.

Preview and enable

With an authenticated gh CLI, a local checkout can preview the plan with:

RELEASE_PR_DRY_RUN=true node sdk/typescript/scripts/release-pr.mjs

The preview may fetch missing Git objects locally, but performs no GitHub writes. Its JSON output includes the proposed files and any reason the updater would pause. After the workflow is on main, use its Run workflow form with dry_run enabled to test the hosted read-only path.

To test writes, enable Allow GitHub Actions to create and approve pull requests under the repository's Settings → Actions → General → Workflow permissions, then manually dispatch the workflow with dry_run disabled. This permits a single write run while automatic updates remain disabled. The workflow uses the repository's GITHUB_TOKEN with Contents: write and Pull requests: write by default; no separate App credentials are required. Preview runs use a separate job with read-only permissions for both scopes.

Review the resulting PR and select Approve workflows to run in its merge box to start hosted CI. GitHub requires this approval for PRs created or updated with GITHUB_TOKEN. Check that a Codex code review completed on the current commit; a passing security check alone does not confirm this. If the automated request does not start a review or the integration asks the automated account to connect, a maintainer with a connected account should request the code review manually and verify it completed on that commit.

For CI to start without this approval, optionally configure a GitHub App installed on this repository with Contents: write and Pull requests: write. Set the RELEASE_APP_CLIENT_ID repository variable and RELEASE_APP_PRIVATE_KEY secret. When the Client ID is configured, write runs request an App token scoped to this repository; a missing or invalid private key fails the run. Previews always use GITHUB_TOKEN. See GitHub's token documentation.

After the manual write run is verified, set the RELEASE_PR_ENABLED repository variable to true to allow updates after pushes to main. Remove it or set it to false to return push-triggered runs to previews. Manual runs always honor their dry_run input, which defaults to a preview; disabling automatic updates does not prevent an explicit manual write run. Generated PRs leave the disclosure attestations unchecked for maintainer review.

Prepare a release

  1. Choose the next stable version and update sdk/typescript/package.json, github-action/package.json, and both root version fields in github-action/package-lock.json. The rolling release PR normally prepares these changes. Keep the Action runtime pin on its published CLI baseline; release packaging updates it after npm publication.
  2. Update .github/release-notes.md. Its first line must be <!-- release-version: X.Y.Z --> with the exact package version.
  3. Summarize the changes a user will notice. Call out required migration or compatibility work, link relevant public documentation, and leave the pull-request inventory to the generated section.
  4. Open a pull request with a strict Conventional Commit title such as chore(release): 0.2.0.
  5. Run the checks required by the changed files and record the initial results in the PR description. Post later manual test results in a comment or review with the tested commit SHA. Editing the description to update status can trigger CI. Before merging, confirm that required CI passed in the Checks tab and that review and the PR's public disclosure checklist cover the current commit.

Review the summary with the same standard as product documentation. Keep it specific, describe behavior before implementation, and do not include private repositories, systems, people, findings, links, or issue identifiers.

Publish

The release starts after the version bump reaches main and node-ci succeeds for that exact commit:

  1. node-release-cut verifies that the version increased, checks the reviewed summary, and creates the exact npm-vX.Y.Z tag.
  2. node-release installs the committed dependency graph, tests and packs the package, publishes it to npm, and records npm provenance. Three TypeScript test shards and the MCP tests run in parallel with package verification. Every shard and package check must pass before the protected npm job can publish the verified archive.
  3. node-github-release verifies the public package, provenance, tag, and archive before publishing the GitHub release. It prepends the reviewed summary to GitHub's categorized notes.
  4. The same workflow runs published-install-smoke against the exact published version on Linux, macOS, and Windows. It uses the current release automation so the checks also work for historical backfills.
  5. If the release source contains action.yml, the workflow prepares the Action from that exact source commit, pins its runtime to the verified npm version and integrity, and fetches the locked runtime through Socket Firewall with an empty cache before executing it. The lock retains public npm URLs. It builds and tests the distribution in a job with read-only repository permissions. A fresh publisher checks out the same source, downloads only the tested runtime lock by artifact ID, and rebuilds and verifies the bundles without executing the CLI. It creates action-vX.Y.Z and publishes a companion GitHub Release with the Action manifest and SBOM attached before publication makes those assets immutable. The companion links to the npm-vX.Y.Z changelog and lists the full Action distribution commit SHA. It is never marked Latest. A final status job reports publication, installation smoke, Action, and container results.

The Action tag points to a generated distribution commit whose parent is the CLI release commit. That additional commit contains the runnable Action bundle and runtime lockfile. Its release manifest records both commits, both tags, the aligned version, and the npm integrity. Metadata finalization verifies the bundle hashes against the files being published. Consumers can pin the Action's distribution commit from that manifest.

Historical releases whose source predates action.yml skip Action publication and still run the exact-version installation checks. The workflow does not add Action code from a later commit to an older CLI release.

After npm accepts a publication, its registry can take several minutes to expose the version. GitHub publication waits up to ten minutes for that version to become available before verifying its archive and signed provenance. Other registry errors fail immediately.

node-release generates the npm plugin payload from the canonical source under plugins/codex-security/ during prepack. The generated sdk/typescript/_bundled_plugin/ directory is not a committed release input; do not prepare a release by editing or committing files there.

The merged release PR receives one progress comment covering post-merge CI, release verification, protected npm approval, public-package provenance, installation checks, Action publication, and container approval and publication. The main CI completion handler requests the first update for a merged release PR, including when CI fails. Subsequent updates link to the relevant workflows and track each publication stage. Each automatic release dispatch starts a separate observer using the returned run ID; this does not depend on chained workflow_run events from the built-in token. The observer checks release jobs every 30 seconds, including while protected approval is pending, and requests a refresh when a milestone changes. Reruns update the same comment using their latest results. Queued duplicates keep the active run and its approval link visible. Historical stages without a recorded run are marked Not recorded. Completion covers the automated workflows; Marketplace publication remains a separate step.

Observers are subject to GitHub's job time limit. To resume observation after a long approval wait, run release-progress on main with the release run-id and watch enabled. GitHub publication starts its own observer after npm succeeds.

The observer and comment writer execute only helpers from protected main. Only the comment writer can update PR comments, and only the observer can request a refresh. Reporting runs independently of the tag-cut job. Verification and publication jobs retain their existing permissions. The dispatch jobs use their existing Actions permission for a best-effort notification bounded to 15 seconds, within the downstream resolver's 60-second completion wait. Progress-reporting failures do not block publication; workflow results remain authoritative.

Monitor all three workflows and the final status in node-github-release. The automated release is complete when npm and GitHub publication, exact-version install checks, and applicable Action and container publication have succeeded. The final job summarizes each result and identifies Marketplace publication as a separate step. A successful workflow does not confirm a Marketplace listing. The protected npm publication gates and immutable npm-vX.Y.Z tag remain in place.

The npm package and CLI GitHub release become public before the installation and Action and container checks finish. Use the final workflow result before announcing that the automated release is complete.

After the installed-package checks pass, node-github-release calls container-release with the verified npm version and source commit. Native binaries, Docker builds, OCI revision labels, and image tags all use that commit, including when the release is older than main. Publication still requires approval in the protected container environment. The final status waits for both architectures, public pulls, attestation, and stable tag promotion. Coordinated container publication starts at 0.5.0. Earlier releases use older container and native build contracts, so their recovery runs continue to publish npm and the Action without requiring this container pipeline. Sources without a Dockerfile also skip container publication.

To publish a missing container for an existing npm release, dispatch node-github-release on main with its npm-vX.Y.Z tag and approve the container deployment after validation. Recovery verifies and reuses an existing container only when its version, source commit, architectures, attestation, public pull, and immutable tag checks pass. It does not rebuild or overwrite that version. Standalone container-vX.Y.Z and manual container-release triggers remain available. See Container releases for publication and verification.

Publish to GitHub Marketplace

Before announcing a new release that includes the GitHub Action, a maintainer must publish the companion action-vX.Y.Z release to GitHub Marketplace.

  1. After node-github-release succeeds, follow edit the Action release in the release status job summary, or open action-vX.Y.Z and choose Edit. That tag contains the tested Action distribution. npm-vX.Y.Z points to the CLI source.
  2. Under Release Action, select Publish this Action to the GitHub Marketplace.
  3. Confirm the metadata checks pass. The Marketplace display name comes from name in the tagged action.yml, currently OpenAI Codex Security. GitHub requires a globally unique Action name. If a released version's name is rejected, correct the source metadata and publish a new version; do not move an existing release tag.
  4. Select Security as the primary category and Code review as the optional secondary category. Confirm the security contact and complete any organization-owned Marketplace agreement requirements.
  5. Review the listing details, keep the Action release unmarked as Latest, and choose Update release. Verify that the public Marketplace page links to this repository and offers the intended action-vX.Y.Z version.

Changing the Marketplace display name does not change the repository reference used by workflows or the npm package name. Existing releases retain their tagged metadata. See GitHub's Marketplace publishing requirements.

Verify

Check the published state before announcing the release:

  • npm-vX.Y.Z points to the merged release commit.
  • npm view @openai/codex-security@X.Y.Z reports the expected version and commit, and the provenance check passed in node-release.
  • The npm GitHub Release is stable, has the correct title, and contains one verified npm package archive.
  • The exact-version published installation checks succeeded.
  • For releases at or after 0.5.0 with a Dockerfile, container publication succeeded and the version tag is publicly pullable on Linux amd64 and arm64.
  • For releases with the Action, action-vX.Y.Z points to the distribution commit recorded in its manifest, whose parent is the CLI release commit. Its companion GitHub Release contains the manifest and SBOM, links to the npm changelog, and lists that full distribution commit SHA. The manifest and runtime lock identify the same CLI version and npm integrity.
  • For new releases with the Action, the public Marketplace listing offers the matching action-vX.Y.Z version.
  • The newest npm release is marked Latest. Action releases and historical backfills are not.
  • For releases created under this process, the reviewed highlights, category headings, documentation links, and full comparison link are correct. Historical releases may have generated notes only.
  • Every merged pull request is included or has an intentional skip-release-notes label.

The published-install-smoke workflow checks each exact version during release publication. It also checks npm's current latest daily and on pull requests changing its smoke checks. Manual dispatch accepts a version (default latest) and an optional ref for the source of the smoke checks. It installs into a temporary consumer, verifies the requested version, checks the npm CLI shim and public SDK, starts the bundled Codex executable with --version, and initializes the bundled MCP server. Linux covers supported Node majors 22, 24, and 26; macOS and Windows cover Node 24. These checks use temporary configuration directories and do not run scans or call model APIs.

The smoke test verifies the installed package independently of the version on main, so it can run while the checkout contains unreleased changes. A failure reports the installed version or failing startup command in the Actions log; inspect that job before treating it as a release regression. To reproduce locally, run node sdk/typescript/scripts/smoke-published-package.mjs X.Y.Z from the repository. Omit the version to check latest.

Recover or repair a release

Do not retarget a release tag or publish a second package under the same version. The workflows are designed to recover from partial publication while keeping the original tag and package identity.

To retry GitHub publication, run node-github-release from main with the existing npm-vX.Y.Z tag. Supply the successful node-release run ID when automatic lookup is not enough. The workflow verifies the npm artifact and provenance again before it creates or updates the release, repeats the exact-version installation checks, and completes applicable Action publication. If action-vX.Y.Z already exists, recovery checks its package manifests and lockfiles against the reviewed source and CLI release identity before installing dependencies or running package scripts. It then reuses that distribution commit. Do not move that tag or regenerate the release from newer Action source. The workflow verifies existing Action release assets and can finish a partial draft before publishing it. It does not replace assets on a published release.

For example, if npm-v0.4.0 is already immutable and its Action publication failed, rerun node-github-release from main with tag: npm-v0.4.0. The retry creates the missing action-v0.4.0 companion release without adding or replacing assets on the npm release. A failure after npm publication can leave the npm package or GitHub Release visible while later checks or Action publication remain incomplete; use the final workflow status to identify the remaining work.

To repair categories on an existing release, correct the merged pull request's title or release label first, then rerun node-github-release for the tag. For a release that predates .github/release-notes.md, start the existing release body with this marker block. Keep a blank line between the end marker and the generated notes:

<!-- codex-security-release-summary:start -->
Reviewed summary
<!-- codex-security-release-summary:end -->

Generated notes

The workflow preserves that marked summary and replaces the generated section. After any recovery or repair, repeat every verification step above and review the final public release body.