Documentation
¶
Overview ¶
Package response applies governed defensive response actions (issue #425): isolate a host, quarantine a file, stop a process. It adds no new trust model — every action goes through the SAME admission gate (internal/usecase/safety) as a DAST probe and an exploitation step, is approved by a human (never a model) with the approval sealed as evidence, is argv-only, is reversible, and is halted by the #418 kill switch. Apply is reachable only after admission plus a recorded human approval.
Index ¶
- Constants
- Variables
- func MarshalVerificationEvidence(req VerificationRequest, outcome rdom.Verification, verifierID string, ...) ([]byte, error)
- type EffectVerifier
- type ExecOutcome
- type ExecRequest
- type Executor
- type IncidentCoordinator
- type ObservationDispatcher
- type PlanStep
- type ReconciliationRunner
- type Record
- type Service
- func (s *Service) Apply(ctx context.Context, engagementID shared.ID, action rdom.Action, ...) (Record, error)
- func (s *Service) Decide(ctx context.Context, actionID shared.ID, reviewer string, approve bool, ...) (Record, error)
- func (s *Service) DryRun(action rdom.Action) ([]PlanStep, error)
- func (s *Service) HaltResponses(ctx context.Context, tenantID shared.ID, actor, reason string) (int, error)
- func (s *Service) ListByState(ctx context.Context, state State) ([]Record, error)
- func (s *Service) PrepareIncidentResponse(ctx context.Context, engagementID shared.ID, action rdom.Action, ...) (Record, error)
- func (s *Service) ReconcileAudits(ctx context.Context) error
- func (s *Service) ReconcileHaltDispatches(ctx context.Context) error
- func (s *Service) ReconcilePending(ctx context.Context) error
- func (s *Service) ReconcileVerifications(ctx context.Context) error
- func (s *Service) Revert(ctx context.Context, actionID shared.ID, target engagement.Target, ...) (Record, error)
- func (s *Service) SetApprovalDecider(approvals approvalDecider)
- func (s *Service) SetHaltWriter(haltWriter ports.ResponseHaltWriter) error
- func (s *Service) SetVerificationTimeout(timeout time.Duration) error
- func (s *Service) VerifiedProvenance(ctx context.Context, actionID shared.ID) (VerificationProvenance, error)
- type SimulationExecutor
- func (SimulationExecutor) Execute(_ context.Context, req ExecRequest) (ExecOutcome, error)
- func (SimulationExecutor) Halt(context.Context, shared.ID, int64) error
- func (SimulationExecutor) Identity() string
- func (SimulationExecutor) ResolveAgent(context.Context, shared.ID, responsesaga.TargetFingerprint) (shared.ID, error)
- func (SimulationExecutor) Supports(kind rdom.Kind) bool
- type State
- type TelemetryEffectVerifier
- type TenantLister
- type Verification
- type VerificationProvenance
- type VerificationReceipt
- type VerificationRequest
- type VerificationSource
Constants ¶
const ( StatePending = rdom.StatePending StateApplied = rdom.StateApplied StateReverted = rdom.StateReverted StateCancelled = rdom.StateCancelled StateViolation = rdom.StateViolation VerificationPending = rdom.VerificationPending VerificationSucceeded = rdom.VerificationSucceeded VerificationFailed = rdom.VerificationFailed VerificationUnknown = rdom.VerificationUnknown )
const DefaultReconciliationInterval = time.Minute
DefaultReconciliationInterval bounds how long a committed halt can wait for executor replay.
const (
DefaultVerificationTimeout = 2 * time.Minute
)
const VerificationEvidenceKind = "response_verification"
VerificationEvidenceKind identifies canonical response-verification claims in the evidence chain.
Variables ¶
var ErrAttemptDeadlineExceeded = errors.New("response attempt deadline exceeded")
ErrAttemptDeadlineExceeded means a durable response attempt exhausted its authorization and evidence window.
var ErrVerificationPending = errors.New("response verification observation pending")
ErrVerificationPending means no signed post-condition has arrived yet. It is not insufficient coverage: callers must leave the attempt in Verifying until an explicit unknown report or a governed timeout.
Functions ¶
func MarshalVerificationEvidence ¶ added in v0.2.0
func MarshalVerificationEvidence(req VerificationRequest, outcome rdom.Verification, verifierID string, source *VerificationSource) ([]byte, error)
MarshalVerificationEvidence returns the one canonical payload accepted for a verification receipt. Verifier adapters seal these exact bytes before returning the resulting evidence ID.
Types ¶
type EffectVerifier ¶ added in v0.2.0
type EffectVerifier interface {
Identity() string
Verify(ctx context.Context, req VerificationRequest) (VerificationReceipt, error)
}
EffectVerifier confirms, against telemetry, whether an applied action's intended EFFECT actually took hold on the target (#638). It is READ-ONLY — it observes, it never executes anything on the host — so wiring it crosses no execution boundary. `CommandApplied ≠ VerifiedSucceeded`: a kill whose syscall returned but whose process is still observed alive verifies as Failed; a target with no covering telemetry verifies as Unknown, never silently a success. Optional (nil ⇒ verification is not run).
type ExecOutcome ¶
type ExecOutcome = ports.ResponseExecOutcome
type ExecRequest ¶
type ExecRequest = ports.ResponseExecRequest
type Executor ¶
type Executor = ports.ResponseExecutor
Executor and its DTOs remain aliases for compatibility; the executable boundary lives in ports.
type IncidentCoordinator ¶ added in v0.2.0
type IncidentCoordinator struct {
// contains filtered or unexported fields
}
IncidentCoordinator binds the governed response lifecycle to the incident event log. Standalone response execution remains available for non-incident workflows, while incident-triggered execution cannot run unless its append-only ResponseRequested event is durable first.
func NewIncidentCoordinator ¶ added in v0.2.0
func NewIncidentCoordinator(responses incidentResponseApplier, incidents incidentResponseAppender, clock ports.Clock) (*IncidentCoordinator, error)
func (*IncidentCoordinator) Apply ¶ added in v0.2.0
func (c *IncidentCoordinator) Apply(ctx context.Context, incidentID shared.ID, action rdom.Action, target engagement.Target, fingerprint responsesaga.TargetFingerprint, actor string) (Record, error)
Apply records the request before admission/execution, then records verification only after the response service accepts independently attested telemetry evidence. Retries do not duplicate incident events.
func (*IncidentCoordinator) ReconcileIncidentLinks ¶ added in v0.2.0
func (c *IncidentCoordinator) ReconcileIncidentLinks(ctx context.Context) error
ReconcileIncidentLinks repairs only the narrow crash window after a response saga durably succeeds verification but before the corresponding ResponseVerified event is appended. The link source is the append-only incident projection, and verification provenance is reloaded from the response service; neither the reconciliation input nor any stored client request can supply provenance.
type ObservationDispatcher ¶ added in v0.2.0
type ObservationDispatcher = ports.ResponseObservationDispatcher
ObservationDispatcher remains an alias for compatibility; the dispatcher port lives in ports.
type PlanStep ¶
type PlanStep struct {
Label string
Argv []string
BlastRadius offensivepolicy.Radius
}
PlanStep is one line of a dry run: the action or reversal that WOULD run, and its argv.
type ReconciliationRunner ¶ added in v0.2.0
type ReconciliationRunner struct {
// contains filtered or unexported fields
}
ReconciliationRunner repairs durable response obligations within each tenant's RLS context.
func NewReconciliationRunner ¶ added in v0.2.0
func NewReconciliationRunner(tenants TenantLister, reconciler pendingReconciler, log *slog.Logger, incidentLinks ...incidentLinkReconciler) (*ReconciliationRunner, error)
func (*ReconciliationRunner) RunOnce ¶ added in v0.2.0
func (r *ReconciliationRunner) RunOnce(ctx context.Context) error
func (*ReconciliationRunner) RunPeriodic ¶ added in v0.2.0
func (r *ReconciliationRunner) RunPeriodic(ctx context.Context, interval time.Duration)
type Record ¶
Record and State are the domain types (domain/response); re-exported as aliases so callers of this usecase package need not import both.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service applies response actions under the shared governance.
func NewService ¶
func NewService(gate *safety.Gate, exec Executor, store ports.ResponseAuditStore, audit ports.IdempotentAuditLogger, clock ports.Clock, verifier EffectVerifier, evidenceVault verificationEvidenceVault, trustedEvidencePublicKey string, observations ports.ResponseVerificationStore, targetReceipts ports.ResponseTargetEvidenceReceiptStore, keys verificationSigningKeyResolver) (*Service, error)
NewService validates dependencies.
func (*Service) Apply ¶
func (s *Service) Apply(ctx context.Context, engagementID shared.ID, action rdom.Action, target engagement.Target, fingerprint responsesaga.TargetFingerprint, approver string) (Record, error)
Apply executes a response action after: (1) it validates (fail-closed on missing reversal/argv/ radius/scope), (2) the approver is a HUMAN (a machine identity is refused — no model verdict can approve), (3) the admission gate admits it (scope guard + recorded human approval, sealed as evidence), and (4) the executed effect stays within the declared blast radius. Re-issuing an applied action is a no-op reporting the already-applied state.
func (*Service) Decide ¶ added in v0.2.0
func (s *Service) Decide(ctx context.Context, actionID shared.ID, reviewer string, approve bool, reason string) (Record, error)
Decide records a second-human decision and resumes the exact durable response action on approval.
func (*Service) DryRun ¶
DryRun enumerates exactly what an action would do — the action and its reversal — and executes NOTHING. Same contract as the offensive-policy dry run.
func (*Service) HaltResponses ¶
func (s *Service) HaltResponses(ctx context.Context, tenantID shared.ID, actor, reason string) (int, error)
HaltResponses cancels every pending (admitted-but-not-yet-applied) response action for the tenant, exactly as the kill switch halts offensive work. It is the ResponseHalter the #418 kill switch drives, so its signature matches that seam. A single operator action, audited with the operator + reason.
func (*Service) ListByState ¶ added in v0.2.0
ListByState returns the tenant's response actions in a state (from ctx tenant), for the operator's view of what is admitted-but-not-applied — the same set the kill switch cancels.
func (*Service) PrepareIncidentResponse ¶ added in v0.2.0
func (s *Service) PrepareIncidentResponse(ctx context.Context, engagementID shared.ID, action rdom.Action, target engagement.Target, fingerprint responsesaga.TargetFingerprint, submitter string) (Record, error)
PrepareIncidentResponse persists the exact pending action identity required by the incident projection's live-action foreign key. It performs no admission, approval, attempt creation, or side effect. Apply reloads and validates this immutable record before the governed execution path can continue.
func (*Service) ReconcileAudits ¶ added in v0.2.0
ReconcileAudits idempotently drains response audit obligations left by a crash or audit outage.
func (*Service) ReconcileHaltDispatches ¶ added in v0.2.0
ReconcileHaltDispatches replays durable executor fences left by a crash or transient executor outage. Executor.Halt is monotonic by contract, so duplicate or older-generation delivery cannot lower a fence.
func (*Service) ReconcilePending ¶ added in v0.2.0
ReconcilePending repairs executor fences before verification and audit delivery so safety takes precedence.
func (*Service) ReconcileVerifications ¶ added in v0.2.0
ReconcileVerifications repairs every nonterminal execution stage without reissuing a command whose side-effect boundary may have been crossed. Missing evidence is retryable only until the durable deadline.
func (*Service) Revert ¶
func (s *Service) Revert(ctx context.Context, actionID shared.ID, target engagement.Target, fingerprint responsesaga.TargetFingerprint, approver string) (Record, error)
Revert applies an action's reversal. The reversal is itself ADMITTED (through the same gate) and AUDITED — a reversal is a first-class governed action, not an unchecked undo.
func (*Service) SetApprovalDecider ¶ added in v0.2.0
func (s *Service) SetApprovalDecider(approvals approvalDecider)
SetApprovalDecider installs the existing HITL service used to decide and resume response actions.
func (*Service) SetHaltWriter ¶ added in v0.2.0
func (s *Service) SetHaltWriter(haltWriter ports.ResponseHaltWriter) error
SetHaltWriter replaces the halt-fence capability. PostgreSQL composition provides a dedicated narrow pool; in-memory operation retains the single transactional store.
func (*Service) SetVerificationTimeout ¶ added in v0.2.0
SetVerificationTimeout bounds command-outcome and telemetry-verification obligations.
func (*Service) VerifiedProvenance ¶ added in v0.2.0
func (s *Service) VerifiedProvenance(ctx context.Context, actionID shared.ID) (VerificationProvenance, error)
VerifiedProvenance returns a successful apply attempt only after revalidating its persisted evidence. This is the read seam used by the incident event bridge; callers cannot supply verifier provenance.
type SimulationExecutor ¶ added in v0.2.0
type SimulationExecutor struct{}
SimulationExecutor is an Executor that EXECUTES NOTHING on any host. It exists so the full governed response loop — admission gate → human approval → execute → telemetry-verified post-condition (#638) — can be wired and exercised end-to-end WITHOUT crossing the execution-safety boundary. It reports a benign, single-target, in-radius outcome so a simulated action records as cleanly applied; it never signals AlreadyApplied, so idempotency is exercised by the ledger, not faked here.
A REAL host executor is DELIBERATELY not provided. Running argv on a live endpoint is a hard-to-reverse outward action (Golden Rule 1/4): it must go through the same argv-only sandbox as every other tool, and wiring it requires a distinct execution-safety review plus explicit operator authorization. Until then the simulation executor keeps the governed loop honest and testable without ever touching a host.
func (SimulationExecutor) Execute ¶ added in v0.2.0
func (SimulationExecutor) Execute(_ context.Context, req ExecRequest) (ExecOutcome, error)
Execute performs no host action. It echoes the declared radius as the observed radius (so the blast-radius guard sees no violation) and reports a single affected entity (the one declared target).
func (SimulationExecutor) Halt ¶ added in v0.2.0
Halt is a no-op because this executor has no side-effect boundary or active host work.
func (SimulationExecutor) Identity ¶ added in v0.2.0
func (SimulationExecutor) Identity() string
Identity names the non-effecting simulation principal for verifier-separation checks.
func (SimulationExecutor) ResolveAgent ¶ added in v0.2.0
func (SimulationExecutor) ResolveAgent(context.Context, shared.ID, responsesaga.TargetFingerprint) (shared.ID, error)
ResolveAgent identifies the non-effecting simulation principal. A live executor resolves the enrolled fleet-agent identity authenticated by its transport adapter for the requested target.
type State ¶
Record and State are the domain types (domain/response); re-exported as aliases so callers of this usecase package need not import both.
type TelemetryEffectVerifier ¶ added in v0.2.0
type TelemetryEffectVerifier struct {
// contains filtered or unexported fields
}
TelemetryEffectVerifier uses an observer's signed readiness report only as a causal trigger. It derives the outcome from independently accepted endpoint timeline and materialized coverage records.
func NewTelemetryEffectVerifier ¶ added in v0.2.0
func NewTelemetryEffectVerifier(identity string, observations ports.ResponseVerificationStore, receipts ports.ResponseTargetEvidenceReceiptStore, timeline ports.EndpointTimelineStore, coverage ports.CoverageWindowStore, evidence verificationEvidenceSealer) (*TelemetryEffectVerifier, error)
func (*TelemetryEffectVerifier) Identity ¶ added in v0.2.0
func (v *TelemetryEffectVerifier) Identity() string
func (*TelemetryEffectVerifier) SetObservationDispatcher ¶ added in v0.2.0
func (v *TelemetryEffectVerifier) SetObservationDispatcher(dispatcher ObservationDispatcher)
func (*TelemetryEffectVerifier) Verify ¶ added in v0.2.0
func (v *TelemetryEffectVerifier) Verify(ctx context.Context, req VerificationRequest) (VerificationReceipt, error)
type TenantLister ¶ added in v0.2.0
type Verification ¶ added in v0.2.0
type Verification = rdom.Verification
Record and State are the domain types (domain/response); re-exported as aliases so callers of this usecase package need not import both.
type VerificationProvenance ¶ added in v0.2.0
type VerificationProvenance struct {
ActionID shared.ID
EngagementID shared.ID
ActionDigest string
Target responsesaga.TargetFingerprint
AttemptKey string
ExecutorID string
VerifierID string
EvidenceID shared.ID
}
VerificationProvenance is the durable successful attempt identity an incident may reference. It is reconstructed from the response store and its evidence receipt, never from a verifier's live label.
type VerificationReceipt ¶ added in v0.2.0
type VerificationReceipt struct {
Outcome rdom.Verification
EvidenceID shared.ID
Source *VerificationSource
}
VerificationReceipt binds a telemetry verdict to durable evidence produced by an independent verifier.
type VerificationRequest ¶ added in v0.2.0
type VerificationRequest = ports.ResponseVerificationRequest
VerificationRequest remains an alias for compatibility; the observer-dispatch DTO lives in ports.
type VerificationSource ¶ added in v0.2.0
type VerificationSource struct {
Report fleetagent.ResponseVerificationReport `json:"report"`
RecordedAt time.Time `json:"recorded_at"`
SignedContentDigest string `json:"signed_content_digest"`
Receipt fleetagent.ResponseTargetEvidenceReceipt `json:"target_evidence_receipt"`
Timeline []endpoint.TimelineEntry `json:"timeline,omitempty"`
Coverage []sensorstate.CoverageWindow `json:"coverage,omitempty"`
}
VerificationSource embeds the exact purpose-signed observer report sealed into verification evidence. RecordedAt is server-owned; SignedContentDigest commits to the report's canonical signed message.