feat: dsh-gate — auto-run non-destructive mutations when no session ID
PolicyService.route now auto-runs config_mutation and reversible_low when sessionID is empty (dsh sidecar path), routing as 'dsh-gate'. Destructive still queues. This eliminates the two-layer consent issue: dsh pre-execute is the sole consent gate, oikos no longer queues dsh-originated mutations. Also updates the dsh plan with Phase 1-3 completion status and the architectural decision that _session_id injection is permanently deferred. v0.38.0
This commit is contained in:
@@ -144,6 +144,26 @@ func TestPlanFirstGate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSessionAutoRunExceptDestructive(t *testing.T) {
|
||||
svc, _ := newPolicySvc(t)
|
||||
noSession := func(cmd, risk string) PolicySubmitInput {
|
||||
return PolicySubmitInput{AgentID: agentID, TargetID: targetID, TargetSlug: "lxc:x", Command: cmd, DeclaredRisk: risk}
|
||||
}
|
||||
// config_mutation with no session → auto-run (dsh owns consent)
|
||||
d := svc.Decide(context.Background(), noSession("systemctl restart caddy", ""))
|
||||
if d.Action != DecisionAuto {
|
||||
t.Errorf("no-session config_mutation = %+v, want auto", d)
|
||||
}
|
||||
if d.AutoViaWindow != "dsh-gate" {
|
||||
t.Errorf("no-session config_mutation via = %q, want dsh-gate", d.AutoViaWindow)
|
||||
}
|
||||
// destructive with no session → still queue
|
||||
d = svc.Decide(context.Background(), noSession("rm -rf /data", ""))
|
||||
if d.Action != DecisionQueue {
|
||||
t.Errorf("no-session destructive = %+v, want queue", d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyntaxValidationGate(t *testing.T) {
|
||||
svc, _ := newPolicySvc(t)
|
||||
for _, bad := range []string{
|
||||
|
||||
Reference in New Issue
Block a user