Skip to content

ci: npm publish by operator dispatch only, in the main-only npm-publish environment - #238

Merged
luisleo526 merged 3 commits into
mainfrom
core/tnx-trig235
Oct 21, 2026
Merged

luisleo526 merged 3 commits into
mainfrom
core/tnx-trig235

Conversation

@luisleo526

@luisleo526 luisleo526 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

This replaces #235. It keeps #235's publish-pyodide trigger change, its tag guard, the docs and the tests, and drops the pf-ci-release runner moves (owner #1050: all CI on GitHub-hosted).

  • publish-pyodide.yml runs only on workflow_dispatch, with a required tag input. A new tag-guard job checks four things: the dispatch ref is refs/heads/main; the tag matches vX.Y.Z[-{alpha,beta,rc}.N]; the tag resolves to a commit; and that commit is reachable from origin/main. Publish then checks out the verified commit and checks VERSION against it. A tag push publishes nothing.
  • CONTRIBUTING.md and npm/README.md document the operator dispatch.
  • tests/test_release_workflows.py adds 112 cases. Among them, a guard against retired runner labels and dispatch-pin mutation tests.

Lab proof: rj-20261021t163238-d572aa on NTU, pytest exit 0 (tests=10215, failures=0, skipped=221; none skipped in the new file), on 1dc7962 (tree 0f17bb0c1e, clean).

Update after review (c95041d): the retired-runner guard now also discovers .yaml workflows, with a regression test for both suffixes. The release.yml comments no longer claim a tag push triggers npm. CONTRIBUTING and npm/README now state the limit plainly: the guard lives in the workflow file on main, but GitHub runs the file from the dispatched ref. So a server-side bound needs an admin-configured GitHub environment, with a main-only deployment-branch policy that the npm trusted publisher requires. That is not in this change. Left as low: runs-on indirection through vars/matrix, third-party dispatch actions, and tag identity beyond "a v-tag on main".

Also in this PR (46970e3, TX-NPMENV): environment: npm-publish on the publish and claim-npm jobs. The environment exists on this repo with a main-only deployment-branch policy (id 63870065). The npm trusted publisher for @pineforge/codegen-pyodide now requires it (owner, NPM-TP = A), so npm publishing fails until this merges. Tests pin exactly that environment on both jobs and no other environment in the file, with four mutations per job that must be refused.

🤖 Generated with Claude Code

luisleo526 and others added 2 commits October 22, 2026 00:18
Salvage the live half of #235 with a read-only release tag guard and a
checkout pinned to its verified commit on main. Retain GitHub-hosted
runners and document the operator dispatch; tag pushes publish nothing.

Retain and adapt manual-dispatch, guard mutation, credential, VERSION,
and real-git oracle tests, including the single-branch clone fix. Add a
repository-wide test rejecting retired runner labels in runs-on values.

Tests were not run locally per executor instructions; lab validation
remains with the supervisor.

Signed-off-by: luisleo526 <[email protected]>
… npm trigger comments and the dispatch-guard claim (PR #238 read)

An independent read of PR #238 (REJECT, six findings), each re-read in the tree by
the supervisor, drives these changes.

1. tests/test_release_workflows.py: test_no_workflow_uses_retired_runner_labels
   globbed *.yml only, while GitHub also loads *.yaml (the dispatch pin already
   globs both). It now discovers both. New parametrized regression
   test_retired_runner_guard_rejects_workflow_mutations (.yml and .yaml): the
   real release.yml text passes the guard in a temp directory, and the same text
   with its single `runs-on: ubuntu-latest` (anchor counted: exactly 1, enforced
   by mutate_once) replaced by `runs-on: self-hosted` is refused with the file name
   and line in the message.
2. .github/workflows/release.yml: comments only (header, conformance-gate note,
   PyPI step, tag step). They no longer say a tag push triggers npm; they say npm
   needs a separate manual workflow_dispatch of publish-pyodide.yml on main with
   the existing tag, and that the hub codegen-release dispatch happens right after
   PyPI and BEFORE any npm publish. No job, step, condition, permission or
   runner changed.
3. CONTRIBUTING.md and npm/README.md: one sentence each. The guard and job
   conditions live in the workflow file on main, but GitHub executes the file
   from the dispatched ref, so they alone cannot stop a user with write access
   who pushes and dispatches a modified workflow on another branch; a
   server-side bound needs an admin to configure a GitHub environment with a
   main-only deployment-branch policy and bind the npm trusted publisher to
   require it. That configuration is NOT part of this change and no
   `environment:` is added here.

Left, low: runs-on indirection through fromJSON(vars...), a matrix or a flow
mapping (the guard splits values on [a-z0-9_-]+); third-party dispatch actions
in the dispatch pin; the guard checks "a v-tag on main", not "the tag
release.yml created".

Not run: no local test run on this machine; the PR's CI is the proof.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@luisleo526 luisleo526 changed the title ci: publish npm only from verified release tags on main (operator dispatch) ci: npm publish by operator dispatch only, hosted runners; tag guard in the workflow on main Oct 21, 2026
…TX-NPMENV)

The independent read of PR #238 (finding 1) showed that the "only from main" property
of npm publishing is not enforced server-side: GitHub runs the workflow file from the
dispatched ref, so a user with write access could dispatch a modified workflow from
another branch. The GitHub environment `npm-publish` now exists on this repository
with a custom deployment-branch policy that allows `main` only (created and read back
by L6, policy id 63870065). A job that declares `environment: npm-publish` cannot run
from another branch, whatever its workflow file says.

Change: `environment: npm-publish` on the `publish` and `claim-npm` jobs of
publish-pyodide.yml (nothing else in the workflow changes).

Order matters and is intentional: declaring the environment before npm trusted
publishing requires it is harmless (the jobs only gain the main-only check); npm
requiring it before the workflow declares it would make publishing fail. So this change
merges first and the owner's npm trusted-publisher binding follows.

Tests (tests/test_release_workflows.py): assert_tagged_npm_dispatch now requires each
npm job to declare exactly `environment: npm-publish` and the workflow to declare no
other environment (text.count("environment:") == 2, counted against the shipped file).
New parametrized test_npm_jobs_must_run_in_the_main_only_environment, per job
(publish, claim-npm) x four mutations of the real text (line removed, renamed to
`production`, a second environment line added, an expression such as ${{ inputs.tag }}
substituted); each must be refused by the pin, and mutate_once fails on a stale anchor.

Not run: no local test run on this machine; the PR's CI is the proof.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@luisleo526 luisleo526 changed the title ci: npm publish by operator dispatch only, hosted runners; tag guard in the workflow on main ci: npm publish by operator dispatch only, in the main-only npm-publish environment Oct 21, 2026
@luisleo526
luisleo526 merged commit 197c831 into main Oct 21, 2026
8 of 12 checks passed
luisleo526 added a commit that referenced this pull request Oct 21, 2026
…ain-only `npm-publish` environment (#240)

PR #238 merged with two doc sentences that still said the server-side bound is configured
by an admin "outside this change". The change did add it (both npm jobs declare
`environment: npm-publish`, merged as 197c831) and the environment exists with a
`main`-only deployment-branch policy. CONTRIBUTING.md and npm/README.md now say that.

Rewritten sentence, in both files, by six consecutive words of the old text: "a
server-side bound requires an admin to configure a GitHub environment ... to require it,
outside this change".

New text: the bound is the GitHub environment `npm-publish`; `publish` and `claim-npm` run
in it; its main-only deployment-branch policy makes GitHub refuse a run from any other ref;
the npm trusted publisher is set by the owner to require the environment (owner decision
NPM-TP), a setting on npmjs.com that cannot be read from this repository, so a publish from
a workflow that does not declare the environment fails at npm. The claim about npm is
attributed to the owner's setting, not asserted as verified here.

Text only: 2 files, no workflow, test or code change. Not run: no local checks on this
machine; the PR's CI runs as usual.

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
luisleo526 added a commit that referenced this pull request Oct 25, 2026
* CHANGELOG: sections for 1.6.2 and 1.6.3 (release-notes backfill, CR-315)

The CHANGELOG had no 1.6.2 or 1.6.3 section: 1.7.0 sat directly above 1.6.1, although the
release note policy at the top of the file asks for a section per released version. This
adds both, from the tags (`git log` and `git diff` between v1.6.1, v1.6.2, v1.6.3) and the
GitHub release notes and the published advisory GHSA-5www-2x9c-mgr6:

- 1.6.3 (2026-10-23): the security fix merged from a private fork (commit 0418898,
  "Codegen can emit C++ calls and type names taken from the input script", high, CWE-94,
  affected pineforge-codegen 0.6.4 up to 1.6.3 and @pineforge/codegen-pyodide 0.7.0 up to
  1.6.3), stated as the advisory states it and without a reproduction recipe; and #237,
  #238, #239, #240 (CI, npm publishing environment, documentation).
- 1.6.2 (2026-10-21): the pf-cpp-allowlist checker (#210), the LIBC_RESERVED_NAMES
  reserved-name change in the emitter, the licensor entity written as PINEFORGE LLC (#234),
  and the CI changes #212, #214, #215, #216, #217, #221, #223, #225, #233, #236.

Additions only (0 lines removed): no sentence is replaced. No file other than CHANGELOG.md
changes.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* CHANGELOG: 1.6.3 compatibility text states that the security fix refuses scripts (REV P2) (CR-315)

REV-CX's read of the CR-315 backfill (reports/verdict-cr315.md) found that the 1.6.3
Compatibility bullet understated the fix. Checked against `git diff v1.6.2 v1.6.3` of
pineforge_codegen/ before writing it:

- visit_call.py / visit_expr.py: an unknown call or a member read on a builtin-backed
  receiver no longer reaches the emitted C++ as text; it ends with
  "<name>(...) is not implemented in PineForge runtime.";
- parser.py: a string, number or operator in a type position or inside <...> raises a
  located ParseError;
- support_checker.py: array.new / array.from with an undeclared element type is refused
  with the same "not implemented" message;
- types.py: the default of an enum-typed element is na<double>() (a name that is not a
  declared user type falls back to its slot's default); visit_expr.py: format, currency
  and order values are typed std::string.

So a script that compiled under 1.6.2 can fail under 1.6.3, which the bullet now says.
Also (REV P3): the pf-cpp-allowlist entry carries the advisory's own caveat (a denylist
with known false positives, not proof that a unit is safe), and the Security entry states
that release images before 1.6.3 contain an affected codegen and the 1.6.3 image the fixed
one.

Replaces text added by the previous commit of this change (d009aee), not on main.
CHANGELOG.md only.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 5.5 <[email protected]>
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