ontoref-derive: #[onto_mcp_tool] attribute macro registers MCP tool unit-structs in
the catalog at link time via inventory::submit!; annotated item is emitted unchanged,
ToolBase/AsyncTool impls stay on the struct. All 34 tools migrated from manual wiring
(net +5: ontoref_list_projects, ontoref_search, ontoref_describe,
ontoref_list_ontology_extensions, ontoref_get_ontology_extension).
validate modes (ADR-018): reads level_hierarchy from workflow.ncl and checks every
.ncl mode for level declared, strategy declared, delegate chain coherent, compose
extends valid. mode resolve <id> shows which hierarchy level handles a mode and why.
--self-test generates synthetic fixtures in a temp dir for CI smoke-testing.
validate run-cargo: two-step Cargo.toml resolution — workspace layout first
(crates/<check.crate>/Cargo.toml), single-crate fallback by package name or repo
basename. Lets the same ADR constraint shape apply to workspace and single-crate repos.
ontology/schemas/manifest.ncl: registry_topology_type contract — multi-registry
coordination, push targets, participant scopes, per-namespace capability.
reflection/requirements/base.ncl: oras ≥1.2.0, cosign ≥2.0.0, sops ≥3.9.0, age
≥1.1.0, restic declared as Hard/Soft requirements with version_min, check_cmd, and
install_hint (ADR-017 toolchain surface).
ADR-019: per-file recipient routing for tenant isolation without multi-vault. Schema
additions: sops.recipient_groups + sops.recipient_rules in ontoref-project.ncl.
secrets-bootstrap generates .sops.yaml from project.ncl in declarative mode. Three
new secrets-audit checks: recipient-routing-coherent, recipient-routing-coverage,
no-multi-vault. Adoption templates: single-team/, multi-tenant/, agent-first/.
Integration templates: domain-producer/, mode-producer/, mode-consumer/.
UI: project_picker surfaces registry badge (⟳ participant) and vault badge
(⛁ vault_id · N, green=declarative / amber=legacy) per project card. Expanded panel
adds collapsible Registry section with namespace, endpoint, and push/pull capability.
manage.html gains Runtime Services card — MCP and GraphQL toggleable without restart
via HTMX POST /ui/manage/services/{service}/toggle.
describe.nu: capabilities JSON includes registry_topology and vault_state per project.
sync.nu: drift check extended to detect //! absence on newly registered crates.
qa.ncl: six entries — credential-vault-best-practice (layered data-flow diagram),
credential-vault-templates (paths A/B/C), credential-vault-troubleshooting (15 named
errors), integration-what-and-why (ADR-042 OCI federation), integration-how-to-implement,
integration-troubleshooting.
on+re: core.ncl + manifest.ncl updated to reflect OCI, MCP, and mode-hierarchy nodes.
Deleted stale presentation assets (2026-02 slides + voice notes).
136 lines
7.2 KiB
Text
136 lines
7.2 KiB
Text
{
|
|
id = "0018",
|
|
slug = "recipient-routing",
|
|
description = "Adopt per-file recipient routing for tenant isolation (ADR-019). Optional: only projects requiring multi-tenant credential separation need to apply. Adds recipient_groups + recipient_rules to project.ncl::sops; bootstrap then generates <vault_dir>/.sops.yaml from declarations and sops encrypts each file with the union of declared groups.",
|
|
|
|
# Adoption is opt-in. Projects without multi-tenant needs MAY skip.
|
|
# Mark as 'applied' when the project explicitly chose a path:
|
|
# - Path A (single-team / legacy): project.ncl has sops but no recipient_groups
|
|
# - Path B/C: project.ncl declares both recipient_groups and recipient_rules
|
|
# Either path satisfies the check below.
|
|
check = {
|
|
tag = "Grep",
|
|
paths = [".ontoref/project.ncl"],
|
|
pattern = "sops",
|
|
},
|
|
|
|
instructions = m%"
|
|
## Per-file recipient routing for tenant isolation (migration 0018, ADR-019)
|
|
|
|
This migration is **OPTIONAL**. Apply only if your project requires multi-tenant
|
|
credential separation, AI-agent restricted access, or developer/admin role mixing
|
|
that the single-recipient-set model from migration 0016 cannot express.
|
|
|
|
### Decide your path
|
|
|
|
┌────────────────────────────────────────────────────────────────────┐
|
|
│ Will multiple actors (clients/agents/teams) operate this project? │
|
|
└─────────────────────────────────┬──────────────────────────────────┘
|
|
│
|
|
┌─────── No ──────┴─────── Yes ──────────────┐
|
|
▼ ▼
|
|
┌──────────────────────────┐ ┌──────────────────────────────────┐
|
|
│ Path A — Single team │ │ Will those actors need DISTINCT │
|
|
│ Migration 0016 sufficient│ │ credential sets per actor? │
|
|
│ — no further action │ └──────────────────┬───────────────┘
|
|
└──────────────────────────┘ │
|
|
┌─────── No ────────────┴──── Yes ──────┐
|
|
▼ ▼
|
|
┌─────────────────────────────────┐ ┌────────────────────────┐
|
|
│ Stay with migration 0016 │ │ Path B/C: this 0018 │
|
|
│ Re-evaluate when needs change │ │ Apply steps below │
|
|
└──────────────────────────────────┘ └────────────────────────┘
|
|
|
|
### Step 1 — Templates
|
|
|
|
Three templates ship under install/resources/templates/sops/:
|
|
|
|
single-team/ — Path A reference (no migration needed)
|
|
multi-tenant/ — Path B reference (clients/services/teams isolated)
|
|
agent-first/ — Path C reference (AI agent has narrow read-only access)
|
|
|
|
Pick one, copy its project.ncl.snippet and manifest.ncl.snippet into the
|
|
matching files in your project. Adapt placeholders to your tenancy.
|
|
|
|
### Step 2 — Declare groups and rules
|
|
|
|
Inside .ontoref/project.ncl::sops, add:
|
|
|
|
recipient_groups = {
|
|
admin = [\"age1...\"], # admins (full access)
|
|
ops = [\"age1...\"], # ops/observability
|
|
clientA = [\"age1clientA-lead...\"], # one group per client/team/agent
|
|
clientB = [\"age1clientB-lead...\"],
|
|
agents = [\"age1agent...\"], # AI agents (typically RO)
|
|
},
|
|
recipient_rules = [
|
|
{ path = \"access\\\\.sops\\\\.yaml$\", groups = [\"admin\", \"ops\"] },
|
|
{ path = \"registry/clientA-.*\\\\.sops\\\\.yaml$\", groups = [\"admin\", \"clientA\"] },
|
|
{ path = \"registry/clientB-.*\\\\.sops\\\\.yaml$\", groups = [\"admin\", \"clientB\"] },
|
|
{ path = \"registry/agent-readonly\\\\.sops\\\\.yaml$\", groups = [\"admin\", \"agents\"] },
|
|
],
|
|
|
|
### Step 3 — Add per-tenant RegistryEntry items in manifest.ncl
|
|
|
|
For each rule, declare a corresponding RegistryEntry whose credential_sops
|
|
matches the rule's path pattern:
|
|
|
|
m.make_registry_entry {
|
|
id = \"clientA\",
|
|
endpoint = \"<your-zot-host>\",
|
|
credential_sops = \"registry/clientA-ro.sops.yaml\",
|
|
credential_sops_rw = \"registry/clientA-rw.sops.yaml\",
|
|
namespaces = {
|
|
own = [\"domains/clientA/\", \"modes/clientA/\"],
|
|
prefixes = [\"domains/clientA/\"],
|
|
},
|
|
}
|
|
|
|
### Step 4 — Bootstrap or migrate
|
|
|
|
NEW PROJECT ore secrets bootstrap
|
|
(generates <vault_dir>/.sops.yaml + access.sops.yaml,
|
|
skips default registry/ro|rw.sops.yaml — operator
|
|
populates per-tenant files via 'ore secrets open')
|
|
|
|
EXISTING PROJECT ore secrets rekey
|
|
(regenerates <vault_dir>/.sops.yaml from new declarations,
|
|
re-encrypts every existing *.sops.yaml with the matching rule)
|
|
|
|
### Step 5 — Verify
|
|
|
|
ore secrets describe # see groups, rules, recipients per file
|
|
ore secrets audit # 6 checks pass:
|
|
# bootstrap-credentials OK
|
|
# no-credential-env OK
|
|
# multi-recipient-mandatory OK
|
|
# recipient-routing-coherent OK
|
|
# recipient-routing-coverage OK
|
|
# no-multi-vault OK
|
|
|
|
### What does NOT change
|
|
|
|
- vault_id remains one per project (multi-vault is explicitly out of scope)
|
|
- Master .kage continues per-developer
|
|
- Restic/Kopia repo and OCI artifact remain unique per project
|
|
- Vault lock semantics unchanged
|
|
- All ADR-017 invariants preserved
|
|
|
|
### When to escalate to multi-vault (not implemented)
|
|
|
|
- Hard isolation: separate master keys per environment (prod vs staging)
|
|
- Hard isolation: separate restic repos to prevent any cross-pull visibility
|
|
- Compliance grade: regulator requires environments cannot share vault
|
|
contents even when encrypted
|
|
|
|
When such a case appears, capture it in a new ADR superseding/extending
|
|
ADR-019 before adopting multi-vault.
|
|
|
|
### References
|
|
|
|
ADR-019 decision + 6 checkable constraints
|
|
reflection/qa.ncl::credential-vault-templates three-path overview
|
|
install/resources/templates/sops/ ready-to-copy snippets
|
|
reflection/migrations/0016 Layer 0/1/2 prerequisites
|
|
"%,
|
|
}
|