Add POST /queries/{name} stored-query invocation handler

Invoke a curated server-side stored query by name: source + name come from
the per-graph queries: registry, the client sends only runtime inputs
(params, branch, snapshot). Gated by the invoke_query Cedar action at the
boundary; the handler delegates to the existing run_query/run_mutate, whose
inner Read/Change enforce still runs — so a stored mutation is double-gated
(invoke_query to reach the tool, change for the write).

- InvokeStoredQueryRequest + an untagged InvokeStoredQueryResponse
  { Read(ReadOutput), Change(ChangeOutput) } → one Json<_> return type and a
  oneOf 200 schema (a correct contract, not a wrong-but-simple one).
- Route lives in per_graph_protected → single-mode /queries/{name} and
  multi-mode /graphs/{id}/queries/{name} for free.
- Deny == unknown: an invoke_query denial and a missing query both return the
  same 404, so the catalog can't be probed by an unauthorized caller.
- OpenAPI regenerated; tests cover read, mutation double-gate (403 vs 200),
  bad-param 400, and the identical-404 deny path.

Completes the MR-969 V1 invocation slice (registry + /queries/{name} + invoke_query).
This commit is contained in:
Ragnor Comerford 2026-05-30 22:36:56 +02:00
parent 6983608f4f
commit d67b10fa6e
No known key found for this signature in database
5 changed files with 462 additions and 1 deletions

View file

@ -168,6 +168,7 @@ const EXPECTED_PATHS: &[&str] = &[
"/export",
"/change",
"/mutate",
"/queries/{name}",
"/schema",
"/schema/apply",
"/ingest",
@ -701,6 +702,7 @@ fn protected_endpoints_reference_bearer_token_security() {
("/read", "post"),
("/change", "post"),
("/schema/apply", "post"),
("/queries/{name}", "post"),
("/ingest", "post"),
("/export", "post"),
("/snapshot", "get"),