Repository navigation
ci: npm publish by operator dispatch only, in the main-only npm-publish environment - #238
Merged
Merged
Conversation
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]>
…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]>
This was referenced Oct 21, 2026
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]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.ymlruns only onworkflow_dispatch, with a requiredtaginput. A newtag-guardjob checks four things: the dispatch ref isrefs/heads/main; the tag matchesvX.Y.Z[-{alpha,beta,rc}.N]; the tag resolves to a commit; and that commit is reachable fromorigin/main. Publish then checks out the verified commit and checks VERSION against it. A tag push publishes nothing.tests/test_release_workflows.pyadds 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
.yamlworkflows, 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-onindirection 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-publishon thepublishandclaim-npmjobs. 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