mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-18 02:24:27 +02:00
The server already dropped omnigraph.yaml (cluster-only boot). This removes the CLI's last use of the legacy `OmnigraphConfig`: graphs are addressed only via `--store`/`--server`/`--cluster`/`--profile`/operator defaults, and actor, output format, and bearer credentials come from `~/.omnigraph/config.yaml`. After this change no CLI command reads `omnigraph.yaml` except `config migrate`. Resolvers (helpers.rs): drop every legacy fallback — - `resolve_actor` → `--as` > `operator.actor` (no `cli.actor`); - `resolve_read_format` → `--json`/`--format` > alias > `defaults.output`; - `resolve_branch`/`resolve_read_target` → `--branch` > alias > "main"; - `resolve_uri`/`resolve_cli_graph` → scope path only; an absent address is a loud error; - `resolve_remote_bearer_token` → operator keyed chain + `OMNIGRAPH_BEARER_TOKEN`. `GraphClient::resolve`/`resolve_with_policy` drop the `&OmnigraphConfig` param; direct-store access carries no Cedar policy (policy lives in the cluster/server). Flags (cli.rs): remove `--config` from every data/query command; it stays only on `cluster *` (the cluster dir) and `config migrate` (the legacy path). Re-home control-plane tooling to `--cluster` (RFC-011): - `policy validate|test|explain` source the Cedar bundle from the cluster's applied policies; `--graph` picks a graph's bundle; `policy test` takes `--tests <file>`; - `queries list|validate` source the registry + schemas from the cluster serving snapshot; `--graph` scopes to one graph; - `lint` requires `--schema` (offline) or a direct/cluster graph target; - `schema plan`/`lint` route their graph-target through the shared direct-scope resolver so `--store`/`--profile`/`defaults.store` addressing works. Tests migrate from `omnigraph.yaml` fixtures to `--store`/operator-config/ `--cluster` (converged-cluster fixtures); the now-impossible command-path RFC-008 tests are deleted (`config migrate` coverage kept). The `OmnigraphConfig` type, `load_config`/deprecation machinery, and `config migrate` are removed in a follow-up. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
124 lines
4.7 KiB
Rust
124 lines
4.7 KiB
Rust
//! In-source test suite for the CLI binary (moved verbatim from
|
|
//! main.rs; `use super::*` resolves through the #[path] declaration).
|
|
|
|
use super::{
|
|
DEFAULT_BEARER_TOKEN_ENV, apply_bearer_token, legacy_change_request_body,
|
|
normalize_bearer_token, resolve_remote_bearer_token,
|
|
};
|
|
use reqwest::header::AUTHORIZATION;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn legacy_change_request_body_uses_legacy_field_names() {
|
|
// `mutate`'s remote arm hits `POST /change`, which old
|
|
// `omnigraph-server` builds deserialize as `ChangeRequest` with
|
|
// **required** `query_source` and optional `query_name` keys.
|
|
// Newer servers accept both spellings via serde alias, but a
|
|
// newer CLI must still emit the legacy keys on the wire so it
|
|
// can talk to an old server during a rolling upgrade.
|
|
let body = legacy_change_request_body(
|
|
"query insert_person($n: String) { insert Person { name: $n } }",
|
|
Some("insert_person"),
|
|
"main",
|
|
Some(&json!({ "n": "Alice" })),
|
|
);
|
|
assert_eq!(
|
|
body["query_source"].as_str(),
|
|
Some("query insert_person($n: String) { insert Person { name: $n } }"),
|
|
);
|
|
assert_eq!(body["query_name"].as_str(), Some("insert_person"));
|
|
assert_eq!(body["branch"].as_str(), Some("main"));
|
|
assert_eq!(body["params"]["n"].as_str(), Some("Alice"));
|
|
// Crucially, the **new** field names must NOT appear -- old
|
|
// servers would silently treat them as unknown fields and then
|
|
// fail on missing required `query_source`.
|
|
assert!(
|
|
body.get("query").is_none(),
|
|
"legacy /change body must not carry the renamed `query` key; got {body}"
|
|
);
|
|
assert!(
|
|
body.get("name").is_none(),
|
|
"legacy /change body must not carry the renamed `name` key; got {body}"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn legacy_change_request_body_omits_optional_fields_when_unset() {
|
|
let body = legacy_change_request_body(
|
|
"query find() { match { $p: Person } return { $p.name } }",
|
|
None,
|
|
"main",
|
|
None,
|
|
);
|
|
assert_eq!(body["branch"].as_str(), Some("main"));
|
|
assert!(body.get("query_name").is_none());
|
|
assert!(body.get("params").is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn apply_bearer_token_adds_header_when_configured() {
|
|
let client = reqwest::Client::new();
|
|
let request = apply_bearer_token(client.get("http://example.com"), Some("demo-token"))
|
|
.build()
|
|
.unwrap();
|
|
assert_eq!(
|
|
request
|
|
.headers()
|
|
.get(AUTHORIZATION)
|
|
.and_then(|value| value.to_str().ok()),
|
|
Some("Bearer demo-token")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn apply_bearer_token_leaves_request_unchanged_when_not_configured() {
|
|
let client = reqwest::Client::new();
|
|
let request = apply_bearer_token(client.get("http://example.com"), None)
|
|
.build()
|
|
.unwrap();
|
|
assert!(request.headers().get(AUTHORIZATION).is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn normalize_bearer_token_trims_and_filters_blank_values() {
|
|
assert_eq!(normalize_bearer_token(None), None);
|
|
assert_eq!(normalize_bearer_token(Some(" ".to_string())), None);
|
|
assert_eq!(
|
|
normalize_bearer_token(Some(" demo-token ".to_string())).as_deref(),
|
|
Some("demo-token")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_remote_bearer_token_falls_back_to_default_env() {
|
|
// RFC-011: with no operator server matching the URL, the only chain
|
|
// left is the default `OMNIGRAPH_BEARER_TOKEN` env (no omnigraph.yaml
|
|
// scoped chain). Hermetic: no operator config is read for a literal URL
|
|
// that matches no `servers:` entry.
|
|
let previous = std::env::var_os(DEFAULT_BEARER_TOKEN_ENV);
|
|
let previous_home = std::env::var_os("OMNIGRAPH_HOME");
|
|
unsafe {
|
|
std::env::set_var(DEFAULT_BEARER_TOKEN_ENV, "global-token");
|
|
std::env::set_var("OMNIGRAPH_HOME", "/nonexistent/omnigraph-test-home");
|
|
}
|
|
|
|
assert_eq!(
|
|
resolve_remote_bearer_token(Some("https://override.example.com"))
|
|
.unwrap()
|
|
.as_deref(),
|
|
Some("global-token")
|
|
);
|
|
|
|
unsafe {
|
|
if let Some(value) = previous {
|
|
std::env::set_var(DEFAULT_BEARER_TOKEN_ENV, value);
|
|
} else {
|
|
std::env::remove_var(DEFAULT_BEARER_TOKEN_ENV);
|
|
}
|
|
if let Some(value) = previous_home {
|
|
std::env::set_var("OMNIGRAPH_HOME", value);
|
|
} else {
|
|
std::env::remove_var("OMNIGRAPH_HOME");
|
|
}
|
|
}
|
|
}
|