Withhold uncommitted decision effects and pin accepted layer canon
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
parent
f5fad7c285
commit
22185e94ec
12 changed files with 269 additions and 65 deletions
|
|
@ -254,9 +254,9 @@ type failingRecorder struct{}
|
|||
|
||||
func (failingRecorder) Append(api.DecisionEnvelope) error { return errors.New("disk full") }
|
||||
|
||||
// FLEX-DEC-2026-018 holds on the readback: an allow whose record fails to
|
||||
// commit is withheld (503, rendered "could not be checked"), never released.
|
||||
func TestReadbackWithholdsUncommittedAllow(t *testing.T) {
|
||||
// GH-DEC-2026-024: both permissive and restrictive results require their
|
||||
// record. Failure is unavailable (503), not a manufactured denial or allow.
|
||||
func TestReadbackWithholdsUncommittedEffects(t *testing.T) {
|
||||
service := newTestReadback(t)
|
||||
service.SetDecisionLog(failingRecorder{})
|
||||
server := httptest.NewServer(newReadbackMux(service, callerauth.Disabled()))
|
||||
|
|
@ -267,8 +267,8 @@ func TestReadbackWithholdsUncommittedAllow(t *testing.T) {
|
|||
t.Fatalf("uncommitted allow = %d, want 503", got)
|
||||
}
|
||||
deny, _ := json.Marshal(subjectRequest("user:bob", false, "demo-app"))
|
||||
if got := postReadback(t, server.URL, string(deny)).StatusCode; got != http.StatusOK {
|
||||
t.Fatalf("uncommitted deny = %d, want 200 (a restriction is never withheld)", got)
|
||||
if got := postReadback(t, server.URL, string(deny)).StatusCode; got != http.StatusServiceUnavailable {
|
||||
t.Fatalf("uncommitted deny = %d, want 503", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -343,3 +343,27 @@ func TestReadbackInformedDecisionCatalogue(t *testing.T) {
|
|||
t.Fatalf("catalogue = %+v", systems)
|
||||
}
|
||||
}
|
||||
|
||||
// A real restrictive policy result reaches the same unavailable HTTP contract
|
||||
// as an allow when its mandatory record cannot commit.
|
||||
func TestEnforcementWithholdsUncommittedDenyHTTP(t *testing.T) {
|
||||
engine, err := buildEngine(context.Background(), opsPath("registry_snapshot.json"), opsPath("policy_package.md"), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
engine.SetDecisionLog(failingRecorder{})
|
||||
server := httptest.NewServer(newServeMux(engine))
|
||||
defer server.Close()
|
||||
body, err := os.ReadFile(opsPath("check_request_deny_ttl_above_max.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
response, err := http.Post(server.URL+"/v1/check", "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
if response.StatusCode != http.StatusServiceUnavailable {
|
||||
t.Fatalf("uncommitted deny status = %d; want 503", response.StatusCode)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue