componentsdk

package
v0.1.23 Latest Latest
Warning

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

Go to latest
Published: Mar 3, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package componentsdk provides a framework for building epack components (collectors, tools, remote adapters, and utilities) that are conformant with the epack component specification.

The SDK eliminates protocol boilerplate and ensures conformance by construction:

  • Automatic --capabilities handling
  • Automatic result.json generation with correct timestamps
  • Automatic exit code mapping
  • Pack reading with size limits enforced
  • Output path validation (no traversal, relative paths only)

Building a Tool

func main() {
    componentsdk.RunTool(componentsdk.ToolSpec{
        Name:         "my-analyzer",
        Version:      "1.0.0",
        Description:  "Analyzes evidence packs",
        RequiresPack: true,
    }, func(ctx componentsdk.ToolContext) error {
        pack := ctx.Pack()
        // ... analyze pack ...
        return ctx.WriteOutput("analysis.json", result)
    })
}

Building a Collector

func main() {
    componentsdk.RunCollector(componentsdk.CollectorSpec{
        Name:    "my-service",
        Version: "1.0.0",
    }, func(ctx componentsdk.CollectorContext) error {
        data := fetchFromAPI(ctx.Config(), ctx.Secret("API_TOKEN"))
        return ctx.Emit(data)
    })
}

Conformance

Components built with this SDK automatically pass conformance tests for:

  • Binary naming (C-001, C-002, C-003)
  • Capabilities output (TOOL-001, COL-002, REM-001, etc.)
  • Result format (TOOL-030 through TOOL-052)
  • Exit codes (C-020, C-021, C-022)
  • Timestamp formatting (TOOL-050, TOOL-051)
  • Output path validation (TOOL-040, TOOL-041, TOOL-042)

Index

Constants

View Source
const (
	// MaxArtifactSize is the maximum size for a single artifact (100 MB).
	MaxArtifactSize = 100 * 1024 * 1024

	// MaxManifestSize is the maximum size for manifest.json (10 MB).
	MaxManifestSize = 10 * 1024 * 1024
)

Pack size limits (enforced to prevent DoS)

View Source
const ProgressProtocolVersion = 1

ProgressProtocolVersion is the version of the progress message protocol.

Variables

View Source
var ErrArtifactTooLarge = errors.New("artifact exceeds maximum size")

ErrArtifactTooLarge is returned when an artifact exceeds MaxArtifactSize.

Functions

func NewAuthError

func NewAuthError(format string, args ...any) error

func NewConfigError

func NewConfigError(format string, args ...any) error

Helper functions to create typed errors

func NewNetworkError

func NewNetworkError(format string, args ...any) error

func RunCollector

func RunCollector(spec CollectorSpec, handler CollectorHandler)

RunCollector executes the collector handler with full protocol compliance. It handles --capabilities, --version, environment parsing, signal handling, timeout, protocol envelope output, and proper exit codes. This function does not return.

func RunRemote

func RunRemote(spec RemoteSpec, handler RemoteHandler)

RunRemote executes the remote adapter with full protocol compliance. It handles --capabilities, --version, JSON stdin/stdout protocol, and error formatting. This function does not return.

func RunTool

func RunTool(spec ToolSpec, handler ToolHandler)

RunTool executes the tool handler with full protocol compliance. It handles --capabilities, --version, environment parsing, result.json generation, and proper exit codes. This function does not return.

func RunUtility

func RunUtility(spec UtilitySpec, handler UtilityHandler)

RunUtility executes the utility handler with protocol compliance. It handles --version, --capabilities, --help, and proper exit codes. This function does not return.

Types

type Artifact

type Artifact = packspec.Artifact

Type aliases from packspec for consistent types across the codebase. These ensure componentsdk uses the same Manifest and Artifact types as pack/.

type AuthError

type AuthError struct{ Err error }

AuthError indicates an authentication error (exit code 3).

func (AuthError) Error

func (e AuthError) Error() string

type CollectorContext

type CollectorContext interface {
	// Context returns a context that is cancelled on SIGTERM or timeout.
	Context() context.Context

	// Name returns the collector name from EPACK_COLLECTOR_NAME.
	Name() string

	// Config returns the parsed configuration, or nil if none provided.
	Config() map[string]any

	// Secret returns the value of an environment variable.
	// Use this for secrets listed in epack.yaml secrets array.
	Secret(name string) string

	// Status reports a status update during collection.
	// Use this for indeterminate progress like "Connecting to API...".
	// Status messages are written to stdout as JSON for the CLI to display.
	Status(message string)

	// Progress reports progress with current/total counts.
	// Use this when iterating over a known number of items.
	// Example: Progress(5, 100, "Fetching repositories")
	Progress(current, total int64, message string)

	// Emit outputs the collected data. This should be called once.
	// The data is wrapped in the protocol envelope automatically.
	Emit(data any) error
}

CollectorContext provides access to the collector execution environment.

type CollectorHandler

type CollectorHandler func(ctx CollectorContext) error

CollectorHandler is the function signature for collector implementations. Return nil for success, or an error for failure. Use the typed error returns (ConfigError, AuthError, NetworkError) for appropriate exit codes.

type CollectorMetadata

type CollectorMetadata struct {
	// Name is the collector name.
	Name string `json:"name"`

	// Version is the collector version.
	Version string `json:"version,omitempty"`

	// CollectedAt is the collection timestamp.
	CollectedAt string `json:"collected_at,omitempty"`
}

CollectorMetadata contains metadata about a collector run. This is SDK-specific metadata for collector components.

type CollectorSpec

type CollectorSpec struct {
	// Name is the collector name (without epack-collector- prefix).
	// Must match ^[a-z0-9][a-z0-9._-]{0,63}$
	Name string

	// Version is the semantic version (e.g., "1.0.0").
	Version string

	// Commit is the git commit SHA that built this binary.
	// Set via ldflags at build time for supply chain provenance.
	Commit string

	// Description is a human-readable description of what the collector gathers.
	Description string

	// Timeout is the maximum execution time. Default is 60 seconds.
	Timeout time.Duration
}

CollectorSpec defines the collector's metadata.

type ConfigError

type ConfigError struct{ Err error }

ConfigError indicates a configuration error (exit code 2).

func (ConfigError) Error

func (e ConfigError) Error() string

type DownloadInfo

type DownloadInfo struct {
	URL       string `json:"url"`
	ExpiresAt string `json:"expires_at,omitempty"`
}

type EmbeddedAttestation

type EmbeddedAttestation = packspec.EmbeddedAttestation

Type aliases from packspec for consistent types across the codebase. These ensure componentsdk uses the same Manifest and Artifact types as pack/.

type Links struct {
	Release string `json:"release,omitempty"`
	Pack    string `json:"pack,omitempty"`
}

type Manifest

type Manifest = packspec.Manifest

Type aliases from packspec for consistent types across the codebase. These ensure componentsdk uses the same Manifest and Artifact types as pack/.

type NetworkError

type NetworkError struct{ Err error }

NetworkError indicates a network/API error (exit code 4).

func (NetworkError) Error

func (e NetworkError) Error() string

type Pack

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

Pack provides read-only access to an evidence pack.

func OpenPack

func OpenPack(path string) (*Pack, error)

OpenPack opens an evidence pack file and reads its manifest. The caller must call Close() when done.

func (*Pack) Artifacts

func (p *Pack) Artifacts() []Artifact

Artifacts returns all artifacts in the pack.

func (*Pack) Close

func (p *Pack) Close() error

Close closes the pack and releases resources.

func (*Pack) HasArtifact

func (p *Pack) HasArtifact(path string) bool

HasArtifact checks if an artifact exists at the given path.

func (*Pack) ListFiles

func (p *Pack) ListFiles() []string

ListFiles returns all file paths in the pack (including non-artifacts).

func (*Pack) Manifest

func (p *Pack) Manifest() *Manifest

Manifest returns the pack's manifest.

func (*Pack) ReadArtifact

func (p *Pack) ReadArtifact(path string) ([]byte, error)

ReadArtifact reads the contents of an artifact by path. Returns ErrArtifactTooLarge if the artifact exceeds MaxArtifactSize.

func (*Pack) ReadArtifactJSON

func (p *Pack) ReadArtifactJSON(path string, v any) error

ReadArtifactJSON reads and unmarshals a JSON artifact.

type PackInfo

type PackInfo struct {
	Digest    string `json:"digest"`
	SizeBytes int64  `json:"size_bytes"`
}

type PackResult

type PackResult struct {
	Digest    string `json:"digest"`
	SizeBytes int64  `json:"size_bytes,omitempty"`
}

type ProgressMessage added in v0.1.17

type ProgressMessage struct {
	Type            string `json:"type"`              // Always "epack_progress"
	ProtocolVersion int    `json:"protocol_version"`  // Progress protocol version
	Kind            string `json:"kind"`              // "status" or "progress"
	Message         string `json:"message"`           // Human-readable message
	Current         int64  `json:"current,omitempty"` // For kind="progress": current value
	Total           int64  `json:"total,omitempty"`   // For kind="progress": total value
}

ProgressMessage is the JSON envelope for progress updates written to stdout. Components can emit zero or more progress messages during execution.

type Provenance

type Provenance = packspec.Provenance

Type aliases from packspec for consistent types across the codebase. These ensure componentsdk uses the same Manifest and Artifact types as pack/.

type PullFinalizeRequest

type PullFinalizeRequest struct {
	RequestID     string `json:"request_id"`
	FinalizeToken string `json:"finalize_token"`
	PackDigest    string `json:"pack_digest"`
	Identity      string `json:"identity,omitempty"`
}

type PullFinalizeResponse

type PullFinalizeResponse struct {
	Confirmed bool `json:"confirmed"`
}

type PullPrepareRequest

type PullPrepareRequest struct {
	RequestID string       `json:"request_id"`
	Target    RemoteTarget `json:"target"`
	Ref       PullRef      `json:"ref"`
	Identity  string       `json:"identity,omitempty"`
}

type PullPrepareResponse

type PullPrepareResponse struct {
	Download      DownloadInfo `json:"download"`
	Pack          PackResult   `json:"pack"`
	FinalizeToken string       `json:"finalize_token"`
}

type PullRef

type PullRef struct {
	Digest    string `json:"digest,omitempty"`
	ReleaseID string `json:"release_id,omitempty"`
	Version   string `json:"version,omitempty"`
	Latest    bool   `json:"latest,omitempty"`
}

type PushFinalizeRequest

type PushFinalizeRequest struct {
	RequestID     string `json:"request_id"`
	FinalizeToken string `json:"finalize_token"`
	Identity      string `json:"identity,omitempty"`
}

type PushFinalizeResponse

type PushFinalizeResponse struct {
	Release ReleaseResult `json:"release"`
	Links   *Links        `json:"links,omitempty"`
}

type PushPrepareRequest

type PushPrepareRequest struct {
	RequestID string       `json:"request_id"`
	Target    RemoteTarget `json:"target"`
	Pack      PackInfo     `json:"pack"`
	Release   ReleaseInfo  `json:"release"`
	Identity  string       `json:"identity,omitempty"`
}

type PushPrepareResponse

type PushPrepareResponse struct {
	Upload        UploadInfo `json:"upload"`
	FinalizeToken string     `json:"finalize_token"`
}

type ReleaseInfo

type ReleaseInfo struct {
	Version     string `json:"version,omitempty"`
	Description string `json:"description,omitempty"`
}

type ReleaseResult

type ReleaseResult struct {
	ReleaseID  string `json:"release_id"`
	PackDigest string `json:"pack_digest"`
	Version    string `json:"version,omitempty"`
}

type RemoteAuth

type RemoteAuth struct {
	Modes []string `json:"modes"` // e.g., ["device_code", "oidc_token", "api_key"]
}

RemoteAuth describes authentication capabilities.

type RemoteError

type RemoteError struct {
	Code      string `json:"code"`
	Message   string `json:"message"`
	Retryable bool   `json:"retryable,omitempty"`
	Action    string `json:"action,omitempty"`
}

RemoteError represents an error response.

func ErrAuthRequired

func ErrAuthRequired(message string) RemoteError

Common error constructors

func ErrConflict

func ErrConflict(message string) RemoteError

func ErrForbidden

func ErrForbidden(message string) RemoteError

func ErrNetworkError

func ErrNetworkError(message string) RemoteError

func ErrNotFound

func ErrNotFound(message string) RemoteError

func ErrRateLimited

func ErrRateLimited(message string) RemoteError

func ErrServerError

func ErrServerError(message string) RemoteError

func (RemoteError) Error

func (e RemoteError) Error() string

type RemoteFeatures

type RemoteFeatures struct {
	// PrepareFinalize indicates support for push.prepare/push.finalize.
	PrepareFinalize bool `json:"prepare_finalize"`

	// Pull indicates support for pull.prepare/pull.finalize.
	Pull bool `json:"pull"`

	// RunsSync indicates support for runs.sync.
	RunsSync bool `json:"runs_sync,omitempty"`

	// AuthLogin indicates support for auth.login.
	AuthLogin bool `json:"auth_login,omitempty"`

	// Whoami indicates support for auth.whoami.
	Whoami bool `json:"whoami,omitempty"`
}

RemoteFeatures describes which operations a remote adapter supports.

type RemoteHandler

type RemoteHandler interface {
	// PushPrepare handles push.prepare requests.
	// Returns upload instructions or an error.
	PushPrepare(req PushPrepareRequest) (*PushPrepareResponse, error)

	// PushFinalize handles push.finalize requests.
	// Returns release information or an error.
	PushFinalize(req PushFinalizeRequest) (*PushFinalizeResponse, error)

	// PullPrepare handles pull.prepare requests.
	// Returns download instructions or an error.
	PullPrepare(req PullPrepareRequest) (*PullPrepareResponse, error)

	// PullFinalize handles pull.finalize requests.
	// Returns confirmation or an error.
	PullFinalize(req PullFinalizeRequest) (*PullFinalizeResponse, error)
}

RemoteHandler handles incoming requests from epack.

type RemoteLimits

type RemoteLimits struct {
	MaxPackSize int64 `json:"max_pack_size,omitempty"` // bytes
}

RemoteLimits describes size and rate limits.

type RemoteSpec

type RemoteSpec struct {
	// Name is the adapter name (without epack-remote- prefix).
	// Must match ^[a-z0-9][a-z0-9._-]{0,63}$
	Name string

	// Version is the semantic version (e.g., "1.0.0").
	Version string

	// Description is a human-readable description.
	Description string

	// Features describes which operations the adapter supports.
	Features RemoteFeatures

	// Auth describes supported authentication modes.
	Auth *RemoteAuth

	// Limits describes any size or rate limits.
	Limits *RemoteLimits
}

RemoteSpec defines the remote adapter's metadata and capabilities.

type RemoteTarget

type RemoteTarget struct {
	Workspace   string `json:"workspace"`
	Environment string `json:"environment,omitempty"`
	Stream      string `json:"stream,omitempty"`
}

type Source

type Source = packspec.Source

Type aliases from packspec for consistent types across the codebase. These ensure componentsdk uses the same Manifest and Artifact types as pack/.

type SourcePack

type SourcePack = packspec.SourcePack

Type aliases from packspec for consistent types across the codebase. These ensure componentsdk uses the same Manifest and Artifact types as pack/.

type ToolContext

type ToolContext interface {
	// RunID returns the unique run identifier.
	RunID() string

	// RunDir returns the run directory path where outputs should be written.
	RunDir() string

	// Pack returns the pack reader if a pack was provided.
	// Returns nil if no pack is available (check ToolSpec.RequiresPack).
	Pack() *Pack

	// PackPath returns the path to the pack file, or empty string if none.
	PackPath() string

	// PackDigest returns the pack's digest, or empty string if none.
	PackDigest() string

	// Config returns the parsed configuration, or nil if none provided.
	Config() map[string]any

	// Status reports a status update during tool execution.
	// Use this for indeterminate progress like "Analyzing pack...".
	// Status messages are written to stdout as JSON for the CLI to display.
	Status(message string)

	// Progress reports progress with current/total counts.
	// Use this when iterating over a known number of items.
	// Example: Progress(5, 100, "Processing artifacts")
	Progress(current, total int64, message string)

	// WriteOutput writes data as JSON to the outputs directory and registers it.
	// The path must be a simple filename (no directories, no traversal).
	// Use WriteOutputBytes for non-JSON content.
	WriteOutput(filename string, data any) error

	// WriteOutputBytes writes raw bytes to the outputs directory and registers it.
	// The path must be a simple filename (no directories, no traversal).
	WriteOutputBytes(filename string, data []byte, mediaType string) error

	// Warn adds a warning to the result.
	Warn(code, message string, path string)

	// Error adds an error to the result (does not stop execution).
	Error(code, message string, path string)
}

ToolContext provides access to the tool execution environment.

type ToolHandler

type ToolHandler func(ctx ToolContext) error

ToolHandler is the function signature for tool implementations. Return nil for success, or an error for failure. The SDK handles result.json generation in both cases.

type ToolSpec

type ToolSpec struct {
	// Name is the tool name (without epack-tool- prefix).
	// Must match ^[a-z0-9][a-z0-9._-]{0,63}$
	Name string

	// Version is the semantic version (e.g., "1.0.0").
	Version string

	// Description is a human-readable description of what the tool does.
	Description string

	// RequiresPack indicates whether this tool requires a pack to operate.
	// If true, ToolContext.Pack() will be available.
	RequiresPack bool

	// Network indicates whether the tool requires network access.
	Network bool

	// RequiresTools lists other tools this tool depends on.
	RequiresTools []string

	// RequiresOutputs lists outputs from other tools this tool depends on.
	RequiresOutputs []string
}

ToolSpec defines the tool's metadata and capabilities.

type UploadInfo

type UploadInfo struct {
	Method    string            `json:"method"`
	URL       string            `json:"url"`
	Headers   map[string]string `json:"headers,omitempty"`
	ExpiresAt string            `json:"expires_at,omitempty"`
}

type UtilityHandler

type UtilityHandler func(args []string) error

UtilityHandler is the function signature for utility implementations. It receives the command-line arguments (excluding the program name and any flags already handled like --version, --capabilities, --help). Return nil for success, or an error for failure.

type UtilitySpec

type UtilitySpec struct {
	// Name is the utility name (without epack-util- prefix).
	// Must match ^[a-z0-9][a-z0-9._-]{0,63}$
	Name string

	// Version is the semantic version (e.g., "1.0.0").
	Version string

	// Description is a human-readable description of what the utility does.
	Description string

	// Usage is the usage synopsis shown in --help output.
	// Example: "epack-util-viewer [options] <pack>"
	Usage string

	// Examples are usage examples shown in --help output.
	Examples []string
}

UtilitySpec defines the utility's metadata and capabilities.

Directories

Path Synopsis
fixtures
collector command
Minimal collector fixture for SDK conformance testing.
Minimal collector fixture for SDK conformance testing.
remote command
Minimal remote adapter fixture for SDK conformance testing.
Minimal remote adapter fixture for SDK conformance testing.
tool command
Minimal tool fixture for SDK conformance testing.
Minimal tool fixture for SDK conformance testing.

Jump to

Keyboard shortcuts

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