2026-05-17 06:21:28 +02:00
package markitect
import (
"fmt"
"slices"
2026-10-10 15:29:00 +02:00
"github.com/netkingdom/access-engine/internal/registry"
"github.com/netkingdom/access-engine/pkg/api"
2026-05-17 06:21:28 +02:00
)
const (
// SystemID is the protected-system id emitted by Markitect manifests.
SystemID = "markitect-tool"
namespaceVersion = "markitect-resource-namespace-v1"
namespaceDoc = "docs/markitect-resource-namespace.md"
)
// Diagnostic describes a Markitect manifest import finding.
type Diagnostic struct {
Code string ` json:"code" `
Severity string ` json:"severity" `
Message string ` json:"message" `
Resource string ` json:"resource,omitempty" `
Fields [ ] string ` json:"fields,omitempty" `
}
// ImportResult captures the normalized manifest and diagnostics.
type ImportResult struct {
Manifest api . ResourceManifest ` json:"manifest" `
Diagnostics [ ] Diagnostic ` json:"diagnostics,omitempty" `
}
type classification struct {
scopeLevel api . ScopeLevel
planes [ ] api . Plane
parentTypes [ ] string
}
var classifications = map [ string ] classification {
"knowledge_base" : {
scopeLevel : api . ScopeLevelWorkspace ,
planes : [ ] api . Plane { api . PlaneIntent , api . PlaneData } ,
} ,
"repository" : {
scopeLevel : api . ScopeLevelProject ,
planes : [ ] api . Plane { api . PlaneBuild , api . PlaneData } ,
parentTypes : [ ] string { "knowledge_base" } ,
} ,
"document" : {
scopeLevel : api . ScopeLevelResource ,
planes : [ ] api . Plane { api . PlaneData } ,
parentTypes : [ ] string { "repository" , "knowledge_base" } ,
} ,
"section" : {
scopeLevel : api . ScopeLevelSubresource ,
planes : [ ] api . Plane { api . PlaneData } ,
parentTypes : [ ] string { "document" } ,
} ,
"span" : {
scopeLevel : api . ScopeLevelField ,
planes : [ ] api . Plane { api . PlaneData } ,
parentTypes : [ ] string { "section" , "document" } ,
} ,
"context_package" : {
scopeLevel : api . ScopeLevelDataset ,
planes : [ ] api . Plane { api . PlaneIntent , api . PlaneData , api . PlanePolicy } ,
parentTypes : [ ] string { "knowledge_base" , "repository" , "document" } ,
} ,
"workflow_artifact" : {
scopeLevel : api . ScopeLevelProcess ,
planes : [ ] api . Plane { api . PlaneExecution , api . PlaneData , api . PlaneAudit } ,
parentTypes : [ ] string { "context_package" , "document" } ,
} ,
"export" : {
scopeLevel : api . ScopeLevelRecord ,
planes : [ ] api . Plane { api . PlaneData , api . PlaneAudit } ,
parentTypes : [ ] string { "workflow_artifact" , "context_package" , "document" } ,
} ,
}
// ImportResourceManifest validates, enriches, and imports a Markitect manifest.
func ImportResourceManifest ( store * registry . Store , manifest api . ResourceManifest ) ( ImportResult , error ) {
if store == nil {
return ImportResult { } , fmt . Errorf ( "registry store is required" )
}
result := ImportResult {
Manifest : EnrichResourceManifest ( manifest ) ,
Diagnostics : ValidateResourceManifest ( manifest ) ,
}
if hasError ( result . Diagnostics ) {
return result , fmt . Errorf ( "markitect resource manifest has import errors" )
}
if err := store . ImportResourceManifest ( result . Manifest ) ; err != nil {
return result , err
}
return result , nil
}
// ValidateResourceManifest returns Markitect-specific import diagnostics.
func ValidateResourceManifest ( manifest api . ResourceManifest ) [ ] Diagnostic {
var diagnostics [ ] Diagnostic
if manifest . ID == "" {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-MANIFEST-ID" , "" , "manifest id is required" , "id" ) )
}
if manifest . System != SystemID {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-SYSTEM" , "" , fmt . Sprintf ( "manifest system must be %q" , SystemID ) , "system" ) )
}
if manifest . Metadata [ "flex_auth_contract" ] != api . FlexAuthContractV0 {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-CONTRACT" , "" , "metadata.flex_auth_contract must declare resource-registration-v0" , "metadata.flex_auth_contract" ) )
}
if manifest . CaringProfile == "" {
diagnostics = append ( diagnostics , warningDiagnostic ( "MARKITECT-CARING-PROFILE" , "" , "missing caring_profile; importer will default to caring-0.4.0-rc2" , "caring_profile" ) )
} else if manifest . CaringProfile != api . CaringProfileCaring040RC2 {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-CARING-PROFILE" , "" , fmt . Sprintf ( "unsupported caring_profile %q" , manifest . CaringProfile ) , "caring_profile" ) )
}
resourceTypes := make ( map [ string ] string , len ( manifest . Resources ) )
for _ , resource := range manifest . Resources {
resourceTypes [ resource . ID ] = resource . Type
}
for _ , resource := range manifest . Resources {
diagnostics = append ( diagnostics , validateResource ( resource , resourceTypes ) ... )
}
return diagnostics
}
// EnrichResourceManifest adds namespace and CARING classification metadata.
func EnrichResourceManifest ( manifest api . ResourceManifest ) api . ResourceManifest {
out := manifest
if out . CaringProfile == "" {
out . CaringProfile = api . CaringProfileCaring040RC2
}
out . Metadata = copyMap ( out . Metadata )
out . Metadata [ "markitect_namespace" ] = namespaceVersion
out . Metadata [ "markitect_namespace_doc" ] = namespaceDoc
out . Resources = append ( [ ] api . Resource ( nil ) , manifest . Resources ... )
for i , resource := range out . Resources {
if class , ok := classifications [ resource . Type ] ; ok {
resource . Attributes = copyMap ( resource . Attributes )
resource . Attributes [ "markitect_resource_type" ] = resource . Type
resource . Attributes [ "caring_scope_level" ] = class . scopeLevel
resource . Attributes [ "caring_planes" ] = append ( [ ] api . Plane ( nil ) , class . planes ... )
out . Resources [ i ] = resource
}
}
return out
}
func validateResource ( resource api . Resource , resourceTypes map [ string ] string ) [ ] Diagnostic {
var diagnostics [ ] Diagnostic
if resource . ID == "" {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-RESOURCE-ID" , "" , "resource id is required" , "resources[].id" ) )
}
if resource . Type == "" {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-RESOURCE-TYPE" , resource . ID , "resource type is required" , "resources[].type" ) )
return diagnostics
}
class , ok := classifications [ resource . Type ]
if ! ok {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-RESOURCE-TYPE" , resource . ID , fmt . Sprintf ( "unknown Markitect resource type %q" , resource . Type ) , "resources[].type" ) )
return diagnostics
}
if resource . Parent != "" {
if parentType , ok := resourceTypes [ resource . Parent ] ; ok && ! slices . Contains ( class . parentTypes , parentType ) {
diagnostics = append ( diagnostics , errorDiagnostic ( "MARKITECT-PARENT-TYPE" , resource . ID , fmt . Sprintf ( "resource type %q cannot be parented by %q" , resource . Type , parentType ) , "resources[].parent" ) )
}
}
if resource . Parent == "" && len ( class . parentTypes ) > 0 {
diagnostics = append ( diagnostics , warningDiagnostic ( "MARKITECT-PARENT-MISSING" , resource . ID , fmt . Sprintf ( "resource type %q usually declares a parent" , resource . Type ) , "resources[].parent" ) )
}
if len ( resource . Labels ) == 0 {
diagnostics = append ( diagnostics , warningDiagnostic ( "MARKITECT-LABELS-MISSING" , resource . ID , "resource has no labels; CARING exposure classification may be ambiguous" , "resources[].labels" ) )
}
if resource . TrustZone == "" {
diagnostics = append ( diagnostics , warningDiagnostic ( "MARKITECT-TRUST-ZONE-MISSING" , resource . ID , "resource has no trust_zone; CARING exposure classification may be ambiguous" , "resources[].trust_zone" ) )
}
return diagnostics
}
func errorDiagnostic ( code , resource , message string , fields ... string ) Diagnostic {
return Diagnostic { Code : code , Severity : "error" , Resource : resource , Message : message , Fields : fields }
}
func warningDiagnostic ( code , resource , message string , fields ... string ) Diagnostic {
return Diagnostic { Code : code , Severity : "warning" , Resource : resource , Message : message , Fields : fields }
}
func hasError ( diagnostics [ ] Diagnostic ) bool {
for _ , diagnostic := range diagnostics {
if diagnostic . Severity == "error" {
return true
}
}
return false
}
func copyMap ( in map [ string ] any ) map [ string ] any {
out := make ( map [ string ] any , len ( in ) )
for key , value := range in {
out [ key ] = value
}
return out
}