Add evidence context policy preparation

This commit is contained in:
2026-07-27 18:04:12 +00:00
parent 64d461fc18
commit 224a8292c4
21 changed files with 900 additions and 98 deletions

View File

@@ -5,6 +5,7 @@ import (
"reflect"
"strings"
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
)
@@ -24,6 +25,7 @@ type PreparedPipeline struct {
chunkValidators preparedValidatorChain
output contracts.OutputEncoder
artifactCodecs *ArtifactCodecRegistry
evidencePlan *preparedEvidencePlan
checkpointFingerprints []CheckpointFingerprint
}
@@ -55,6 +57,17 @@ type preparedTypedLane struct {
codec artifactCodecEntry
}
type preparedEvidencePlan struct {
policy EvidenceContextPolicy
lanes []preparedEvidenceLane
}
type preparedEvidenceLane struct {
laneID string
kind contracts.ArtifactKind
project func(any) ([]source.SourceRef, error)
}
type preparedValidatorChain struct {
resolved ResolvedValidatorChain
validators []preparedValidator
@@ -129,6 +142,10 @@ func Prepare(resolved ResolvedPipeline, registries Registries, deps ModuleDepend
return nil, constructionError(stable.ID, "", StageOutput, stable.Output.Module, "", err)
}
prepared.output = output
prepared.evidencePlan, err = prepareEvidencePlan(stable, registries, output)
if err != nil {
return nil, err
}
prepared.checkpointFingerprints, err = collectPreparedCheckpointFingerprints(prepared)
if err != nil {
return nil, err
@@ -136,6 +153,52 @@ func Prepare(resolved ResolvedPipeline, registries Registries, deps ModuleDepend
return prepared, nil
}
func prepareEvidencePlan(resolved ResolvedPipeline, registries Registries, output contracts.OutputEncoder) (*preparedEvidencePlan, error) {
provider, ok := output.(EvidenceContextPolicyProvider)
if !ok {
return nil, nil
}
policy := cloneEvidenceContextPolicy(provider.EvidenceContextPolicy())
if !policy.Enabled {
return nil, nil
}
if policy.WindowUnits < 0 {
return nil, constructionError(resolved.ID, "", StageOutput, resolved.Output.Module, "", fmt.Errorf("evidence window units must not be negative"))
}
lanes, err := normalizeEvidenceLaneIDs(policy.LaneIDs)
if err != nil {
return nil, constructionError(resolved.ID, "", StageOutput, resolved.Output.Module, "", err)
}
policy.LaneIDs = lanes
active := make(map[string]ResolvedArtifactLane)
for _, lane := range resolved.AllArtifactLanes() {
active[lane.ID] = lane
}
plan := &preparedEvidencePlan{policy: cloneEvidenceContextPolicy(policy)}
for _, laneID := range policy.LaneIDs {
lane, ok := active[laneID]
if !ok {
continue
}
if registries.ArtifactEvidence == nil {
return nil, constructionError(resolved.ID, laneID, StageOutput, resolved.Output.Module, "", fmt.Errorf("artifact evidence registry must not be nil for active evidence lane"))
}
evidence, _, evidenceErr := registries.ArtifactEvidence.entry(lane.ArtifactKind)
if evidenceErr != nil {
return nil, constructionError(resolved.ID, laneID, StageOutput, resolved.Output.Module, "", evidenceErr)
}
codecType, ok := registries.ArtifactCodecs.valueType(lane.ArtifactKind)
if !ok {
return nil, constructionError(resolved.ID, laneID, StageOutput, resolved.Output.Module, "", fmt.Errorf("artifact codec %q has no Go type", lane.ArtifactKind))
}
if evidence.valueType != codecType {
return nil, constructionError(resolved.ID, laneID, StageOutput, resolved.Output.Module, "", fmt.Errorf("artifact evidence kind %q requires Go type %s, but active artifact codec uses %s", lane.ArtifactKind, typeName(evidence.valueType), typeName(codecType)))
}
plan.lanes = append(plan.lanes, preparedEvidenceLane{laneID: laneID, kind: lane.ArtifactKind, project: evidence.project})
}
return plan, nil
}
func prepareLane(pipeline ResolvedPipeline, lane ResolvedArtifactLane, registries Registries, deps ModuleDependencies) (preparedLaneExecutor, error) {
executor := preparedLaneExecutor{resolved: cloneResolvedArtifactLane(lane)}
request := func(binding ModuleBinding, references contracts.ReferenceSet) BuildRequest {
@@ -303,7 +366,7 @@ func constructionError(pipelineID, laneID string, stage ModuleStage, moduleKey,
func (registries Registries) catalog() ModuleCatalog {
return ModuleCatalog{
Inputs: registries.Inputs, Chunkers: registries.Chunkers, ArtifactCodecs: registries.ArtifactCodecs,
Inputs: registries.Inputs, Chunkers: registries.Chunkers, ArtifactCodecs: registries.ArtifactCodecs, ArtifactEvidence: registries.ArtifactEvidence,
Extractors: registries.Extractors, Mergers: registries.Mergers, Normalizers: registries.Normalizers,
Validators: registries.Validators, ValidatorChains: registries.ValidatorChains, Outputs: registries.Outputs,
}