Integrate extraction artifacts into analysis catalog

This commit is contained in:
2026-08-10 00:24:02 +00:00
parent bba582b4ca
commit 39af7d4f3c
8 changed files with 690 additions and 7 deletions

View File

@@ -11,6 +11,7 @@ import (
const (
ArtifactProvenanceGeneratedCurrentAnalyzeRun = "generated.current_analyze_run"
ArtifactProvenanceDisabledFromDisk = "filesystem.disabled_artifact_output"
ArtifactProvenanceCurrentExtractManifest = "manifest.current_extract_run"
)
// ConfiguredArtifactDefinition describes one configured analyze artifact.
@@ -19,10 +20,21 @@ type ConfiguredArtifactDefinition struct {
OutputPath string
}
// ExtractionArtifactDefinition describes one configured Notarius output lane.
type ExtractionArtifactDefinition struct {
LaneID string
PipelineID string
MediaType string
SchemaID string
SchemaVersion string
ModuleKey string
}
// CatalogEntry is one runtime catalog entry resolved by source ID.
type CatalogEntry struct {
SourceID string
ConfiguredKey string
ExtractionKey string
CanonicalRelPath string
ProducerStage string
OutputKind string
@@ -31,12 +43,14 @@ type CatalogEntry struct {
Available bool
Path string
Provenance string
ProducerRunID string
}
// ArtifactCatalog tracks built-in and configured artifact definitions and runtime state.
// ArtifactCatalog tracks built-in, configured, and extraction artifact definitions and runtime state.
type ArtifactCatalog struct {
entries map[string]CatalogEntry
configuredIndex map[string]string
extractionIndex map[string]string
}
// NewArtifactCatalog returns an empty runtime artifact catalog.
@@ -44,9 +58,41 @@ func NewArtifactCatalog() *ArtifactCatalog {
return &ArtifactCatalog{
entries: map[string]CatalogEntry{},
configuredIndex: map[string]string{},
extractionIndex: map[string]string{},
}
}
// RegisterExtractionArtifacts registers the configured Notarius output lanes.
func (c *ArtifactCatalog) RegisterExtractionArtifacts(configured map[string]ExtractionArtifactDefinition) error {
keys := make([]string, 0, len(configured))
for key := range configured {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
trimmed := strings.TrimSpace(key)
if trimmed == "" {
return fmt.Errorf("extraction artifact keys must be non-empty")
}
if _, exists := c.extractionIndex[trimmed]; exists {
return fmt.Errorf("duplicate extraction artifact key %q", trimmed)
}
sourceID := ExtractionArtifactSourceID(trimmed)
if err := c.addEntry(CatalogEntry{
SourceID: sourceID,
ExtractionKey: trimmed,
ProducerStage: "extract",
OutputKind: "notarius_lane",
Planned: true,
}); err != nil {
return fmt.Errorf("register extraction artifact %q: %w", trimmed, err)
}
c.extractionIndex[trimmed] = sourceID
}
return nil
}
// ConfiguredArtifactSourceID converts a configured artifact key into canonical source ID.
func ConfiguredArtifactSourceID(key string) string {
return artifactpolicy.ConfiguredSourceID(key)
@@ -151,6 +197,15 @@ func (c *ArtifactCatalog) SourceIDForConfiguredKey(key string) (string, bool) {
return sourceID, ok
}
// SourceIDForExtractionKey returns the canonical source ID for one Notarius output key.
func (c *ArtifactCatalog) SourceIDForExtractionKey(key string) (string, bool) {
if c == nil {
return "", false
}
sourceID, ok := c.extractionIndex[strings.TrimSpace(key)]
return sourceID, ok
}
// ListConfigured returns configured entries sorted by configured key.
func (c *ArtifactCatalog) ListConfigured() []CatalogEntry {
if c == nil || len(c.configuredIndex) == 0 {
@@ -169,6 +224,23 @@ func (c *ArtifactCatalog) ListConfigured() []CatalogEntry {
return out
}
// ListExtraction returns extraction entries sorted by configured output key.
func (c *ArtifactCatalog) ListExtraction() []CatalogEntry {
if c == nil || len(c.extractionIndex) == 0 {
return nil
}
keys := make([]string, 0, len(c.extractionIndex))
for key := range c.extractionIndex {
keys = append(keys, key)
}
sort.Strings(keys)
out := make([]CatalogEntry, 0, len(keys))
for _, key := range keys {
out = append(out, c.entries[c.extractionIndex[key]])
}
return out
}
// MarkAvailableGenerated marks one source as available in current analyze execution.
func (c *ArtifactCatalog) MarkAvailableGenerated(sourceID, path string) error {
return c.markAvailable(sourceID, path, ArtifactProvenanceGeneratedCurrentAnalyzeRun)
@@ -179,6 +251,16 @@ func (c *ArtifactCatalog) MarkAvailableFromDisk(sourceID, path string) error {
return c.markAvailable(sourceID, path, ArtifactProvenanceDisabledFromDisk)
}
func (c *ArtifactCatalog) markAvailableFromExtractManifest(sourceID, path, producerRunID string) error {
if err := c.markAvailable(sourceID, path, ArtifactProvenanceCurrentExtractManifest); err != nil {
return err
}
entry := c.entries[strings.TrimSpace(sourceID)]
entry.ProducerRunID = strings.TrimSpace(producerRunID)
c.entries[entry.SourceID] = entry
return nil
}
func (c *ArtifactCatalog) markAvailable(sourceID, path, provenance string) error {
if c == nil {
return fmt.Errorf("artifact catalog is nil")