response

package
v0.2.4 Latest Latest
Warning

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

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

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

View Source
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
)
View Source
const DefaultReconciliationInterval = time.Minute

DefaultReconciliationInterval bounds how long a committed halt can wait for executor replay.

View Source
const (
	DefaultVerificationTimeout = 2 * time.Minute
)
View Source
const VerificationEvidenceKind = "response_verification"

VerificationEvidenceKind identifies canonical response-verification claims in the evidence chain.

Variables

View Source
var ErrAttemptDeadlineExceeded = errors.New("response attempt deadline exceeded")

ErrAttemptDeadlineExceeded means a durable response attempt exhausted its authorization and evidence window.

View Source
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 (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

type Record = rdom.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

func (s *Service) DryRun(action rdom.Action) ([]PlanStep, error)

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

func (s *Service) ListByState(ctx context.Context, state State) ([]Record, error)

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

func (s *Service) ReconcileAudits(ctx context.Context) error

ReconcileAudits idempotently drains response audit obligations left by a crash or audit outage.

func (*Service) ReconcileHaltDispatches added in v0.2.0

func (s *Service) ReconcileHaltDispatches(ctx context.Context) error

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

func (s *Service) ReconcilePending(ctx context.Context) error

ReconcilePending repairs executor fences before verification and audit delivery so safety takes precedence.

func (*Service) ReconcileVerifications added in v0.2.0

func (s *Service) ReconcileVerifications(ctx context.Context) error

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

func (s *Service) SetVerificationTimeout(timeout time.Duration) error

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

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

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.

func (SimulationExecutor) Supports added in v0.2.0

func (SimulationExecutor) Supports(kind rdom.Kind) bool

Supports keeps the non-effecting simulation path available for every catalogued response kind.

type State

type State = rdom.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

type TenantLister added in v0.2.0

type TenantLister interface {
	ListTenantIDs(context.Context) ([]shared.ID, error)
}

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.

Jump to

Keyboard shortcuts

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