@ai-ecoverse/slicc 1.47.3 → 1.48.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.
- package/README.md +21 -66
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -210,10 +210,10 @@ A profile that doesn't exist is an error (`SLICC six's Chrome profile doesn't ex
|
|
|
210
210
|
Put the binary and the release's `SHA256SUMS` in one folder, then check:
|
|
211
211
|
- **Checksum on macOS and Linux:** `shasum -a 256 -c SHA256SUMS --ignore-missing`. On Linux `sha256sum -c SHA256SUMS --ignore-missing` does the same.
|
|
212
212
|
- **Checksum on Windows (PowerShell):** `(Get-FileHash slicc-windows-amd64.exe -Algorithm SHA256).Hash.ToLower()` must equal the hash on that file's line in `SHA256SUMS` (`Select-String slicc-windows-amd64.exe SHA256SUMS`).
|
|
213
|
-
- **Provenance:** `gh attestation verify
|
|
213
|
+
- **Provenance:** `gh attestation verify SHA256SUMS --repo ai-ecoverse/slicc-cli --signer-workflow ai-ecoverse/slicc-shared-web/.github/workflows/pipeline.yml` checks the GitHub build-provenance attestation (Sigstore) that the release made for `SHA256SUMS`, which then covers each file through its checksum. `slicc update` checks the same attestation itself (see [Attestations](#attestations)).
|
|
214
214
|
|
|
215
215
|
Signing:
|
|
216
|
-
- **macOS:** the binaries are signed with a Developer ID, with the hardened runtime, and notarized. A bare binary can't carry a stapled ticket (only apps, disk images and installer packages can), so Gatekeeper checks the notarization online the first time it runs. Inside Sliccstart.app the binary is stapled with the app.
|
|
216
|
+
- **macOS:** the binaries are signed with a Developer ID, with the hardened runtime, and notarized, by `rcodesign` on the release's Linux runner. A bare binary can't carry a stapled ticket (only apps, disk images and installer packages can), so Gatekeeper checks the notarization online the first time it runs. Inside Sliccstart.app the binary is stapled with the app.
|
|
217
217
|
- **Windows:** Windows binaries are unsigned; SmartScreen may warn on first run. AppLocker, WDAC or Intune policies can block them.
|
|
218
218
|
|
|
219
219
|
## Reproducing a release
|
|
@@ -229,7 +229,7 @@ gh release download v<version> --repo ai-ecoverse/slicc-cli -p SHA256SUMS -O - |
|
|
|
229
229
|
- It uses `-trimpath`, so the checkout's path doesn't matter.
|
|
230
230
|
- It runs the Go release that `go.mod` names (its `toolchain` line, else its `go` line, which then needs a patch version such as `go 1.26.5`; without one `package.sh` refuses to build) through `GOTOOLCHAIN`, downloading it when another Go is installed. It clears `GOFLAGS`, `GOEXPERIMENT`, `GOAMD64`, `GOARM64`, `GOWASM` and `GOFIPS140`, sets `GOENV=off` so no `go env -w` setting applies, and sets `GOWORK=off`, so the environment doesn't change the build. Its log names the Go it used.
|
|
231
231
|
|
|
232
|
-
The darwin binaries differ only by their signature: the release signs the same unsigned bytes. The integration test `TestReleaseBuildIsReproducibleFromAnyCheckout` (on
|
|
232
|
+
The darwin binaries differ only by their signature: the release signs the same unsigned bytes. The integration test `TestReleaseBuildIsReproducibleFromAnyCheckout` (everywhere but Windows, so on Linux in CI, where the release builds too) builds a checkout tagged after its commit, and a `git archive` of it with `GOAMD64`, `GOARM64`, `GOFIPS140`, `GOFLAGS` and a `go env -w` file set, and requires identical `SHA256SUMS`.
|
|
233
233
|
|
|
234
234
|
Releases whose `package.sh` lacks `-buildvcs=false` were built with Go's VCS stamping, so their bytes depend on the tags present at build time: rebuild one from its commit with that tag and every later one deleted locally (`git tag -d`), as the release saw it, with the Go that `go.mod` names at that tag (`GOTOOLCHAIN=go<version>`) and a clean Go environment (`GOENV=off`, and none of the variables above set).
|
|
235
235
|
|
|
@@ -243,7 +243,7 @@ fnox (secrets on a real OS) is upstream jdx/fnox: install it from https://fnox.j
|
|
|
243
243
|
|
|
244
244
|
**`slicc install jerk`** installs jerk into the data folder's `bin` (any other name, or none, exits 2 with `slicc install: name jerk` and the usage):
|
|
245
245
|
- `jerk` from the latest release of `ai-ecoverse/slicc-jerk` (0.6.0 or later, the first with the `--via-link` calls the link needs; an older latest release is refused with `slicc install: ai-ecoverse/slicc-jerk <version> is older than 0.6.0, the first release slicc works with`);
|
|
246
|
-
- **the release contract** (the same as slicc-cli's own): a plain binary `<name>-<os>-<arch>` (`.exe` on Windows; `darwin`, `linux`, `windows` × `amd64`, `arm64`), and `SHA256SUMS` with a line for it, with a build provenance attestation
|
|
246
|
+
- **the release contract** (the same as slicc-cli's own, but for who attests): a plain binary `<name>-<os>-<arch>` (`.exe` on Windows; `darwin`, `linux`, `windows` × `amd64`, `arm64`), and `SHA256SUMS` with a line for it, with a build provenance attestation over the binary or over `SHA256SUMS` by one of the identities that step 5 of [Attestations](#attestations) lists for it;
|
|
247
247
|
- slicc checks the download against `SHA256SUMS` and verifies its attestation (see [Attestations](#attestations)), then installs it only once its `--version` names the release's version, through a rename next to the old one (as `slicc update` does);
|
|
248
248
|
- it says `installed <name> <version> at <path> (SHA256SUMS and the build provenance attestation by <identity>)`, or `<name> <version> is already installed at <path>`;
|
|
249
249
|
- `--checksum-only` skips the attestation, with a warning, and says `SHA256SUMS only; the attestation wasn't checked`;
|
|
@@ -262,24 +262,24 @@ Only a user runs `slicc install`. Nothing on a link starts an install.
|
|
|
262
262
|
2. its single DSSE signature verifies with the certificate's key (ECDSA P-256 or P-384) over the DSSE pre-authentication encoding;
|
|
263
263
|
3. the certificate chains, as a code-signing certificate, to a Fulcio root in the trusted root that is valid at the entry's integrated time, and the certificate itself was valid then;
|
|
264
264
|
4. one of the certificate's embedded SCTs (`1.3.6.1.4.1.11129.2.4.2`) verifies with a certificate transparency log key in the trusted root, valid at the SCT's time, over the precertificate (the certificate body without its SCT list) and its issuer's key hash (RFC 6962);
|
|
265
|
-
5. the certificate's identity: issuer (Fulcio extension `1.3.6.1.4.1.57264.1.8`) `https://token.actions.githubusercontent.com`, and exactly one subject alternative name, the
|
|
265
|
+
5. the certificate's identity: issuer (Fulcio extension `1.3.6.1.4.1.57264.1.8`) `https://token.actions.githubusercontent.com`, and exactly one subject alternative name. For `update` (`ai-ecoverse/slicc-cli`) that is slicc-shared-web's release pipeline, `https://github.com/ai-ecoverse/slicc-shared-web/.github/workflows/pipeline.yml@refs/tags/v2.<minor>.<patch>`, and the certificate's build configuration (Fulcio extension `1.3.6.1.4.1.57264.1.18`) must be the caller, `https://github.com/ai-ecoverse/slicc-cli/.github/workflows/ci.yml@refs/heads/main`, so the pipeline run by another repo or from a branch doesn't count. For `install` (`ai-ecoverse/slicc-jerk`) it is one of `https://github.com/ai-ecoverse/slicc-jerk/.github/workflows/release.yml@refs/heads/main` (its releases before the shared pipeline), `https://github.com/ai-ecoverse/slicc-jerk/.github/workflows/ci.yml@refs/heads/main`, or the shared pipeline as for `update`, called from slicc-jerk's `ci.yml` at `main`; any other workflow, ref or repo is refused;
|
|
266
266
|
6. the Rekor entry is a `dsse` 0.0.1 entry whose payload hash, signature and verifier are the envelope's and the certificate's;
|
|
267
267
|
7. its signed entry timestamp verifies with the key of a Rekor log in the trusted root, valid at the integrated time;
|
|
268
268
|
8. its inclusion proof leads from the entry to the proof's root hash (RFC 6962), and the checkpoint carries that tree size and root hash and is signed by the same log.
|
|
269
269
|
|
|
270
270
|
Errors name the step that failed (`attestation identity: …`). A bundle from a Rekor v2 log, or any other shape, fails closed.
|
|
271
271
|
|
|
272
|
+
**Releases before the move to the shared pipeline** were attested by `ai-ecoverse/slicc-cli/.github/workflows/release.yml@refs/heads/main`. A binary from one of them refuses the later releases: update it once by hand, with `slicc update --checksum-only`, `install.sh`, or npm.
|
|
273
|
+
|
|
272
274
|
**Unsupported: Rekor v2.** Bundles from Rekor v2 logs (Ed25519 log keys, `dsse` 0.0.2 entries, RFC 3161 timestamps instead of signed entry timestamps) aren't supported. They fail closed, so `update` and `install` refuse such a release until the verifier learns them; `--checksum-only` is the way around it meanwhile.
|
|
273
275
|
|
|
274
276
|
**The trusted root.** `internal/attest/trusted_root.json` is Sigstore's public-good trusted root (Fulcio CAs, Rekor and CT log keys) (the `trusted_root.json` target of `https://tuf-repo-cdn.sigstore.dev`), embedded in the binary. `SLICC_SIGSTORE_TRUSTED_ROOT` replaces it, for tests.
|
|
275
277
|
|
|
276
|
-
**Rotating the trusted root.** The
|
|
278
|
+
**Rotating the trusted root.** The integration test `TestTheEmbeddedSigstoreTrustedRootIsCurrent` runs `node scripts/sigstore-root.mjs`, which follows the TUF repository's `timestamp.json`, snapshot and targets to the current `trusted_root.json` and compares its SHA-256 with the embedded file; when they differ, the test fails, so every pull request stays red until the root is re-embedded (it skips when the TUF repository doesn't answer, exit code 3). To rotate:
|
|
277
279
|
1. run `node scripts/sigstore-root.mjs --write`, which downloads the new file and checks it against the targets hash;
|
|
278
280
|
2. review the diff (new Fulcio certificates or Rekor keys, `validFor` ranges) against Sigstore's announcement; the script doesn't check TUF signatures, so this review is the trust decision;
|
|
279
281
|
3. open a `fix:` PR, so a release ships it. Binaries released before it keep the old root, and fail closed on attestations that need the new one until they update with `--checksum-only` or by hand.
|
|
280
282
|
|
|
281
|
-
**Parity.** The workflow's `parity` job runs `TestAttestParityWithGH`: for the latest release, `gh attestation verify --repo ai-ecoverse/slicc-cli --signer-workflow …/release.yml` and slicc's verifier must both accept the binary, and both refuse it after one byte is appended.
|
|
282
|
-
|
|
283
283
|
## Updates
|
|
284
284
|
|
|
285
285
|
`slicc update [--check] [--checksum-only]` replaces the running binary (symlinks resolved), wherever it is, such as `~/.local/bin/slicc` from `install.sh`, with the latest GitHub release of `ai-ecoverse/slicc-cli`. It downloads the asset for this OS and CPU, checks it against the release's `SHA256SUMS`, and verifies its build provenance attestation (see [Attestations](#attestations)); `--checksum-only` skips the attestation, with a warning. The new binary has to answer `--version` with the release's version before anything is replaced. The swap is a rename next to the old binary; on Windows the running binary is first moved aside to `<name>.old`, which the next run deletes. `slicc update --check` only reports.
|
|
@@ -2109,9 +2109,9 @@ CI installs a pinned release: `go install github.com/ai-ecoverse/slicc-cli/cmd/s
|
|
|
2109
2109
|
|
|
2110
2110
|
## Development
|
|
2111
2111
|
|
|
2112
|
-
Go 1.26 and Node ≥ 24 (for the lint tools). `npm run build` writes `bin/slicc`. `npm run lint` runs the slicc lint tools, `gofmt`, `go mod tidy -diff`, `go vet` and golangci-lint. `npm test` runs the integration tests in `test/integration/`, which build the binary and drive it; run `npm ci` first, since the [Inside seven](#inside-seven) tests need the pinned `@ai-ecoverse/slicc-kernel`. Unit tests stay next to the code and out of git (`npm run test:unit`). `go build` and `npm run build` link no version, so these binaries report `dev`. `npm run dist` cross-builds all six targets into `artifacts/release/` with `SHA256SUMS`, unsigned. `npm run npm:stage` then stages the npm packages into `dist/npm/`, and `npm run npm:check` packs them with `npm publish --dry-run`.
|
|
2112
|
+
Go 1.26 and Node ≥ 24 (for the lint tools). `npm run build` writes `bin/slicc`. `npm run lint` runs the slicc lint tools, `gofmt`, `go mod tidy -diff`, `go vet` (also with `GOOS=darwin` and `GOOS=windows`, since CI tests on Linux only) and golangci-lint; `npm run lint:sh` runs shellcheck on `install.sh` and the scripts. `npm test` runs the integration tests in `test/integration/`, which build the binary and drive it; run `npm ci` first, since the [Inside seven](#inside-seven) tests need the pinned `@ai-ecoverse/slicc-kernel`. Unit tests stay next to the code and out of git (`npm run test:unit`). `go build` and `npm run build` link no version, so these binaries report `dev`. `npm run dist` cross-builds all six targets into `artifacts/release/` with `SHA256SUMS`, unsigned. `npm run npm:stage` then stages the npm packages into `dist/npm/`, and `npm run npm:check` packs them with `npm publish --dry-run`.
|
|
2113
2113
|
|
|
2114
|
-
**
|
|
2114
|
+
**CI.** `.github/workflows/ci.yml` is the only workflow: one caller of [slicc-shared-web's pipeline](https://github.com/ai-ecoverse/slicc-shared-web#pipeline), pinned at the release of the `@ai-ecoverse/slicc-shared-web` devDependency, with `secrets: inherit`. On pull requests and in the merge queue it runs `lint` (`npm run lint` with golangci-lint, pinned in `ci.yml` and installed into `$RUNNER_TEMP`, then `npm run lint:sh`), then `npm test` on four Linux shards of the pool, then on a pull request the Claude and Codex reviews with this repo's `review-prompt`. The checks to require are `ci / integration` and `ci / review`. A push to `main` runs lint and the release (see [Releases](#releases)); it runs no tests, since what reaches `main` passed the merge queue. macOS and Windows aren't tested in CI: lint vets both, and platform code needs a local run there. **Test shards.** `npm test` runs `scripts/test-shard.mjs ci/4 -race -count=1 -timeout 15m -v ./test/integration/...`. On the pipeline's shard `SLICC_TEST_SHARD` (0 to 3) it runs that shard's share of the top-level tests; without it (a local run) it runs them all. The split is greedy by measured time: `test/integration/shard-times.json` holds each top-level test's seconds on `linux`, each test goes to the shard with the least time so far, a test without a time counts as the median, and the last shard runs everything the others don't, so a new test still runs. `go test` gets the pipeline's own `NODE_OPTIONS` back (without its shard preload and JUnit reporter) and none of its `SLICC_TEST_*` variables. The script writes each top-level test's result to the shard's JUnit report (`SLICC_TEST_JUNIT`), which the pipeline's `integration` check counts: it fails when no test ran or one failed. It also fails a shard that selects no tests or whose `go test -v` runs none, and, when a shard hits its `-timeout`, names the test that was running and how long the finished ones took. `node scripts/shard-times.mjs --run <CI run id>` refreshes the times from a finished run's `test (<n>)` logs (`linux=<log file>` reads local `go test -v` output instead); commit the result when tests get much slower or faster. `TestEachCIShardFitsItsTimeout` fails when a shard adds up to more than three quarters of its `-timeout`, or when `timeout-minutes` leaves less than 5 minutes past it: then raise `shards` in `ci.yml` and the count in `npm test` together. The [guard vectors](https://github.com/ai-ecoverse/slicc-browsers#guard-vectors) run on every shard; `SLICC_GUARD_VECTORS=0` skips them locally. On macOS they leave out the C9 vectors (extension worlds; the `C9.` prefix that `guardSkippedOn` in `guardrunner_test.go` returns for `darwin`): there their unguarded control hung in Chrome itself ([#344](https://github.com/ai-ecoverse/slicc-cli/issues/344)). `TestCDPGuardVectorsSkipC9OnlyOnMacOS` keeps the skip to macOS, and `TestCDPHidesExtensionWorlds` covers the extension-world guard everywhere. **Node:** CI runs Node 26: on Node 24.21.0, V8 crashed the WASI kernel harness (`TestWasi*`) about once in a hundred runs on Windows and occasionally on Linux.
|
|
2115
2115
|
|
|
2116
2116
|
**Test names: `--hosts <file>`** (test-only, left out of `--help`). `slicc attach`, `slicc open`, `slicc pair` and `slicc <join-url> follow` take a hosts file, so tests get deterministic names without public DNS. Each line is `<ip> <name> [<name>…]`, and `#` starts a comment. Names match case-insensitively, with or without a trailing dot, and a name on several lines gets every address, in file order. Wherever the node resolves a name (`resolve`, `tcp` by name, `http`, and the policy's [browser endpoints](#network-policy)), a name in the file gets the file's addresses of the requested family, possibly none, and never the system resolver's. Other names go to the system resolver. The policy applies afterwards as usual: `resolve` drops refused addresses, and a dial to a refused address is `EACCES`. `tcp` and `http` try the addresses in file order. A file that can't be read or parsed exits 2. A name mapped to a loopback address only helps the node's own dials, `http` and `tcp` by name: a seven kernel that gets a loopback address from `resolve` dials its own loopback, because loopback never goes out through an exit. For end-to-end exit tests, map test names to a non-loopback address of the machine.
|
|
2117
2117
|
|
|
@@ -2142,71 +2142,26 @@ Chrome 156 no longer has `Network.setRequestInterception`, so the deprecated `Ne
|
|
|
2142
2142
|
|
|
2143
2143
|
**Real browsers in tests.** The Chrome the harness starts itself is `SLICC_TEST_CHROME` (test-only: the path of a Chrome executable), else the machine's Chrome or Chromium, with the real environment, a temporary profile and `--use-mock-keychain --password-store=basic`. The tests that have `slicc` itself launch a real Chrome run it under a temporary home, where its profiles are throwaway ones. Off CI they never launch the machine's own Chrome: they need `SLICC_TEST_CHROME` set to a Chrome for Testing inside its `.app`, which they link into the temporary home's `Applications` folder on macOS and launch by its id (`chrome-for-testing`), and they skip with a notice without it, or on other systems. On CI they launch the runner's Google Chrome. An older Chrome for Testing can fail the tests that read Chrome's own prefs.
|
|
2144
2144
|
|
|
2145
|
-
On GitHub's Windows runners the system drive `C:` is slow: with Chrome profiles there, Chrome sometimes waited seconds before a new tab's first request (up to past the 15 s page-load limit) or before exiting (`did not exit`). With them on `D:`, the runner's temp drive, those stalls weren't seen and the suite ran about a quarter faster. So
|
|
2145
|
+
On GitHub's Windows runners the system drive `C:` is slow: with Chrome profiles there, Chrome sometimes waited seconds before a new tab's first request (up to past the 15 s page-load limit) or before exiting (`did not exit`). With them on `D:`, the runner's temp drive, those stalls weren't seen and the suite ran about a quarter faster. So on a Windows runner, point `TEMP` and `TMP` at its temp drive: the tests' temporary homes and Chrome profiles live there. When a test page doesn't load, the failure says where it stopped: the tab's URL and `readyState`, the resources it fetched, and every request the page server saw.
|
|
2146
2146
|
|
|
2147
2147
|
The real-Chrome tests in `test/integration/` launch headless, so they run the executable directly. A windowed launch on macOS goes through `open -n -W -a`, which CI doesn't cover: on GitHub's macOS runners, Chrome started that way never writes `DevToolsActivePort`.
|
|
2148
2148
|
|
|
2149
2149
|
## Releases
|
|
2150
2150
|
|
|
2151
|
-
PRs merge through the merge queue
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
3. (still in `build`) `scripts/npm-stage.mjs` stages `@ai-ecoverse/slicc` and the six platform packages into `dist/npm/`. It also stages the same launcher as `sliccy` (with two bins, `sliccy` and `slicc`, and a short preview README) into `dist/npm-next/`, as version `7.0.0-next.<version>`, with exact `optionalDependencies` on this release's platform packages. `npx sliccy@next` runs the bin named after the package, `sliccy`, and both bins run the same launcher. `--bin <name>` (repeatable) overrides the bins of any staged launcher. `--wasi` also stages `@ai-ecoverse/wasi-slicc` into `dist/npm/wasi-slicc/` from `slicc-wasip1-wasm.wasm` and `npm/wasi-slicc/host/slicc-host.mjs`, with README.md's [Inside seven](#inside-seven) section as its README; `--wasi-only` stages only that package.
|
|
2159
|
-
4. The `release` job unpacks the build, checking its `dist/VERSION` against the planned version, and `actions/attest-build-provenance` attests every binary, the `.wasm` included, through `SHA256SUMS`.
|
|
2160
|
-
5. semantic-release checks the version again (`dist/VERSION`, and `scripts/go-major.mjs`, see below), tags, creates the GitHub release with every binary and `SHA256SUMS`, then `scripts/npm-publish.mjs` publishes the platform packages and the launcher through npm trusted publishing (OIDC, with provenance), and then `sliccy` with `--tag next`. Versions already on npm are skipped. Before publishing `sliccy`, the script checks that every exact-pinned `optionalDependencies` version is on the registry, waits up to `SLICC_REGISTRY_WAIT_SECONDS` (default 900) for freshly published ones to appear, and fails otherwise (exit code 3), so a `sliccy` version never points at missing platform packages. Then the `release` job asks `git ls-remote` whether `v<version>` is on `origin` at the commit it built, and only then outputs the version. When semantic-release published nothing (for example because `main` moved on during the full matrix, so the checkout is behind), there is no output: `install-smoke` and `sliccy-next` skip, and the run stays green with no `release-red` issue. An `origin` it can't read fails the job.
|
|
2161
|
-
6. `scripts/go-warm.sh <version>`, once the tag is on `origin`, asks `proxy.golang.org` for the module at `v<version>` (`go list -m` with a scratch module cache) and asks `pkg.go.dev` to fetch it. The proxy fetch is retried briefly; the `pkg.go.dev` fetch is one attempt of at most 10 s, since the proxy fetch already gets the version indexed. Both only warn, and the step can't fail the release.
|
|
2162
|
-
|
|
2163
|
-
**Certification in the pull request** (`.github/workflows/cert-review-pr.yml`, `tools/cert-review/`). Every same-repo pull request gets the commit status `cert-review` on its head, which the merge queue requires beside `ci`. Fork pull requests get none: only Lars merges one. Every tool runs from the pull request's base commit, main's copy, never from the code under test, which is only built and tested; the review uses `refs/pull/N/merge` and records its first parent and the head.
|
|
2164
|
-
- **plan** (light runner) runs on opened, synchronize, reopened, ready_for_review, converted_to_draft, and `cert-review-approved` being added or removed, and plans the whole run again, since such an event cancels a run in progress; other labels neither start nor cancel anything. **Draft status replaces the old `merge-ok` label:** a draft is neither built nor reviewed and its `cert-review` is red `draft: not reviewed, mark it ready for review`, so an older result on the same head can't satisfy the check; **mark ready = reviewed, and merges on green**. With the hold rule (held = draft) the order for a PR that needs the coordinator's security or link-spec read is: the coordinator reviews the draft, it is marked ready, the cert runs (with its Claude review), then the queue; a cert finding means a new head, back to draft and a re-read. Renovate's pull requests aren't drafts, so they're reviewed by themselves. A `pending` status left on the head by a run that ended without a result becomes `error` (re-run the failed jobs), so the check never waits forever. The shared self-guard (`cert-self-guard`, pinned) holds a change to the reviewer's own paths (`REVIEWER_GLOBS` in `tools/cert-review/lib.mjs`: all of `.github/**`, every workflow and action, so no pull request's own workflow can post `cert-review`, and `tools/cert-review/**`) until a coordinator puts `cert-review-approved` on that head. Such pull requests always go to the coordinator before queueing.
|
|
2165
|
-
- **build** (hosted `ubuntu-latest`, no secrets) builds the merge commit and its first parent the release's way, each in a full clone with its tags: `SLICC_SIGN=0 scripts/package.sh <v>`, `npm-stage.mjs` for every package, and `npm pack`, with one version `X.Y.(Z+1)-pr.N.<run>` on both sides. `outputs.mjs` hashes every release file and tarball.
|
|
2166
|
-
- **classify** decides by output where the build can see it: a pull request is behaviour when a binary, the wasm, `SHA256SUMS` or an npm tarball differs from main's build. Paths whose effect the unsigned build never shows are behaviour whatever it outputs: `scripts/**` (signing and notarization, publishing, the release plan, `go-*`, `sliccy-next.mjs`), `install.sh`, `npm/**`, `package.json` and `package-lock.json` (they choose the semantic-release code the release runs), `.releaserc*`, and the reviewer's paths. Otherwise the status is `not behaviour: identical build outputs` (success), so a docs or test change that ships nothing new needs nothing more. Renovate's pull requests aren't drafts, so a dev-pin bump is reviewed by itself and merges on green. A behaviour change on a draft is `draft: not reviewed, mark it ready for review` (failure); once it's ready, the review starts.
|
|
2167
|
-
- **rebuild** (heavy runner) runs [the recipe](#reproducing-a-release) on a `git archive` of the merge commit, in another path on another machine; every release file must be byte-identical to build's.
|
|
2168
|
-
- **delta** names the Go tests the pull request adds or changes in `test/integration/*_test.go` (the `func Test…` a hunk falls in). A changed helper counts as changing every test in its file; a helper in a file with no tests is a test gap (`helper <name>`), never a guess.
|
|
2169
|
-
- **suite** (heavy runner): the candidate leg runs the whole integration suite on the merge commit on Linux (`go test -json`); the base leg is the NEGATIVE: main's tree with the pull request's whole `test/` diff applied, running only its tests, against main's own binary. A fix whose test fails there and passes on the candidate is `negative`; passing on both is `no-negative`; not compiling or skipping on main is `prev-not-run`. Gaps are known issues, never a FAIL by themselves.
|
|
2170
|
-
- **bios** runs seven's own canary on the candidate wasm when classify sees `slicc-wasip1-wasm.wasm` or the `@ai-ecoverse/wasi-slicc` tarball differ from main's build: it calls slicc-bios's `canary.yml` as a reusable workflow, pinned to the commit in `tools/cert-review/bios.json`, with build's `cert-build-wasi-slicc-<v>` artifact as the candidate (strict binding: its run, artifact id, artifact digest and tarball sha256, never its name alone) and the shards that install the in-kernel slicc (`follow-chat`, whose `follow-slicc.test.mjs` follows another seven). It passes no secret. The canary's shards run on hosted runners. It runs only while the repository variable `CERT_BIOS_CANARY` is `on`, and that variable stays unset until [slicc-bios#599](https://github.com/ai-ecoverse/slicc-bios/issues/599) is fixed: the canary binds an artifact candidate's tarball, but the in-kernel pnpm still resolves its version on the npm registry, so every new wasm would read as a regression. While it's off, record gets `--bios-off ai-ecoverse/slicc-bios#599`, and the line says `bios: off (ai-ecoverse/slicc-bios#599), wasm changed` (an unchanged wasm still says `bios: not needed, wasm unchanged`).
|
|
2171
|
-
- **review** (light runner) runs `claude-code-action/base-action` on that evidence with `AWS_BEARER_TOKEN_BEDROCK`, the workflow's only secret, in that step only; without the key the step skips and the line says `INCOMPLETE: no reviewer key`. Its read-only `gh` calls use the runner's own `gh`; nothing downloads one, and a runner without it makes the review INCOMPLETE. The reviewer writes only `verdict.json` and `comment.md`, in a folder of its own: a `fail` can add a defect, but nothing it writes can clear one decided in code.
|
|
2172
|
-
- **record** (code only) recomputes the findings from the code-made evidence (delta, suite and rebuild artifacts), re-hashes the build artifact against build's `SHA256SUMS` hash, checks the rebuild, reads CI's results on the head (the macOS, Windows and Linux test legs and `ci`, waiting up to an hour; a pull request's CI run whose `runner` decided Linux only, read from its `test matrix` annotation `os=linux` in the same check suite as a green `ci`, and whose workflow run is a `pull_request` one, needs no macOS or Windows leg, and the comment says `not run on this PR (Linux-only; the merge queue runs every OS)`; on any other run every OS is still required, and a leg that ran must pass), bios's canary report (`bios-canary`, by the id and digest the call returned, its pin, this run, this build's tarball and every pinned shard) and the verdict. A byte or reproducibility mismatch, a failing canary test, or the reviewer's fail, is `cert-ci: FAIL` (failure); missing evidence (a known issue that can't be read or doesn't exist included, and a canary that left no result, missed a shard, or was flaky) is `cert-ci: INCOMPLETE` (error: re-run the failed jobs); otherwise `certified ai-ecoverse/slicc-cli PR #N at <head>, build <v> SHA256SUMS sha256=<hex> (wasm sha256=<hex>; bios: follow-chat pass at slicc-bios@<sha>, bios: not needed, wasm unchanged, or bios: off (<issue>), wasm changed; reproducible: …; ci: …; known: …; test gaps: …)`. **report** posts it as the status and a sticky comment.
|
|
2173
|
-
- **No silent pass.** Every step that runs a cert tool requires that tool's verdict: plan's `build=`, a posted status from classify and the lookup, a `certified …` line and a `success` record before report posts success, and in `cert-verify.yml` the reproduction's and the darwin check's verdict lines, verify's `certified slicc-cli@<version> binaries …` line and the notes job's `notes: …` line. A tool that exits 0 and prints nothing fails its step, and the status is `error`.
|
|
2174
|
-
- **Evidence by artifact id and digest.** Every job that uploads evidence hands on the artifact's id and digest as job outputs, one pair per matrix side. Every consumer downloads by `artifact-ids` with `digest-mismatch: error`, never by name or pattern, and no upload overwrites another. A download that failed counts as no evidence. The review and record take from each producer's artifact only its own files (`gather.mjs`: the candidate suite gives `candidate.*`, main's gives `prev.*`), so one job can't plant another's evidence. classify, record and cert-verify's verify list the run's artifacts: an artifact under a declared id with another name or digest, or a `cert-*` artifact from this attempt that no producer declared, is `cert-ci: INCOMPLETE` (classify posts `error`). Artifacts left by an earlier attempt of the run are ignored.
|
|
2175
|
-
- **merge group**: CI's deterministic suites, plus a code-only lookup that each pull request in the group has a green status on the head being merged; otherwise red, naming it. No build, review or model.
|
|
2176
|
-
|
|
2177
|
-
**Verify on npm** (`.github/workflows/cert-verify.yml`, `tools/cert-review/`). `release.yml` stays plain semantic-release. When a `Release` run on `main` succeeds, `cert-verify` takes the `v*` tag on the commit it built (or the version given to a manual run) and checks it, code only, with no secret and no `id-token`, in a concurrency group of its own, so the next release never waits for it:
|
|
2178
|
-
- `release / reproduce from the tag` (`vars.CERT_RUNNER`, no token): [the recipe](#reproducing-a-release) on a `git archive` of `v<version>` on Linux. Every `linux`, `windows` and `.wasm` asset and `install.sh` must match the release's `SHA256SUMS` line, built on macOS.
|
|
2179
|
-
- `release / darwin signature and notarization` (hosted `macos-latest`) checks both darwin binaries:
|
|
2180
|
-
- codesign first: `codesign -dv` (identifier `ai.sliccy.slicc`, a `Developer ID Application` authority, team `vars.CERT_APPLE_TEAM`, default `S8LB56P782`, the hardened runtime) and `codesign --verify --strict`. A failure there is FAIL whatever Gatekeeper says, and a codesign that didn't finish is INCOMPLETE.
|
|
2181
|
-
- On a codesign pass, `spctl -a -vv -t install` asks Gatekeeper online. Its first answer for a new binary is sometimes `Unnotarized`, so it asks up to three times with a growing pause and keeps every answer in the evidence. It passes only on `source=Notarized Developer ID`.
|
|
2182
|
-
- `release / verify on npm` (`vars.CERT_LIGHT_RUNNER`, read-only) covers each package a publish variable lets out: `@ai-ecoverse/slicc`, its six platform packages, `@ai-ecoverse/wasi-slicc` and `sliccy@7.0.0-next.<version>`. For each, it:
|
|
2183
|
-
- waits up to an hour for npm;
|
|
2184
|
-
- checks `dist.integrity` against the registry tarball;
|
|
2185
|
-
- checks the SLSA provenance: subject = the tarball's sha512, `release.yml` at `refs/heads/main`, a GitHub-hosted builder, `gitCommit` = `gitHead` = the tag's commit, which is on `main`;
|
|
2186
|
-
- checks that each platform package's binary and `wasi-slicc`'s `bin/slicc.wasm` are the release's assets, and that `@ai-ecoverse/slicc` and `sliccy` pin this version's platform packages;
|
|
2187
|
-
- then runs `npm audit signatures`.
|
|
2188
|
-
|
|
2189
|
-
On GitHub, the release must have exactly the eight assets and `SHA256SUMS`, each must re-hash to its line, and `gh attestation verify` must accept each one for `release.yml` at `refs/heads/main`. `get.sliccy.ai/slicc` must redirect to `releases/latest/download/install.sh`, whose bytes are this release's while it is the latest. The job also reads the rebuild and darwin evidence and the release notes. A mismatch anywhere, or notes that already certify another sha, is `supply-chain alert: …`. Missing evidence (no rebuild or darwin result, a check that didn't finish) is `cert-ci: INCOMPLETE …`. Its record (`verify.json`) is written last, with the final state.
|
|
2190
|
-
- `release / write the certified lines` (hosted `ubuntu-latest`, the only job with `contents: write`, after a verify that passed) does only the notes edit, from the lines verify handed over. Between `<!-- cert-verify -->` markers it writes one line per package and one for the binaries:
|
|
2191
|
-
- `certified <package>@<version> sha256=<the registry tarball's sha256> (covers …; ci: …; pr-certified: …; known: …)`;
|
|
2192
|
-
- `certified slicc-cli@<version> binaries SHA256SUMS sha256=<the SHA256SUMS file's sha256> (…)`.
|
|
2193
|
-
|
|
2194
|
-
`pr-certified` lists each pull request since the previous tag with its `cert-review` status on its head. When one of them has none (a pull request from before the check was required), the lines start with `verified` instead of `certified`, since they then cover only the supply chain; readers take only `certified` as a cert. A `verified` line with the same sha counts as written. Notes that already carry the same lines stay unchanged, and lines in the block for packages outside this run's set are kept. Another sha writes nothing and fails with a `supply-chain alert`.
|
|
2151
|
+
PRs merge through the merge queue, which requires `ci / integration` and `ci / review`. semantic-release cuts a release from every push to `main` in the pipeline's `release` job (GitHub-hosted `ubuntu-latest`, since npm's trusted publishing takes OIDC tokens only from GitHub-hosted runners), in its own concurrency group that never cancels; `main` runs lint before it and no tests, since the merge queue tested the commit. The job gets the Apple secrets named in `ci.yml`'s `release-secrets` and nothing else. Nothing is released by hand: a failed release is fixed by the next push to `main`, which releases every commit since the last tag. `.releaserc.json` runs:
|
|
2152
|
+
1. `scripts/go-major.mjs <version>` (verify, see below).
|
|
2153
|
+
2. `scripts/release-build.sh <version>` (prepare): `scripts/package.sh <version>` builds `darwin`, `linux` and `windows` × `amd64`, `arm64` with `CGO_ENABLED=0`, `-trimpath`, `-buildvcs=false` and `-X main.version=<version>`, and `slicc-wasip1-wasm.wasm` (`GOOS=wasip1 GOARCH=wasm`) the same way, with the Go toolchain `go.mod` names (see [Reproducing a release](#reproducing-a-release)). It signs the darwin binaries with [rcodesign](https://github.com/indygreg/apple-platform-rs) (pinned by version and SHA-256, downloaded unless `RCODESIGN` names one), identifier `ai.sliccy.slicc`, hardened runtime, Developer ID with a timestamp, notarizes both in one zip with Apple's Notary API, and writes `SHA256SUMS`. The windows and linux binaries are not signed. In the release (`SLICC_SIGN=required`) a missing secret fails the build; elsewhere (`SLICC_SIGN` unset) it warns and leaves the darwin binaries unsigned, and `SLICC_SIGN=0` skips signing. The script then runs the runner's own binary with `--version`, which must answer `slicc <version>`, and `scripts/npm-stage.mjs` stages `@ai-ecoverse/slicc` and the six platform packages into `dist/npm/`, with `--wasi` also `@ai-ecoverse/wasi-slicc` (from `slicc-wasip1-wasm.wasm` and `npm/wasi-slicc/host/slicc-host.mjs`, with README.md's [Inside seven](#inside-seven) section as its README), and the same launcher as `sliccy` (two bins, `sliccy` and `slicc`, and a short preview README) into `dist/npm-next/` as `7.0.0-next.<version>`, with exact `optionalDependencies` on this release's platform packages. `npx sliccy@next` runs the bin named after the package, and both bins run the same launcher. `--bin <name>` (repeatable) overrides the bins of any staged launcher.
|
|
2154
|
+
3. `@semantic-release/github` tags and creates the GitHub release with every binary, `install.sh` and `SHA256SUMS`.
|
|
2155
|
+
4. `scripts/npm-publish.mjs` (publish) publishes the platform packages, then the launcher and `wasi-slicc`, through npm trusted publishing from `ci.yml` (OIDC, with provenance), then `sliccy` with `--tag next`. Versions already on npm are skipped. Before publishing `sliccy`, it checks that every exact-pinned `optionalDependencies` version is on the registry, waits up to `SLICC_REGISTRY_WAIT_SECONDS` (default 900) for freshly published ones, and fails otherwise (exit code 3), so a `sliccy` version never points at missing platform packages.
|
|
2156
|
+
|
|
2157
|
+
After a release, the pipeline attests the build provenance of `artifacts/release/SHA256SUMS` (`attest` in `ci.yml`), which `slicc update` checks (see [Attestations](#attestations)), and `after-release` runs `scripts/go-warm.sh <version>`: it asks `proxy.golang.org` for the module at `v<version>` (`go list -m` with a scratch module cache) and asks `pkg.go.dev` to fetch it. Both only warn.
|
|
2195
2158
|
|
|
2196
2159
|
**Go module versions.** In Go a pushed tag is the release: `proxy.golang.org` caches it, `sum.golang.org` records its hash for good, and `pkg.go.dev` indexes it.
|
|
2197
2160
|
- **Never move or delete a pushed tag.** The checksum database would then reject that version for every user. A bad version gets a `retract` directive in `go.mod`, and a new release.
|
|
2198
|
-
- **Major versions.** A module at v2 or above needs `/vN` at the end of its module path, or `go install …@latest` never sees it. `scripts/go-major.mjs <version>` fails the release when the version's major doesn't fit the module path in `go.mod` (no suffix allows v0 and v1, `/vN` allows only vN).
|
|
2199
|
-
|
|
2200
|
-
**Gate verdicts.** A gate's silence never reads as a pass. Each script that gates a merge or a release ends a pass with a `<name>: PASS …` line: `test-shard: PASS linux 1/2 ran 143 tests`, `go-major: PASS 1.4.0 (major 1) fits module path …`, `release-plan: PASS release 1.4.0` (or `no release due`), `npm-publish: PASS latest: published 7, 1 already published, 0 held by their gates, of 8 packages`, `sliccy-next: PASS sliccy@7.0.0-next.1.4.0`, `install-check: PASS all installer checks passed`, and `release-issue: PASS red; opened #N` (or `commented on #N`, `green; closed #N`, `cancelled (…) without a failure; nothing to report`). Every caller in `ci.yml`, `release.yml` and `.releaserc.json` runs the gate through `sh scripts/verdict.sh <name> <command…>`, which fails with the gate's exit code when it fails, and fails when it exits 0 without its `<name>: PASS` line, so an early exit, a skipped main block or empty output fails the step. `test-shard.mjs` also fails a shard that selects no tests, or whose `go test -v` runs none, and `npm-publish.mjs` fails on a directory with no packages. The `fresh` job sets `verdict` to `current`, `stale`, or `unknown` when `git ls-remote` can't read `main` (`fresh: PASS unknown (semantic-release decides)`, which refuses a release behind the remote anyway); a release after CI needs `current` or `unknown`, so a missing verdict releases nothing. The scripts find their main block with `realpath` on both `process.argv[1]` and the module's own path (`scripts/is-main.mjs`), so they also run through a symlinked checkout or script.
|
|
2201
|
-
|
|
2202
|
-
**Recovering `sliccy@next`.** When a release tagged and published its platform packages but `sliccy` didn't go out (a registry that lagged past the wait, say), `gh workflow run release.yml --ref main -f sliccy_next_only=true` publishes it without a new release. On `main` only, that run skips the release job and runs `scripts/sliccy-next.mjs`. The script takes the latest `vX.Y.Z` tag reachable from `HEAD`, stages `sliccy@7.0.0-next.<version>` with the launcher (`npm/slicc.js`) from that tag and exact `optionalDependencies` on that version's platform packages, and publishes it through `npm-publish.mjs` with `--tag next`. The same guards apply: the `SLICCY_NEXT_PUBLISH` gate, the tag and version checks, the registry check, and a version that is already published is skipped. Only the latest release can be recovered, so `next` never moves backwards.
|
|
2203
|
-
|
|
2204
|
-
Every pull request's CI checks the packaging in its `installer-assets` job: an unsigned build of all six targets, the npm packages and `sliccy` (with `--tag next`) packed with `--dry-run`, and `scripts/sliccy-next.mjs --dry-run` (the recovery path against the latest real release, registry check included). The dry run doesn't wait for the latest release: when its platform packages aren't all served yet, it is still publishing (npm has taken 25 minutes), so it checks the release before it instead, with the usual wait, and fails when that one is missing too; only the real publish waits for the latest. The `installer` jobs then run `install.sh` against those assets with curl on Linux and with wget on Alpine; the macOS curl run is left out of pull requests, the merge queue and pushes to `main`, so each needs only one macOS runner, and runs in the release's full matrix. A pull request that changes `release.yml`, `.releaserc.json`, or a script only the release runs (`scripts/package.sh`, `scripts/npm-*.mjs`, `scripts/release-issue.mjs`, `scripts/release-plan.mjs`, `scripts/sliccy-next.mjs`, `scripts/go-*`, `scripts/is-main.mjs`, `scripts/verdict.sh`) also runs the release workflow as a dry run: the same checks in the `build` job on macOS, and each binary run with `--version` on its own OS and CPU.
|
|
2161
|
+
- **Major versions.** A module at v2 or above needs `/vN` at the end of its module path, or `go install …@latest` never sees it. `scripts/go-major.mjs <version>` fails the release when the version's major doesn't fit the module path in `go.mod` (no suffix allows v0 and v1, `/vN` allows only vN). A `BREAKING CHANGE` commit therefore needs a deliberate module-path change first.
|
|
2205
2162
|
|
|
2206
|
-
|
|
2207
|
-
- macOS signing: `APPLE_CERTIFICATE_BASE64`, `APPLE_DEVELOPER_CERTIFICATE_PASSWORD`;
|
|
2208
|
-
- notarization: `APPLE_API_KEY_ID`, `APPLE_API_KEY_ISSUER_ID`, `APPLE_API_KEY_P8_BASE64`.
|
|
2163
|
+
**Gate verdicts.** A gate's silence never reads as a pass. Each script that gates a release ends a pass with a `<name>: PASS …` line: `go-major: PASS 1.4.0 (major 1) fits module path …`, `release-build: PASS 1.4.0, slicc-linux-amd64 runs, 8 files in SHA256SUMS` and `npm-publish: PASS latest: published 8, 0 already published of 8 packages`. `.releaserc.json` runs each through `sh scripts/verdict.sh <name> <command…>`, which fails with the gate's exit code when it fails, and fails when it exits 0 without its `<name>: PASS` line. `npm-publish.mjs` also fails on a directory with no packages. The scripts find their main block with `realpath` on both `process.argv[1]` and the module's own path (`scripts/is-main.mjs`), so they also run through a symlinked checkout or script.
|
|
2209
2164
|
|
|
2210
|
-
npm needs no token. `npm run trust` (fledgling) configures trusted publishing for the
|
|
2165
|
+
npm needs no token. `npm run trust` (fledgling) configures trusted publishing from `ci.yml` for the nine packages under `fledgling.include` in `package.json`, `@ai-ecoverse/wasi-slicc` and `sliccy` included.
|
|
2211
2166
|
|
|
2212
2167
|
`sliccy` only ever goes to the `next` dist-tag, so `npx sliccy` keeps running SLICC six and `npx sliccy@next` runs this binary. `npm-publish.mjs` refuses, even in a dry run, to publish `sliccy` with any tag but `next` or with a version that doesn't match `^7\.0\.0-next\.`. Nothing here changes `sliccy`'s other dist-tags.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"description": "SLICC's command line for seven: links a machine's network, compute and browsers to seven over WebRTC",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"node": ">=18"
|
|
19
19
|
},
|
|
20
20
|
"optionalDependencies": {
|
|
21
|
-
"@ai-ecoverse/slicc-darwin-arm64": "1.
|
|
22
|
-
"@ai-ecoverse/slicc-darwin-amd64": "1.
|
|
23
|
-
"@ai-ecoverse/slicc-linux-arm64": "1.
|
|
24
|
-
"@ai-ecoverse/slicc-linux-amd64": "1.
|
|
25
|
-
"@ai-ecoverse/slicc-windows-arm64": "1.
|
|
26
|
-
"@ai-ecoverse/slicc-windows-amd64": "1.
|
|
21
|
+
"@ai-ecoverse/slicc-darwin-arm64": "1.48.0",
|
|
22
|
+
"@ai-ecoverse/slicc-darwin-amd64": "1.48.0",
|
|
23
|
+
"@ai-ecoverse/slicc-linux-arm64": "1.48.0",
|
|
24
|
+
"@ai-ecoverse/slicc-linux-amd64": "1.48.0",
|
|
25
|
+
"@ai-ecoverse/slicc-windows-arm64": "1.48.0",
|
|
26
|
+
"@ai-ecoverse/slicc-windows-amd64": "1.48.0",
|
|
27
27
|
"@ai-ecoverse/slicc-jerk": "^1.2.2"
|
|
28
28
|
}
|
|
29
29
|
}
|