diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..c7f9b07 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,130 @@ +# m2-market configuration reference + +Covers the CLI's local config/state files (per machine/operator) and the +`m2-ledger` service's environment variables. Sourced from +`specs/001-market-first-wedge/contracts/cli.md`, +`specs/001-market-first-wedge/contracts/ledger-api.md`, and +`specs/001-market-first-wedge/data-model.md` (§Operator, §InstallState). + +## 1. `~/.m2-market/config.toml` + +Per-machine CLI config (contracts/cli.md). One file per operator/machine — +`operator_id` and API keys are provisioned per machine, not shared (data-model.md +§Operator: "CLI config carries `operator_id` + API keys per machine"). + +```toml +# ~/.m2-market/config.toml +# Required: identifies this machine/operator for all ledger + catalog calls. +operator_id = "op_nasr" + +# Required: tenant scope for catalog search/index filtering. +tenant = "machine-machine" + +# m2-ledger HTTP API (contracts/ledger-api.md). CLI uses a "service"-class key +# (see §4 below) — never an admin key. +ledger_url = "http://m2-ledger:8000" +ledger_api_key = "svc_xxxxxxxxxxxxxxxxxxxx" + +# Catalog semantic search / indexer backend. +memory_api_url = "https://memory.machinemachine.ai" +memory_api_key = "mem_xxxxxxxxxxxxxxxxxxxx" + +# Registry (Forgejo) — used by `m2-market publish` to push branches/open listing PRs. +forgejo_url = "https://git.machinemachine.ai" +forgejo_token = "frg_xxxxxxxxxxxxxxxxxxxx" + +# Which AdapterProtocol implementation `install` uses to plan/apply/verify bundles +# (contracts/apply-adapter.md). "local" is the only adapter in v1. +apply_adapter = "local" +``` + +Notes: + +- All four `*_url` + `*_key`/`*_token` pairs are required for `install`/`publish`/`search` + to function; `wallet`/`show` need at least `ledger_url`+`ledger_api_key`. +- **File permissions must be `0600`** — this file holds live API keys. Treat it the + same as an SSH private key (see §5 Security rules). +- No secrets are ever baked into images or repos; this file is the runtime injection + point (constitution VI). + +## 2. `~/.m2-market/state.json` + +Per-machine install ledger for the local `AdapterProtocol` — the idempotency and +re-apply guard `install` checks before re-running work (Story 1 AC-3: re-run with an +existing grant + applied state is a no-op, exit 0). Shape defined in +`data-model.md` §InstallState; this is the file `m2core_sync` will merge into once +fedlearn rails land. + +Shape: `{installs: {listing_id: {version, grant_id, ts, changeset_hash, status}}}`, +where `status` is one of `applied | failed | rolled_back`. + +Example: + +```json +{ + "installs": { + "sol_pdf_export_v1": { + "version": "1.2.0", + "grant_id": "grant_8f3a1c", + "ts": "2026-06-30T14:02:11Z", + "changeset_hash": "sha256:9c1f...e42b", + "status": "applied" + } + } +} +``` + +## 3. `m2-ledger` service environment variables + +`m2-ledger` is deployed as a Coolify app on the `coolify` network (constitution VI — +no secrets in the image; all of the below are injected at runtime as env vars, never +committed). + +| Var | Purpose | Default | Notes | +|---|---|---|---| +| `LEDGER_DB_PATH` | Path to the SQLite tx-log database file. | — (required) | Single source of truth; balances are always derived by folding this log (data-model.md §Wallet), never a separately-writable balance table. | +| `LEDGER_SERVICE_KEYS` | Comma-separated list of valid `service`-class API keys. | — (required) | Accepted via `X-API-Key` header for service endpoints (§4). | +| `LEDGER_ADMIN_KEYS` | Comma-separated list of valid `admin`-class API keys. | — (required) | Accepted via `X-API-Key` header for admin endpoints (§4). Keep this set small; these mint credit and can trigger snapshots. | +| `LEDGER_PLATFORM_PCT` | Default platform cut applied on `/tx/install` when the request body omits `platform_pct`. | `0.10` | **UNCONFIRMED** — data-model.md/ledger-api.md flag this as a default pending confirmation, not a locked value. | +| `LEDGER_STARTER_GRANT` | Default credit amount minted by `/grant/starter` when the request body omits `amount`. | `100` | **UNCONFIRMED** — same flag as above; ledger-api.md invariant 5 lists both defaults as config-not-code. | +| `REGISTRY_REPO_URL` | Forgejo repo URL (`m2/market-registry`) that `/snapshot` commits `audit/YYYY-MM-DD.json` into. | — (required) | Used by both the admin-triggered snapshot and the daily cron snapshot. | +| `FORGEJO_TOKEN` | Forgejo API token used to author the snapshot commit above. | — (required) | Scope to the single registry repo; do not reuse the CLI's `forgejo_token` from config.toml. | + +## 4. Key classes: service vs admin + +Two API key classes, both passed via the `X-API-Key` header (contracts/ledger-api.md). +Callers: the CLI, the Store, and the indexer use `service` keys; only ledger operators +(humans/admin tooling) hold `admin` keys. + +| Endpoint | Key class | +|---|---| +| `GET /health` | none | +| `GET /balance/{operator_id}` | service | +| `POST /tx/install` | service | +| `POST /tx/refund` | service | +| `GET /tx?operator_id=&reason=&since=` | service | +| `GET /license/{operator_id}/{listing_id}` | service | +| `POST /grant/starter` | admin | +| `POST /snapshot` | admin (also runs unauthenticated via daily cron, in-process) | + +Rule of thumb: anything that **mints** credit (`starter` grants) or **exports** the +full ledger (`snapshot`) is admin-only. Everything a normal install/refund/balance-check +flow needs is service-scoped — this is the key class that belongs in +`~/.m2-market/config.toml`'s `ledger_api_key`. + +## 5. Security rules + +1. **No secrets in repos or container images.** All keys/tokens in this document + (`ledger_api_key`, `memory_api_key`, `forgejo_token`, `LEDGER_SERVICE_KEYS`, + `LEDGER_ADMIN_KEYS`, `FORGEJO_TOKEN`) are injected at runtime — via `config.toml` + on the machine for the CLI, or via Coolify env vars for `m2-ledger`. Never commit + real values; example values above are placeholders only (constitution VI: + canary-first, reversible deployment — "No secrets in repos or images; keys + injected at runtime"). +2. **`~/.m2-market/config.toml` must be mode `0600`.** It is the only place all four + live credentials (ledger, memory, Forgejo) sit together on a machine. + ```bash + chmod 600 ~/.m2-market/config.toml + ``` +3. **Admin keys (`LEDGER_ADMIN_KEYS`) are minting/export authority** — scope + distribution tightly (see §4); CLI configs should never carry an admin key.