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