Skip to main content

internal/infra/pg/artifactstore.go

internal/infra/pg · 355 lines · 22 declarations · source

Declarations

const MaxArtifactBytes

const MaxArtifactBytes = 512 << 10

source

var ErrInvalidArtifact, ErrArtifactNotFound, ErrArtifactConflict and 1 more

var (
ErrInvalidArtifact = errors.New("invalid artifact request")
ErrArtifactNotFound = errors.New("artifact not found")
ErrArtifactConflict = errors.New("artifact version or identity conflict")
ErrArtifactCapacity = errors.New("artifact storage capacity exceeded")
)

source

type ArtifactStore

type ArtifactStore struct {
pool *pgxpool.Pool
schema Schema
}

source

func NewArtifactStore

func NewArtifactStore(pool *pgxpool.Pool, schema Schema) *ArtifactStore

source

type ArtifactPut

type ArtifactPut struct {
ID string `json:"id"`
ExpectedVersion string `json:"expected_version,omitempty"`
DataSubjectID string `json:"data_subject_id"`
Kind string `json:"kind"`
Name string `json:"name"`
Content ArtifactContent `json:"content"`
}

source

type ArtifactMetadata

type ArtifactMetadata struct {
ID string `json:"id"`
Version string `json:"version"`
DataSubjectID string `json:"data_subject_id"`
Kind string `json:"kind"`
Name string `json:"name"`
SourceObservationID string `json:"source_observation_id"`
Bytes int `json:"bytes"`
AuthoredBy string `json:"authored_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ExpiresAt time.Time `json:"expires_at"`
}

source

type ArtifactWrite

type ArtifactWrite struct {
ArtifactMetadata
Replayed bool `json:"replayed"`
}

source

type Artifact

type Artifact struct {
ArtifactMetadata
Content []byte `json:"content"`
}

source

type ArtifactPage

type ArtifactPage struct {
Artifacts []ArtifactMetadata `json:"artifacts"`
Next *RecordCursor `json:"next,omitempty"`
}

source

func artifactUUID

func artifactUUID(value string) (string, error)

source

func artifactDigest

func artifactDigest(r ArtifactPut) []byte

source

func artifactKey

func artifactKey(id string) [32]byte

source

func lockArtifact

func lockArtifact(ctx context.Context, tx pgx.Tx, schema Schema, scope, id string) error

source

const artifactColumns

const artifactColumns = `a.artifact_id::text,a.version::text,a.data_subject_id,a.kind,a.name,a.source_observation_id::text,
octet_length(a.content),a.authored_by::text,a.created_at,a.updated_at,o.retention_until`

source

const artifactFrom

const artifactFrom = ` FROM {schema}.agent_artifact a JOIN {schema}.observation o ON o.scope=a.scope AND o.observation_id=a.source_observation_id `

source

func artifactDest

func artifactDest(m *ArtifactMetadata) []any

source

func artifactFailure

func artifactFailure(err error) error

source

method ArtifactStore.Put

func (s *ArtifactStore) Put(ctx context.Context, scope, principal string, r ArtifactPut) (ArtifactWrite, error)

Put stores opaque bytes under one owner. Creation identities have erasure-safe tombstones; overwrites use versions and retain only the latest bytes, never an implicit content archive.

source

method ArtifactStore.Get

func (s *ArtifactStore) Get(ctx context.Context, scope, id, dataSubjectID string) (Artifact, error)

Get reads one artifact, optionally requiring it to belong to a named data subject.

Why the subject is a predicate and not a check afterwards

A credential opens a project, and a project holds every end user's objects. An application that serves many people through one credential therefore has nothing stopping it handing user A the object of user B — the credential permits it, so no amount of care in the application is a boundary, only a habit. Naming the subject puts the requirement in the statement that reads the row: a mismatch selects nothing, and the caller is told what it would be told about an object that does not exist, because to that caller it does not.

Absent, the behaviour is what it always was, which is what the frozen contract requires.

source

type ArtifactFilter

type ArtifactFilter struct {
Kind string
NamePrefix string
}

source

method ArtifactStore.List

func (s *ArtifactStore) List(ctx context.Context, scope, subject, after string, limit int, filters ...ArtifactFilter) (ArtifactPage, error)

source

method ArtifactStore.Delete

func (s *ArtifactStore) Delete(ctx context.Context, scope, principal, id, version, dataSubjectID string) error

Delete removes one artifact, optionally requiring it to belong to a named data subject. The subject is a predicate for the reason it is one on Get: deleting another person's object is the same mistake, already spent.

source