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 ¶
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 ¶
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 ¶
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 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 ¶
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.