mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-09 01:35:18 +02:00
docs: update CLI/server/policy docs for the v1 config schema reshape
Rewrites the `omnigraph.yaml` schema reference and the CLI/policy/server config examples for `version: 1`: `cli:` -> `defaults:`, `server:` -> `serve:` (with the `graphs:` list), top-level `policy:`/`queries:` -> per-graph, `project:` removed, `uri:` -> `storage:`. Adds a legacy-spelling migration table and notes the legacy fallbacks. Updates testing.md's config-test inventory.
This commit is contained in:
parent
fff2a852e6
commit
14736a9ca5
5 changed files with 65 additions and 47 deletions
|
|
@ -39,9 +39,12 @@ The engine's `tests/` is the principal coverage surface; most graph-shaped behav
|
|||
| `recovery.rs` | Open-time recovery sweep — sidecar I/O, classifier dispatch (NoMovement / RolledPastExpected / UnexpectedAtP1 / UnexpectedMultistep / InvariantViolation), all-or-nothing decision, roll-forward via `ManifestBatchPublisher::publish`, roll-back via `Dataset::restore`, audit row in `_graph_commit_recoveries.lance`, `OpenMode::ReadOnly` skip path |
|
||||
| `composite_flow.rs` | Compositional/narrative end-to-end stories — multi-step flows that compose mechanics covered by other test files. Catches integration regressions where individual operations all pass their unit tests but their composition breaks (sequential merges, post-merge main writes, time-travel through merge DAG, reopen consistency over multi-merge histories). |
|
||||
|
||||
**Config & CLI (RFC-002 V1a)** — these live outside the engine `tests/` dir: the
|
||||
version-gated config-strictness and `deprecation_warnings` tests are inline in
|
||||
`omnigraph-config` (`src/lib.rs` test module); the `GraphLocator` discriminant +
|
||||
**Config & CLI (RFC-002 V1a + V1-remainder schema reshape)** — these live outside
|
||||
the engine `tests/` dir: the version-gated config-strictness, the v1
|
||||
legacy-key rejection / legacy-fold renames (`cli:`→`defaults:`, `server:`→`serve:`,
|
||||
removed `project:` and top-level `policy:`/`queries:`), and `deprecation_warnings`
|
||||
tests are inline in `omnigraph-config` (`src/lib.rs` test module); the
|
||||
`GraphLocator` discriminant +
|
||||
graph-identity tests are inline in `omnigraph-cli` (`src/main.rs`) plus
|
||||
`tests/cli.rs` / `tests/system_local.rs`; the server embedded-only rejection tests
|
||||
are in `omnigraph-server/tests/server.rs` (`multi_graph_startup`).
|
||||
|
|
|
|||
|
|
@ -20,19 +20,20 @@ A reference for the `omnigraph` binary's command surface and `omnigraph.yaml` sc
|
|||
| `run list \| show \| publish \| abort` | transactional run ops |
|
||||
| `schema plan \| apply \| show (alias: get)` | migrations |
|
||||
| `lint` (alias: `check`) | offline / graph-backed query validation. Replaces `query lint` / `query check`, which are kept as deprecated argv-level shims that print a one-line warning and rewrite to `omnigraph lint` |
|
||||
| `queries validate \| list` | operate on the server-side stored-query registry (the `queries:` block). `validate` type-checks every stored query against the live schema offline (opens the selected graph; exits non-zero on any breakage), catching schema drift without restarting the server; `list` prints the selected registry's query names, MCP exposure, and typed params. For per-graph registries, pass `--graph <graph>` or set `cli.graph`; with no graph selection, `list` shows only top-level `queries:`. Distinct from `lint`, which validates a single `.gq` file |
|
||||
| `queries validate \| list` | operate on the server-side stored-query registry (the `queries:` block). `validate` type-checks every stored query against the live schema offline (opens the selected graph; exits non-zero on any breakage), catching schema drift without restarting the server; `list` prints the selected registry's query names, MCP exposure, and typed params. For per-graph registries, pass `--graph <graph>` or set `defaults.graph`; with no graph selection, `list` shows only top-level `queries:`. Distinct from `lint`, which validates a single `.gq` file |
|
||||
| `optimize` | non-destructive Lance compaction (skips tables with `Blob` columns; `--json` reports a `skipped` field) |
|
||||
| `cleanup --keep N --older-than 7d --confirm` | destructive version GC |
|
||||
| `embed` | offline JSONL embedding pipeline |
|
||||
| `policy validate \| test \| explain` | Cedar tooling. Selects `cli.graph`, else `server.graph`, else top-level `policy.file` |
|
||||
| `policy validate \| test \| explain` | Cedar tooling. Selects `defaults.graph`, else `serve.graphs`, else top-level `policy.file` |
|
||||
| `version` / `-v` | print `omnigraph 0.3.x` |
|
||||
|
||||
## `omnigraph.yaml` schema
|
||||
|
||||
```yaml
|
||||
version: 1 # omit for the legacy schema (lenient, deprecation-warned);
|
||||
# `1` = strict: unknown/typo'd keys are rejected at any depth
|
||||
project: { name }
|
||||
# `1` = strict: unknown/typo'd keys, and the removed legacy
|
||||
# keys (`project:`, `cli:`, `server:`, top-level
|
||||
# `policy:`/`queries:`), are rejected at any depth
|
||||
servers: # named remote endpoints (referenced by graphs.<>.server)
|
||||
<name>: { endpoint: <https://host:port> }
|
||||
graphs:
|
||||
|
|
@ -45,6 +46,7 @@ graphs:
|
|||
bearer_token_env: <ENV_NAME>
|
||||
branch: <name> # optional default branch
|
||||
snapshot: <version> # optional read-pinned snapshot
|
||||
policy: { file: <policy.yaml> } # per-graph Cedar policy (embedded graphs only)
|
||||
queries: # per-graph stored-query registry (server-role; multi-graph mode)
|
||||
<query-name>: # key MUST equal the `query <name>` symbol inside the .gq
|
||||
file: <path-to-.gq> # relative to this config's directory
|
||||
|
|
@ -52,10 +54,11 @@ graphs:
|
|||
expose: true # default true: listed in the MCP catalog (GET /queries); set false to hide (still HTTP-callable)
|
||||
tool_name: <name> # optional MCP tool-name override (defaults to <query-name>;
|
||||
# must be unique across exposed queries)
|
||||
server:
|
||||
graph: <name>
|
||||
serve: # host-role serving config (was `server:`)
|
||||
graphs: [<name>] # served set; one entry = single-graph mode, omit = serve all
|
||||
bind: <ip:port>
|
||||
cli:
|
||||
policy: { file: <server-policy.yaml> } # server-level Cedar (management endpoints)
|
||||
defaults: # CLI/client defaults (was `cli:`)
|
||||
graph: <name>
|
||||
branch: <name>
|
||||
output_format: json|jsonl|csv|kv|table
|
||||
|
|
@ -77,12 +80,19 @@ aliases:
|
|||
graph: <name>
|
||||
branch: <name>
|
||||
format: <output-format>
|
||||
queries: # top-level registry — applies only to a bare-URI (anonymous) graph; a graph served by name uses its `graphs.<id>.queries`. Mirrors top-level `policy`.
|
||||
<query-name>: { file: <path-to-.gq> } # mcp.expose defaults to true
|
||||
policy:
|
||||
file: ./policy.yaml
|
||||
```
|
||||
|
||||
**Legacy spellings** (honored only when `version:` is omitted; each emits a load-time deprecation warning, and is rejected under `version: 1`):
|
||||
|
||||
| Legacy | v1 |
|
||||
|---|---|
|
||||
| `cli:` | `defaults:` |
|
||||
| `server:` (`graph:` scalar) | `serve:` (`graphs:` list) |
|
||||
| top-level `policy:` | `graphs.<name>.policy` |
|
||||
| top-level `queries:` | `graphs.<name>.queries` |
|
||||
| `project:` | removed (no consumer) |
|
||||
| `uri:` | `storage:` (embedded) / `server:` (remote) |
|
||||
|
||||
## Output formats (`query` command, alias: `read`)
|
||||
|
||||
- `json` — pretty-printed object with metadata + rows
|
||||
|
|
|
|||
|
|
@ -71,14 +71,14 @@ and configure the matching `bearer_token_env` in `omnigraph.yaml`.
|
|||
|
||||
## Multi-graph servers (v0.6.0+)
|
||||
|
||||
Against a multi-graph server (started with `--config omnigraph.yaml` referencing a non-empty `graphs:` map), use `omnigraph graphs list` to enumerate the registered graphs. The server must configure bearer tokens and `server.policy.file` with a rule that allows `graph_list`; `/graphs` is closed by default even when the server runs with `--unauthenticated`.
|
||||
Against a multi-graph server (started with `--config omnigraph.yaml` referencing a non-empty `graphs:` map), use `omnigraph graphs list` to enumerate the registered graphs. The server must configure bearer tokens and `serve.policy.file` with a rule that allows `graph_list`; `/graphs` is closed by default even when the server runs with `--unauthenticated`.
|
||||
|
||||
```bash
|
||||
OMNIGRAPH_BEARER_TOKEN=admin-token \
|
||||
omnigraph graphs list --uri http://server.example.com --json
|
||||
```
|
||||
|
||||
For config-driven clients, set the remote graph's `bearer_token_env` to an environment variable containing a token whose actor is authorized by `server.policy.file`.
|
||||
For config-driven clients, set the remote graph's `bearer_token_env` to an environment variable containing a token whose actor is authorized by `serve.policy.file`.
|
||||
|
||||
`list` rejects local URI targets — it's for remote multi-graph servers only.
|
||||
|
||||
|
|
@ -118,14 +118,18 @@ also pass `--schema`.
|
|||
query roots:
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
servers:
|
||||
dev:
|
||||
endpoint: http://127.0.0.1:8080
|
||||
graphs:
|
||||
local:
|
||||
uri: ./demo.omni
|
||||
storage: ./demo.omni
|
||||
dev:
|
||||
uri: http://127.0.0.1:8080
|
||||
server: dev
|
||||
bearer_token_env: OMNIGRAPH_BEARER_TOKEN
|
||||
|
||||
cli:
|
||||
defaults:
|
||||
graph: local
|
||||
branch: main
|
||||
|
||||
|
|
@ -137,10 +141,10 @@ query:
|
|||
|
||||
The config file can also define:
|
||||
|
||||
- server bind defaults
|
||||
- `serve:` bind / served-set / server-level policy defaults
|
||||
- auth env files
|
||||
- query aliases for common read and change commands
|
||||
- `policy.file` for Cedar authorization rules
|
||||
- per-graph `policy:` for Cedar authorization rules
|
||||
|
||||
When policy is enabled, `schema apply` is authorized through the
|
||||
`schema_apply` action and is typically limited to admins on protected `main`.
|
||||
|
|
|
|||
|
|
@ -33,31 +33,30 @@ Server-scoped actions cannot use `branch_scope` or `target_branch_scope` — the
|
|||
In multi mode (`omnigraph.yaml` with a non-empty `graphs:` map), policy files attach at two levels:
|
||||
|
||||
```yaml
|
||||
server:
|
||||
serve:
|
||||
policy:
|
||||
file: ./server-policy.yaml # server-level: graph_list
|
||||
|
||||
graphs:
|
||||
alpha:
|
||||
uri: s3://tenant-bucket/alpha
|
||||
storage: s3://tenant-bucket/alpha
|
||||
policy:
|
||||
file: ./policies/alpha.yaml # per-graph: read, change, branch_*, schema_apply
|
||||
beta:
|
||||
uri: s3://tenant-bucket/beta
|
||||
storage: s3://tenant-bucket/beta
|
||||
# no per-graph policy → no engine-layer Cedar enforcement on beta
|
||||
```
|
||||
|
||||
**Config follows graph identity, not server mode.** A graph served by **name**
|
||||
(`--graph <name>` or `server.graph`) uses its own `graphs.<name>.policy.file`,
|
||||
exactly as in multi-graph mode. Top-level `policy.file` applies only to an
|
||||
**anonymous** graph — one served by a bare `<URI>` with no `graphs:` entry.
|
||||
Serving a **named** graph (single- or multi-graph mode) while top-level
|
||||
`policy.file` (or `queries:`) is populated **refuses boot**, naming the block,
|
||||
since the top-level value would otherwise be silently shadowed by the per-graph
|
||||
block. Move per-graph rules to `graphs.<graph_id>.policy.file` and `graph_list`
|
||||
rules to `server.policy.file`.
|
||||
(`--graph <name>` or `serve.graphs`) uses its own `graphs.<name>.policy.file`,
|
||||
and `graph_list` rules go under `serve.policy.file`. (Under the legacy schema —
|
||||
no `version:` — a top-level `policy.file` applied to an **anonymous** graph
|
||||
served by a bare `<URI>`, and serving a **named** graph while top-level
|
||||
`policy.file`/`queries:` was populated refused boot to avoid silent shadowing;
|
||||
`version: 1` removes the top-level blocks entirely in favor of the per-graph and
|
||||
`serve.policy` blocks.)
|
||||
|
||||
Each graph's HTTP request flows through its own per-graph policy. The management endpoint (`GET /graphs`) flows through the server-level policy. When `server.policy.file` is unset, `GET /graphs` is denied in every runtime state, including `--unauthenticated`; with bearer tokens configured, it returns 403 after admission control because `graph_list` is not a `read`-equivalent action. The operator must explicitly authorize via `server-policy.yaml` to expose `/graphs`.
|
||||
Each graph's HTTP request flows through its own per-graph policy. The management endpoint (`GET /graphs`) flows through the server-level policy. When `serve.policy.file` is unset, `GET /graphs` is denied in every runtime state, including `--unauthenticated`; with bearer tokens configured, it returns 403 after admission control because `graph_list` is not a `read`-equivalent action. The operator must explicitly authorize via `server-policy.yaml` to expose `/graphs`.
|
||||
|
||||
Example server-level policy:
|
||||
|
||||
|
|
@ -77,19 +76,21 @@ rules:
|
|||
`omnigraph.yaml`:
|
||||
|
||||
```yaml
|
||||
policy:
|
||||
file: ./policy.yaml # Cedar rules + groups
|
||||
tests: ./policy.tests.yaml # declarative test cases
|
||||
|
||||
cli:
|
||||
version: 1
|
||||
graphs:
|
||||
my-graph:
|
||||
storage: ./graph.omni
|
||||
policy: { file: ./policy.yaml } # Cedar rules + groups; `policy.tests.yaml` sibling auto-discovered
|
||||
defaults:
|
||||
graph: my-graph
|
||||
actor: act-andrew # default actor for CLI direct-engine writes
|
||||
```
|
||||
|
||||
Each per-graph rule may use at most one of `branch_scope` or `target_branch_scope`. Server-scoped rules (`graph_list`) take neither — they have no branch context.
|
||||
|
||||
`cli.actor` is the default actor identity for CLI direct-engine writes
|
||||
`defaults.actor` is the default actor identity for CLI direct-engine writes
|
||||
when `policy.file` is configured. Override per-invocation with `--as
|
||||
<ACTOR>` (top-level flag) — `--as` wins, otherwise `cli.actor` is used,
|
||||
<ACTOR>` (top-level flag) — `--as` wins, otherwise `defaults.actor` is used,
|
||||
otherwise no actor. With policy configured and neither set, the
|
||||
engine-layer footgun guard intentionally denies the write (silent bypass
|
||||
via "I forgot the actor" is exactly what the guard prevents). Remote
|
||||
|
|
@ -98,9 +99,9 @@ bearer token.
|
|||
|
||||
## CLI
|
||||
|
||||
Policy tooling resolves its graph like server single-mode policy: `cli.graph`
|
||||
wins, otherwise `server.graph` is used, otherwise the top-level `policy.file`
|
||||
is validated/tested/explained as the anonymous policy.
|
||||
Policy tooling resolves its graph like server single-graph policy: `defaults.graph`
|
||||
wins, otherwise `serve.graphs` is used, otherwise (legacy schema only) the
|
||||
top-level `policy.file` is validated/tested/explained as the anonymous policy.
|
||||
|
||||
- `omnigraph policy validate` — parse + count actors, exit 1 on parse error.
|
||||
- `omnigraph policy test` — run cases in `policy.tests.yaml`, exit 1 on any expectation mismatch.
|
||||
|
|
@ -131,7 +132,7 @@ reaches `authorize_request()` without a matching policy permit.
|
|||
|---|---|---|---|
|
||||
| **Open** | no | no | Every request is permitted. Refuses to start unless `--unauthenticated` or `OMNIGRAPH_UNAUTHENTICATED=1` is set — the operator must explicitly opt in. |
|
||||
| **DefaultDeny** | yes | no | Every authenticated request for an action other than `read` is rejected with HTTP 403. Closes the "tokens but forgot the policy file" trap — an operator who sets up auth and forgot to point at a policy file used to ship the illusion of protection. |
|
||||
| **PolicyEnabled** | yes | yes | Authenticated requests that reach a configured policy engine are evaluated by Cedar. Server-scoped actions still require `server.policy.file`. |
|
||||
| **PolicyEnabled** | yes | yes | Authenticated requests that reach a configured policy engine are evaluated by Cedar. Server-scoped actions still require `serve.policy.file`. |
|
||||
|
||||
The classifier is `classify_server_runtime_state` in
|
||||
`crates/omnigraph-server/src/lib.rs`; it returns `Err` for the "no
|
||||
|
|
|
|||
|
|
@ -8,17 +8,17 @@ Axum 0.8 + tokio + utoipa-generated OpenAPI. **Two modes** (v0.6.0+): single-gra
|
|||
|
||||
`omnigraph-server <URI>` or `omnigraph-server --graph <name> --config omnigraph.yaml`. Routes are flat — `/snapshot`, `/read`, `/branches`, etc.
|
||||
|
||||
**Config follows graph identity.** A bare `<URI>` is an *anonymous* graph and uses the **top-level** `policy.file` / `queries:`. A graph chosen by **name** (`--graph` / `server.graph`) uses its own `graphs.<name>.{policy.file, queries}` — the same block multi-graph mode uses. ⚠️ *Changed from v0.6.0, which always used top-level config in single mode: a named-graph config that puts `policy`/`queries` at top-level now **refuses boot** and points you at `graphs.<name>.…` (move the block there). Bare-`<URI>` single mode is unchanged.*
|
||||
**Config follows graph identity.** A graph chosen by **name** (`--graph` / `serve.graphs`) uses its own `graphs.<name>.{policy.file, queries}` — the same block multi-graph mode uses. A bare `<URI>` is an *anonymous* graph with no per-graph config; under `version: 1` the top-level `policy:` / `queries:` blocks are **removed**, so attach policy or stored queries by giving the graph a named `graphs:` entry. ⚠️ *Under the legacy schema (no `version:`) a bare `<URI>` still falls back to top-level `policy.file` / `queries:`, and a named-graph config that puts `policy`/`queries` at top-level **refuses boot**, pointing you at `graphs.<name>.…`.*
|
||||
|
||||
### Multi-graph mode (v0.6.0+)
|
||||
|
||||
`omnigraph-server --config omnigraph.yaml` with a non-empty `graphs:` map and **no** single-mode selector (no `server.graph`, no `<URI>`, no `--graph`). The server opens every configured graph in parallel at startup (bounded concurrency = 4, fail-fast on the first open error). Routes are nested under `/graphs/{graph_id}/...`. Bare flat paths return 404 in multi mode.
|
||||
`omnigraph-server --config omnigraph.yaml` with a non-empty `graphs:` map and **no** single-mode selector (no `serve.graphs`, no `<URI>`, no `--graph`). The server opens every configured graph in parallel at startup (bounded concurrency = 4, fail-fast on the first open error). Routes are nested under `/graphs/{graph_id}/...`. Bare flat paths return 404 in multi mode.
|
||||
|
||||
Mode inference (four-rule matrix):
|
||||
|
||||
1. CLI positional `<URI>` → single
|
||||
2. CLI `--graph <name>` → single
|
||||
3. `server.graph` in config → single
|
||||
3. `serve.graphs` in config → single
|
||||
4. `--config` + non-empty `graphs:` + no single-mode selector → **multi**
|
||||
5. otherwise → error with migration hint
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue