Skip to content

Commit 4c2e90f

Browse files
committed
chore(release): v0.3.0 - Verification Context v1.0 + attestation trust boundary
Version bumps: pyproject, sonar.projectVersion, __version__ -> 0.3.0. CHANGELOG: [Unreleased] finalized as [0.3.0]; adds the admission-semantics bullet (VERIFIED admits only with a cryptographically valid bound attestation; placeholder tokens now BLOCK) and new runtime dependencies (pyjwt, cryptography). README: all three stale presence-only attestation statements updated to the shipped cryptographic reality; NetworkGuard usage example extended with the full mint flow (verify -> to_diagnostic -> mint_diagnostic_attestation -> to_verification_context) and verified runnable end-to-end; roadmap restructured with v0.3.0 as current and the deferred Docker/K8s/Azure items moved to Next. 513 tests pass; docs+version-only release prep.
1 parent 128746f commit 4c2e90f

5 files changed

Lines changed: 30 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
# Changelog
22

3-
## [Unreleased]
3+
## [0.3.0] - 2026-08-24
44

55
### Added
66
- Verification Context v1.0 across all four guards (tracker #36) — every guard now exposes `to_verification_context()`, producing a schema-valid, tamper-evident VC document (claim, verifier identity, `sha256`-bound evidence `proof_ref`, ADMIT/DENY admission):
77
- IamGuard (#38, PR #45), NetworkGuard (#39, PR #46), CostGuard (#40, PR #48), ArtifactBoundaryGuard (#41, PR #50)
88
- Shared bridge module `verification_context_bridge` (#37, PR #44): diagnostic → VC document conversion with fail-closed attestation policy and decision-status demotion
99
- Conformance suite `tests/test_vc_conformance.py` (#42, PR #52) — bridge + all guards + document validation + malformed-input fail-closed acceptance tests
1010
- README: "Verification Context v1.0" section — why VC, usage examples, downstream integration guide; VC badge in the header
11+
- **Attestation trust boundary (#47, PR #54)** — new `qwed_infra/attestation.py`: ES256 (ECDSA P-256) JWT attestation service with ephemeral key lifecycle auditing, revocation registry, and the never-None fail-closed `AttestationResult` contract; `enforce_trust_decision()` in diagnostics.py as the single consumption-side gate validating signature/issuer/expiry/revocation plus claim bindings (status match, `query_hash == sha256(formal_statement)`, `proof_hash == diagnostic proof_ref`)
12+
- `mint_diagnostic_attestation()` — issues a token bound to a diagnostic's own evidence commitment
1113

1214
### Changed
13-
- **BREAKING (pre-1.0, unreleased API):** guard adapters no longer accept pre-computed result objects. `to_verification_context()` takes **raw verification inputs** and runs the guard's own deterministic solver internally (`NetworkGuard.to_verification_context(resources, source, destination, port, ...)` / `IamGuard.to_verification_context(policy, action, resource, context, ...)` / `CostGuard.to_verification_context(resources, budget_monthly, ...)` / `ArtifactBoundaryGuard.to_verification_context(package_dir, ...)`) — a result-accepting signature is forgeable (a caller could fabricate a positive result and mint ADMIT), so it was removed before any release (PRs #45/#46/#48/#50)
15+
- **BREAKING (pre-1.0, unreleased API):** guard adapters no longer accept pre-computed result objects. `to_verification_context()` takes **raw verification inputs** and runs the guard's own deterministic solver internally (`NetworkGuard.to_verification_context(resources, source, destination, port, ...)` / `IamGuard.to_verification_context(policy, action, resource, context=None, ...)` / `CostGuard.to_verification_context(resources, budget_monthly, ...)` / `ArtifactBoundaryGuard.to_verification_context(package_dir, ...)`) — a result-accepting signature is forgeable (a caller could fabricate a positive result and mint ADMIT), so it was removed before any release (PRs #45/#46/#48/#50)
16+
- **ADMISSION SEMANTICS:** `VERIFIED` results now admit **only** with a cryptographically valid attestation bound to the exact claim and evidence. Arbitrary non-empty attestation strings no longer grant ADMIT (they are rejected as forged tokens); a missing token demotes VERIFIED to UNVERIFIABLE/DENY. Callers previously passing placeholder tokens must mint via `create_verification_attestation()` / `mint_diagnostic_attestation()`
17+
- New runtime dependencies: `pyjwt>=2.8.0,!=2.12.1`, `cryptography>=41.0.0`
1418

1519
### Fixed
1620
- Fail-closed on malformed inputs at every VC boundary: undecimal budgets, extreme Decimal values, non-string build backends, malformed topology/policy/package inputs, symlink escapes/loops, wheel entries outside the scanned boundary — all map to BLOCKED/DENY documents instead of exceptions or guessed approval (#48, #49/PR #51, #50)

README.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,15 @@ A `True/False` return value is enough for one process — but CI/CD pipelines, r
203203
| Lives only in your process log | JSON-serializable, schema-validated, evidence-bound (`sha256` proof_ref computed over the exact evidence) |
204204
| No story when someone asks "who verified this?" | `proof.verifier`, `audit_trace`, and rule IDs answer it |
205205

206-
The document is **fail-closed by construction**: anything that is not proven is `DENY``UNVERIFIABLE` and `BLOCKED` outcomes can never produce `ADMIT`. Note that in v1.0 the attestation token is checked for **presence only** — cryptographic validation (signature/issuer/expiry/claim binding) lands with #47.
206+
The document is **fail-closed by construction**: anything that is not proven is `DENY``UNVERIFIABLE` and `BLOCKED` outcomes can never produce `ADMIT`. Attestations are **cryptographically validated** (ES256 signature, issuer, expiry, revocation) and bound to the exact claim and evidence (`query_hash`, `proof_hash`) — a token minted for one statement can never admit another.
207207

208208
### Usage
209209

210210
Each guard runs its own verification internally and returns a VC document. You pass raw inputs — never a pre-computed result object:
211211

212212
```python
213213
from qwed_infra import NetworkGuard
214+
from qwed_infra.attestation import mint_diagnostic_attestation
214215

215216
net = NetworkGuard()
216217
infra = {
@@ -223,15 +224,26 @@ infra = {
223224
},
224225
}
225226

227+
statement = "Traffic from internet to subnet-web on port 80 is safe"
228+
229+
# Mint an attestation bound to THIS claim + evidence (the guard computes the
230+
# same check internally; the token's proof_hash must match its commitment).
231+
diagnostic = NetworkGuard.to_diagnostic(
232+
net.verify_reachability(infra, "internet", "subnet-web", 80)
233+
)
234+
attestation = mint_diagnostic_attestation(
235+
diagnostic, engine="NetworkGuard", query=statement
236+
)
237+
226238
doc = net.to_verification_context(
227239
infra, # raw topology — the guard verifies this itself
228240
"internet",
229241
"subnet-web",
230242
80,
231-
formal_statement="Traffic from internet to subnet-web on port 80 is safe",
232-
# optional; v1.0 checks PRESENCE only (any non-empty string). Without it,
233-
# VERIFIED degrades to UNVERIFIABLE. Cryptographic validation: #47.
234-
attestation_token="my-release-attestation-v1",
243+
formal_statement=statement,
244+
# optional; without it VERIFIED degrades to UNVERIFIABLE/DENY.
245+
# A forged, expired, revoked, or non-matching token BLOCKS.
246+
attestation_token=attestation.token,
235247
)
236248

237249
print(doc.verdict.value) # -> VERIFIED / BLOCKED / UNVERIFIABLE
@@ -276,7 +288,7 @@ else:
276288

277289
Store or forward `document` anywhere JSON goes — release gates, pipeline artifacts, audit logs. The `proof_ref` binds a VERIFIED decision to the exact evidence that produced it. VC evidence can contain sensitive infrastructure, policy, or cost data — apply your own access control, redaction, and retention rules when storing or forwarding documents downstream.
278290

279-
> **Roadmap (#47):** today the attestation token is checked for **presence only**; cryptographic validation and claim binding (signature, issuer, expiry, digest binding à la `enforce_trust_decision`) land with the attestation trust boundary milestone.
291+
> **Attestation trust model:** attestations are self-signed by the guard process (ES256, ephemeral key) and cryptographically validated at the admission boundary — signature, issuer, expiry, revocation, plus binding to the exact claim and evidence. This is the interim stage on the path to an external witness/transparency log (ADR-005 in qwed-verification); multi-replica deployments require shared signing keys until replica-key resolution exists.
280292
281293
---
282294

@@ -296,8 +308,9 @@ A: We use public On-Demand pricing for "Worst Case" estimation. If you have Ente
296308
## 🗺️ Roadmap
297309

298310
***v0.1.0:** IAM Z3 Logic, Basic Network Graph, Static Cost Catalog. (Released Jan 2025)
299-
***v0.2.0:** Fail-closed parser + IAM, NetworkGuard CIDR fix, CI fail-open removal, diagnostic port (audit.py/InfraDiagnosticResult), CostGuard Decimal/unknown types, ArtifactBoundaryGuard. (Current)
300-
* 🔮 **v0.3.0:** Docker/deployment artifact verification, K8s manifest support, Azure provider.
311+
***v0.2.0:** Fail-closed parser + IAM, NetworkGuard CIDR fix, CI fail-open removal, diagnostic port (audit.py/InfraDiagnosticResult), CostGuard Decimal/unknown types, ArtifactBoundaryGuard.
312+
***v0.3.0:** Verification Context v1.0 across all four guards (bridge, `to_verification_context()` adapters, conformance suite) + attestation trust boundary — ES256-signed receipts bound to the exact claim and evidence gate every ADMIT. (Current)
313+
* 🔮 Next: Docker/deployment artifact verification, K8s manifest support, Azure provider.
301314

302315
---
303316

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "qwed-infra"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
description = "Deterministic Verification for Infrastructure as Code (IaC) using Z3 and Graph Theory."
55
authors = [
66
{name = "QWED Team", email = "rahul@qwedai.com"},

qwed_infra/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.2.0"
1+
__version__ = "0.3.0"
22

33
from .guards.iam_guard import IamGuard
44
from .guards.network_guard import NetworkGuard

sonar-project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ sonar.projectKey=QWED-AI_qwed-infra
22
sonar.organization=qwed-ai
33

44
sonar.projectName=QWED Infra
5-
sonar.projectVersion=0.2.0
5+
sonar.projectVersion=0.3.0
66

77
# Source directories
88
sonar.sources=qwed_infra

0 commit comments

Comments
 (0)