Read an unwritten guard mode as enforce when merging, not as the weakest

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilker ManapandClaude Opus 5.5 committed 2026-10-04 15:22:07 +02:00
1 parent 83e1444981
commit 2cc52fd1a7
2 files changed
+15 -4

No files matched your search

+7 -4
View File
@@ -189,7 +189,13 @@ func Merge(names []string, ps []Policy) Policy {
var allowSets [][]string
var prompts []string
for _, p := range ps {
out.Mode = stricterOf(out.Mode, p.Mode, []string{"", "off", "shadow", "enforce"})
// Unwritten is enforce, not the weakest: a policy that says nothing
// of its mode, merged with one in shadow, must still act.
mode := p.Mode
if mode == "" {
mode = "enforce"
}
out.Mode = stricterOf(out.Mode, mode, []string{"", "off", "shadow", "enforce"})
out.Fail = stricterOf(out.Fail, p.Fail, []string{"", "open", "closed"})
out.Stream = stricterOf(out.Stream, p.Stream, []string{"", "sentence", "buffer_all"})
out.NoStore = out.NoStore || p.NoStore
@@ -212,9 +218,6 @@ func Merge(names []string, ps []Policy) Policy {
out.Tools.MaxCallsPerTurn = minSet(out.Tools.MaxCallsPerTurn, t.MaxCallsPerTurn)
out.Tools.ValidateArguments = out.Tools.ValidateArguments || t.ValidateArguments
}
if out.Mode == "" && len(ps) > 0 {
out.Mode = "enforce"
}
for i, s := range allowSets {
if i == 0 {
out.Tools.Allow = slices.Clone(s)
+8
View File
@@ -37,6 +37,14 @@ func TestPoliciesNarrowAndNeverLoosen(t *testing.T) {
if len(none.Tools.Allow) != 1 || none.Tools.Allow[0] == "a" || none.Tools.Allow[0] == "b" {
t.Errorf("disjoint allow lists: %v", none.Tools.Allow)
}
// Found on the PoC: a shadow default merged with an attached policy that
// did not write its mode left the attached one in shadow too.
if m := Merge(nil, []Policy{{Mode: "shadow"}, {}}); m.Mode != "enforce" {
t.Errorf("shadow and an unwritten mode: %q", m.Mode)
}
if m := Merge(nil, []Policy{{Mode: "shadow"}}); m.Mode != "shadow" {
t.Errorf("shadow alone: %q", m.Mode)
}
if Merge(nil, nil).active() || !Merge(nil, []Policy{{}}).active() || Merge(nil, []Policy{{Mode: "off"}}).active() {
t.Error("activeness")
}