code-foundry 1.16.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,144 @@
1
+ name: Qualified Foundry Publication
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ tag:
7
+ description: Published immutable release tag at the caller commit.
8
+ required: true
9
+ type: string
10
+ asset:
11
+ description: Exact pre-attached Code Foundry npm tarball name.
12
+ required: true
13
+ type: string
14
+ environment:
15
+ description: Protected GitHub environment for npm publication.
16
+ required: false
17
+ default: npm
18
+ type: string
19
+ secrets:
20
+ NPM_TOKEN:
21
+ required: false
22
+
23
+ permissions:
24
+ attestations: read
25
+ contents: read
26
+
27
+ jobs:
28
+ qualify:
29
+ name: Qualify Node ${{ matrix.node }}
30
+ if: vars.CI_BILLING_PAUSED != 'true' && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
31
+ runs-on: ubuntu-24.04
32
+ timeout-minutes: 15
33
+ strategy:
34
+ fail-fast: false
35
+ matrix:
36
+ node: ['20', '22', '24']
37
+ steps:
38
+ - name: Checkout trusted qualification runtime
39
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
40
+ with:
41
+ persist-credentials: false
42
+ ref: ${{ github.sha }}
43
+ - name: Setup Node
44
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
45
+ with:
46
+ node-version: ${{ matrix.node }}
47
+ - name: Install pinned Actionlint
48
+ run: go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
49
+ - name: Download and cryptographically verify the release archive
50
+ env:
51
+ GH_TOKEN: ${{ github.token }}
52
+ RELEASE_TAG: ${{ inputs.tag }}
53
+ RELEASE_ASSET: ${{ inputs.asset }}
54
+ run: |
55
+ set -euo pipefail
56
+ node src/commands/qualified-publication.mjs download \
57
+ "$GITHUB_REPOSITORY" "$RELEASE_TAG" "$GITHUB_SHA" "$RELEASE_ASSET" \
58
+ "$RUNNER_TEMP/candidate" > "$RUNNER_TEMP/download.json"
59
+ - name: Qualify those exact bytes
60
+ env:
61
+ RELEASE_ASSET: ${{ inputs.asset }}
62
+ run: |
63
+ set -euo pipefail
64
+ node src/lib/consumer-qualification.mjs \
65
+ "$RUNNER_TEMP/candidate/$RELEASE_ASSET" "$GITHUB_SHA" \
66
+ "$RUNNER_TEMP/report.json" "$(go env GOPATH)/bin/actionlint"
67
+ - name: Retain this attempt's qualification report
68
+ if: always()
69
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
70
+ with:
71
+ name: qualified-${{ github.run_attempt }}-node-${{ matrix.node }}
72
+ path: ${{ runner.temp }}/report.json
73
+ if-no-files-found: error
74
+ retention-days: 14
75
+
76
+ publish:
77
+ name: Publish qualified archive
78
+ needs: qualify
79
+ if: vars.CI_BILLING_PAUSED != 'true' && github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
80
+ runs-on: ubuntu-24.04
81
+ timeout-minutes: 15
82
+ environment: ${{ inputs.environment }}
83
+ concurrency:
84
+ group: qualified-foundry-npm-${{ github.repository }}-${{ inputs.tag }}
85
+ cancel-in-progress: false
86
+ permissions:
87
+ actions: read
88
+ attestations: read
89
+ contents: read
90
+ id-token: write
91
+ env:
92
+ HAS_NPM_TOKEN: ${{ secrets.NPM_TOKEN != '' }}
93
+ RELEASE_TAG: ${{ inputs.tag }}
94
+ RELEASE_ASSET: ${{ inputs.asset }}
95
+ steps:
96
+ - name: Checkout trusted publication runtime
97
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
98
+ with:
99
+ persist-credentials: false
100
+ ref: ${{ github.sha }}
101
+ - name: Setup Node for trusted publishing
102
+ if: env.HAS_NPM_TOKEN != 'true'
103
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
104
+ with:
105
+ node-version: '24'
106
+ - name: Setup Node for token publishing
107
+ if: env.HAS_NPM_TOKEN == 'true'
108
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
109
+ with:
110
+ node-version: '24'
111
+ registry-url: https://registry.npmjs.org
112
+ - name: Retrieve only this run attempt's evidence
113
+ env:
114
+ GH_TOKEN: ${{ github.token }}
115
+ run: |
116
+ set -euo pipefail
117
+ for node in 20 22 24; do
118
+ gh run download "$GITHUB_RUN_ID" --repo "$GITHUB_REPOSITORY" \
119
+ --name "qualified-$GITHUB_RUN_ATTEMPT-node-$node" \
120
+ --dir "$RUNNER_TEMP/reports/$node"
121
+ done
122
+ node src/commands/qualified-publication.mjs download \
123
+ "$GITHUB_REPOSITORY" "$RELEASE_TAG" "$GITHUB_SHA" "$RELEASE_ASSET" \
124
+ "$RUNNER_TEMP/candidate" > "$RUNNER_TEMP/download.json"
125
+ - name: Reverify and publish the tested tarball without lifecycle hooks
126
+ env:
127
+ GH_TOKEN: ${{ github.token }}
128
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
129
+ run: |
130
+ set -euo pipefail
131
+ node src/commands/qualified-publication.mjs publish \
132
+ "$GITHUB_REPOSITORY" "$RELEASE_TAG" "$GITHUB_SHA" "$RELEASE_ASSET" \
133
+ "$RUNNER_TEMP/candidate" \
134
+ "$RUNNER_TEMP/reports/20/report.json" \
135
+ "$RUNNER_TEMP/reports/22/report.json" \
136
+ "$RUNNER_TEMP/reports/24/report.json" > "$RUNNER_TEMP/publication.json"
137
+ - name: Retain publication identity
138
+ if: always()
139
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
140
+ with:
141
+ name: qualified-publication-${{ github.run_attempt }}
142
+ path: ${{ runner.temp }}/publication.json
143
+ if-no-files-found: warn
144
+ retention-days: 14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.18.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.17.0...v1.18.0) (2026-09-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * **releases:** stage qualified assets and publish verified identical archives ([#547](https://github.com/0xPlayerOne/code-foundry/issues/547)) ([dffcb83](https://github.com/0xPlayerOne/code-foundry/commit/dffcb834c8ee8c5c2bcba606350276e6a7de58d0))
9
+
10
+ ## [1.17.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.16.0...v1.17.0) (2026-09-09)
11
+
12
+
13
+ ### Features
14
+
15
+ * **quality:** add opt-in site, app, Worker, and package acceptance profiles ([#545](https://github.com/0xPlayerOne/code-foundry/issues/545)) ([1201793](https://github.com/0xPlayerOne/code-foundry/commit/1201793805b443c835b608609704bc43bcb035f5))
16
+
3
17
  ## [1.16.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.15.0...v1.16.0) (2026-09-09)
4
18
 
5
19
 
package/README.md CHANGED
@@ -39,6 +39,8 @@ contract. For normal updates, edit that file and run `npx code-foundry sync`.
39
39
  audits, Draft Guard, Draft PR, Release PR, and Release.
40
40
  - A deterministic performance lane with ordered command support, stable result
41
41
  artifacts, and an optional shared Node package budget profile.
42
+ - An opt-in product-quality runner for static sites, web apps, Workers, and
43
+ published packages.
42
44
  - A small `.githooks/pre-commit` launcher with language-aware formatting and
43
45
  linting.
44
46
  - An optional `.mise.toml`/`mise.lock`, repository profile configuration, and
@@ -15,9 +15,9 @@ belong to the run that produced them, not the source tree.
15
15
  | Format, lint, type-check, and build | 15 s | Bound the local CI feedback loop |
16
16
  | Runtime dependencies | 0 | Keep the installed CLI dependency-free |
17
17
  | Development dependencies | 4 | Prevent unreviewed toolchain growth |
18
- | Packed artifact | 225 kB | Bound registry transfer and install cost |
19
- | Unpacked artifact | 860 kB | Bound installed footprint |
20
- | Packed files | 100 | Detect accidental release contents |
18
+ | Packed artifact | 250 kB | Bound registry transfer and install cost |
19
+ | Unpacked artifact | 930 kB | Bound installed footprint |
20
+ | Packed files | 110 | Detect accidental release contents |
21
21
 
22
22
  The performance workflow disables build-cache reads and writes for this task.
23
23
  That makes timing comparisons independent of a warm protected-branch cache and
@@ -26,7 +26,14 @@ prevents benchmark code from populating shared cache entries.
26
26
  The consumer qualification workflow adds the installed-package harness and
27
27
  workflow contract to the distributable. The merged candidate measured 221,495
28
28
  packed bytes, 853,573 unpacked bytes, and 100 files on Node 24.18.0; the updated
29
- budgets leave a small margin while continuing to bound package growth.
29
+ budgets leave a small margin while continuing to bound package growth. The
30
+ product-quality profiles and consumer qualification workflow measured 232,650
31
+ packed bytes, 890,418 unpacked bytes, and 103 files on Node 24.18.0, so the
32
+ limits remain intentionally bounded while covering both opt-in feature sets.
33
+ The qualified-publication workflow adds the release staging and publication
34
+ contract to the distributable. This candidate measured 238,816 packed bytes,
35
+ 915,957 unpacked bytes, and 106 files on Node 24.18.0; the 250 kB and 930 kB
36
+ limits retain a measured margin while covering the required release path.
30
37
 
31
38
  ## v1.6.1 baseline
32
39
 
package/docs/README.md CHANGED
@@ -15,6 +15,7 @@ its own names, environments, and deployment details.
15
15
  - [Caching and remote caching](CACHING.md)
16
16
  - [Performance budgets and baselines](PERFORMANCE.md)
17
17
  - [Required capabilities and task evidence](required-capabilities.md)
18
+ - [Product quality profiles](product-quality.md)
18
19
  - [Agent-facing validation commands](agent-validation.md)
19
20
  - [Declarative fleet inventory and staged rollouts](fleet-rollouts.md)
20
21
 
@@ -0,0 +1,173 @@
1
+ # Product Quality Profiles
2
+
3
+ Opt-in acceptance checks for built sites, interactive applications, Workers, and packages.
4
+
5
+ **Status:** Additive runner; existing repositories are not opted in automatically.
6
+ **Evidence:** Fresh per-run reports under `.code-foundry/quality/`.
7
+
8
+ ## Activation
9
+
10
+ Commit a version-1 JSON manifest and use the installed, pinned Foundry runtime:
11
+
12
+ ```json
13
+ {
14
+ "scripts": {
15
+ "quality:build": "node node_modules/code-foundry/src/quality.mjs .github/product-quality.json build",
16
+ "quality:browser": "node node_modules/code-foundry/src/quality.mjs .github/product-quality.json browser"
17
+ }
18
+ }
19
+ ```
20
+
21
+ Wire these scripts into the consumer's existing validation entrypoints. The
22
+ Foundry runtime discovers only `performance:check`/`perf:check` and
23
+ `test:e2e`/`e2e`; if those names do not already exist, they can run
24
+ `bun run quality:build` and `bun run quality:browser`. If they do exist, preserve their current
25
+ commands and compose the quality command after them rather than replacing the
26
+ existing performance or E2E checks. The standalone entrypoint deliberately avoids
27
+ changing the public CLI dispatch being introduced in the separate agent-validation
28
+ PR. Install the reviewed Foundry version in the consumer's existing dependency
29
+ manager and lockfile, not an unpinned network invocation. Add `.code-foundry/` to
30
+ Git/package ignores and retain selected evidence through the consumer workflow's
31
+ artifact uploader. Reports and browser traces may contain application data; review
32
+ retention and never upload authenticated traces publicly without sanitization.
33
+
34
+ ```json
35
+ {
36
+ "schema_version": 1,
37
+ "prepare": { "build": [["bun", "run", "build"]] },
38
+ "profiles": [
39
+ {
40
+ "id": "marketing",
41
+ "type": "static-site",
42
+ "dist": "dist",
43
+ "origin": "https://example.com",
44
+ "routes": [{ "path": "/", "html": "index.html", "javascriptAssets": [] }],
45
+ "budgets": { "htmlBytes": 100000, "javascriptBytes": 80000, "imageBytes": 600000 },
46
+ "sitemap": "sitemap.xml",
47
+ "robots": "robots.txt",
48
+ "redirects": { "file": "_redirects", "rules": [{ "from": "/old", "to": "/", "status": 301 }] }
49
+ }
50
+ ]
51
+ }
52
+ ```
53
+
54
+ Example numbers are not fleet defaults. Measure and review thresholds in the
55
+ consumer repository. `prepare` runs once per selected phase, so several profiles
56
+ can share one build without repeating it. A phase with no applicable profiles
57
+ fails instead of pretending to validate something. Available phases are `build`,
58
+ `browser`, and `deployed`; assign a profile's `phase` explicitly to override its
59
+ default (`browser` for web-app, `build` for the others).
60
+
61
+ ## Static sites
62
+
63
+ The static profile checks explicit rendered routes for titles, descriptions,
64
+ canonical identity, accidental noindex, local links/anchors, directly referenced
65
+ resources, declared additional JavaScript chunks, sitemap inclusion, robots
66
+ sitemap declaration, and exact simple `_redirects` rules. All responsive image
67
+ candidates count toward the asset budget. Budgets measure build bytes, not an
68
+ estimate of browser transfer size or Core Web Vitals. `javascriptAssets` must
69
+ include transitive chunks selected from the consumer's bundler manifest; this
70
+ runner does not invent a framework dependency graph. External resources fail
71
+ closed rather than being treated as zero-byte dependencies.
72
+
73
+ This conservative generated-HTML parser is not a browser DOM or a complete HTML
74
+ conformance validator. Complex base-element routing, sitemap indexes, wildcard or
75
+ conditional redirects, client-only metadata, and CDN behavior need repository-owned
76
+ or deployed tests. All generated/public routes should be declared (or the manifest
77
+ generated from the framework's route output) to avoid untested routes. Redirect
78
+ checks prove the artifact declaration, not production routing behavior.
79
+
80
+ ## Interactive applications
81
+
82
+ ```json
83
+ {
84
+ "id": "application",
85
+ "type": "web-app",
86
+ "baseURL": "http://127.0.0.1:4321",
87
+ "webServerCommand": "bun run preview --host 127.0.0.1",
88
+ "journeys": "tests/quality-journeys.mjs",
89
+ "snapshots": "tests/quality-snapshots",
90
+ "routes": [{ "id": "home", "path": "/", "readySelector": "main h1", "visual": true }]
91
+ }
92
+ ```
93
+
94
+ `baseURL` must be an HTTP(S) origin without a path, query, or fragment; routes
95
+ are root-relative paths on that origin. Use the repository's locked
96
+ `@playwright/test`, `@axe-core/playwright`, and matching Chromium installation.
97
+ No browser tooling is silently downloaded. The runner
98
+ imports the consumer's journey module and requires at least one additional real
99
+ passing test beyond its generated route tests. Skips, flakes, expected-failure
100
+ annotations, incomplete results, and missing routes fail the evidence check.
101
+ Each generated route validates navigation, waits for the declared readiness
102
+ selector, checks page runtime errors, and performs axe WCAG 2/2.1 A/AA checks.
103
+ Automation does not establish complete accessibility compliance.
104
+
105
+ Selected visual routes compare repository-owned baselines with
106
+ `updateSnapshots: none`. Missing baselines fail; this runner never approves them.
107
+ Create and review baselines separately in the same browser/OS/font environment.
108
+ The generated configuration fixes Chromium, viewport, retries, and screenshot
109
+ animation handling; specialized device/authentication fixtures remain in the
110
+ consumer's journey tests. Remote base URLs require explicit `allowRemote: true`;
111
+ that is consent to network testing, not isolation. Secrets, account fixtures, and
112
+ production-safe test behavior remain the consumer's responsibility.
113
+
114
+ ## Cloudflare Workers
115
+
116
+ ```json
117
+ {
118
+ "id": "worker",
119
+ "type": "worker",
120
+ "buildCommand": ["bun", "run", "worker:bundle", "{output}"],
121
+ "files": ["worker.js"],
122
+ "budgets": { "rawBytes": 1000000, "gzipBytes": 250000 },
123
+ "runtimeCommand": ["bun", "run", "worker:compatibility", "{output}"]
124
+ }
125
+ ```
126
+
127
+ The build command must emit selected bundles into the fresh output directory.
128
+ `{output}` arguments and `CODE_FOUNDRY_QUALITY_OUTPUT_DIR` expose that directory.
129
+ Raw bytes and the sum of individually gzipped files are measured; they are not
130
+ claimed to equal Cloudflare's uploaded aggregate size or startup limits. Use
131
+ locked Wrangler/workerd to test compatibility dates, flags, and bindings in the
132
+ mandatory native runtime command. Production smoke probes belong in the verified
133
+ delivery workflow, not a hidden dependency of the deterministic build phase.
134
+ No Worker, Durable Object, binding, migration, or production resource is created.
135
+
136
+ ## Published packages
137
+
138
+ ```json
139
+ {
140
+ "id": "package",
141
+ "type": "package",
142
+ "imports": ["my-package", "my-package/feature"],
143
+ "runtimes": ["node"],
144
+ "offline": true
145
+ }
146
+ ```
147
+
148
+ The package profile packs once without lifecycle scripts, installs that archive
149
+ into an isolated temporary consumer, and exercises declared package exports using
150
+ Node and/or Bun already installed on the runner. Run build/test preparation
151
+ explicitly first. Both install scripts and package lifecycle hooks are disabled;
152
+ packages requiring installation hooks need a separately reviewed specialized
153
+ consumer suite. Runtime dependencies must be cached for the default offline mode;
154
+ `offline: false` explicitly permits normal registry resolution. Temporary package
155
+ installations are removed. Evidence is rejected if it leaks into the package.
156
+
157
+ ## Evidence and trust
158
+
159
+ Each summary has a unique run ID, manifest hash, phase, source commit/dirty status
160
+ when available, per-profile metrics or failure reasons, and final status. A new
161
+ output directory prevents old reports from becoming current evidence. The source
162
+ fields are descriptive, not a signed dirty-worktree snapshot. Commands are argv
163
+ arrays without shell expansion; repository-owned commands still have the normal
164
+ permissions of the executing process and are not sandboxed. Playwright's optional
165
+ web-server command is its native shell-command interface and must be reviewed.
166
+
167
+ The runner does not replace Lighthouse CI, native application tests, manual
168
+ accessibility testing, real consumer canaries, or release provenance. Existing
169
+ Lighthouse assertions can remain in repository-owned scripts/preparation; no
170
+ Lighthouse score or threshold is silently introduced by this feature.
171
+
172
+ References: [Playwright accessibility](https://playwright.dev/docs/accessibility-testing),
173
+ [Playwright snapshot configuration](https://playwright.dev/docs/api/class-testconfig#test-config-update-snapshots).
@@ -0,0 +1,111 @@
1
+ # Qualified Publication
2
+
3
+ Publish only the same immutable Code Foundry archive that passed consumer qualification.
4
+
5
+ **Dependencies:** Consumer qualification (#544) and release integrity (#537).
6
+ **Activation:** Opt-in replacement publisher; no existing publisher is silently changed.
7
+
8
+ The reusable `qualified-foundry-publish.yml` downloads an explicitly named npm
9
+ archive from an already-published immutable release, verifies the release and
10
+ asset attestations against the caller's exact commit, qualifies that same archive
11
+ on Node 20/22/24, and only then admits a protected npm publication job. The final
12
+ job downloads only reports from its own workflow run **and run attempt**, rechecks
13
+ all required fixtures and archive/source identities, repeats cryptographic asset
14
+ verification, validates the package name/version, and publishes the tarball with
15
+ lifecycle scripts disabled. It never publishes a directory or rebuilds the package.
16
+
17
+ The publishing job uses a GitHub environment, serializes publication for a tag,
18
+ and has no dependency installation/build step. Qualification has no npm credential.
19
+ Normal npm trusted publishing is preferred; an explicit optional token supports
20
+ existing consumers. Configure the trusted publisher for the **actual caller and
21
+ reusable-workflow relationship** before enabling this route. Existing version
22
+ publication is not overwritten: retrying an already-published version fails rather
23
+ than treating a registry conflict or network error as proof of identity.
24
+
25
+ ## Release producer contract
26
+
27
+ Build and test a package once, attach its tarball to a **draft** release, then
28
+ publish that release with immutability enabled. The archive must contain the
29
+ Code Foundry CLI/templates; this is intentionally not a generic package harness.
30
+ The candidate's `package.json` name must be `code-foundry` and its version must
31
+ match the explicit tag. All qualification modules must exist in the caller commit.
32
+ A recent GitHub CLI with `release verify` and `release verify-asset` is required;
33
+ missing support or authentication errors fail closed.
34
+
35
+ This workflow blocks npm publication, not a GitHub Release that was already
36
+ published. It does **not** add assets after an immutable release is published.
37
+ The `stage` command implements the draft-asset producer: it verifies qualification,
38
+ checks immutability without changing settings, resolves the existing tag to the
39
+ qualified commit, uploads the archive and digest-bound qualification receipt,
40
+ rechecks uploaded digests, then publishes and verifies the release. It requires
41
+ an existing draft and existing tag; it never creates/moves tags or overwrites
42
+ conflicting assets. Settings permission failures block writes. Matching existing
43
+ assets can resume staging; conflicting assets require manual reconciliation.
44
+ The pre-release gate in #544 supplies the required matrix reports.
45
+ The legacy Release Please workflow creates releases without
46
+ this archive staging step. Wire the new `stage` command into a draft-producing
47
+ caller instead of pointing the old direct-release caller at the new publisher:
48
+
49
+ ```sh
50
+ node src/commands/qualified-publication.mjs stage \
51
+ "$GITHUB_REPOSITORY" "$TAG" "$SOURCE_SHA" "$ASSET" "$CANDIDATE_DIRECTORY" \
52
+ "$REPORT_NODE_20" "$REPORT_NODE_22" "$REPORT_NODE_24"
53
+ ```
54
+
55
+ The stage command needs a credential with immutable-setting read, release
56
+ write, and attestation-read access; a normal Actions token may lack the
57
+ administration-read permission.
58
+ No elevated credential is installed or requested automatically. The producer must
59
+ also prevent concurrent tag mutation (for example with protected release-tag
60
+ rules and a single tag-scoped producer); GitHub does not offer an atomic
61
+ "publish this draft only if the tag still resolves to SHA" operation. The final
62
+ verification blocks npm if that invariant is violated, but cannot undo an
63
+ already-published immutable release.
64
+
65
+ Disable the old npm path before
66
+ activating the replacement to prevent racing publishers. None of those production
67
+ settings or existing release workflows are changed in this PR.
68
+
69
+ Example caller job after its release producer (illustrative job IDs):
70
+
71
+ ```yaml
72
+ permissions:
73
+ actions: read
74
+ attestations: read
75
+ contents: read
76
+ id-token: write
77
+ jobs:
78
+ publish:
79
+ needs: release-producer
80
+ uses: ./.github/workflows/qualified-foundry-publish.yml
81
+ with:
82
+ tag: ${{ needs.release-producer.outputs.tag }}
83
+ asset: ${{ needs.release-producer.outputs.npm-asset }}
84
+ environment: npm
85
+ secrets:
86
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
87
+ ```
88
+
89
+ Only main-branch `push` and `workflow_dispatch` callers are admitted. Pull-request
90
+ events (including fork PRs), release-event shortcuts, and billing-paused runs
91
+ cannot publish through this workflow. The event guard does not itself verify
92
+ branch protection or prohibit a fork's independent main-branch workflow; configure
93
+ branch/environment protections and registry publisher identity separately.
94
+ The tag must resolve to `github.sha`, not a caller-selected old commit. To retry
95
+ an older release after main moves, use a separately reviewed recovery procedure;
96
+ do not weaken the identity gate ad hoc.
97
+
98
+ ## Local policy tests and trust
99
+
100
+ `node --test test/qualified-publication.test.mjs` uses CLI/verifier fixtures to
101
+ exercise missing matrix members, skipped checks, absent Actionlint, changed
102
+ archives, invalid asset names, wrong package identity, and prevention of npm
103
+ execution before verification. These tests do not establish live GitHub signing,
104
+ OIDC permissions, registry publication, or runner tool availability.
105
+
106
+ Qualification reports are not standalone signatures: they are trusted only after
107
+ selection from this workflow's successful jobs in the same run attempt. Supplying
108
+ arbitrary local JSON to the library is not a security boundary. The reusable
109
+ workflow and its caller must be reviewed/trusted and protected; repository-owned
110
+ code executes with the permissions of its job. No credentials or production
111
+ resources were configured by adding this feature.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
6
6
  "bugs": {