diff --git a/MEMORY.md b/MEMORY.md index 8e3f06e..6e177fb 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -38,7 +38,22 @@ domain decisions. ## Current release status (2026-08-07) -- **v0.4.1 is the canonical release.** All five public packages are on npm at +- **v0.5.0 is prepared on `main`, not yet published.** PR #61 fixed a real + gap in `@changesafe/core`'s currently-published `0.4.1`: a domain adapter + could skip any universal policy (not just the two the shape permits) with + zero enforcement outside the app's own registration path, and a skip's + claimed replacement was never verified to exist. Every receipt now carries + `policyCoverage`. PR #60 added Kubernetes support to `changesafe eval` and + fixed a prompt-injection surface (label/selector values leaking into the + trusted preamble) and an eval-accuracy gap (unvalidated rollback + references) found in review. `CORE_POLICY_VERSION` moves to `core-v0.2.0`, + `TERRAFORM_POLICY_VERSION` to `terraform-v0.2.0` — see + `docs/RELEASE_NOTES_v0.5.0.md`. All nine workspace packages are bumped to + `0.5.0` on `main`; publishing still needs an explicit owner-authorized tag + and GitHub Release, after which this section should record the same + registry-smoke verification v0.4.1 got before being called canonical. +- **v0.4.1 is still the canonical release** until v0.5.0 actually publishes. + All five public packages are on npm at `0.4.1`, published by the release workflow over trusted publishing, and every one carries a verified provenance attestation recording `.github/workflows/publish.yml` in `wonkwonlee/ChangeSafe` at diff --git a/README.md b/README.md index 4289e77..d3a78c0 100644 --- a/README.md +++ b/README.md @@ -345,7 +345,7 @@ there is no `--auto-approve`. Full usage: [packages/cli/README.md](packages/cli/ ## Packages -Five public packages are on npm. As of **v0.4.1** they are published by the +Five public packages are on npm. Since **v0.4.1** they are published by the release workflow over npm trusted publishing, and each carries a provenance attestation naming the workflow, repository, and commit that produced it — `npm audit signatures` verifies them, and you should rather than take this @@ -355,6 +355,7 @@ bootstrap/remediation versions carry no attestation. Use `0.4.1` or later. `0.4.0` published only three of the five packages before failing, so the CLI and the Kubernetes domain do not exist at that version; those three are genuine and attested, but the set is incomplete. +(`v0.5.0` is prepared but not yet published — see `docs/LAUNCH.md`.) ```bash npm i @changesafe/core @changesafe/domain-terraform # embed the gate diff --git a/docs/LAUNCH.md b/docs/LAUNCH.md index 81d3cc9..757b9f5 100644 --- a/docs/LAUNCH.md +++ b/docs/LAUNCH.md @@ -5,9 +5,27 @@ deploys, tags, or posts automatically. ## Release truth -- `v0.4.1` is the canonical package/tag release: the complete published set of - the multi-domain workbench, and the first to go out through the trusted - publishing workflow rather than a manual publish. +- `v0.5.0` is **prepared on `main`, not yet published.** It is not the + canonical release until an owner-authorized tag and GitHub Release + actually complete the publish workflow — until then, `v0.4.1` remains + what `npm install` and the GitHub Action resolve to, and every + user-facing reference (this file's example below, `README.md`) stays + pinned to it. What v0.5.0 will contain once published: a universal-policy + skip legitimacy fix in `@changesafe/core` (a domain adapter could + previously skip any universal policy, not just the two the shape permits, + with no enforcement outside the app's own registration path), a new + Terraform `PLAN_CONTEXT_REQUIRED` policy replacing a prose-only + `VERIFICATION_REQUIRED` skip, every receipt now recording + `policyCoverage`, and `changesafe eval` gaining Kubernetes support. + `CORE_POLICY_VERSION` moves to `core-v0.2.0` and + `TERRAFORM_POLICY_VERSION` to `terraform-v0.2.0` — a v0.5.0 receipt will + not be directly comparable to an earlier one. See + [RELEASE_NOTES_v0.5.0.md](RELEASE_NOTES_v0.5.0.md). Once published and + registry-verified the same way v0.4.1 was below, update this bullet and + the pinned references to v0.5.0. +- `v0.4.1` is the canonical package/tag release: the complete published set + of the multi-domain workbench, and the first to go out through the + trusted publishing workflow rather than a manual publish. - **Do not point anyone at `0.4.0`.** It published three of five packages before failing, so the CLI and the Kubernetes domain do not exist at that version. The three that shipped are genuine and carry provenance; the set is diff --git a/docs/RELEASE_NOTES_v0.5.0.md b/docs/RELEASE_NOTES_v0.5.0.md new file mode 100644 index 0000000..70b424d --- /dev/null +++ b/docs/RELEASE_NOTES_v0.5.0.md @@ -0,0 +1,116 @@ +# ChangeSafe v0.5.0 + +A trust-model fix in `@changesafe/core`, a new Terraform policy that replaces +a prose-only skip with a real one, `changesafe eval` gaining Kubernetes +support, and two security-relevant fixes to the Kubernetes analysis prompt. + +**Policy behavior changed.** `CORE_POLICY_VERSION` moves to `core-v0.2.0` and +`TERRAFORM_POLICY_VERSION` moves to `terraform-v0.2.0`. A v0.5.0 receipt is +not directly comparable to a v0.4.x one — that is the point of the version +existing, not an oversight. + +## Universal-policy skip legitimacy, enforced in core + +A domain adapter's `skippedUniversalPolicies` could previously name any of +the five universal policies, not just the two whose shape assumes a +model-authored proposal or an in-place patch (`ROLLBACK_COMPLETE`, +`VERIFICATION_REQUIRED`). The only check against this lived in the app's own +runtime registration (`features/domains/runtime.ts`), not in published core — +so a hand-written adapter, or `changesafe gate` run directly against one, +got no enforcement at all. A probe adapter that skipped all five universal +policies passed `evaluatePolicies` cleanly with zero findings and `LOW` risk, +despite the proposal carrying an injection attempt, invented evidence, no +rollback, and no verification. + +`replacedBy` was also a bare string, so nothing verified a skip's claimed +replacement existed. Terraform's `VERIFICATION_REQUIRED` skip named `"the +pull request review"` — prose, not a policy. + +Fixed: + +- `evaluatePolicies` and `policyOrder` both validate every skip before doing + anything else, and throw for an illegitimate `policyId`, a duplicate skip, + or a replacement that names a policy the adapter does not declare (or that + collides with a universal policy id, which `policyOrder`'s id filter could + not otherwise distinguish from the skip itself). Only + `ROLLBACK_COMPLETE`/`VERIFICATION_REQUIRED` may ever be skipped — + `PATCH_SCHEMA`, `BLAST_RADIUS`, and `UNTRUSTED_INSTRUCTION` are structurally + answerable by every domain and no adapter may skip them. +- `SkipReplacement` is a typed shape (`{ kind: "domain-policy", policyId }`) + instead of a string. A replacement that named a non-mechanical process + rather than a real policy would have produced no finding of its own — the + gate would pass with a genuine verdict gap rather than merely an + honestly-labeled one — so that option does not exist at all. +- Every receipt now carries `policyCoverage`: the exact ordered policy ids + that ran, plus what was skipped and why. A verifier reads this from the + signed payload instead of fetching and trusting the adapter's source to + interpret an absent policy id. The field is optional on + `ChangeReceiptSchema` so a receipt issued before it existed (v0.4.1 and + earlier) still parses for hash and signature verification — + `createReceipt` always sets it going forward, and `canonicalize` drops an + `undefined` property, so a legacy receipt's hash is unaffected. + +## Terraform gains `PLAN_CONTEXT_REQUIRED` + +Terraform's proposal is derived mechanically from the plan with no model +involved, so it can never declare its own precondition or postcheck steps — +that is the honest reason it skips `VERIFICATION_REQUIRED`. What replaces it +used to be prose. It is now a real policy: `PLAN_CONTEXT_REQUIRED` warns when +a destructive change carries zero PR or commit context, because the pull +request review this domain relies on for verification needs something to +review. A plan that destroys nothing, or that carries any context entry, +passes. + +## `changesafe eval` measures Kubernetes too + +The benchmark previously imported `networkAnalysisPrompt` and `networkDomain` +only, so it measured one domain while the corpus spans three. Kubernetes now +has its own hardened prompt (`packages/ai/src/prompts/kubernetes.ts`) and is +registered in `ANALYSIS_DOMAINS`; `eval --domain kubernetes` resolves it +instead of the hardcoded network path. Terraform stays out by design — its +plan already is the proposal, so there is nothing for a model to propose. +Report schema moves to version 3, recording `corpus.domain`, so a report is +only ever compared against another from the same domain. + +## Two fixes in the same change + +Landed as part of getting Kubernetes eval support production-honest, not +found independently: + +- **Kubernetes eval input is normalized.** The strict, already-normalized + `KubernetesSnapshotSchema` was being parsed directly against raw, + collector-shaped scenario fixtures — every bundled Kubernetes scenario + failed before ever reaching the provider. `eval`'s Kubernetes domain now + tries the strict parse first and falls back to `normalizeSnapshot`, the + same boundary `changesafe gate` already used. +- **Pod-label and Service-selector values stay inside the untrusted + block.** The Kubernetes prompt's trusted preamble — the section the model + is told to trust, ahead of `` — was echoing + `podLabels` and `selector` values into it. Those are `Record` with no charset restriction beyond length, so an instruction-like + value there bypassed the untrusted-content boundary the system prompt + describes. They are no longer copied into the preamble; the full snapshot + already carries them inside the untrusted block. +- **Rollback references are validated too.** The Kubernetes prompt's local + cross-check validated a forward `replace` against the snapshot but never a + rollback `replace`, and accepted any rollback `remove` regardless of + whether it undid something the proposal actually added. A model response + with an ungrounded rollback reference was counted `accepted` by the + benchmark before the gate's `PATCH_SCHEMA` policy caught it downstream — + inflating the grounded-output metric for a proposal that was always going + to be blocked. +- **Prompt/adapter pairing is typed.** The analysis domain registry paired + each prompt with its adapter through two independent `as unknown as never` + casts, so nothing prevented registering, say, the Kubernetes prompt against + the network adapter. A single generic function now binds both under one + type parameter, so a mismatched pairing fails to typecheck. + +## Known limits + +- Terraform still cannot catch command smuggling: it is an external-diff + domain with no simulator, and no Terraform policy inspects planned + attribute values for command payloads. Tracked, not papered over with a + scenario the gate would not actually refuse. +- `K8S_SERVICE_SELECTOR` still only re-checks Services that existed before a + change; whether it should also check newly created Services is an open + decision, not yet made. diff --git a/lib/domain/version.ts b/lib/domain/version.ts index b35f8c4..c33f051 100644 --- a/lib/domain/version.ts +++ b/lib/domain/version.ts @@ -1,5 +1,5 @@ /** Kept in sync with package.json manually; embedded in receipts. */ -export const APP_VERSION = "0.4.1"; +export const APP_VERSION = "0.5.0"; /** Bumped whenever any frozen policy's behavior changes; embedded in receipts. */ export const POLICY_VERSION = "policies-v0.1.0"; diff --git a/package-lock.json b/package-lock.json index c41d0c2..b7edd35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "changesafe", - "version": "0.4.1", + "version": "0.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "changesafe", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "workspaces": [ "packages/*" @@ -8265,12 +8265,12 @@ }, "packages/ai": { "name": "@changesafe/ai", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { - "@changesafe/core": "^0.4.1", - "@changesafe/domain-kubernetes": "^0.4.1", - "@changesafe/domain-network": "^0.4.1", + "@changesafe/core": "^0.5.0", + "@changesafe/domain-kubernetes": "^0.5.0", + "@changesafe/domain-network": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { @@ -8279,7 +8279,7 @@ }, "packages/cli": { "name": "changesafe", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { "@kubernetes/client-node": "^1.4.0", @@ -8289,14 +8289,14 @@ "changesafe": "dist/changesafe.js" }, "devDependencies": { - "@changesafe/ai": "^0.4.1", - "@changesafe/core": "^0.4.1", - "@changesafe/domain-kubernetes": "^0.4.1", - "@changesafe/domain-network": "^0.4.1", - "@changesafe/domain-terraform": "^0.4.1", - "@changesafe/kubernetes-collector": "^0.4.1", - "@changesafe/ledger": "^0.4.1", - "@changesafe/server": "^0.4.1", + "@changesafe/ai": "^0.5.0", + "@changesafe/core": "^0.5.0", + "@changesafe/domain-kubernetes": "^0.5.0", + "@changesafe/domain-network": "^0.5.0", + "@changesafe/domain-terraform": "^0.5.0", + "@changesafe/kubernetes-collector": "^0.5.0", + "@changesafe/ledger": "^0.5.0", + "@changesafe/server": "^0.5.0", "esbuild": "^0.25.0", "typescript": "^5", "zod": "^4.4.3" @@ -8791,7 +8791,7 @@ }, "packages/core": { "name": "@changesafe/core", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { "zod": "^4.4.3" @@ -8805,10 +8805,10 @@ }, "packages/domain-kubernetes": { "name": "@changesafe/domain-kubernetes", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "yaml": "2.9.0", "zod": "^4.4.3" }, @@ -8821,10 +8821,10 @@ }, "packages/domain-network": { "name": "@changesafe/domain-network", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { @@ -8836,10 +8836,10 @@ }, "packages/domain-terraform": { "name": "@changesafe/domain-terraform", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { @@ -8851,9 +8851,9 @@ }, "packages/kubernetes-collector": { "name": "@changesafe/kubernetes-collector", - "version": "0.4.1", + "version": "0.5.0", "dependencies": { - "@changesafe/domain-kubernetes": "^0.4.1", + "@changesafe/domain-kubernetes": "^0.5.0", "@kubernetes/client-node": "^1.4.0", "zod": "^4.4.3" }, @@ -8863,10 +8863,10 @@ }, "packages/ledger": { "name": "@changesafe/ledger", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { @@ -8875,13 +8875,13 @@ }, "packages/server": { "name": "@changesafe/server", - "version": "0.4.1", + "version": "0.5.0", "license": "MIT", "dependencies": { - "@changesafe/core": "^0.4.1", - "@changesafe/domain-network": "^0.4.1", - "@changesafe/domain-terraform": "^0.4.1", - "@changesafe/ledger": "^0.4.1", + "@changesafe/core": "^0.5.0", + "@changesafe/domain-network": "^0.5.0", + "@changesafe/domain-terraform": "^0.5.0", + "@changesafe/ledger": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/package.json b/package.json index c203852..d93cf51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "changesafe", - "version": "0.4.1", + "version": "0.5.0", "private": true, "description": "A deterministic airlock for AI-proposed infrastructure changes: AI proposes, pure policies validate, a human decides, simulation stays sandboxed.", "license": "MIT", diff --git a/packages/ai/package.json b/packages/ai/package.json index e87a63e..5a9f4ea 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/ai", - "version": "0.4.1", + "version": "0.5.0", "description": "Provider-agnostic model adapters that produce ChangeProposals. One Zod schema drives structured output on every provider; every provider's output faces identical local validation.", "license": "MIT", "private": true, @@ -17,9 +17,9 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/core": "^0.4.1", - "@changesafe/domain-kubernetes": "^0.4.1", - "@changesafe/domain-network": "^0.4.1", + "@changesafe/core": "^0.5.0", + "@changesafe/domain-kubernetes": "^0.5.0", + "@changesafe/domain-network": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/packages/cli/dist/changesafe.js b/packages/cli/dist/changesafe.js index 0c5934e..87edab1 100755 --- a/packages/cli/dist/changesafe.js +++ b/packages/cli/dist/changesafe.js @@ -26181,7 +26181,7 @@ import { writeFileSync } from "node:fs"; import path2 from "node:path"; // src/version.ts -var CLI_PACKAGE_VERSION = "0.4.1"; +var CLI_PACKAGE_VERSION = "0.5.0"; var CLI_APP_VERSION = `changesafe-cli-${CLI_PACKAGE_VERSION}`; var SERVER_APP_VERSION = `changesafe-server-${CLI_PACKAGE_VERSION}`; diff --git a/packages/cli/package.json b/packages/cli/package.json index 7ce98e2..57912d0 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "changesafe", - "version": "0.4.1", + "version": "0.5.0", "description": "Gate AI-proposed infrastructure changes from the terminal or CI: deterministic policies, honest exit codes, hashed receipts. The gate itself never calls a model.", "license": "MIT", "type": "module", @@ -45,16 +45,16 @@ "yaml": "2.9.0" }, "devDependencies": { - "@changesafe/ai": "^0.4.1", - "@changesafe/core": "^0.4.1", - "@changesafe/domain-network": "^0.4.1", - "@changesafe/domain-terraform": "^0.4.1", - "@changesafe/ledger": "^0.4.1", - "@changesafe/server": "^0.4.1", + "@changesafe/ai": "^0.5.0", + "@changesafe/core": "^0.5.0", + "@changesafe/domain-network": "^0.5.0", + "@changesafe/domain-terraform": "^0.5.0", + "@changesafe/ledger": "^0.5.0", + "@changesafe/server": "^0.5.0", "esbuild": "^0.25.0", "typescript": "^5", "zod": "^4.4.3", - "@changesafe/domain-kubernetes": "^0.4.1", - "@changesafe/kubernetes-collector": "^0.4.1" + "@changesafe/domain-kubernetes": "^0.5.0", + "@changesafe/kubernetes-collector": "^0.5.0" } } diff --git a/packages/cli/src/version.ts b/packages/cli/src/version.ts index 0e65008..fa03e02 100644 --- a/packages/cli/src/version.ts +++ b/packages/cli/src/version.ts @@ -12,7 +12,7 @@ * a check. */ -export const CLI_PACKAGE_VERSION = "0.4.1"; +export const CLI_PACKAGE_VERSION = "0.5.0"; export const CLI_APP_VERSION = `changesafe-cli-${CLI_PACKAGE_VERSION}`; diff --git a/packages/core/package.json b/packages/core/package.json index 852286b..1703edb 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/core", - "version": "0.4.1", + "version": "0.5.0", "description": "The deterministic airlock engine: typed change proposals, pure safety policies, transactional decisions, and hashed receipts. Domain-agnostic.", "license": "MIT", "type": "module", diff --git a/packages/domain-kubernetes/package.json b/packages/domain-kubernetes/package.json index d4278c6..da66d67 100644 --- a/packages/domain-kubernetes/package.json +++ b/packages/domain-kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/domain-kubernetes", - "version": "0.4.1", + "version": "0.5.0", "description": "Kubernetes domain contracts for ChangeSafe: offline snapshots and manifest proposals only; never contacts or mutates a cluster.", "license": "MIT", "type": "module", @@ -51,7 +51,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "yaml": "2.9.0", "zod": "^4.4.3" }, diff --git a/packages/domain-network/package.json b/packages/domain-network/package.json index 8082184..c3df724 100644 --- a/packages/domain-network/package.json +++ b/packages/domain-network/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/domain-network", - "version": "0.4.1", + "version": "0.5.0", "description": "Network domain for ChangeSafe: declarative device state, an allowlisted patch engine, deterministic reachability, sandboxed simulation, and network safety policies.", "license": "MIT", "type": "module", @@ -43,7 +43,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/packages/domain-terraform/package.json b/packages/domain-terraform/package.json index b2f6b49..4c67099 100644 --- a/packages/domain-terraform/package.json +++ b/packages/domain-terraform/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/domain-terraform", - "version": "0.4.1", + "version": "0.5.0", "description": "Terraform domain for ChangeSafe: gate `terraform show -json` plan output with deterministic policies. Read-only; never runs Terraform.", "license": "MIT", "type": "module", @@ -43,7 +43,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/packages/kubernetes-collector/package.json b/packages/kubernetes-collector/package.json index ddf646e..6bcdb30 100644 --- a/packages/kubernetes-collector/package.json +++ b/packages/kubernetes-collector/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/kubernetes-collector", - "version": "0.4.1", + "version": "0.5.0", "private": true, "description": "Namespace-scoped read-only Kubernetes snapshot collector for ChangeSafe.", "type": "module", @@ -11,7 +11,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/domain-kubernetes": "^0.4.1", + "@changesafe/domain-kubernetes": "^0.5.0", "@kubernetes/client-node": "^1.4.0", "zod": "^4.4.3" }, diff --git a/packages/ledger/package.json b/packages/ledger/package.json index 7048865..9e7cce7 100644 --- a/packages/ledger/package.json +++ b/packages/ledger/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/ledger", - "version": "0.4.1", + "version": "0.5.0", "description": "Append-only SQLite receipt ledger with a hash chain, so deleting or reordering a decision is detectable rather than silent.", "license": "MIT", "private": true, @@ -17,7 +17,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/core": "^0.4.1", + "@changesafe/core": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/packages/server/package.json b/packages/server/package.json index 5ea5b89..faab167 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@changesafe/server", - "version": "0.4.1", + "version": "0.5.0", "description": "Authenticated self-hosted decision path: OIDC approver identity, server-recomputed findings, signed receipts, append-only ledger. Executes nothing.", "license": "MIT", "private": true, @@ -17,10 +17,10 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@changesafe/core": "^0.4.1", - "@changesafe/domain-network": "^0.4.1", - "@changesafe/domain-terraform": "^0.4.1", - "@changesafe/ledger": "^0.4.1", + "@changesafe/core": "^0.5.0", + "@changesafe/domain-network": "^0.5.0", + "@changesafe/domain-terraform": "^0.5.0", + "@changesafe/ledger": "^0.5.0", "zod": "^4.4.3" }, "devDependencies": { diff --git a/tests/integration/version-sync.test.ts b/tests/integration/version-sync.test.ts index 595d552..efca318 100644 --- a/tests/integration/version-sync.test.ts +++ b/tests/integration/version-sync.test.ts @@ -26,8 +26,8 @@ import { TERRAFORM_POLICY_VERSION } from "@changesafe/domain-terraform"; const root = path.resolve(import.meta.dirname, "../.."); -const TARGET_VERSION = "0.4.1"; -const TARGET_INTERNAL_RANGE = "^0.4.1"; +const TARGET_VERSION = "0.5.0"; +const TARGET_INTERNAL_RANGE = "^0.5.0"; const ManifestSchema = z.object({ name: z.string().min(1), @@ -77,7 +77,7 @@ function internalRanges(manifest: z.infer) { }).filter(([name]) => name.startsWith("@changesafe/")); } -describe("v0.4.1 workspace release identity", () => { +describe("v0.5.0 workspace release identity", () => { it("moves every root and workspace manifest together", () => { for (const relative of MANIFEST_PATHS) { expect(readManifest(relative).version, `${relative}/package.json version`).toBe( diff --git a/tests/unit/network-review-receipt.test.ts b/tests/unit/network-review-receipt.test.ts index 899e5c9..1180afd 100644 --- a/tests/unit/network-review-receipt.test.ts +++ b/tests/unit/network-review-receipt.test.ts @@ -31,7 +31,7 @@ import { } from "@/features/reviews/controller"; import { NETWORK_SCENARIOS } from "@/scenarios"; -const APP_VERSION = "0.4.1"; +const APP_VERSION = "0.5.0"; const CREATED_AT = "2026-07-29T00:00:00.000Z"; function scenarioOrThrow(scenarioId: string) {