Files
markitect-tool/docs/access-control-policy-gateway.md

5.5 KiB

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:

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:

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:

---
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:

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:

mkt search Knowledge \
  --policy examples/policy/local-label-policy.yaml \
  --subject public-agent

Filter indexed query results:

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

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.

Relationship policies use RelationshipPolicyAdapter:

RelationshipPolicyRequest(subject, relation, object_id, namespace, context)
  -> PolicyDecision

This is the attachment point for Zanzibar/OpenFGA/SpiceDB-style systems.

Rule policies use RulePolicyAdapter:

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.