@monumental-archive/lab-wasm 0.24.4 → 0.25.3
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.
- package/README.md +196 -0
- package/package.json +7 -1
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# release-lab
|
|
2
|
+
|
|
3
|
+
<!-- badges:begin -->
|
|
4
|
+
[](https://github.com/monumental-archive/release-lab/actions/workflows/gate.yml)
|
|
5
|
+
[](https://scorecard.dev/viewer/?uri=github.com/monumental-archive/release-lab)
|
|
6
|
+
[](https://raw.githubusercontent.com/monumental-archive/.github/levels/release-lab/build.report.json)
|
|
7
|
+
[](https://raw.githubusercontent.com/monumental-archive/.github/levels/release-lab/source.report.json)
|
|
8
|
+
[](https://raw.githubusercontent.com/monumental-archive/.github/levels/release-lab/dependency.report.json)
|
|
9
|
+
[](https://www.bestpractices.dev/projects/14067)
|
|
10
|
+
[](https://www.bestpractices.dev/projects/14067)
|
|
11
|
+
[](https://api.reuse.software/info/github.com/monumental-archive/release-lab)
|
|
12
|
+
[](https://codecov.io/gh/monumental-archive/release-lab)
|
|
13
|
+
[](https://doi.org/10.5281/zenodo.21914272)
|
|
14
|
+
[](https://www.npmjs.com/package/@monumental-archive/lab-wasm)
|
|
15
|
+
[](https://github.com/orgs/monumental-archive/packages/container/package/release-lab)
|
|
16
|
+
[](https://github.com/orgs/monumental-archive/packages/container/package/lab-pg)
|
|
17
|
+
[](https://fair-software.eu)
|
|
18
|
+
<!-- badges:end -->
|
|
19
|
+
|
|
20
|
+
The org's release lab: where risky release machinery is proven before any
|
|
21
|
+
production repository runs it. Fixture crates, **real GitHub APIs, real
|
|
22
|
+
credentials, real rulesets, real registries**.
|
|
23
|
+
|
|
24
|
+
The publishes are real, and that is the point — a rehearsal that ships
|
|
25
|
+
nowhere proves nothing. `@monumental-archive/lab-wasm` is on npm with
|
|
26
|
+
provenance, the images are on GHCR, the releases are immutable and carry
|
|
27
|
+
their full evidence bundles. What is disposable is the *meaning*: the
|
|
28
|
+
crates have no consumers and the version numbers are spent freely.
|
|
29
|
+
|
|
30
|
+
One line the lab never crosses: **crates.io**. Uploads there are
|
|
31
|
+
yank-only and a fixture has no business holding a name, so `rust-crate`
|
|
32
|
+
is the single class rehearsed dry. DOIs are deliberately NOT grouped
|
|
33
|
+
with that line (.github#316): a crates.io name is a scarce global
|
|
34
|
+
namespace a fixture would squat; a DOI is a citation record that
|
|
35
|
+
squats nothing. Every lab release mints a **real, permanent** version
|
|
36
|
+
DOI under the lab's one concept record — that pile-up at rehearsal
|
|
37
|
+
cadence is the design, because a rehearsal against a mirrored sandbox
|
|
38
|
+
API never proves the path the permanent record takes, and proving that
|
|
39
|
+
path is this repository's entire job.
|
|
40
|
+
|
|
41
|
+
The canon it proves lives in
|
|
42
|
+
[monumental-archive/.github](https://github.com/monumental-archive/.github)
|
|
43
|
+
— `docs/release.md`. Repositories conform to that canon; this is where the
|
|
44
|
+
canon is exercised first.
|
|
45
|
+
|
|
46
|
+
## Why a separate repository
|
|
47
|
+
|
|
48
|
+
A reusable workflow cannot run on its own — it needs a caller, and the
|
|
49
|
+
caller has to be a repository. Letting `.github` call its own workflows is
|
|
50
|
+
not enough, and that is not a theory: the shared gate carried a
|
|
51
|
+
`github.workflow_sha` bug precisely because its only exerciser lived in the
|
|
52
|
+
same repository, where the caller's SHA and the reusable workflow's SHA
|
|
53
|
+
happen to be identical. It broke the moment a different repository called
|
|
54
|
+
it.
|
|
55
|
+
|
|
56
|
+
So the lab is three things at once:
|
|
57
|
+
|
|
58
|
+
- **A foreign caller.** The only way to exercise the cross-repository path
|
|
59
|
+
— `job_workflow_sha`, permission downgrades, secrets forwarding, App
|
|
60
|
+
tokens crossing a repository boundary.
|
|
61
|
+
- **Fixtures.** The shared workflows are generic, but they still need real
|
|
62
|
+
inputs to execute their real code paths.
|
|
63
|
+
- **A cheap blast radius.** Release failures are mostly irreversible:
|
|
64
|
+
crates.io is yank-only, a published GHCR digest exists forever, an
|
|
65
|
+
immutable release cannot be repaired. Here they cost nothing.
|
|
66
|
+
|
|
67
|
+
The standing job is the last one. `uses:` accepts no expressions, so a
|
|
68
|
+
caller's SHA pin is frozen into whatever ref it ran from — **a bug in a
|
|
69
|
+
shared workflow is permanent for every tag already pinned to it.** Every
|
|
70
|
+
change to a shared workflow needs a foreign caller to prove it before any
|
|
71
|
+
production repository bumps its pin.
|
|
72
|
+
|
|
73
|
+
## What is exercised here
|
|
74
|
+
|
|
75
|
+
The canon's release machinery is complete (`.github#28`, closed): both
|
|
76
|
+
archetypes, every artifact class, repro gate, evidence bundles, signed
|
|
77
|
+
verdicts, DOIs. All of it ran here first. Four fixture crates carry it —
|
|
78
|
+
minimal, but structurally honest enough to make the shared workflows
|
|
79
|
+
execute their real code paths and reach their real endpoints:
|
|
80
|
+
|
|
81
|
+
| Fixture | Class it feeds |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `lab-core` | rust-crate (the library, and the internal path+version dependency shape) |
|
|
84
|
+
| `lab-cli` | rust-binary, and the binary that lands in the image |
|
|
85
|
+
| `lab-wasm` | wasm-npm |
|
|
86
|
+
| `lab-pg` | pgrx-extension, and its per-major extension images |
|
|
87
|
+
|
|
88
|
+
The caller stubs are the entire surface a conforming repository owns; the
|
|
89
|
+
logic they invoke lives in the canon, SHA-pinned:
|
|
90
|
+
|
|
91
|
+
| Stub | What it proves |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| `gate.yml` | the shared CI gate, called across a repository boundary |
|
|
94
|
+
| `release.yml` | phase 1 — version decision, changelog, Release PR, and on merge the App-minted `v*` tag and draft release |
|
|
95
|
+
| `publish.yml` | phase 2 at full width — `rust-binary`, `oci-image`, `wasm-npm` and `pgrx-extension` built for real across every supported Postgres major, repro-gated, signed through the org signer, pushed to GHCR and npm, with a real version DOI and an evidence bundle |
|
|
96
|
+
| `continuous.yml` | the continuous archetype — digest publish on merge, weekly rebuild, no tags, no versions |
|
|
97
|
+
| `exercise-sign.yml` | the org signer across a repository boundary: bytes built here, signed there without the signer ever seeing them, verified the way a stranger would |
|
|
98
|
+
| `source-attest.yml` | this repository's reserved source-signing identity (below) |
|
|
99
|
+
| `audit.yml`, `audit-repro.yml`, `scorecard.yml` | the Monday advisory audit, the Thursday cold rebuild of the latest published release, and the copied Scorecard stub |
|
|
100
|
+
|
|
101
|
+
Two classes are deliberately not run here for real. **rust-crate** is
|
|
102
|
+
rehearsed dry — the lab never uploads to crates.io — and its coexistence
|
|
103
|
+
and dry-run shape were proven on v0.15.3. **source-archive** is the
|
|
104
|
+
canon's own phase 2, exercised by `.github` on itself.
|
|
105
|
+
|
|
106
|
+
Both archetypes coexisting in one repository is intentional, not
|
|
107
|
+
leftover: `continuous.yml` refuses tags and `publish.yml` refuses
|
|
108
|
+
branches, and that pair of inverse guards is only tested where both live.
|
|
109
|
+
|
|
110
|
+
## What proving here has caught
|
|
111
|
+
|
|
112
|
+
Each of these was found on a real run, before any production repository
|
|
113
|
+
was touched, and none of them was visible to a linter:
|
|
114
|
+
|
|
115
|
+
| Found | How it presented | Resolution |
|
|
116
|
+
| --- | --- | --- |
|
|
117
|
+
| Canon checkout used `github.workflow_sha` | `upload-pack: not our ref` — the entry-point workflow's SHA is the *caller's* commit | `github.job_workflow_sha`, and ultimately the `$/.github/actions/canon` self-reference (`.github#165`) |
|
|
118
|
+
| The same bug, latent in the shared CI gate | never failed: its only caller lived in the same repository, where both SHAs coincide | fixed together |
|
|
119
|
+
| `git-cliff` absent from the toolbelt | `git: 'cliff' is not a git command` | belt standup |
|
|
120
|
+
| Tag-mint App lacked `pull_requests: write` | `The permissions requested are not granted to this installation` | App permission + install approval |
|
|
121
|
+
| An undecided advisory in a release SBOM | the dependency gate refused to publish v0.19.1 | dependency-keyed VEX; RUSTSEC-2021-0127 decided on v0.20.1 |
|
|
122
|
+
| The containerised `cargo build` was not reproducible | the repro gate went red on all seven image digests at v0.21.0, and nothing published | `.github#295` — five of seven fixed by `--provenance=false --sbom=false` + `rewrite-timestamp`, the last two by moving the compile out of the Dockerfile; bit-for-bit on v0.22.1 |
|
|
123
|
+
|
|
124
|
+
The last row is the shape worth keeping in mind. The gate blocked the
|
|
125
|
+
registry uploads, the tags, the append-only Sigstore entries and the
|
|
126
|
+
release itself; the entire cost of the finding was a disposable lab
|
|
127
|
+
version number.
|
|
128
|
+
|
|
129
|
+
## The `v*` tag-creation lock
|
|
130
|
+
|
|
131
|
+
Canon: humans never push release tags; only the pipeline's App mints them.
|
|
132
|
+
The ruleset restricts `v*` **creation** with the tag-mint App as sole bypass
|
|
133
|
+
actor.
|
|
134
|
+
|
|
135
|
+
Both halves are proven here under `enforcement: active` — note that
|
|
136
|
+
`evaluate` proves *neither*, since it enforces nothing and bypass actors
|
|
137
|
+
record no evaluation, so an empty rule-suite list looks identical whether
|
|
138
|
+
the lock works perfectly or does not exist:
|
|
139
|
+
|
|
140
|
+
| Half | Repro | Expected |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| Negative | `git tag -a v9.9.9-x -m x && git push origin v9.9.9-x` as a human | `GH013 ... Cannot create ref due to creations being restricted.` |
|
|
143
|
+
| Positive | merge a release PR; the tag job mints the tag via the App | annotated tag + draft release appear |
|
|
144
|
+
|
|
145
|
+
`current_user_can_bypass: never` is the check that the org owner is bound
|
|
146
|
+
too.
|
|
147
|
+
|
|
148
|
+
## Source attestation
|
|
149
|
+
|
|
150
|
+
This repository is one of the org's three source-track emitters
|
|
151
|
+
(`.github#207`) and was the first: it proved the emitter end to end before
|
|
152
|
+
`signer` and the canon founded their own chains, and the org's Source L3
|
|
153
|
+
claim moved only once all three were stranger-verified.
|
|
154
|
+
|
|
155
|
+
The chain was founded at `ea49b2f0` (2026-08-12) by
|
|
156
|
+
`.github/workflows/source-attest.yml`, the reserved signing identity. That
|
|
157
|
+
file's path at `@refs/heads/main` **is** the identity — a keyless
|
|
158
|
+
certificate names the workflow path plus ref — so moving or renaming it is
|
|
159
|
+
a breaking change to the root-of-trust contract, and its contents change
|
|
160
|
+
freely while its path never does.
|
|
161
|
+
|
|
162
|
+
Every revision on `main` since carries signed source provenance and a
|
|
163
|
+
source VSA in `refs/notes/commits`. Verify any of them with nothing but
|
|
164
|
+
the published root of trust (`docs/source-assessment.md` in the canon):
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
san="https://github.com/monumental-archive/release-lab"
|
|
168
|
+
san="${san}/.github/workflows/source-attest.yml@refs/heads/main"
|
|
169
|
+
cosign verify-blob --bundle <bundle> --certificate-identity "${san}" \
|
|
170
|
+
--certificate-oidc-issuer \
|
|
171
|
+
https://token.actions.githubusercontent.com <statement>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The first five links claim `SLSA_SOURCE_LEVEL_2` and stay that way: they
|
|
175
|
+
were emitted before the claims job held a token that could read org-level
|
|
176
|
+
tag-ruleset details, so the VSA under-claimed rather than assert a control
|
|
177
|
+
it could not see. They are not backfilled — honest degradation is a real
|
|
178
|
+
behaviour here, not a design intention.
|
|
179
|
+
|
|
180
|
+
An earlier pilot (2026-08-10) drove `slsa-framework/source-tool` and
|
|
181
|
+
parked on four upstream defects (watch `.github#199`); the org built its
|
|
182
|
+
own emitter instead of waiting. Those genesis attestations remain in this
|
|
183
|
+
repository's notes as the historical record — a different dialect, not a
|
|
184
|
+
link in the current chain.
|
|
185
|
+
|
|
186
|
+
Unlike releases, the notes chain is **not** disposable: each link verifies
|
|
187
|
+
its predecessor, so deleting notes breaks verification for everything after.
|
|
188
|
+
|
|
189
|
+
## Housekeeping
|
|
190
|
+
|
|
191
|
+
Immutable releases are ON (the draft-then-publish shape depends on it). Old
|
|
192
|
+
lab releases and tags are disposable; delete them freely between runs —
|
|
193
|
+
this repository has no consumers. One exception: the **latest** release is
|
|
194
|
+
load-bearing, because the Thursday `audit-repro` job rebuilds it and
|
|
195
|
+
compares against its published `checksums.txt`. Delete that one and the
|
|
196
|
+
audit reddens until the next release is cut.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@monumental-archive/lab-wasm",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Fixture wasm crate for the org release pipeline",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.25.3",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -19,5 +19,11 @@
|
|
|
19
19
|
"sideEffects": [
|
|
20
20
|
"./lab_wasm.js",
|
|
21
21
|
"./snippets/*"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"fixture",
|
|
25
|
+
"release",
|
|
26
|
+
"provenance",
|
|
27
|
+
"slsa"
|
|
22
28
|
]
|
|
23
29
|
}
|