Releases: Polycentric-Labs/evidentia
Release list
v0.11.0
Highlights
Theme: The federal wave — three verified federal firsts on machine-readable rails. v0.11.0 ships the re-cut Wave 1-2 scope of the v0.11 plan: FedRAMP CR26 Security Decision Record emission — evidentia conmon ksi emits the SDR keySecurityIndicators block (10 families / 46 KSIs) conformant to FedRAMP's official 2026-06-24 schemas, vendored at pinned upstream SHAs (re-verified at the schemas' 1.0.0 graduation) and drift-watched weekly — the first production-grade open-source emitter of the CR26 SDR format, and the first from any established tool; OMB M-25-21 minimum-practice tracking — structured per-practice status for the memo's seven §4(b) practices with CAIO waiver objects carrying the annual re-certification and 30-day OMB-report clocks, structure the federal AI Use Case Inventory lacks entirely; and OMB M-25-22 acquisition-lifecycle tracking — Evidentia's first procurement surface, modeling the memo's six §4 phases as auditable records with the §4(a) high-impact determination tie-in. The cycle's OSCAL 1.2.1 → 1.2.2 evaluation closed with a ratified DEFER-WITH-TRIGGER verdict (emitted documents stay on 1.2.1; adoption triggers armed), and a pre-release claim-accuracy sweep re-verified every public claim against primary sources (parity restated at the live 93.4%; machine-gated counts; first-mover registry updated with explicit caveats). Test suite: 4,947 passed; mypy strict clean; ruff clean.
Deferred (ratified v0.12 plan re-cut, 2026-07-18 — see docs/releases/plans/v0.12-plan.md): Wave 4 phase 3 (EU-AI-Act ↔ ISO 42001 crosswalk) → v0.12-if-capacity; Wave 4 phases 1/2/4, Wave 3 DORA, and the medical-device traceability enrichment → v1.1; Waves 5-6 (OpenVEX/VSA, SARIF collector, auto-review) → post-1.0; arXiv preprint timing = open decision. The GUI parity pass for the five federal api-only verbs leads v0.12.
Changed
-
FedRAMP CR26 vendored schemas re-synced to the upstream 1.0.0 graduation (#198)
(FedRAMP/schemas@ae0dc43e, 2026-07-15 — caught by a manual drift probe
inside the weekly sentinel's blind window): the Security Decision Record
schema's$schemaVersionmoved 0.1.0 → 1.0.0, fixing the Public-Preview
draft's vacuousitemswrapper nesting so the per-KSI constraints now
actually enforce — constraintsevidentia conmon ksioutput already
satisfies (emitted documents re-validated against upstream 1.0.0, zero
emitter changes).fedramp-common-definitionsre-vendored byte-identical at
0.1.1;UPSTREAM.jsonpins refreshed (all 11 tracked$schemaVersions).
The documented one-line cross-document$refdelta is retained — upstream
fix PR #4 remains unmerged; the 1.0.0 graduation did not include it. -
Claim-accuracy sweep across the public docs (#197) (pre-v0.11.0; every change
traced to the 2026-07-15 primary-source verification pass): CLI↔GUI parity
claims recomputed from the manifest (98% → 93.4%, 99 full / 7 api-only /
0 cli-only — README badge,parity-coverage.mdregenerated, positioning,
enterprise-grade, ROADMAP); count drift fixed to the machine-gated truths
(96 catalogs / 16 crosswalks / 14 collectors / 13 MCP tools / 4,900+ tests);
the FedRAMP first-mover registry row updated to the shippedconmon ksi
verb + CR26 SDR schema framing with explicit caveats, and two new
first-mover rows registered (M-25-21 practice/waiver-clock tracking,
M-25-22 acquisition lifecycle); the CISA SbD Pledge described as an
alignment self-attestation everywhere (never a signatory claim; formal
signing planned at v1.0); OSCAL-MCP landscape statements aligned to "one
of several" (CISO Assistantca_mcp+ trestle-mcp exist); the stale
"Sept 30 2026 FedRAMP mandate" framing replaced with CR26 FRC-CSO-JSN
(mandatory 2027-01-01) + NTC-0009 (2027-11-01, Class D High,
format-agnostic — never an "OSCAL mandate"); the unverifiable "18 months
ahead" claim removed; GovReady-Q described as dormant, not defunct;
OpenVEX / VSA rows moved to planned-tense with no version commitment; the
federal-SI walk-through refreshed (M-25-21 primary lens consistently,
M-26-05 rescission of the M-22-18 self-attestation form, the v0.11
federal-wave surfaces added, resolved limitations pruned).
Fixed
- Pre-tag review hardening of the Wave-2 federal surfaces (found by the
v0.11.0/pre-release-reviewsecurity fan-out, fixed before tag):
ai-gov set-high-impactno longer silently discards recorded M-25-21
practice status + CAIO waiver provenance when a later call amends the
determination's bases/rationale — the practices are carried forward per the
model's retention contract (API + CLI; regression tests on both surfaces).
conmon ksinow rejects duplicate KSI indicator keys in the status file
(previously last-wins-merged, silently dropping a block from the emitted
SDR — while still honoring legal YAML merge keys), warns when a
--state-fileanchor keys a cadence slug that matches no
bundled cadence (its dates would otherwise be silently absent), and writes
--outatomically with a clean error contract instead of a raw traceback on
a missing/unwritable path.PracticeWaiver.issued_byand
AIAcquisition.linked_system_idgained themax_lengthbound every sibling
string field already carries.
Added
-
OMB M-25-22 AI acquisition-lifecycle tracking —
evidentia ai-gov acquisition(#196) (v0.11 Wave 2; spec ratified 2026-07-14, lifecycle phases
verified verbatim against the memo text): Evidentia's first procurement
surface.AIAcquisitionrecords track a procurement through the six §4
phases (Identification of Requirements → Market Research & Planning →
Solicitation Development → Selection and Award → Contract Administration
→ Contract Closeout) with status-only per-phase records (M-25-22 defines
no waiver mechanism) and carry the §4(a) initial likely-high-impact
determination in M-25-21 vocabulary plus an optional AI-registry link
(acquisitions may precede registration).AIAcquisitionStoreclones the
registry-store pattern (UUID filenames, traversal guard, atomic writes,
trusted-directory boundary,EVIDENTIA_AI_ACQUISITION_DIR).
CLIai-gov acquisition register|list|show|set-phase+ API mirror under
/api/ai-gov/acquisitions(parityapi-onlypending the next GUI pass);
acquisition_progress()roll-up never fabricates a status for an
unrecorded phase;AI_ACQUISITION_REGISTERED/
AI_ACQUISITION_PHASE_RECORDEDaudit events. -
OMB M-25-21 minimum-practice tracking —
evidentia ai-gov set-practice
(#195) (v0.11 Wave 2): fills the per-practice extension point reserved at
v0.10.12.OMBHighImpactAssessmentgains structured status for the seven
§4(b) minimum risk-management practices (practice headings verified
against the memo text), each recordable as implemented / in_progress /
not_started / waived — waived requires a §4(a)(ii) CAIO waiver
record (written determination, granting official, annual
re-certification date, 30-day OMB report date), enforced by a model
validator.practice_compliance()rolls up recorded / missing /
satisfied without ever inventing a status for an unrecorded practice;
waiver_certification_due()/waiver_omb_report_overdue()evaluate the
memo's two waiver clocks. Ships as CLI verb + API mirror
(POST /api/ai-gov/systems/{id}/set-practice, parityapi-onlypending
the next GUI pass) +AI_SYSTEM_PRACTICE_RECORDEDaudit event. Persisted
v0.10.12-era assessments load unchanged (the field defaults to empty —
reported as missing, never as satisfied). -
FedRAMP CR26 KSI emission —
evidentia conmon ksi(#194) (v0.11 Wave 2,
target re-verified against the live CR26 stack + ratified 2026-07-14; see
the plan's §Wave 2 re-base record): emits thekeySecurityIndicators
block of a CR26 Security Decision Record as a standalone JSON
document, validated OFFLINE against
fedramp-security-decision-record-schema-2026-06-24.jsonbefore writing
(rules SDR-CSO-FRR / SDR-CSX-KSI / SDR-CSO-MTD; in force for 20x since
2026-07-04). Ships with:- the
fedramp-ksi-2026bundled catalog (10 families / 46 Key
Security Indicators, generated verbatim fromFedRAMP/rules
fedramp-consolidated-rules.jsonat a pinned commit by
scripts/catalogs/gen_fedramp_ksi.py,--checkdrift mode included)
plus a KSI→NIST 800-53 Rev 5 crosswalk extracted from the upstream
per-indicatorcontrolsdeclarations (base-control granularity;
enhancement citations preserved verbatim in notes); - vendored CR26 schemas under
evidentia_core/fedramp/schemas/with
full provenance pins (UPSTREAM.json) and one documented local delta:
upstream publishes every cross-document$refwith the JSON Pointer in
the URI path, which no conforming JSON Schema 2020-12 validator can
resolve (FedRAMP/schemas#3; fix PR #4 unmerged) — the vendored copy
moves the pointer into the fragment; - CONMON cadence integration:
persistence_cyclesentries in the
operator's KSI status file render the SDR-CSX-KSI "cycle for measures
implemented persistently" statements from the same cadence calendar the
rest ofevidentia conmonruns on (last-completed / next-due dates via
--state-file); - the
fedramp-schema-watchweekly sentinel (Wed 09:17 UTC):
compares liveFedRAMP/rules+FedRAMP/schemasagainst the
UPSTREAM.json pins — NOTICE drift opens/updates a tracking issue; a KSI
content change, MAJOR$schemaVersionbump, or a new dated ruleset
(CR27) also reds the run. Both upstream repos are 2026 Public Preview
drafts with same-day churn observed at vendor time — the pins rot
without a watcher. - Operator doc:
docs/fedramp-ksi.md.jsonschema+referencing
promoted from transitive to directevidentia-coredependencies...
- the
v0.10.18
Highlights
Theme: Container rebuild on a fresh hardened base (day-N CVE response). A rebuild-only patch fired by the post-publish rescan's fixable-only gate: the 2026-07-13 weekly rescan of the published v0.10.17 image surfaced DEBIAN-CVE-2026-34743 (xz-utils/liblzma 5.8.1-1, Medium 5.3) with a fix published upstream (5.8.1-1+deb13u1), and the standing policy is "a fix is now available → rebuild the published image on a fresh base". Both pinned bases move to their current digests (the same drift the base-freshness sentinel flagged in issue #182) and the image is rebuilt, smoke-tested, re-signed, and re-attested end-to-end; the post-publish rescan re-verifies the published image's CVE posture after release. This tag also ships everything that merged to main between v0.10.17 and the tag: the v0.11 cycle-open gate work (ROADMAP-currency gate + ROADMAP restructure, previously tracked as Unreleased) and the entire v0.11 hygiene track (H1–H6, below) — the hygiene PRs merged ahead of the tag, so the v0.11 plan's release boundary re-cuts to v0.11.0 = Waves 1–2. No package (packages/*/src) code changes beyond the version bump.
Added
- ROADMAP-currency gate (
scripts/check_roadmap_currency.py) — the
roadmap's status headings must agree with the CHANGELOG's shipped
## [X.Y.Z]blocks: nothing PLANNED/RESERVED that has shipped, no SHIPPED
entries inside a PLANNED cycle umbrella, exactly one open cycle, and the
open cycle must link an on-disk plan doc (plus an advisory that every
release in the latest cycle has its entry). CHANGELOG blocks are the
source of truth — deliberately not git tags, which the shallow CI checkout
cannot see and which unpublished ghost tags would poison. Runs in the
requiredconsistencyscope and the pre-push hook, and was observed
firing on the real v0.10.x roadmap drift (four shipped releases
mis-marked PLANNED) before the tree was fixed. Two prose currency anchors
registered alongside it (the deprecation-calendar closing line and the
enterprise-grade maintenance-summary claim), so those live lines now
force-update on every version bump and hard-fail when stale. Recorded as
lesson 11 indocs/engineering-practices.md: a doc's currency claim is
a gate or it is a lie.
Added (v0.11 hygiene track — H1–H6, merged ahead of this tag)
- H2 —
dependency-review.yml: GitHub-native diff-level dependency gate on
every PR (actions/dependency-review-actionv5.0.0, SHA-pinned,
fail-on-severity: low) — blocks a PR introducing a known-vulnerable
dependency before it lands in a lockfile. - H3 —
verify-recipes.yml: the published consumer-verification recipes
(PEP 740 wheel attestations, cosign signature + SLSA provenance,
gh attestation verify, SBOM download + osv-scan) now run weekly against
the latest Release with coverage assertions (8/8 wheels) and a recipe-drift
guard coupling the workflow todocs/verification.md. Its dry-run already
fixed real doc rot: the SBOM recipe moves off the deprecated
osv-scanner scan --sbomform toscan source -L. - H4 — release-SBOM enrichment + NTIA gate (
enrich_release_sbom.py+
check_sbom_ntia.py, wired intorelease.ymland active in THIS release's
build): the release-asset SBOM gainsmetadata.supplier/authorsand
first-party supplier/publisher/purl identity (osv-scanner previously
skipped all 8evidentia*components — "Neither CPE nor PURL found"), then
an NTIA minimum-elements gate fails the build if the SBOM is structurally
present but useless. Observed firing with 18 findings on the real v0.10.17
SBOM before the enrichment. - H5 —
uv-pilot-watch.yml: weekly graduation sentinel for theuv audit
/UV_MALWARE_CHECKpreview pilots (functional no-preview-flag probe + uv
CHANGELOG stabilization scan; detect-and-nudge, never a gate). - H6 — four small deferrals: #18 changelog-vs-commits advisory diff (in
verify-changelog.yml, always-exit-0);security-insights.ymlCI-validated
against the official OpenSSF v2.2.0 CUE schema (cue vet, vendored
byte-identical schema — the gate fired on a real missing required
rulesetsfield, fixed honestly); demo-image pyyaml hash-pin
(--require-hashes);cflite-batch.yml60-minute runtime cap. - Wave 1 OSCAL 1.2.2 verdict recorded (ROADMAP + v0.11 plan):
DEFER-WITH-TRIGGER — emitted documents stay on OSCAL 1.2.1 (the 1.2.2
schema delta is byte-identical for every emitted surface, while
compliance-trestle v4.2.0 hard-rejectsoscal-version: 1.2.2); plus fixes
for live docs still claiming the POA&M emitter produces OSCAL 1.1.2 (false
since v0.9.6).
Changed
- Emitted CycloneDX SBOMs move 1.6 → 1.7 (H1) across all four emission
sites (release asset, post-publish rescan, SSOT osv gate,
PEP 770 per-wheel SBOMs), with the pinned osv-scanner bumped
v2.3.8 → v2.4.0 at all six install sites — v2.3.8 rejects CycloneDX 1.7
("invalid specification version"), a break the local full gate suite caught
before it could ship; v2.4.0 verified against the repo's exact SSOT
invocation. The gap-analyzer CycloneDX VEX emitter deliberately stays
1.6 (a product schema surface, moving only with its own review). - setuptools floated to 83.0.0 (PYSEC-2026-3447, Medium 6.1, published
2026-07-14 — the fixable-means-upgrade policy applied same-day), floating
torch 2.11.0 → 2.13.0 + triton in the dev closure; two osv allowlist
entries whose documented removal triggers fired were removed
(GHSA-rrmf-rvhw-rf47: torch 2.13.0 exits the advisory's last_affected
2.12.0; PYSEC-2025-183: the disputed pyjwt advisory was bounded upstream to
last_affected 2.10.1, below the locked 2.13.0). - Container base digests refreshed (day-N CVE rebuild) — the
dhi.io/python:3.13distroless runtime pin moves
b41747df…→1842a6b9…, and thepython:3.13-slimbuilder pin moves
c33f0bc4…→eb43ff12…in lockstep across its four sites (the main
Dockerfile, the demo Dockerfile'sassetsstage, and the two
interpreter-paritypip-compilerunner pins inrelease.yml/
container-build.yml). Fired by the post-publish rescan's fixable-only
policy on DEBIAN-CVE-2026-34743; the 28 unfixable base-OS advisories
remain notify-only per that policy, and the rescan re-verifies the
published image after this release. The fresh DHI digest also
restructured the base's python layout (/opt/python→ the standard
/usr/bin+/usr/lib/python3.13) — caught by the PR's container gate
(exec /opt/venv/bin/evidentia: no such file or directory),
CI-probe-verified against the exact pinned digest, and fixed by repointing
thevenv-fixstage's interpreter symlinks +pyvenv.cfgat/usr. - ROADMAP restructured at the v0.11 cycle open — the v0.10.x line is
closed SHIPPED (16 published releases), the four mis-marked entries
(v0.10.5 / v0.10.9 / v0.10.11 / v0.10.12) are corrected to SHIPPED, the
four missing entries (v0.10.10 / v0.10.13 / v0.10.16 / v0.10.17) are
backfilled, and v0.11 is promoted to the open cycle linking its plan doc
(docs/releases/plans/v0.11-plan.md, ratified 2026-07-09).
docs/enterprise-grade.md's header is restructured so its live currency
claim sits on a single anchorable line. The quarterly safeguards-resweep
issue template gains a practice-delta item (method recorded in
docs/engineering-practices.md§Research rigor).
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.18"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.18
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See docs/sigstore-quickstart.md
for the full verification narrative + supply-chain framing.
CHANGELOG
Full changelog (every release): CHANGELOG.md
Container image
ghcr.io/polycentric-labs/evidentia:v0.10.18ghcr.io/polycentric-labs/evidentia:latest- Digest:
sha256:a4bbf2b382c1d5a806bfe0ef525ab7d6a455ec9466ed2c0f6644d008e63da531
Verify (cosign keyless OIDC):
cosign verify ghcr.io/polycentric-labs/evidentia:v0.10.18 \
--certificate-identity-regexp 'https://github\.com/Polycentric-Labs/evidentia/\.github/workflows/release\.yml@refs/tags/v.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'Verify (SLSA build provenance):
gh attestation verify oci://ghcr.io/polycentric-labs/evidentia:v0.10.18 \
-R Polycentric-Labs/evidentiaSee docs/sigstore-quickstart.md
for the full verification narrative.
v0.10.17
Highlights
Theme: v0.10.x hardening close-out. The final v0.10.x release, completing the Horizon-A elite-engineering-practice arc. Lands a publish-safe release-pipeline preflight dry-run — a workflow_dispatch that runs the full build/validate path (gate + wheels + per-package SBOMs + reproducible double-build + container-from-local-wheels + smoke tests) but is structurally unable to publish (the publish jobs require github.event_name == 'push') — backed by v*-tag-only PyPI/GHCR deployment environments with required-reviewer approval, so a real release now pauses for an explicit deployment sign-off. Also: two real audit-logger security fixes surfaced by an adversarial review of the CodeQL 2.26.0 findings (CWE-117 log CR/LF injection + CWE-312 cleartext credential in an exception field); the dead CodeQL .qll path-injection sanitizer pack replaced with a Models-as-Data barrierModel extension (honestly dismissal-managed until the stock query consumes it); the Tier-1 demo image reworked to a shell-free distroless multi-stage build; CodSpeed perf reporting activated; CI job timeout caps; and a refreshed distroless base digest. No package API changes.
Added
- Release-pipeline preflight dry-run —
release.ymlnow accepts a manual
workflow_dispatchthat runs the full pre-publish path (the SSOT gate suite +
wheels + per-package SBOMs + the reproducible-build double-build + the
container-built-from-local-wheels + the image smoke tests) without publishing,
so the failure classes that previously surfaced only at tag time (a base/dep
regression, auvxexit-127, apip-compilehash mismatch — the v0.10.14 /
v0.10.15 ghost-tag failures) can be caught on-demand before a tag is cut
(gh workflow run release.yml --ref main). The dry-run is structurally incapable
of publishing:tag-guardand both publish jobs requiregithub.event_name == 'push', so a dispatch — even one selected on av*tag ref — yields
publishable=falseandpublish-pypi/publish-containerskip. As a second,
platform-level belt thepypiandghcrdeployment environments are restricted
tov*tag refs with required reviewers, so a real release now also pauses
for an explicit deployment approval. Seedocs/release-checklist.mdStep 5.6.
Changed
timeout-minutescaps added to thedastandcodspeedjobs — the two
observe-first suites added this cycle ran open-ended (schemathesis stateful
fuzzing and CodSpeed Valgrind instrumentation), so a pathological path or a hung
upload could tie up a runner indefinitely. Both now carry an explicit cap (dast
30 min, codspeed 20 min), mirroringmutmut.yml's existing cap on the other
heavy suite.docker/Dockerfile.demoreworked to a shell-free multi-stage build — the
Tier-1 hosted-demo image (the real CLI behind an argv allowlist) now builds its
final stage FROM the distroless signed release base withCOPY+ENV+USER- exec-form
ENTRYPOINTonly — noRUN, no/bin/sh. All the build-time shell
work (vendoringpyyaml) moved to apython:3.13-slimassetsbuilder stage,
and the launcher + namespace shim are now committed files (docker/demo/) rather
thanprintf-generated. It drops privileges to the distroless nonroot uid
65532 (numeric — nouseradd), replacing the pre-DHIUSER evidentia
(uid 1000) assumption that broke on the distroless migration. Runtime behavior is
unchanged (still refuses a raw shell / off-allowlist argv, forced--offline,
credential-empty); locally smoke-validated with--build-arg BASE=python:3.13-slim.
- exec-form
- Refreshed the DHI runtime base image digest — the pinned
dhi.io/python:3.13base advanced tosha256:b41747df…, picking up the
latest Docker Hardened Images patches; the release rebuilds on the fresh
base (closes the base-freshness sentinel nudge, issue #143). DocumentationURL repointed to the owned docs domain — the
evidentiapackage's project URL now points athttps://docs.evidentiagrc.com
(the published docs site on an owned domain) instead of an un-owned host.- Content currency — added the OMB M-24-10 → M-25-21 deprecation row to
the deprecation calendar; refreshed the enterprise-grade maintenance
summary through v0.10.16; de-dangled a stale cross-reference in the
v0.9.1 security-review backfill.
Fixed
- CodSpeed perf-regression pilot now reports — added the
mode: simulation
input that CodSpeed Action v4 now requires (the Valgrind instruction-counting
instrument for standard GitHub-hosted runners; without it the step errored out
before ever benchmarking, and step-levelcontinue-on-errorsilently masked
it as green). With the repo now registered on codspeed.io, the job benchmarks
tests/benchmarks/and reports per-PR perf deltas via the CodSpeed dashboard
and PR comment.continue-on-errorstays at the step level so a transient
CodSpeed upload/outage remains non-blocking (observe-first); the
perf-regression signal comes from the PR comment, not from failing the check.
Security
- Audit log CR/LF injection + credential leakage hardened
(evidentia_core.audit.logger). Two defects surfaced by an
adversarial review of CodeQL 2.26.0 findings: (1) CWE-117 — in the
default (non-JSON) logging mode the message is rendered verbatim by
the stdlib formatter, so attacker-controlled CR/LF (e.g. aMetric
nameviaPOST /api/governance/metrics) could forge log lines;
the plaintext-rendered message now escapes newlines. (2) CWE-312 —
the secret scrubber covered only the free-textmessage, leaving a
credential inlined in an exception string (error.message = str(exc)) in cleartext in the structured record; theerrorfield's
string values are now scrubbed too. Structured JSON emission was
already newline-safe viajson.dumpsand is unchanged.
Fixed
- CodeQL custom path-injection sanitizer pack removed (never loaded)
— thevalidate_within/resolve_catalog_pathpy/path-injection
false-positive class was held down by per-instance dismissals because
the custom.qllsanitizer pack never loaded:packs:accepts only
published registry specs (a local path was logged as "Invalid CodeQL
pack specification" and ignored), and an external library pack cannot
inject a barrier into a stock query anyway. Replaced with a
Models-as-DatabarrierModelextension (loaded via the config's
dataExtensions:key, which does resolve cleanly). NOTE:
py/path-injectiondoes not yet consume MaDbarrierModel, so the
model is a forward-looking hook and this FP class remains
dismissal-managed for now. - Unauthenticated 500 on
POST /api/ai-gov/register— a
whitespace-onlyprovider/ownerpassed the request model's raw
min_lengthbut failed the whitespace-stripping registry model,
raising an uncaughtValidationError. Now normalized to a structured
400, matching the sibling update handler. Found by the new DAST work.
Added
- CodSpeed performance-regression gate (non-required, observe-first) —
apytest-codspeedmicro-benchmark suite (tests/benchmarks/, excluded
from the default collection) over the hot paths fromdocs/benchmarks.md:
gap analysis (1 + 2 frameworks), catalog load, report serialization, and
two API request paths (health + gap-reports). A newcodspeed.yml
workflow runs them under CodSpeed's instruction-counting runner and
reports per-PR perf deltas.continue-on-errorand not a required check;
it lands inert until the repo is registered on codspeed.io (free OSS
tier), then activates with no further change. uvsupply-chain pilots (non-required, observe-first) — two uv
preview features run intest.ymlas second opinions to the
authoritativeosv-scannerSBOM gate, bothcontinue-on-errorso they
never block a merge: auv auditadvisory scan, and a
UV_MALWARE_CHECK=1sync that queries OSV MAL advisories for the locked
closure (a resolution-time tripwire for known-malicious packages). The
malware check runs in its own non-required job rather than on the
required sync steps while the feature is in preview.- Stateful DAST suite +
dast.ymlsentinel — a schemathesis
state-machine test (tests/dast/test_openapi_stateful.py) walks
create→read→update→delete link chains over the ai-gov and catalog
lifecycles (hunting IDOR / state-leak / stale-reference /
sequence-dependent 5xx classes that stateless per-operation fuzzing
cannot reach), complementing the existing stateless
test_openapi_fuzz.py. A new non-requireddast.ymlworkflow runs
both on a weekly cron, manual dispatch, and API-surface PRs
(observe-first; not a merge gate). - DAST-driven API schema + error-contract hardening — several
fixes surfaced while building the stateful-DAST harness: OpenAPI
linkson the ai-gov register→get/put/delete and catalog
import→delete lifecycles;UpdateSystemRequest's
at-least-one-field rule mirrored into the published schema (anyOf);
a non-whitespacepatternon the AI-system descriptor
name/purposeso the schema matches the strip+min_length
runtime; thesystem_idUUID shape documented on the lifecycle ops;
and an app-wide handler normalizing FastAPI's hardcoded body-decode
400 to the structuredErrorEnvelopeshape every other deliberate
error already carries. EvidenceReftwo-mode contract in the published schema — the
at-least-one-of (artifact_id,file_path) andfile_path→sha256
business rules, previously enforced only by a Pydantic model validator,
are now mirrored into the OpenAPI component viajson_schema_extra
(top-levelanyOf+if/then). Closes a DASTRejectedPositiveData
finding onPOST /api/model-risk/models(schema-valid-but-422 bodies) and
tightens the generated UI types.- PEP 770 per-wheel SBOMs — every published wh...
v0.10.16
Highlights
Theme: Engineering hardening + distroless container base — never ship a failed test again. Bundles the accumulated supply-chain work into one release: cryptography-native DSSE/in-toto air-gap signing, the atomic (validate-before-publish) release pipeline, and the migration of the published container onto a distroless Docker Hardened Images base (nonroot uid 65532; no shell, curl, or gpg). No package API changes. (The 0.10.14 and 0.10.15 tags were created but never published — in both cases the atomic release's validate-before-publish design stopped anything from shipping. 0.10.14's build caught a non-reproducible container-requirements-hash issue; 0.10.15 fixed that, built and validated everything, then failed pre-upload on a missing uv install in the restructured publish job's twine check — the publish jobs' first-ever live execution, since they cannot run in PR CI. 0.10.16 is the same release content plus both pipeline fixes.)
Added
- Cryptography-native air-gap signing via DSSE/in-toto — a binary-free,
network-free signing path that works inside distroless and minimal-base
containers (evidentia_core.oscal.keysign). Operators pass a PEM/PKCS#8
Ed25519 or RSA private key via--sign-with-keyonevidentia gap analyze
andevidentia traceability emit; Evidentia writes a.dsse.jsonsidecar
(DSSE envelope carrying an in-toto Statement v1, signed with Ed25519 or
RSA-PSS-SHA-256). Verify withevidentia oscal verify <artifact> --verify-key <pubkey.pem> --require-signature(fail-closed; pinned key
required). Encrypted private keys are supported via the
EVIDENTIA_SIGNING_KEY_PASSPHRASEenv var (never a CLI flag). The API and
MCP surfaces accept the signed artifacts for verification; the UI console
verifies and emits unsigned (artifact signing remains an air-gap CLI
operation). This path is the recommended signing method for air-gapped
deployments and distroless containers where thegpgbinary is absent. docs/engineering-practices.md— a public account of the engineering safeguard stack (PR-flow + merge queue, atomic releases, SLSA provenance + cosign + SBOM + OIDC publishing, continuous fuzzing + Scorecard + CodeQL, verified docs) and the candid failure classes that shaped each safeguard.- Security posture documents.
docs/SECURE-BY-DESIGN-PLEDGE.md(voluntary alignment with the CISA Secure by Design Pledge's seven goals),docs/slsa-source-track.md(an honest SLSA v1.2 Source Track self-assessment — the L3 technical controls are enforced and verifiable, the L4 two-party-review gap disclosed),docs/runbooks/ghsa-cve-issuance.mdanddocs/runbooks/release-rollback.md(maintainer runbooks for GHSA + CVE issuance via GitHub-as-CNA and for release rollback/yank per PEP 592), and a rootsecurity-insights.yml(OpenSSF Security Insights v2.2.0 manifest). All linked fromSECURITY.md.
Changed
- PR-flow + merge queue on
main. A repository ruleset now requires a pull request, the full set of status checks, and a squash merge queue, with an empty bypass list — no direct push tomain, including by administrators. This reverses the prior direct-push model so the complete CI matrix gates every change before it lands, not after. Every workflow producing a required check gained amerge_grouptrigger (paths-filtered workflows do not run onmerge_group, so the container smoke test instead always runs with a step-level relevance early-exit). - Atomic release.
release.ymlbuilds and validates all artifacts — wheels, SBOM, and the container image (built from the locally-built wheels, not the package index) — before the irreversible PyPI publish, then pushes the byte-identical validated image. This closes the post-publish container-build-failure class (the v0.10.12 packages-only release) and the index-propagation race. The Dockerfile is now multi-stage with anINSTALL_SOURCEbuild argument; the operator default (install from PyPI) is unchanged. - Container base migrated to Docker Hardened Images. The published image now rides a distroless
dhi.io/python:3.13runtime (nonroot uid 65532, home/home/nonroot) built via a multi-stagepython:3.13-slimbuilder that installs the hash-pinned closure into a venv — dropping the shell,curl, andgpgbinaries from the runtime. Air-gap evidence signing inside the container uses the binary-free DSSE path (above); the GPG-emit code path fails closed (GPGNotAvailableError) when nogpgbinary is present, and Sigstore stays online-only. The healthcheck is reimplemented in pure Python (nocurl). Becausecryptographybecame a direct core dependency with the DSSE signing path, the container closure now resolvescryptography49.0.0 (≥48.0.1 — so GHSA-537c-gmf6-5ccf is fixed in the shipped image, not merely allowlisted). Honest framing: the win is post-exploitation attack-surface reduction plus keeping the fixable-rescan gate green, not a raw CVE-count cut (the distroless base still carries unfixable advisories, and removingcurlis not egress denial — Pythonsocket/urllibremain). A scheduled base-image freshness sentinel opens a tracking issue when the DHI base digest drifts or the published image ages past 90 days, so the day-N clock is reset by an ordinary rebuild-and-release rather than left to the rescan alone. NOT Alpine (musl breaks the manylinux AI/crypto wheels). - The container smoke test is now a required check. Restructured to run on every pull request with a relevance early-exit, so it reports success on changes that do not touch the container while still building whenever the Dockerfile or its inputs change — which is what lets it be required without blocking unrelated PRs.
- Required-check concurrency. The four required-check workflows (
test,consistency,container-build,secret-scan) now cancel in-progress runs only onpull_requestevents;push:[main]andmerge_groupruns always run to a green conclusion, so everymaincommit earns its own completed required check (no spurious cancelled runs on rapid back-to-back merges). - Post-publish container rescan gates on fixable advisories. The scheduled rescan of the published container image (
post-publish-rescan.yml) no longer goes permanently red on day-N base-OS CVEs that have no upstream fix — the chronically-red-gate failure class the doctrine forbids (an osv-scanner dispatch on the published image reports 81 advisories, only 4 fixable).osv-scannerhas no native fixable gate and exits non-zero on any advisory, so the job now captures the scan as JSON and a committed, unit-tested policy step (scripts/check_osv_fixable.py) fails only when a detected advisory has an applicable fix for the detected package — matched on the package's own ecosystem and name (exact down to the Debian release suffix), so a fix in an unrelated release that merely shares the CVE does not count (matching any shared-CVE affected entry would instead flag 110 of the 248 raw vulnerability records, not 4). Unfixable base-OS CVEs are notify-only, rendered in full to the run job-summary; the scan step fails closed on any osv-scanner exit code other than 0/1 (so a partial or errored scan that writes an empty result cannot be mistaken for a clean image), and a missing or malformed report is rejected too. The gate is expected to fire on the current published image until its 4 fixable advisories are cleared by a rebuild. The JSON schema and the fixable determination were verified empirically against realosv-scannerv2.3.8 output on the published image and captured as a committed regression fixture. The PyPI-closure rescan job is unchanged. Doctrine indocs/engineering-practices.md; the companion minimal-base-image migration that shrinks the OS-CVE surface itself ships in this release (see Container base migrated to Docker Hardened Images above).
Fixed
- Flake-resistance policy (
docs/testing-flake-policy.md) — bans wall-clock-timing assertions and treats a skipped or dead gate as a failure, after a Windows clock-granularity flake and a Hypothesis-deadline flake were eliminated.
Security
- npm registry-signature verification. The frontend CI job runs
npm audit signaturesafternpm ci, verifying installed UI tarballs against npm's registry signatures and maintainer Sigstore provenance — the JS/TS analogue of the Python side's PEP 740 attestations. - Release-tag root-of-trust protection. A server-side repository ruleset makes
refs/tags/v*append-only (no force-move, no delete, signatures required), and GitHub Immutable Releases locks published release assets and tags — so the cosign certificate-identity binding on a signed tag cannot be silently broken after publish.
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.16"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.16
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See docs/sigstore-quickstart.md
for the full verification narrative + supply-chain framing.
CHANGELOG
Full changelog (every release): CHANGELOG.md
Container image
ghcr.io/polycentric-labs/evidentia:v0.10.16ghcr.io/polycentric-labs/evidentia:latest- Digest:
sha256:52a8df7ee2d2c2a1afaff82d65e8b9f2e1b7e410bf03a57e956de7432d037c35
Verify (cosign keyless OIDC):
cosign verify ghcr.io/polycentric-labs/evide...v0.10.13
Highlights
Theme: Patch — restore the container base to Python 3.13. v0.10.12 published to PyPI successfully, but its container image failed to build: the base had been bumped to python:3.14-slim, which the AI stack (litellm, requires-python <3.14) cannot resolve. This patch reverts the base to python:3.13-slim so the published container is complete and CVE-clean. The Python packages are otherwise identical to 0.10.12.
Fixed
- Container base reverted to
python:3.13-slimafter a Dependabot bump (#83) topython:3.14-slimbrokerelease.yml's container build. The 3.14 base contradicted the Dockerfile's own guard comment —litellmdeclaresrequires-python <3.14, so on a 3.14 base the resolver caps atlitellm 1.83.7(which carries CVE-2026-40217, HIGH) and the regenerated CVE-clean pin (litellm1.89.x) is uninstallable; the container build failed only after the PyPI publish had already succeeded. Re-pinned topython:3.13-slim@sha256:c33f0bc…(the current 3.13-slim digest), realigning theFROMline with its own guard comment so the container resolves the CVE-clean AI stack. This regression surfaced the same cycle the patch/minor Dependabot auto-merge was removed in favour of human review — it is exactly the class of unreviewed-dependency-change that review catches. - Container smoke test un-broken — the gate that should have caught the above.
container-build.yml's smoke test had silently exited at version-extraction on every push since v0.10.11: itssedforevidentia[gui]==never matched the pip-compile-normalizedevidentia==line in the perennially-stale committeddocker/requirements.txt(whichbump_version.pynever advances), so it never reached the build step. A chronically-red gate became noise that masked exactly thepython:3.14base regression above. The version is now read from PyPI's latest published release — self-correcting, with no dependency on the committed preview pin — so the smoke test builds the container on every Dockerfile change again, and an incompatible base-image bump is caught at PR/push time instead of at release.
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.13"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.13
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See docs/sigstore-quickstart.md
for the full verification narrative + supply-chain framing.
CHANGELOG
Full changelog (every release): CHANGELOG.md
Container image
ghcr.io/polycentric-labs/evidentia:v0.10.13ghcr.io/polycentric-labs/evidentia:latest- Digest:
sha256:c8c7acbf4797fd5209cc9e3383f7f4b07e01af340b1e122c7368ee39364f023c
Verify (cosign keyless OIDC):
cosign verify ghcr.io/polycentric-labs/evidentia:v0.10.13 \
--certificate-identity-regexp 'https://github\.com/Polycentric-Labs/evidentia/\.github/workflows/release\.yml@refs/tags/v.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'Verify (SLSA build provenance):
gh attestation verify oci://ghcr.io/polycentric-labs/evidentia:v0.10.13 \
-R Polycentric-Labs/evidentiaSee docs/sigstore-quickstart.md
for the full verification narrative.
v0.10.12
Highlights
Theme: v0.10.12 — full CLI↔GUI parity build-out + the OMB M-25-21 AI-governance migration. A feature-rich minor release: the local web console reaches ~98% CLI↔GUI parity (up from ~13% in v0.10.11), the AI-governance module migrates to current federal guidance (OMB M-25-21), and the supply-chain / security posture is hardened (continuous fuzzing, an SSRF fix, and OpenSSF Scorecard lifts).
Added
- OMB M-25-21 "high-impact AI" model — the AI-governance module now reflects current federal guidance. OMB M-24-10 (the prior basis for the rights-impacting / safety-impacting / both / neither taxonomy) was rescinded on 2025-04-03 by M-25-21 ("Accelerating Federal Use of AI through Innovation, Governance, and Public Trust"), which collapses the old split into a single "high-impact AI" category — AI whose output is a principal basis for decisions with significant effect on civil rights/liberties/privacy, access to essential services (education, housing, insurance, credit, employment), critical government resources, human health & safety, critical infrastructure, or strategic assets. New core module
evidentia_core.ai_governance.omb_m_25_21shipsHighImpactDetermination(high_impact/not_high_impact/not_assessed),HighImpactBasis(the six consequence areas), theOMBHighImpactAssessmentsub-model (determination + bases + rationale),triggers_minimum_practices(), andcrosswalk_from_legacy()(an explicit, operator-invoked old→new mapping — Evidentia never silently re-determines a persisted M-24-10 value). Surfaced as a matched CLI ↔ REST ↔ console triple —evidentia ai-gov set-high-impact <id> --determination <d> [--basis <b>]… [--rationale <t>],POST /api/ai-gov/systems/{id}/set-high-impact(RBACwrite-gated), and a "High-impact AI (OMB M-25-21)" form + display on the/ai-govconsole — plus a newomb_high_impactregistry field, theAI_SYSTEM_HIGH_IMPACT_CLASSIFIEDaudit event, and the SCR change-classifier treating anot_high_impact→high_impactescalation as transformative. Purely additive + backward-compatible: every existing M-24-10 inventory entry still loads. The seven M-25-21 minimum risk-management practices are documented this cycle; structured per-practice tracking is a v0.11 extension ofOMBHighImpactAssessment. - Full CLI↔GUI parity build-out — the local web console grows to 22 consoles at ~98% CLI↔GUI parity (up from ~13% in v0.10.11), with matched REST endpoints for every new console (governance, retention, evidence, catalog management, risk-quantify, TPRM, continuous-monitoring, model-risk, POA&M, AI-governance, OSCAL-verify, traceability, collect, integrations). The two credentialed / network-egress consoles — Collect and Integrations — surface a UI guard when no
AuthProvideris configured: aSecurityPostureBannerplus disabled run/push buttons (a convenience guard, not a server-side control — the endpoints stay open until an auth token is set, which is the real fix). Artifact signing remains an air-gap CLI operation (the consoles verify and emit unsigned only). - Init wizard write-to-disk path —
POST /api/init/commitlets the onboarding wizard write the generatedsystem-context.yaml, control inventory, and catalog index to the server's working directory (skips existing files unlessoverwrite=true, mirroringevidentia init --force).
Changed
- Web-console bundle reduced via route code-splitting — every console page is now lazy-loaded with
React.lazy+ a Suspense boundary, dropping the main chunk to 339 kB (105 kB gzip) and clearing the >500 kB build warning. - The CLI↔GUI parity gate is now bidirectional — a new inverse-completeness check requires every live OpenAPI operation to be either served by a CLI leaf or listed (with a rationale) in an
api_extraallowlist; an unclassified endpoint or a stale allowlist row fails the gate. - Audit vocabulary fully typed —
EventAction.TRACEABILITY_EMITTEDandEventAction.INTEGRATIONS_SERVICENOW_PUSHpromoted from ECS-style dotted strings to enum members (byte-identical emission; existing SIEM queries unaffected), completing the typed-EventActionrefactor. A newEventAction.RETENTION_METADATA_DELETEDdistinguishes a retention metadata delete (the RESTDELETE /retention/{id}) from a secure WORM purge, so an auditor querying the action vocabulary can no longer read a metadata delete as a secure purge. - Console accessibility (WCAG 4.1.3 Status Messages) — fetch-error cards now announce via
role="alert", async pending states viarole="status"/aria-live, and the OSCAL-verify identity hint is associated to its disabled control viaaria-describedby(12 files across the console set). - Dependency-update auto-merge removed — the v0.10.8
dependabot-automerge.ymlworkflow (which auto-enabled merge on green patch/minor Dependabot PRs) is removed and the repoallow_auto_mergesetting is disabled. Dependabot itself stays fully on — grouped update PRs, alerts, and security updates — but dependency changes are now merged deliberately, after human review, rather than automatically. For a supply-chain-integrity tool the stronger posture is that every dependency change in this repo was reviewed by a human: the xz-utils / event-stream class of compromise ships as an innocuous, green-CI patch/minor bump, which is exactly what auto-merge would have admitted unattended.
Fixed
- Evidence console empty-state hint — points operators to
evidentia evidence save(which emits the lineage id) instead of the nonexistentevidence listcommand. - Framework-ID typo in operator guides — corrected
nist-800-53-rev5-mod→ the canonicalnist-800-53-rev5-moderateacross the SARIF / OCSF-detection / gap-analysis guides (the invalid id madegap analyzeexit non-zero).
Security
- SSRF + credential-exfil guard on the Tableau publish endpoint — the request-body
server_urlis now validated throughnetwork_guard.enforce_public_host(default-on private-IP block) +pin_resolved_host(anti-DNS-rebind), with https-only enforcement, closing a path by which a caller could reach a cloud-metadata endpoint (e.g. 169.254.169.254) and exfiltrate the Tableau PAT. Configuration is validated before the report lookup. - Continuous fuzzing (ClusterFuzzLite) + a fuzz-found DoS fix — six
atherisharnesses (catalog import, OSCAL profile load/resolve, OSCAL verify, OCSF ingest, gap-report load, TPRM questionnaire) run in CI alongside cross-platform Hypothesis property tests; the first run found and fixed an uncaught-exception denial-of-service inoscal verifyon malformed back-matter. This is the OpenSSF Scorecard "Fuzzing" lift; the harnesses graduate to OSS-Fuzz unchanged. - Pre-tag review hardening —
oscal verifyis now exhaustively guarded to return a verdict (never raise) on any malformed-but-valid-JSON document, completing the fuzz-found CWE-248 fix across the wholeverify_digests+ digest-extraction chain (the robustness harness no longer swallowsTypeError, so it guards the invariant). The two open compute endpoints bound their inline inputs (risk/quantifyscenarios≤ 1000;oscal/verifycontent≤ ~8 MB). And theSecurityPostureBanner+ the web-console security model now state plainly that disabling the credentialed buttons is a UI convenience guard, not a server-side control — the API endpoints stay open untilEVIDENTIA_API_AUTH_TOKEN_FILEis set. The six full-model create endpoints (governance challenges/metrics/workflows, POA&M items, TPRM vendors, model-risk models) now return 422 rather than an unhandled 500 on a malformed clientid(a DAST-found response-contract fix), and the audit secret-scrubber additionally redacts the in-tree credential shapes it previously missed — fine-grained GitHub PATs, OpenAI/Anthropic keys, DSN-embedded passwords, and bearer tokens.
Deprecated
- The OMB M-24-10 surface —
evidentia_core.ai_governance.omb_m_24_10.OMBImpactCategory, theomb_impactregistry field, theai-gov set-omb-impactCLI/REST verb, and theAI_SYSTEM_OMB_CLASSIFIEDaudit event — after M-24-10's 2025-04-03 rescission by M-25-21. Retained and fully backward-compatible (persisted inventories still load; no behaviour change; no runtime deprecation warning). Use the M-25-21 high-impact surface for new work, andomb_m_25_21.crosswalk_from_legacyto map a legacy value forward.
Documentation
- GitHub Pages site on the owned domain — the Material-for-MkDocs documentation site is served at
docs.evidentiagrc.com(CNAME + canonicalsite_url); apages.ymlworkflow builds it undermkdocs build --strict. OpenSSF Scorecard was hardened in the same cycle (aSCORECARD_TOKENfor the branch-protection/webhooks checks; the SLSA build-provenance bundle is attached to each GitHub Release). - Operator console guides + screenshots — six new console walkthroughs, with bash and PowerShell command variants across every command-bearing guide; three new console screenshots (Collect, Integrations, Traceability); a new
web-console-security.mdconcept page documenting the standing security model forevidentia serve(inherited controls, the anonymous-by-default posture + auth-gating, per-console exposure, and a hardening checklist); and a refresh ofpositioning-and-value.md§3 to the current v0.10.12 surface. - Windows verification recipes — the canonical
docs/verification.mdnow carries the bash + PowerShell variants for every release-artifact verification recipe (PEP 740, cosign, SBOM, SLSA); the generated wiki mirror regenerates from it, so the two no longer drift.
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https...v0.10.11
Highlights
Theme: v0.10.11 — public demo completion + signed traceability + hygiene. Patch bump (v0.10.10 → v0.10.11). Finishes the public demo surface, promotes threat→control→evidence into a first-class signed capability, and clears the v0.10.10 follow-on hygiene. The full CLI↔GUI parity build-out (incl. a dedicated traceability console route) is the v0.10.12 cycle.
Added
- Signed Control↔Threat Traceability Matrix — a new
evidentia traceability emitverb produces a Sigstore-signable OSCAL profile mapping controls to the threats they mitigate. The representation was locked by a multi-model research pass (primary-source verified): a static control↔threat matrix is an OSCAL profile — NOT Assessment Results (a semantic abuse of an assessment-activity model) and NOT the OSCALmappingmodel (released in 1.2.1, but control↔control only — its source/target are catalog/profile and items are control/statement, so it cannot target a threat ID). The profile imports a control catalog and adds alink rel="mitigates"+ Evidentia-namespaced props to each control, with threats in integrity-hashedback-matter.resources[](canonical JSON + SHA-256, the same tamper-evident pattern as the gap-analysis AR exporter). It signs via the existing--sign-with-gpg/--sign-with-sigstorepath and round-trips throughevidentia oscal verify(now generalized to locate any OSCAL model's back-matter, so digests + tamper detection work on the profile too). The relationship vocabulary is a domain mitigation set (mitigates/partially-mitigates/compensating/detects), deliberately NOT NIST OLIR (which is concept-to-concept / control↔control). Threat resource UUIDs + per-mapping IDs are derived deterministically (uuid5) so re-emitting the same matrix reproduces byte-identical evidence. Shipsmodels/traceability.py,oscal/traceability_exporter.py, and an illustrative self-attested example (examples/traceability-DEMO-example.yaml). OWASP Threat-Dragon ingest, the MITRE CTID Mappings-Explorer crosswalk, and a CycloneDX representation are the v0.11 build. - OSCAL emit/verify console view (demo-gated, read-mostly). A new
#/oscalroute renders a gap run's emitted OSCAL Assessment Results — the document summary, its integrity-hashed back-matter resources, the signed artifact, and an illustrative verification panel (digests + Sigstore/Rekor + the air-gap GPG path) — by extracting a sharedSignedArtifactCard+VerificationPanel(now reused by both the FDA demo and this view). Fixture-backed; wiring it to a live run + a real verify endpoint is v0.10.12 parity. - FDA-index build mode — a
VITE_DEMO_FDA_INDEXflag rendersFdaDemoPagefull-bleed as the index (outsideAppLayout), sofdademo.evidentiagrc.comcan serve the in-repo bundle as the single source of truth, retiring the decoupled prototype fork. The build-time flag also tree-shakes the unused console routes. The mainVITE_DEMOconsole deploy config (packages/evidentia-ui/vercel.json) shipped in v0.10.10; this completes the in-repo demo surface. Deploys + domain attaches remain operator-driven (Tier-4).
Security
- Collector SSRF guard now runs before the optional driver import. The four SQL collectors (postgres / mysql / mssql / oracle) run the public-host SSRF guard (
enforce_public_host) BEFORE importing their optional driver, so a private/loopback/link-local host is refused even when the driver is not installed — the security property is now verifiable in a no-extras environment (snowflake + databricks already guarded before their SDK import). A new CIno-extrassmoke job asserts the guard with ZERO optional drivers installed, structurally backstopping the CI-vs-local extras gap that surfaced at v0.10.10. The SSRF tests are refactored to inject a fake driver module instead ofpytest.importorskip.
Fixed
MetricCardDOM nesting — the value renders in a<div>, not a<p>, so the shipped#/demo/fda"Total gaps" card (a<Badge>, which is a<div>) no longer triggers avalidateDOMNestingconsole error. Adds a regression guard.oscal sign→gap analyze --sign-with-*doc correction indocs/threat-model.md+docs/troubleshooting.md(the removed verb), landing the edits stashed during the v0.10.10 ship.- Roadmap accuracy — the v0.11 "CycloneDX TM-BOM (ECMA-424 working-group track)" line overstated maturity; verification found no ratified CycloneDX TM-BOM type exists (CycloneDX = ECMA-424, current spec v1.7; threat data rides VEX + properties), so it is reframed as a forward-looking representation.
- Demo console is labeled a partial-functionality preview ("Preview · synthetic data · partial functionality · no live backend") and the
GapExportControltest no longer trips a jsdomBlob.streamconsole error.
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.11"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.11
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See docs/sigstore-quickstart.md
for the full verification narrative + supply-chain framing.
CHANGELOG
Full changelog (every release): CHANGELOG.md
Container image
ghcr.io/polycentric-labs/evidentia:v0.10.11ghcr.io/polycentric-labs/evidentia:latest- Digest:
sha256:4ed6d4b1f1256252fa270a34bf4367ad9c9e8661f839e37e0b1eb96b42194600
Verify (cosign keyless OIDC):
cosign verify ghcr.io/polycentric-labs/evidentia:v0.10.11 \
--certificate-identity-regexp 'https://github\.com/Polycentric-Labs/evidentia/\.github/workflows/release\.yml@refs/tags/v.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'Verify (SLSA build provenance):
gh attestation verify oci://ghcr.io/polycentric-labs/evidentia:v0.10.11 \
-R Polycentric-Labs/evidentiaSee docs/sigstore-quickstart.md
for the full verification narrative.
v0.10.10
Highlights
Theme: v0.10.10 — supply-chain hardening + the public demo suite. Patch bump (v0.10.9 → v0.10.10). Closes the v0.10.9 Step-7 container findings, the post-ship Security-tab disposition, and the two product findings the Tier-1 demo threat model surfaced; and lands the in-repo artifacts for a three-tier public demo.
Added
- FDA Section 524B medical-device pack. Generic, public support for FDA premarket device cybersecurity, in four parts. (1) A real bundled catalog
fda-524b-appendix1(Tier A, the eight §V.B.1 security control categories — Authentication, Authorization, Cryptography, Code/Data/Execution Integrity, Confidentiality, Event Detection and Logging, Resiliency and Recovery, Updatability and Patchability — names verbatim from the Feb 3, 2026 guidance, characterizations in Evidentia's own words; framework count 92 → 93), reachable via CLI + API + the web console's Gap Analyze picker. (2) License-respecting stubsiso-14971+aami-sw96(placeholder + cite, no normative standard text) and two illustrative, self-attested crosswalks (fda-524b-appendix1 → iso-14971/→ aami-sw96) carrying the safety-vs-security risk-model note (ISO 14971 probability × severity vs AAMI SW96/TIR57 exploitability × severity on a shared patient-harm severity axis; 93 → 95). (3) A demo-only web-console route#/demo/fda(registered only in theVITE_DEMO=truebuild, inside the normal layout — the landing is untouched) that runs a synthetic, banner-labeled 524B gap analysis with zero backend, traces each STRIDE device threat → 524B control → verification test, and ends on an illustrative signed-evidence artifact, plus a synthetic display-fixtureexamples/fda-524b-DEMO-example-assessment.oscal.json(no signing key in the repo; it verifies nothing). (4) An FDA medical-device guide atdocs/wiki/5-compliance/fda-medical-device-compliance.md. All content is generic and synthetic — no customer/third-party references. - Public demo suite (in-repo artifacts). Three surfaces telling one story (the bundled
examples/meridian-fintech-v2sample), perdocs/demo-suite-design.md: Tier 2 — a static "demo mode" build of the web console (VITE_DEMO=true) that swaps the API client for a baked-fixtures module (src/lib/demo/), renders the SSE routes as canned streams, usesHashRouterfor static subpath hosting, and shows a "DEMO · synthetic data · no live backend" banner — it issues zero/apicalls (no backend, no credentials); Tier 0 — a self-hosted asciinema cast (packages/evidentia-ui/public/demo.cast, generated byscripts/demo/gen_cast.pyfrom the real CLI run) + a vendored player embedded on the demo page + README; Tier 1 — a constrained argv-allowlist runner (evidentia.demo.runner) + a demo-profiledocker/Dockerfile.demoenforcing the threat-model conditions (no raw shell, scrubbed env, forced--offline, network-free fixture-only verbs, built FROM the signed release digest). The deploy steps (Vercel, the hosted Tier-1 runner, the marketing-site link) are deferred Tier-4 actions, not part of this build.
Security
- Container base Python 3.14 → 3.13 — removes three container CVEs at the root. The published v0.10.9 container was pinned to litellm 1.83.7 (the only release installable on Python 3.14), which carries CVE-2026-40217 (HIGH — sandbox escape in litellm's custom-code guardrail) and transitively held python-dotenv 1.0.1 (CVE-2026-28684) + aiohttp 3.13.5 (two client-cookie CVEs). litellm ≥ 1.84 — and the fix for all three — declares
requires-python <3.14, so the ceiling was thepython:3.14-slimbase itself. Dropping the base topython:3.13-slim(digest-pinned) lets the container resolve the same CVE-clean set the library'suv.lockpins (litellm 1.89.0, aiohttp 3.14.1, python-dotenv 1.2.2, starlette 1.3.1) — and supersedes the v0.10.9 F-V109-4 "known limitation" (the aiohttp ceiling is gone). The live HIGH was not reachable (Evidentia uses litellm for completions, not the guardrail-proxy feature CVE-2026-40217 affects); the base change removes it regardless. Verified osv-clean by version; enforced by the new container osv-gate. - Collectors SSRF guard (threat-model T2), now rebind-resistant (closes F-V1010-S1). The OCSF collector's private-IP refusal (the v0.10.2
--block-private-ips) is lifted into a sharedevidentia_core.network_guard.enforce_public_hostand applied default-on to all 13 outbound collectors (okta, databricks, snowflake, github, vanta, drata, bitsight, securityscorecard + the 4 SQL adapters) and the API collectors router — closing the surface where an operator-supplied host (or, on an exposedserve, an anonymous request) could reach cloud-metadata / internal endpoints. The guard now PINS the validated IP through the actual connection so a TOCTOU DNS-rebind cannot bypass it:enforce_public_hostreturns the addresses it classified as public, andpin_resolved_hostforces the connecting library's independent re-resolution back to those addresses for the duration of the request (a thread-localsocket.getaddrinfopin covering httpx, urllib, and the thin/pure-Python DB drivers + SDKs; libpqhostaddrfor Postgres; ODBCHostNameInCertificate+IP-dial for MSSQL). The hostname is unchanged, so TLS SNI, theHostheader, and certificate verification still target the original hostname — only the dialed IP is locked. This corrects the v0.10.2 known-limitation note ("single-resolve at pre-fetch time; DNS rebinding … out of scope"): rebinding between validation and connection is now defeated. Secure-by-default: internal-endpoint collection requires the opt-out (--allow-private-ips/block_private_ips=false); fail-closed on unresolvable hosts. The blocked set also covers RFC 6598 carrier-grade NAT (100.64.0.0/10), which cpython'sipaddressdoes not classify as private. SSRF + per-transport rebind regression tests cover the httpx, urllib, and SQL/psycopg paths. (AWS is unaffected — boto3 resolves SDK endpoints, not an operator host.) tuf6.0.0 → 7.0.0 (closes GHSA-qp9x-wp8f-qgjj) —sigstore4.3.0 relaxed itstuf~=6.0pin totuf<8,>=6, firing the v0.10.7 removal trigger; theosv-scanner.tomlignore is dropped. The signing/verify paths (incl. the v0.10.9 Fulcio-cert-extension extraction) re-validate clean under sigstore 4.3.0.- Container osv-gate.
release.yml+container-build.ymlnow osv-scan the regenerateddocker/requirements.txt(pinned osv-scanner v2.3.8) after the regen and before the docker build, so a vulnerable container dependency hard-fails the build instead of shipping silently — the exact gap that let the v0.10.9 container HIGH through. (The F-V109-4--upgraderegen fix, landed in the workflows during the v0.10.9 re-fire, is now also applied tobump_version.py's own regen path.) - Security-tab disposition (no code) — 6 accept-only alerts dismissed with rationale: torch GHSA-rrmf-rvhw-rf47 (no fix exists; the
torch.jit.scriptpath is unused), the two container-aiohttp client-cookie CVEs (moot after the base change), and 3 OpenSSF-Scorecard code-scanning signals (justified job-scopedcontents:write+ the org-level ruleset Scorecard can't see). Code-scanning is now 0-open. - Workspace dependency hygiene.
python-multipart0.0.27 → 0.0.32 andstarlette1.0.1 → 1.3.1 clear newly-surfaced osv advisories.cryptographyGHSA-537c-gmf6-5ccf (a vulnerable statically-linked OpenSSL in the wheels; availability-only) is accepted-with-rationale inosv-scanner.toml— it is absent from every shipped artifact (the container shipsevidentia[gui]and a basepip install evidentiapulls no cryptography; it surfaces only in the full-extras dev SBOM), the fix (48.0.1) is graph-blocked bypy-ocsf-models 0.9.0'scryptography<47cap, and the upstream cap-lift (prowler-cloud/py-ocsf-models#300+ PR #301) is the documented removal trigger.
Changed
serveposture hardening doc (threat-model T3) —docs/threat-model.mddocuments that the containerCMDdefaults toserve --host 0.0.0.0(online, no-auth) and recommends 127.0.0.1 binding,EVIDENTIA_API_AUTH_TOKEN_FILEfor any non-loopback exposure, and--offline/EVIDENTIA_API_OFFLINE=1when collectors aren't needed.- GitHub collector gained a
--base-urlflag (+ API field) for GitHub Enterprise endpoints; the new SSRF guard runs in the client constructor (a no-op for the defaultapi.github.com).
Fixed
- Config-test isolation —
find_config_filegained an optionalstop_atboundary; the config unit + API tests now bound the upwardevidentia.yamlwalk to their tmp tree, so a stray ancestor config (e.g. a~/evidentia.yaml— pytest tmp dirs live under$HOME) can no longer leak into the suite and cause spurious failures. - Demo-suite polish (pre-release-review Step 3) — the demo gap view shows an honest "representative N of {total}" caption when the rendered rows are a subset; in-app links use the router so navigation survives the static
HashRouterhost; the demo SSE stream honors Cancel (AbortController); and the runner's never-satisfiableoscal verifyallowlist vector is removed (deferred to a bundled signed fixture at Tier-1 deploy).
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.10"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.10
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See [docs/sigstore-quickstart.m...
v0.10.9
Highlights
Theme: v0.10.9 — debt + robustness patch. Patch bump (v0.10.8 → v0.10.9). Closes the v0.10.8 ship findings and skill-iteration debt, and hardens the release machinery that cycle built.
Release summary: A consolidation cycle with one product-behavior fix and a set of release-machinery, UI-polish, and dependency items — every item traces to a named v0.10.8 finding or deferral. Product fix: the eval CLI's auto-sign now checks OIDC-token obtainability (not just GITHUB_ACTIONS), degrading gracefully to unsigned output with a warning in CI jobs lacking id-token: write instead of crashing (the F-V108-CI1 product fix — v0.10.8 only made the tests hermetic). Release machinery: the CLI↔GUI parity gate flips advisory → blocking, including a new parity check in the tag-time gate suite, so a parity regression can no longer reach PyPI; the uv-lock pin-drift pre-push check attributes drift per commit, eliminating the v0.10.8 false-positive class (SF-V108-3); the quarterly safeguards-resweep issue probe is idempotent across closed issues. Dependencies: the aiohttp accepted-CVE removal trigger fired — litellm 1.88.1 dropped its exact pin, aiohttp floats to 3.14.1, and both [[IgnoredVulns]] entries are removed. Alongside the cycle, a verified competitive/market research refresh corrected the positioning + integration-survey docs (every change traceable to a primary-source verification ledger). 3892 tests pass / 8 skipped; mypy strict 0/0 across 272 source files; ruff clean; frontend tsc + build + vitest 35/35. Workspace ships 8 PyPI packages unchanged from v0.10.8. Per-cycle detail in docs/v0.10.9-plan.md.
Added
lib/sse.tsshared SSE reader in the web console — one genericreadSse<T>replaces the functionally identical per-page readers in ExplainPage and RiskGeneratePage, with a 6-case vitest spec locking in the exact streaming semantics (chunk-split frames, multi-data:records, keep-alive noise, trailing-partial discard). See commit91742a3.paritycheck in the tag-time gate suite.run_gate_suite.py --scope fullnow runscheck_parity.pyas its 8th check, so the irreversible publish is blocked on a CLI↔GUI parity regression, not just annotated. See commit417c912.
Changed
- Eval CLI auto-sign degrades gracefully without an OIDC token.
_resolve_sign's auto-detect branch now additionally requiresACTIONS_ID_TOKEN_REQUEST_TOKEN+ACTIONS_ID_TOKEN_REQUEST_URL(present only in jobs withid-token: write); when CI is detected but no token is obtainable, the eval JSON is written unsigned with a stderr warning instead of crashing withSigstoreSigningError. An explicit--signkeeps attempt-and-raise semantics. 13 new tests cover the tri-state × token matrix. See commit417c912. - CLI↔GUI parity gate is blocking.
parity.ymlpropagatescheck_parity.py's exit code (the v0.10.8 advisory|| echoescape is removed), completing the advisory → blocking flip planned at v0.10.8. See commit417c912. check_uv_lock_pin_driftattributes pin drift per commit (SF-V108-3): each commit touchinguv.lockis diffed against its first parent (plus the working-tree pair), and the push blocks only when a single commit both bumps a workspace version and moves a third-party pin — a separately-committed dependency bump in the range no longer trips the gate (the v0.10.8 false-positive replays green; an aggregate-diff fallback preserves the old strictness on unusual topologies). See commit417c912.- safeguards-resweep is idempotent across closed issues — exact-title matching across open and closed states; a deliberately closed quarterly tracking issue is no longer resurrected. See commit
417c912. PoamPageuses the generated OpenAPIControlGap-Outputtype, dropping the hand-rolled local widen. See commit91742a3.- litellm 1.83.14 → 1.88.1, aiohttp 3.13.4 → 3.14.1. The documented aiohttp removal trigger fired: litellm 1.88.1 relaxed its exact
aiohttp==3.13.4pin to<4.0,>=3.10, so aiohttp floats past the 3.14.0 fix release and both accepted client-cookie CVE entries (GHSA-hg6j-4rv6-33pg, GHSA-jg22-mg44-37j8) are removed fromosv-scanner.toml. See commitbd8650f. - The
check_secretstest module resolves a usable bash (Git-for-Windows first) and skips with a precise reason when only the WSL System32 shim is on PATH, instead of failing 6/6 with exit 127 on Windows dev boxes. See commit316582d. readSseno longer swallows handler exceptions — the malformed-frame catch is narrowed toJSON.parseonly, so anonEventthrow propagates to the caller instead of being silently eaten; the reader lock is released on all exits (try/finally).- The safeguards-resweep issue probe lists
--state all --limit 100without--search, removing the dependence on GitHub search tokenization and the 30-result default page; throwaway git-fixture repos in the pre-push-check tests pincommit.gpgsign=falseso host signing config can't make them prompt or fail.
Fixed
- CI
secret-scanworkflow — switched fromgitleaks/gitleaks-action(which requires a paidGITLEAKS_LICENSEfor organization-owned repos, so it failed at the license gate on every push without ever scanning) to the MIT-licensed gitleaks CLI binary (pinned v8.30.1, SHA256-verified, matching the osv-scanner pin). Running gitleaks end-to-end for the first time surfaced 7 findings, all verified as deliberately-fake test fixtures (the secret-scrubber test's placeholder credentials + fake 16-hexreport_keytest values) — now allowlisted by module path in.gitleaks.toml; no real secrets. See commit3d7469a.
Docs
- Verified competitive/market refresh (quarterly-ish resync; last full pass v0.9.5) applied to
positioning-and-value.md+integration-survey.md+ the ROADMAP: the Credo-AI self-host/air-gap reframe, the CISO-Assistant MCP correction, the DFAH claim narrowed to "first/only OSS GRC-toolkit implementation", five fabricated-claim strikes (incl. "NASDAQ: SNYK" and a non-existent arXiv citation), the PCAOB five-capabilities framing corrected to Evidentia's own mapping, and the FedRAMP machine-readable timeline re-based to NTC-0009 (2027-11-01, Class D High). Every correction traces to a primary-source verification ledger; all four kickoff regulatory designators (CR26 / RFC-0024 / SR 26-2 / OCC Bulletin 2026-13) double-verified on .gov sources — the shippedocc-sr-26-02catalog stands. See commit5cfaf06.
Security
- F-V109-1 (HIGH, found by the in-cycle scoped security review): single-flag verify no longer silently skips identity pinning.
verify_filepreviously built its identity policy only when both--expected-identityand--expected-issuerwere supplied — passing exactly one silently discarded the constraint and verified under an any-signerUnsafeNoOppolicy, so a tampered artifact re-signed under any OIDC identity reportedVALID. Identity pinning now follows the cosign model (both-or-neither): a single flag is a hard usage error onevidentia eval verify(exit 2), a report-level failure onevidentia oscal verify, and a structured tool error on theverify_signed_artifactMCP tool. Pre-existing since the verify surface shipped; not a v0.10.9 regression. - F-V109-2 (MEDIUM): flag-less verification now warns that signer identity is unverified.
evidentia eval verifywithout pinning flags checks the signature + transparency-log inclusion only — it now prints an explicit stderr warning that ANY Sigstore identity would pass and how to pin the signer (exit code unchanged for valid bundles; the MCP result payload carries the equivalent structured warning). - F-V109-3 (LOW): the verification output's
issuer:line now shows the real OIDC issuer (extracted from the Fulcio certificate extension, OID 1.3.6.1.4.1.57264.1.8) instead of the constant Fulcio X.509 DN, so the human cross-check line can actually discriminate identity providers (clearly-labeled DN fallback when the extension is absent). - New accepted advisory: GHSA-rrmf-rvhw-rf47 (torch 2.11.0, CVE-2025-3000, GitHub-reviewed severity LOW, local-only
torch.jit.scriptmemory corruption). GitHub-reviewed into the GHSA database 2026-06-10 (NVD-published 2025-03); no fixed version exists (affected through the latest torch); torch is transitive-only via the optionalfaithfulness-semanticeval extra and no Evidentia source references torch. Operator-confirmed accept; re-validate by 2026-12-10. See commitbd8650f. - The aiohttp accepted-CVE pair is closed (not merely re-affirmed): the upstream block lifted and the fixed version now ships in
uv.lock(see Changed).
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.9"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.9
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See docs/sigstore-quickstart.md
for the full verification narrative + supply-chain framing.
CHANGELOG
Full changelog (every release): CHANGELOG.md
Container image
ghcr.io/polycentric-labs/evidentia:v0.10.9ghcr.io/polycentric-labs/evidentia:latest- Digest:
sha256:68750fa8cf260cb3f218d24294e101da5f38f2d92d15e9ecc815fce2c7fce6f6
Verify (cosign keyless OIDC):
cosign verify ghcr.io/polycentric-labs/evidentia:v0.10.9 \
--certificate-identity-r...v0.10.8
Highlights
Theme: v0.10.8 — safeguards automation + CLI↔GUI parity + Tier-B GUI build-out. Patch bump (v0.10.7 → v0.10.8). Wires the v0.10.7 quality discipline into the automatic release mechanism and opens the CLI↔GUI parity programme.
Release summary: A release-hardening + parity + GUI-build-out cycle with no new end-user product capability — every item either automates a previously-manual safeguard, measures CLI↔GUI coverage, or surfaces an existing CLI/REST capability in the web console. Release-hardening: a tag-time gate job now runs the full check suite on the tagged commit and the PyPI/GHCR publish jobs needs: gate, so the irreversible publish is blocked on a red or stale tree (closing the gap that left the staleness guards pre-push-only); a consistency.yml CI job mirrors the version + docs-health + README guards onto every push/PR; the pre-push hook regenerates the README Recent-Releases block and fails if it drifted; and a secret-scan.yml (gitleaks) catches a committed credential even on a clone without the local hook. All of these (plus the pre-push hook and the tag-gate) read one declarative check-list via scripts/run_gate_suite.py, so the surfaces cannot drift (the v0.9.8 gate-fidelity lesson). CLI↔GUI parity: a new docs/cli-gui-parity.yaml manifest classifies every CLI leaf (full / api-only / cli-only / exempt) and scripts/check_parity.py enforces completeness + API-existence + GUI-existence + a cli-only debt-ratchet (catching the coverage gap a passing type-drift gate masks); GUI coverage rises 6.1% → 13.3% via four new Tier-B web screens. Phase-G upkeep: stale-branch flagging, Dependabot patch/minor auto-merge, and a quarterly safeguards re-sweep. 3869 tests pass / 14 skipped; mypy strict 0/0 across 272 source files; ruff clean. Workspace ships 8 PyPI packages unchanged from v0.10.7. Per-cycle detail in docs/v0.10.8-plan.md.
Added
- Tag-time release gate.
release.ymlgains agatejob that runs the full SSOT check suite on the tagged commit, and the PyPI/GHCRpublishjobs nowneeds: gate. A red or stale tree therefore can't reach the irreversible publish —scripts/run_gate_suite.py --scope fullcovers tests + types + lint + version-consistency + docs-health + osv, closing the gap that left those guards pre-push-only while the publish ran ungated. See commit10efb09. - CI staleness mirror. New
consistency.ymlruns the same SSOT gate suite (--scope consistency: version-consistency + docs-health + README-releases) on every push/PR tomain, so a stale version reference, broken doc cross-link, or stale README block fails fast rather than at tag time. See commit10efb09. - README Recent-Releases auto-regen in the pre-push gate. A new pre-push check regenerates the README releases block from
CHANGELOG.mdand fails if it changed, making the v0.10.7-class README staleness mechanically impossible (the--checkguard was version-only by design). See commit586c1a3. - CI secret-scan.
secret-scan.ymlruns gitleaks on every push/PR tomainwith a shared.gitleaks.toml(upstream ruleset + a tests-fixtures/examples allowlist), complementing the local pre-push secret scan so a committed credential is caught even on a clone without the hook. See commit2ef1fba. - CLI↔GUI parity manifest + gate.
docs/cli-gui-parity.yamlclassifies every CLI leaf;scripts/check_parity.pyenforces completeness + API-existence + GUI-existence (catching the types-only illusion the OpenAPI-drift gate misses) + a cli-only debt-ratchet;parity.ymlruns it advisory this release (blocking in v0.10.9);docs/parity-coverage.mdis the generated burndown + the README badge. See commits34a6c53,57bf51f. - Four Tier-B web screens. POA&M (
/poam) — list + severity/status filters + in-page detail + forward-only milestone state-transitions; TPRM (/tprm) — vendor list + tier/type filters + atomic create form; ConMon (/conmon) — read-only cadence browser; Explain (/explain) — framework + control-id picker + SSE-streamed plain-English explanation with an LLM-provider guard. Each follows the existing inline-useQuery+ shadcn/ui patterns; vitest covers render + the primary interaction (29/29). GUI coverage 6.1% → 13.3% as 7 CLI leaves flip api-only → full. See commitsb08ff49,7de204e. - Phase-G upkeep automations.
stale-branches.ymlflags branches with no commit in >30d to the run summary (read-only, never deletes);dependabot-automerge.ymlenables auto-merge on green patch/minor Dependabot PRs (gated to thedependabot[bot]actor; major bumps stay manual; requires the repo "Allow auto-merge" setting enabled separately);safeguards-resweep.ymlopens a quarterly tracking issue to re-run the automated-vs-manual safeguards audit. All passaudit_workflow_permissions --strict(the 2 write-scoped workflows carry JUSTIFIED annotations). See commitf5ca9e7. - Operator-walkthrough wiki media. A web-console section added to
manage-poam+conmon-deployment, the TPRM GUI walkthrough merged intomanage-third-party-risk, and a newexplain-controlsguide — each with a captured screenshot underdocs/wiki/images/. See commit4318cff. - README hero refresh. A centered hero — the 2400×1260 OG brand card + a tight tagline + Get Started / Documentation / PyPI call-to-action buttons + the nine status badges centered beneath (presentation only; the Recent-Releases block + the container-tag version anchor untouched). See commit
87b851a.
Changed
pyjwt2.12.1 → 2.13.0 — closes CVE-2026-48522 / 48524 / 48525 / 48526 (osv PYSEC-2026-175/177/178/179, up to CVSS 7.4), surfaced by the new osv gate; the bump resolves cleanly (onlypyjwtmoves) and the full suite re-validates green. See commit7669ed3..gitleaks.tomlis classifiedfrozenin the version-tracking manifest — it carries a v0.10.8 audit-trail comment but no project-version literal, so the never-skip version-consistency guard flagged it once committed; classifying it alongside the other root-level config dotfiles resolves that. See commitd611588.
Docs
explain-controls.mdintro corrected — the explanation is delivered over a Server-Sent-Events stream (astartframe, then a single terminal frame), not progressive token rendering; the prior wording over-stated incremental streaming. A G28 docs-from-verified-facts fix caught by diffing the guide againstExplainPage.tsx.- The v0.10.5 / v0.10.6 / v0.10.7 in-repo security-review docs were backfilled (v0.10.5/.6 honestly mark ship-telemetry VERIFY-LIMITED where no per-run JSON exists; v0.10.7 is fully verified). See commit
70e8057. docs/sarif-ingestion-collector-design.mdNEW — design spec for a v0.11evidentia collect sarifingestion collector (control-agnostic default + attestation-gated candidate mappings, mirroring the v0.10.1 OCSF ingest path);docs/integration-survey.mdgains an agentic-security interop assessment (data-layer SARIF handoff; no code reuse across the PolyForm/Apache-2.0 boundary). See commits10b0a5c,a99273a.docs/v0.9.3-plan.md3 stale cross-link WARNs fixed; the acceptedtuf6.0.0osv-scanner.tomlignore gains a removal-trigger note (drop whensigstoreships tuf-7 support). See commit244ec83.
Security
pyjwtfour-CVE bump (see Changed) — the headline supply-chain fix this cycle, caught pre-tag by the new osv gate before publish.- The tag-time gate's osv step and the gitleaks CI secret-scan are net-new supply-chain safeguards that now run on the irreversible publish path, not just the local pre-push hook.
Verify the wheels (PEP 740 publish attestations)
Every wheel uploaded to PyPI from this release carries a
Sigstore-signed PEP 740 publish attestation. Verify locally:
pip install pypi-attestations
pypi-attestations verify pypi \
--repository https://github.com/polycentric-labs/evidentia \
"pypi:evidentia==0.10.8"Verification confirms the wheel was built + published from
polycentric-labs/evidentia/release.yml@refs/tags/v0.10.8
under GitHub Actions OIDC — i.e., a malicious mirror cannot
serve a tampered wheel without the verification failing.
See docs/sigstore-quickstart.md
for the full verification narrative + supply-chain framing.
CHANGELOG
Full changelog (every release): CHANGELOG.md
Container image
ghcr.io/polycentric-labs/evidentia:v0.10.8ghcr.io/polycentric-labs/evidentia:latest- Digest:
sha256:19bee7abd9096125803a7faa682844867af81559d422c6f4f65e446c881b530f
Verify (cosign keyless OIDC):
cosign verify ghcr.io/polycentric-labs/evidentia:v0.10.8 \
--certificate-identity-regexp 'https://github\.com/Polycentric-Labs/evidentia/\.github/workflows/release\.yml@refs/tags/v.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'Verify (SLSA build provenance):
gh attestation verify oci://ghcr.io/polycentric-labs/evidentia:v0.10.8 \
-R Polycentric-Labs/evidentiaSee docs/sigstore-quickstart.md
for the full verification narrative.