97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
package contracts
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
)
|
|
|
|
// ArtifactKind is the stable logical identity of a domain artifact.
|
|
type ArtifactKind string
|
|
|
|
// ArtifactSchema describes the durable representation owned by an artifact
|
|
// codec. JSONSchema is cloned whenever framework ownership changes.
|
|
type ArtifactSchema struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Version string `json:"version"`
|
|
JSONSchema []byte `json:"-"`
|
|
}
|
|
|
|
// SerializedArtifact is the domain-neutral representation of a typed
|
|
// artifact at an explicit serialization boundary.
|
|
type SerializedArtifact struct {
|
|
Kind ArtifactKind `json:"kind"`
|
|
Schema ArtifactSchema `json:"schema"`
|
|
MediaType string `json:"media_type"`
|
|
Content []byte `json:"-"`
|
|
Metadata map[string]any `json:"metadata,omitempty"`
|
|
}
|
|
|
|
// SerializedOutput associates a domain-neutral artifact with the pipeline
|
|
// operation that produced it. Provenance remains outside codec-owned bytes.
|
|
type SerializedOutput struct {
|
|
StepID string `json:"step_id,omitempty"`
|
|
LaneID string `json:"lane_id"`
|
|
NormalizerKey string `json:"normalizer_key"`
|
|
SourceID string `json:"source_id,omitempty"`
|
|
Artifact SerializedArtifact `json:"artifact"`
|
|
}
|
|
|
|
// ArtifactCodec owns the stable encoding for one concrete artifact type.
|
|
type ArtifactCodec[T any] interface {
|
|
Kind() ArtifactKind
|
|
Schema() ArtifactSchema
|
|
MediaType() string
|
|
// EncodeCandidate serializes a stage result before semantic validation. It
|
|
// must not apply validity checks owned by typed validators; Encode remains
|
|
// the strict final-artifact boundary used after validation succeeds.
|
|
EncodeCandidate(T) ([]byte, error)
|
|
Encode(T) ([]byte, error)
|
|
Decode([]byte) (T, error)
|
|
}
|
|
|
|
// DigestArtifactSchema returns the SHA-256 digest of the exact JSON Schema
|
|
// bytes. Schema formatting is therefore part of the registered identity.
|
|
func DigestArtifactSchema(schema ArtifactSchema) string {
|
|
sum := sha256.Sum256(schema.JSONSchema)
|
|
return "sha256:" + hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func CloneArtifactSchema(schema ArtifactSchema) ArtifactSchema {
|
|
schema.JSONSchema = append([]byte(nil), schema.JSONSchema...)
|
|
return schema
|
|
}
|
|
|
|
func CloneSerializedArtifact(artifact SerializedArtifact) SerializedArtifact {
|
|
artifact.Schema = CloneArtifactSchema(artifact.Schema)
|
|
artifact.Content = append([]byte(nil), artifact.Content...)
|
|
artifact.Metadata = cloneArtifactMetadata(artifact.Metadata)
|
|
return artifact
|
|
}
|
|
|
|
// CloneSerializedArtifactPointer returns an independently owned artifact when
|
|
// one is present.
|
|
func CloneSerializedArtifactPointer(artifact *SerializedArtifact) *SerializedArtifact {
|
|
if artifact == nil {
|
|
return nil
|
|
}
|
|
cloned := CloneSerializedArtifact(*artifact)
|
|
return &cloned
|
|
}
|
|
|
|
func CloneSerializedOutput(output SerializedOutput) SerializedOutput {
|
|
output.Artifact = CloneSerializedArtifact(output.Artifact)
|
|
return output
|
|
}
|
|
|
|
func cloneArtifactMetadata(metadata map[string]any) map[string]any {
|
|
if len(metadata) == 0 {
|
|
return nil
|
|
}
|
|
out := make(map[string]any, len(metadata))
|
|
for key, value := range metadata {
|
|
out[key] = value
|
|
}
|
|
return out
|
|
}
|