Skip to content

fix(release-kit): repair confirmed quality findings in the payload - #20

Closed
John-David Dalton (jdalton) wants to merge 11 commits into
mainfrom
release-templates
Closed

fix(release-kit): repair confirmed quality findings in the payload#20
John-David Dalton (jdalton) wants to merge 11 commits into
mainfrom
release-templates

Conversation

@jdalton

Copy link
Copy Markdown
Collaborator

Follow-up to the merged #19. Repairs the CONFIRMED quality findings that reproduce in the sauce release-kit payload (the byte-authority). Verified against the adversarial findings set; findings that were jdm-aot-only or already-correct in sauce are documented rather than changed.

Correctness (payload behavior)

  • --access no longer hard-coded public. runStaged/runDirect/runWorkspacePublish resolve access (kit config → publishConfig.access → scoped/unscoped default) via a new resolveReleaseAccess, so a restricted package is no longer shipped public. Proven by a real bootstrap --dry-run: publish @acme/widget@0.0.0 --access restricted.
  • npm.distTag is now consumed — staged --tag falls back to the config value, not a hard-coded latest.
  • Unknown flags are rejected. @socketsecurity/lib parseArgs does not throw on unknown flags even under strict; npm-publish / cargo-publish / create-release now diff parsed keys (camelCase-alias aware) and exit 2. github-release / brew-publish parse errors exit 2 (were 1). Bootstrap already exits 2 (node:util strict).
  • Exit-code + help consistency — npm-publish mode/backfill conflicts exit 2; --help names node scripts/socket-release/npm-publish.mts, not the dead pnpm publish.

Stale references / duplication

  • Dropped the phantom publish-pipeline mentions (the healer is github-release.mts).
  • Extracted packumentUrl() + NPM_AUTH_TOKEN_KEY into constants/npm-registry.mts (8 inline copies + 3 hard-coded token keys); removed the unused NPM_REGISTRY export.
  • trusted-publisher-plan derives CANONICAL_* from the single trustedPublisherLaw() — one law source.
  • Trimmed dangling check//docs/ citations and wheelhouse provenance from headers; fixed create-release's missing-config pointer.

Tests (was: zero release-time coverage)

  • publish-helpers: resolveNpmAccess (access-public regression guard), stageAction, readStagedShasum, packumentUrl, unknownFlags, extractChangelogSection.
  • trust-sweep: conformsToLaw pinned per law field — kills the surviving environment-comparison mutation.
  • registry-liveness-gate: runGate driven live/404/unreachable with an injected fetch, plus the pure decision functions.

Not changed (documented, with evidence)

  • playwright-law.mts and the trusted-publisher browser quartet are live/intentional in sauce (imported by the release-kit-launches-are-sanctioned check and allowlisted in release-kit-is-coherent), not dead as in jdm-aot.
  • Soak findings, the golden self-create, and the lint-opt-out do not reproduce in the sauce payload (no soak module; read-only fixtures; the payload is linted).

Gates

232 release-kit tests pass; release-kit-is-coherent + release-kit-launches-are-sanctioned green; actionlint clean on all 4 workflow templates; payload + tests typecheck clean; bootstrap --help/--dry-run verified.

… examples

The copy-in release engine (scripts/socket-release/): the ported fleet
publish stack (npm staged publishing, cargo, web-auth router, browser
session law), a NEW eight-step bootstrap (preflight, placeholder with
hard --reserve consent, npm-access-permissive, github-env,
staged-config, trusted-publisher, npm-access-staged-only, verify), the
NEW brew tier (checksums-authority formula bumps, direct tap commits),
github-release.mts (the registry-gated tag-gap healer), env-mapped
SHA-pinned workflow templates, and the publishing-access
permissive-then-staged-only machinery.

Plus the sauce-side kit tooling: kit-manifest.json generator (--check),
the channel-mapped installer (plan default, --apply, --force, --verify
byte-parity, --json), three consumer examples with expected-install
goldens, and the kit README (deferrals, contract-drift posture,
first-publish/first-brew procedures with factory-rendered gates).
shipped-surfaces classifies the new tree with a narrow marker
allowlist for the shared browser-profile literal.
Four auto-discovered repo checks: release-kit-is-coherent (manifest
freshness, fleet-marker leaks, no shipped tests, pure-module import
discipline), release-kit-launches-are-sanctioned (the wheelhouse text
scan over the payload plus the law self-check),
release-kit-workflows-are-env-mapped (no expressions in run bodies,
SHA-pinned dated uses, permissions + concurrency), and
release-kit-types-resolve (the payload tsc program, release tier). The
payload tree joins the repo-owned oxlint ignore tail: its bytes are the
shipped product — kit-manifest.json pins them and every consumer
byte-verifies them — so lint autofixes must never rewrite them; the
kit's own gates lint it instead.
Five skills under skills/socket-release/: the user-invoked installer
skill (clone sauce, install channels, pin deps, bootstrap through the
gates, playwright law verbatim) and four agent skills that operate the
shipped flows end to end — npm-publish (bootstrap with the
publishing-access permissive/staged-only steps, staged dispatch, soak,
--approve promote, backfill, deprecate-as-rollback), gh-release (ORDER
RULE, immutable three-step cut, checksums.txt, tag-gap healing),
crates-publish (staged model, trusted publishing, index-propagation
wait, yank-as-rollback), and brew-tap (tap layout, formula bump,
sha256 verification against the release's own manifest). Every command
each skill names resolves to a shipped script; every human moment is a
fleet gate. Marketplace + generated tables updated via generate.
Unit suites over the payload's pure core: plan DAG/resume/receipts,
state round-trip + contextKey invalidation, render + the hand-rolled
validateRunJson (accepts every committed run golden, rejects mutated
documents), the eight-factory gate mirror, kit config accept/reject,
preflight's ten check arms, placeholder consent + fail-closed
classification, env probes with exact gh api argv fixes, staged-config
byte-parity + conflict refusal + surgical package.json edit,
trusted-publisher fail-closed trust reads + revoke-then-create argv,
verify aggregation with the staged-only terminal assertion, the
publishing-access parser over the three golden pages + unknown-shape
refusal, brew formula round-trips + the four tap refusals with zero
commits, install manifest/planner, and the checksum-writer grammar
round-trip. Integration: the installer against real temp dirs per
example (expected-install parity, idempotent second apply, --verify),
and full in-process bootstrap runs on fully fake seams pinned to four
run goldens with exit codes 0/2/3/4. All fixtures synthetic,
authority-annotated; no test opens a socket or launches a browser.
Correctness (payload behavior):
- staged/direct/workspace publishes resolve npm access (kit config ->
  publishConfig.access -> scoped/unscoped default) instead of hard-coding
  --access public, so a restricted package is no longer shipped public.
- npm.distTag is now consumed: the staged --tag falls back to the kit
  config value, not a hard-coded 'latest'.
- reject unknown flags across the registry-writing CLIs: npm-publish,
  cargo-publish, create-release diff parsed keys (camelCase-alias aware) and
  exit 2; github-release/brew-publish parse errors now exit 2, not 1.
- npm-publish mode/backfill conflicts exit 2 (usage error), matching the
  bootstrap contract; --help names the real invocation, not `pnpm publish`.

Stale references / duplication:
- drop the phantom `publish-pipeline` mentions (npm-publish --help, approve,
  npm/shared); the healer is github-release.mts.
- extract packumentUrl() + NPM_AUTH_TOKEN_KEY into constants/npm-registry.mts
  (8 inline copies + 3 hard-coded token keys collapsed); remove the unused
  NPM_REGISTRY export.
- trusted-publisher-plan derives its CANONICAL_* from the single
  trustedPublisherLaw() so the browser plan and the registry sweep can never
  assert different desired shapes.
- trim dangling check/doc citations and wheelhouse provenance from headers.
- create-release: point the missing-config refusal at the real interface.

Tests (was: zero release-time coverage):
- publish-helpers: resolveNpmAccess (access-public regression guard),
  stageAction, readStagedShasum, packumentUrl, unknownFlags,
  extractChangelogSection.
- trust-sweep: conformsToLaw pinned per law field (kills the surviving
  environment-comparison mutation).
- registry-liveness-gate: runGate driven live/404/unreachable with an
  injected fetch, plus the pure decision functions.
- typecheck the two release-kit test files that failed strict tsc.
- rename install/effects.mts -> install/seams.mts (Law 3: an injectable effect module is seams.mts); update all 7 referencing sites (installer, gen-manifest, 3 sauce checks, install test).

- reclassify lib/commit-via-github-api.mts common -> brew in channelsForPath (its only importer is publish-infra/brew/tap.mts); regen kit-manifest.json; update npm-lib+rust-crate expected-install.json and manifest.test.mts. No runtime behavior change: the de-listed bytes were unreachable for npm/crates-only consumers.

- README: add ARCHITECTURE (the npm thread walked file-by-file) + the naming law (10 rules), stating which are machine-enforced.

- release-kit-is-coherent.mts: enforce naming law 1 (root-entry allowlist) and law 6 (suffix/.d.mts sidecar) mechanically.

Skipped (documented): behavior-changing rows (soak backport, access-lifecycle forward-port, cli-flags content-adoption, create-release deletion, github-release registry hardcode) and fleet-canonical/cascade-owned rows (trust-sweep/trusted-publisher renames, check/script-paths-resolve move, skill renames).
…e to >=95%

Add fast-check (catalog 4.9.0) property suites for every fuzzable boundary in
the kit and back them with deterministic branch tests so coverage is stable:

  - brew formula rewrite: arbitrary formula text + version/sha inputs yield a
    valid rewritten formula or a loud refusal, never silent corruption
  - npm access-state / trusted-publisher / staged-tarball page parsers, driven
    by arbitrary HTML and single-byte mutations of the golden fixtures
  - the pnpm-workspace catalog editor: splice/remove round-trips + idempotence
  - installer manifest path handling: no traversal or clobbering outside target
  - the drift / byte-parity checker: any single-byte mutation of a payload copy
    is detected as a conflict

Fuzzing surfaced two real defects, fixed here:

  - parseStagedPayload threw a TypeError on a valid-JSON null/primitive body; it
    now degrades to an empty envelope (payload change, kit-manifest regenerated)
  - the installer accepted manifest paths with ".." or an absolute/drive root; a
    new isSafePayloadPath guard makes parseKitManifest refuse them loudly

Every pure module now clears >=95% lines and branches (parsers, plan, gates,
config at 100%; formula 96.8% branch; workspace-yaml 98.7%; render 98.3%).
Wire .config/repo/coverage.json so the coverage tooling measures the kit, and
retire the stale fuzz-tier exemption reason now that Tier-1 fast-check suites
cover the release-kit parsers.
- npm-publish.mts: disable yargs boolean-negation so --no-reconcile/--no-release/--no-scan bind their declared keys instead of writing phantom reconcile/release/scan keys that the unknown-flag guard rejected (exit 2); expose parsePublishArgs for regression coverage.
- release.mts extractChangelogSection: match the version at a heading boundary (end / space / ]) so 1.2.30 no longer answers for 1.2.3, nor 2.0.0-rc.1 for 2.0.0.
- registry-liveness-gate.mjs: resolve fs.globSync lazily via createRequire so the gate loads on the runner's system Node <22 (globSync is Node 22+); only the crates workspace-glob path needs it.
- brew-publish.mts + README: point the missing-checksums fix at github-release.mts --tag <tag> --release, not the dead create-release.mts.
- README naming law: add bootstrap.mts to the machine-enforced root allowlist, add release-kit-types-resolve to the sauce-side gates, fix install/{...,seams}.mts.
- SKILL.md backfill: add the mandatory non-latest --tag/dist-tag.
- Move every publish-infra/** and bootstrap/steps/** test to mirror its payload path (naming law rule 8) and add a structural enforcement test.
- Regenerate kit-manifest.json for the edited payload bytes.
…defects

- npm-publish.mts: reject stray positionals (exit 2) via a new
  unexpectedPositionalsMessage so a dash-less mode typo (e.g. `approve` for
  `--approve`) no longer falls through to the default --staged path.
- publish-infra/npm/staged.mts: gate runDirect's already-published heal on
  !dryRun so `--direct --dry-run` on a live version performs no tag/GH-release
  writes; emit a dry-run preview. runDirect gains root + release test seams.
- bootstrap/seams.mts + publish-infra/shared.mts: resolve a sentinel non-zero
  code (127) on spawn ENOENT instead of rejecting, so a missing gh/git/pnpm
  degrades to preflight's designed red-check rather than an unhandled crash.
- templates/.../mint-app-installation-token.mjs: drop the dangling
  scripts/socket-release/check/app-tokens-are-scoped.mts pointer (the real
  check is fleet-internal and unshipped) — name a fleet CI check, no path.
- skills/socket-release/gh-release/SKILL.md: route "Cutting a release with
  assets" to github-release.mts (create-release.mts is the dead second entry,
  absent from real consumers).
- kit-manifest.json regenerated; regression tests added for each code fix.
…release-subject redirect

- README naming law rule 5 + npm-publish/SKILL.md: drop the "soak" phase from
  the two-phase-verb doctrine. The byte-authority payload ships no soak (no
  lib/soak.mts, no --soak/--skip-soak, no approve-time refusal), so npm/cargo
  promotion is `stage → approve`. Note crates.io has no dist-tags and no
  unpublish (its promote is a permanent one-way approve), and brew is a
  plan → apply formula bump tied to an already-published release.
- test/repo/unit/release-kit/_shared/release-subject.test.mts: cover the
  publishConfig.directory redirect path end to end — the plain shape, the
  redirect shape, the repository fallback, and all four safety throws
  (empty/non-string directory, a directory escaping the repo root, a missing
  subject manifest, a subject manifest with no name/version). The escape guard
  had no test in the byte-authority; a mutation disabling it now fails.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant