statusmanager

package
v0.0.0-...-89b5c40 Latest Latest
Warning

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

Go to latest
Published: Feb 26, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Overview

Package statusmanager persists ocireconciler reconciliation state as OCI attestations.

This package provides a mechanism for storing and retrieving reconciliation status as signed OCI attestations, using Sigstore's keyless signing with Fulcio and Rekor. It mirrors the githubreconciler/statusmanager pattern but targets OCI digests and stores progress directly as attestations rather than GitHub check runs.

Key Features

  • Keyless signing using Fulcio certificates and Rekor transparency log
  • Identity-scoped attestations with predicate type "https://statusmanager.chainguard.dev/{identity}"
  • REPLACE semantics ensuring exactly one attestation per digest/predicate pair
  • Full signature verification on read using cosign verification
  • Support for repository override (similar to COSIGN_REPOSITORY)

Basic Usage

Create a Manager and use sessions to track reconciliation state:

// Create a manager (requires GCP service account credentials)
mgr, err := statusmanager.New[MyDetails](ctx, "my-reconciler")
if err != nil {
    return err
}

// Start a session for a specific digest
session := mgr.NewSession(digest)

// Check previous state
observed, err := session.ObservedState(ctx)
if err != nil {
    return err
}
if observed != nil {
    log.Printf("Previous state: %+v", observed.Details)
}

// Perform reconciliation work...

// Record new state
err = session.SetActualState(ctx, &statusmanager.Status[MyDetails]{
    Details: MyDetails{Result: "success"},
})

Status Type

The Status type is generic over the Details field, allowing you to store arbitrary structured data alongside the automatically-populated ObservedGeneration:

type Status[T any] struct {
    ObservedGeneration string // Automatically set to the digest
    Details            T      // Your custom status data
}

Repository Override

When the subject image is in a registry that doesn't support attestations, or when you want to store attestations separately, use WithRepositoryOverride:

mgr, err := statusmanager.New[MyDetails](ctx, "my-reconciler",
    statusmanager.WithRepositoryOverride("gcr.io/my-project/attestations"),
)

This works similarly to setting COSIGN_REPOSITORY with cosign.

Read-Only Managers

For consumers that only need to read status (not write), use NewReadOnly with WithExpectedIdentity to specify which signing identity to verify:

mgr, err := statusmanager.NewReadOnly[MyDetails](ctx, "my-reconciler",
    statusmanager.WithExpectedIdentity("[email protected]"),
)

Authentication

The manager uses Google Cloud service account credentials for both:

  • Obtaining ID tokens for Fulcio keyless signing
  • Registry authentication (when using WithRemoteOptions with google.Keychain)

Example with registry authentication:

mgr, err := statusmanager.New[MyDetails](ctx, "my-reconciler",
    statusmanager.WithRemoteOptions(remote.WithAuthFromKeychain(google.Keychain)),
)

Thread Safety

Manager instances are safe for concurrent use. Each Session should be used by a single goroutine, but multiple sessions can be created from the same Manager concurrently.

Index

Constants

View Source
const (

	// RekorHTTPLimit is the maximum HTTP request size accepted by Rekor's reverse proxy.
	//
	// This limit was determined empirically (2025-12-29) by generating realistic SBOM-like
	// payloads at varying sizes and measuring the actual HTTP request sizes after base64
	// encoding and DSSE envelope wrapping. Testing showed:
	//   - 75 MB payload → 127.6 MB HTTP request ✅ SUCCESS
	//   - 100 MB payload → 170.3 MB HTTP request ❌ FAILED (502 Bad Gateway)
	//
	// The limit (~150 MB) is imposed by Rekor's reverse proxy (nginx/load balancer),
	// not the Rekor application itself.
	//
	// For production use with airflow APK (14.3 MB SBOM, 63 vuln matches):
	//   - BEFORE metadata stripping: 116.52 MB status → 198 MB HTTP ❌ 502 Bad Gateway
	//   - AFTER metadata stripping: 13.95 MB status → 23.72 MB HTTP ✅ 201 Created
	RekorHTTPLimit = 150 * 1024 * 1024 // 150 MB

	// StatusJSONSizeLimit is the maximum serialized JSON status size before base64/DSSE overhead.
	//
	// Calculation: RekorHTTPLimit / 1.7 (empirically measured overhead factor)
	//   - Base64 encoding adds ~33% overhead (4/3 ratio)
	//   - DSSE envelope wrapping adds additional ~28% overhead
	//   - Combined overhead factor: ~1.7x
	//
	// This gives us: 150 MB / 1.7 ≈ 88 MB for the raw JSON status
	StatusJSONSizeLimit = RekorHTTPLimit * 10 / 17 // ~88 MB
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Manager

type Manager[T any] struct {
	// contains filtered or unexported fields
}

Manager writes and reads reconciliation status as attestations.

func New

func New[T any](ctx context.Context, identity string, opts ...Option) (*Manager[T], error)

New constructs a Manager capable of mutating attestations.

func NewReadOnly

func NewReadOnly[T any](ctx context.Context, identity string, opts ...Option) (*Manager[T], error)

NewReadOnly constructs a Manager that can only read status.

func (*Manager[T]) NewSession

func (m *Manager[T]) NewSession(digest name.Digest) *Session[T]

NewSession initializes a reconciliation session for the provided digest.

type Option

type Option func(*config)

Option customizes the Manager.

func WithExpectedIdentity

func WithExpectedIdentity(identity cosign.Identity) Option

WithExpectedIdentity specifies the sigstore identity to verify when reading attestations. This option is required for read-only managers and must not be provided for writable managers (which extract the identity from their credentials).

func WithOIDCProvider

func WithOIDCProvider(p fulcio.OIDCProvider) Option

WithOIDCProvider overrides the OIDC provider used for Fulcio keyless signing.

func WithRemoteOptions

func WithRemoteOptions(opts ...remote.Option) Option

WithRemoteOptions appends remote.Options applied when reading/writing attestations.

func WithRepositoryOverride

func WithRepositoryOverride(repo string) Option

WithRepositoryOverride directs attestation writes to the provided repository string.

func WithSigner

func WithSigner(s types.CosignerSignerVerifier) Option

WithSigner injects a preconfigured signer (useful for tests).

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent customizes the user-agent attached to Fulcio/Rekor requests.

type Session

type Session[T any] struct {
	// contains filtered or unexported fields
}

Session represents reconciliation state for a single digest.

func (*Session[T]) ObservedState

func (s *Session[T]) ObservedState(ctx context.Context) (*Status[T], error)

ObservedState returns the latest recorded status, if any.

func (*Session[T]) SetActualState

func (s *Session[T]) SetActualState(ctx context.Context, status *Status[T]) error

SetActualState persists the provided status as an attestation.

type Status

type Status[T any] struct {
	ObservedGeneration string `json:"observedGeneration"`
	Details            T      `json:"details"`
}

Status captures serialized reconciliation progress for a digest.

Jump to

Keyboard shortcuts

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