agentpush

package
v0.26.0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: AGPL-3.0 Imports: 11 Imported by: 0

Documentation

Overview

Package agentpush isolates the live-push flow that builds a workspace's secret batch (session-independent, via the one builder) and delivers it to the running workspace pod's agentd via HTTP. It exists as a service (not a handler method) because multiple call sites need it:

  • SetBindings (handler) — user toggled a binding in the settings drawer.
  • ReloadSecrets (handler) — explicit POST /workspaces/:id/reload-secrets.
  • secretautopush — watcher-driven push after pod recreation (worklog 0591), the reason this package was extracted.

Batch construction carries no session identity (design 0052 §4.1, US-70.2): the builder decrypts user entries via the server-side DEK unwrap, so every pusher — request-bound or background — produces the same batch for the same workspace state.

See worklog 0589 for the design rationale — this package is the concrete satisfier of the SecretPusher interface defined by consumers.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoPodIPResolver — the service was constructed without a resolver.
	// A wiring bug; the service can't deliver anything and should not have
	// been used. Return 503 at the HTTP boundary.
	ErrNoPodIPResolver = errors.New("agentpush: pod IP resolver not configured")
	// ErrNoRunningPod — the workspace exists but has no reachable pod
	// right now (Pending, Suspended, or recreating). Not a hard failure
	// for the push flow: user-initiated callers surface 409, the
	// pod-recreation auto-push logs at info and increments the "no_pod"
	// metric outcome (this is transient, expected during pod boot races).
	ErrNoRunningPod = errors.New("agentpush: workspace has no running pod")
	// ErrNoPasswordProvider — the service was constructed without a
	// password provider. A wiring bug; agentd enforces Basic auth on
	// reload-secrets (#848) so the dispatch cannot succeed.
	ErrNoPasswordProvider = errors.New("agentpush: password provider not configured")
)

Sentinels — callers switch on these to map to HTTP status codes.

Functions

This section is empty.

Types

type BatchBuilder added in v0.26.0

type BatchBuilder interface {
	BuildWorkspaceBatch(ctx context.Context, ownerUserID, workspaceID string) (*secrets.Batch, *secrets.BuildDegrade, error)
}

BatchBuilder is the minimum surface Push needs to build the payload: the one workspace batch builder, degrading loudly (machine-readable reason) when the user's DEK cannot be unwrapped. Satisfied by *secrets.SecretService.BuildWorkspaceBatch.

type ModelCache

type ModelCache interface {
	Evict(workspaceID string)
}

ModelCache is invalidated after a successful push so ListModels reflects the fresh provider set. Optional; nil skips the eviction.

type Option

type Option func(*Service)

Option configures a Service.

func WithHTTPClient

func WithHTTPClient(c *http.Client) Option

WithHTTPClient overrides the default 5s-timeout HTTP client (tests).

func WithLogger

func WithLogger(l pkginterfaces.LoggerInterface) Option

WithLogger installs the logger used for non-fatal warnings.

func WithMetricsHook

func WithMetricsHook(hook func(outcome string)) Option

WithMetricsHook installs an outcome-recording callback used by the pod-recreation auto-push path. Outcomes: "success", "inject_failed", "reload_failed", "no_pod". Optional; nil is silently skipped.

func WithModelCache

func WithModelCache(c ModelCache) Option

WithModelCache installs the cache to evict after a successful push.

func WithPasswordProvider added in v0.15.9

func WithPasswordProvider(p PasswordProvider) Option

WithPasswordProvider installs the workspace-password lookup required for the authenticated reload-secrets dispatch (#848).

func WithPodIPResolver

func WithPodIPResolver(r PodIPResolver) Option

WithPodIPResolver installs the pod-IP lookup.

type PasswordProvider added in v0.15.9

type PasswordProvider interface {
	WorkspacePassword(ctx context.Context, workspaceID string) (string, error)
}

PasswordProvider resolves the workspace's agentd Basic-auth password. agentd rejects unauthenticated reload-secrets posts (#848); satisfied by interfaces.WorkspacePasswordProvider (US-46.11).

type PodIPResolver

type PodIPResolver interface {
	GetWorkspacePodIP(ctx context.Context, userID, workspaceID string) (string, error)
}

PodIPResolver looks up the running pod IP for a workspace. Returns an empty string (and nil error, or a wrapped one) when no pod is running.

type Result

type Result struct {
	Reloaded  int  `json:"reloaded"`
	Restarted bool `json:"restarted"`
}

Result summarizes what agentd did with the pushed payload.

type Service

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

Service is the concrete SecretPusher.

func New

func New(builder BatchBuilder, opts ...Option) *Service

New builds a Service. Only builder is required; podResolver may be nil during early wiring in which case Push returns ErrNoPodIPResolver. modelCache and logger are optional.

func (*Service) Push

func (s *Service) Push(ctx context.Context, userID, workspaceID string) (Result, error)

Push builds the workspace batch (the one builder — session identity plays no role in what decrypts) and posts the mixed-fleet legacy body to the workspace pod's agentd.

A degraded build (user DEK unavailable) is still pushed — the server-KEK subset keeps the pod's platform providers alive — but the degrade is logged at Warn with its machine-readable reason (I10: no silent partials).

Empty payloads ('[]') are still sent — agentd uses them to CLEAR its in-memory secret materialisations. Without this, an unbind would leave the live pod with stale plaintext until restart.

Jump to

Keyboard shortcuts

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