feat: evidence source provenance (EvidenceMapping) support - #840
marcusburghardt wants to merge 5 commits into
Conversation
Add OpenSpec change artifacts for plumbing the Gemara EvidenceMapping (source field) through complyctl's evidence pipeline. This enables providers to report evidence provenance -- which artifact, location, and content digest each evidence entry was collected from. Artifacts: - proposal.md: motivation and scope - specs/evidence-source/spec.md: behavioral requirements - design.md: technical decisions and approach - tasks.md: implementation checklist Assisted-by: OpenCode (claude-opus-4-6) Signed-off-by: Marcus Burghardt <maburgha@redhat.com>
Refine Non-Goals to acknowledge go-gemara#127 tracks evidence-to-OSCAL and evidence-to-SARIF conversion upstream. SARIF already delegates to gemaraconv.ToSARIF() and will benefit automatically. Local OSCAL formatter migration tracked in a separate complyctl issue. Assisted-by: OpenCode (claude-opus-4-6) Signed-off-by: Marcus Burghardt <maburgha@redhat.com>
Apply auto-fixes for findings from 6 Divisor spec reviewers: - Normalize SHALL to MUST per AGENTS.md spec convention - Add scenario for partial source fields (common real-world case) - Add scenario for coordinate/entry_id passthrough (Gemara mutual exclusivity documented but not enforced by complyctl) - Qualify YAML omission scenario with JSON serialization edge case (encoding/json does not omit zero-value structs) - Add D5 design decision for passthrough model + digest format note - Expand D3 with gemara value-type serialization note - Task 1.1: add buf breaking check for backward-compat verification - Task 2.2: acknowledge missing internalEvidenceToProto test coverage - Task 3.2: add JSON serialization and YAML omission assertions - Task 5.2: add schema validation and specific E2E assertions - Add documentation tasks (CHANGELOG.md, AGENTS.md Recent Changes) Assisted-by: OpenCode (claude-opus-4-6) Signed-off-by: Marcus Burghardt <maburgha@redhat.com>
Add EvidenceMapping message to proto API and plumb the source field through the entire evidence pipeline, enabling providers to report where evidence was collected from. Changes: - Proto: add EvidenceMapping message with reference_id, coordinate, entry_id, digest, remarks fields; add source field (field 6) to Evidence message; remove stale ADR 0023 comment - SDK: add EvidenceSource struct and Source *EvidenceSource field to provider.Evidence in pkg/provider/client.go - Mapping: add internalEvidenceSourceToProto() in server.go and protoEvidenceMappingToInternal() in client.go for gRPC boundary - Evaluator: map provider.EvidenceSource to gemara.EvidenceMapping when constructing evaluation log entries - Markdown: render source provenance as 'source: <ref> @ <coord>' in formatEvidenceMeta() - Test provider: emit evidence with Source for E2E coverage - Tests: comprehensive coverage for both proto mapping directions, evaluator serialization (YAML + JSON), and markdown rendering Backward-compatible: providers without source are unaffected. Assisted-by: OpenCode (claude-opus-4-6) Signed-off-by: Marcus Burghardt <maburgha@redhat.com>
ee3915f to
ddb1674
Compare
gxmiranda
left a comment
There was a problem hiding this comment.
Clean, well-specified feature implementation that plumbs the Gemara EvidenceMapping through complyctl's entire evidence pipeline -- from proto definition through gRPC mapping, evaluator, and Markdown rendering. Comprehensive test coverage (both mapping directions, nil/partial/full cases, YAML/JSON serialization), backward-compatible design, and proper spec-first workflow with OpenSpec artifacts. All CI checks pass.
This review was generated by /review-pr (AI-assisted).
| // evidence was collected. Mirrors go-gemara EvidenceMapping. | ||
| message EvidenceMapping { | ||
| // Ties this evidence to a mapping-reference in the artifact's metadata | ||
| string reference_id = 1; |
There was a problem hiding this comment.
Do plugins have awareness of a mapping reference? Would we prefer that they send us a list of their sources too?
There was a problem hiding this comment.
Great question. I explored this in depth, including running through some possible scenarios with AI assistance against existing policy content in the repo.
Current state: This PR implements the transport layer — reference_id flows through from provider → proto → evaluator → output. If the provider sets it, it appears in the evaluation log and Markdown report. If not, it's empty.
The gap you identified: Providers may not know about mapping-references from the policy metadata. The host (complyctl) has this information (via the DependencyGraph), but currently doesn't pass it to the evaluator.
Host-side enrichment would require:
- Preserve
MappingReferencesfromparsePolicyLayer()in the resolver (currently discarded) - Build a
reqToMappingRefmap (requirement → catalog mapping-reference id) - Pass it to the
Evaluatorand enrich evidence that has emptyreference_id - Populate
EvaluationLog.Metadata.MappingReferencesin the output (currently empty) — without this,reference_idvalues would be dangling references
Trade-offs:
- The matching heuristic (requirement → catalog → mapping-reference) works for the common case but
reference_idis generic — evidence could relate to guidance or threats, not just catalogs - Both enrichment AND metadata output must ship together for the reference to be meaningful
- It touches the resolver (core pipeline), which needs its own design consideration
Options:
- Keep this PR as transport — providers can populate
reference_idif they have the info; follow up with host-side enrichment in a dedicated PR with proper spec - Expand this PR — add host-side enrichment now (scope expansion: resolver + evaluator + metadata output changes)
I'm leaning toward option 1 (transport now, enrichment follow-up) to keep this PR focused, but I'd value your input on whether you think the enrichment should block this PR or can be a fast follow-up.
jpower432
left a comment
There was a problem hiding this comment.
Implementation looks good, but I see an issue with regard to reference-id. There doesn't seem to be a way to collect this actual reference from plugins and I don't think the host would have that information either.
Remove documentation claiming coordinate and entry_id are mutually exclusive in EvidenceMapping. The Gemara maintainer (@jpower432) confirmed this was an upstream documentation bug, now fixed in the next release. Addresses PR complytime#840 review feedback from @jpower432. Assisted-by: OpenCode (claude-opus-4-6) Signed-off-by: Marcus Burghardt <maburgha@redhat.com>
Summary
Plumb the Gemara
#EvidenceMapping(sourcefield) through complyctl'sentire evidence pipeline, enabling providers to report where evidence
was collected from.
Fixes #841
Context
The Gemara CUE schema (
evaluationlog.cueline 73,auditlog.cuelines 78-97) defines
#Evidencewith asourcefield of type#EvidenceMappingthat records evidence provenance -- which artifact,which location within it, and a content digest. The go-gemara SDK already
exposes this as
Evidence.Source. complyctl's proto API currently defersthis field with a comment referencing an unwritten "ADR 0023".
Changes
EvidenceMappingmessage (reference_id,coordinate,entry_id,digest,remarks) andsourcefield(field 6) on
Evidence. Remove stale ADR 0023 comment.EvidenceSourcestruct andSource *EvidenceSourcefield onEvidenceinpkg/provider/.internalEvidenceSourceToProto()inserver.goand
protoEvidenceMappingToInternal()inclient.go.provider.EvidenceSourcetogemara.EvidenceMappingwhen constructing evaluation log entries.source: <ref> @ <coord>in
formatEvidenceMeta().Sourcefor E2E coverage.evaluator serialization (YAML + JSON), and markdown rendering.
Backward-compatible: providers that don't send
sourceare unaffected.OpenSpec Artifacts
openspec/changes/evidence-source/proposal.mdopenspec/changes/evidence-source/specs/evidence-source/spec.mdopenspec/changes/evidence-source/design.mdopenspec/changes/evidence-source/tasks.mdRelated