Releases: agentrust-io/weight-custody-manifest
Release list
WCM 0.28.2
WCM 0.28.2 adds a conformance vector format for captures taken from real vendor silicon, and lets a manifest require hardware-reported platform state before the key broker releases a key.
Vendor vectors (kind: vendor, #116). The existing quote vectors use a synthetic PKI. A vendor vector names its root by the SHA-256 of the root's DER, carries the leaf and intermediates inline, and declares which binding its REPORT_DATA asserts. The runner derives six refusal mutations from every accepting capture, so a capture cannot arrive with only a happy path. validity.not_after is derived from the chain and a mismatch is refused (#127). schema/wcm-vendor-vector-v1.schema.json publishes the same rules for implementations in other languages. No captures are committed under the kind yet.
Platform state (#120). snp.py parses PLATFORM_INFO at offset 0x40. The new optional release_policy.platform_integrity can require alias_check_complete (AMD-SB-3015) and ciphertext_hiding, and the KBS denies with a reason naming the bit. Existing manifests keep a byte-identical signing pre-image.
Corrections to SPEC.md 3.6. The Azure SEV-SNP CVM this SDK validates against reports PLATFORM_INFO = 0x25 with ciphertext hiding clear, so it does not meet WCM's own precondition for the semi-trusted-operator claim. The GPU relay path and the description of per-device revocation are corrected too, and new threat T1.9 records the alias-check control and its time-of-check limit.
NVIDIA. NvidiaCcProvider ran end to end on a live H200 in CC mode inside an Intel TDX guest, with a wrong nonce, a tampered body and a stripped chain each refused. The path is now recorded as validated.
Publication (#114). Publishing checks the release tag, SDK version and main-branch ancestry, and scans the source tree and built archives. CodeQL now covers Python and GitHub Actions.
Thanks to Zoheb Shaik for the H200 session, the report-stability measurements, and the not_after fix in #129.
Validation: all ten required checks passed on the release PR (#133). Locally, with #129 merged, 713 tests passed and 4 were skipped, and a freshly built wheel passed all 91 reference conformance vectors. These checks do not establish production readiness or additional hardware assurance.
python -m pip install weight-custody-manifest==0.28.2WCM 0.28.1
WCM 0.28.1 fixes SEV-SNP report verification when the VCEK certificate is signed by an RSA-PSS issuer. Report verification now uses ECDSA P-384/SHA-384 independently of the certificate issuer's signature parameters. Unsupported combinations return a failed verification result.
Thanks to Zoheb Shaik for reporting the defect and supplying the SEV-SNP hardware reproduction used to confirm it.
The reference JSON parser defaults to ECDSA/SHA-256. Configure another supported report profile explicitly; issuer metadata no longer selects the report algorithm.
This release also restores public Source, Issues and Changelog package links, fixes documentation publishing, and removes a device-identifying receipt from the current repository tree. Earlier Git history is unchanged. The original receipt is retained outside the public distribution, and its pinned test skips when unavailable.
Validation on the release PR: 643 tests passed, four skipped, 92.77% coverage; all ten CI checks passed. The built wheel and source archive passed metadata checks. A fresh wheel installation passed all 91 reference conformance vectors. These checks do not establish production readiness or additional hardware assurance.
Install after publication:
python -m pip install weight-custody-manifest==0.28.1v0.28.0
Supersedes 0.27.0.
Evidence. Protected-runtime evidence captured on a real Azure SEV-SNP confidential VM (Standard_DC2ads_v5, AMD EPYC 7763), closing #78 and #79. The memory-fingerprint sweep ran over 256 MB of SEV-SNP-encrypted guest DRAM at 65536 pages, with the challenge nonce derived from a live vTPM attestation report so the sweep is bound to that guest. Both negatives were exercised on the same hardware. Guarantee scope is unchanged: a sweep inside the guest cannot observe a DDR interposer outside it, and SPEC.md 3.6 still says so.
Packaging and controls. A leak scan now runs in CI on every push, pull request and published release, matching identifier shapes rather than a list of known strings. Internal infrastructure identifiers were removed from two test-fixture documents, and the one pinned hardware receipt that cannot be edited without breaking its SHA-256 integrity pin is now excluded from the sdist instead, so the pin keeps working in the repository and the identifier is not published.
CI. Public demos run against the wheel the branch would actually ship. The leak scan's allowlist now matches on Windows, where it previously failed a clean tree with eleven false findings.
Full notes in CHANGELOG.md.
v0.27.0
[sdk] Added wcm.artifact_digest, the deterministic content digest for a
model artifact on disk, named wcm-artifact-digest/v1. SPEC.md takes
weights_hash as given and says nothing about how a directory of shards,
indexes and tokenizer assets collapses into one value, so every consumer
invented it: the same construction already existed in three places outside this
repository with nothing keeping them in step. A recipe that exists several times
does not stay one recipe, and when the copies drift the mismatch presents as
weights_hash not matching, which reads as tampered weights.
This is a convention rather than specification, and RECIPE_ID says so: a
deployment computing weights_hash another way is not non-conforming, it simply
must not expect this function to agree. Symlinks are refused by default, which
the prior copies did not do, because following one lets a digest cover bytes
outside the artifact and lets those bytes change without anything in the
artifact changing.
[hardware/azure] Corrected Azure vTPM measured-launch verification against
real Standard_DC2as_v5 hardware. TPM quote pcrDigest is the SHA-256 of the
selected PCR values, so the single-PCR policy requires a second hash over PCR
23's reset-and-extend value. Added a sanitized, reproducible capture tool.
[compatibility/azure] Kept the positive-serial certificate policy as the
default while allowing Azure's THIM-provided AMD VCEK leaf through an explicit,
provider-local compatibility path. Other provider certificates still fail
closed on non-positive serial numbers.
[security/kbs] Key release now requires the complete authority-layer manifest
identity to be pinned out of band. Without it a caller could present an
attacker-authored policy that reused a weights hash the broker already held, and
be released against terms nobody agreed. Servers built from the environment must
load explicit trusted manifest identities, and the gate is carried into signed
renewal decisions rather than being a release-time check a renewal could route
around. (#98)
[sdk/runtime] Added wcm.runtime_records: Ed25519-signed, hash-chained
custody records with contiguous sequence enforcement, so a protected runtime can
produce a portable receipt for its own lease lifecycle rather than a log line
anybody could write. RuntimeEvent covers lease start, renewal, lapse,
revocation, wipe request, wipe completion and process termination. (#94)
[sdk/runtime] Added wcm.memory_sweep: a signed protected-memory sweep that
writes unpredictable nonce-derived data across every page of a declared range and
reads them back in a distinct nonce-derived order, so a controlled alias mapping
of the kind a BadRAM-class attack produces is detectable. The algorithm is
implemented and tested; protected-boundary hardware evidence remains open
(issue #79), and LIMITATIONS.md is unchanged on that point. (#95)
[hardware/azure] The Azure provider now resets application-owned PCR 23 and
extends it exactly once with the canonical manifest-approved SHA-256
serving-image digest before each release attempt, closing the repository-side
half of measured launch. (#93)
[security/attestation] Bound the Azure vTPM SHA-256 PCR 23 value to the
manifest-approved workload measurement, with coverage for wrong state, wrong
measurement, malformed digest and absent policy. Defined a deterministic
fail-closed RFC 5280 policy for non-positive certificate serial numbers; CI
exercises both cryptography 50's real warning path and a simulated cryptography
51 load-time exception, and the runtime dependency stays capped below the
unreleased 51. (#92)
[packaging] Every project URL on PyPI now resolves for an anonymous reader.
0.26.0 shipped four links that 404 while this repository is private, which PyPI
renders as live regardless. (#100)
[tests] TDX missing-device coverage no longer depends on the host running the
suite, so the fail-closed assertion still holds on a machine with real Intel TDX
hardware. (#102)
WCM 0.26.0
Changelog
Notable changes to the Weight Custody Manifest specification and Python SDK.
Format loosely follows Keep a Changelog; the SDK
uses semantic-ish versioning while pre-1.0.
Unreleased
No changes yet.
0.26.0 - 2026-08-21
[security/sdk] Added EnclaveSession.authorize_operation() for long-lived
confidential runtimes to enforce the existing lease and operation budget without
exporting another key copy on every inference. use_key() now delegates to the
same authorization path, preserving its existing operation-count semantics.
[security/renewal] Added short-lived signed KBS renewal decisions. The
initial release pins the renewal signer; a fresh decision binds the model,
signed manifest, consumed challenge, complete evidence, gate results, and
validity window without returning a model key. EnclaveSession.apply_renewal()
verifies and consumes the decision once before resetting cadence and operation
budgets.
[hardware/validation] Added a sanitized paired CPU/GPU validation record and
reproducible release runner covering Azure SEV-SNP/vTPM and NVIDIA H100 evidence.
The record is portable and offline-verifiable; it does not include provider
tokens or raw attestation secrets.
[security/verification] Bound Azure vTPM provider selection and paired
hardware receipts to the validated evidence path, with negative coverage for
changed workload state, substituted transport, and missing GPU evidence.
[release] Added the guarded public-release preflight, public launch checklist,
reproducible release BOM tooling, current package metadata, and refreshed KBS
dependency locks.
0.25.0 - 2026-08-12
[security/kbs] The environment-built network KBS now fails closed when a
cryptographic CPU quote verifier/trust root is not configured. Health and
challenge issuance remain available, but release cannot silently downgrade to
structural CPU evidence. A private GCP boundary validation caught the gap and
confirmed replay, transport-key substitution, and unapproved-image refusal after
the fix.
[hardware/sdk] Added live-derived Linux SEV-SNP and TDX provider fixes,
fail-closed NVIDIA NVAT evidence adaptation, and Azure SNP→HCL runtime→HCL
attestation-key→fresh vTPM quote verification with nonce/transport binding.
[operations] Added read-only partner-node preflight, unified happy/negative
readiness receipts, and a single fail-closed final-launch command with evidence
redaction, JSON validation, deterministic inventory hashing, and explicit
hardware-claim boundaries.
[security/sdk] Raised the runtime cryptography floor to 50.0, excluding
the vulnerable 49.x releases reported by pip-audit while retaining the
existing upper bound for the current major-version compatibility contract.
[security/ci] Pinned every GitHub Actions dependency, including the PyPI
trusted-publishing action, to an immutable commit. This prevents a mutable tag
from changing the code executed by the release or documentation deployment
workflow without a reviewable repository change.
[spec/sdk] Normative manifest JSON Schema, frozen at v1
(schema/wcm-manifest-v1.schema.json, $id
https://wcm.agentrust-io.com/schema/manifest/v1.json). Until now the manifest
existed only as prose in SPEC.md §3.1 plus the Pydantic reference model, so a
third-party implementer had nothing machine-readable to validate against. The
structural half is generated from the model (python/tools/gen_schema.py, with a
--check mode CI runs, so the committed file cannot drift); the four cross-field
rules the model enforces in validators are hand-carried as if/then blocks.
Ships inside the wheel, so wcm.schema.manifest_schema() works from an installed
package. Adds a shared vector corpus at conformance/vectors/manifest/ (24
language-neutral accept/reject cases) that tests/test_schema.py runs against
both the schema and the model, asserting they agree.
Frozen means additive-only: fields and enum values may be added, but nothing is
removed, renamed, made required, narrowed, or repurposed inside v1, and a
breaking change would publish .../manifest/v2.json alongside rather than edit
v1. That is a deliberate trade, since the spec itself is still pre-1.0: an
implementer gets a stable target now, and anything the spec grows into arrives as
an addition. manifest_version stays unconstrained; it versions the manifest
instance under the issuing builder's scheme, not the schema.
Honest gap, documented not papered over: one model constraint,
derived_from != weights_hash, is not expressible in standard JSON Schema, which
cannot compare the values at two instance locations. It stays a verifier-side
check. It is recorded in schema/README.md, carried as a negative vector marked
schema_expressible: false, and asserted directly in the tests, so a
schema-only implementation cannot pass by delegating everything to the schema and
removing the model validator cannot make the parity test go quietly green. No new
runtime dependency: wcm.schema returns the schema document and leaves
validation to the caller (jsonschema is a dev-only test dependency).
[build] The reference KBS image is now bit-for-bit reproducible, and CI
tests it rather than documenting it as an operator step. kbs_image.measurement
is only worth pinning in a manifest if an independent party can arrive at the same
value, and until now the Dockerfile took the base image by tag and pinned only
direct dependencies, so it could not.
- Base image pinned by digest (
BASE_DIGEST), with a new Dependabotdocker
ecosystem entry to move it, since a digest pin does not pick up security updates
on its own. - Fully hash-locked dependencies.
docker/constraints.txt(3 direct pins) is
replaced bydocker/requirements.lock(22 pins, the full transitive closure)
anddocker/requirements-build.lock, both installed with
pip --require-hashes. Each pin lists every artifact PyPI publishes for that
version, so the lock is not tied to one wheel tag. Regenerate with
python tools/gen_kbs_lock.py(--checkfor staleness), which resolves for the
image's platform rather than the host's, and frompyproject.toml's own declared
requirements, so a pin cannot violate what the package says it supports. - No unpinned fetch anywhere in the build. The wheel is built in a discarded
builder stage with--no-build-isolationagainst the locked build set, then
installed--no-deps --no-index. CI assertsimport hatchlingfails in the
runtime image. - mtimes normalized to
SOURCE_DATE_EPOCHinside each layer that writes
files, because pip and hatchling stamp build time into what they write. Scoped
to the paths the build touches; a blanketfind /would copy every base-image
file up into the final layer. pip --no-compile. pip byte-compiles by default and a.pycembeds the
source mtime, so normalizing mtimes afterwards leaves bytecode holding the old
value: reproducible-looking sources over irreproducible bytecode.
PYTHONDONTWRITEBYTECODEdoes not cover it, since it governs the interpreter
rather than pip's compile pass.docker/verify-reproducible.sh, run by CI and runnable locally: builds
twice (the second with--no-cache) and compares the two images' exported
filesystem content, every entry's type, permissions and path plus a sha256 of
every regular file, then prints a stable content digest. Content rather than
layer digests, because BuildKit stamps a build-time mtime onto the destination
directory entry aCOPYcreates, which no in-image normalization can reach, so
layer comparison fails on metadata noise that says nothing about what the image
contains. Verified: two independent builds produce byte-identical content across
5,948 files.
Scope stated precisely in python/docs/reproducible-kbs-image.md: this proves
the build does not depend on when it ran, on cached layers, or on what a resolver
would have picked that day. All three of those actually broke the check while it
was being written, which is the argument for having it. It does not prove
cross-machine reproducibility, since both builds share one runner, one Docker
version, and one checkout. The honest claim is reproducible under a fixed builder
with every content input pinned; verifying across independent builders belongs to
whoever certifies a deployment.
[spec/sdk] Conformance suite (conformance/) so an independent
implementation can be checked against the same inputs the reference is, in any
language. Four levels matching the four layers, WCM-* error codes
(conformance/codes.md), 91 language-neutral JSON vectors, and a runner exposed
as wcm conformance that both self-tests this SDK and scores another
implementation's results file. Ships in the wheel, so it works from
pip install weight-custody-manifest.
Three rules make a pass mean something: every valid input must be accepted (an
over-strict implementation fails too), every invalid one must be rejected for
the declared code (so "reject everything" cannot pass), and a vector with no
reported result counts as a failure (so a partial submission cannot claim a
level). All three are tested directly, with deliberate cheating attempts.
All four levels are vectored, 91 vectors. L1 (manifest and joint signature,
32) and L4 (derivative lineage, 10) ask questions about documents. L2
(attestation-gated release, 37) and L3 (runtime custody, 12) ask what a system does
over time, so their vectors are ordered scenarios: the clock is supplied by
the vector and moves only on an explicit advance_clock step, and nonces are
generated by the implementation and bound to names that later steps reference, since
a nonce must be unp...
WCM 0.25.0
WCM 0.25.0 publishes the accumulated schema/conformance work plus live-derived SEV-SNP, TDX, NVIDIA NVAT, and Azure SNP-vTPM integrations. The network KBS now fails closed without cryptographic CPU verification, and the release adds partner preflight, one-command launch validation, deterministic evidence inventories, and explicit hardware-claim boundaries.
Validated with 520 tests and zero skips in the release environment. The release workflow builds and publishes fresh artifacts through PyPI Trusted Publishing.
v0.24.0
chore(release): 0.24.0 (#65)
Bumps version to 0.24.0 and adds the SDK changelog entry covering the frozen v1 manifest JSON Schema, the conformance suite (91 vectors, all four levels), the retire_after parsing fix, and the bit-for-bit reproducible KBS image.
No breaking API changes. Verified from a clean venv against the built wheel; twine check passes on both artifacts. The tag and GitHub Release remain the Project Lead's step.
v0.23.0
CLI: expose the full stack from the terminal.
New wcm subcommands: verify-quote (verify a captured SEV-SNP / TDX / NVIDIA H100 CC quote against the vendor roots), verify-provenance (the OpenSSF model-signing interop), gate (a release-policy diagnostic with clear pass/fail per check), and inspect (a manifest at a glance). So pip install weight-custody-manifest now gives you a terminal that can verify real hardware quotes and sanity-check a manifest, not just keygen/sign/verify.
Verified against the committed real-silicon fixtures. No new dependency for the core; verify-provenance uses the [model-signing] extra. Also refreshed the roadmap to reflect the validated SEV-SNP + TDX + H100 CC matrix. See CHANGELOG 0.23.0.
v0.22.1
Packaging fix: repoint the PyPI project URLs to public, live surfaces (the runnable examples catalog) while the spec/SDK repo is private, so the PyPI page has no dead links. No code change. See CHANGELOG 0.22.1.
v0.22.0
NVIDIA H100 confidential-GPU verification, validated on real silicon.
wcm.nvidia now verifies a real NVIDIA H100 CC attestation offline: the device certificate chain to NVIDIA's Device Identity CA root, the ECDSA P-384 / SHA-384 report signature by the attestation leaf key, and the raw-nonce binding. Confirmed against a genuine attestation captured from a live Standard_NCC40ads_H100_v5 (H100 NVL, CC mode on), committed as a test fixture that verifies offline. This drops the earlier PROVISIONAL status: the SEV-SNP + Intel TDX + NVIDIA H100 CC matrix is now validated on real silicon.
Honest scope unchanged: a physically-extracted attestation key still produces a genuinely-valid signature (open question 8.8); this raises the bar to a real hardware signature, it does not defeat a hardware owner.
See CHANGELOG 0.22.0 and SPEC v0.15.