> ## Documentation Index
> Fetch the complete documentation index at: https://delivery.vexa.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Kit v0.1.6 — the first publish on a rotated channel key

> Package, push and sign the kit on the pilot channel with a newly rotated key, then prove the rotation in both directions and pull the result back the way a subscriber will.

**Date:** 2026-09-06. **Channel:** the pilot channel on `channel.vexa.ai` — the
**live** registry, not a test rig. **Source:** `Vexa-ai/vexa-delivery` `main` @
`850c2469`, clean detached checkout. **Container work** ran on `bbb`, never on
the laptop.

The channel's signing key was rotated earlier the same day. This is the first
artifact published under the new key, so the question the pass had to answer is
not only *did the kit publish* but **did the rotation actually take** — a new
key that verifies is worth little if the retired one still verifies too.

## What was published

|                        |                                                                                                                        |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Ref**                | `channel.vexa.ai/vexa/channel/<pilot-channel>/kit:v0.1.6`                                                              |
| **Digest**             | `sha256:f885bbae2efeae28ea778e8e47ae0ba0a2ddc7bc28404b08de9139909ed824fb`                                              |
| **Layer / tgz sha256** | `d65aec2f9fc4b21107e892761d819e102b0817dd9f807252b3837bac1f72f0e9` — 262080 bytes, and byte-identical when pulled back |
| **Artifact type**      | `application/vnd.vexa.kit`                                                                                             |
| **Built**              | `2026-09-06T22:42:25Z`, the marker written into the package's `VERSION`                                                |
| **Pushed with**        | `oras 1.2.3`, publisher credential supplied on stdin — never argv, never written to disk on either host                |
| **Signing**            | cosign **2.6.5**, key mode, `--new-bundle-format=false --use-signing-config=false --tlog-upload=false`                 |
| **`latest`**           | moved to `sha256:f885bbae…`; it had pointed at v0.1.5                                                                  |
| **Predecessors**       | `v0.1.0 … v0.1.5` left standing                                                                                        |

`kit/release.sh --dry-run` ran first and packaged an identical 262080-byte tree
before anything was pushed.

**cosign is pinned to the 2.x series on purpose.** The channel's admission
controller is Kyverno 1.19, which cannot read the signature layout 3.x writes;
a 3.x signature is invisible to it rather than invalid, which is the worse of
the two failures. The host carries 2.6.1, 2.6.5 and 3.1.3 side by side, so the
release ran with `cosign` resolved to 2.6.5 through an explicit PATH entry
rather than through whichever copy happened to win — `release.sh` calls bare
`cosign` and has no override of its own.

**The flag set survives the version pin.** The 2026-08-24 rehearsal recorded
that 3.x *requires* `--use-signing-config=false` alongside `--tlog-upload=false`.
2.6.5 accepts both, so the script's signing line is correct on either — worth
stating because it is the kind of thing that silently stops being true.

## Proof 1 — the version tag and `latest` name one digest

```
oras resolve …/kit:v0.1.6  -> sha256:f885bbae…
oras resolve …/kit:latest  -> sha256:f885bbae…
```

`latest` is moved with `oras tag` against the same descriptor bytes, so the
signature made over the digest carries without a second signing operation.

## Proof 2 — it verifies against the channel's pinned key

```
cosign verify --key channel.pub --insecure-ignore-tlog=true \
  channel.vexa.ai/vexa/channel/<pilot-channel>/kit@sha256:f885bbae…
→ The following checks were performed on each of these signatures:
    - The cosign claims were validated
```

`--insecure-ignore-tlog=true` is correct here rather than a weakening: the
channel signs offline against a pinned key and uploads nothing to a
transparency log, which is what makes it air-gappable. It is the same form
`kit/bootstrap.sh` runs on the subscriber's side.

## Proof 3 — the rotation took, shown in both directions

Same command, same digests, differing only in `--key`:

| Artifact       | Key             | Result                                                                                            |
| -------------- | --------------- | ------------------------------------------------------------------------------------------------- |
| kit **v0.1.5** | **retired** key | **Verified** — the control                                                                        |
| kit **v0.1.5** | new key         | refused, `no matching signatures`                                                                 |
| kit **v0.1.6** | **new** key     | **Verified**                                                                                      |
| kit **v0.1.6** | **retired** key | **refused** — `no matching signatures: invalid signature when validating ASN.1 encoded signature` |

**The control row is the one that makes this a proof.** On its own, *"the old
key does not verify v0.1.6"* is equally consistent with having pointed the check
at a key that never signed anything on this channel — an easy mistake to make
when a rotation has left more than one retired public half lying around, which
was exactly the case here. The retired key **does** verify v0.1.5 and **does
not** verify v0.1.6; the new key does the inverse. A third public half found
alongside the others was tested too, and refuses v0.1.6 as expected.

**Where the retired key came from matters, and it was not where it was
supposed to be.** The obvious source — the previous revision of the published
`channel.pub` in the state repository — does not exist: the commit that was
believed to have replaced it had in fact *created* the file, and its contents
were themselves superseded hours later. Reading git history for "the version
before" produced a key that had never signed anything. The genuine retired key
came from the vault, and was confirmed as genuine by the control row above
rather than by where it was filed. **A key's provenance is a claim to test, not
a path to trust.**

## Proof 4 — a subscriber-shaped pull gets a verified v0.1.6

Run on `bbb` from a directory holding **only** `bootstrap.sh`, with `HOME` and
`TMPDIR` isolated so the publisher credential used for the push was not
reachable — the isolated `HOME` was empty, with no `.docker/config.json` in it
— and with a **pull-only** credential supplied through the environment.

```
== resolving channel.vexa.ai/vexa/channel/<pilot-channel>/kit:latest
   digest sha256:f885bbae…
== cosign verify …@sha256:f885bbae… against channel.pub
   signature OK
vexa-kit v0.1.6 unpacked to …/vexa-kit
  verified sha256:f885bbae… against channel.pub before unpacking
```

The ordering is the security property and it held: the signature is checked
before a single byte is unpacked.

| Check                  | Result                                                                    |
| ---------------------- | ------------------------------------------------------------------------- |
| unpacked `VERSION`     | `version=v0.1.6`, `built=2026-09-06T22:42:25Z`                            |
| unpacked `.kit-source` | records the digest above, for the self-update path                        |
| `install.sh` flags     | `--argocd`, `--kyverno`, `--claim-code`, `--manifests` — all four present |

**The isolation is not decoration.** The same host had just pushed with the
publisher credential, which `oras login` leaves in `~/.docker/config.json`, and
`bootstrap.sh` deliberately carries on-disk auths across to defeat a hanging
credential helper. Without isolating `HOME`, the pull would have quietly
authenticated as the publisher and proven nothing about the subscriber's path.

## What this pass does not close

* **The pull-only credential was an existing account of ours, not a freshly
  minted throwaway.** The credential tool could not mint one; that gap is
  tracked internally and is not a property of the kit. What the substitution
  costs is narrow: reads are not scoped per account at the edge — only writes
  are — so the path exercised is the same one a subscriber takes, but this pass
  did not exercise *credential issue and revoke*.
* **Nothing was installed from this kit.** Pull, verify, unpack and shape are
  proven. `install.sh` was not run against a cluster here.
* **The kit tree is current as of this writing**: `kit/` is unchanged between
  `850c2469` and `main`, so v0.1.6 is not already behind.
