2026-09-03 23:48:45 +02:00
// Package layer asserts the NetKingdom security-layer-model §11 declaration.
package layer
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"gopkg.in/yaml.v3"
)
// Layer vocabulary from security-layer-model_v0.7 §3.
var validLayers = map [ string ] bool {
"Staff" : true ,
"Engine" : true ,
"Tooling" : true ,
}
// Engine roles from §3.3. An Engine declaration must state one.
var validEngineRoles = map [ string ] bool {
"PDP" : true ,
"PIP" : true ,
}
// Tooling clients are invocations, not mentions. These match import paths and
// argv construction that would actually contact OpenBao/Vault.
var toolingPatterns = [ ] * regexp . Regexp {
regexp . MustCompile ( ` github\.com/hashicorp/vault ` ) ,
regexp . MustCompile ( ` github\.com/openbao/ ` ) ,
regexp . MustCompile ( ` exec\.Command\([^)]*["'](?:bao|vault)["'] ` ) ,
}
// Declaration is the machine-readable §11 form carried in INTENT.md frontmatter.
type Declaration struct {
Layer string ` yaml:"layer" `
Role string ` yaml:"role" `
Framework string ` yaml:"framework" `
DeclaredBy string ` yaml:"declared_by" `
DeclaredAt string ` yaml:"declared_at" `
Make the layer declaration a boundary, and review the boundaries it implies.
INTENT.md pinned standard_version: "0.7" in the frontmatter §11 requires. That
conflated two things the standard separates itself: assent "records assent to a
BOUNDARY, given at the version named. It is not assent to the current text."
flex-auth is Engine/PDP at v0.6, v0.7, v0.8 and after; the role does not change
when the text is amended. The field was also decorative — parsed into
Declaration.StandardVersion and never validated — so the version was load-bearing
only via a test asserting it equalled 0.7.
That test is inverted rather than deleted: internal/layer now rejects a version
pin in the declaration and requires conformance_record to name a file that
exists. Version-scoped state moves to docs/conformance/security-layer-conformance.md,
a derived artifact carrying what it derives from and the version derived at, as
§11 requires of derived artifacts.
SCOPE.md: gap assessment replaces "conforming with one declared gap" with three
gaps, each with an owner and a route. G2 is new — flex-auth declares no emission
guarantee where §11 requires one of every §4 source of evidence. It is recorded
as a gap rather than as conformance because the flattering reading, that
audit-core is the source and flex-auth merely produces, has been asserted by
nobody but flex-auth. Also corrects the stance register from two rows to five.
Fixing one line meant reading what the declaration asserts, and a boundary is
only half held here. docs/conformance/boundaries-review.md checks the other
halves across twelve counterparts and finds four security-relevant repositories
with no layer declaration at all — including key-cape, the identity source whose
claims flex-auth consumes as normative input. That boundary is asserted from one
side only. Recorded as unstated, never as agreed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 28468@bnt-lap001
Assistant-Session: c76569b2-6056-4dad-aea4-49cd7a018f5d
2026-09-21 00:11:56 +02:00
// ConformanceRecord points at the derived, version-stamped conformance state.
// The declaration itself is a boundary and carries no standard version.
ConformanceRecord string ` yaml:"conformance_record" `
// StandardVersion must stay empty: a layer is a boundary, and the standard
// says assent is "to a BOUNDARY, given at the version named. It is not
// assent to the current text."
StandardVersion string ` yaml:"standard_version" `
2026-09-03 23:48:45 +02:00
PepStance any ` yaml:"pep_stance" `
ToolingContacts [ ] any ` yaml:"tooling_contacts" `
}
// Check parses INTENT.md, asserts the Engine/PDP declaration, and scans
// production Go sources for undeclared Tooling clients.
func Check ( root string ) error {
decl , err := LoadDeclaration ( filepath . Join ( root , "INTENT.md" ) )
if err != nil {
return err
}
if err := ValidateDeclaration ( decl ) ; err != nil {
return err
}
hits , err := ScanToolingClients ( root )
if err != nil {
return err
}
if len ( hits ) > 0 {
return fmt . Errorf ( "undeclared Tooling client(s) under §11: %s" , strings . Join ( hits , "; " ) )
}
return nil
}
// LoadDeclaration reads YAML frontmatter from INTENT.md.
func LoadDeclaration ( path string ) ( Declaration , error ) {
data , err := os . ReadFile ( path )
if err != nil {
return Declaration { } , fmt . Errorf ( "read layer declaration: %w" , err )
}
frontmatter , err := splitFrontmatter ( string ( data ) )
if err != nil {
return Declaration { } , err
}
var decl Declaration
if err := yaml . Unmarshal ( [ ] byte ( frontmatter ) , & decl ) ; err != nil {
return Declaration { } , fmt . Errorf ( "parse layer declaration: %w" , err )
}
return decl , nil
}
// ValidateDeclaration asserts §3 vocabulary and Engine-role presence.
func ValidateDeclaration ( decl Declaration ) error {
if ! validLayers [ decl . Layer ] {
return fmt . Errorf ( "layer %q is not in the §3 vocabulary (Staff, Engine, Tooling)" , decl . Layer )
}
if decl . Layer == "Engine" && ! validEngineRoles [ decl . Role ] {
return fmt . Errorf ( "Engine declaration must state role PDP or PIP; got %q" , decl . Role )
}
if decl . Layer != "Engine" && strings . TrimSpace ( decl . Role ) != "" {
return fmt . Errorf ( "layer %q must not state an Engine role" , decl . Layer )
}
if len ( decl . ToolingContacts ) > 0 {
return fmt . Errorf ( "Engine/PDP holds no Tooling client; tooling_contacts must be empty" )
}
if decl . PepStance != nil {
return fmt . Errorf ( "flex-auth is not PEP-shaped; pep_stance must be null" )
}
Make the layer declaration a boundary, and review the boundaries it implies.
INTENT.md pinned standard_version: "0.7" in the frontmatter §11 requires. That
conflated two things the standard separates itself: assent "records assent to a
BOUNDARY, given at the version named. It is not assent to the current text."
flex-auth is Engine/PDP at v0.6, v0.7, v0.8 and after; the role does not change
when the text is amended. The field was also decorative — parsed into
Declaration.StandardVersion and never validated — so the version was load-bearing
only via a test asserting it equalled 0.7.
That test is inverted rather than deleted: internal/layer now rejects a version
pin in the declaration and requires conformance_record to name a file that
exists. Version-scoped state moves to docs/conformance/security-layer-conformance.md,
a derived artifact carrying what it derives from and the version derived at, as
§11 requires of derived artifacts.
SCOPE.md: gap assessment replaces "conforming with one declared gap" with three
gaps, each with an owner and a route. G2 is new — flex-auth declares no emission
guarantee where §11 requires one of every §4 source of evidence. It is recorded
as a gap rather than as conformance because the flattering reading, that
audit-core is the source and flex-auth merely produces, has been asserted by
nobody but flex-auth. Also corrects the stance register from two rows to five.
Fixing one line meant reading what the declaration asserts, and a boundary is
only half held here. docs/conformance/boundaries-review.md checks the other
halves across twelve counterparts and finds four security-relevant repositories
with no layer declaration at all — including key-cape, the identity source whose
claims flex-auth consumes as normative input. That boundary is asserted from one
side only. Recorded as unstated, never as agreed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 28468@bnt-lap001
Assistant-Session: c76569b2-6056-4dad-aea4-49cd7a018f5d
2026-09-21 00:11:56 +02:00
if strings . TrimSpace ( decl . StandardVersion ) != "" {
return fmt . Errorf ( "layer declaration must carry no standard_version: a layer is a boundary, not a version-scoped claim; version-stamped state belongs in conformance_record (got %q)" , decl . StandardVersion )
}
if strings . TrimSpace ( decl . ConformanceRecord ) == "" {
return fmt . Errorf ( "layer declaration must name a conformance_record: §11 requires a derived artifact to carry the version it was derived at" )
}
2026-09-03 23:48:45 +02:00
return nil
}
// ScanToolingClients returns production Go files that invoke OpenBao/Vault.
func ScanToolingClients ( root string ) ( [ ] string , error ) {
var hits [ ] string
for _ , dir := range [ ] string { "cmd" , "internal" , "pkg" } {
err := filepath . WalkDir ( filepath . Join ( root , dir ) , func ( path string , d os . DirEntry , err error ) error {
if err != nil {
return err
}
if d . IsDir ( ) || ! strings . HasSuffix ( path , ".go" ) || strings . HasSuffix ( path , "_test.go" ) {
return nil
}
body , err := os . ReadFile ( path )
if err != nil {
return err
}
for _ , pattern := range toolingPatterns {
if pattern . Find ( body ) != nil {
rel , _ := filepath . Rel ( root , path )
hits = append ( hits , rel )
break
}
}
return nil
} )
if err != nil && ! os . IsNotExist ( err ) {
return nil , err
}
}
return hits , nil
}
func splitFrontmatter ( document string ) ( string , error ) {
document = strings . TrimPrefix ( document , "\ufeff" )
lines := strings . SplitAfter ( document , "\n" )
if len ( lines ) == 0 || strings . TrimSpace ( lines [ 0 ] ) != "---" {
return "" , fmt . Errorf ( "INTENT.md must start with YAML frontmatter" )
}
for i := 1 ; i < len ( lines ) ; i ++ {
if strings . TrimSpace ( lines [ i ] ) == "---" {
return strings . Join ( lines [ 1 : i ] , "" ) , nil
}
}
return "" , fmt . Errorf ( "INTENT.md frontmatter is not closed" )
}