generated from coulomb/repo-seed
Implement canonical schema foundation
This commit is contained in:
@@ -9,6 +9,8 @@ FLEX-WP-0005):
|
|||||||
examples/
|
examples/
|
||||||
claims/ # key-cape lightweight-mode and Keycloak heavy-mode
|
claims/ # key-cape lightweight-mode and Keycloak heavy-mode
|
||||||
# claim envelopes (P5.5)
|
# claim envelopes (P5.5)
|
||||||
|
caring/ # executable CARING descriptor, request,
|
||||||
|
# decision, registry, and audit fixtures (P2.1)
|
||||||
markitect/ # FlexAuthResourceManifest fixtures, decision
|
markitect/ # FlexAuthResourceManifest fixtures, decision
|
||||||
# fixtures, and Rego-in-Markdown policy packages
|
# fixtures, and Rego-in-Markdown policy packages
|
||||||
topaz/ # docker-compose + sample directory and policy
|
topaz/ # docker-compose + sample directory and policy
|
||||||
|
|||||||
8
examples/caring/README.md
Normal file
8
examples/caring/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# CARING examples
|
||||||
|
|
||||||
|
Small fixtures for the executable CARING 0.4.0-RC2 profile used by
|
||||||
|
`FLEX-WP-0002 P2.1`.
|
||||||
|
|
||||||
|
These are intentionally compact. They are not policy-engine fixtures yet;
|
||||||
|
they prove that the canonical descriptor, request, decision, registry, and
|
||||||
|
audit shapes can round-trip through `pkg/api`.
|
||||||
26
examples/caring/access_descriptor.yaml
Normal file
26
examples/caring/access_descriptor.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
id: descriptor:tenant-alpha-document-reader
|
||||||
|
profile: caring-0.4.0-rc2
|
||||||
|
subject_type: Human
|
||||||
|
organization_relation: Customer
|
||||||
|
canonical_role: Doer
|
||||||
|
scope:
|
||||||
|
level: Resource
|
||||||
|
id: document:internal-note
|
||||||
|
tenant: tenant:alpha
|
||||||
|
resource: document:internal-note
|
||||||
|
planes:
|
||||||
|
- Data
|
||||||
|
capabilities:
|
||||||
|
- View
|
||||||
|
exposure_modes:
|
||||||
|
- Masked
|
||||||
|
- Plaintext
|
||||||
|
conditions:
|
||||||
|
- PurposeBound
|
||||||
|
- Logged
|
||||||
|
lifecycle_state: Operate
|
||||||
|
restrictions:
|
||||||
|
- ExportBlocked
|
||||||
|
access_path: direct
|
||||||
|
metadata:
|
||||||
|
source: examples/caring
|
||||||
22
examples/caring/audit_event.json
Normal file
22
examples/caring/audit_event.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"id": "audit:decision:tenant-alpha-internal-note",
|
||||||
|
"type": "decision",
|
||||||
|
"decision_id": "decision:tenant-alpha-internal-note",
|
||||||
|
"subject": {
|
||||||
|
"id": "user:alice",
|
||||||
|
"type": "Human",
|
||||||
|
"tenant": "tenant:alpha"
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"id": "document:internal-note",
|
||||||
|
"type": "document",
|
||||||
|
"system": "markitect-tool",
|
||||||
|
"tenant": "tenant:alpha"
|
||||||
|
},
|
||||||
|
"action": "read",
|
||||||
|
"effect": "allow",
|
||||||
|
"timestamp": "2026-05-17T00:00:00Z",
|
||||||
|
"metadata": {
|
||||||
|
"profile": "caring-0.4.0-rc2"
|
||||||
|
}
|
||||||
|
}
|
||||||
41
examples/caring/check_request.yaml
Normal file
41
examples/caring/check_request.yaml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
id: check:tenant-alpha-internal-note
|
||||||
|
subject:
|
||||||
|
id: user:alice
|
||||||
|
type: Human
|
||||||
|
tenant: tenant:alpha
|
||||||
|
action: read
|
||||||
|
resource:
|
||||||
|
id: document:internal-note
|
||||||
|
type: document
|
||||||
|
system: markitect-tool
|
||||||
|
tenant: tenant:alpha
|
||||||
|
context:
|
||||||
|
purpose: knowledge-base-read
|
||||||
|
assurance:
|
||||||
|
mfa: true
|
||||||
|
caring_context:
|
||||||
|
id: descriptor:tenant-alpha-document-reader
|
||||||
|
profile: caring-0.4.0-rc2
|
||||||
|
subject_type: Human
|
||||||
|
organization_relation: Customer
|
||||||
|
canonical_role: Doer
|
||||||
|
scope:
|
||||||
|
level: Resource
|
||||||
|
id: document:internal-note
|
||||||
|
tenant: tenant:alpha
|
||||||
|
resource: document:internal-note
|
||||||
|
planes:
|
||||||
|
- Data
|
||||||
|
capabilities:
|
||||||
|
- View
|
||||||
|
exposure_modes:
|
||||||
|
- Masked
|
||||||
|
- Plaintext
|
||||||
|
conditions:
|
||||||
|
- PurposeBound
|
||||||
|
- Logged
|
||||||
|
lifecycle_state: Operate
|
||||||
|
restrictions:
|
||||||
|
- ExportBlocked
|
||||||
|
access_path: direct
|
||||||
|
policy_version: markitect.documents.v1
|
||||||
69
examples/caring/decision_envelope.json
Normal file
69
examples/caring/decision_envelope.json
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"id": "decision:tenant-alpha-internal-note",
|
||||||
|
"request_id": "check:tenant-alpha-internal-note",
|
||||||
|
"effect": "allow",
|
||||||
|
"reason": "reader_relation",
|
||||||
|
"matched_policy_version": "markitect.documents.v1",
|
||||||
|
"matched_rule": "allow_document_read",
|
||||||
|
"resource": {
|
||||||
|
"id": "document:internal-note",
|
||||||
|
"type": "document",
|
||||||
|
"system": "markitect-tool",
|
||||||
|
"tenant": "tenant:alpha"
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"id": "user:alice",
|
||||||
|
"type": "Human",
|
||||||
|
"tenant": "tenant:alpha"
|
||||||
|
},
|
||||||
|
"obligations": [
|
||||||
|
{
|
||||||
|
"type": "log_access",
|
||||||
|
"parameters": {
|
||||||
|
"level": "standard"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"diagnostics": {
|
||||||
|
"policy_package": "examples/caring"
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"evaluator": "flex-auth",
|
||||||
|
"mode": "standalone",
|
||||||
|
"policy_package": "markitect.documents",
|
||||||
|
"policy_version": "v1",
|
||||||
|
"decision_time": "2026-05-17T00:00:00Z"
|
||||||
|
},
|
||||||
|
"caring": {
|
||||||
|
"profile": "caring-0.4.0-rc2",
|
||||||
|
"descriptor": {
|
||||||
|
"id": "descriptor:tenant-alpha-document-reader",
|
||||||
|
"profile": "caring-0.4.0-rc2",
|
||||||
|
"subject_type": "Human",
|
||||||
|
"organization_relation": "Customer",
|
||||||
|
"canonical_role": "Doer",
|
||||||
|
"scope": {
|
||||||
|
"level": "Resource",
|
||||||
|
"id": "document:internal-note",
|
||||||
|
"tenant": "tenant:alpha",
|
||||||
|
"resource": "document:internal-note"
|
||||||
|
},
|
||||||
|
"planes": ["Data"],
|
||||||
|
"capabilities": ["View"],
|
||||||
|
"exposure_modes": ["Masked", "Plaintext"],
|
||||||
|
"conditions": ["PurposeBound", "Logged"],
|
||||||
|
"lifecycle_state": "Operate",
|
||||||
|
"restrictions": ["ExportBlocked"],
|
||||||
|
"access_path": "direct"
|
||||||
|
},
|
||||||
|
"restrictions_evaluated": ["ExportBlocked"],
|
||||||
|
"exposure_modes": ["Masked", "Plaintext"],
|
||||||
|
"conformance_findings": [
|
||||||
|
{
|
||||||
|
"code": "CARING-EXPORT-SEPARATION",
|
||||||
|
"severity": "info",
|
||||||
|
"message": "View is allowed, but Exportable exposure remains separately blocked."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
45
examples/caring/policy_fixture.yaml
Normal file
45
examples/caring/policy_fixture.yaml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
id: fixture:markitect-internal-read-allow
|
||||||
|
request:
|
||||||
|
id: check:tenant-alpha-internal-note
|
||||||
|
subject:
|
||||||
|
id: user:alice
|
||||||
|
type: Human
|
||||||
|
tenant: tenant:alpha
|
||||||
|
action: read
|
||||||
|
resource:
|
||||||
|
id: document:internal-note
|
||||||
|
type: document
|
||||||
|
system: markitect-tool
|
||||||
|
tenant: tenant:alpha
|
||||||
|
caring_context:
|
||||||
|
id: descriptor:tenant-alpha-document-reader
|
||||||
|
profile: caring-0.4.0-rc2
|
||||||
|
subject_type: Human
|
||||||
|
organization_relation: Customer
|
||||||
|
canonical_role: Doer
|
||||||
|
scope:
|
||||||
|
level: Resource
|
||||||
|
id: document:internal-note
|
||||||
|
tenant: tenant:alpha
|
||||||
|
resource: document:internal-note
|
||||||
|
planes:
|
||||||
|
- Data
|
||||||
|
capabilities:
|
||||||
|
- View
|
||||||
|
exposure_modes:
|
||||||
|
- Masked
|
||||||
|
- Plaintext
|
||||||
|
conditions:
|
||||||
|
- PurposeBound
|
||||||
|
- Logged
|
||||||
|
restrictions:
|
||||||
|
- ExportBlocked
|
||||||
|
expect:
|
||||||
|
effect: allow
|
||||||
|
reason: reader_relation
|
||||||
|
conformance_findings:
|
||||||
|
- code: CARING-EXPORT-SEPARATION
|
||||||
|
severity: info
|
||||||
|
message: View is allowed, but Exportable exposure remains separately blocked.
|
||||||
|
metadata:
|
||||||
|
source: examples/caring
|
||||||
29
examples/caring/policy_package.yaml
Normal file
29
examples/caring/policy_package.yaml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
id: markitect.documents.internal-read
|
||||||
|
name: Markitect internal document read
|
||||||
|
version: v1
|
||||||
|
status: draft
|
||||||
|
package: flexauth.markitect.documents
|
||||||
|
caring:
|
||||||
|
profile: caring-0.4.0-rc2
|
||||||
|
canonical_roles:
|
||||||
|
- Doer
|
||||||
|
organization_relations:
|
||||||
|
- Customer
|
||||||
|
scopes:
|
||||||
|
- level: Resource
|
||||||
|
id: document:internal-note
|
||||||
|
tenant: tenant:alpha
|
||||||
|
planes:
|
||||||
|
- Data
|
||||||
|
capabilities:
|
||||||
|
- View
|
||||||
|
exposure_modes:
|
||||||
|
- Masked
|
||||||
|
- Plaintext
|
||||||
|
conditions:
|
||||||
|
- PurposeBound
|
||||||
|
- Logged
|
||||||
|
restrictions:
|
||||||
|
- ExportBlocked
|
||||||
|
metadata:
|
||||||
|
source: examples/caring
|
||||||
32
examples/caring/relationship_fact.yaml
Normal file
32
examples/caring/relationship_fact.yaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
id: rel:alice-reader-internal-note
|
||||||
|
system: markitect-tool
|
||||||
|
subject: group:platform-architecture
|
||||||
|
relation: reader
|
||||||
|
object: document:internal-note
|
||||||
|
tenant: tenant:alpha
|
||||||
|
conditions:
|
||||||
|
- Logged
|
||||||
|
caring:
|
||||||
|
id: descriptor:tenant-alpha-document-reader
|
||||||
|
profile: caring-0.4.0-rc2
|
||||||
|
subject_type: Group
|
||||||
|
organization_relation: Customer
|
||||||
|
canonical_role: Doer
|
||||||
|
scope:
|
||||||
|
level: Resource
|
||||||
|
id: document:internal-note
|
||||||
|
tenant: tenant:alpha
|
||||||
|
resource: document:internal-note
|
||||||
|
planes:
|
||||||
|
- Data
|
||||||
|
capabilities:
|
||||||
|
- View
|
||||||
|
exposure_modes:
|
||||||
|
- Masked
|
||||||
|
- Plaintext
|
||||||
|
conditions:
|
||||||
|
- Logged
|
||||||
|
restrictions:
|
||||||
|
- ExportBlocked
|
||||||
|
provenance:
|
||||||
|
source: examples/caring
|
||||||
22
examples/caring/subject_manifest.yaml
Normal file
22
examples/caring/subject_manifest.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
id: subjects:tenant-alpha
|
||||||
|
subjects:
|
||||||
|
- id: user:alice
|
||||||
|
type: Human
|
||||||
|
display_name: Alice Example
|
||||||
|
organization_relation: Customer
|
||||||
|
roles:
|
||||||
|
- Doer
|
||||||
|
groups:
|
||||||
|
- group:platform-architecture
|
||||||
|
tenant: tenant:alpha
|
||||||
|
groups:
|
||||||
|
- id: group:platform-architecture
|
||||||
|
display_name: Platform Architecture
|
||||||
|
members:
|
||||||
|
- user:alice
|
||||||
|
tenant: tenant:alpha
|
||||||
|
tenants:
|
||||||
|
- id: tenant:alpha
|
||||||
|
name: Tenant Alpha
|
||||||
|
metadata:
|
||||||
|
source: examples/caring
|
||||||
50
internal/policy/package_test.go
Normal file
50
internal/policy/package_test.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package policy_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/netkingdom/flex-auth/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPolicyPackageMetadataParses(t *testing.T) {
|
||||||
|
var metadata api.PolicyPackageMetadata
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "policy_package.yaml"), &metadata)
|
||||||
|
|
||||||
|
if metadata.Caring.Profile != api.CaringProfileCaring040RC2 {
|
||||||
|
t.Fatalf("metadata.Caring.Profile = %q; want %q", metadata.Caring.Profile, api.CaringProfileCaring040RC2)
|
||||||
|
}
|
||||||
|
if len(metadata.Caring.Capabilities) != 1 || metadata.Caring.Capabilities[0] != api.CapabilityView {
|
||||||
|
t.Errorf("metadata.Caring.Capabilities = %v; want [View]", metadata.Caring.Capabilities)
|
||||||
|
}
|
||||||
|
if len(metadata.Caring.Restrictions) != 1 || metadata.Caring.Restrictions[0] != api.RestrictionExportBlocked {
|
||||||
|
t.Errorf("metadata.Caring.Restrictions = %v; want [ExportBlocked]", metadata.Caring.Restrictions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPolicyFixtureParses(t *testing.T) {
|
||||||
|
var fixture api.PolicyFixture
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "policy_fixture.yaml"), &fixture)
|
||||||
|
|
||||||
|
if fixture.Expect.Effect != api.DecisionEffectAllow {
|
||||||
|
t.Errorf("fixture.Expect.Effect = %q; want allow", fixture.Expect.Effect)
|
||||||
|
}
|
||||||
|
if fixture.Request.CaringContext == nil {
|
||||||
|
t.Fatal("fixture.Request.CaringContext is nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadYAML(t *testing.T, path string, out any) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read %s: %v", path, err)
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(data, out); err != nil {
|
||||||
|
t.Fatalf("unmarshal %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
43
internal/registry/manifest_test.go
Normal file
43
internal/registry/manifest_test.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package registry_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/netkingdom/flex-auth/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegistryManifestsParse(t *testing.T) {
|
||||||
|
var subjects api.SubjectManifest
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "subject_manifest.yaml"), &subjects)
|
||||||
|
if len(subjects.Subjects) != 1 {
|
||||||
|
t.Fatalf("Subjects len = %d; want 1", len(subjects.Subjects))
|
||||||
|
}
|
||||||
|
if subjects.Subjects[0].Roles[0] != api.CanonicalRoleDoer {
|
||||||
|
t.Errorf("Subject role = %q; want Doer", subjects.Subjects[0].Roles[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
var fact api.RelationshipFact
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "relationship_fact.yaml"), &fact)
|
||||||
|
if fact.Subject != "group:platform-architecture" || fact.Object != "document:internal-note" {
|
||||||
|
t.Fatalf("relationship fact did not parse as expected: %+v", fact)
|
||||||
|
}
|
||||||
|
if fact.Caring == nil || fact.Caring.Profile != api.CaringProfileCaring040RC2 {
|
||||||
|
t.Fatalf("fact.Caring = %+v; want CARING profile descriptor", fact.Caring)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadYAML(t *testing.T, path string, out any) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read %s: %v", path, err)
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(data, out); err != nil {
|
||||||
|
t.Fatalf("unmarshal %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
249
pkg/api/canonical.go
Normal file
249
pkg/api/canonical.go
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// ProtectedSystemManifest describes a system that delegates authorization to
|
||||||
|
// flex-auth.
|
||||||
|
type ProtectedSystemManifest struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
|
ResourceTypes []ResourceType `json:"resource_types,omitempty" yaml:"resource_types,omitempty"`
|
||||||
|
Actions []ActionDefinition `json:"actions,omitempty" yaml:"actions,omitempty"`
|
||||||
|
CaringProfiles []string `json:"caring_profiles,omitempty" yaml:"caring_profiles,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceType describes a resource namespace entry owned by a protected system.
|
||||||
|
type ResourceType struct {
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
ParentTypes []string `json:"parent_types,omitempty" yaml:"parent_types,omitempty"`
|
||||||
|
ScopeLevel ScopeLevel `json:"scope_level,omitempty" yaml:"scope_level,omitempty"`
|
||||||
|
Planes []Plane `json:"planes,omitempty" yaml:"planes,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionDefinition maps a protected-system action to CARING capabilities.
|
||||||
|
type ActionDefinition struct {
|
||||||
|
Name string `json:"name" yaml:"name"`
|
||||||
|
Capabilities []Capability `json:"capabilities,omitempty" yaml:"capabilities,omitempty"`
|
||||||
|
Planes []Plane `json:"planes,omitempty" yaml:"planes,omitempty"`
|
||||||
|
ExposureModes []ExposureMode `json:"exposure_modes,omitempty" yaml:"exposure_modes,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubjectManifest declares subjects, groups, teams, and tenants for local
|
||||||
|
// registry loading.
|
||||||
|
type SubjectManifest struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Subjects []Subject `json:"subjects,omitempty" yaml:"subjects,omitempty"`
|
||||||
|
Groups []Group `json:"groups,omitempty" yaml:"groups,omitempty"`
|
||||||
|
Teams []Team `json:"teams,omitempty" yaml:"teams,omitempty"`
|
||||||
|
Tenants []Tenant `json:"tenants,omitempty" yaml:"tenants,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subject is a human, service, automation, agent, or other acting identity.
|
||||||
|
type Subject struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Type SubjectType `json:"type" yaml:"type"`
|
||||||
|
DisplayName string `json:"display_name,omitempty" yaml:"display_name,omitempty"`
|
||||||
|
OrganizationRelation OrganizationRelation `json:"organization_relation,omitempty" yaml:"organization_relation,omitempty"`
|
||||||
|
Roles []CanonicalRole `json:"roles,omitempty" yaml:"roles,omitempty"`
|
||||||
|
Groups []string `json:"groups,omitempty" yaml:"groups,omitempty"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
Claims map[string]any `json:"claims,omitempty" yaml:"claims,omitempty"`
|
||||||
|
CaringDescriptors []CaringAccessDescriptor `json:"caring_descriptors,omitempty" yaml:"caring_descriptors,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group is an assignment convenience, not a canonical role.
|
||||||
|
type Group struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
DisplayName string `json:"display_name,omitempty" yaml:"display_name,omitempty"`
|
||||||
|
Members []string `json:"members,omitempty" yaml:"members,omitempty"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
CaringDescriptors []CaringAccessDescriptor `json:"caring_descriptors,omitempty" yaml:"caring_descriptors,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Team is a group-like ownership unit used by protected systems.
|
||||||
|
type Team struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
DisplayName string `json:"display_name,omitempty" yaml:"display_name,omitempty"`
|
||||||
|
Members []string `json:"members,omitempty" yaml:"members,omitempty"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
CaringDescriptors []CaringAccessDescriptor `json:"caring_descriptors,omitempty" yaml:"caring_descriptors,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tenant is a structural isolation boundary.
|
||||||
|
type Tenant struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RelationshipFact records a relation between subjects, groups, teams, tenants,
|
||||||
|
// and resources.
|
||||||
|
type RelationshipFact struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
System string `json:"system,omitempty" yaml:"system,omitempty"`
|
||||||
|
Subject string `json:"subject" yaml:"subject"`
|
||||||
|
Relation string `json:"relation" yaml:"relation"`
|
||||||
|
Object string `json:"object" yaml:"object"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
Conditions []Condition `json:"conditions,omitempty" yaml:"conditions,omitempty"`
|
||||||
|
Caring *CaringAccessDescriptor `json:"caring,omitempty" yaml:"caring,omitempty"`
|
||||||
|
Provenance map[string]any `json:"provenance,omitempty" yaml:"provenance,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolicyPackageMetadata is the frontmatter contract for Rego-in-Markdown
|
||||||
|
// policy packages.
|
||||||
|
type PolicyPackageMetadata struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Version string `json:"version" yaml:"version"`
|
||||||
|
Status string `json:"status,omitempty" yaml:"status,omitempty"`
|
||||||
|
Package string `json:"package" yaml:"package"`
|
||||||
|
Caring CaringPolicyMetadata `json:"caring" yaml:"caring"`
|
||||||
|
Activation map[string]any `json:"activation,omitempty" yaml:"activation,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaringPolicyMetadata declares the CARING envelope a policy governs.
|
||||||
|
type CaringPolicyMetadata struct {
|
||||||
|
Profile string `json:"profile" yaml:"profile"`
|
||||||
|
CanonicalRoles []CanonicalRole `json:"canonical_roles,omitempty" yaml:"canonical_roles,omitempty"`
|
||||||
|
OrganizationRelations []OrganizationRelation `json:"organization_relations,omitempty" yaml:"organization_relations,omitempty"`
|
||||||
|
Scopes []CaringScope `json:"scopes,omitempty" yaml:"scopes,omitempty"`
|
||||||
|
Planes []Plane `json:"planes,omitempty" yaml:"planes,omitempty"`
|
||||||
|
Capabilities []Capability `json:"capabilities,omitempty" yaml:"capabilities,omitempty"`
|
||||||
|
ExposureModes []ExposureMode `json:"exposure_modes,omitempty" yaml:"exposure_modes,omitempty"`
|
||||||
|
Conditions []Condition `json:"conditions,omitempty" yaml:"conditions,omitempty"`
|
||||||
|
Restrictions []Restriction `json:"restrictions,omitempty" yaml:"restrictions,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolicyFixture binds a check request to an expected decision.
|
||||||
|
type PolicyFixture struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Request CheckRequest `json:"request" yaml:"request"`
|
||||||
|
Expect DecisionExpectation `json:"expect" yaml:"expect"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecisionExpectation is the compact fixture expectation for policy tests.
|
||||||
|
type DecisionExpectation struct {
|
||||||
|
Effect DecisionEffect `json:"effect" yaml:"effect"`
|
||||||
|
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||||
|
Obligations []Obligation `json:"obligations,omitempty" yaml:"obligations,omitempty"`
|
||||||
|
ConformanceFindings []CaringConformanceFinding `json:"conformance_findings,omitempty" yaml:"conformance_findings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckRequest is the stable protected-system-facing decision request.
|
||||||
|
type CheckRequest struct {
|
||||||
|
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
|
Subject SubjectRef `json:"subject" yaml:"subject"`
|
||||||
|
Action string `json:"action" yaml:"action"`
|
||||||
|
Resource ResourceRef `json:"resource" yaml:"resource"`
|
||||||
|
Context map[string]any `json:"context,omitempty" yaml:"context,omitempty"`
|
||||||
|
CaringContext *CaringAccessDescriptor `json:"caring_context,omitempty" yaml:"caring_context,omitempty"`
|
||||||
|
PolicyVersion string `json:"policy_version,omitempty" yaml:"policy_version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchCheckRequest evaluates one subject/action against multiple resources.
|
||||||
|
type BatchCheckRequest struct {
|
||||||
|
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
|
Subject SubjectRef `json:"subject" yaml:"subject"`
|
||||||
|
Action string `json:"action" yaml:"action"`
|
||||||
|
Resources []ResourceRef `json:"resources" yaml:"resources"`
|
||||||
|
Context map[string]any `json:"context,omitempty" yaml:"context,omitempty"`
|
||||||
|
PolicyVersion string `json:"policy_version,omitempty" yaml:"policy_version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubjectRef is a normalized subject reference in request and decision shapes.
|
||||||
|
type SubjectRef struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Type SubjectType `json:"type,omitempty" yaml:"type,omitempty"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceRef is a normalized resource reference in request and decision shapes.
|
||||||
|
type ResourceRef struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||||
|
System string `json:"system,omitempty" yaml:"system,omitempty"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecisionEffect is the stable decision outcome vocabulary.
|
||||||
|
type DecisionEffect string
|
||||||
|
|
||||||
|
const (
|
||||||
|
DecisionEffectAllow DecisionEffect = "allow"
|
||||||
|
DecisionEffectDeny DecisionEffect = "deny"
|
||||||
|
DecisionEffectRedact DecisionEffect = "redact"
|
||||||
|
DecisionEffectAuditOnly DecisionEffect = "audit_only"
|
||||||
|
DecisionEffectNotApplicable DecisionEffect = "not_applicable"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DecisionEnvelope is the stable response produced by standalone and delegated
|
||||||
|
// evaluators.
|
||||||
|
type DecisionEnvelope struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
RequestID string `json:"request_id,omitempty" yaml:"request_id,omitempty"`
|
||||||
|
Effect DecisionEffect `json:"effect" yaml:"effect"`
|
||||||
|
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
|
||||||
|
MatchedPolicyVersion string `json:"matched_policy_version,omitempty" yaml:"matched_policy_version,omitempty"`
|
||||||
|
MatchedRule string `json:"matched_rule,omitempty" yaml:"matched_rule,omitempty"`
|
||||||
|
Resource ResourceRef `json:"resource" yaml:"resource"`
|
||||||
|
Subject SubjectRef `json:"subject" yaml:"subject"`
|
||||||
|
Obligations []Obligation `json:"obligations,omitempty" yaml:"obligations,omitempty"`
|
||||||
|
Diagnostics map[string]any `json:"diagnostics,omitempty" yaml:"diagnostics,omitempty"`
|
||||||
|
Provenance DecisionProvenance `json:"provenance" yaml:"provenance"`
|
||||||
|
Caring *CaringDecisionMetadata `json:"caring,omitempty" yaml:"caring,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obligation describes a follow-up behavior required by a decision.
|
||||||
|
type Obligation struct {
|
||||||
|
Type string `json:"type" yaml:"type"`
|
||||||
|
Parameters map[string]any `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecisionProvenance captures evaluator and policy provenance.
|
||||||
|
type DecisionProvenance struct {
|
||||||
|
Evaluator string `json:"evaluator" yaml:"evaluator"`
|
||||||
|
Mode string `json:"mode" yaml:"mode"`
|
||||||
|
PolicyPackage string `json:"policy_package,omitempty" yaml:"policy_package,omitempty"`
|
||||||
|
PolicyVersion string `json:"policy_version,omitempty" yaml:"policy_version,omitempty"`
|
||||||
|
DirectoryETag string `json:"directory_etag,omitempty" yaml:"directory_etag,omitempty"`
|
||||||
|
DecisionTime string `json:"decision_time,omitempty" yaml:"decision_time,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaringDecisionMetadata carries CARING descriptor and conformance details in
|
||||||
|
// a decision envelope.
|
||||||
|
type CaringDecisionMetadata struct {
|
||||||
|
Profile string `json:"profile" yaml:"profile"`
|
||||||
|
Descriptor *CaringAccessDescriptor `json:"descriptor,omitempty" yaml:"descriptor,omitempty"`
|
||||||
|
RestrictionsEvaluated []Restriction `json:"restrictions_evaluated,omitempty" yaml:"restrictions_evaluated,omitempty"`
|
||||||
|
ExposureModes []ExposureMode `json:"exposure_modes,omitempty" yaml:"exposure_modes,omitempty"`
|
||||||
|
DerivedCapabilities []CaringDerivedCapability `json:"derived_capabilities,omitempty" yaml:"derived_capabilities,omitempty"`
|
||||||
|
ConformanceFindings []CaringConformanceFinding `json:"conformance_findings,omitempty" yaml:"conformance_findings,omitempty"`
|
||||||
|
ExposureEvent *CaringExposureEvent `json:"exposure_event,omitempty" yaml:"exposure_event,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuditEvent is the local log shape for decisions and exposure events.
|
||||||
|
type AuditEvent struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Type string `json:"type" yaml:"type"`
|
||||||
|
DecisionID string `json:"decision_id,omitempty" yaml:"decision_id,omitempty"`
|
||||||
|
Subject SubjectRef `json:"subject" yaml:"subject"`
|
||||||
|
Resource ResourceRef `json:"resource,omitempty" yaml:"resource,omitempty"`
|
||||||
|
Action string `json:"action,omitempty" yaml:"action,omitempty"`
|
||||||
|
Effect DecisionEffect `json:"effect,omitempty" yaml:"effect,omitempty"`
|
||||||
|
Timestamp string `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
|
||||||
|
ExposureEvent *CaringExposureEvent `json:"exposure_event,omitempty" yaml:"exposure_event,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
130
pkg/api/canonical_test.go
Normal file
130
pkg/api/canonical_test.go
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
package api_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/netkingdom/flex-auth/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCaringAccessDescriptorExampleParses(t *testing.T) {
|
||||||
|
var got api.CaringAccessDescriptor
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "access_descriptor.yaml"), &got)
|
||||||
|
|
||||||
|
if got.Profile != api.CaringProfileCaring040RC2 {
|
||||||
|
t.Fatalf("Profile = %q; want %q", got.Profile, api.CaringProfileCaring040RC2)
|
||||||
|
}
|
||||||
|
if got.CanonicalRole != api.CanonicalRoleDoer {
|
||||||
|
t.Errorf("CanonicalRole = %q; want Doer", got.CanonicalRole)
|
||||||
|
}
|
||||||
|
if got.Scope.Level != api.ScopeLevelResource || got.Scope.Tenant != "tenant:alpha" {
|
||||||
|
t.Errorf("Scope = %+v; want resource scope in tenant:alpha", got.Scope)
|
||||||
|
}
|
||||||
|
if len(got.Restrictions) != 1 || got.Restrictions[0] != api.RestrictionExportBlocked {
|
||||||
|
t.Errorf("Restrictions = %v; want [ExportBlocked]", got.Restrictions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckRequestExampleParses(t *testing.T) {
|
||||||
|
var got api.CheckRequest
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "check_request.yaml"), &got)
|
||||||
|
|
||||||
|
if got.Subject.ID != "user:alice" {
|
||||||
|
t.Errorf("Subject.ID = %q; want user:alice", got.Subject.ID)
|
||||||
|
}
|
||||||
|
if got.Resource.ID != "document:internal-note" {
|
||||||
|
t.Errorf("Resource.ID = %q; want document:internal-note", got.Resource.ID)
|
||||||
|
}
|
||||||
|
if got.CaringContext == nil {
|
||||||
|
t.Fatal("CaringContext is nil")
|
||||||
|
}
|
||||||
|
if got.CaringContext.AccessPath != api.AccessPathDirect {
|
||||||
|
t.Errorf("CaringContext.AccessPath = %q; want direct", got.CaringContext.AccessPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRegistryExamplesParse(t *testing.T) {
|
||||||
|
var subjects api.SubjectManifest
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "subject_manifest.yaml"), &subjects)
|
||||||
|
if len(subjects.Subjects) != 1 || subjects.Subjects[0].Type != api.SubjectTypeHuman {
|
||||||
|
t.Fatalf("subjects did not parse as expected: %+v", subjects.Subjects)
|
||||||
|
}
|
||||||
|
|
||||||
|
var relationship api.RelationshipFact
|
||||||
|
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "relationship_fact.yaml"), &relationship)
|
||||||
|
if relationship.Caring == nil {
|
||||||
|
t.Fatal("RelationshipFact.Caring is nil")
|
||||||
|
}
|
||||||
|
if relationship.Caring.SubjectType != api.SubjectTypeGroup {
|
||||||
|
t.Errorf("RelationshipFact.Caring.SubjectType = %q; want Group", relationship.Caring.SubjectType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecisionAndAuditExamplesParse(t *testing.T) {
|
||||||
|
var decision api.DecisionEnvelope
|
||||||
|
loadJSON(t, filepath.Join("..", "..", "examples", "caring", "decision_envelope.json"), &decision)
|
||||||
|
if decision.Effect != api.DecisionEffectAllow {
|
||||||
|
t.Errorf("Decision.Effect = %q; want allow", decision.Effect)
|
||||||
|
}
|
||||||
|
if decision.Caring == nil || decision.Caring.Profile != api.CaringProfileCaring040RC2 {
|
||||||
|
t.Fatalf("Decision.Caring = %+v; want CARING profile metadata", decision.Caring)
|
||||||
|
}
|
||||||
|
if len(decision.Caring.ConformanceFindings) != 1 {
|
||||||
|
t.Errorf("ConformanceFindings len = %d; want 1", len(decision.Caring.ConformanceFindings))
|
||||||
|
}
|
||||||
|
|
||||||
|
var audit api.AuditEvent
|
||||||
|
loadJSON(t, filepath.Join("..", "..", "examples", "caring", "audit_event.json"), &audit)
|
||||||
|
if audit.DecisionID != decision.ID {
|
||||||
|
t.Errorf("Audit.DecisionID = %q; want %q", audit.DecisionID, decision.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSchemaFilesAreJSON(t *testing.T) {
|
||||||
|
schemaDir := filepath.Join("..", "..", "schemas")
|
||||||
|
entries, err := os.ReadDir(schemaDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read schema dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if entry.IsDir() || filepath.Ext(entry.Name()) != ".json" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
t.Run(entry.Name(), func(t *testing.T) {
|
||||||
|
var got map[string]any
|
||||||
|
loadJSON(t, filepath.Join(schemaDir, entry.Name()), &got)
|
||||||
|
if got["$schema"] == "" || got["$id"] == "" {
|
||||||
|
t.Fatalf("%s missing $schema or $id", entry.Name())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadYAML(t *testing.T, path string, out any) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read %s: %v", path, err)
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(data, out); err != nil {
|
||||||
|
t.Fatalf("unmarshal %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadJSON(t *testing.T, path string, out any) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read %s: %v", path, err)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, out); err != nil {
|
||||||
|
t.Fatalf("unmarshal %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
335
pkg/api/caring.go
Normal file
335
pkg/api/caring.go
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// CaringProfileCaring040RC2 is the executable profile identifier for the
|
||||||
|
// CARING 0.4.0-RC2 standard pinned by flex-auth.
|
||||||
|
const CaringProfileCaring040RC2 = "caring-0.4.0-rc2"
|
||||||
|
|
||||||
|
// SubjectType is the CARING subject dimension.
|
||||||
|
type SubjectType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SubjectTypeHuman SubjectType = "Human"
|
||||||
|
SubjectTypeGroup SubjectType = "Group"
|
||||||
|
SubjectTypeOrganization SubjectType = "Organization"
|
||||||
|
SubjectTypeService SubjectType = "Service"
|
||||||
|
SubjectTypeAutomation SubjectType = "Automation"
|
||||||
|
SubjectTypeAgent SubjectType = "Agent"
|
||||||
|
SubjectTypeSystem SubjectType = "System"
|
||||||
|
SubjectTypeDevice SubjectType = "Device"
|
||||||
|
SubjectTypeProcess SubjectType = "Process"
|
||||||
|
SubjectTypeAnonymous SubjectType = "Anonymous"
|
||||||
|
SubjectTypeUnknown SubjectType = "Unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OrganizationRelation is the CARING organization-relation dimension.
|
||||||
|
type OrganizationRelation string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrganizationRelationVendor OrganizationRelation = "Vendor"
|
||||||
|
OrganizationRelationServiceProvider OrganizationRelation = "ServiceProvider"
|
||||||
|
OrganizationRelationDistributor OrganizationRelation = "Distributor"
|
||||||
|
OrganizationRelationConsultant OrganizationRelation = "Consultant"
|
||||||
|
OrganizationRelationCustomer OrganizationRelation = "Customer"
|
||||||
|
OrganizationRelationCommunity OrganizationRelation = "Community"
|
||||||
|
OrganizationRelationAuthority OrganizationRelation = "Authority"
|
||||||
|
OrganizationRelationUnknown OrganizationRelation = "Unknown"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CanonicalRole is the CARING lifecycle responsibility posture.
|
||||||
|
type CanonicalRole string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CanonicalRoleCreator CanonicalRole = "Creator"
|
||||||
|
CanonicalRoleBuilder CanonicalRole = "Builder"
|
||||||
|
CanonicalRoleVerifier CanonicalRole = "Verifier"
|
||||||
|
CanonicalRoleMaintainer CanonicalRole = "Maintainer"
|
||||||
|
CanonicalRoleIntegrator CanonicalRole = "Integrator"
|
||||||
|
CanonicalRoleOperator CanonicalRole = "Operator"
|
||||||
|
CanonicalRoleManager CanonicalRole = "Manager"
|
||||||
|
CanonicalRoleCoach CanonicalRole = "Coach"
|
||||||
|
CanonicalRoleDoer CanonicalRole = "Doer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ScopeLevel is the CARING scope ladder.
|
||||||
|
type ScopeLevel string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ScopeLevelEcosystem ScopeLevel = "Ecosystem"
|
||||||
|
ScopeLevelProduct ScopeLevel = "Product"
|
||||||
|
ScopeLevelPlatform ScopeLevel = "Platform"
|
||||||
|
ScopeLevelCluster ScopeLevel = "Cluster"
|
||||||
|
ScopeLevelEnvironment ScopeLevel = "Environment"
|
||||||
|
ScopeLevelTenant ScopeLevel = "Tenant"
|
||||||
|
ScopeLevelNamespace ScopeLevel = "Namespace"
|
||||||
|
ScopeLevelDomain ScopeLevel = "Domain"
|
||||||
|
ScopeLevelWorkspace ScopeLevel = "Workspace"
|
||||||
|
ScopeLevelProject ScopeLevel = "Project"
|
||||||
|
ScopeLevelProcess ScopeLevel = "Process"
|
||||||
|
ScopeLevelDataset ScopeLevel = "Dataset"
|
||||||
|
ScopeLevelResource ScopeLevel = "Resource"
|
||||||
|
ScopeLevelSubresource ScopeLevel = "Subresource"
|
||||||
|
ScopeLevelRecord ScopeLevel = "Record"
|
||||||
|
ScopeLevelField ScopeLevel = "Field"
|
||||||
|
ScopeLevelAction ScopeLevel = "Action"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Plane is the CARING access-surface dimension.
|
||||||
|
type Plane string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PlaneIntent Plane = "Intent"
|
||||||
|
PlaneBuild Plane = "Build"
|
||||||
|
PlaneRuntime Plane = "Runtime"
|
||||||
|
PlaneExecution Plane = "Execution"
|
||||||
|
PlaneConfiguration Plane = "Configuration"
|
||||||
|
PlaneData Plane = "Data"
|
||||||
|
PlaneIdentity Plane = "Identity"
|
||||||
|
PlanePolicy Plane = "Policy"
|
||||||
|
PlaneSecret Plane = "Secret"
|
||||||
|
PlaneAudit Plane = "Audit"
|
||||||
|
PlaneCommercial Plane = "Commercial"
|
||||||
|
PlaneCommunity Plane = "Community"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Capability is a CARING capability verb.
|
||||||
|
type Capability string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CapabilityView Capability = "View"
|
||||||
|
CapabilityViewCollection Capability = "ViewCollection"
|
||||||
|
CapabilityObserve Capability = "Observe"
|
||||||
|
CapabilityCreate Capability = "Create"
|
||||||
|
CapabilityEditOwn Capability = "EditOwn"
|
||||||
|
CapabilityEditAssigned Capability = "EditAssigned"
|
||||||
|
CapabilityEditAny Capability = "EditAny"
|
||||||
|
CapabilityDeleteOwn Capability = "DeleteOwn"
|
||||||
|
CapabilityDeleteAny Capability = "DeleteAny"
|
||||||
|
CapabilityBulkDelete Capability = "BulkDelete"
|
||||||
|
CapabilitySubmit Capability = "Submit"
|
||||||
|
CapabilityComment Capability = "Comment"
|
||||||
|
CapabilityReview Capability = "Review"
|
||||||
|
CapabilityApprove Capability = "Approve"
|
||||||
|
CapabilityReject Capability = "Reject"
|
||||||
|
CapabilityPublish Capability = "Publish"
|
||||||
|
CapabilityArchive Capability = "Archive"
|
||||||
|
CapabilityRestore Capability = "Restore"
|
||||||
|
CapabilityExecute Capability = "Execute"
|
||||||
|
CapabilityConfigure Capability = "Configure"
|
||||||
|
CapabilityOperate Capability = "Operate"
|
||||||
|
CapabilityDeploy Capability = "Deploy"
|
||||||
|
CapabilityIntegrate Capability = "Integrate"
|
||||||
|
CapabilityGrant Capability = "Grant"
|
||||||
|
CapabilityRevoke Capability = "Revoke"
|
||||||
|
CapabilityDelegate Capability = "Delegate"
|
||||||
|
CapabilityImpersonate Capability = "Impersonate"
|
||||||
|
CapabilityExport Capability = "Export"
|
||||||
|
CapabilityImport Capability = "Import"
|
||||||
|
CapabilityReplicate Capability = "Replicate"
|
||||||
|
CapabilityEncrypt Capability = "Encrypt"
|
||||||
|
CapabilityDecrypt Capability = "Decrypt"
|
||||||
|
CapabilityMask Capability = "Mask"
|
||||||
|
CapabilityInspect Capability = "Inspect"
|
||||||
|
CapabilityAudit Capability = "Audit"
|
||||||
|
CapabilityOverride Capability = "Override"
|
||||||
|
CapabilityEscalate Capability = "Escalate"
|
||||||
|
CapabilityBind Capability = "Bind"
|
||||||
|
CapabilityUse Capability = "Use"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExposureMode describes how much information becomes visible or extractable.
|
||||||
|
type ExposureMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExposureModeNone ExposureMode = "None"
|
||||||
|
ExposureModeMetadata ExposureMode = "Metadata"
|
||||||
|
ExposureModeMasked ExposureMode = "Masked"
|
||||||
|
ExposureModeAggregated ExposureMode = "Aggregated"
|
||||||
|
ExposureModeSynthetic ExposureMode = "Synthetic"
|
||||||
|
ExposureModePseudonymous ExposureMode = "Pseudonymous"
|
||||||
|
ExposureModeEncrypted ExposureMode = "Encrypted"
|
||||||
|
ExposureModePlaintext ExposureMode = "Plaintext"
|
||||||
|
ExposureModeSecretMaterial ExposureMode = "SecretMaterial"
|
||||||
|
ExposureModeExportable ExposureMode = "Exportable"
|
||||||
|
ExposureModeCrossTenantAggregate ExposureMode = "CrossTenantAggregate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Condition is a CARING runtime or governance condition.
|
||||||
|
type Condition string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConditionMFARequired Condition = "MFARequired"
|
||||||
|
ConditionDeviceTrusted Condition = "DeviceTrusted"
|
||||||
|
ConditionNetworkTrusted Condition = "NetworkTrusted"
|
||||||
|
ConditionTicketRequired Condition = "TicketRequired"
|
||||||
|
ConditionTenantConsentRequired Condition = "TenantConsentRequired"
|
||||||
|
ConditionCustomerApprovalRequired Condition = "CustomerApprovalRequired"
|
||||||
|
ConditionDualApprovalRequired Condition = "DualApprovalRequired"
|
||||||
|
ConditionTimeLimited Condition = "TimeLimited"
|
||||||
|
ConditionBusinessHoursOnly Condition = "BusinessHoursOnly"
|
||||||
|
ConditionEmergencyOnly Condition = "EmergencyOnly"
|
||||||
|
ConditionTrainingRequired Condition = "TrainingRequired"
|
||||||
|
ConditionContractRequired Condition = "ContractRequired"
|
||||||
|
ConditionNDARequired Condition = "NDARequired"
|
||||||
|
ConditionPurposeBound Condition = "PurposeBound"
|
||||||
|
ConditionCaseBound Condition = "CaseBound"
|
||||||
|
ConditionEnvironmentBound Condition = "EnvironmentBound"
|
||||||
|
ConditionNamespaceBound Condition = "NamespaceBound"
|
||||||
|
ConditionPipelineBound Condition = "PipelineBound"
|
||||||
|
ConditionChangeWindowBound Condition = "ChangeWindowBound"
|
||||||
|
ConditionLogged Condition = "Logged"
|
||||||
|
ConditionRecorded Condition = "Recorded"
|
||||||
|
ConditionNotificationRequired Condition = "NotificationRequired"
|
||||||
|
ConditionPostReviewRequired Condition = "PostReviewRequired"
|
||||||
|
ConditionHumanReviewRequired Condition = "HumanReviewRequired"
|
||||||
|
ConditionPolicyReviewRequired Condition = "PolicyReviewRequired"
|
||||||
|
ConditionWorkloadIdentityRequired Condition = "WorkloadIdentityRequired"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LifecycleState describes why access exists now.
|
||||||
|
type LifecycleState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
LifecycleStateDesign LifecycleState = "Design"
|
||||||
|
LifecycleStateBuild LifecycleState = "Build"
|
||||||
|
LifecycleStateTest LifecycleState = "Test"
|
||||||
|
LifecycleStateReview LifecycleState = "Review"
|
||||||
|
LifecycleStateRelease LifecycleState = "Release"
|
||||||
|
LifecycleStateOnboard LifecycleState = "Onboard"
|
||||||
|
LifecycleStateIntegrate LifecycleState = "Integrate"
|
||||||
|
LifecycleStateMigrate LifecycleState = "Migrate"
|
||||||
|
LifecycleStateOperate LifecycleState = "Operate"
|
||||||
|
LifecycleStateSupport LifecycleState = "Support"
|
||||||
|
LifecycleStateImprove LifecycleState = "Improve"
|
||||||
|
LifecycleStateDeprecate LifecycleState = "Deprecate"
|
||||||
|
LifecycleStateArchive LifecycleState = "Archive"
|
||||||
|
LifecycleStateIncident LifecycleState = "Incident"
|
||||||
|
LifecycleStateLegal LifecycleState = "Legal"
|
||||||
|
LifecycleStateTerminate LifecycleState = "Terminate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Restriction is an overriding CARING deny or limiting policy effect.
|
||||||
|
type Restriction string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RestrictionNoAccess Restriction = "NoAccess"
|
||||||
|
RestrictionSuspended Restriction = "Suspended"
|
||||||
|
RestrictionTerminated Restriction = "Terminated"
|
||||||
|
RestrictionQuarantined Restriction = "Quarantined"
|
||||||
|
RestrictionScopeExcluded Restriction = "ScopeExcluded"
|
||||||
|
RestrictionDataClassRestricted Restriction = "DataClassRestricted"
|
||||||
|
RestrictionLegalHold Restriction = "LegalHold"
|
||||||
|
RestrictionExportBlocked Restriction = "ExportBlocked"
|
||||||
|
RestrictionImpersonationBlocked Restriction = "ImpersonationBlocked"
|
||||||
|
RestrictionCrossTenantBlocked Restriction = "CrossTenantBlocked"
|
||||||
|
RestrictionSecretAccessBlocked Restriction = "SecretAccessBlocked"
|
||||||
|
RestrictionPolicyFrozen Restriction = "PolicyFrozen"
|
||||||
|
RestrictionEmergencyLocked Restriction = "EmergencyLocked"
|
||||||
|
RestrictionRiskDenied Restriction = "RiskDenied"
|
||||||
|
RestrictionExecutionBlocked Restriction = "ExecutionBlocked"
|
||||||
|
RestrictionWorkloadCreationBlocked Restriction = "WorkloadCreationBlocked"
|
||||||
|
RestrictionPrivilegeEscalationBlocked Restriction = "PrivilegeEscalationBlocked"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExposureEventType is a CARING exceptional or irregular access class.
|
||||||
|
type ExposureEventType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExposureEventSupport ExposureEventType = "X-Support"
|
||||||
|
ExposureEventBreakGlass ExposureEventType = "X-BreakGlass"
|
||||||
|
ExposureEventSecurityTest ExposureEventType = "X-SecurityTest"
|
||||||
|
ExposureEventIncident ExposureEventType = "X-Incident"
|
||||||
|
ExposureEventLegalDemand ExposureEventType = "X-LegalDemand"
|
||||||
|
ExposureEventComplianceAudit ExposureEventType = "X-ComplianceAudit"
|
||||||
|
ExposureEventMigration ExposureEventType = "X-Migration"
|
||||||
|
ExposureEventRecovery ExposureEventType = "X-Recovery"
|
||||||
|
ExposureEventAdversarial ExposureEventType = "X-Adversarial"
|
||||||
|
ExposureEventMisconfiguration ExposureEventType = "X-Misconfiguration"
|
||||||
|
ExposureEventInducedAccess ExposureEventType = "X-InducedAccess"
|
||||||
|
ExposureEventPrivilegeEscalation ExposureEventType = "X-PrivilegeEscalation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccessPath describes how access is exercised.
|
||||||
|
type AccessPath string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AccessPathDirect AccessPath = "direct"
|
||||||
|
AccessPathDelegated AccessPath = "delegated"
|
||||||
|
AccessPathMediated AccessPath = "mediated"
|
||||||
|
AccessPathInduced AccessPath = "induced"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CaringScope identifies where a CARING descriptor applies.
|
||||||
|
type CaringScope struct {
|
||||||
|
Level ScopeLevel `json:"level" yaml:"level"`
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Parent string `json:"parent,omitempty" yaml:"parent,omitempty"`
|
||||||
|
Tenant string `json:"tenant,omitempty" yaml:"tenant,omitempty"`
|
||||||
|
Resource string `json:"resource,omitempty" yaml:"resource,omitempty"`
|
||||||
|
Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaringAccessDescriptor is the executable flex-auth representation of a
|
||||||
|
// CARING access assignment.
|
||||||
|
type CaringAccessDescriptor struct {
|
||||||
|
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
|
Profile string `json:"profile" yaml:"profile"`
|
||||||
|
SubjectType SubjectType `json:"subject_type" yaml:"subject_type"`
|
||||||
|
OrganizationRelation OrganizationRelation `json:"organization_relation" yaml:"organization_relation"`
|
||||||
|
CanonicalRole CanonicalRole `json:"canonical_role" yaml:"canonical_role"`
|
||||||
|
Scope CaringScope `json:"scope" yaml:"scope"`
|
||||||
|
Planes []Plane `json:"planes" yaml:"planes"`
|
||||||
|
Capabilities []Capability `json:"capabilities" yaml:"capabilities"`
|
||||||
|
ExposureModes []ExposureMode `json:"exposure_modes,omitempty" yaml:"exposure_modes,omitempty"`
|
||||||
|
Conditions []Condition `json:"conditions,omitempty" yaml:"conditions,omitempty"`
|
||||||
|
LifecycleState LifecycleState `json:"lifecycle_state,omitempty" yaml:"lifecycle_state,omitempty"`
|
||||||
|
Restrictions []Restriction `json:"restrictions,omitempty" yaml:"restrictions,omitempty"`
|
||||||
|
ExposureEvent ExposureEventType `json:"exposure_event,omitempty" yaml:"exposure_event,omitempty"`
|
||||||
|
DerivedCapabilities []CaringDerivedCapability `json:"derived_capabilities,omitempty" yaml:"derived_capabilities,omitempty"`
|
||||||
|
AccessPath AccessPath `json:"access_path,omitempty" yaml:"access_path,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaringDerivedCapability records effective authority created by another grant.
|
||||||
|
type CaringDerivedCapability struct {
|
||||||
|
Capability Capability `json:"capability" yaml:"capability"`
|
||||||
|
Reason string `json:"reason" yaml:"reason"`
|
||||||
|
Source string `json:"source,omitempty" yaml:"source,omitempty"`
|
||||||
|
Planes []Plane `json:"planes,omitempty" yaml:"planes,omitempty"`
|
||||||
|
ExposureModes []ExposureMode `json:"exposure_modes,omitempty" yaml:"exposure_modes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaringConformanceFinding is a diagnostic emitted by descriptive or
|
||||||
|
// prescriptive CARING validation.
|
||||||
|
type CaringConformanceFinding struct {
|
||||||
|
Code string `json:"code" yaml:"code"`
|
||||||
|
Severity string `json:"severity" yaml:"severity"`
|
||||||
|
Message string `json:"message" yaml:"message"`
|
||||||
|
Fields []string `json:"fields,omitempty" yaml:"fields,omitempty"`
|
||||||
|
Descriptor string `json:"descriptor,omitempty" yaml:"descriptor,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaringExposureEvent records exceptional or irregular information exposure.
|
||||||
|
type CaringExposureEvent struct {
|
||||||
|
ID string `json:"id" yaml:"id"`
|
||||||
|
Type ExposureEventType `json:"type" yaml:"type"`
|
||||||
|
Actor string `json:"actor" yaml:"actor"`
|
||||||
|
Subject string `json:"subject" yaml:"subject"`
|
||||||
|
Descriptor *CaringAccessDescriptor `json:"descriptor,omitempty" yaml:"descriptor,omitempty"`
|
||||||
|
Scope *CaringScope `json:"scope,omitempty" yaml:"scope,omitempty"`
|
||||||
|
Planes []Plane `json:"planes,omitempty" yaml:"planes,omitempty"`
|
||||||
|
CapabilitiesUsed []Capability `json:"capabilities_used,omitempty" yaml:"capabilities_used,omitempty"`
|
||||||
|
DerivedCapabilities []CaringDerivedCapability `json:"derived_capabilities,omitempty" yaml:"derived_capabilities,omitempty"`
|
||||||
|
ExposureModes []ExposureMode `json:"exposure_modes,omitempty" yaml:"exposure_modes,omitempty"`
|
||||||
|
Reason string `json:"reason" yaml:"reason"`
|
||||||
|
AuthoritySource string `json:"authority_source,omitempty" yaml:"authority_source,omitempty"`
|
||||||
|
Approval string `json:"approval,omitempty" yaml:"approval,omitempty"`
|
||||||
|
StartTime string `json:"start_time,omitempty" yaml:"start_time,omitempty"`
|
||||||
|
EndTime string `json:"end_time,omitempty" yaml:"end_time,omitempty"`
|
||||||
|
ResourcesAccessed []string `json:"resources_accessed,omitempty" yaml:"resources_accessed,omitempty"`
|
||||||
|
Evidence []string `json:"evidence,omitempty" yaml:"evidence,omitempty"`
|
||||||
|
NotificationStatus string `json:"notification_status,omitempty" yaml:"notification_status,omitempty"`
|
||||||
|
PostReview string `json:"post_review,omitempty" yaml:"post_review,omitempty"`
|
||||||
|
ConformanceFindings []CaringConformanceFinding `json:"conformance_findings,omitempty" yaml:"conformance_findings,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
|
}
|
||||||
@@ -6,23 +6,25 @@ package api
|
|||||||
// schemas/resource_manifest.schema.json for the JSON Schema and
|
// schemas/resource_manifest.schema.json for the JSON Schema and
|
||||||
// examples/markitect/resource_manifest.yaml for the canonical example.
|
// examples/markitect/resource_manifest.yaml for the canonical example.
|
||||||
type ResourceManifest struct {
|
type ResourceManifest struct {
|
||||||
ID string `json:"id" yaml:"id"`
|
ID string `json:"id" yaml:"id"`
|
||||||
System string `json:"system" yaml:"system"`
|
System string `json:"system" yaml:"system"`
|
||||||
Resources []Resource `json:"resources" yaml:"resources"`
|
Resources []Resource `json:"resources" yaml:"resources"`
|
||||||
Actions []string `json:"actions,omitempty" yaml:"actions,omitempty"`
|
Actions []string `json:"actions,omitempty" yaml:"actions,omitempty"`
|
||||||
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
CaringProfile string `json:"caring_profile,omitempty" yaml:"caring_profile,omitempty"`
|
||||||
|
Metadata map[string]any `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resource is one entry in a ResourceManifest.
|
// Resource is one entry in a ResourceManifest.
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
ID string `json:"id" yaml:"id"`
|
ID string `json:"id" yaml:"id"`
|
||||||
Type string `json:"type" yaml:"type"`
|
Type string `json:"type" yaml:"type"`
|
||||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
Parent string `json:"parent,omitempty" yaml:"parent,omitempty"`
|
Parent string `json:"parent,omitempty" yaml:"parent,omitempty"`
|
||||||
Labels []string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
Labels []string `json:"labels,omitempty" yaml:"labels,omitempty"`
|
||||||
TrustZone string `json:"trust_zone,omitempty" yaml:"trust_zone,omitempty"`
|
TrustZone string `json:"trust_zone,omitempty" yaml:"trust_zone,omitempty"`
|
||||||
Owner string `json:"owner,omitempty" yaml:"owner,omitempty"`
|
Owner string `json:"owner,omitempty" yaml:"owner,omitempty"`
|
||||||
Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"`
|
Caring *CaringAccessDescriptor `json:"caring,omitempty" yaml:"caring,omitempty"`
|
||||||
|
Attributes map[string]any `json:"attributes,omitempty" yaml:"attributes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlexAuthContractV0 is the metadata.flex_auth_contract value that
|
// FlexAuthContractV0 is the metadata.flex_auth_contract value that
|
||||||
|
|||||||
@@ -3,9 +3,13 @@
|
|||||||
JSON Schema definitions for flex-auth's canonical artefacts:
|
JSON Schema definitions for flex-auth's canonical artefacts:
|
||||||
|
|
||||||
- `resource_manifest.schema.json` (pinned in `FLEX-WP-0005 P5.3`)
|
- `resource_manifest.schema.json` (pinned in `FLEX-WP-0005 P5.3`)
|
||||||
|
- `protected_system_manifest.schema.json`
|
||||||
- `subject_manifest.schema.json`
|
- `subject_manifest.schema.json`
|
||||||
- `relationship_fact.schema.json`
|
- `relationship_fact.schema.json`
|
||||||
- `policy_package_frontmatter.schema.json`
|
- `caring_profile.schema.json`
|
||||||
|
- `caring_access_descriptor.schema.json`
|
||||||
|
- `policy_package.schema.json`
|
||||||
|
- `policy_fixture.schema.json`
|
||||||
- `check_request.schema.json`
|
- `check_request.schema.json`
|
||||||
- `decision_envelope.schema.json`
|
- `decision_envelope.schema.json`
|
||||||
- `audit_event.schema.json`
|
- `audit_event.schema.json`
|
||||||
|
|||||||
20
schemas/audit_event.schema.json
Normal file
20
schemas/audit_event.schema.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/audit_event.schema.json",
|
||||||
|
"title": "AuditEvent",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "type", "subject"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"type": {"type": "string", "minLength": 1},
|
||||||
|
"decision_id": {"type": "string", "minLength": 1},
|
||||||
|
"subject": {"$ref": "https://flex-auth.netkingdom/schemas/check_request.schema.json#/$defs/subject_ref"},
|
||||||
|
"resource": {"$ref": "https://flex-auth.netkingdom/schemas/check_request.schema.json#/$defs/resource_ref"},
|
||||||
|
"action": {"type": "string", "minLength": 1},
|
||||||
|
"effect": {"enum": ["allow", "deny", "redact", "audit_only", "not_applicable"]},
|
||||||
|
"timestamp": {"type": "string", "minLength": 1},
|
||||||
|
"exposure_event": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/exposure_event"},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
358
schemas/caring_access_descriptor.schema.json
Normal file
358
schemas/caring_access_descriptor.schema.json
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json",
|
||||||
|
"title": "CaringAccessDescriptor",
|
||||||
|
"description": "Executable flex-auth representation of a CARING access descriptor pinned to CARING 0.4.0-RC2.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"profile",
|
||||||
|
"subject_type",
|
||||||
|
"organization_relation",
|
||||||
|
"canonical_role",
|
||||||
|
"scope",
|
||||||
|
"planes",
|
||||||
|
"capabilities"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"profile": {"const": "caring-0.4.0-rc2"},
|
||||||
|
"subject_type": {"$ref": "#/$defs/subject_type"},
|
||||||
|
"organization_relation": {"$ref": "#/$defs/organization_relation"},
|
||||||
|
"canonical_role": {"$ref": "#/$defs/canonical_role"},
|
||||||
|
"scope": {"$ref": "#/$defs/scope"},
|
||||||
|
"planes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/plane"},
|
||||||
|
"minItems": 1,
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"capabilities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/capability"},
|
||||||
|
"minItems": 1,
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"exposure_modes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/exposure_mode"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/condition"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"lifecycle_state": {"$ref": "#/$defs/lifecycle_state"},
|
||||||
|
"restrictions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/restriction"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"exposure_event": {"$ref": "#/$defs/exposure_event_type"},
|
||||||
|
"derived_capabilities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/derived_capability"}
|
||||||
|
},
|
||||||
|
"access_path": {"enum": ["direct", "delegated", "mediated", "induced"]},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"subject_type": {
|
||||||
|
"enum": [
|
||||||
|
"Human",
|
||||||
|
"Group",
|
||||||
|
"Organization",
|
||||||
|
"Service",
|
||||||
|
"Automation",
|
||||||
|
"Agent",
|
||||||
|
"System",
|
||||||
|
"Device",
|
||||||
|
"Process",
|
||||||
|
"Anonymous",
|
||||||
|
"Unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"organization_relation": {
|
||||||
|
"enum": [
|
||||||
|
"Vendor",
|
||||||
|
"ServiceProvider",
|
||||||
|
"Distributor",
|
||||||
|
"Consultant",
|
||||||
|
"Customer",
|
||||||
|
"Community",
|
||||||
|
"Authority",
|
||||||
|
"Unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"canonical_role": {
|
||||||
|
"enum": [
|
||||||
|
"Creator",
|
||||||
|
"Builder",
|
||||||
|
"Verifier",
|
||||||
|
"Maintainer",
|
||||||
|
"Integrator",
|
||||||
|
"Operator",
|
||||||
|
"Manager",
|
||||||
|
"Coach",
|
||||||
|
"Doer"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scope_level": {
|
||||||
|
"enum": [
|
||||||
|
"Ecosystem",
|
||||||
|
"Product",
|
||||||
|
"Platform",
|
||||||
|
"Cluster",
|
||||||
|
"Environment",
|
||||||
|
"Tenant",
|
||||||
|
"Namespace",
|
||||||
|
"Domain",
|
||||||
|
"Workspace",
|
||||||
|
"Project",
|
||||||
|
"Process",
|
||||||
|
"Dataset",
|
||||||
|
"Resource",
|
||||||
|
"Subresource",
|
||||||
|
"Record",
|
||||||
|
"Field",
|
||||||
|
"Action"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["level", "id"],
|
||||||
|
"properties": {
|
||||||
|
"level": {"$ref": "#/$defs/scope_level"},
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"parent": {"type": "string", "minLength": 1},
|
||||||
|
"tenant": {"type": "string", "minLength": 1},
|
||||||
|
"resource": {"type": "string", "minLength": 1},
|
||||||
|
"attributes": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plane": {
|
||||||
|
"enum": [
|
||||||
|
"Intent",
|
||||||
|
"Build",
|
||||||
|
"Runtime",
|
||||||
|
"Execution",
|
||||||
|
"Configuration",
|
||||||
|
"Data",
|
||||||
|
"Identity",
|
||||||
|
"Policy",
|
||||||
|
"Secret",
|
||||||
|
"Audit",
|
||||||
|
"Commercial",
|
||||||
|
"Community"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"capability": {
|
||||||
|
"enum": [
|
||||||
|
"View",
|
||||||
|
"ViewCollection",
|
||||||
|
"Observe",
|
||||||
|
"Create",
|
||||||
|
"EditOwn",
|
||||||
|
"EditAssigned",
|
||||||
|
"EditAny",
|
||||||
|
"DeleteOwn",
|
||||||
|
"DeleteAny",
|
||||||
|
"BulkDelete",
|
||||||
|
"Submit",
|
||||||
|
"Comment",
|
||||||
|
"Review",
|
||||||
|
"Approve",
|
||||||
|
"Reject",
|
||||||
|
"Publish",
|
||||||
|
"Archive",
|
||||||
|
"Restore",
|
||||||
|
"Execute",
|
||||||
|
"Configure",
|
||||||
|
"Operate",
|
||||||
|
"Deploy",
|
||||||
|
"Integrate",
|
||||||
|
"Grant",
|
||||||
|
"Revoke",
|
||||||
|
"Delegate",
|
||||||
|
"Impersonate",
|
||||||
|
"Export",
|
||||||
|
"Import",
|
||||||
|
"Replicate",
|
||||||
|
"Encrypt",
|
||||||
|
"Decrypt",
|
||||||
|
"Mask",
|
||||||
|
"Inspect",
|
||||||
|
"Audit",
|
||||||
|
"Override",
|
||||||
|
"Escalate",
|
||||||
|
"Bind",
|
||||||
|
"Use"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exposure_mode": {
|
||||||
|
"enum": [
|
||||||
|
"None",
|
||||||
|
"Metadata",
|
||||||
|
"Masked",
|
||||||
|
"Aggregated",
|
||||||
|
"Synthetic",
|
||||||
|
"Pseudonymous",
|
||||||
|
"Encrypted",
|
||||||
|
"Plaintext",
|
||||||
|
"SecretMaterial",
|
||||||
|
"Exportable",
|
||||||
|
"CrossTenantAggregate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"enum": [
|
||||||
|
"MFARequired",
|
||||||
|
"DeviceTrusted",
|
||||||
|
"NetworkTrusted",
|
||||||
|
"TicketRequired",
|
||||||
|
"TenantConsentRequired",
|
||||||
|
"CustomerApprovalRequired",
|
||||||
|
"DualApprovalRequired",
|
||||||
|
"TimeLimited",
|
||||||
|
"BusinessHoursOnly",
|
||||||
|
"EmergencyOnly",
|
||||||
|
"TrainingRequired",
|
||||||
|
"ContractRequired",
|
||||||
|
"NDARequired",
|
||||||
|
"PurposeBound",
|
||||||
|
"CaseBound",
|
||||||
|
"EnvironmentBound",
|
||||||
|
"NamespaceBound",
|
||||||
|
"PipelineBound",
|
||||||
|
"ChangeWindowBound",
|
||||||
|
"Logged",
|
||||||
|
"Recorded",
|
||||||
|
"NotificationRequired",
|
||||||
|
"PostReviewRequired",
|
||||||
|
"HumanReviewRequired",
|
||||||
|
"PolicyReviewRequired",
|
||||||
|
"WorkloadIdentityRequired"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"lifecycle_state": {
|
||||||
|
"enum": [
|
||||||
|
"Design",
|
||||||
|
"Build",
|
||||||
|
"Test",
|
||||||
|
"Review",
|
||||||
|
"Release",
|
||||||
|
"Onboard",
|
||||||
|
"Integrate",
|
||||||
|
"Migrate",
|
||||||
|
"Operate",
|
||||||
|
"Support",
|
||||||
|
"Improve",
|
||||||
|
"Deprecate",
|
||||||
|
"Archive",
|
||||||
|
"Incident",
|
||||||
|
"Legal",
|
||||||
|
"Terminate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"restriction": {
|
||||||
|
"enum": [
|
||||||
|
"NoAccess",
|
||||||
|
"Suspended",
|
||||||
|
"Terminated",
|
||||||
|
"Quarantined",
|
||||||
|
"ScopeExcluded",
|
||||||
|
"DataClassRestricted",
|
||||||
|
"LegalHold",
|
||||||
|
"ExportBlocked",
|
||||||
|
"ImpersonationBlocked",
|
||||||
|
"CrossTenantBlocked",
|
||||||
|
"SecretAccessBlocked",
|
||||||
|
"PolicyFrozen",
|
||||||
|
"EmergencyLocked",
|
||||||
|
"RiskDenied",
|
||||||
|
"ExecutionBlocked",
|
||||||
|
"WorkloadCreationBlocked",
|
||||||
|
"PrivilegeEscalationBlocked"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"exposure_event_type": {
|
||||||
|
"enum": [
|
||||||
|
"X-Support",
|
||||||
|
"X-BreakGlass",
|
||||||
|
"X-SecurityTest",
|
||||||
|
"X-Incident",
|
||||||
|
"X-LegalDemand",
|
||||||
|
"X-ComplianceAudit",
|
||||||
|
"X-Migration",
|
||||||
|
"X-Recovery",
|
||||||
|
"X-Adversarial",
|
||||||
|
"X-Misconfiguration",
|
||||||
|
"X-InducedAccess",
|
||||||
|
"X-PrivilegeEscalation"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"derived_capability": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["capability", "reason"],
|
||||||
|
"properties": {
|
||||||
|
"capability": {"$ref": "#/$defs/capability"},
|
||||||
|
"reason": {"type": "string", "minLength": 1},
|
||||||
|
"source": {"type": "string", "minLength": 1},
|
||||||
|
"planes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/plane"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"exposure_modes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/exposure_mode"},
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conformance_finding": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["code", "severity", "message"],
|
||||||
|
"properties": {
|
||||||
|
"code": {"type": "string", "minLength": 1},
|
||||||
|
"severity": {"enum": ["info", "warning", "violation", "blocked"]},
|
||||||
|
"message": {"type": "string", "minLength": 1},
|
||||||
|
"fields": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||||||
|
"descriptor": {"type": "string", "minLength": 1},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exposure_event": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "type", "actor", "subject", "reason"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"type": {"$ref": "#/$defs/exposure_event_type"},
|
||||||
|
"actor": {"type": "string", "minLength": 1},
|
||||||
|
"subject": {"type": "string", "minLength": 1},
|
||||||
|
"descriptor": {"$ref": "#"},
|
||||||
|
"scope": {"$ref": "#/$defs/scope"},
|
||||||
|
"planes": {"type": "array", "items": {"$ref": "#/$defs/plane"}},
|
||||||
|
"capabilities_used": {"type": "array", "items": {"$ref": "#/$defs/capability"}},
|
||||||
|
"derived_capabilities": {"type": "array", "items": {"$ref": "#/$defs/derived_capability"}},
|
||||||
|
"exposure_modes": {"type": "array", "items": {"$ref": "#/$defs/exposure_mode"}},
|
||||||
|
"reason": {"type": "string", "minLength": 1},
|
||||||
|
"authority_source": {"type": "string", "minLength": 1},
|
||||||
|
"approval": {"type": "string", "minLength": 1},
|
||||||
|
"start_time": {"type": "string", "minLength": 1},
|
||||||
|
"end_time": {"type": "string", "minLength": 1},
|
||||||
|
"resources_accessed": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||||||
|
"evidence": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||||||
|
"notification_status": {"type": "string", "minLength": 1},
|
||||||
|
"post_review": {"type": "string", "minLength": 1},
|
||||||
|
"conformance_findings": {"type": "array", "items": {"$ref": "#/$defs/conformance_finding"}},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
schemas/caring_profile.schema.json
Normal file
16
schemas/caring_profile.schema.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/caring_profile.schema.json",
|
||||||
|
"title": "CaringProfile",
|
||||||
|
"description": "Machine-readable pin for a CARING profile supported by flex-auth.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "standard", "version"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"const": "caring-0.4.0-rc2"},
|
||||||
|
"standard": {"const": "CARING"},
|
||||||
|
"version": {"const": "0.4.0-RC2"},
|
||||||
|
"source": {"type": "string", "minLength": 1},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
schemas/check_request.schema.json
Normal file
42
schemas/check_request.schema.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/check_request.schema.json",
|
||||||
|
"title": "CheckRequest",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["subject", "action", "resource"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"subject": {"$ref": "#/$defs/subject_ref"},
|
||||||
|
"action": {"type": "string", "minLength": 1},
|
||||||
|
"resource": {"$ref": "#/$defs/resource_ref"},
|
||||||
|
"context": {"type": "object", "additionalProperties": true},
|
||||||
|
"caring_context": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json"},
|
||||||
|
"policy_version": {"type": "string", "minLength": 1}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"subject_ref": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"type": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/subject_type"},
|
||||||
|
"tenant": {"type": "string", "minLength": 1},
|
||||||
|
"attributes": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resource_ref": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"type": {"type": "string", "minLength": 1},
|
||||||
|
"system": {"type": "string", "minLength": 1},
|
||||||
|
"tenant": {"type": "string", "minLength": 1},
|
||||||
|
"attributes": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
schemas/decision_envelope.schema.json
Normal file
74
schemas/decision_envelope.schema.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/decision_envelope.schema.json",
|
||||||
|
"title": "DecisionEnvelope",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "effect", "resource", "subject", "provenance"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"request_id": {"type": "string", "minLength": 1},
|
||||||
|
"effect": {"enum": ["allow", "deny", "redact", "audit_only", "not_applicable"]},
|
||||||
|
"reason": {"type": "string"},
|
||||||
|
"matched_policy_version": {"type": "string", "minLength": 1},
|
||||||
|
"matched_rule": {"type": "string", "minLength": 1},
|
||||||
|
"resource": {"$ref": "https://flex-auth.netkingdom/schemas/check_request.schema.json#/$defs/resource_ref"},
|
||||||
|
"subject": {"$ref": "https://flex-auth.netkingdom/schemas/check_request.schema.json#/$defs/subject_ref"},
|
||||||
|
"obligations": {"type": "array", "items": {"$ref": "#/$defs/obligation"}},
|
||||||
|
"diagnostics": {"type": "object", "additionalProperties": true},
|
||||||
|
"provenance": {"$ref": "#/$defs/provenance"},
|
||||||
|
"caring": {"$ref": "#/$defs/caring_decision_metadata"}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"obligation": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["type"],
|
||||||
|
"properties": {
|
||||||
|
"type": {"type": "string", "minLength": 1},
|
||||||
|
"parameters": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"provenance": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["evaluator", "mode"],
|
||||||
|
"properties": {
|
||||||
|
"evaluator": {"type": "string", "minLength": 1},
|
||||||
|
"mode": {"type": "string", "minLength": 1},
|
||||||
|
"policy_package": {"type": "string", "minLength": 1},
|
||||||
|
"policy_version": {"type": "string", "minLength": 1},
|
||||||
|
"directory_etag": {"type": "string", "minLength": 1},
|
||||||
|
"decision_time": {"type": "string", "minLength": 1}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"caring_decision_metadata": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["profile"],
|
||||||
|
"properties": {
|
||||||
|
"profile": {"const": "caring-0.4.0-rc2"},
|
||||||
|
"descriptor": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json"},
|
||||||
|
"restrictions_evaluated": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/restriction"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"exposure_modes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/exposure_mode"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"derived_capabilities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/derived_capability"}
|
||||||
|
},
|
||||||
|
"conformance_findings": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/conformance_finding"}
|
||||||
|
},
|
||||||
|
"exposure_event": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/exposure_event"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
schemas/policy_fixture.schema.json
Normal file
33
schemas/policy_fixture.schema.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/policy_fixture.schema.json",
|
||||||
|
"title": "PolicyFixture",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "request", "expect"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"request": {"$ref": "https://flex-auth.netkingdom/schemas/check_request.schema.json"},
|
||||||
|
"expect": {"$ref": "#/$defs/decision_expectation"},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"decision_expectation": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["effect"],
|
||||||
|
"properties": {
|
||||||
|
"effect": {"enum": ["allow", "deny", "redact", "audit_only", "not_applicable"]},
|
||||||
|
"reason": {"type": "string", "minLength": 1},
|
||||||
|
"obligations": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/decision_envelope.schema.json#/$defs/obligation"}
|
||||||
|
},
|
||||||
|
"conformance_findings": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/conformance_finding"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
schemas/policy_package.schema.json
Normal file
68
schemas/policy_package.schema.json
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/policy_package.schema.json",
|
||||||
|
"title": "PolicyPackageMetadata",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "version", "package", "caring"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"name": {"type": "string", "minLength": 1},
|
||||||
|
"version": {"type": "string", "minLength": 1},
|
||||||
|
"status": {"type": "string", "minLength": 1},
|
||||||
|
"package": {"type": "string", "minLength": 1},
|
||||||
|
"caring": {"$ref": "#/$defs/caring_policy_metadata"},
|
||||||
|
"activation": {"type": "object", "additionalProperties": true},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"caring_policy_metadata": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["profile"],
|
||||||
|
"properties": {
|
||||||
|
"profile": {"const": "caring-0.4.0-rc2"},
|
||||||
|
"canonical_roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/canonical_role"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"organization_relations": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/organization_relation"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"scopes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/scope"}
|
||||||
|
},
|
||||||
|
"planes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/plane"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"capabilities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/capability"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"exposure_modes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/exposure_mode"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"conditions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/condition"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"restrictions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/restriction"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
schemas/protected_system_manifest.schema.json
Normal file
69
schemas/protected_system_manifest.schema.json
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/protected_system_manifest.schema.json",
|
||||||
|
"title": "ProtectedSystemManifest",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"name": {"type": "string", "minLength": 1},
|
||||||
|
"description": {"type": "string"},
|
||||||
|
"resource_types": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/resource_type"}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "#/$defs/action"}
|
||||||
|
},
|
||||||
|
"caring_profiles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"const": "caring-0.4.0-rc2"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"resource_type": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["name"],
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string", "minLength": 1},
|
||||||
|
"parent_types": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||||||
|
"scope_level": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/scope_level"},
|
||||||
|
"planes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/plane"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["name"],
|
||||||
|
"properties": {
|
||||||
|
"name": {"type": "string", "minLength": 1},
|
||||||
|
"capabilities": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/capability"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"planes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/plane"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"exposure_modes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/exposure_mode"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
schemas/relationship_fact.schema.json
Normal file
24
schemas/relationship_fact.schema.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/relationship_fact.schema.json",
|
||||||
|
"title": "RelationshipFact",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "subject", "relation", "object"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"system": {"type": "string", "minLength": 1},
|
||||||
|
"subject": {"type": "string", "minLength": 1},
|
||||||
|
"relation": {"type": "string", "minLength": 1},
|
||||||
|
"object": {"type": "string", "minLength": 1},
|
||||||
|
"tenant": {"type": "string", "minLength": 1},
|
||||||
|
"conditions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/condition"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"caring": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json"},
|
||||||
|
"provenance": {"type": "object", "additionalProperties": true},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,11 @@
|
|||||||
"items": {"type": "string", "minLength": 1},
|
"items": {"type": "string", "minLength": 1},
|
||||||
"uniqueItems": true
|
"uniqueItems": true
|
||||||
},
|
},
|
||||||
|
"caring_profile": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional CARING profile identifier used by resource-level descriptors.",
|
||||||
|
"const": "caring-0.4.0-rc2"
|
||||||
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Free-form provenance and contract metadata. Conventions: 'source' (origin description), 'flex_auth_contract' (contract version string, currently 'resource-registration-v0').",
|
"description": "Free-form provenance and contract metadata. Conventions: 'source' (origin description), 'flex_auth_contract' (contract version string, currently 'resource-registration-v0').",
|
||||||
@@ -76,6 +81,10 @@
|
|||||||
"description": "Owner identifier, conventionally 'team:<slug>' or 'user:<slug>'.",
|
"description": "Owner identifier, conventionally 'team:<slug>' or 'user:<slug>'.",
|
||||||
"minLength": 1
|
"minLength": 1
|
||||||
},
|
},
|
||||||
|
"caring": {
|
||||||
|
"description": "Optional CARING descriptor for this resource. Policy packages may require this field for conformance checks.",
|
||||||
|
"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json"
|
||||||
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Free-form attributes that policy packages may consult. Reserved keys may be defined by individual policy packages.",
|
"description": "Free-form attributes that policy packages may consult. Reserved keys may be defined by individual policy packages.",
|
||||||
|
|||||||
68
schemas/subject_manifest.schema.json
Normal file
68
schemas/subject_manifest.schema.json
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://flex-auth.netkingdom/schemas/subject_manifest.schema.json",
|
||||||
|
"title": "SubjectManifest",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"subjects": {"type": "array", "items": {"$ref": "#/$defs/subject"}},
|
||||||
|
"groups": {"type": "array", "items": {"$ref": "#/$defs/group"}},
|
||||||
|
"teams": {"type": "array", "items": {"$ref": "#/$defs/group"}},
|
||||||
|
"tenants": {"type": "array", "items": {"$ref": "#/$defs/tenant"}},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"subject": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id", "type"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"type": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/subject_type"},
|
||||||
|
"display_name": {"type": "string", "minLength": 1},
|
||||||
|
"organization_relation": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/organization_relation"},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json#/$defs/canonical_role"},
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
"groups": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||||||
|
"tenant": {"type": "string", "minLength": 1},
|
||||||
|
"claims": {"type": "object", "additionalProperties": true},
|
||||||
|
"caring_descriptors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json"}
|
||||||
|
},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"display_name": {"type": "string", "minLength": 1},
|
||||||
|
"members": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
||||||
|
"tenant": {"type": "string", "minLength": 1},
|
||||||
|
"caring_descriptors": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {"$ref": "https://flex-auth.netkingdom/schemas/caring_access_descriptor.schema.json"}
|
||||||
|
},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tenant": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["id"],
|
||||||
|
"properties": {
|
||||||
|
"id": {"type": "string", "minLength": 1},
|
||||||
|
"name": {"type": "string", "minLength": 1},
|
||||||
|
"metadata": {"type": "object", "additionalProperties": true}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,7 +67,7 @@ Backends may change later, but these envelopes must stay stable:
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: FLEX-WP-0002-T001
|
id: FLEX-WP-0002-T001
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "534e5251-8529-48fe-8cf8-b3b6bc4ec1f4"
|
state_hub_task_id: "534e5251-8529-48fe-8cf8-b3b6bc4ec1f4"
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user