Replaces the config-only QONTO_ASSISTANT_ENFORCE_SCOPE cached-claim check with two live-checked facts, per docs/SecurityPractice.md #4: 1. flex-auth POST /v1/check on finance.qonto.read for the calling actor/tenant (FlexAuthCheckClient, modeled on tenant-engine's own client for the same API). Registration lives in the flex-auth repo (examples/qonto-assistant/) -- rules + embedded tests verified with flex-auth test-policy/load-registry/check, and a live flex-auth serve hit by this exact client over real HTTP (not a mock). 2. tenant-engine's live capability-role lookup (GET /tenants/{id}/roles/live), denying unless the tenant currently holds one of QONTO_TENANT_ENGINE_REQUIRED_ROLES (default VEN,CUS) -- optional and additive to the flex-auth check. Both clients fail closed by construction (unreachable/malformed/non-2xx all deny, never grant), matching FlexAuthCheckClient's existing fail-closed philosophy elsewhere in the fleet. LiveAuthorizationGate combines both and is wired into CapabilityService._execute ahead of the internal policy kernel; off by default (no QONTO_FLEX_AUTH_URL set) so existing deployments are unaffected until configured. Verified beyond mocked unit tests: ran a real `flex-auth serve` loaded with the registered policy, and a real tenant-engine instance seeded with a VEN grant for tenant:friendly:binky, and exercised this repo's actual FlexAuthCheckClient/TenantEngineClient/LiveAuthorizationGate against both live processes over real HTTP -- allow for the correct tenant, live_authz_denied for a mismatched tenant. 28 new unit tests (flex_auth_client, tenant_engine_client, live_authorization_gate + CapabilityService integration). Full suite -> 80 passed; REST/MCP smokes and compileall still clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| docs | ||
| research | ||
| scripts | ||
| specs | ||
| src/qonto_assistant | ||
| tests | ||
| workplans | ||
| .custodian-brief.md | ||
| .gitignore | ||
| .repo-classification.yaml | ||
| AGENTS.md | ||
| INTENT.md | ||
| LICENSE | ||
| Makefile | ||
| pyproject.toml | ||
| README.md | ||
| SCOPE.md | ||
| WORK-RECORDS.md | ||
qonto-assistant
Policy-governed Qonto domain API and MCP assistant for Binky (and later multi-tenant dogfood).
One choke point for bank access across every coding agent and harness. Clients never hold the Qonto API key. v1 policy: read for awareness only — no spend, no volume-cost actions.
Start here
| Doc | What |
|---|---|
INTENT.md |
Why this exists; boundaries |
specs/ArchitectureBlueprint.md |
Architecture, phases, policy model |
research/2026-07-21-mcp-gateway-and-governed-domain-assistant.md |
External + internal research |
docs/operator-runbook.md |
How to run and verify Phase 1 (REST) |
docs/mcp-integration.md |
How to run and verify Phase 2 (MCP) |
Status
Phase 1 runtime is implemented:
- Python 3.12 service under
src/qonto_assistant/ - default-deny YAML policy
- Qonto read-only client (
organization,transactions) - REST endpoints:
/v1/health,/v1/accounts,/v1/transactions,/v1/snapshot - audit metadata, rate limiting, concurrency bounds, tests
Phase 2 (MCP surface, workplans/QONTO-WP-0003-mcp-surface.md) is
finished: a streamable-HTTP MCP adapter is mounted at /mcp on the same
capability core and policy kernel as REST — proven identical by test, not
just by construction (tests/test_policy.py, tests/test_audit_parity.py)
— with tools qonto_org_summary, qonto_list_transactions, and
qonto_cost_run_rate_hints. The endpoint is gated by a shared-secret bearer
token (QONTO_ASSISTANT_MCP_TOKEN); see docs/mcp-integration.md for the
auth model, its explicit gap vs. the OIDC/workload target (no issuer exists
in this fleet yet), and the shared multi-harness client config snippet. The
finance-qonto-read agent-harness tool profile is documented (qonto-assistant
side) but not yet registered in agent-harness itself — separate repo,
separate workplan.
Current verification:
PYTHONPATH=src ../state-hub/.venv/bin/python -m pytest→31 passedpython3 -m compileall src tests scripts../state-hub/.venv/bin/python scripts/smoke_rest_api.py --python ../state-hub/.venv/bin/python../state-hub/.venv/bin/python scripts/smoke_mcp.py --python ../state-hub/.venv/bin/python
Local fixture-backed smoke mode is available through QONTO_FIXTURE_DIR, so the
service can be exercised without real Qonto credentials. The REST smoke checks
both a 31-day recent snapshot and a 90-day recurring-cost snapshot; the MCP
smoke additionally exercises the bearer-token auth gate and an out-of-catalog
tool deny path.
Phase 3 (flex-auth resource finance.qonto.read, graduated quotas,
redaction profiles) is not started — see workplans/QONTO-WP-0003-mcp-surface.md
closure notes for the seed.
Normal local workflow, when toolchain support exists:
make install-dev
make test
make run
Related
- OpenBao lane:
tenants/binky/qonto-api(ops-wardenbinky-qonto-api) - First pull / CostRunRate:
binky-controlBINKY-WP-0005