Skip to content

Commit 077b362

Browse files
theCodeDriftclaude
andcommitted
ci(vale): pin the publish job to main in code, not only in settings
Review finding on #136: with the required reviewer gone, the environment's deployment branch policy is the ONLY thing keeping an off-`main` `workflow_dispatch` from publishing. Under `npm-production` there were two independent obstacles; this PR removed one of them, so the remaining one should not also be the only one. The guard duplicates the branch policy on purpose. One copy lives in a settings page that can be edited without review and whose relaxation is an absence — nothing turns red when it happens. The other lives here, next to the reasoning, and cannot change without a diff. `github.ref == 'refs/heads/main'` covers both paths into this job. The `push` path is already filtered to `main`, so the guard is a no-op there; the `workflow_dispatch` path is the real case, since a dispatch runs from whatever ref it was launched on. Only `publish` is guarded. `gate` and `prepare` hold no environment, no id-token, and only `contents: read`, so off-`main` they are a harmless dry run of the digest verification and the pack. Guarding them instead would protect `publish` by inference through `needs:` — one control with a spare, which is the shape being corrected. The spec requirement gains the same constraint, so deleting either copy is a spec violation rather than a tidy-up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
1 parent db977b7 commit 077b362

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

‎.github/workflows/release-vale.yml‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,31 @@ jobs:
290290
publish:
291291
name: Publish to npm
292292
needs: prepare
293+
# DELIBERATE DUPLICATE of the `npm-autopublish` deployment branch policy.
294+
# The duplication IS the point: two independent controls, one of which lives
295+
# in a settings page and one of which lives here, in a file that cannot
296+
# change without code review. Do not delete this as redundant with the
297+
# environment — the environment is exactly what it is defending against.
298+
#
299+
# This became load-bearing when the required reviewer went away. Under
300+
# `npm-production` an off-`main` publish had to get past the branch policy
301+
# AND a human clicking approve; with the reviewer gone the branch policy is
302+
# the only thing left, and a settings edit by someone who does not know it
303+
# is load-bearing silently enables publishing from any branch. That failure
304+
# is an ABSENCE, so nothing goes red when it happens.
305+
#
306+
# One expression covers both ways this job can be reached. The `push` path
307+
# is already `branches: [main]`, so the guard is a no-op there and costs
308+
# nothing. The `workflow_dispatch` path is the real case: a dispatch runs
309+
# from whatever ref it was launched on, and `github.ref` is that ref.
310+
#
311+
# Only `publish` is guarded, on purpose. `gate` and `prepare` hold no
312+
# environment, no id-token, and only `contents: read`, so running them off
313+
# `main` publishes nothing — it is a useful dry run of the digest
314+
# verification and the pack. Guarding them instead would protect this job
315+
# only by inference through `needs:`, which is one control with a spare
316+
# rather than two controls.
317+
if: github.ref == 'refs/heads/main'
293318
runs-on: ubuntu-latest
294319
# The scoping and audit boundary for the release, and where the npm trusted
295320
# publisher for each @taskless/vale-* package is bound. Reviewer-free by

‎openspec/specs/vale-binary-packages/spec.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ Platform packages SHALL be versioned and published by a workflow dedicated to th
9191

9292
A published-version check cannot bound these runs — every run stamps a previously unused timestamp — so the upstream comparison SHALL be what prevents redundant publishing.
9393

94-
That workflow SHALL publish without a human approval step, using the reviewer-free publishing environment. Its review gate is the manifest-update pull request, where a human reviews the upstream version and every checksum before anything may be published; an environment approval would be a second copy of a gate that already exists, at a point where nothing is being decided. The publish remains bounded by the branch policy on that environment and by the requirement below that a published platform package changes no consumer.
94+
That workflow SHALL publish without a human approval step, using the reviewer-free publishing environment. Its review gate is the manifest-update pull request, where a human reviews the upstream version and every checksum before anything may be published; an environment approval would be a second copy of a gate that already exists, at a point where nothing is being decided. The publish remains bounded by the branch policy on that environment and by the requirement below that a published platform package changes no consumer. Because removing the approval leaves the branch restriction as the only control over where a publish may run from, that restriction SHALL be enforced twice — once by the environment's configuration and once by the workflow itself, so that neither can be relaxed without the other noticing.
9595

9696
#### Scenario: Upstream unchanged publishes nothing
9797

@@ -114,6 +114,11 @@ That workflow SHALL publish without a human approval step, using the reviewer-fr
114114
- **THEN** it SHALL proceed without waiting for an environment approval
115115
- **AND** it SHALL run in the reviewer-free publishing environment, restricted to the default branch
116116

117+
#### Scenario: A publish requested from another branch does nothing
118+
119+
- **WHEN** a publish is requested manually from a ref other than the default branch
120+
- **THEN** no package is published, and this SHALL hold independently of the publishing environment's configuration
121+
117122
#### Scenario: Ordinary pushes do not publish platform packages
118123

119124
- **WHEN** a commit is pushed to the default branch

0 commit comments

Comments
 (0)