postgres

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: MPL-2.0 Imports: 36 Imported by: 0

Documentation

Overview

Package postgres persists the domain aggregates.

Depends on the domain, never the reverse, and never on a wire model. Tenant isolation is enforced by row-level security driven by a per-request SET LOCAL inside a transaction — see docs/architecture.md.

Index

Constants

View Source
const (
	ScanRunSucceeded = "succeeded"
	ScanRunFailed    = "failed"
)
View Source
const (
	ScannerStateDisabled    = "disabled"
	ScannerStateOK          = "ok"
	ScannerStateDegraded    = "degraded"
	ScannerStateAuditPaused = "audit_paused"
)

Variables

View Source
var (
	// ErrChannelExists lets the compatibility adapter distinguish the probed
	// AlreadyExists response from other channel conflicts.
	ErrChannelExists = errors.New("channel already exists")
	// ErrManagedChannel lets the adapter preserve the assign endpoint's probed
	// refusal shape even when the repository guard is the layer that fires.
	ErrManagedChannel = errors.New("cannot assign to managed channel")
)
View Source
var (
	ErrObjectStorageNotConfigured = errors.New("object storage is not configured")
	ErrObjectStorageUnavailable   = errors.New("object storage is unavailable")
)
View Source
var (
	ErrPluginBundleImportBusy     = errors.New("plugin bundle import is already queued or running")
	ErrPluginBundleImportNotFound = errors.New("plugin bundle import not found")
)
View Source
var (
	ErrPluginBundleBusy     = errors.New("plugin bundle export is already queued or running")
	ErrPluginBundleNotFound = errors.New("plugin bundle export not found")
)
View Source
var (
	ErrPluginRegistryAlreadyEnabled = errors.New("plugin registry already enabled")
	ErrPluginRegistryNotEnabled     = errors.New("plugin registry not enabled")
	ErrPluginRegistryAlreadyExposed = errors.New("plugin registry already exposed")
	ErrPluginRegistryNotExposed     = errors.New("plugin registry not exposed")
	ErrPluginRegistryStillExposed   = errors.New("plugin registry still exposed")
)
View Source
var (
	ErrPluginVersionExists = errors.New("plugin version already exists")
	ErrPluginSourceHeld    = errors.New("plugin name is held by another source")
)
View Source
var (
	ErrPluginVersionRevoked    = errors.New("plugin version already revoked")
	ErrPluginVersionNotRevoked = errors.New("plugin version not revoked")
)
View Source
var ErrPluginImportRunning = errors.New("plugin import is running")

ErrPluginImportRunning refuses to clear a job a worker holds.

View Source
var ErrPluginUploadHasNoUpdates = errors.New("an uploaded plugin has no upstream to check for updates")

ErrPluginUploadHasNoUpdates refuses update checks on an uploaded plugin, which has no upstream to ask (ADR-0027 A6).

View Source
var ErrScanIneligible = errors.New("build is not in the current scan set")
View Source
var ErrScanRunRefused = errors.New("scan run refused: the build changed during the scan")

ErrScanRunRefused reports a completion recorded as failed because the build's inventory or status changed while the scan ran.

Functions

func AssertRLSApplies

func AssertRLSApplies(ctx context.Context, db *sql.DB) error

AssertRLSApplies refuses to serve as a role that row-level security cannot constrain.

FORCE ROW LEVEL SECURITY covers the table owner, but NOT a superuser and not a role holding BYPASSRLS. Connecting as either — pointing DFBG_DATABASE_URL at the stock `postgres` user is the commonest way — silently disables every tenancy policy: every tenant sees every tenant, nothing errors, nothing logs, and the isolation tests still pass because they create their own unprivileged role.

ADR-0017 requires misconfiguration to fail closed. This one fails silently OPEN, which is why it is checked at startup rather than left to be noticed.

func BeginOrganizationTenant added in v0.5.0

func BeginOrganizationTenant(ctx context.Context, db *sql.DB, organizationID string) (*sql.Tx, error)

BeginOrganizationTenant starts a transaction scoped to one organization. Project and bucket settings are cleared so project-scoped policies match no row.

func BeginTenant

func BeginTenant(ctx context.Context, db *sql.DB, organizationID, projectID, bucketID string) (*sql.Tx, error)

BeginTenant starts a transaction whose RLS scope cannot escape to the pool. bucketID narrows the scope to one bucket; empty means the whole project. Every caller states it so an unscoped transaction is a visible decision, not a forgotten argument.

func InventoryDigest added in v0.4.2

func InventoryDigest(inventory scan.Inventory) string

InventoryDigest identifies exactly which package rows a scan examined, so a run can be refused at completion if the build's inventory moved under it.

func InventoryDigestTx added in v0.4.2

func InventoryDigestTx(ctx context.Context, tx *sql.Tx, buildID string) (string, error)

InventoryDigestTx digests the build's live inventory inside the caller's transaction; it is the completion-time half of the run binding.

func Migrate

func Migrate(db *sql.DB) error

Migrate applies all known schema migrations.

func PluginNameOf added in v0.5.0

func PluginNameOf(product string) string

PluginNameOf is the plugin a product names: packer-plugin-amazon and acme/packer-plugin-amazon are both amazon; an uploaded plugin's product is its name already.

Types

type AncestryVersion

type AncestryVersion struct {
	ID          registry.ID
	BucketName  string
	Fingerprint string
	Sequence    int
}

AncestryVersion is the version identity needed by the ancestry projection.

type Artifact

type Artifact struct {
	ID                 registry.ID
	BuildID            registry.ID
	ExternalIdentifier string
	Region             string
	CreatedAt          time.Time
}

Artifact is one external artifact recorded for a build.

type Bucket

type Bucket struct {
	ID                  registry.ID
	Name                string
	Description         string
	Labels              map[string]string
	LatestVersion       *registry.Version
	LatestVersionBuilds []StoredBuild
	ChildrenStatus      *registry.AncestryStatus
	Platforms           []string
	CreatedAt           time.Time
	UpdatedAt           time.Time
}

Bucket is the persisted bucket metadata used by the API adapters.

type BucketAncestry

type BucketAncestry struct {
	Parent               AncestryVersion
	ParentChannelName    string
	ParentChannelVersion *AncestryVersion
	Child                AncestryVersion
}

BucketAncestry is one parent-child relationship recorded by a child build.

type BuildAdvisory added in v0.4.2

type BuildAdvisory struct {
	Identifier    string
	Severity      scan.Severity
	Summary       string
	Aliases       []string
	Published     *time.Time
	FixedVersions []string
	Packages      []BuildAdvisoryPackage
}

BuildAdvisory groups every affected SBOM package report for one advisory.

type BuildAdvisoryPackage added in v0.4.2

type BuildAdvisoryPackage struct {
	Name         string
	Version      string
	Purl         string
	SBOMID       string
	FixedVersion string
	// Reported is the provider's verbatim severity value, kept beside the
	// derived band because the scales are not comparable across providers.
	Reported string
}

BuildAdvisoryPackage is one affected package report in one SBOM.

type BuildFindings added in v0.4.2

type BuildFindings struct {
	Inventory        string
	PackagesTotal    int
	Scanned          bool
	Run              *ScanRun
	LatestAttempt    *ScanAttempt
	PackagesAffected int
	Advisories       []BuildAdvisory
}

BuildFindings is one build's package inventory state and current verified scan findings.

type BuildFindingsSummary added in v0.4.2

type BuildFindingsSummary struct {
	RunID            string
	Scanned          int
	Findings         int
	AffectedPackages int
	Worst            scan.Severity
	Counts           SeverityCounts
	ObservedAt       time.Time
	Adapter          string
	Engine           string
	DatabaseRevision string
	Coverage         scan.Coverage
}

BuildFindingsSummary is one build's current verified findings summary.

type BuildPackageFilter added in v0.4.2

type BuildPackageFilter struct {
	Name       string
	NamePrefix string
	Version    string
}

type BuildScanState

type BuildScanState struct {
	BuildID              string
	CurrentFindingsRunID string
	LatestAttemptRunID   string
}

BuildScanState carries the per-build currency pointers.

type Channel

type Channel struct {
	ID         registry.ID
	BucketName string
	Name       string
	Restricted bool
	// Managed marks a channel the service itself maintains — the per-bucket
	// "latest" that CreateBucket brings into existence and version completion
	// assigns to (dossier §7, Appendix A probes 04-06, 13-14). The compat
	// handler refuses client mutation of managed channels.
	Managed bool
	Version *registry.Version
	// AssignmentAuthorID comes from the current immutable assignment row.
	AssignmentAuthorID string
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

Channel is a named pointer to the latest version assigned to it.

type ChannelAssignment

type ChannelAssignment struct {
	ID         registry.ID
	ChannelID  registry.ID
	Version    *registry.Version
	AuthorID   string
	AssignedAt time.Time
}

ChannelAssignment is one immutable channel assignment.

type ClaimedPluginBundle added in v0.5.0

type ClaimedPluginBundle struct {
	Tenant            OrganizationTenant
	OrganizationName  string
	RequestedHost     string
	CreatedAt         time.Time
	PreviousObjectKey string
}

ClaimedPluginBundle is an export a worker now owns.

type ClaimedPluginBundleImport added in v0.5.0

type ClaimedPluginBundleImport struct {
	Tenant OrganizationTenant
	Upload PluginBundleUpload
}

ClaimedPluginBundleImport is an import a worker now owns.

type ClaimedPluginImport added in v0.5.0

type ClaimedPluginImport struct {
	Tenant  OrganizationTenant
	ID      uuid.UUID
	Request PluginImportRequest
}

ClaimedPluginImport is a job a worker now owns.

type ClaimedPluginPrune added in v0.5.0

type ClaimedPluginPrune struct {
	Tenant   OrganizationTenant
	AgeDays  int
	Schedule string
}

ClaimedPluginPrune is a run a worker now owns.

type ClaimedPluginUpdateCheck added in v0.5.0

type ClaimedPluginUpdateCheck struct {
	Tenant OrganizationTenant
	ID     uuid.UUID
	Name   string
	Source PluginSource
}

ClaimedPluginUpdateCheck is a plugin whose update check a checker now owns.

type ExportablePlugin added in v0.5.0

type ExportablePlugin struct {
	Name     string
	Source   PluginSource
	Versions []ExportablePluginVersion
}

ExportablePlugin is one plugin with at least one non-revoked version.

type ExportablePluginFile added in v0.5.0

type ExportablePluginFile struct {
	Filename  string
	OS        string
	Arch      string
	SHA256    string
	Size      int64
	ObjectKey string
}

ExportablePluginFile is one object included in a bundle.

type ExportablePluginVersion added in v0.5.0

type ExportablePluginVersion struct {
	Version   string
	Sums      ExportablePluginFile
	Signature *ExportablePluginFile
	Manifest  *ExportablePluginFile
	Zips      []ExportablePluginFile
}

ExportablePluginVersion is one non-revoked stored version.

type ExternalArtifactMatch

type ExternalArtifactMatch struct {
	Bucket  Bucket
	Build   StoredBuild
	Version *registry.Version
}

ExternalArtifactMatch is the registry context for one matching build artifact.

type HeldSourceError added in v0.5.0

type HeldSourceError struct {
	Source PluginSource
}

HeldSourceError names the source already holding a plugin name.

func (HeldSourceError) Error added in v0.5.0

func (e HeldSourceError) Error() string

func (HeldSourceError) Unwrap added in v0.5.0

func (e HeldSourceError) Unwrap() error

type Organization

type Organization struct {
	ID        string
	Name      string
	CreatedAt time.Time
}

Organization is a tenancy root.

type OrganizationTenant added in v0.5.0

type OrganizationTenant struct {
	OrganizationID uuid.UUID
	// contains filtered or unexported fields
}

OrganizationTenant is the RLS scope for organization-level repository operations.

func ParseOrganizationTenant added in v0.5.0

func ParseOrganizationTenant(organizationID string) OrganizationTenant

type Pin

type Pin struct {
	BucketName string
	PinnedAt   time.Time
	PinnedBy   string
}

Pin is shared project presentation state for one bucket.

type PluginBlob added in v0.5.0

type PluginBlob struct {
	Filename string
	SHA256   string
	Body     io.ReadSeeker
	Size     int64
}

PluginBlob is one file of a version, readable more than once.

type PluginBundle added in v0.5.0

type PluginBundle struct {
	State       string
	RequestedBy string
	CreatedAt   time.Time
	StartedAt   *time.Time
	FinishedAt  *time.Time
	Error       string
	Bundle      *PluginBundleResult
}

PluginBundle is the current export job and its last successful archive.

type PluginBundleImport added in v0.5.0

type PluginBundleImport struct {
	State       string
	RequestedBy string
	Upload      PluginBundleUpload
	CreatedAt   time.Time
	StartedAt   *time.Time
	FinishedAt  *time.Time
	Error       string
	Origin      PluginBundleOrigin
	Outcomes    json.RawMessage
}

PluginBundleImport is the current import job and its outcome.

type PluginBundleOrigin added in v0.5.0

type PluginBundleOrigin struct {
	Host         string
	Organization string
	ExportedAt   *time.Time
	Version      string
	PluginCount  int
	VersionCount int
}

PluginBundleOrigin is what the imported bundle's manifest said about itself.

type PluginBundleResult added in v0.5.0

type PluginBundleResult struct {
	ExportedAt   time.Time
	ObjectKey    string
	Filename     string
	Size         int64
	SHA256       string
	PluginCount  int
	VersionCount int
}

PluginBundleResult describes one stored bundle archive.

type PluginBundleUpload added in v0.5.0

type PluginBundleUpload struct {
	ObjectKey string
	Filename  string
	Size      int64
	SHA256    string
}

PluginBundleUpload is an uploaded bundle waiting in object storage.

type PluginChange added in v0.5.0

type PluginChange struct {
	Version   string   `json:"version"`
	Action    string   `json:"action"`
	Platforms []string `json:"platforms,omitempty"`
}

PluginChange is one change a sync applies to one version.

type PluginDownloadWindows added in v0.5.0

type PluginDownloadWindows struct {
	Last7Days   int64
	Last30Days  int64
	Last365Days int64
	AllTime     int64
}

PluginDownloadWindows counts completed zip serves in rolling UTC windows.

type PluginDownloads added in v0.5.0

type PluginDownloads struct {
	Today       time.Time
	AllVersions PluginDownloadWindows
	Versions    []PluginVersionDownloads
}

PluginDownloads is one plugin's download aggregate.

type PluginFileKind added in v0.5.0

type PluginFileKind int

PluginFileKind names which of a version's files a read asks for.

const (
	ServedSums PluginFileKind = iota
	ServedSignature
	ServedManifest
	ServedZip
)

type PluginImport added in v0.5.0

type PluginImport struct {
	ID          uuid.UUID
	Plugin      string
	Request     PluginImportRequest
	Origin      PluginImportOrigin
	State       string
	Outcomes    json.RawMessage
	CreatedAt   time.Time
	StartedAt   *time.Time
	FinishedAt  *time.Time
	QueuedAhead int
}

PluginImport is a recorded import job.

type PluginImportFilter added in v0.5.0

type PluginImportFilter struct {
	States  []string
	Plugins []string
	Limit   int
	Offset  int
}

PluginImportFilter narrows a job listing. Empty States or Plugins means every one.

type PluginImportOrigin added in v0.5.0

type PluginImportOrigin struct {
	CreatedBy  string
	Kind       string
	BatchIndex int
	BatchSize  int
	RetryOf    *uuid.UUID
}

PluginImportOrigin is who queued a job and from where: an import form, a plugin's page, the catalogue's Sync selected (one job of a batch), or an upload.

type PluginImportRequest added in v0.5.0

type PluginImportRequest struct {
	SourceKind string
	Product    string
	Versions   []string
	Platforms  []string
	Changes    []PluginChange
}

PluginImportRequest is what an operator asked an import to do: mirror versions on the given platforms, or apply an ordered list of changes.

type PluginPrune added in v0.5.0

type PluginPrune struct {
	Enabled          bool
	AgeDays          int
	Schedule         string
	NextAt           *time.Time
	LastRunAt        *time.Time
	LastCleared      int
	LastError        string
	WouldClear       int
	Unfinished       int
	Kept             int
	OldestFinishedAt *time.Time
}

PluginPrune is an organization's job-pruning schedule and what a run would do now: WouldClear counts the finished jobs older than the age limit.

type PluginRegistry added in v0.5.0

type PluginRegistry struct {
	Enabled bool
	Exposed bool
}

PluginRegistry is the organization registry lifecycle state.

type PluginSource added in v0.5.0

type PluginSource struct {
	Kind       string
	Repository string
}

PluginSource is where a plugin's versions come from (ADR-0027 A2).

type PluginSummary added in v0.5.0

type PluginSummary struct {
	Name              string
	Source            PluginSource
	PublishedVersions []string
	StoredVersions    []string
	Update            PluginUpdateCheck
}

PluginSummary is one plugin in an organization's catalogue.

type PluginUpdateAvailable added in v0.5.0

type PluginUpdateAvailable struct {
	Plugin       string             `json:"plugin"`
	Source       PluginUpdateSource `json:"source"`
	Latest       string             `json:"latest"`
	Tag          string             `json:"tag,omitempty"`
	NewestStored string             `json:"newest_stored,omitempty"`
}

PluginUpdateAvailable is the payload of a plugin.update_available event.

type PluginUpdateCheck added in v0.5.0

type PluginUpdateCheck struct {
	Enabled   bool
	CheckedAt *time.Time
	Error     string
	Latest    string
	LatestTag string
}

PluginUpdateCheck is a plugin's update-check setting and its last result (ADR-0027 A6). Latest is the newest stable upstream version seen.

type PluginUpdateSource added in v0.5.0

type PluginUpdateSource struct {
	Kind       string `json:"kind"`
	Repository string `json:"repository,omitempty"`
}

PluginUpdateSource is where an update was seen.

type PluginVersionDownloads added in v0.5.0

type PluginVersionDownloads struct {
	PluginDownloadWindows
	Version string
	State   string
}

PluginVersionDownloads is one version's windows and current state.

type PluginVersionInput added in v0.5.0

type PluginVersionInput struct {
	Name      string
	Version   string
	Source    PluginSource
	Protocol  string
	Listed    []string
	Sums      PluginBlob
	Signature *PluginBlob
	Manifest  *PluginBlob
	Zips      []PluginZip
}

PluginVersionInput is a verified version ready to persist. Protocol is set only when the registry must render the manifest Packer will request.

type PluginVersionSummary added in v0.5.0

type PluginVersionSummary struct {
	Version   string
	Revoked   bool
	Listed    []string
	Stored    []string
	CreatedAt time.Time
}

PluginVersionSummary is one version with the platforms its sums list and the platforms the registry holds zips for.

type PluginZip added in v0.5.0

type PluginZip struct {
	PluginBlob
	OS   string
	Arch string
}

PluginZip is a stored zip and the platform it serves.

type Project

type Project struct {
	ID             string
	OrganizationID string
	Name           string
	CreatedAt      time.Time
}

Project is one tenant within an organization.

type ReportedPackage

type ReportedPackage struct {
	Name           string
	Version        string
	Purl           string
	Licenses       []string
	ComponentPaths [][]string
	Sboms          []Sbom
}

ReportedPackage is package inventory asserted by one or more client-supplied SBOMs. Dufflebag parses and attributes it but does not verify it against the image, matching the treatment of forwarded_for and ancestry input.

type Repository

type Repository struct {
	// contains filtered or unexported fields
}

Repository persists registry aggregates in tenant-scoped transactions.

func NewRepository

func NewRepository(db *sql.DB) *Repository

func NewRepositoryWithObjectStore

func NewRepositoryWithObjectStore(db *sql.DB, objects *objectstore.Store) *Repository

NewRepositoryWithObjectStore enables the object-only SBOM store configured by the deployment. A repository without one refuses SBOM transfers.

func (*Repository) AddPluginZips added in v0.5.0

func (r *Repository) AddPluginZips(
	ctx context.Context, tenant OrganizationTenant, name, version string, zips []PluginZip,
) error

AddPluginZips adds verified zips to an existing version (ADR-0027 A7). Blobs land before rows, as for a new version.

func (*Repository) AllocateScanRunSequence

func (r *Repository) AllocateScanRunSequence(ctx context.Context, tenant Tenant) (int64, error)

AllocateScanRunSequence reserves the run's ordering position before any provider egress, so an attempt that dies mid-flight cannot reuse it.

func (*Repository) AssignChannelVersion

func (r *Repository) AssignChannelVersion(
	ctx context.Context,
	tenant Tenant,
	bucketName, sourceName, targetName, authorID string,
	at time.Time,
) (*Channel, *Channel, error)

func (*Repository) BagDropBucketExists

func (r *Repository) BagDropBucketExists(
	ctx context.Context, organizationID, projectID, bucketName string,
) (bool, error)

func (*Repository) ClaimPluginBundle added in v0.5.0

func (r *Repository) ClaimPluginBundle(ctx context.Context, stale time.Duration) (*ClaimedPluginBundle, error)

ClaimPluginBundle hands one queued or stale export to the caller.

func (*Repository) ClaimPluginBundleImport added in v0.5.0

func (r *Repository) ClaimPluginBundleImport(ctx context.Context, stale time.Duration) (*ClaimedPluginBundleImport, error)

ClaimPluginBundleImport hands one queued or stale import to the caller.

func (*Repository) ClaimPluginImport added in v0.5.0

func (r *Repository) ClaimPluginImport(ctx context.Context, stale time.Duration) (*ClaimedPluginImport, error)

ClaimPluginImport hands the next queued job, or one whose worker stopped reporting for stale, to the caller. Organizations carry no RLS, so they are enumerated and each is claimed from inside its own tenant, as the scanner claims per project (ScannerService.claimNextForTenant). SKIP LOCKED keeps two workers, or two replicas, off the same job.

func (*Repository) ClaimPluginPrune added in v0.5.0

func (r *Repository) ClaimPluginPrune(ctx context.Context) (*ClaimedPluginPrune, error)

ClaimPluginPrune hands one organization whose run is due to the caller and stamps it run in the same transaction, so replicas never prune one organization twice. The claim also leases the next run an hour out, so a run that dies before recording fires again rather than never. Organizations are enumerated as ClaimPluginImport does.

func (*Repository) ClaimPluginUpdateCheck added in v0.5.0

func (r *Repository) ClaimPluginUpdateCheck(
	ctx context.Context, interval time.Duration, includeGitHub bool,
) (*ClaimedPluginUpdateCheck, error)

ClaimPluginUpdateCheck hands the next plugin due a check to the caller and stamps it checked in the same transaction, so replicas never check one plugin twice in an interval. Organizations are enumerated as ClaimPluginImport does.

func (*Repository) CountBuildPackages added in v0.4.2

func (r *Repository) CountBuildPackages(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID string,
	filter BuildPackageFilter,
) (int, []string, error)

CountBuildPackages validates and counts the filtered package projection. Current uploads parse before commit, so pending can only be compatibility residue written by the preceding release. Its Postgres bytes are deliberately abandoned and the row receives an honest terminal state.

func (*Repository) CountPluginDownload added in v0.5.0

func (r *Repository) CountPluginDownload(
	ctx context.Context, tenant OrganizationTenant, pluginID uuid.UUID, version, platform string, day time.Time,
) error

CountPluginDownload records one completed plugin zip serve.

func (*Repository) CreateAuditTarget

func (r *Repository) CreateAuditTarget(
	ctx context.Context,
	id string,
	path string,
	createdAt time.Time,
) (identity.AuditTarget, error)

CreateAuditTarget writes a target into the lowest free slot.

The advisory lock serializes slot selection, so two concurrent creates cannot read the same free slot. It is held for the transaction, and the transaction does nothing but this insert, so the contention window is a single statement on a table of at most three rows.

No retry. An earlier version retried a full table three times, on the theory that a concurrent delete might free a slot — but delete does not take this lock, so three immediate attempts bore no relation to when a delete would commit. It was a loop that could only turn a truthful conflict into a slower truthful conflict. A caller that wants a slot freed deletes one and asks again.

func (*Repository) CreateBucket

func (r *Repository) CreateBucket(ctx context.Context, tenant Tenant, bucket Bucket) (*Bucket, error)

func (*Repository) CreateBuild

func (r *Repository) CreateBuild(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
	templateType registry.TemplateType,
	build StoredBuild,
	versionName func(*registry.Version) string,
) (*StoredBuild, error)

func (*Repository) CreateChannel

func (r *Repository) CreateChannel(
	ctx context.Context,
	tenant Tenant,
	channel Channel,
	versionFingerprint, authorID string,
) (*Channel, error)

func (*Repository) CreateKeyringEntries

func (r *Repository) CreateKeyringEntries(ctx context.Context, entries []keyring.Entry, at time.Time) (bool, error)

CreateKeyringEntries stores a freshly generated keyring in one transaction. It reports false — writing nothing — when any entry already exists: another replica won the first-boot race, and the caller must load that keyring instead of serving with its own losing copy.

func (*Repository) CreateOrganization

func (r *Repository) CreateOrganization(
	ctx context.Context,
	organization Organization,
) (*Organization, error)

func (*Repository) CreatePluginImport added in v0.5.0

func (r *Repository) CreatePluginImport(
	ctx context.Context, tenant OrganizationTenant, request PluginImportRequest, origin PluginImportOrigin,
) (uuid.UUID, error)

CreatePluginImport queues an import. The registry must be enabled.

func (*Repository) CreatePrincipal

func (r *Repository) CreatePrincipal(ctx context.Context, principal *identity.Principal) error

CreatePrincipal persists a principal and all of its active secrets atomically.

func (*Repository) CreateProject

func (r *Repository) CreateProject(ctx context.Context, project Project) (*Project, error)

func (*Repository) CreateVersion

func (r *Repository) CreateVersion(
	ctx context.Context,
	tenant Tenant,
	version *registry.Version,
) (*registry.Version, error)

func (*Repository) CreateWebhook

func (r *Repository) CreateWebhook(ctx context.Context, record webhook.Record) (*webhook.Record, error)

func (*Repository) DeleteAuditTarget

func (r *Repository) DeleteAuditTarget(ctx context.Context, id string) error

DeleteAuditTarget removes a target, freeing its slot for the next create.

func (*Repository) DeleteBagDropAssociation

func (r *Repository) DeleteBagDropAssociation(
	ctx context.Context, organizationID, projectID, bucketName string,
) error

func (*Repository) DeleteBagDropConfig

func (r *Repository) DeleteBagDropConfig(
	ctx context.Context, organizationID, projectID string,
) error

func (*Repository) DeleteBucket

func (r *Repository) DeleteBucket(ctx context.Context, tenant Tenant, name string) error

DeleteBucket removes a bucket and everything under it.

Versions, builds, artifacts, channels and the sboms follow by cascade, and the baseline trigger lets the cascade through the append-only guard on channel_assignments. Unassignment markers (rows with no version) are left behind deliberately: like history for a deleted channel, they outlive what they describe, and nothing lists them once the channel is gone.

func (*Repository) DeleteBuild

func (r *Repository) DeleteBuild(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID string,
) error

DeleteBuild removes one build aggregate without changing the parent version's completion, sequence, or revocation state.

func (*Repository) DeleteChannel

func (r *Repository) DeleteChannel(
	ctx context.Context,
	tenant Tenant,
	bucketName, channelName string,
) error

func (*Repository) DeleteOrganization

func (r *Repository) DeleteOrganization(ctx context.Context, id string) error

func (*Repository) DeletePin

func (r *Repository) DeletePin(ctx context.Context, tenant Tenant, bucketName string) error

func (*Repository) DeletePluginBundleObject added in v0.5.0

func (r *Repository) DeletePluginBundleObject(ctx context.Context, _ OrganizationTenant, key string) error

DeletePluginBundleObject removes a replaced bundle archive.

func (*Repository) DeletePluginImport added in v0.5.0

func (r *Repository) DeletePluginImport(ctx context.Context, tenant OrganizationTenant, id uuid.UUID) error

DeletePluginImport clears a job that is not running: one statement, so a job claimed between the read and the delete is kept.

func (*Repository) DeletePluginVersion added in v0.5.0

func (r *Repository) DeletePluginVersion(ctx context.Context, tenant OrganizationTenant, name, version string) error

DeletePluginVersion removes one version and its files. Removing a plugin's last version removes the plugin, which frees its name for another source (ADR-0027 A8).

func (*Repository) DeletePrincipal

func (r *Repository) DeletePrincipal(ctx context.Context, principalID string) error

DeletePrincipal removes a principal. Root deletion takes a transaction-scoped advisory lock before counting and deleting, making "at least one root remains" one serialized decision across concurrent requests and server instances.

func (*Repository) DeleteProject

func (r *Repository) DeleteProject(ctx context.Context, organizationID, projectID string) error

func (*Repository) DeleteVersion

func (r *Repository) DeleteVersion(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
	at time.Time,
) error

DeleteVersion removes a version aggregate after refusing any current user channel assignment. The managed latest channel is re-pointed using the same newest-valid assignment selection as revocation rollback.

func (*Repository) DeleteWebhook

func (r *Repository) DeleteWebhook(ctx context.Context, organizationID, projectID, webhookID string) error

func (*Repository) DeleteWebhookOutboxEvent

func (r *Repository) DeleteWebhookOutboxEvent(ctx context.Context, project webhook.Project, eventID string) error

func (*Repository) DisablePluginRegistry added in v0.5.0

func (r *Repository) DisablePluginRegistry(ctx context.Context, tenant OrganizationTenant) error

DisablePluginRegistry removes the registry and everything in it. The row lock holds off a concurrent expose until the rows are gone; blobs follow the commit so a failure can only orphan them.

func (*Repository) DownloadSbom

func (r *Repository) DownloadSbom(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID, name string,
) ([]byte, error)

DownloadSbom retrieves one document's bytes from object storage.

func (*Repository) EnablePluginRegistry added in v0.5.0

func (r *Repository) EnablePluginRegistry(
	ctx context.Context, tenant OrganizationTenant,
) (PluginRegistry, error)

func (*Repository) EncryptionMode

func (r *Repository) EncryptionMode(ctx context.Context) (recorded, encrypted bool, err error)

EncryptionMode reads the stored mode marker. recorded=false means no boot has stamped one yet.

func (*Repository) ExpireScanTranscripts

func (r *Repository) ExpireScanTranscripts(ctx context.Context, tenant Tenant, now time.Time, limit int) (int, error)

ExpireScanTranscripts deletes transcript objects and locators past the seven-day window, bounded per call. The run row keeps its digest forever.

func (*Repository) ExportablePluginVersions added in v0.5.0

func (r *Repository) ExportablePluginVersions(ctx context.Context, tenant OrganizationTenant) ([]ExportablePlugin, error)

ExportablePluginVersions returns every non-revoked stored version.

func (*Repository) ExposePluginRegistry added in v0.5.0

func (r *Repository) ExposePluginRegistry(
	ctx context.Context, tenant OrganizationTenant,
) (PluginRegistry, error)

func (*Repository) GetBagDropBucketSnapshot

func (r *Repository) GetBagDropBucketSnapshot(
	ctx context.Context, organizationID, projectID, bucketName string,
) (*bagdrop.BucketSnapshot, error)

func (*Repository) GetBagDropConfig

func (r *Repository) GetBagDropConfig(
	ctx context.Context, organizationID, projectID string,
) (*bagdrop.Record, error)

func (*Repository) GetBucket

func (r *Repository) GetBucket(ctx context.Context, tenant Tenant, name string) (*Bucket, error)

func (*Repository) GetBucketWithLatestVersion

func (r *Repository) GetBucketWithLatestVersion(
	ctx context.Context,
	tenant Tenant,
	name string,
) (*Bucket, error)

func (*Repository) GetBuild

func (r *Repository) GetBuild(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID string,
) (*StoredBuild, error)

func (*Repository) GetBuildFindings added in v0.4.2

func (r *Repository) GetBuildFindings(
	ctx context.Context, tenant Tenant, bucketName, fingerprint, buildID string,
) (*BuildFindings, error)

GetBuildFindings reads a build, inventory state and current findings in one tenant transaction. Every run, pointer and finding row is MAC verified.

func (*Repository) GetBuildScanState

func (r *Repository) GetBuildScanState(ctx context.Context, tenant Tenant, buildID string) (*BuildScanState, error)

GetBuildScanState returns the verified pointer row, or nil when the build has never been scanned.

func (*Repository) GetChannel

func (r *Repository) GetChannel(
	ctx context.Context,
	tenant Tenant,
	bucketName, channelName string,
) (*Channel, error)

func (*Repository) GetNextWebhookOutboxEvent

func (r *Repository) GetNextWebhookOutboxEvent(ctx context.Context, project webhook.Project, at time.Time) (*webhook.OutboxEvent, error)

func (*Repository) GetOrganization

func (r *Repository) GetOrganization(ctx context.Context, id string) (*Organization, error)

func (*Repository) GetPluginBundle added in v0.5.0

func (r *Repository) GetPluginBundle(ctx context.Context, tenant OrganizationTenant) (PluginBundle, error)

GetPluginBundle reads the current job and last successful archive.

func (*Repository) GetPluginBundleImport added in v0.5.0

func (r *Repository) GetPluginBundleImport(ctx context.Context, tenant OrganizationTenant) (PluginBundleImport, error)

GetPluginBundleImport reads the current import job.

func (*Repository) GetPluginImport added in v0.5.0

func (r *Repository) GetPluginImport(ctx context.Context, tenant OrganizationTenant, id uuid.UUID) (PluginImport, error)

GetPluginImport reads one job of the organization.

func (*Repository) GetPluginPrune added in v0.5.0

func (r *Repository) GetPluginPrune(ctx context.Context, tenant OrganizationTenant) (PluginPrune, error)

func (*Repository) GetPluginRegistry added in v0.5.0

func (r *Repository) GetPluginRegistry(
	ctx context.Context, tenant OrganizationTenant,
) (PluginRegistry, error)

func (*Repository) GetPrincipalByClientID

func (r *Repository) GetPrincipalByClientID(ctx context.Context, clientID string) (*identity.Principal, error)

GetPrincipalByClientID loads a principal before its tenant is known.

func (*Repository) GetPrincipalByID

func (r *Repository) GetPrincipalByID(ctx context.Context, id string) (*identity.Principal, error)

GetPrincipalByID loads a principal to resolve its authority.

Separate from GetPrincipalByClientID because the questions differ: that one authenticates a credential and must equalise timing against enumeration, this one resolves authority for an ALREADY authenticated caller, where the identifier came from a token we signed and its existence is not a secret.

Resolved per request rather than carried in the token, so revoking or lowering a role takes effect on the next request instead of at token expiry (ADR-0019).

func (*Repository) GetProject

func (r *Repository) GetProject(
	ctx context.Context,
	organizationID, projectID string,
) (*Project, error)

func (*Repository) GetSbom

func (r *Repository) GetSbom(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID, name string,
) (*Sbom, error)

GetSbom retrieves one document's metadata.

func (*Repository) GetScanRun

func (r *Repository) GetScanRun(ctx context.Context, tenant Tenant, runID string) (*ScanRun, error)

GetScanRun returns the verified run row.

func (*Repository) GetScanTranscript

func (r *Repository) GetScanTranscript(ctx context.Context, tenant Tenant, runID string) ([]byte, error)

GetScanTranscript returns the decompressed transcript bytes, verified against the run row's digest. It backs audit inspection and tests only — the findings API never serves transcripts.

func (*Repository) GetStoredPluginVersion added in v0.5.0

func (r *Repository) GetStoredPluginVersion(
	ctx context.Context, tenant OrganizationTenant, name, version string,
) (StoredPluginVersion, error)

GetStoredPluginVersion reads one version and its stored metadata files.

func (*Repository) GetVersion

func (r *Repository) GetVersion(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
) (*registry.Version, error)

func (*Repository) GetVersionFindingsSummary added in v0.4.2

func (r *Repository) GetVersionFindingsSummary(
	ctx context.Context, tenant Tenant, bucketName, fingerprint string,
) (*VersionFindingsSummaryResult, error)

GetVersionFindingsSummary returns verified stored summaries for one version.

func (*Repository) GetWebhook

func (r *Repository) GetWebhook(ctx context.Context, organizationID, projectID, webhookID string) (*webhook.Record, error)

func (*Repository) HasBlockingBagDropAssociations

func (r *Repository) HasBlockingBagDropAssociations(
	ctx context.Context, organizationID, projectID string,
) (bool, error)

func (*Repository) InitializeInstance

func (r *Repository) InitializeInstance(
	ctx context.Context,
	principal *identity.Principal,
	recoveryDigest []byte,
	recoveryThreshold int,
) error

InitializeInstance claims an uninitialized instance by creating its first platform root principal.

The instance table is a transaction-scoped singleton lock, not the claimed predicate. Once one caller holds it, root existence is checked and the root is written before the lock is released. A second caller then observes that root and refuses. The last root cannot be deleted through the API, so the predicate is a one-way door without tying initialization to tenant lifetime.

func (*Repository) InstanceStatus

func (r *Repository) InstanceStatus(
	ctx context.Context,
) (initialized bool, initializedAt *time.Time, database bool, err error)

InstanceStatus answers the unauthenticated health probe: whether the instance is claimed, and whether the database responds at all.

The failure reason stays server-side on the unauthenticated health path: the ping's error text carries host and driver detail (review finding 16).

func (*Repository) IssuePrincipalSecret

func (r *Repository) IssuePrincipalSecret(
	ctx context.Context, principalID, secretID string, expiresAt *time.Time, at time.Time,
) (string, identity.Secret, error)

IssuePrincipalSecret locks the principal while the domain checks and updates its active-secret set, so concurrent rotations cannot exceed the domain's two-secret limit.

func (*Repository) ListAuditTargets

func (r *Repository) ListAuditTargets(ctx context.Context) ([]identity.AuditTarget, error)

ListAuditTargets returns the configured targets in slot order.

Slot orders the result and is then discarded: it exists so a fourth target cannot be written (the baseline's three-slot constraint), not so a caller can reason about it.

func (*Repository) ListBagDropAssociations

func (r *Repository) ListBagDropAssociations(
	ctx context.Context, organizationID, projectID string,
) ([]bagdrop.Association, error)

func (*Repository) ListBagDropProjects

func (r *Repository) ListBagDropProjects(ctx context.Context) ([]bagdrop.Project, error)

ListBagDropProjects follows the scanner's privileged enumeration pattern: projects are globally enumerable system data, then each Bag Drop config is read through a tenant-scoped repository operation.

func (*Repository) ListBucketAncestry

func (r *Repository) ListBucketAncestry(
	ctx context.Context,
	tenant Tenant,
	bucketName, ancestryType, channelName, versionFingerprint string,
) ([]BucketAncestry, error)

ListBucketAncestry projects the parent identifiers Packer stored on builds.

func (*Repository) ListBuckets

func (r *Repository) ListBuckets(ctx context.Context, tenant Tenant) ([]Bucket, error)

func (*Repository) ListBuildPackages

func (r *Repository) ListBuildPackages(
	ctx context.Context,
	tenant Tenant,
	buildID string,
	filter BuildPackageFilter,
	offset, limit int,
) ([]ReportedPackage, error)

ListBuildPackages returns one ordered page of the flat package projection.

func (*Repository) ListBuilds

func (r *Repository) ListBuilds(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
) ([]StoredBuild, error)

func (*Repository) ListChannelAssignmentHistory

func (r *Repository) ListChannelAssignmentHistory(
	ctx context.Context,
	tenant Tenant,
	bucketName, channelName string,
) ([]ChannelAssignment, error)

func (*Repository) ListChannels

func (r *Repository) ListChannels(
	ctx context.Context,
	tenant Tenant,
	bucketName string,
) ([]Channel, error)

func (*Repository) ListKeyringEntries

func (r *Repository) ListKeyringEntries(ctx context.Context) ([]keyring.Entry, error)

ListKeyringEntries reads the wrapped keyring for unwrapping at startup.

func (*Repository) ListOrganizationsForPrincipal

func (r *Repository) ListOrganizationsForPrincipal(
	ctx context.Context, principal *identity.Principal,
) ([]Organization, error)

ListOrganizationsForPrincipal returns only the organisations a caller may see.

Filtering lives here rather than in the handler because a handler that forgets leaks every tenant identifier on the instance — and organisation identifiers are half of every compatibility-plane path, so they are the thing the rest of the system works to keep secret (ADR-0016).

A platform-scoped caller sees everything; that is what platform scope means, and only root may hold it. Any other caller sees exactly its own organisation, so the answer is a lookup rather than a filtered scan.

The argument is a principal rather than a bare scope because Scope's zero value is the MOST privileged one: a forgotten Scope{} used to hand this method platform scope by accident. A principal cannot be constructed with an invalid scope/role pairing (validBinding, pinned by TestPlatformScopeIsReachableOnlyWithRoot), so the caller must present a value that validated itself (duf-ueq).

func (*Repository) ListPins

func (r *Repository) ListPins(ctx context.Context, tenant Tenant) ([]Pin, error)

func (*Repository) ListPluginImports added in v0.5.0

func (r *Repository) ListPluginImports(ctx context.Context, tenant OrganizationTenant, filter PluginImportFilter) ([]PluginImport, int, error)

ListPluginImports is one page of the organization's jobs, newest first, with the count of every job the filter matches.

func (*Repository) ListPluginVersions added in v0.5.0

func (r *Repository) ListPluginVersions(
	ctx context.Context, tenant OrganizationTenant, name string,
) (PluginSource, []PluginVersionSummary, error)

ListPluginVersions returns one plugin and its versions, newest first.

func (*Repository) ListPlugins added in v0.5.0

func (r *Repository) ListPlugins(ctx context.Context, tenant OrganizationTenant) ([]PluginSummary, error)

ListPlugins returns the organization's plugins, empty when the registry is not enabled.

func (*Repository) ListPrincipals

func (r *Repository) ListPrincipals(
	ctx context.Context, caller *identity.Principal, selection identity.Scope,
) ([]*identity.Principal, error)

ListPrincipals loads the principals bound to EXACTLY the selected scope — platform, one organization, or one project — never a subtree. Listing and creation follow the same where-you-stand rule, so what a console selection shows is what a principal created there would be (duf-4qr).

The caller authorizes; the selection only filters. They are separate arguments because a root session browses scopes it does not stand in, while a tenancy caller must never see outside its own binding regardless of what selection it names. The handler already refuses that, and it is re-asserted here at the point of disclosure — the duf-ueq pattern — so a forgotten check upstream cannot leak another tenancy's principals.

Takes the caller rather than a bare scope, for the reason documented on ListOrganizationsForPrincipal: Scope's zero value is the most privileged input, and a principal cannot be constructed holding it without root (duf-ueq).

func (*Repository) ListProjects

func (r *Repository) ListProjects(ctx context.Context, organizationID string) ([]Project, error)

func (*Repository) ListProjectsForPrincipal

func (r *Repository) ListProjectsForPrincipal(
	ctx context.Context, principal *identity.Principal, organization uuid.UUID,
) ([]Project, error)

ListProjectsForPrincipal returns only projects visible to the caller within the selected organization. Organization-scoped callers and platform root see the organization collection; a project-scoped caller sees only its binding.

func (*Repository) ListSboms

func (r *Repository) ListSboms(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID string,
) ([]Sbom, error)

ListSboms lists the raw document metadata attached to one build.

func (*Repository) ListScanFindings

func (r *Repository) ListScanFindings(ctx context.Context, tenant Tenant, runID string) ([]StoredFinding, error)

ListScanFindings returns the verified findings of one run.

func (*Repository) ListScanFindingsForPackages added in v0.4.2

func (r *Repository) ListScanFindingsForPackages(
	ctx context.Context, tenant Tenant, runID string, packages []ReportedPackage,
) ([]StoredFinding, error)

ListScanFindingsForPackages returns verified findings for package identities.

func (*Repository) ListVersions

func (r *Repository) ListVersions(
	ctx context.Context,
	tenant Tenant,
	bucketName string,
) ([]*registry.Version, map[string][]StoredBuild, error)

ListVersions returns a bucket's versions, newest first.

Incomplete versions carry no sequence, so created_at breaks the tie and keeps them in a stable order rather than whatever the planner returns.

func (*Repository) ListWebhookDeliveries

func (r *Repository) ListWebhookDeliveries(ctx context.Context, organizationID, projectID, webhookID string) ([]webhook.Delivery, error)

func (*Repository) ListWebhookEventDeliveries

func (r *Repository) ListWebhookEventDeliveries(ctx context.Context, project webhook.Project, eventID string) ([]webhook.Delivery, error)

func (*Repository) ListWebhookProjects

func (r *Repository) ListWebhookProjects(ctx context.Context) ([]webhook.Project, error)

func (*Repository) ListWebhooks

func (r *Repository) ListWebhooks(ctx context.Context, organizationID, projectID string) ([]webhook.Record, error)

func (*Repository) MarkBagDropAssociationAttempt

func (r *Repository) MarkBagDropAssociationAttempt(
	ctx context.Context, organizationID, projectID, bucketName string, at time.Time,
) error

func (*Repository) ObjectStorageState

func (r *Repository) ObjectStorageState() string

ObjectStorageState is what the health probe reports: whether a store is configured at all, and if it is, what the last operation to touch it saw. Not configured is a deployment that never asked for one, which is a working registry for anyone not producing SBOMs — not a fault.

func (*Repository) OpenPluginObject added in v0.5.0

func (r *Repository) OpenPluginObject(ctx context.Context, key string) (io.ReadCloser, error)

OpenPluginObject streams a stored plugin file.

func (*Repository) PluginDownloads added in v0.5.0

func (r *Repository) PluginDownloads(
	ctx context.Context, tenant OrganizationTenant, name string, today time.Time,
) (PluginDownloads, error)

PluginDownloads returns rolling counts for one plugin and each counted version.

func (*Repository) PluginRegistryDefaultPlatforms added in v0.5.0

func (r *Repository) PluginRegistryDefaultPlatforms(ctx context.Context, tenant OrganizationTenant) ([]string, error)

PluginRegistryDefaultPlatforms are the platforms a first import selects.

func (*Repository) PluginVersionSumsDigest added in v0.5.0

func (r *Repository) PluginVersionSumsDigest(ctx context.Context, tenant OrganizationTenant, name, version string) (string, error)

PluginVersionSumsDigest is the digest of a held version's SHA256SUMS, or empty when the organization does not hold the version. The object key's last segment is the file's digest (objectstore.PluginKey).

func (*Repository) PrunePluginImports added in v0.5.0

func (r *Repository) PrunePluginImports(ctx context.Context, tenant OrganizationTenant, before time.Time) (int, error)

PrunePluginImports clears the finished jobs that finished before the cutoff and reports how many; queued and running jobs are never touched.

func (*Repository) PublishPluginVersion added in v0.5.0

func (r *Repository) PublishPluginVersion(
	ctx context.Context, tenant OrganizationTenant, input PluginVersionInput,
) error

PublishPluginVersion stores a verified version. Blobs land before rows: a later failure leaves invisible orphans, never a row without bytes.

func (*Repository) PurgeSupersededScanRuns

func (r *Repository) PurgeSupersededScanRuns(ctx context.Context, tenant Tenant, cutoff time.Time, limit int) (int, error)

PurgeSupersededScanRuns deletes run history older than the cutoff, bounded per call, never touching any run a build's pointers still reference.

func (*Repository) PutBagDropAssociation

func (r *Repository) PutBagDropAssociation(
	ctx context.Context, association bagdrop.Association,
) (*bagdrop.Association, error)

func (*Repository) PutBagDropConfig

func (r *Repository) PutBagDropConfig(
	ctx context.Context, record *bagdrop.Record,
) (*bagdrop.Record, error)

func (*Repository) PutPluginBundle added in v0.5.0

func (r *Repository) PutPluginBundle(ctx context.Context, _ OrganizationTenant, key string, body io.ReadSeeker, size int64) error

PutPluginBundle stores one bundle archive.

func (*Repository) QueuePluginBundle added in v0.5.0

func (r *Repository) QueuePluginBundle(ctx context.Context, tenant OrganizationTenant, requestedBy, host string) error

QueuePluginBundle queues a new export unless one is already active.

func (*Repository) QueuePluginBundleImport added in v0.5.0

func (r *Repository) QueuePluginBundleImport(ctx context.Context, tenant OrganizationTenant, requestedBy string, upload PluginBundleUpload) error

QueuePluginBundleImport queues an import of an uploaded bundle unless one is already active.

func (*Repository) RecordBagDropAssociationFailure

func (r *Repository) RecordBagDropAssociationFailure(
	ctx context.Context, organizationID, projectID, bucketName, summary string, at time.Time,
) error

func (*Repository) RecordBagDropAssociationSuccess

func (r *Repository) RecordBagDropAssociationSuccess(
	ctx context.Context, organizationID, projectID, bucketName string, at time.Time,
) error

func (*Repository) RecordBagDropVerification

func (r *Repository) RecordBagDropVerification(
	ctx context.Context, organizationID, projectID string,
	result bagdrop.VerificationResult, verifiedAt time.Time,
) (*bagdrop.Record, error)

func (*Repository) RecordEncryptionMode

func (r *Repository) RecordEncryptionMode(ctx context.Context, encrypted bool, at time.Time) error

RecordEncryptionMode stamps the configured mode at first boot. The insert is idempotent; the caller re-reads and compares, so two racing first boots cannot each believe their own answer.

func (*Repository) RecordPluginBundle added in v0.5.0

func (r *Repository) RecordPluginBundle(ctx context.Context, tenant OrganizationTenant, result *PluginBundleResult, runErr string) error

RecordPluginBundle records either a successful archive or a failed run.

func (*Repository) RecordPluginBundleImport added in v0.5.0

func (r *Repository) RecordPluginBundleImport(
	ctx context.Context, tenant OrganizationTenant, state string, origin PluginBundleOrigin, outcomes any, runErr string,
) error

RecordPluginBundleImport records progress or the final outcome of an import.

func (*Repository) RecordPluginImport added in v0.5.0

func (r *Repository) RecordPluginImport(
	ctx context.Context, tenant OrganizationTenant, id uuid.UUID, state string, outcomes any,
) error

RecordPluginImport stores a job's progress; a terminal state finishes it. Each record also renews the claim, so a working job is never stale.

func (*Repository) RecordPluginPrune added in v0.5.0

func (r *Repository) RecordPluginPrune(ctx context.Context, tenant OrganizationTenant, cleared int, runErr string, nextAt *time.Time) error

RecordPluginPrune stores a run's outcome and when the next one is due.

func (*Repository) RecordPluginUpdateCheck added in v0.5.0

func (r *Repository) RecordPluginUpdateCheck(
	ctx context.Context, tenant OrganizationTenant, id uuid.UUID, latest, tag, checkErr string,
) error

RecordPluginUpdateCheck stores a check's result: the newest stable upstream version and its tag, or the error that stopped the check. A failed check keeps the last version seen.

func (*Repository) RecordScanRun

func (r *Repository) RecordScanRun(ctx context.Context, tenant Tenant, run ScanRun, findings []scan.Finding, transcript []byte) error

RecordScanRun persists one terminal attempt: transcript to object storage first (a transcript write failure fails the run — nothing is recorded), then the immutable run row, its findings, and the guarded advance of the per-build pointers, all in one build-serialized transaction.

func (*Repository) RecordWebhookDeliveryAttempt

func (r *Repository) RecordWebhookDeliveryAttempt(ctx context.Context, delivery webhook.Delivery) error

func (*Repository) RecordWebhookVerification

func (r *Repository) RecordWebhookVerification(
	ctx context.Context, record webhook.Record, eventID, status string,
	responseCode *int, detail *string, at time.Time,
) (*webhook.Record, error)

func (*Repository) RecoveryVerifier

func (r *Repository) RecoveryVerifier(ctx context.Context) ([]byte, int, error)

RecoveryVerifier reads the digest and threshold /sys/recovery checks shares against. identity.ErrNotFound covers both an unclaimed instance and one initialized before recovery existed: neither holds a verifier, and /sys/recovery refuses identically.

func (*Repository) RemoveBagDropAssociation

func (r *Repository) RemoveBagDropAssociation(
	ctx context.Context, organizationID, projectID, bucketName string, at time.Time,
) (bagdrop.RemovalOutcome, error)

func (*Repository) RestoreRevokedVersion

func (r *Repository) RestoreRevokedVersion(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
	at time.Time,
) (*registry.Version, error)

RestoreRevokedVersion clears a version's revocation and every inherited descendant revocation that names it, in one transaction.

func (*Repository) RevokePrincipalSecret

func (r *Repository) RevokePrincipalSecret(
	ctx context.Context, principalID, secretID string, at time.Time,
) error

RevokePrincipalSecret locks the principal while the domain decides. A ROOT principal must keep at least one usable, never-expiring credential (ADR-0004, amended 2026-08-02; extended for expiry by duf-2rw); every other principal may be left with none.

func (*Repository) RevokeVersion

func (r *Repository) RevokeVersion(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
	req RevocationRequest,
	versionName func(*registry.Version) string,
	at time.Time,
) (*registry.Version, error)

RevokeVersion revokes a version and, unless skipped, marks every transitive descendant revoked as inherited from it — one transaction, so a reader can never see a revoked ancestor with unrevoked descendants.

versionName is passed in because the v0/vN collapse is the compat plane's rule and the denormalized ancestor identity stores the wire name (ADR-0002: the domain never sees the sentinel).

func (*Repository) RewrapKeyringEntries

func (r *Repository) RewrapKeyringEntries(ctx context.Context, entries []keyring.Entry, at time.Time) error

RewrapKeyringEntries replaces every wrapped blob in one transaction.

func (*Repository) ScheduleWebhookOutboxEvent

func (r *Repository) ScheduleWebhookOutboxEvent(ctx context.Context, project webhook.Project, eventID string, at time.Time) error

func (*Repository) SearchExternalArtifacts

func (r *Repository) SearchExternalArtifacts(
	ctx context.Context,
	tenant Tenant,
	externalIdentifier, platform, region string,
) ([]ExternalArtifactMatch, error)

SearchExternalArtifacts finds builds that contain an exact external identifier.

func (*Repository) ServedPluginFile added in v0.5.0

func (r *Repository) ServedPluginFile(
	ctx context.Context, organization, name, version string, kind PluginFileKind, filename string,
) (ServedPluginFile, error)

ServedPluginFile resolves one file of a served version.

func (*Repository) ServedPluginVersions added in v0.5.0

func (r *Repository) ServedPluginVersions(ctx context.Context, organization, name string) ([]string, error)

ServedPluginVersions lists the versions an exposed registry serves for one plugin. Unexposed, unknown and fully revoked all answer ErrNotFound.

func (*Repository) SetBagDropEnabled

func (r *Repository) SetBagDropEnabled(
	ctx context.Context, organizationID, projectID string, enabled bool,
	result *bagdrop.VerificationResult, at time.Time,
) (*bagdrop.Record, error)

func (*Repository) SetKeyring

func (r *Repository) SetKeyring(ring *keyring.Keyring)

SetKeyring arms payload encryption and row integrity. It is called after construction because loading the keyring needs this repository: the wrapped entries live in the database it fronts.

func (*Repository) SetPin

func (r *Repository) SetPin(
	ctx context.Context, tenant Tenant, bucketName, pinnedBy string, pinnedAt time.Time,
) (*Pin, error)

func (*Repository) SetPluginPrune added in v0.5.0

func (r *Repository) SetPluginPrune(ctx context.Context, tenant OrganizationTenant, enabled bool, ageDays int, schedule string, nextAt *time.Time) error

SetPluginPrune stores the schedule; nextAt is nil when pruning is off.

func (*Repository) SetPluginRegistryDefaultPlatforms added in v0.5.0

func (r *Repository) SetPluginRegistryDefaultPlatforms(
	ctx context.Context, tenant OrganizationTenant, platforms []string,
) ([]string, error)

SetPluginRegistryDefaultPlatforms replaces the organization's defaults.

func (*Repository) SetPluginUpdateCheck added in v0.5.0

func (r *Repository) SetPluginUpdateCheck(ctx context.Context, tenant OrganizationTenant, name string, enabled bool) error

SetPluginUpdateCheck turns a plugin's update check on or off.

func (*Repository) SetPluginVersionRevoked added in v0.5.0

func (r *Repository) SetPluginVersionRevoked(
	ctx context.Context, tenant OrganizationTenant, name, version string, revoked bool,
) error

SetPluginVersionRevoked revokes or restores one version. Revoked versions keep their bytes and their plugin's name; only serving stops.

func (*Repository) TouchSecretLastUsed

func (r *Repository) TouchSecretLastUsed(ctx context.Context, secretID string, at time.Time) error

TouchSecretLastUsed records successful credential use. last_used_at is not covered by principalSecretMACMessage, so no re-seal is needed.

func (*Repository) UnexposePluginRegistry added in v0.5.0

func (r *Repository) UnexposePluginRegistry(
	ctx context.Context, tenant OrganizationTenant,
) (PluginRegistry, error)

func (*Repository) UpdateBucket

func (r *Repository) UpdateBucket(
	ctx context.Context,
	tenant Tenant,
	name, description string,
	labels map[string]string,
	at time.Time,
) (*Bucket, error)

func (*Repository) UpdateBuild

func (r *Repository) UpdateBuild(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint string,
	build StoredBuild,
	versionName func(*registry.Version) string,
	at time.Time,
) (*StoredBuild, error)

func (*Repository) UpdateChannel

func (r *Repository) UpdateChannel(
	ctx context.Context,
	tenant Tenant,
	bucketName, channelName string,
	updateRestricted, restricted bool,
	updateVersion bool, versionFingerprint, authorID string,
	at time.Time,
) (*Channel, error)

func (*Repository) UpdateWebhook

func (r *Repository) UpdateWebhook(ctx context.Context, record webhook.Record) (*webhook.Record, error)

func (*Repository) UploadSbom

func (r *Repository) UploadSbom(
	ctx context.Context,
	tenant Tenant,
	bucketName, fingerprint, buildID string,
	sbom Sbom,
) (*Sbom, error)

UploadSbom stores an SBOM under a build, replacing one of the same name.

A replace rather than a conflict, because UploadSbom is a PUT and a re-run build re-uploads under the same name — and any error here fails the whole build before it can be marked complete (dossier §5.6).

type RevocationRequest

type RevocationRequest struct {
	RevokeAt                time.Time
	Message                 string
	Author                  string
	SkipDescendants         bool
	DisableRollbackChannels bool
}

RevocationRequest is a manual revocation as the compat plane received it.

type Sbom

type Sbom struct {
	ID             registry.ID
	BuildID        registry.ID
	Name           string
	Format         string
	CompressedData []byte
	ParseStatus    string
	ParseError     string
	CreatedAt      time.Time
	// contains filtered or unexported fields
}

Sbom is one stored SBOM document attached to a build. The bytes are kept exactly as the client sent them even though a package projection is parsed from them; the projection is client-reported inventory, not verified fact.

type ScanAttempt added in v0.4.2

type ScanAttempt struct {
	ObservedAt time.Time
	Status     string
	Error      string
}

ScanAttempt is a build's newest scan attempt when it is not the current run.

type ScanRun

type ScanRun struct {
	ID               string
	BuildID          string
	RunSequence      int64
	Status           string
	Error            string
	Adapter          string
	Engine           string
	DatabaseRevision string
	ObservedAt       time.Time
	TranscriptDigest string
	Coverage         scan.Coverage
	CreatedAt        time.Time
	// InventoryDigest is carried at completion only: the claim-time digest the
	// run scanned, compared against the live inventory and never stored.
	InventoryDigest string
}

ScanRun is one terminal scanner attempt. Rows are immutable: the sequence is allocated before provider egress and the row is inserted exactly once, already terminal.

type ScannerHealth

type ScannerHealth struct {
	State                 string
	Adapter               string
	Endpoint              string
	LastObservedAt        time.Time
	Detail                string
	AuditCircuitOpenUntil time.Time
}

ScannerHealth is the remembered provider state. Nothing here probes the provider: this feeds a health route, and a route that reaches a third party when polled turns monitoring into traffic against someone else's service.

type ScannerService

type ScannerService struct {
	// contains filtered or unexported fields
}

ScannerService drains assignment work and exposes the shared direct rescan path used by the later HTTP endpoint.

func NewScannerService

func NewScannerService(
	repository *Repository, adapter scan.Scanner, writer audit.Writer, config ScannerServiceConfig,
) (*ScannerService, error)

func (*ScannerService) DrainOnce

func (s *ScannerService) DrainOnce(ctx context.Context) error

DrainOnce drains all work currently claimable with bounded concurrency.

Selection walks the tenant list ONCE per pass and hands the ordered result to the whole pool: forced RLS means no query can order the queue globally, so a walk per worker would cost workers x tenants peeks to dispatch one pool's worth of scans (duf-xwrw). Tenants are ordered by the age of their oldest entry; a tenant's backlog then drains together rather than strictly interleaving with other tenants, which is deliberate — cross-tenant fairness belongs to the cadence loop that can actually flood the queue.

func (*ScannerService) Health

func (s *ScannerService) Health() ScannerHealth

Health reports the last observed provider state. The audit circuit outranks a provider fault: when scanning has stopped to avoid unrecorded writes, that is the more important thing an operator needs to know.

func (*ScannerService) ManualRescan

func (s *ScannerService) ManualRescan(ctx context.Context, tenant Tenant, buildID string) error

ManualRescan queues a build rather than scanning it inline. The console button is a request for work, not a private fast path: dispatching inline would let one caller pressing repeatedly consume workers ahead of another tenant's already-due entries. The queue's primary key coalesces repeats, so pressing twice before a worker arrives produces one execution.

func (*ScannerService) Run

func (s *ScannerService) Run(ctx context.Context)

Run drains promptly, schedules bounded retention, and returns on cancellation.

func (*ScannerService) SweepDueBuilds

func (s *ScannerService) SweepDueBuilds(ctx context.Context) (int, error)

SweepDueBuilds enqueues every scan-set member whose findings have aged past the freshness threshold. Returns how many builds it enqueued.

Fairness is round-robin ACROSS TENANTS: a sweep can enqueue one tenant's entire estate, and a queue ordered purely by enqueue time would then put every other tenant behind it. Taking one build per tenant per round means a tenant with a single stale build waits for one round, not for someone else's thousand. Event traffic cannot create that problem, which is why fairness lives here rather than with the drainer.

type ScannerServiceConfig

type ScannerServiceConfig struct {
	AdapterName string
	// Interval is the freshness threshold: a scan-set member whose findings
	// are older than this comes due for rescanning. Zero disables the cadence
	// sweep, leaving assignments and the rescan button as the only triggers.
	Interval       time.Duration
	Engine         string
	Workers        int
	PassTimeout    time.Duration
	RunRetention   time.Duration
	Clock          func() time.Time
	CircuitBackoff func() time.Duration
	Logger         *slog.Logger
}

type ServedPluginFile added in v0.5.0

type ServedPluginFile struct {
	OrganizationID uuid.UUID
	PluginID       uuid.UUID
	ObjectKey      string
	Size           int64
	Content        []byte
}

ServedPluginFile is one file the read plane answers with: stored bytes by object key, or content the registry renders.

type SeverityCounts added in v0.4.2

type SeverityCounts struct {
	Unknown    int `json:"unknown"`
	Negligible int `json:"negligible"`
	Low        int `json:"low"`
	Medium     int `json:"medium"`
	High       int `json:"high"`
	Critical   int `json:"critical"`
}

SeverityCounts contains every findings severity band, including zeroes.

type StoredBuild

type StoredBuild struct {
	registry.Build
	VersionID                registry.ID
	PackerRunUUID            string
	Labels                   map[string]string
	Metadata                 json.RawMessage
	SourceExternalIdentifier string
	ParentVersionID          string
	ParentChannelID          string
	Artifacts                []Artifact
	CreatedAt                time.Time
	UpdatedAt                time.Time
}

StoredBuild is the domain build plus persisted compatibility-neutral metadata.

type StoredFinding

type StoredFinding struct {
	scan.Finding
	FirstSeenAt time.Time
}

StoredFinding is a scan.Finding plus the store-owned first-seen provenance.

func DeduplicateBuildFindings added in v0.4.2

func DeduplicateBuildFindings(findings []StoredFinding) []StoredFinding

DeduplicateBuildFindings collapses repeated SBOM reports to one logical package-identity/advisory finding. The lowest SBOM id wins so callers get a stable representative without depending on query order.

type StoredPluginVersion added in v0.5.0

type StoredPluginVersion struct {
	Source   PluginSource
	Sums     []byte
	Manifest []byte
	Protocol string
	Stored   []string
}

StoredPluginVersion is what a version already holds: its verbatim SHA256SUMS and manifest, the protocol extracted when it had no manifest, and the platforms it has zips for.

type Tenant

type Tenant struct {
	OrganizationID uuid.UUID
	ProjectID      uuid.UUID
	BucketID       string
	// contains filtered or unexported fields
}

Tenant is the explicit RLS scope for one repository operation.

func DeniedTenant

func DeniedTenant() Tenant

DeniedTenant is a tenant that no operation will resolve.

Authorization failures are represented as a tenant rather than as an error at the call site, so every existing not-found path answers them with its own endpoint-appropriate code — and so a handler cannot obtain a usable tenant without having been authorized for it.

func ParseTenant

func ParseTenant(organizationID, projectID string) Tenant

ParseTenant reads the two tenant path parameters.

type VersionAssignedError

type VersionAssignedError struct {
	Channels []string
}

VersionAssignedError identifies the user channels that must be unassigned before a version can be deleted.

func (*VersionAssignedError) Error

func (e *VersionAssignedError) Error() string

type VersionBuildFindingsSummary added in v0.4.2

type VersionBuildFindingsSummary struct {
	BuildID       string
	ComponentType string
	Platform      string
	Inventory     string
	Packages      int
	// Scanned is true when a current successful run exists, with or without a
	// stored summary; a build scanned before summaries existed has none yet.
	Scanned       bool
	Summary       *BuildFindingsSummary
	LatestAttempt *ScanAttempt
}

VersionBuildFindingsSummary describes one build in a version summary response.

type VersionFindingsSummary added in v0.4.2

type VersionFindingsSummary struct {
	Findings         int
	AffectedPackages int
	Worst            scan.Severity
	Counts           SeverityCounts
	BuildsSummarised int
	ComputedAt       time.Time
}

VersionFindingsSummary is one version's current verified findings summary.

type VersionFindingsSummaryResult added in v0.4.2

type VersionFindingsSummaryResult struct {
	Version *VersionFindingsSummary
	Builds  []VersionBuildFindingsSummary
}

VersionFindingsSummaryResult contains the version rollup and all its builds.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL