package artifacts import ( "os" "path/filepath" "strings" "gitea.maximumdirect.net/eric/narratio/internal/artifactmodel" "gitea.maximumdirect.net/eric/narratio/internal/manifest" ) // MaxExtractionPayloadBytes bounds one validated Notarius lane or index payload. const MaxExtractionPayloadBytes int64 = 64 * 1024 * 1024 const ( extractStageName = "extract" extractionLaneKind = "notarius_lane" extractionIndexKind = "notarius_index" extractionMetadataRun = "narratio_run_id" extractionMetadataRoot = "bundle_root" ) // HydrateExtractionArtifacts marks extraction sources available only when the current // manifest contains one complete, internally consistent, succeeded extraction bundle. // Invalid, stale, incomplete, or unsafe records leave every extraction source unavailable. func (c *ArtifactCatalog) HydrateExtractionArtifacts( paths SessionPaths, m *manifest.Manifest, configured map[string]ExtractionArtifactDefinition, ) { if c == nil || m == nil || len(configured) == 0 { return } proof := InspectExtractionEvidence(paths, m, configured) if proof.State != ExtractionEvidenceValid { return } for sourceID, path := range proof.Outputs { _ = c.markAvailableFromExtractManifest(sourceID, path, proof.ProducerRunID) } } func compatibleCatalogExtractionContract(got *artifactmodel.ContractMetadata, want ExtractionArtifactDefinition) bool { return got != nil && got.MediaType == want.MediaType && got.SchemaID == want.SchemaID && got.SchemaVersion == want.SchemaVersion && (want.ModuleKey == "" || got.ModuleKey == want.ModuleKey) } func compatibleCatalogExtractionProvenance( got *artifactmodel.ExternalProvenance, runID, pipelineID string, want ExtractionArtifactDefinition, ) bool { return got != nil && got.System == "notarius" && got.RunID == runID && got.PipelineID == pipelineID && pipelineID == strings.TrimSpace(want.PipelineID) && got.ArtifactID == want.LaneID } func safeExistingExtractionDirectory(sessionRoot, bundleRoot string) bool { if !pathWithinExtractionRoot(sessionRoot, bundleRoot) || !safeExtractionComponents(sessionRoot, bundleRoot) { return false } info, err := os.Lstat(bundleRoot) return err == nil && info.IsDir() && info.Mode()&os.ModeSymlink == 0 } func safeExtractionComponents(root, target string) bool { relative, err := filepath.Rel(filepath.Clean(root), filepath.Clean(target)) if err != nil || relative == "." || relative == ".." || strings.HasPrefix(relative, ".."+string(filepath.Separator)) { return false } current := filepath.Clean(root) for _, part := range strings.Split(relative, string(filepath.Separator)) { current = filepath.Join(current, part) info, err := os.Lstat(current) if err != nil || info.Mode()&os.ModeSymlink != 0 { return false } } return true } func pathWithinExtractionRoot(root, target string) bool { relative, err := filepath.Rel(filepath.Clean(root), filepath.Clean(target)) return err == nil && relative != "." && relative != ".." && !strings.HasPrefix(relative, ".."+string(filepath.Separator)) } func safeExtractionPathSegment(value string) bool { return value != "" && value != "." && value != ".." && filepath.Base(value) == value && !strings.ContainsAny(value, `/\\`) } func extractionMetadataString(metadata map[string]any, key string) string { value, _ := metadata[key].(string) return strings.TrimSpace(value) } func extractionReceiptIdentity(metadata map[string]any) (string, string) { receipt, _ := metadata["receipt"].(map[string]any) return extractionMetadataString(receipt, "run_id"), extractionMetadataString(receipt, "pipeline_id") }