generated from coulomb/repo-seed
218 lines
6.6 KiB
Markdown
218 lines
6.6 KiB
Markdown
# Access-Controlled Knowledge Gateway
|
|
|
|
Date: 2026-05-04
|
|
|
|
## Purpose
|
|
|
|
The policy gateway adds an explicit boundary before cached query, search, and
|
|
future context-package results leave a backend. It starts with a local label
|
|
policy and keeps room for more rigid authorization systems later.
|
|
|
|
This layer does not make Markitect a full identity platform. Core Markitect
|
|
answers a narrower question:
|
|
|
|
```text
|
|
subject + action + object + context -> policy decision
|
|
```
|
|
|
|
Backend and workflow code can then filter, redact, log, and explain results
|
|
using the same decision envelope.
|
|
|
|
## Access-Control Ladder
|
|
|
|
The intended progression is:
|
|
|
|
| Level | Mode | Purpose |
|
|
| --- | --- | --- |
|
|
| 1 | Labels and trust zones | Local labs, prototypes, and agent context safety. |
|
|
| 2 | Path/file ACLs | Repository-local restrictions and team boundaries. |
|
|
| 3 | Relationship policies | Zanzibar/OpenFGA/SpiceDB-style subject-object relations. |
|
|
| 4 | Attribute/rule policies | OPA/Rego, Cedar, and policy-as-data engines. |
|
|
| 5 | External policy services | Organization identity, audit, and authorization systems. |
|
|
|
|
WP-0009 implements levels 1 and 2 directly and defines adapter boundaries for
|
|
levels 3 and 4.
|
|
|
|
## Local Label Policy
|
|
|
|
Local policy files are YAML:
|
|
|
|
```yaml
|
|
id: local-label-policy
|
|
mode: enforce
|
|
default_labels: [public]
|
|
default_subject: public-agent
|
|
subjects:
|
|
public-agent:
|
|
allowed_labels: [public]
|
|
trust_zones: [public]
|
|
internal-agent:
|
|
allowed_labels: [public, internal]
|
|
trust_zones: [public, internal]
|
|
path_rules:
|
|
- id: private-path
|
|
pattern: private/**
|
|
labels: [internal]
|
|
trust_zone: internal
|
|
```
|
|
|
|
Policy modes:
|
|
|
|
- `off`: allow every result and emit allow decisions.
|
|
- `audit`: keep results but mark decisions that would have been denied.
|
|
- `enforce`: deny or redact results before they leave the boundary.
|
|
|
|
Denied behavior:
|
|
|
|
- `on_denied: drop` removes denied results. This is the default.
|
|
- `on_denied: redact` keeps the envelope but replaces text and value.
|
|
|
|
Object labels can come from document frontmatter, policy metadata, or path
|
|
rules. Supported frontmatter shapes:
|
|
|
|
```yaml
|
|
---
|
|
labels: [internal]
|
|
policy:
|
|
labels: [internal]
|
|
trust_zone: internal
|
|
---
|
|
```
|
|
|
|
Path rules augment frontmatter labels. This lets a repository declare that
|
|
everything under `private/**` is internal even if an individual document forgets
|
|
its frontmatter label.
|
|
|
|
## CLI
|
|
|
|
Check one decision:
|
|
|
|
```text
|
|
mkt policy check public-agent query private/doc.md \
|
|
--policy examples/policy/local-label-policy.yaml \
|
|
--path private/doc.md
|
|
```
|
|
|
|
Filter local FTS search results:
|
|
|
|
```text
|
|
mkt search Knowledge \
|
|
--policy examples/policy/local-label-policy.yaml \
|
|
--subject public-agent
|
|
```
|
|
|
|
Filter indexed query results:
|
|
|
|
```text
|
|
mkt cache query 'sections[heading=Decision]' \
|
|
--policy examples/policy/local-label-policy.yaml \
|
|
--subject public-agent
|
|
```
|
|
|
|
Map NetKingdom/key-cape-style claims into a Markitect policy subject:
|
|
|
|
```text
|
|
mkt policy subject examples/policy/netkingdom-claims.yaml \
|
|
--policy-map examples/policy/enterprise-policy-map.yaml
|
|
```
|
|
|
|
Inspect a Markitect resource manifest intended for flex-auth registration:
|
|
|
|
```text
|
|
mkt policy resource-manifest examples/policy/flex-auth-resource-manifest.yaml
|
|
```
|
|
|
|
JSON and YAML outputs include:
|
|
|
|
- `policy`: mode, subject, action, allowed, denied, redacted, audit counts
|
|
- `policy_decisions`: per-result decisions with stable ids and reasons
|
|
- `diagnostics`: denied/redacted result diagnostics
|
|
|
|
Text output shows a compact policy summary before the filtered matches.
|
|
|
|
## Decision Logs
|
|
|
|
Every local decision contains:
|
|
|
|
- stable `decision_id`
|
|
- subject
|
|
- action
|
|
- object id
|
|
- effect: `allow`, `deny`, `redact`, or `audit_denied`
|
|
- reason
|
|
- mode
|
|
- rule id
|
|
- labels
|
|
- trust zone
|
|
- metadata, including object path and policy id
|
|
|
|
`LocalLabelPolicyGateway.explain_decision(decision_id)` returns a decision made
|
|
by the current gateway instance. Persistent decision logs are intentionally left
|
|
to future backend storage.
|
|
|
|
## Adapter Boundaries
|
|
|
|
Enterprise IAM integration is covered in
|
|
`docs/enterprise-access-control-integration.md`. In that architecture,
|
|
Markitect is the policy enforcement point for Markdown knowledge results, while
|
|
NetKingdom/key-cape-compatible OIDC supplies identity claims and external
|
|
policy engines can act as policy decision points.
|
|
|
|
Identity and directory integration use these provider-neutral boundaries:
|
|
|
|
- `IdentityClaimsAdapter` validates OIDC/JWT/SAML material and returns
|
|
normalized `EnterpriseIdentity`.
|
|
- `DirectoryGroupResolver` resolves group overage or stale directory claims
|
|
through SCIM/Graph/LDAP/Keycloak-style adapters.
|
|
- `EnterprisePolicyMapper` maps canonical enterprise roles, scopes, and groups
|
|
to `PolicySubject` labels, trust zones, and allowed actions.
|
|
- `DecisionLogStore` persists durable audit records for policy decisions.
|
|
|
|
The Markitect-side enterprise helpers provide deterministic local
|
|
implementations:
|
|
|
|
- `NetKingdomIdentityClaimsAdapter` validates required IAM-profile claims,
|
|
issuer, audience, token lifetime, local-production issuer safety, roles, and
|
|
scopes for trusted claims or explicit JWT fixtures.
|
|
- `StaticDirectoryGroupResolver` records group overage/freshness for tests and
|
|
development.
|
|
- `EnterprisePolicyMap` and `LocalEnterprisePolicyMapper` translate groups,
|
|
roles, and scopes into `PolicySubject` labels, trust zones, and actions.
|
|
- `FlexAuthResourceManifest` describes Markitect knowledge resources that a
|
|
future flex-auth service can register.
|
|
- `LocalDecisionLogStore` is a JSONL development sink; durable enterprise audit
|
|
remains flex-auth scope.
|
|
|
|
Relationship policies use `RelationshipPolicyAdapter`:
|
|
|
|
```text
|
|
RelationshipPolicyRequest(subject, relation, object_id, namespace, context)
|
|
-> PolicyDecision
|
|
```
|
|
|
|
This is the attachment point for Zanzibar/OpenFGA/SpiceDB-style systems.
|
|
|
|
Rule policies use `RulePolicyAdapter`:
|
|
|
|
```text
|
|
RulePolicyRequest(subject, action, object, context, policy_id)
|
|
-> PolicyDecision
|
|
```
|
|
|
|
This is the attachment point for OPA/Rego, Cedar, or other
|
|
attribute/rule-based systems.
|
|
|
|
Adapters must return the same `PolicyDecision` shape as the local label
|
|
gateway. That keeps query filtering, diagnostics, provenance, and future
|
|
context-package filtering independent from the concrete policy engine.
|
|
|
|
## Extension Fit
|
|
|
|
The local gateway is registered as `policy.local-label`. It is an internal
|
|
extension with no network dependency. Backends and workflows can request the
|
|
`policy` or `policy_filter` capability without importing an external service.
|
|
|
|
The design intentionally stays close to Markdown: labels can live in document
|
|
frontmatter, path rules live in YAML, and external authorization languages are
|
|
extensions rather than replacements for the core contract.
|