store

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package store keeps sealift's data volume: settings, projects, analyses and exports.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidLimits = errors.New("invalid limits")

ErrInvalidLimits reports a minimum release age or a parallelism outside the range the settings allow.

View Source
var ErrInvalidTarget = errors.New("invalid target")

ErrInvalidTarget reports a target with an empty field or a Node or pnpm version that is not exact: the caller's own mistake, not a server failure.

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when a project ID has no matching directory.

Functions

This section is empty.

Types

type AnalysisInfo

type AnalysisInfo struct {
	ID           string
	ProjectID    string
	State        State
	CreatedAt    time.Time
	Result       json.RawMessage
	TrivyVersion string
	TrivyDBDate  time.Time
	PnpmVersion  string
	Failure      *StepFailure // the first step status.json recorded as failed, nil otherwise
}

AnalysisInfo summarizes one committed analysis for the API: its identity, its state, and the result an API response embeds once ranking.json exists. Result is nil before the job ranks anything.

type ExportInfo

type ExportInfo struct {
	ID         string
	ProjectID  string
	AnalysisID string
	State      State
	CreatedAt  time.Time
	Files      []string
	// Failure names the first step status.json recorded as failed, and
	// why, for a failed export. Nil for a done or cancelled one.
	Failure *StepFailure
}

ExportInfo summarizes one export for the API: its identity, the analysis it came from, its state, and the files ready to download once it is done. A committed export directory can hold any terminal state: a successful one reports Done from manifest.json alone, while a failed or cancelled one keeps its directory too, with a status.json Export.Run wrote on its way out (see internal/jobs).

type Pending

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

Pending is an analysis or export directory being written under a .tmp name. Commit publishes it atomically; Discard removes it and everything under it.

func (*Pending) Commit

func (p *Pending) Commit() error

Commit renames the <id>.tmp directory to <id>, publishing it atomically. Nothing under a committed directory changes afterward.

func (*Pending) Discard

func (p *Pending) Discard() error

Discard removes the <id>.tmp directory and everything under it, leaving no trace of a job that never finished.

func (*Pending) Final

func (p *Pending) Final() string

Final returns the path Commit renames Path to: the directory a reader finds once the job has published it. A caller that needs to read back something a completed job wrote, such as reconciling a status.json field against the queue's own account of how the job ended, uses this rather than assuming Path with its ".tmp" suffix trimmed.

func (*Pending) ID

func (p *Pending) ID() string

ID returns the analysis or export ID this directory commits under.

func (*Pending) Path

func (p *Pending) Path() string

Path returns the <id>.tmp directory the caller writes into.

type Project

type Project struct {
	ID             string
	Name           string
	Target         Target
	Dir            string
	ManifestSha256 string // sha256 of the uploaded package.json bytes, lowercase hex
	CreatedAt      time.Time
}

Project is one project directory: an uploaded package.json, its target platform, and the analyses and exports run against it.

type Settings

type Settings struct {
	Target              Target `json:"target"`
	SignatureKey        string `json:"signatureKey"`
	MinReleaseAgeDays   int    `json:"minReleaseAgeDays"`
	ResolveParallelism  int    `json:"resolveParallelism"`
	DownloadParallelism int    `json:"downloadParallelism"`
}

Settings holds every value the interface can change.

type State

type State string

State is the state of an analysis, an export or a queued job.

const (
	Queued      State = "queued"
	Running     State = "running"
	Done        State = "done"
	Failed      State = "failed"
	Cancelled   State = "cancelled"
	Interrupted State = "interrupted"
)

States of a job and of the directory it writes.

type StepFailure added in v0.2.0

type StepFailure struct {
	Step    string
	Message string
}

StepFailure names the step an analysis or export failed on and why, read back from the failed step's own status.json entry: the log.txt a reader would otherwise have to open to find that reason.

type Store

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

Store is sealift's data volume: settings, projects, analyses and exports rooted at one directory.

func Open

func Open(root string) (*Store, error)

Open creates the data volume layout under root when it is missing, then loads private/settings.json or writes the defaults there.

It also sets the process umask to 002. A container's default umask of 022 would strip the group write bit from every file this package creates through os.OpenFile, and the tools user needs that bit to write lockfiles and caches outside private/.

func (*Store) Analyses

func (s *Store) Analyses(projectID string) ([]AnalysisInfo, error)

Analyses lists every committed analysis of a project, newest first. A directory that fails to parse, such as one with a corrupt status.json, is logged and skipped rather than failing the whole list, the same tolerance MarkRunningInterrupted and Projects give a damaged entry.

func (*Store) AnalysisInfo

func (s *Store) AnalysisInfo(projectID, id string) (AnalysisInfo, error)

AnalysisInfo reads one committed analysis by ID.

func (*Store) AnalysisLog added in v0.2.0

func (s *Store) AnalysisLog(projectID, id string) (*os.File, error)

AnalysisLog opens a committed analysis' log.txt for reading, the running account of every step a reader would otherwise have to reconstruct from status.json alone.

func (*Store) CreateProject

func (s *Store) CreateProject(name string, manifest []byte) (Project, error)

CreateProject slugs name into a project ID, appends a random 6 hex character suffix to keep it unique, and writes package.json and project.json under projects/<id>/. It rejects a name that slugs to nothing.

func (*Store) DeleteAnalysis

func (s *Store) DeleteAnalysis(projectID, id string) error

DeleteAnalysis removes a committed analysis directory.

func (*Store) DeleteExport

func (s *Store) DeleteExport(projectID, id string) error

DeleteExport removes a committed export directory.

func (*Store) DeleteProject

func (s *Store) DeleteProject(id string) error

DeleteProject removes a project directory and everything under it.

func (*Store) ExportFile

func (s *Store) ExportFile(projectID, exportID, name string) (*os.File, error)

ExportFile opens one file inside a committed export directory for reading, refusing a name that is not a plain file name: no path separator, no "..", nothing that could join outside the export directory.

func (*Store) ExportInfo

func (s *Store) ExportInfo(projectID, id string) (ExportInfo, error)

ExportInfo reads one committed export by ID.

func (*Store) Exports

func (s *Store) Exports(projectID string) ([]ExportInfo, error)

Exports lists every committed export of a project, newest first.

func (*Store) MarkRunningInterrupted

func (s *Store) MarkRunningInterrupted() (int, error)

MarkRunningInterrupted is the startup sweep: every analyses/<id> or exports/<id> status.json still in state running belongs to a job the previous process never finished, so it moves to state interrupted. It returns how many files it changed.

func (*Store) NewDir

func (s *Store) NewDir(kind, projectID string) (*Pending, error)

NewDir creates a new pending directory for a project, named after the current UTC time. kind is "analyses" or "exports". The caller writes into Path and calls Commit or Discard when done.

Two calls inside the same second would otherwise get the same ID: this checks both the pending (.tmp) and the final path before reserving one, and appends a short random suffix to the second try onward, the same defense reserveProjectDir gives project IDs. Without it, the second job's own Commit would collide with the first job's already-committed directory of the same timestamp.

func (*Store) NewResolveDir

func (s *Store) NewResolveDir() (string, error)

NewResolveDir reserves a fresh, group-writable directory under cache/resolve for one isolated pnpm resolution. Unlike os.MkdirTemp, which always creates mode 0700 under the system temp directory, this stays under the volume Open laid out and in a mode the tools account can traverse once it runs pnpm as a different uid. The caller removes the directory once the resolution ends.

func (*Store) Project

func (s *Store) Project(id string) (Project, error)

Project reads one project by ID. A project created before manifestSha256 existed carries none in project.json; this computes it from package.json instead of returning it empty, but never rewrites the record: Project is a read.

func (*Store) ProjectManifest added in v0.2.1

func (s *Store) ProjectManifest(projectID string) (*os.File, error)

ProjectManifest opens the package.json a project was created from, as uploaded. ErrNotFound when the project does not exist.

func (*Store) Projects

func (s *Store) Projects() ([]Project, error)

Projects lists every project, newest first.

func (*Store) ProjectsByManifestSha256 added in v0.2.0

func (s *Store) ProjectsByManifestSha256(hash string) ([]Project, error)

ProjectsByManifestSha256 returns every project whose manifest hash equals hash, newest first: a session re-uploading a manifest it has already analysed wants its most recent project, not alphabetical order.

func (*Store) ReadJSON

func (s *Store) ReadJSON(path string, v any) error

ReadJSON unmarshals the JSON file at path into v.

func (*Store) RemoveOrphanDirs

func (s *Store) RemoveOrphanDirs() (int, error)

RemoveOrphanDirs removes every analyses/<id>.tmp or exports/<id>.tmp directory left under any project. A .tmp directory can only exist while its job is running: Analysis commits its own on every path, including failure and cancellation, before Run returns, and Export leaves one only for the queue's finalize hook to commit while the server is still up. A .tmp directory found at startup therefore belongs to a job the previous process never got to finish. It returns how many it removed.

func (*Store) Root

func (s *Store) Root() string

Root returns the directory the store is rooted at.

func (*Store) SaveSettings

func (s *Store) SaveSettings(set Settings) error

SaveSettings atomically writes settings to private/settings.json, mode 0600, and refuses an invalid target or limits out of range.

func (*Store) SetProjectTarget

func (s *Store) SetProjectTarget(id string, t Target) error

SetProjectTarget changes a project's target platform, refusing an empty field the same way SaveSettings does.

func (*Store) Settings

func (s *Store) Settings() Settings

Settings returns the current settings. Safe for concurrent use.

func (*Store) WriteJSON

func (s *Store) WriteJSON(path string, v any) error

WriteJSON atomically marshals v as indented JSON to path, mode 0664, so a reader never observes a partial file.

type Target

type Target struct {
	OS      string `json:"os"`      // "linux"
	CPU     string `json:"cpu"`     // "x64"
	Libc    string `json:"libc"`    // "glibc" or "musl"
	Node    string `json:"node"`    // "22.17.1"
	PnpmVer string `json:"pnpmVer"` // "10.34.5"
}

Target is the system an export gets prepared for, plus the toolchain versions the resolution pins.

Jump to

Keyboard shortcuts

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