python3 publisher/vexa_channel.py fetch | publisher | First step of a release crank: pull the release archive, its provenance bundle and the trusted root out of GitHub via gh into a working directory. Everything after this is offline, so this is the only step that needs the network to reach the OSS release. |
python3 publisher/vexa_channel.py build | publisher | Assemble the channel entry and run cross-checks C1..C9 against the release tag, the candidate image map at that tag, and the internal delivery receipt. A failed check refuses the entry — there is no silent path, only an explicit --break-glass record that becomes visible data inside the signed entry. |
python3 publisher/vexa_channel.py verify | publisher | Re-run every offline check against an entry directory without touching a registry. Use it after build to see what the entry claims before you push it, and to re-check an entry someone else built. |
python3 publisher/vexa_channel.py push | publisher | Publish the built entry: push it to the registry with oras, sign it and every image digest with cosign, and move the channel tag. The signing toolchain checks T1/T2 run inside this path so they cannot be skipped — T2 proves the signature is discoverable in the exact shape the customer’s Kyverno will ask for. |
python3 publisher/vexa_channel.py chart | publisher | Package the OSS chart with the release’s image digests baked in, so the customer’s Argo resolves a tag to nothing and a digest to exactly one image. Push it to the channel’s chart repository; the chart’s semver IS the channel position a station follows. |
python3 publisher/vexa_channel.py refresh | publisher | Re-stamp an entry’s expiry — same release, next seq, new horizon — when the channel is still current but its entry is about to go stale. Every entry expires, so a channel nobody refreshes stops verifying on its own; that is deliberate, and this is the verb that says “still good” without republishing the release. |
python3 publisher/vexa_channel.py revoke | publisher | Withdraw a release or a digest from the channel by appending to its signed revocation list — or publish an EMPTY list, which is how the list goes live before it is needed. We can publish and cannot un-publish: this is the only path that stops a subscriber’s sync, and the --reason is what their operator reads when it stops. |
python3 publisher/vexa_channel.py platform-chart | publisher | The same packaging act as chart, for the chart nobody outside can see: the proprietary vexa-platform chart, pinned from digests captured off a running cluster rather than off a release tag. Reach for it when what ships is an estate we operate, not an OSS release — there is no upstream tag to read pins from, so the live namespace is the source of truth and anything that cannot be pinned through values has to be declared as unpinnable, with its reason. |
python3 publisher/vexa_channel.py platform-entry | publisher | Build a channel entry for a whole platform estate — several charts, no single OSS release tag behind them. It refuses without a validation contract, because an estate with no stated scope is an estate nobody can prove anything about. What the estate is known NOT to cover goes in known_holes and rides inside the signed entry, where a subscriber reads it before they find out. |
python3 publisher/vexa_channel.py sign-images | publisher | Sign every digest in the candidate map into the channel’s signature repository. Separated from push because the signature layout — not the signature — is what the customer’s admission controller reads, and a re-signing pass must be runnable without republishing the entry. |
python3 publisher/vexa_channel.py attest | publisher | Record a signed, structured claim about a release: a station’s verdict, a soak result, anything a downstream contract can require: by name. This is how the internal channel accumulates evidence that the published channel entry is later built from. |
python3 publisher/vexa_station.py ingest | publisher | Take the station-report.yaml a customer sent back and record it under stations/<name>/ after checking it is complete, self-consistent and free of plaintext secrets. Until a station is ingested we cannot gate a release against it, so an un-ingested report is an un-represented customer. |
python3 publisher/vexa_station.py gate | publisher | Ask the other half of the publish question — not “may this release exist” but “may it be published AT this station, given that station’s contract”. Renders the packaged chart with the station’s own values and refuses on any unmet require: item unless it is loudly waived in the gate report. |
python3 publisher/vexa_stations.py record-publish | publisher | Reduce a published entry into channels/<channel>/channel.yaml. You rarely type this: vexa-channel push --ledger calls it, so the ledger cannot drift from the act it records. Reach for it directly only to seed a channel from an entry that was published before the ledger existed. |
python3 publisher/vexa_stations.py record-ingest | publisher | Reduce an already-ingested station directory into its state.yaml and store its receipt. Also rarely typed directly — vexa-station ingest --ledger calls it — but it is how you backfill a station that was ingested before the ledger, without asking the customer to send the report again. |
python3 publisher/vexa_stations.py pin | publisher | Move a station’s pin: the promotion. This is the one write to channel.yaml a human makes, and it refuses to run without a justification, because a promotion with no stated reason is indistinguishable in history from a slip. |
python3 publisher/vexa_stations.py show | publisher | Read the whole ledger in one screen: every channel’s sequence and current entry, and every station’s pin, observed position, last verdict and flags. The fastest answer to “which customers are behind, and on what”. |
python3 publisher/vexa_subscriber.py list | publisher | Show every account on the channel registry and its scope. The first thing to run when a customer reports a 401, and the inventory you reconcile against before a rotation. |
python3 publisher/vexa_subscriber.py add | publisher | Mint a credential for an account — the same verb rotates an existing one. Onboarding a new subscriber and rotating a compromised one are the same act against the registry, and both end with an age-encrypted handoff. |
python3 publisher/vexa_subscriber.py revoke | publisher | Remove an account’s credential. Use it when a pilot ends or a credential is suspected: revocation stops future pulls, it does not un-deliver what the subscriber already has. |
kit/release.sh | publisher | Publish a new signed version of the customer kit itself to the channel. The kit is delivered the same way the product is — bootstrapped tree, cosign signature, latest tag — so shipping a kit fix is a release, not an email with a tarball. |
python3 kit/preflight/vexa_preflight.py | customer | Run before the first sync and before every upgrade, to answer “will this cluster run what the channel delivers” while there is still time to fix the answer. Every check is anchored to a failure seen in a real customer cluster; the first sync is the wrong moment to discover a taint. |
python3 kit/smoke/vexa_smoke.py | customer | Run after an install or an upgrade to prove the release worked HERE: the pods that should be running are, and — with --flows — a bot joined a real meeting and produced transcript segments. The receipt it writes is what turns “it synced” into “it works”. |
python3 kit/validate/vexa_validate.py | customer | The one command an operator runs end to end: preflight, optionally install, smoke, then write it all into one secret-free station-report.yaml you read before you send it. Reach for it at onboarding and at every upgrade you want a receipt for; reach for the individual tools only when you are debugging one leg of it. |
python3 kit/report/vexa_state_report.py | customer | Run it FIRST on a deployment that already exists. It is a read-only kubectl get sweep of one namespace — no database connection, no pods/exec, no credentials of any kind, no SQL — and it writes one commented YAML file describing the shape of that environment: platform and version, how the database and transcription are wired, per-container resources against the namespace’s quotas and LimitRanges, the image digests actually running, the settings you have customised, where your images come from, the taints on your nodes and where each workload is pinned, how the estate is exposed (Ingress and, on OpenShift, Route), what your namespace’s Pod Security labels and NetworkPolicies will let run, and the name of the release already installed. The few questions no read-only call can answer — whether a pull by digest succeeds, whether your egress policy lets DNS out — are asked by name rather than assumed. Start with --dry-run, which connects to nothing and prints every command it would run. It prints a path and stops: nothing transmits. |
kit/bootstrap.sh | customer | The first command a new station ever runs: fetch the kit tree from the channel and verify its signature against the channel public key and nothing else. Everything the operator does afterwards comes from a tree whose provenance was checked before it was trusted. |
kit/install.sh | customer | Install the station itself — the Argo subscription that follows a channel position, plus the admission policy that pins the channel key. Prod gets an Application only when you set --prod-pin, because moving that pin is the operator’s gate and not ours to pre-press. |
kit/self-update.sh | customer | Move an already-bootstrapped kit tree to a newer kit version, checked against the key recorded in the tree at bootstrap. --check reports what an update would do and changes nothing, which is the form to use before an upgrade window rather than during one. |