Finish FLEX-WP-0019 layer-model v0.7 conformance
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 57s

Close the remaining PDP obligations: mechanical layer declaration check,
registry-snapshot digest in provenance, explicit allow TTL, per-input-class
freshness deadlines, and the published decision-record contract. Document
the canonical request digest as the §6.4.2 replay test.

Assistant: grok
Assistant-Session: 01a06256-fb71-7102-b3a9-27e6734257d0
This commit is contained in:
tegwick 2026-09-03 23:48:45 +02:00
parent 9689894c15
commit 56940727bf
32 changed files with 1194 additions and 111 deletions

View file

@ -137,6 +137,12 @@ func (s *Store) Snapshot() Snapshot {
}
}
// Digest is the SHA-256 of the canonical JSON snapshot. Two stores with the
// same records agree; a changed record changes the digest.
func (s *Store) Digest() string {
return api.CanonicalDigest(s.Snapshot())
}
// PutProtectedSystem stores or replaces a protected system manifest.
func (s *Store) PutProtectedSystem(system api.ProtectedSystemManifest) error {
if system.ID == "" {

View file

@ -3,6 +3,7 @@ package registry_test
import (
"encoding/json"
"path/filepath"
"strings"
"testing"
"github.com/netkingdom/flex-auth/internal/registry"
@ -70,6 +71,33 @@ func TestStoreLoadsAndSavesDeterministicSnapshot(t *testing.T) {
}
}
func TestStoreDigestChangesWhenSnapshotChanges(t *testing.T) {
store, err := registry.LoadFile(filepath.Join("..", "..", "examples", "caring", "registry_snapshot.json"))
if err != nil {
t.Fatalf("LoadFile: %v", err)
}
first := store.Digest()
if !strings.HasPrefix(first, "sha256:") || len(first) != len("sha256:")+64 {
t.Fatalf("Digest = %q", first)
}
if store.Digest() != first {
t.Fatal("digest is not stable for an unchanged snapshot")
}
if err := store.ImportResourceManifest(api.ResourceManifest{
ID: "markitect-extra",
System: "markitect-tool",
Resources: []api.Resource{
{ID: "document:other-note", Type: "document"},
},
}); err != nil {
t.Fatalf("ImportResourceManifest: %v", err)
}
if store.Digest() == first {
t.Fatal("digest did not change after snapshot mutation")
}
}
func TestStoreRejectsInvalidRecords(t *testing.T) {
store := registry.NewStore()
if err := store.PutSubject(api.Subject{}); err == nil {