Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,51 @@ jobs:
- name: Install dependencies
run: python -m pip install --upgrade pip setuptools && pip install -e ".[dev]"

- name: Force cryptography past agt-core's stale cap
# agt-core 4.1.0 declares cryptography>=46.0.7,<49.0, so a plain resolve
# lands on 48.0.1, which carries two advisories REACHABLE from our TPM
# chain verification (CVE-2026-69249, CVE-2026-69248). Both are fixed in
# 49.0.0.
#
# The cap is not load-bearing: #471 records a clean-venv run of agt-core
# 4.1.0 against cryptography 49.0.0 with the full suite passing (1041) and
# CedarBackend evaluating unchanged. So this installs over the declared
# constraint deliberately, and pip's dependency-conflict warning is
# expected. Suppressing the two advisories instead was considered and
# rejected: they reach real code paths, and a security product should not
# silence those to get a green tick.
#
# HONEST LIMIT: this fixes what CI tests, not what users get. Until
# agt-core 4.1.1 ships the cap lift
# (microsoft/agent-governance-toolkit#3614), `pip install cmcp` still
# resolves cryptography 48.x for everyone else. Delete this step and take
# `cryptography>=49.0` in pyproject.toml the moment 4.1.1 is on PyPI.
# Tracked in #471.
run: |
pip install --upgrade "cryptography>=49,<50"
python -c "import cryptography; print('cryptography', cryptography.__version__)"

- name: Security scan
run: pip install bandit pip-audit && bandit -r src/ -c pyproject.toml && pip-audit
# --skip-editable: pip-audit resolves the editable install of this package
# against PyPI and fails when the version is not published yet, so without
# it no version-bump PR can ever pass CI. Dependencies are still audited.
#
# --ignore-vuln CVE-2026-69247: unreachable here, and it is the only one
# suppressed. It is a Bleichenbacher oracle in PKCS#7 EnvelopedData
# *decryption*, and nothing in this package decrypts PKCS#7. The only use is
# load_der_pkcs7_certificates / load_pem_pkcs7_certificates in tee/tpm.py,
# parsing a certificate bundle fetched from an AIA URL, which performs no
# RSA decryption.
#
# Deliberately NOT suppressed: CVE-2026-69249 and CVE-2026-69248, both
# reachable through the untrusted cert_chain a claim carries into
# verify_ak_ek_chain / verify_vcek_chain. Do not add them here to go green.
# They are not suppressed and they do not need to be: the step above
# installs cryptography 49, which fixes both, so this passes because the
# vulnerability is gone rather than because the report is muted. If that
# step is ever removed before agt-core 4.1.1 ships, this goes red again,
# which is the correct behaviour.
run: pip install bandit pip-audit && bandit -r src/ -c pyproject.toml && pip-audit --skip-editable --ignore-vuln CVE-2026-69247

- name: Lint
run: ruff check src/ tests/
Expand Down
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **BREAKING for verifiers: claims now carry `gateway.attestation_evidence` (#469, #370).** Signed platform
evidence (`raw_evidence`, `quote_signature`, `cert_chain`, `ek_cert_chain`) travels inside the claim so the
verifier has something to check the TPM quote against. It could not live under `trace.runtime`, because
agentrust-trace's `RuntimeInfo` is `extra="forbid"` and rejected the claim as `CLAIM_MALFORMED` before the
platform branch ran, which is precisely what kept the chain verifiers unreachable.

The break is one-directional, and only for verifiers:

| | result |
|---|---|
| this verifier reading an older claim with no evidence | fine, the fields are optional and `trace.runtime` is still read as a fallback |
| a verifier older than 0.4.0 reading a claim from this gateway | `CLAIM_MALFORMED` on `gateway.attestation_evidence` |

`GatewayAddenda` and `RuntimeClaim` are both `extra="forbid"`, so any additive field anywhere in the claim is
rejected by a verifier built before it, and `verify_trace_claim` never reads `cmcp_version`. There is no
negotiation path, so "evidence travels with the claim" and "older verifiers keep working" cannot both hold.
Evidence transport won, since without it the TPM quote is unauthenticated. Anyone verifying claims from a
0.4.0 gateway must upgrade `cmcp-runtime` to 0.4.0, which is what ships `cmcp_verify`. Claims with no
evidence serialize byte-identically to 0.3.0, so software-only deployments are unaffected.

Minor rather than patch under SemVer: the wire format gained a field that older readers reject.

### Fixed

- **`TPM2_NV_Certify` could never have worked as shipped in #459 (hardware, 2026-08-01).** Two defects, both found by running it against a real Azure Trusted Launch vTPM and neither catchable by the unit tests as written:
Expand Down
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "cmcp-runtime"
version = "0.3.0"
version = "0.4.0"
description = "Hardware-attested MCP runtime, TEE-enforced policy and TRACE Claim generation"
readme = "README.md"
license = { text = "MIT" }
Expand Down Expand Up @@ -32,6 +32,11 @@ dependencies = [
# declaring ML-DSA-65 or hybrid crashed the verifier with an uncaught
# RuntimeError on any install without the optional [pq] extra.
"agent-manifest>=0.10",
# Cannot be raised past 48.x today, which leaves two reachable advisories
# unfixed. See #471: agent-governance-toolkit-core 4.x pins
# cryptography<49.0, and the only release that allows 49 (5.0.0) pins
# agentrust-trace<0.3.0 against the >=0.5 this package needs. Raising the
# floor here makes the dependency set unsatisfiable rather than secure.
"cryptography>=42.0",
"pyyaml>=6.0",
"httpx>=0.27",
Expand Down
2 changes: 1 addition & 1 deletion src/cmcp_runtime/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""cMCP Runtime: hardware-attested MCP runtime."""

__version__ = "0.3.0"
__version__ = "0.4.0"