qonto-assistant/docs/operator-runbook.md

191 lines
4.5 KiB
Markdown
Raw Normal View History

# Qonto Assistant Operator Runbook
## What this Phase 1 service does
`qonto-assistant` is the read-only REST surface for governed Qonto access.
Phase 1 ships:
- policy-gated `GET /v1/accounts`
- policy-gated `GET /v1/transactions`
- policy-gated `GET /v1/snapshot`
- structured audit events without secrets
- env-backed or OpenBao-CLI-backed credential loading
Spend, transfer, card, invoicing, payment-link, and other volume-cost actions
remain denied by policy.
## Preferred local workflow
If `make` and `python3 -m venv` are available:
```bash
make install-dev
make test
make run
```
The API then listens on `http://127.0.0.1:8080`.
## Verified fallback on this workstation
This workstation currently lacks:
- `make`
- `python3 -m venv` support (`ensurepip` missing)
- `python3 -m pip`
Use an existing fleet virtualenv that already contains FastAPI/httpx/pytest:
```bash
PYTHONPATH=src ../state-hub/.venv/bin/python -m pytest
python3 -m compileall src tests
```
This fallback was used to verify the current implementation.
## Credential sources
### Option A: env-injected credentials
Provide either:
- `API_USER` + `API_KEY`
- or `QONTO_ORGANIZATION_ID` + `QONTO_API_KEY`
Example:
```bash
export API_USER='...'
export API_KEY='...'
```
### Option B: OpenBao CLI fetch inside the service
Set:
```bash
export QONTO_CREDENTIAL_SOURCE=bao-cli
export QONTO_OPENBAO_PATH=tenants/binky/qonto-api
export QONTO_OPENBAO_COMMAND=bao
```
The service then shells out to `bao kv get -field=...` and caches the
credentials in memory for a short TTL.
## Start the API
Preferred:
```bash
make run
```
Fallback:
```bash
PYTHONPATH=src ../state-hub/.venv/bin/python -m qonto_assistant.main
```
## Fixture-backed local mode
For local smoke work without real bank credentials:
```bash
export QONTO_FIXTURE_DIR=tests/fixtures/qonto
PYTHONPATH=src ../state-hub/.venv/bin/python -m qonto_assistant.main
```
In this mode the service serves canned Qonto organization and transaction
payloads from `tests/fixtures/qonto/`.
## One-command HTTP smoke
```bash
../state-hub/.venv/bin/python scripts/smoke_rest_api.py \
--python ../state-hub/.venv/bin/python
```
This starts the service on a random local port against the fixture payloads,
checks `/v1/health`, `/v1/accounts`, a recent `31`-day snapshot, and a wider
`90`-day cost-review snapshot, then shuts the process down.
## Example calls
Minimal local call:
```bash
python3 - <<'PY'
import json
import urllib.request
req = urllib.request.Request(
"http://127.0.0.1:8080/v1/accounts",
headers={"X-Actor-ID": "local-operator", "X-Tenant-ID": "binky"},
)
with urllib.request.urlopen(req, timeout=10) as resp:
print(json.dumps(json.load(resp), indent=2))
PY
```
Transactions view:
```bash
python3 - <<'PY'
import json
import urllib.request
req = urllib.request.Request(
"http://127.0.0.1:8080/v1/transactions?page_size=50&window_days=31",
headers={"X-Actor-ID": "finance-steward", "X-Tenant-ID": "binky"},
)
with urllib.request.urlopen(req, timeout=10) as resp:
print(json.dumps(json.load(resp), indent=2))
PY
```
Snapshot for CostRunRate refresh:
```bash
python3 - <<'PY'
import json
import urllib.request
req = urllib.request.Request(
"http://127.0.0.1:8080/v1/snapshot?window_days=90&page_size=50",
headers={"X-Actor-ID": "finance-steward", "X-Tenant-ID": "binky"},
)
with urllib.request.urlopen(req, timeout=10) as resp:
print(json.dumps(json.load(resp), indent=2))
PY
```
Use `window_days=31` for a recent-activity view. Use `window_days=90` or `93`
when recurring fixed-cost hints are required.
## MCP surface
Phase 2 mounts a streamable-HTTP MCP adapter at `/mcp` on this same process,
sharing the policy kernel and audit layer above. See
`docs/mcp-integration.md` for the tool catalog, the auth model
(`QONTO_ASSISTANT_MCP_TOKEN`), and the shared client config snippet.
## CostRunRate refresh path
`binky-control` should consume `GET /v1/snapshot` and extract:
- redacted organization/account summary
- recent transactions
- recurring debit hints for fixed-cost review
The repo does not write directly into `binky-control/finance/CostRunRate.md`.
That consumer-side write remains outside this repo.
## Safety notes
- Never print or commit `API_KEY`.
- Prefer `X-Tenant-ID: binky` explicitly even in single-tenant dogfood.
- Audit output is metadata-only; account identifiers stay redacted by default.
- The service supports a `bearer` auth mode for future upstream evolution, but
the current dogfood path remains `legacy_api_key` because that is the proven
BINKY-WP-0005 header mode.