From 403eee364fccb74214fe7f12b4b1a85463ed4b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Z=20Sink=C3=B3?= Date: Thu, 13 Aug 2026 12:19:22 +0200 Subject: [PATCH] =?UTF-8?q?release(prep):=20v0.2.0=20=E2=80=94=20a=20kiad?= =?UTF-8?q?=C3=A1s=20el=C5=91k=C3=A9sz=C3=ADt=C3=A9se?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Miért 0.2.0 és nem 0.1.6: ez a kiadás töri a nyelvet. Egy patch-verzió elrejtené, hogy a 0.1.5-re írt kompozíciók nem mind érvényesek alatta. Role lapos hétértékű enumból három ortogonális tengely; a `role: reference` rövid alak megszűnt reference `shape_type: reference` visszavonva — annotáció lett; a dokumentált `cic:{namespace}:{Kind}` formátum hibás volt descriptor `type` → `shape_type`, amit minden kompozíció amúgy is így írt default nem uniform: megfigyelt, derived, volatile és kulcs értékre tilos surface a node nem mondhat ellent a felületnek; a beágyazottak öröklik presence egyetlen tengely, tagadó alak nélkül lista minden listának van kulcsa; összetettnél `item_key` kötelező envelope v2 a build_hash az EGÉSZ bundle-t fedi. A v1 négy tagot fedett, így a kind/version/timestamp aláíratlan volt — egy 0.1.5 → 9.9.9 átcímkézés 2099-es időbélyeggel tisztán verifikált. A v1 továbbra is verifikál; D-015 rögzíti, a D-013 módosításaként. A docs/RELEASE-0.2.0.md a migrációt is leírja, és kimondja, amit mérni lehetett: a három élő kompozíciónak (kubernetes-pod, network-interface, compute-resource) EGYIK lépés sem kell. A szabályok a korpuszból íródtak, nem ellene. A README-k OCI példái v0.2.0-ra állítva. Az aláírt artifact NINCS ebben a commitban: a `make release` Vault-kulcsot igényel, és ezen az ágon fut le. A kapu addig is zöld: self-test 40/40, 153 teszt, 89% lefedettség. --- [signing-metadata] key = cic-my-sign-key signature = vault:v1:MEUCIQDbbVQ7sW4QOgmRFa8bE9+AENx0VcuBfpacG8vbjHCFOwIgXBd0tg3I2N6qhGM3w3/315qeREy+NgO94yrkP6h0Etc= hash-algorithm = sha256 digest = 7JU4YiJrxSlHdOSQDCr+kshftKNb4KlNVcQStCGi4dg= [certificate] -----BEGIN CERTIFICATE----- MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0 lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW -----END CERTIFICATE----- --- README.hu.md | 6 +- README.md | 6 +- docs/RELEASE-0.2.0.md | 136 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 docs/RELEASE-0.2.0.md diff --git a/README.hu.md b/README.hu.md index 57f800a..41f64ca 100644 --- a/README.hu.md +++ b/README.hu.md @@ -156,13 +156,13 @@ A séma release OCI artifactként érhető el a GitHub Container Registry-ben. **ORAS-szal:** ```bash -oras pull ghcr.io/centralinfracore/schema/cic-primitives:v0.1.5-src2026 +oras pull ghcr.io/centralinfracore/schema/cic-primitives:v0.2.0-src2026 ``` **curl-lel (ORAS nélkül):** ```bash -REPO="centralinfracore/schema/cic-primitives"; TAG="v0.1.5-src2026"; \ +REPO="centralinfracore/schema/cic-primitives"; TAG="v0.2.0-src2026"; \ TOKEN=$(curl -fsSL "https://ghcr.io/token?scope=repository:${REPO}:pull" | jq -r .token); \ DIGEST=$(curl -fsSL \ -H "Authorization: Bearer ${TOKEN}" \ @@ -170,5 +170,5 @@ DIGEST=$(curl -fsSL \ "https://ghcr.io/v2/${REPO}/manifests/${TAG}" | jq -r '.layers[0].digest'); \ curl -fL -H "Authorization: Bearer ${TOKEN}" \ "https://ghcr.io/v2/${REPO}/blobs/${DIGEST}" \ - -o cic-primitives-v0.1.5.yaml + -o cic-primitives-v0.2.0.yaml ``` diff --git a/README.md b/README.md index a822b4c..57fdc22 100644 --- a/README.md +++ b/README.md @@ -157,13 +157,13 @@ The schema release is available as an OCI artifact in GitHub Container Registry. **With ORAS:** ```bash -oras pull ghcr.io/centralinfracore/schema/cic-primitives:v0.1.5-src2026 +oras pull ghcr.io/centralinfracore/schema/cic-primitives:v0.2.0-src2026 ``` **With curl (no ORAS required):** ```bash -REPO="centralinfracore/schema/cic-primitives"; TAG="v0.1.5-src2026"; \ +REPO="centralinfracore/schema/cic-primitives"; TAG="v0.2.0-src2026"; \ TOKEN=$(curl -fsSL "https://ghcr.io/token?scope=repository:${REPO}:pull" | jq -r .token); \ DIGEST=$(curl -fsSL \ -H "Authorization: Bearer ${TOKEN}" \ @@ -171,5 +171,5 @@ DIGEST=$(curl -fsSL \ "https://ghcr.io/v2/${REPO}/manifests/${TAG}" | jq -r '.layers[0].digest'); \ curl -fL -H "Authorization: Bearer ${TOKEN}" \ "https://ghcr.io/v2/${REPO}/blobs/${DIGEST}" \ - -o cic-primitives-v0.1.5.yaml + -o cic-primitives-v0.2.0.yaml ``` diff --git a/docs/RELEASE-0.2.0.md b/docs/RELEASE-0.2.0.md new file mode 100644 index 0000000..d3c0f6d --- /dev/null +++ b/docs/RELEASE-0.2.0.md @@ -0,0 +1,136 @@ +# Release 0.2.0 — what changes, and what breaks + +`0.1.5 → 0.2.0`, a **minor** bump, because this release changes the language in +ways a `0.1.6` would have hidden. Composition files written against `0.1.5` are +not all valid under `0.2.0`. + +## Breaking: the language + +### Role is three axes, not a flat list + +The seven values were never one dimension. They are now stated as they always +were, and the difference is enforceable rather than descriptive: + +```yaml +authority ∈ { config, state, operational } exactly one, from the surface if omitted +structural ⊆ { key, reference } zero or more +lifecycle ∈ { derived, volatile } zero or one +``` + +Short forms are unchanged and still valid (`role: config`, `role: key`, +`role: state`, `role: derived`, `role: volatile`). **`role: reference` is no +longer a valid short form** — a reference's authority cannot be derived, so it +requires the long form. + +What this buys: a node that is observed, points at another entity, and is not +persisted can finally be written. Flat, it had to be called `state` and the +other two properties were lost. + +### `reference` is an annotation, not a Shape type + +`shape_type: reference` is retired. Every composition already wrote it the new +way; the catalogue was the thing that was wrong. + +```yaml +shape_type: scalar +scalar_type: string +semantic_type: cic-reference +reference_target: "cic:network:NetworkInterface" # {namespace}:{Kind} +``` + +`shape.yaml` documented the target as `cic:{namespace}:{Kind}`, which expands to +`cic:cic:network:X` because the namespace already carries the prefix. The +documented format was wrong; the corpus was right. + +### `type` on a field descriptor is `shape_type` + +The catalogue called it `type`. No composition has ever written that. + +### Defaults are no longer uniform + +The schema may not supply a default for a value it does not own: + +| Role | defaultable? | +|---|---| +| `authority: config` | yes | +| `authority: state` / `operational` | **no** | +| `lifecycle: derived` / `volatile` | **no** | +| `structural: key` | **no** | + +`missing`, `unknown`, `not_observed`, `not_implemented` and a defaulted value +are five different statements. An adapter that could not read `power_state` +does not produce `power_state: running` because that is the schema default. + +### A node may not contradict its surface + +`config_surface` admits `authority: config`; `state_surface` admits `state` or +`operational`. Nested `fields` and `item_fields` inherit the parent's surface, +and a node that omits `role` takes the surface's authority — omitting a member +is not a way out of a rule. + +### Presence is one axis + +`mandatory` and `optional` may not both appear, and neither may be written as +`false`. `mandatory` with a `default` is invalid. + +### Lists state their key + +Every list has a key. A single `role: key` item field is enough; two or more +require an explicit `item_key` so the composite key's order is defined. + +## Breaking: the release artifact + +**Envelope v2.** `build_hash` now covers the whole bundle except +`release.sign`, `release.build_hash` and `cic_countersign`. Under v1 it covered +four members, leaving `kind`, `version` and `timestamp` unsigned — a bundle +relabelled `0.1.5 → 9.9.9` with a 2099 timestamp verified clean. + +v1 artifacts keep verifying; `release.envelope` says which applies, and its +absence means 1. Recorded as **D-015**, which amends D-013. + +The bundle gains a `provenance` block — source commit, dependency lock digest, +grammar digest — signed automatically under v2. + +## Verification: what it now proves, and what it refuses to claim + +- the counter-signature is **verified**, and the authority certificate is + checked against the root the bundle carries. Before, the schema described the + block and the verifier ignored it: a countersign replaced with garbage still + reported success. +- the developer pledge's hash is **recomputed** and its signature **verified**. + Before, only `kind` and the date window were checked, so a hand-written + commitment with invented fields passed. +- `verify-release` no longer prints "integrity OK" after admitting it could not + check the chain. It lists what is proven and what is not, and says + *"Internally consistent — signed by the certificate this artifact carries. + That is not the same as trusted."* +- `--trust-root ` pins the root out of band. Without it, every certificate + in the artifact is self-asserted, and the output says so. + +## Migration + +Compositions written for 0.1.5 need, at most: + +1. `role: reference` → the long form with an explicit authority; +2. `shape_type: reference` → `scalar` + `semantic_type` + `reference_target`; +3. any `default` on an observed, derived, volatile or key node removed; +4. any node whose authority contradicts its surface moved or relabelled; +5. `mandatory: false` / `optional: false` → omit the member; +6. lists with two or more key fields → add `item_key`. + +Measured on the live corpus before release: `kubernetes-pod.yaml`, +`network-interface.yaml` and `compute-resource.yaml` need **none** of these. +The rules were written from the corpus, not against it. + +## Gates this release runs through + +`make release` refuses to build if the grammar rejects a composition it would +ship, and runs the grammar's own self-test first — a checker that can no longer +fail proves nothing about what it approves. + +``` +self-test 40/40 fixtures, 19 of them deliberately broken +tests 153 +coverage 89%, ratchet at 88 +mutation 990 mutants on compiler.py; the trust-critical survivors killed +```