The publish-npm job now targets the npm-publish environment, whose
required-reviewer rule pauses the job for maintainer approval in the
Actions UI before anything reaches the registry. Also removes the
release-as 0.1.0 pin from release-please-config.json now that v0.1.0
has shipped — leaving it would stamp every future release 0.1.0.
* feat: publish zero to npm via release-please
Adds release-please to automate versioning and releases from
conventional commits on main:
- release-please-config.json / .release-please-manifest.json: node
release type (package.json is the version source of truth), plain
v-prefixed tags, bootstrap-sha at current HEAD, and release-as 0.1.0
to pin the first release (remove after v0.1.0 ships).
- .github/workflows/release-please.yml: maintains the release PR; on
merge it tags + creates the GitHub Release, then dispatches
release-artifacts.yml at the tag (GITHUB_TOKEN-created tags cannot
fire on-push-tags workflows).
- .github/workflows/release-artifacts.yml: tag-gated steps now match
the ref instead of the push event so the dispatched-at-tag run
publishes assets, and a new publish-npm job publishes @gitlawb/zero
after verifying every postinstall asset URL is publicly downloadable
(also blocks publishing while the repo is private).
* Update .github/workflows/release-please.yml
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* feat: publish to npm via OIDC trusted publishing instead of NPM_TOKEN
npm's trusted publishing exchanges the workflow's OIDC token for
publish auth, so no long-lived NPM_TOKEN secret exists to leak, and
provenance is generated automatically. Drops registry-url from
setup-node (its .npmrc line hard-fails on the unset NODE_AUTH_TOKEN)
and updates npm first (OIDC needs npm >= 11.5.1). One-time caveat:
npm only lets you configure a trusted publisher on an existing
package, so the first @gitlawb/zero publish is a manual bootstrap.
* fix: drop npm@latest from the OIDC publish path
Rely on the npm bundled with the pinned Node 24 toolchain (>= 11.5.1,
the trusted-publishing minimum) instead of pulling an unpinned
npm@latest from the registry inside the publish job, and fail fast
with a clear error if a future toolchain change regresses it.
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* ci(release): build all 5 platforms (add Intel macOS + Linux arm64 runners)
zero-release package builds + smoke-tests natively, so each target needs its own
runner. The matrix had only ubuntu-latest/macos-latest/windows-latest (linux-x64,
macos-arm64, windows-x64) — so install.sh/install.ps1 404 for Intel Macs
(macos-x64) and Linux arm64. Adds macos-13 (Intel) and ubuntu-24.04-arm so the
release covers all platforms the installers resolve.
* ci(release): use macos-15-intel for the Intel macOS leg
macos-13 was retired (June 2026) so the matrix leg would never schedule.
macos-15-intel is the current GitHub-hosted Intel x64 runner (supported through
Aug 2027). Addresses CodeRabbit review on #321.
Make `npm install -g @gitlawb/zero` deliver a working CLI. bin/zero.js already
execs an adjacent binary, but nothing fetched it and the name `zero` is taken
on npm. This wires up delivery:
- package.json: rename to @gitlawb/zero; add a postinstall hook, files, engines,
os/cpu, repository, and a license placeholder (the LICENSE file is still
pending and tracked separately).
- scripts/postinstall.mjs: detect platform/arch (mapping mirrors
internal/release/release.go — darwin->macos, amd64->x64), download
zero-v{version}-{os}-{arch}.{tar.gz|zip} from the matching GitHub Release,
verify its SHA-256, and extract into place. Extraction goes to a temp dir and
copies only known binary basenames, so a crafted archive cannot escape the
package (no zip-slip). Idempotent via a version marker; ZERO_SKIP_DOWNLOAD and
unsupported platforms are non-fatal skips.
Security hardening (from an adversarial review):
- require https for the download origin (the same-origin .sha256 makes TLS the
load-bearing integrity control); ZERO_ALLOW_INSECURE_DOWNLOAD=1 opts out for
local testing, and an https->http redirect is refused.
- the checksum parser is anchored per line and validates the filename field.
- cap the download size; warn when an optional sandbox helper is absent.
release-artifacts.yml: on a tag push, assert the git tag equals
v{package.json version} before packaging — zero-release names assets from
package.json while the release publishes under the tag, so any drift would 404
every install (install.sh, install.ps1, and npm alike).
Tests (internal/npmwrapper): package.json now requires exactly a postinstall
hook (no repo build scripts) plus name/license/repository/files; new
node-driven tests cover the per-platform asset plan, the skip env, and the
unsupported-platform path. Verified end-to-end against a local mirror:
download -> verify -> extract places the binary, a tampered checksum is
rejected, and http is refused without the opt-in.
Going live still needs two maintainer steps: create the `gitlawb` npm org +
NPM_TOKEN, and publish the first v0.1.0 release so there is an asset to fetch.
Resolve product/UX audit findings for the OSS launch: doctor now fails uncredentialed remote providers (no false green), Redact() no longer mangles the common first-run auth error, SSRF-safe loopback exemption unblocks keyless local models, new validated --theme flag, WCAG-AA contrast fixes, NO_COLOR compliance, clearer first-contact errors, and full OSS scaffolding (SECURITY/CoC/CHANGELOG/templates/release workflow). Audit ledger maps every Fixed claim to a real change with zero overclaims.
* Bump toolchain to go1.26.4 to clear reachable stdlib CVEs
go.mod pinned toolchain go1.24.13, whose bundled standard library has 9
govulncheck-reachable CVEs (crypto/tls KeyUpdate DoS, net/http2 loop, crypto/x509 x3,
net, net/url, os, net/textproto). CI and release build via go-version-file: go.mod, so
shipped binaries inherited them.
Bumping the toolchain directive to go1.26.4 clears all nine — govulncheck ./... now
reports 0 reachable (minimum that clears them is go1.25.11; go1.26.4 matches the team's
local Go). The go directive stays at 1.24.2 (minimum language version). Verified:
go build/vet/gofmt clean, full go test ./... green.
* Add govulncheck CI gate and SHA-pin GitHub Actions
- ci.yml: new 'security' job runs govulncheck as a hard gate (fails on a reachable
vulnerability; passes now that the toolchain is bumped) plus an advisory deadcode step
that surfaces dormant code without blocking.
- Pin every GitHub Action to a full commit SHA (checkout, upload-artifact, github-script)
with a version comment, across all four workflows — previously only setup-go was pinned,
leaving the mutable v4/v7 tags as a supply-chain risk.
* Add hooks management command (add/remove/enable/disable)
Wires the previously-dormant hooks.ConfigStore (10 unreachable funcs -> 0) into the CLI:
zero hooks add <id> --event <event> --command <cmd> [--name --description --matcher --arg --user --json]
zero hooks remove|enable|disable <id> [--user --json]
Writes the project hook config by default (<cwd>/.zero/hooks.json) or the user config with
--user, reusing the store's locking + atomic writes + validation (normalizeDefinition). New
hooks are enabled; state is managed via enable/disable. JSON output is secret-scrubbed via
redaction. Mirrors the existing 'zero mcp add/remove/enable/disable' shape. Covered by
add/remove/toggle round-trip, validation, unknown-event, and JSON-redaction tests.
* Fix govulncheck CI job: pin GOTOOLCHAIN to the go.mod toolchain
go run govulncheck@latest selected the toolchain from govulncheck's own go.mod
(downgrading to go1.25.11), which then could not load our go1.26-requiring packages
(fips140only_go1.26.go), failing the security job. Resolve GOTOOLCHAIN from go.mod's
toolchain line so govulncheck and deadcode both run under go1.26.4.
* Address review: harden CI checkout, pin tool versions, validate hook event
CodeRabbit findings on #193:
- ci.yml: persist-credentials: false on all checkout steps (smoke/performance/security)
— these jobs run repo code and never push, so don't keep the token in git config.
- ci.yml: pin [email protected] and [email protected].0 instead of @latest, so the security
gate is deterministic and not subject to supply-chain drift.
- hooks: add exported IsValidEvent/KnownEvents (single source); parseEvent reuses it, and
'zero hooks add' now rejects an invalid --event with a usage error at parse time instead
of falling through to the Upsert app-error crash path.