Skip to content

ci: backport protected publishing environments to release - #7202

Merged
kixelated merged 2 commits into
releasefrom
ci-read-only-secrets-release
Oct 31, 2026
Merged

kixelated merged 2 commits into
releasefrom
ci-read-only-secrets-release

Conversation

@kixelated

@kixelated kixelated commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

release runs its own workflow copies, which still read write-capable repository secrets. Removing those secrets after moq-dev/moq#7166 would break releases.

Approach

  • Backport protected publish/npm Environments, release-tag verification for privileged workflow chains, and JSR token handling onto the existing release workflows.
  • Cover release-only cache.yml and cachix.yml consumers of CACHIX_AUTH_TOKEN.
  • Preserve dry runs without protected environments. Adapt Kotlin's condition to release's existing inputs and make JS publish only on pushes.
  • The moq-bot jobs (dependabot, release-brew, release-go, release-go-ffi, release-swift-ffi, release-swift-lib) name bot, which release adopted in 7e240565e8 and main already uses; they read only APP_CLIENT_ID/APP_PRIVATE_KEY.

Impact

  • Public API and wire: none. No package versions change.
  • Repository settings changed by the maintainer's pick (before/after in this comment): publish now also admits moq-boy-v*, moq-gst-v*, and libmoq-v* tags, and the release tags ruleset also protects refs/tags/libmoq-v*. No secrets, organization secret access, trusted publishers, or JSR tokens changed. Existing JSR OIDC trust remains usable until the maintainer provisions its replacement token.

Validation

  • Nix dev shell, after merging origin/release: just gh check, just ci check origin/release, and just ci test origin/release passed.
  • Merged-tree audit: every job reading a write secret names an Environment that admits the refs it runs on (publish, bot, npm, pypi, pub.dev); the remaining OIDC/inherit jobs call reusable workflows whose callee jobs name theirs. No workflow has a duplicate environment: key.
  • Earlier (Codex): the six release-tag guards passed 24 mocked missing-tag, mismatched-commit, and matching-commit cases; mocked publishers confirmed JSR token isolation for publishing and dry runs. No real publish ran.

Decisions

Maintainer pick, 2026-10-31:

  • Legacy release tag access for release's Cachix publisher:
    • ✅ Admit moq-boy-v*, moq-gst-v*, libmoq-v* to publish and protect libmoq-v* in release tags (applied by the agent with gh api)
    • Retire the legacy Cachix publications

Agent choices under the maintainer's overnight authorization, for review:

  • Merge conflicts with release's bot Environment: took bot for all six moq-bot jobs, including the two (release-go-ffi, release-swift-lib) where git's auto-merge silently left a second environment: publish key, keeping this branch's tag guards. release-rs had the same duplicate; it keeps one publish key with main's comment, since it reads more than the moq-bot key.
  • Ruleset first, then the publish policies, so no unprotected tag pattern could deploy to publish in between.

Review

  • Codex (quest review), gpt-6.1-sol, medium effort, head 39f690a298 against origin/release: 0 findings. Covers the hand-resolved merge.
  • Claude Code, Claude Opus 5.5, in-session review of the full diff (the quest review --harness claude CLI was not logged in), head 39f690a298: 0 findings. Covers Codex's original changes. Checked each Environment against the triggering refs, brew's tag filter against its three formula templates, that the tag guards fail closed, and that release.ts matches main's token isolation.

Follow-ups

Tracked by quest/m0/ci/read-only-secrets.md and moq-dev/moq#7201, now updated: after this lands, the maintainer copies the remaining credentials into publish, deletes the repository copies and access to the organization's DISCORD_WEBHOOK, restricts npm/PyPI/pub.dev publishers to their Environments, provisions JSR_TOKEN in npm before unlinking JSR repository trust, and runs the negative branch probe. Do not remove repository credentials before this backport is live.

(Written by Claude Opus 5.5)

Adapt the workflow hardening from main to the release branch, including its legacy Cachix publishers. Keep dry runs unprivileged and pass the environment-scoped JSR token only to deno publish.

Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
…ts-release

# Conflicts:
#	.github/workflows/dependabot.yml
#	.github/workflows/release-brew.yml
#	.github/workflows/release-go.yml
#	.github/workflows/release-swift-ffi.yml
@kixelated

Copy link
Copy Markdown
Collaborator Author

Settings change applied 2026-10-31 by the maintainer's pick (legacy release tag access: admit the three tags and protect libmoq-v*). Nothing else was changed; no secrets, organization secret access, trusted publishers, or JSR tokens were touched.

release tags ruleset (25452857), applied first so no unprotected pattern could deploy to publish. Only conditions.ref_name.include changed; rules (creation, update, deletion), enforcement (active), and bypass actors are unchanged.

include
Before refs/tags/moq-relay-v*, refs/tags/moq-cli-v*, refs/tags/moq-boy-v*, refs/tags/moq-c-v*, refs/tags/moq-gst-v*, refs/tags/moq-ffi-v*, refs/tags/moq-dart-v*
After the same, plus refs/tags/libmoq-v*

publish Environment deployment policies (custom branch policies; protected_branches: false, can_admins_bypass: true, unchanged):

Policies
Before branch main, branch release, tag moq-cli-v*, tag moq-ffi-v*, tag moq-relay-v*
After the same, plus tag moq-boy-v* (64995122), tag moq-gst-v* (64995124), tag libmoq-v* (64995125)

These admit release's Cachix publisher for every tag its cachix.yml triggers on.

(Written by Claude Opus 5.5)

@kixelated
kixelated marked this pull request as ready for review October 31, 2026 06:51
@pullfrog

pullfrog Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

This run hit its 1h time limit while still working. Give runs longer with --timeout=2h (or --notimeout) in this repo's instructions, or raise the workflow's timeout input if it sets one, since that input wins. A smaller PR or a lower effort also finishes sooner.

Repo settings → · Flags →

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using deepseek-v4.1-flash (free via Pullfrog for OSS)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated review by review (OpenAI)

Reviewed commit: 39f690a29802fdb8706e37c2c1e9156b8c62759e.

No actionable bugs found. Backporting the existing Environment boundary is a focused way to keep release publishing compatible with credential migration. Tag-to-commit checks fail closed before upstream code executes, protected environments align with publishing paths, and dry runs avoid those environments. JSR_TOKEN is removed before build/npm subprocesses and passed only to real Deno publication. No API or wire changes.

Verification limits: static GitHub inspection of all 16 changed files and relevant workflow paths, with an independent guard review. No builds, tests, mocked publishers or real publishing were run. Live Environment/ruleset settings, credential migration and external trusted-publisher restrictions were not independently verified; the documented settings migration remains necessary before repository credentials are removed.

(Written by OpenAI)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Landing summary for head 39f690a298, merged into release with a merge commit.

Changes: backports main's protected publishing Environments to release. Publishing jobs take credentials from publish, bot, or npm only on tag, release, main, or workflow_run events. Every workflow_run publisher now requires a protected release tag at the run's commit. Dry-runs and pull-request jobs request no Environment. release.ts hands JSR_TOKEN to deno publish alone.

Read-only PR CI: confirmed. The diff adds no permissions write scopes, and every Environment it adds is conditioned on a non-pull_request event (cache.yml, cachix.yml, apt-repo.yml, rpm-repo.yml, and alert.yml never trigger on pull requests). Pull-request CI on this head ran with no Environment credentials.

Checks: all required checks passed on this head. The earlier Release gate failure (run 41177122366) was cancelled by concurrency when the rerun 41178253418 started, and that rerun passed. Pullfrog (optional) hit its 1h limit without posting findings. quest check --base origin/release passed (439 documents).

Reviews: Codex and Claude local reviews of this head reported 0 findings (see ## Review). The OpenAI online review (review 5721703392) reported no actionable bugs. No unresolved threads.

Not done here: the credential migration (copying secrets into publish, removing repository copies, restricting trusted publishers, provisioning JSR_TOKEN in npm) stays with the maintainer, as the PR body's Follow-ups describe.

(Written by Claude Opus 5.5)

@kixelated
kixelated merged commit 7b784e5 into release Oct 31, 2026
44 of 47 checks passed
@kixelated
kixelated deleted the ci-read-only-secrets-release branch October 31, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant