pack

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: Apache-2.0 Imports: 39 Imported by: 0

Documentation

Overview

Package pack provides the build pipeline, SBOM, signing, and secret scanning.

Index

Constants

View Source
const (
	AdvisorySeverityCritical = "CRITICAL"
	AdvisorySeverityHigh     = "HIGH"
	AdvisorySeverityMedium   = "MEDIUM"
	AdvisorySeverityLow      = "LOW"
	AdvisorySeverityNone     = "NONE"
)

AdvisorySeverity levels for OSV findings.

View Source
const LockSchemaVersion = 1

LockSchemaVersion is the current agent.lock schema version.

Variables

View Source
var ErrImmutableViolation = errors.New("immutable violation: deployed agent artifacts cannot be modified in place")

ErrImmutableViolation is returned when an in-place mutation of a deployed agent artifact is attempted.

View Source
var ErrOCILayoutCorrupt = errors.New("local OCI layout is missing or corrupt")

ErrOCILayoutCorrupt is returned when the local OCI layout is missing or corrupt.

Functions

func CleanupLocalRegistry

func CleanupLocalRegistry(ctx context.Context) error

CleanupLocalRegistry stops and removes the agentpaas-registry test container.

func ComputeBuildInputDigest

func ComputeBuildInputDigest(projectDir string, ignore *IgnoreMatcher) (string, error)

ComputeBuildInputDigest computes SHA-256 over the canonical build context. Canonical = sorted file paths (relative to ProjectDir, forward slashes) + each file's content. Respects .agentpaasignore exclusions. Symlink-safe: uses os.Lstat, rejects symlinks.

func CreateBuildContext

func CreateBuildContext(projectDir string, ignore *IgnoreMatcher) (io.Reader, error)

CreateBuildContext creates a deterministic tar reader of the build context. Files are added in sorted path order. Uses ignore matcher to exclude files. Symlink-safe.

func DefaultAgentPaasIgnore

func DefaultAgentPaasIgnore() string

DefaultAgentPaasIgnore returns the default .agentpaasignore content.

func DefaultAgentYAML

func DefaultAgentYAML(runtime RuntimeType) string

DefaultAgentYAML returns the minimal agent.yaml content for scaffolding.

func DefaultIgnorePatterns

func DefaultIgnorePatterns() []string

DefaultIgnorePatterns returns the default exclude patterns used when .agentpaasignore is absent.

func DefaultMainPy

func DefaultMainPy() string

DefaultMainPy returns the default main.py entry point stub.

func DeployedAgentPath

func DeployedAgentPath(homeDir, agentName string) string

DeployedAgentPath returns the deployed agent state directory.

func EnsureLocalRegistry

func EnsureLocalRegistry(ctx context.Context) (string, error)

EnsureLocalRegistry ensures a local OCI registry is running and returns its URL.

func GenerateSBOM

func GenerateSBOM(ctx context.Context, imageRef string) (sbom []byte, digest string, err error)

GenerateSBOM runs syft to produce an SPDX-json SBOM for the built image. Returns the SBOM content and its SHA-256 digest.

func InitFromCode

func InitFromCode(projectDir string, runtime RuntimeType) error

InitFromCode reconciles an agent.yaml from existing source files. If agent.yaml exists, it is left untouched. If not, a minimal one is created with the detected runtime and agent name derived from the dir.

func InitPolicy

func InitPolicy(projectDir string) error

InitPolicy writes a minimal default-deny policy.yaml if one does not exist. If policy.yaml already exists, it is left untouched (never overwrite policy).

func InitScaffold

func InitScaffold(projectDir string, runtime RuntimeType) error

InitScaffold creates a new agent project in the given directory. If the directory does not exist, it is created. If agent.yaml already exists, return an error (don't overwrite). Files created:

  • agent.yaml (minimal template with name, version, runtime, entry)
  • main.py (entry point stub: def app(input): return {"status":"ok"})
  • requirements.txt (empty, with a comment)
  • .agentpaasignore (default excludes)

func IsDeployed

func IsDeployed(homeDir, agentName string) bool

IsDeployed returns true if the agent has been deployed.

func IsRegistryPortConflict

func IsRegistryPortConflict(err error) bool

IsRegistryPortConflict reports whether err indicates the configured registry host port is already bound by a non-agentpaas process.

func LocalImageRef

func LocalImageRef(agentName, imageDigest string) string

LocalImageRef returns a digest-pinned image ref for the local registry.

func PublicKeyFingerprint

func PublicKeyFingerprint(pub *ecdsa.PublicKey) string

PublicKeyFingerprint computes the SHA-256 fingerprint of a public key.

func PublicKeyFromPEM

func PublicKeyFromPEM(pemBytes []byte) (*ecdsa.PublicKey, error)

PublicKeyFromPEM parses a PEM-encoded ECDSA P-256 public key.

func PushImageToLocalRegistry

func PushImageToLocalRegistry(ctx context.Context, sourceTag, agentName, agentVersion string) (string, error)

PushImageToLocalRegistry tags and pushes a locally built image to the local registry, returning a digest-pinned image ref suitable for cosign signing.

func RecordDeployment

func RecordDeployment(homeDir, agentName string, lock *AgentLock) error

RecordDeployment writes the deployed agent metadata to disk atomically.

func RepairHint

func RepairHint(err *OCILayoutError) string

RepairHint returns a human-readable repair hint for the given OCILayoutError.

func ResolveDependencies

func ResolveDependencies(ctx context.Context, projectDir string, runtime RuntimeType) ([]string, error)

ResolveDependencies runs uv to lock dependencies. For requirements.txt: `uv pip compile requirements.txt -o /tmp/locked.txt` For pyproject.toml: `uv lock` Returns the list of locked package@version strings. Returns error with verbatim uv output on conflict.

func SignImage

func SignImage(ctx context.Context, imageRef string, keyPath string) (referrer string, err error)

SignImage signs the built image with cosign using the package identity key. Returns the signature referrer path.

func ValidateOCILayout

func ValidateOCILayout(layoutPath string) error

ValidateOCILayout checks that a local OCI layout directory is valid.

func VerifyAgentLock

func VerifyAgentLock(lock *AgentLock, imageRef string) error

VerifyAgentLock verifies an agent.lock manifest.

func VerifyDeployedIntegrity

func VerifyDeployedIntegrity(homeDir, agentName string, auditAppender audit.AuditAppender) error

VerifyDeployedIntegrity checks that the deployed agent.lock and image.digest on disk have NOT been modified since deployment.

func VerifyLockfileSignature

func VerifyLockfileSignature(lock *AgentLock) error

VerifyLockfileSignature verifies the lockfile's ECDSA signature against the AID public key embedded in the lockfile.

func WriteAgentLock

func WriteAgentLock(lock *AgentLock, path string) error

WriteAgentLock writes the agent.lock manifest as canonical JSON to a file.

Types

type AdvisoryFinding

type AdvisoryFinding struct {
	ID         string   `json:"id"`
	Package    string   `json:"package"`
	Version    string   `json:"version"`
	Severity   string   `json:"severity"`
	Summary    string   `json:"summary"`
	FixedIn    string   `json:"fixed_in,omitempty"`
	References []string `json:"references,omitempty"`
}

AdvisoryFinding represents a single OSV advisory.

type AdvisoryReport

type AdvisoryReport struct {
	Total     int               `json:"total"`
	Critical  int               `json:"critical"`
	High      int               `json:"high"`
	Medium    int               `json:"medium"`
	Low       int               `json:"low"`
	Findings  []AdvisoryFinding `json:"findings"`
	Scanned   bool              `json:"scanned"`
	RawOutput string            `json:"raw_output,omitempty"`
}

AdvisoryReport is the summary of OSV scan results.

func ScanAdvisories

func ScanAdvisories(ctx context.Context, sbomPath string) (*AdvisoryReport, error)

ScanAdvisories runs osv-scanner on the SBOM and returns an advisory summary.

func (*AdvisoryReport) ShouldFailBuild

func (r *AdvisoryReport) ShouldFailBuild(failOnCritical bool) bool

ShouldFailBuild returns true when configured critical/high advisories exist.

func (*AdvisoryReport) Summary

func (r *AdvisoryReport) Summary() string

Summary returns a human-readable summary string for CLI output.

type AgentLock

type AgentLock struct {
	// SchemaVersion is the agent.lock schema version (currently 1).
	SchemaVersion int `json:"schema_version"`
	// AgentName is the agent name from agent.yaml.
	AgentName string `json:"agent_name"`
	// AgentVersion is the agent version from agent.yaml.
	AgentVersion string `json:"agent_version"`
	// Runtime is the detected/explicit runtime type (python, langgraph, crewai).
	Runtime string `json:"runtime"`
	// Platform is the target platform (e.g. "linux/arm64").
	Platform string `json:"platform"`
	// BaseImageDigest is the digest-pinned distroless base image.
	BaseImageDigest string `json:"base_image_digest"`
	// HarnessVersion is the version of the harness binary embedded as PID 1.
	HarnessVersion string `json:"harness_version"`
	// BuildInputDigest is the SHA-256 over the canonical build context.
	BuildInputDigest string `json:"build_input_digest"`
	// ImageDigest is the SHA-256 digest of the built OCI image.
	ImageDigest string `json:"image_digest"`
	// SBOMDigest is the SHA-256 digest of the SBOM (SPDX-json).
	SBOMDigest string `json:"sbom_digest"`
	// PolicyDigest is the SHA-256 digest of the policy.yaml.
	// Computed at pack time from the project's policy.yaml.
	PolicyDigest string `json:"policy_digest"`
	// PackageAID is the Agent Identity Document - the public key PEM.
	PackageAID string `json:"package_aid"`
	// PublicKeyFingerprint is the SHA-256 fingerprint of the public key.
	PublicKeyFingerprint string `json:"public_key_fingerprint"`
	// SBOMReferrer is the OCI referrer path for the SBOM artifact.
	SBOMReferrer string `json:"sbom_referrer,omitempty"`
	// SignatureReferrer is the OCI referrer path for the cosign signature.
	SignatureReferrer string `json:"signature_referrer,omitempty"`
	// Reproducibility holds build reproducibility metadata.
	Reproducibility ReproducibilityMeta `json:"reproducibility"`
	// LockfileSignature is the ECDSA signature over the canonical JSON
	// of this struct (with LockfileSignature omitted). Base64-encoded.
	LockfileSignature string `json:"lockfile_signature"`
	// CreatedAt is the wall-clock time the lockfile was created.
	// For reproducibility, this is set to SOURCE_DATE_EPOCH, not time.Now().
	CreatedAt time.Time `json:"created_at"`
	// AgentYAML is the parsed agent.yaml (including LLM config). Stored as part
	// of the lockfile for runtime LLM credential resolution. nil when absent.
	AgentYAML *AgentYAML `json:"agent_yaml,omitempty"`
}

AgentLock is the canonical, signed manifest for a packed agent. This is the exact review unit consumed by `agentpaas run` and promotion.

func CreateAgentLock

func CreateAgentLock(ctx context.Context, cfg LockConfig) (*AgentLock, error)

CreateAgentLock creates the canonical, signed agent.lock manifest.

func ReadAgentLock

func ReadAgentLock(path string) (*AgentLock, error)

ReadAgentLock reads and parses an agent.lock file.

type AgentYAML

type AgentYAML struct {
	Name        string    `yaml:"name"`
	Version     string    `yaml:"version"`
	Runtime     string    `yaml:"runtime"`
	Entry       string    `yaml:"entry"`
	Description string    `yaml:"description"`
	LLM         LLMConfig `yaml:"llm"`
	Metadata    struct {
		Name        string `yaml:"name"`
		Version     string `yaml:"version"`
		Description string `yaml:"description"`
	} `yaml:"metadata"`
	Spec struct {
		Runtime    string `yaml:"runtime"`
		Entrypoint string `yaml:"entrypoint"`
		Entry      string `yaml:"entry"`
	} `yaml:"spec"`
}

AgentYAML is a minimal subset of agent.yaml fields needed for detection and packaging. The runtime field overrides auto-detection. Both flat fields and the v1 metadata/spec schema are supported.

func LoadAgentYAML

func LoadAgentYAML(projectDir string) (*AgentYAML, error)

LoadAgentYAML reads and parses agent.yaml from the project directory. Returns nil, nil if agent.yaml does not exist (not an error).

type AuditAppender

type AuditAppender = audit.AuditAppender

AuditAppender is implemented by audit sinks that accept audit records.

type BuildConfig

type BuildConfig struct {
	// ProjectDir is the agent project directory to build.
	ProjectDir string
	// Runtime is the detected/explicit runtime type.
	Runtime RuntimeType
	// BaseImage is the distroless base image ref (digest-pinned).
	// Default: "gcr.io/distroless/python3-debian12@sha256:2fdb05402a2cf21cf78fdb3ba4c5db167241e9e498140f5bf689d7efb773731f"
	BaseImage string
	// HarnessPath is the path to the pre-built harness binary to embed as PID 1.
	// If empty, uses the standard harness binary location.
	HarnessPath string
	// SourceDateEpoch is the fixed timestamp for reproducible builds.
	// Default: time.Unix(0, 0) (epoch).
	SourceDateEpoch time.Time
	// NonRootUID is the uid for the non-root user. Default: 64000.
	NonRootUID int
	// ImageTag is the tag for the built image (e.g. "agentpaas/myagent:0.1.0").
	ImageTag string
}

BuildConfig controls the image build process.

type BuildResult

type BuildResult struct {
	ImageDigest string    `json:"image_digest"`
	ImageRef    string    `json:"image_ref"`
	BuildTime   time.Time `json:"build_time"`
	// BuildInputDigest is the SHA-256 over the canonical build context
	// (sorted file list + file contents). Same input -> same digest -> same image.
	BuildInputDigest string `json:"build_input_digest"`
	// DepsLocked is the resolved/locked dependency list from uv.
	DepsLocked []string `json:"deps_locked"`
}

BuildResult holds the outcome of an image build.

func BuildImage

func BuildImage(ctx context.Context, cfg BuildConfig) (*BuildResult, error)

BuildImage builds a deterministic OCI image for the agent project.

type DeployedAgent

type DeployedAgent struct {
	AgentName    string    `json:"agent_name"`
	ImageDigest  string    `json:"image_digest"`
	SourceDigest string    `json:"source_digest"`
	LockfileSig  string    `json:"lockfile_signature"`
	DeployedAt   time.Time `json:"deployed_at"`
}

DeployedAgent is the metadata of a deployed agent on disk.

func LoadDeployedAgent

func LoadDeployedAgent(homeDir, agentName string) (*DeployedAgent, error)

LoadDeployedAgent reads the deployed agent metadata from disk. Returns os.ErrNotExist if the agent was never deployed.

type DetectionResult

type DetectionResult struct {
	Runtime         RuntimeType `json:"runtime"`
	HasAgentYAML    bool        `json:"has_agent_yaml"`
	ProjectDir      string      `json:"project_dir"`
	ExplicitRuntime bool        `json:"explicit_runtime"`
}

DetectionResult holds the outcome of project type detection.

func DetectProject

func DetectProject(projectDir string) (*DetectionResult, error)

DetectProject examines a project directory and returns the runtime type. If agent.yaml exists and has a runtime: field, that overrides detection. Otherwise, scan requirements.txt, pyproject.toml, and .py files for langgraph or crewai imports.

type IgnoreMatcher

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

IgnoreMatcher implements .agentpaasignore pattern matching. It supports:

  • Exact filename matches (e.g. ".git")
  • Glob patterns (e.g. "*.pyc", "__pycache__")
  • Directory patterns (e.g. "node_modules/")
  • Comments (lines starting with #)
  • Negation patterns (lines starting with !)

func LoadIgnore

func LoadIgnore(projectDir string) (*IgnoreMatcher, error)

LoadIgnore reads .agentpaasignore from projectDir and returns a matcher. If .agentpaasignore does not exist, returns a matcher with default excludes.

func NewIgnoreMatcher

func NewIgnoreMatcher(content string) *IgnoreMatcher

NewIgnoreMatcher creates a matcher from the given .agentpaasignore content.

func (*IgnoreMatcher) Match

func (m *IgnoreMatcher) Match(filePath string) bool

Match returns true if the given path should be ignored (excluded from build context).

type LLMConfig

type LLMConfig struct {
	Provider   string `yaml:"provider"`   // openai|anthropic|xai
	Model      string `yaml:"model"`      // e.g. "gpt-4o", "claude-sonnet-4", "grok-beta"
	Credential string `yaml:"credential"` // Keychain secret name (e.g. "openai-key")
}

LLMConfig defines the LLM provider and credential binding for the agent. This is used by the harness to route agent.llm() calls through the gateway as credentialed HTTP egress (Option B unified egress).

type LockConfig

type LockConfig struct {
	// BuildResult is the result from BuildImage (T02).
	BuildResult *BuildResult
	// ScanResult is the result from ScanSecrets (T03).
	ScanResult *ScanResult
	// AgentYAML is the parsed agent.yaml.
	AgentYAML *AgentYAML
	// Runtime is the detected runtime type.
	Runtime RuntimeType
	// BaseImageDigest is the digest-pinned base image.
	BaseImageDigest string
	// HarnessVersion is the harness binary version.
	HarnessVersion string
	// Platform is the target platform.
	Platform string
	// SourceDateEpoch is the fixed timestamp.
	SourceDateEpoch time.Time
	// KeyStore is the identity keystore for package identity key signing.
	KeyStore identityKeyStore
	// KeyID is the package identity key ID to use for signing.
	KeyID string
	// PolicyYAML is the raw policy.yaml file contents. If nil/empty (no policy.yaml
	// in the project), the lockfile's PolicyDigest is left empty for backward compat.
	PolicyYAML []byte
}

LockConfig controls the agent.lock generation process.

type OCILayoutError

type OCILayoutError struct {
	Path   string
	Reason string
	Hint   string
	Cause  error
}

OCILayoutError provides an actionable repair hint when the OCI layout is missing or corrupt.

func (*OCILayoutError) Error

func (e *OCILayoutError) Error() string

func (*OCILayoutError) Is

func (e *OCILayoutError) Is(target error) bool

func (*OCILayoutError) Unwrap

func (e *OCILayoutError) Unwrap() error

type ReproducibilityMeta

type ReproducibilityMeta struct {
	// SourceDateEpoch is the fixed timestamp used for the build.
	SourceDateEpoch time.Time `json:"source_date_epoch"`
	// BaseImagePinned is true if the base image is digest-pinned.
	BaseImagePinned bool `json:"base_image_pinned"`
	// DepsLocked is true if dependencies were locked via uv.
	DepsLocked bool `json:"deps_locked"`
	// TarOrder is "sorted" for deterministic tar order.
	TarOrder string `json:"tar_order"`
}

ReproducibilityMeta holds metadata for verifying build reproducibility.

type RuntimeType

type RuntimeType string

RuntimeType represents the detected agent runtime/framework.

const (
	RuntimePython    RuntimeType = "python"
	RuntimeLangGraph RuntimeType = "langgraph"
	RuntimeCrewAI    RuntimeType = "crewai"
	RuntimeUnknown   RuntimeType = "unknown"
)

type ScanConfig

type ScanConfig struct {
	// ProjectDir is the agent project directory to scan.
	ProjectDir string
	// Ignore is the .agentpaasignore matcher (from T01).
	Ignore *IgnoreMatcher
	// AllowPatterns are regex patterns for secrets that are explicitly allowed.
	// Each requires a successful audit append (see AuditAppend below).
	AllowPatterns []string
	// AuditAppend is called to record an allow-pattern justification.
	// If nil, --allow-secret-pattern aborts with an error.
	AuditAppend AuditAppender
}

ScanConfig controls the secret scan process.

type ScanResult

type ScanResult struct {
	// Findings from source tree scan.
	SourceFindings []SecretFinding `json:"source_findings"`
	// Findings from build context scan (after .agentpaasignore applied).
	ContextFindings []SecretFinding `json:"context_findings"`
	// ContextSize is the total build context size in bytes.
	ContextSize int64 `json:"context_size"`
	// ContextSizeWarning is true if ContextSize > 100MB.
	ContextSizeWarning bool `json:"context_size_warning"`
}

ScanResult holds the outcome of a secret scan.

func ScanSecrets

func ScanSecrets(ctx context.Context, cfg ScanConfig) (*ScanResult, error)

ScanSecrets runs gitleaks over the source tree and effective build context. Steps: 1. Run gitleaks on the full source tree (no ignore filtering). 2. Run gitleaks on the effective build context (after .agentpaasignore). 3. Compute build context size (sum of non-ignored file sizes). 4. Warn if context >100MB. 5. Apply allow-patterns (with audit append requirement). Returns ScanResult with findings. Does NOT fail itself — caller checks findings.

func (*ScanResult) FailClosed

func (r *ScanResult) FailClosed() bool

FailClosed returns true if the scan should fail (secrets found that are not allow-patterned with audit append).

func (*ScanResult) HasSecrets

func (r *ScanResult) HasSecrets() bool

HasSecrets returns true if any findings exist (source or context).

type SecretFinding

type SecretFinding struct {
	// File is the relative path from ProjectDir.
	File string `json:"file"`
	// Line is the 1-based line number.
	Line int `json:"line"`
	// Rule is the gitleaks rule ID that matched.
	Rule string `json:"rule"`
	// Secret is the masked secret value (first 4 chars + *** + last 4 chars).
	Secret string `json:"secret"`
	// contains filtered or unexported fields
}

SecretFinding represents a detected secret in the source or build context.

Jump to

Keyboard shortcuts

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