Skip to content

feat: fleet governance adapter (SPEC-1b-2) — mcpDeny policy + gateway registration - #107

Merged
rz1989s merged 7 commits into
mainfrom
feat/1b-2-fleet-governance-adapter
Sep 3, 2026
Merged

rz1989s merged 7 commits into
mainfrom
feat/1b-2-fleet-governance-adapter

Conversation

@rz1989s

@rz1989s rz1989s commented Sep 3, 2026

Copy link
Copy Markdown
Member

Fleet governance adapter (SPEC-1b-2)

Implements the fleet half of the armory-gateway MCP governance integration per docs/SPEC-1b-2-fleet-governance-adapter.md (relocated into docs/ with this PR): when the (private, unpublished) gateway package is resolvable, fleet registers an MCP governance provider at session start; every MCP call through the gateway then passes fleet's mcpDeny policy before executing. When the gateway is absent — the default for public fleet installs — registration is skipped silently and behavior is unchanged.

What's in the box

  • Version alignment@earendil-works/* deps aligned to ^0.84.4 (vision rider merged separately as subagent tool: failed explicit-model override returns empty output instead of a clean error #26).
  • mcpDeny settings field (src/settings/fleet-settings.ts) — global (~/.pi/agent/fleet/settings.json) + project (<cwd>/.pi/fleet/settings.json, wins per-field); glob metacharacters in entries are rejected at parse time with an actionable warning (warn+drop, valid entries stay enforced).
  • Pure policy matcher (src/governance/mcp-policy.ts) — total function, no I/O: bare server denies every tool on that server; server__tool denies one exact tool (exact-tool match takes precedence over a bare-server entry regardless of deny-list order); absent/empty list allows; malformed entries can never match (exact lookups only, no entry parsing at match time). Deny reason: denied by armory-fleet mcpDeny policy: matched "<entry>".
  • Gateway adapter (src/governance/gateway-adapter.ts) — guarded dynamic import (the private specifier never appears in a static import, so public installs can't break at link time); identity-based provider (only server/tool enter the matcher); deny list re-read fresh per call, so policy edits take effect without re-registration.
  • session_start wiring (src/index.ts) — registration reuses the session's own FleetSettingsStore (cwd-correct project path), idempotent under the gateway's replace-semantics.
  • Dev link + CIfile:../armory-gateway devDependency for contract tests; CI gains a sibling-clone step (token-authenticated) placed before pnpm install --frozen-lockfile, no continue-on-error.
  • Docs — README "MCP governance" section (wired behavior only); SPEC + PLAN relocated into docs/ with the two as-built deviations folded in (glob-metachar rejection, exact-tool precedence).

Acceptance (SPEC §13)

  • Full fleet gate green on ^0.84.4: pnpm typecheck && pnpm test:run (this repo's actual gate); new test files flat in test/ so the glob picks them up.
  • Contract tests prove: registration fires through the REAL gateway module; deny/allow routing; per-call freshness; duplicate-copy convergence via the shared Symbol.for store; absent-gateway silent skip.
  • No static top-level import of @getpipher/armory-gateway anywhere in fleet src/ — the only occurrence is the guarded import() inside the adapter.
  • README claims only wired behavior; mcpDeny documented with examples.

Verification

  • Full gate green at HEAD (f16269a): pnpm typecheck clean, pnpm test:run 856/856 pass, 0 fail (849 prior + 6 gateway contract tests + 1 wiring-shape test).
  • All 6 contract tests pass against the real linked gateway module (file:../armory-gateway, skipped 0 locally) — including duplicate-instance convergence through the cache-busted second module URL.
  • CI now includes the armory-gateway sibling-clone job (SIBLINGS_PAT, already set on the repo) required by the committed file: devDependency under --frozen-lockfile.

Deliberately deferred (named in SPEC §14–15, durable record)

  • ARMORY_AGENT_ID/ARMORY_TASK_ID env emission — no reading code path exists today (pi children are in-process noExtensions sessions; claude children never load the gateway). Revival gated on child MCP access + a concurrency-safe context mechanism.
  • Cost-sink registration — fleet has no per-MCP-call accounting surface yet; write-only plumbing otherwise.
  • Gateway publish/graduation, peer-dependency placement, richer per-call policy surfaces — each named with revival conditions in the spec.

@rz1989s
rz1989s merged commit a4b33e4 into main Sep 3, 2026
1 check passed
@rz1989s
rz1989s deleted the feat/1b-2-fleet-governance-adapter branch September 3, 2026 00:30
rz1989s added a commit that referenced this pull request Sep 3, 2026
Retire the superseded vision 0.5.2 pnpm patch (0.5.3 shipped with the
lib-types fix; drops pnpm-workspace.yaml + patches/ riding the branch).
Take main's @earendil-works/* ^0.84.4 alignment and the armory-gateway
dev file: link from the governance adapter work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant