refactor(config): remove top-level policy:/queries: under v1

Top-level `policy:`/`queries:` (the single-graph-mode blocks) are removed under
`version: 1` — policy and stored queries belong on the owning `graphs.<name>`
entry. Both are rejected at load (pointing at the per-graph block) and honored-
but-warned under the legacy schema; the per-graph `graphs.<name>.policy`/`queries`
blocks are nested, so the key scan leaves them untouched. Drops the now-illegal
empty top-level `policy: {}` from the shared CLI test helpers.
This commit is contained in:
Ragnor Comerford 2026-06-04 21:43:03 +02:00
parent 304ac5ec23
commit fff2a852e6
No known key found for this signature in database
2 changed files with 49 additions and 2 deletions

View file

@ -129,7 +129,6 @@ defaults:
query:
roots:
- .
policy: {{}}
",
yaml_string(&graph.to_string_lossy())
)
@ -151,7 +150,6 @@ defaults:
query:
roots:
- .
policy: {{}}
",
yaml_string(url)
)

View file

@ -1017,6 +1017,8 @@ fn legacy_key_migration_hint(key: &str) -> Option<&'static str> {
"project" => Some("remove it; it has no effect under `version: 1`"),
"cli" => Some("rename to `defaults:`"),
"server" => Some("rename to `serve:` (note `graph:` becomes the `graphs:` list)"),
"policy" => Some("move it onto the owning graph (`graphs.<name>.policy`)"),
"queries" => Some("move it onto the owning graph (`graphs.<name>.queries`)"),
_ => None,
}
}
@ -1604,6 +1606,53 @@ cli:
);
}
#[test]
fn version_one_rejects_top_level_policy() {
// Top-level `policy:`/`queries:` are removed under v1 — they belong on
// the owning graph entry. An empty `policy: {}` must error too (presence,
// not contents).
let err = load_yaml_err(
"version: 1\ngraphs:\n local:\n storage: ./demo.omni\npolicy:\n file: ./p.yaml\n",
);
assert!(
err.contains("policy") && err.contains("graphs.<name>.policy"),
"v1 must reject top-level `policy:` and point at the per-graph block: {err}"
);
}
#[test]
fn version_one_rejects_top_level_queries() {
let err = load_yaml_err(
"version: 1\ngraphs:\n local:\n storage: ./demo.omni\n\
queries:\n q:\n file: ./q.gq\n",
);
assert!(
err.contains("queries") && err.contains("graphs.<name>.queries"),
"v1 must reject top-level `queries:` and point at the per-graph block: {err}"
);
}
#[test]
fn version_one_honors_per_graph_policy_and_queries() {
// The per-graph blocks (`graphs.<name>.policy` / `.queries`) are nested,
// not top-level, so the v1 key scan leaves them alone.
let config = load_yaml(
r#"version: 1
graphs:
prod:
storage: s3://b/prod
policy:
file: ./prod.yaml
queries:
q:
file: ./q.gq
"#,
);
assert!(config.resolve_target_policy_file("prod").is_some());
assert_eq!(config.target_query_entries("prod").unwrap().len(), 1);
assert!(config.deprecation_warnings().is_empty());
}
#[test]
fn version_one_rejects_legacy_project_key() {
// `version: 1` removes the `project:` block (no consumer). Writing it