Access controlled knowledge gateway functionality

This commit is contained in:
2026-05-04 15:00:16 +02:00
parent e87406ac9e
commit d923661852
20 changed files with 1486 additions and 14 deletions

View File

@@ -0,0 +1,173 @@
# 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
```
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
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.

View File

@@ -136,6 +136,12 @@ Protocol interfaces are provided for:
These are contracts for future implementations. They are intentionally light
and do not force the current CLI through a persistent backend.
WP-0009 adds the first concrete `AccessPolicyGateway` implementation:
`LocalLabelPolicyGateway`. It supports labels, trust zones, path rules, enforce
and audit modes, denied-result diagnostics, redaction, and explainable decisions.
Relationship and rule-policy systems remain adapter protocols rather than core
dependencies.
## CLI
Read-only inspection commands:
@@ -145,6 +151,7 @@ mkt backend list --path examples/backends
mkt backend inspect local-sqlite-cache --path examples/backends --require snapshots --require provenance
mkt backend snapshot-id docs/content-references.md
mkt backend refresh-plan docs --state examples/backend-state/snapshot-state.yaml
mkt policy check public-agent query private/doc.md --policy examples/policy/local-label-policy.yaml --path private/doc.md
```
The existing `mkt cache status` remains the lightweight file-manifest change

View File

@@ -36,6 +36,7 @@ framework organizes how Markitect itself exposes and composes capabilities.
| `validator` | schema, contract, section assertion | document/context in, diagnostics out |
| `runtime` | context loader, form state, dynamic rules | document/contract/context in, diagnostics and state out |
| `assessment-runner` | provider-neutral rubric execution | assessment request in, normalized result out |
| `policy-gateway` | local label gateway, future external auth adapters | subject/action/object in, decision or filtered results out |
| `template-engine` | deterministic templates | template/data in, Markdown out |
| `generation-adapter` | provider-neutral assisted generation | request in, generated candidate out |
| `cli-group` | cache, backend, ref, class | command descriptors or registration hook |

View File

@@ -36,12 +36,14 @@ Query indexed snapshots:
```text
mkt cache query 'sections[heading=Decision]' --root .
mkt cache query '$.headings[*].text' --engine jsonpath --root .
mkt cache query 'sections[heading=Decision]' --policy examples/policy/local-label-policy.yaml --subject public-agent
```
Search indexed section/block text:
```text
mkt search SQLite --root .
mkt search SQLite --policy examples/policy/local-label-policy.yaml --subject public-agent
```
Inspect a parsed AST without using the cache:
@@ -90,8 +92,19 @@ This is enough to recover the useful markitect-main idea of keeping parsed
structure available for faster and richer query backends, while keeping the
normal CLI usable without a cache.
## Policy-Aware Retrieval
`mkt cache query` and `mkt search` can run with a local label policy before
results leave the local backend boundary. When `--policy` is supplied, Markitect
extracts labels and trust zones from document frontmatter and applies any path
rules in the policy file. JSON/YAML output includes policy decisions and
diagnostics.
See `docs/access-control-policy-gateway.md` for the policy vocabulary and
adapter boundaries.
## Future Work
Follow-on backend work can now focus on richer dependency extraction from
references, transclusion, and literate chunks; access-controlled query gateways;
and larger-scale memory/context packages.
references, transclusion, and literate chunks; persistent decision logs; and
larger-scale memory/context packages.

View File

@@ -37,7 +37,7 @@ and descriptions mirror the operational view.
| `MKTT-WP-0013` | complete | done | `MKTT-WP-0003`, `MKTT-WP-0004`, `MKTT-WP-0006`, `MKTT-WP-0007`, `MKTT-WP-0010` | Internal extension framework is complete: characterization tests, canonical processing model, descriptors, registries, lifecycle callbacks, query-engine registry, built-in extension catalog, CLI command specs, and authoring guide. |
| `MKTT-WP-0005` | complete | done | `MKTT-WP-0003`, `MKTT-WP-0004` | Runtime context, form state, dynamic rules, workflow integration, and provider-neutral assessment boundary are complete. |
| `MKTT-WP-0011` | complete | done | `MKTT-WP-0003`; task-level triggers: `MKTT-WP-0010-T001`, `MKTT-WP-0010-T005` | Markdown dataflow workflow layer is complete: workflow standard, source collectors, binding model, deterministic steps, assisted boundary, safe outputs, CLI, docs, and examples. |
| `MKTT-WP-0009` | P2 | todo | `MKTT-WP-0006` | Establish access-control gateway before security-sensitive cache/context use. |
| `MKTT-WP-0009` | complete | done | `MKTT-WP-0006` | Access-controlled knowledge gateway is complete: local labels, trust zones, path rules, policy-aware cache query/search, decisions, diagnostics, and external adapter boundaries. |
| `MKTT-WP-0012` | P3 | todo | `MKTT-WP-0004`, `MKTT-WP-0010`, `MKTT-WP-0011` | Future Quarkdown-inspired document function layer: reusable Markdown-native function calls over processors, references, contracts, workflows, and later assisted steps. |
| `MKTT-WP-0008` | P3 | todo | `MKTT-WP-0006`, `MKTT-WP-0007`, `MKTT-WP-0009` | Agent working-memory cache after backend and policy floor are available. |