1-SEC contributors · Reviewed · Module: core

Enforcement Dry-Run: Observe Response Decisions Before Actions

The response engine separates response selection from action execution and records dry-run outcomes.

What 1-SEC checks

The response engine separates response selection from action execution and records dry-run outcomes. Module policy enablement, severity thresholds, allowlists, cooldowns, and action limits can affect whether a rule is selected before an executor runs.

Read the implementation: SetDryRun

Required telemetry and context

This control uses an explicit configuration/API path rather than a standalone detector input event. Verify the caller and configuration before relying on its result.

  • enforcement.enabled
  • enforcement.dry_run
  • module policy enabled
  • min_severity
  • response target
  • action history

Field names above describe relevant context, not a complete API request. Consult the current event contract for envelope and detail requirements. Preserve booleans, numbers, and strings as the receiving handler expects them. Agent-provided text cannot independently verify identity or authorization.

Deployment, prevention, and response

Review which alert selected which action and target, including the original event metadata. Verify the intended policy, safe exclusions, available executor, privileges, and recovery plan. Switch to actual enforcement only after testing in an isolated environment with an authorized target.

Record the source event, affected agent/host, actual target, policy decision, and response result. Review enforcement configuration separately from detection. A recommendation, selected action, dry-run record, and completed action are different outcomes.

Reproduce the source fixtures

From a checkout of the linked 1-SEC source revision, run the selected fixtures with the repository's Go toolchain. These commands run tests; they do not execute a real attack against your systems.

go test ./internal/core -run '^(TestResponseEngine_HandleAlert_DryRun|TestResponseEngine_SetDryRun|TestResponseEngine_HandleAlert_DisabledPolicy)$' -count=1

The referenced source fixtures ran in the selected local package suites. Helper tests and synthetic events establish only the assertions shown, not production prevention or framework compatibility.

TestResponseEngine_HandleAlert_DryRun

Full fixture and assertions — run in its original package with its helpers.

func TestResponseEngine_HandleAlert_DryRun(t *testing.T) {
	re := testResponseEngine(t, enforcementConfig("balanced", true))

	alert := testAlertWithIP("injection_shield", "10.0.0.1", SeverityHigh)
	re.handleAlert(alert)

	records := re.GetRecords(100, "")
	if len(records) == 0 {
		t.Fatal("expected at least one response record in dry-run mode")
	}

	for _, r := range records {
		if r.Status != ActionStatusDryRun {
			t.Errorf("expected DRY_RUN status, got %s", r.Status)
		}
	}
}

// ─── handleAlert — severity below threshold ─────────────────────────────────
TestResponseEngine_SetDryRun

Full fixture and assertions — run in its original package with its helpers.

func TestResponseEngine_SetDryRun(t *testing.T) {
	re := testResponseEngine(t, enforcementConfig("balanced", false))

	if !re.SetDryRun("injection_shield", true) {
		t.Error("expected SetDryRun to return true for existing module")
	}

	policies := re.GetPolicies()
	if !policies["injection_shield"].DryRun {
		t.Error("expected injection_shield dry_run to be true")
	}

	if re.SetDryRun("nonexistent_module", true) {
		t.Error("expected SetDryRun to return false for nonexistent module")
	}
}

// ─── Stats ──────────────────────────────────────────────────────────────────
TestResponseEngine_HandleAlert_DisabledPolicy

Full fixture and assertions — run in its original package with its helpers.

func TestResponseEngine_HandleAlert_DisabledPolicy(t *testing.T) {
	cfg := DefaultConfig()
	cfg.Enforcement = &EnforcementConfig{
		Enabled: true,
		DryRun:  true,
		Policies: map[string]ResponsePolicyYAML{
			"test_module": {
				Enabled:     false,
				MinSeverity: "LOW",
				Actions: []ResponseRuleYAML{
					{Action: "log_only", MinSeverity: "LOW"},
				},
			},
		},
	}

	re := testResponseEngine(t, cfg)
	alert := testAlertWithIP("test_module", "10.0.0.1", SeverityCritical)
	re.handleAlert(alert)

	records := re.GetRecords(100, "")
	if len(records) != 0 {
		t.Errorf("expected no records for disabled policy, got %d", len(records))
	}
}

// ─── Allow list ─────────────────────────────────────────────────────────────

Tuning, evaluation, and coverage limits

Dry-run observations do not prove an executor can block an IP or stop a process on a production OS. A successful dry-run record is not a performed action. It also does not override a separate management gateway policy denial.

Evaluate this behavior with representative authorized activity and a controlled known-positive case. Investigate the exact rule, inputs, and state before suppressing an alert. Do not assume a hard-coded heuristic is a configurable setting. Measure your own deployment; the source fixtures do not establish a benchmark, detection rate, compliance certification, or incident-prevention claim.

Related implemented controls

Implementation reviewed at source revision 2af8ea9dab2057a1ffc3cce9bf44220271fab18e. Recheck the actual release and integration before deployment. Sources and corrections policy.