diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ce6e194..3ffd88ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,25 @@ This file is the authoritative user-facing release chronology. The former [release-notes ledger](docs/archive/2026/graphql-orm-release-notes.md) is retained for historical context. +## 0.24.0 - 2026-08-22 + +Companion macros crate: `graphql-orm-macros` **0.24.0**. Generated ORM and +macro behavior is unchanged. + +- Updated the optional `auth-agql` dependency to `agql-auth` 0.16.0 at merged + revision `3bc38cd94794f1e868a9cc3a5551047b95a32105`. The bridge remains a + projection of an already accepted principal and does not select matcher + policy or gain token-issuer responsibilities. +- Hosts that enable `auth-agql` and also depend directly on `agql-auth` must + use the same exact revision so public principal and assurance types resolve + from one source universe. +- Collapsed an equivalent macro-generation branch and removed a redundant + doctest wrapper to remain warnings-clean under the pinned Clippy toolchain; + emitted tokens and the compile-fail probe are unchanged. + +No database, GraphQL SDL, generated-code, migration-history, backup, token, or +stored-data migration is required. + ## 0.23.0 - 2026-08-14 Companion macros crate: `graphql-orm-macros` **0.23.0**. Backend-neutral diff --git a/Cargo.lock b/Cargo.lock index a947ad1e..e5b8afac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,8 +87,8 @@ dependencies = [ [[package]] name = "agql-auth" -version = "0.15.0" -source = "git+https://github.com/Dastari/agql-auth.git?rev=e841ffd382082ad7419be259fe957f949b956ff7#e841ffd382082ad7419be259fe957f949b956ff7" +version = "0.16.0" +source = "git+https://github.com/Dastari/agql-auth.git?rev=3bc38cd94794f1e868a9cc3a5551047b95a32105#3bc38cd94794f1e868a9cc3a5551047b95a32105" dependencies = [ "argon2", "async-graphql", @@ -3075,7 +3075,7 @@ dependencies = [ [[package]] name = "graphql-orm" -version = "0.23.0" +version = "0.24.0" dependencies = [ "agql-auth", "async-graphql", @@ -3104,7 +3104,7 @@ dependencies = [ [[package]] name = "graphql-orm-ai" -version = "0.88.0" +version = "0.89.0" dependencies = [ "agql-auth", "async-graphql", @@ -3172,7 +3172,7 @@ dependencies = [ [[package]] name = "graphql-orm-macros" -version = "0.23.0" +version = "0.24.0" dependencies = [ "convert_case 0.7.1", "proc-macro2", @@ -3193,7 +3193,7 @@ dependencies = [ [[package]] name = "graphql-orm-router" -version = "0.1.4" +version = "0.2.0" dependencies = [ "agql-auth", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index 98fa550e..2aad7630 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ license = "MIT" repository = "https://github.com/Dastari/graphql-orm" [workspace.dependencies] -agql-auth = { git = "https://github.com/Dastari/agql-auth.git", rev = "e841ffd382082ad7419be259fe957f949b956ff7", version = "0.15.0" } +agql-auth = { git = "https://github.com/Dastari/agql-auth.git", rev = "3bc38cd94794f1e868a9cc3a5551047b95a32105", version = "0.16.0" } arc-swap = "1.7" async-graphql = { version = "7", features = ["dataloader", "uuid"] } async-graphql-parser = "7" @@ -37,7 +37,7 @@ cynic-parser = { version = "=0.11.2", features = ["pretty"] } futures = "0.3" getrandom = "0.3" graphql-composition = "=0.12.2" -graphql-orm = { path = "crates/graphql-orm", version = "0.23.0", default-features = false } +graphql-orm = { path = "crates/graphql-orm", version = "0.24.0", default-features = false } graphql-orm-ai-tool-profiles = { path = "crates/graphql-orm-ai-tool-profiles", version = "0.9.0" } graphql-orm-backup = { path = "crates/graphql-orm-backup", version = "0.7.1", default-features = false } graphql-orm-operation-catalog = { path = "crates/graphql-orm-operation-catalog", version = "0.3.0" } diff --git a/MIGRATION.md b/MIGRATION.md index 0beccbba..6f7f8c97 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -13,6 +13,18 @@ supersedes: [] `graphql-orm` is distributed from GitHub only. Use a reviewed full 40-character commit in `rev`; neither the runtime nor macros crate is published to crates.io. +## 0.23.0 to 0.24.0: agql-auth 0.16 alignment + +Hosts enabling `auth-agql` or depending directly on `agql-auth` must align to +version 0.16.0 at merged revision +`3bc38cd94794f1e868a9cc3a5551047b95a32105`. Adopt `graphql-orm` and the +aligned `graphql-orm-macros` 0.24.0 from the same reviewed monorepo revision. +This retains one public auth type universe. Version 0.16 adds +consumer-supplied exact-only hierarchical matcher policy; the ORM bridge +remains projection-only and does not select or install that policy. No +database, schema, GraphQL SDL, generated-code, token, backup, or stored-data +migration is required. + ## 0.22.1 to 0.23.0: explicit collection-bound semantics Update `graphql-orm`, `graphql-orm-macros`, and @@ -1183,6 +1195,6 @@ access path. - No JWT, OIDC, cookie, wildcard, or application-specific scope logic was added to `graphql-orm`. - PostgreSQL RLS helper functions still use exact scope matching. -- The current `auth-agql` feature targets `agql-auth` 0.15.0 at revision - `e841ffd382082ad7419be259fe957f949b956ff7`; earlier release sections above +- The current `auth-agql` feature targets `agql-auth` 0.16.0 at revision + `3bc38cd94794f1e868a9cc3a5551047b95a32105`; earlier release sections above retain their historical pins. diff --git a/README.md b/README.md index 439664e6..ecca1eb5 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ reviewed full SHA for the release: ```toml [dependencies] -graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", default-features = false, features = ["sqlite"] } +graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", default-features = false, features = ["sqlite"] } ``` Choose exactly the backend support needed by each service. Cargo can unify diff --git a/crates/graphql-orm-ai/CHANGELOG.md b/crates/graphql-orm-ai/CHANGELOG.md index 0d39b988..bace13c6 100644 --- a/crates/graphql-orm-ai/CHANGELOG.md +++ b/crates/graphql-orm-ai/CHANGELOG.md @@ -18,6 +18,23 @@ checkpoint facts. For the current workspace baseline and active gates, use the [implementation status](docs/implementation-status.md) and the central [AI production-readiness plan](../../docs/plans/active/ai-production-readiness/README.md). +## [0.89.0] - 2026-08-22 + +Persistent schema module: **0.63.0** (unchanged from 0.88.0). + +### Changed + +- Aligned the public `agql-auth` type universe to 0.16.0 at merged revision + `3bc38cd94794f1e868a9cc3a5551047b95a32105`. This matters to consumers because + the AI prelude publicly re-exports `CurrentPrincipalResolver`, + `PrincipalReference`, and `ResolvedPrincipal`. +- Hosts that depend directly on `agql-auth` must use that same full revision. + AI authorization, principal rehydration, provider, and persistence behavior + are unchanged. + +There is no schema, data, protected-payload, GraphQL SDL, backup or restore +migration in this release. + ## [0.88.0] - 2026-08-22 Persistent schema module: **0.63.0** (unchanged from 0.87.0). diff --git a/crates/graphql-orm-ai/Cargo.toml b/crates/graphql-orm-ai/Cargo.toml index 4fb20183..282daf02 100644 --- a/crates/graphql-orm-ai/Cargo.toml +++ b/crates/graphql-orm-ai/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "graphql-orm-ai" -version = "0.88.0" +version = "0.89.0" edition = "2024" authors = ["Toby Martin "] description = "Project-agnostic AI agent runtime for graphql-orm applications" diff --git a/crates/graphql-orm-ai/MIGRATION.md b/crates/graphql-orm-ai/MIGRATION.md index b89476a1..02e2db84 100644 --- a/crates/graphql-orm-ai/MIGRATION.md +++ b/crates/graphql-orm-ai/MIGRATION.md @@ -19,6 +19,21 @@ they describe. For the current workspace baseline and active delivery gates, use [implementation status](docs/implementation-status.md) and the central [AI production-readiness plan](../../docs/plans/active/ai-production-readiness/README.md). +## 0.88.0 to 0.89.0: agql-auth 0.16 type-universe alignment + +Adopt `graphql-orm-ai` 0.89.0 from one reviewed full monorepo revision and +align every direct `agql-auth` dependency to version 0.16.0 at merged revision +`3bc38cd94794f1e868a9cc3a5551047b95a32105`. The AI prelude publicly +re-exports `CurrentPrincipalResolver`, `PrincipalReference`, and +`ResolvedPrincipal`, so resolving another source revision would create a +different public Rust type universe even though these type contracts are +otherwise unchanged. + +The AI schema module remains **0.63.0**. There is no database, data, table, +column, index, constraint, backfill, GraphQL SDL, protected-payload, backup or +restore migration. AI authorization, principal rehydration, and provider +behavior are unchanged. + ## 0.87.0 to 0.88.0: direct GPT-5.6 dynamic tools on Codex 0.148.0 Adopt `graphql-orm-ai` 0.88.0 from one reviewed full monorepo revision. The AI diff --git a/crates/graphql-orm-ai/README.md b/crates/graphql-orm-ai/README.md index 419d2159..826460f3 100644 --- a/crates/graphql-orm-ai/README.md +++ b/crates/graphql-orm-ai/README.md @@ -28,7 +28,7 @@ for AI, ORM, storage, backup, and tool-profile packages: ```toml [dependencies] -graphql-orm-ai = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.87.0", default-features = false, features = ["sqlite"] } +graphql-orm-ai = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.89.0", default-features = false, features = ["sqlite"] } ``` Exactly one persistence backend is required: `sqlite` (default), `postgres`, diff --git a/crates/graphql-orm-ai/docs/implementation-status.md b/crates/graphql-orm-ai/docs/implementation-status.md index bb23b1f0..faba2761 100644 --- a/crates/graphql-orm-ai/docs/implementation-status.md +++ b/crates/graphql-orm-ai/docs/implementation-status.md @@ -10,10 +10,10 @@ supersedes: [] # Implementation Status -`graphql-orm-ai` is at crate version `0.87.0` with AI schema module -`0.63.0`. It uses workspace `graphql-orm` `0.23.0`, backend-neutral +`graphql-orm-ai` is at crate version `0.89.0` with AI schema module +`0.63.0`. It uses workspace `graphql-orm` `0.24.0`, backend-neutral `graphql-orm-ai-tool-profiles` `0.9.0`, and external `agql-auth` -`0.15.0` at `e841ffd382082ad7419be259fe957f949b956ff7`. +`0.16.0` at `3bc38cd94794f1e868a9cc3a5551047b95a32105`. Completed stateless local-provider turns can carry a proof-bearing contained native-item refusal after authoritative usage settlement. Those runs close as diff --git a/crates/graphql-orm-ai/src/providers/codex_app_server.rs b/crates/graphql-orm-ai/src/providers/codex_app_server.rs index 1aa06250..7e522799 100644 --- a/crates/graphql-orm-ai/src/providers/codex_app_server.rs +++ b/crates/graphql-orm-ai/src/providers/codex_app_server.rs @@ -6601,7 +6601,7 @@ pub(crate) mod tests { .and_then(Value::as_str) .is_some_and(|description| description.contains("maximum 25")) ); - assert!(schema.to_string().find("anyOf").is_none()); + assert!(!schema.to_string().contains("anyOf")); } fn named_semantic_type(name: &str, nullable: bool) -> GraphqlSemanticTypeRef { diff --git a/crates/graphql-orm-backup/AGENTS.md b/crates/graphql-orm-backup/AGENTS.md index 43107853..295cd1c0 100644 --- a/crates/graphql-orm-backup/AGENTS.md +++ b/crates/graphql-orm-backup/AGENTS.md @@ -32,13 +32,13 @@ This crate is a reusable backup and restore companion for applications that use ## Current Agent Handoff - Current crate version is `0.7.1`. -- The optional ORM adapter resolves `graphql-orm` 0.22.1 from the workspace. +- The optional ORM adapter resolves `graphql-orm` 0.24.0 from the workspace. Internal packages use workspace path dependencies and the root `Cargo.lock`. Keep downstream applications on one reviewed monorepo revision so ORM, backup, and storage share the same canonical source/type universe. - `graphql-orm` owns its optional `agql-auth` integration and pins - `agql-auth` 0.15.0 at - `e841ffd382082ad7419be259fe957f949b956ff7`. This crate must not enable or + `agql-auth` 0.16.0 at + `3bc38cd94794f1e868a9cc3a5551047b95a32105`. This crate must not enable or depend directly on application authorization. - Applying and dry-run restore compare the manifest backend/schema hash with the target before target checks or writes. Preserve that fail-closed diff --git a/crates/graphql-orm-macros/Cargo.toml b/crates/graphql-orm-macros/Cargo.toml index fede9790..a7bbe756 100644 --- a/crates/graphql-orm-macros/Cargo.toml +++ b/crates/graphql-orm-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "graphql-orm-macros" -version = "0.23.0" +version = "0.24.0" edition = "2024" authors = ["Toby Martin"] description = "Procedural macros for async-graphql and ORM-backed entities, relations, and CRUD operations." diff --git a/crates/graphql-orm-macros/README.md b/crates/graphql-orm-macros/README.md index 5bb87c5a..e6fde125 100644 --- a/crates/graphql-orm-macros/README.md +++ b/crates/graphql-orm-macros/README.md @@ -16,13 +16,13 @@ macro/runtime versions aligned: ```toml [dependencies] -graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", default-features = false, features = ["sqlite"] } +graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", default-features = false, features = ["sqlite"] } ``` Direct use is supported for tooling that needs the macro package: ```toml -graphql-orm-macros = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", default-features = false, features = ["sqlite"] } +graphql-orm-macros = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", default-features = false, features = ["sqlite"] } ``` The direct dependency still requires a compatible `graphql-orm` runtime in the diff --git a/crates/graphql-orm-macros/src/operations.rs b/crates/graphql-orm-macros/src/operations.rs index 0c442f93..988b8258 100644 --- a/crates/graphql-orm-macros/src/operations.rs +++ b/crates/graphql-orm-macros/src/operations.rs @@ -4867,12 +4867,10 @@ pub(crate) fn generate_graphql_operations( #(#retention_event_id_values)* ::graphql_orm::graphql::orm::composite_key_id(&bind_values) }} + } else if pk_is_bytes { + quote! { ::graphql_orm::graphql::orm::binary_key_id(&self.#pk_field) } } else { - if pk_is_bytes { - quote! { ::graphql_orm::graphql::orm::binary_key_id(&self.#pk_field) } - } else { - quote! { self.#pk_field.to_string() } - } + quote! { self.#pk_field.to_string() } }; let retention_surface = if entity_meta.retention_policy.is_some() { quote! { diff --git a/crates/graphql-orm-router/CHANGELOG.md b/crates/graphql-orm-router/CHANGELOG.md index fa108847..ca5507e0 100644 --- a/crates/graphql-orm-router/CHANGELOG.md +++ b/crates/graphql-orm-router/CHANGELOG.md @@ -10,6 +10,21 @@ supersedes: [] # Changelog +## 0.2.0 - 2026-08-22 + +- Added strict `scopeMatcher` file configuration. Omission and `kind: exact` + preserve exact-string behavior; `kind: hierarchical` exposes the generic + separator, wildcard, universal-wildcard, super-scope, and exact-only options + from the optional resource-server matcher. +- Updated the optional `agql-auth` adapter to 0.16.0 for consumer-supplied + exact-only fixed scopes and resource-qualified scope patterns. +- Supplied the configured matcher to the existing authorization path shared by + fixed and rendered operation requirements; operation evaluation code is + unchanged. Subgraph resolver authorization remains authoritative. + +No descriptor, GraphQL schema, token wire, or stored-data migration is +required. Hierarchical file configuration requires the `auth-agql` feature. + ## 0.1.4 - 2026-08-13 - Updated the optional resource-server-only `agql-auth` adapter to 0.15.0 at diff --git a/crates/graphql-orm-router/Cargo.toml b/crates/graphql-orm-router/Cargo.toml index b85258be..b336356f 100644 --- a/crates/graphql-orm-router/Cargo.toml +++ b/crates/graphql-orm-router/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "graphql-orm-router" -version = "0.1.4" +version = "0.2.0" edition = "2024" rust-version = "1.90" description = "Federated GraphQL router for graphql-orm and project-neutral subgraphs" diff --git a/crates/graphql-orm-router/MIGRATION.md b/crates/graphql-orm-router/MIGRATION.md index 858efd15..98b15912 100644 --- a/crates/graphql-orm-router/MIGRATION.md +++ b/crates/graphql-orm-router/MIGRATION.md @@ -10,6 +10,23 @@ supersedes: [] # graphql-orm-router migration guide +## 0.1.4 to 0.2.0 + +Replace the reviewed full-revision pin and rebuild the router. Hosts that also +depend directly on `agql-auth` must align to version 0.16.0 at the exact +reviewed revision so Cargo resolves one auth type universe. + +Omitted `scopeMatcher` configuration remains exact and needs no migration. +To opt into the generic hierarchy, build with `auth-agql` and add +`{"scopeMatcher":{"kind":"hierarchical"}}`; then explicitly review +separator, wildcard, universal-wildcard, `superScopes`, `exactOnlyScopes`, and +`exactOnlyScopePatterns` policy. Exact-only requirements are checked before a +super scope or wildcard, including rendered resource-qualified requirements. + +No descriptor, GraphQL schema, token wire, or stored-data migration is +required. Run `--check` against the complete graph and exercise both ordinary +and exact-only authorization cases before deployment. + ## 0.1.3 to 0.1.4 Replace the reviewed full-revision pin and rebuild the router. When a host @@ -91,8 +108,8 @@ New access tokens should use the OAuth space-delimited `scope` claim. The legacy `scopes` array is accepted only with `acceptLegacyScopes: true`; a token containing conflicting forms is rejected. The optional `auth-agql` feature is a validation/matching adapter only and introduces no issuer responsibilities. -It resolves `agql-auth` 0.15.0 at exact revision -`e841ffd382082ad7419be259fe957f949b956ff7`; hosts with a direct dependency +It resolves `agql-auth` 0.16.0 at exact revision +`3bc38cd94794f1e868a9cc3a5551047b95a32105`; hosts with a direct dependency must use the same source and revision. Configure legacy acceptance directly with `agql_auth::AccessTokenValidatorBuilder::legacy_scope_claims` before wrapping the validator in `AgqlAuthenticationProvider::new`. diff --git a/crates/graphql-orm-router/README.md b/crates/graphql-orm-router/README.md index b71a2e74..2a3a888a 100644 --- a/crates/graphql-orm-router/README.md +++ b/crates/graphql-orm-router/README.md @@ -26,7 +26,7 @@ This unpublished package is Git-only: ```toml [dependencies] -graphql-orm-router = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.1.4" } +graphql-orm-router = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.2.0" } ``` Enable `auth-agql` only when adapting a separately configured @@ -68,6 +68,7 @@ composition warnings before serving. | Surface | Default or boundary | | --- | --- | | Authentication | Fail-closed; anonymous mode is explicit development-only. | +| Scope matching | Exact by default; hierarchical matching requires `auth-agql` and explicit file or programmatic configuration. | | Public path | `/graphql`; `/health` and `/readiness` are also exposed. | | Subgraphs | At least one static source; file configuration requires strict JSON. | | Dynamic registration | Disabled unless authenticated administration and exact network policy are configured. | diff --git a/crates/graphql-orm-router/docs/configuration.md b/crates/graphql-orm-router/docs/configuration.md index 08c5e1b0..98ae3628 100644 --- a/crates/graphql-orm-router/docs/configuration.md +++ b/crates/graphql-orm-router/docs/configuration.md @@ -58,6 +58,7 @@ an unbounded value. | `graphqlPath` | `/graphql`; absolute, non-root, without query or fragment. | | `anonymousDevelopment` | `false`; mutually exclusive with authentication and unsuitable for production. | | `authentication` | Required unless anonymous development is explicitly enabled. | +| `scopeMatcher` | Omitted means exact-string matching. `kind: "hierarchical"` requires the `auth-agql` feature. | | `subgraphs` | At least one static source is required. | | `forwardedHeaders` | Empty. Sensitive, hop-by-hop, cookie, and authorization names are rejected. | | `schemaFetchTimeoutMs` | 10000. | @@ -88,6 +89,25 @@ array. JWKS uses HTTPS. Plain HTTP is accepted only for loopback when The router validates RS256 public keys only. Configuration has no private-key, token-signing, session, refresh-token, or RSA-decryption field. +Scope matching is a separate resource-server policy. Omission or +`{"kind":"exact"}` preserves exact-string compatibility. With the +`auth-agql` feature, `kind: "hierarchical"` accepts these optional fields: + +| Field | Default or rule | +| --- | --- | +| `separator` | `.`; one visible character. | +| `wildcard` | `*`; one non-empty segment without whitespace. | +| `wildcardMatchesMultiSegment` | `true`; a trailing wildcard matches the remaining hierarchy. | +| `allowUniversalWildcard` | `false`; a bare wildcard has no implicit authority. | +| `superScopes` | Empty; each listed grant satisfies ordinary requirements. | +| `exactOnlyScopes` | Empty; each listed requirement accepts only an equal grant. | +| `exactOnlyScopePatterns` | Empty; matching resource-qualified requirements accept only equal grants. | + +Exact-only requirements are evaluated before super-scope and wildcard rules. +Lists are normalized and deduplicated at startup. The router applies this one +matcher to fixed and rendered operation requirements; resolver guards remain +authoritative. + For programmatic setup, `JwksAuthenticationConfig::new` requires a JWKS URL, issuer, and non-empty audiences. It defaults to a 15-minute key cache, 5-minute refresh interval, 5-second request timeout, 1 MiB JWKS body limit, diff --git a/crates/graphql-orm-router/examples/router.example.json b/crates/graphql-orm-router/examples/router.example.json index 0b9f6331..7fa1dde6 100644 --- a/crates/graphql-orm-router/examples/router.example.json +++ b/crates/graphql-orm-router/examples/router.example.json @@ -8,6 +8,9 @@ "refreshIntervalSeconds": 300, "cacheTtlSeconds": 900 }, + "scopeMatcher": { + "kind": "exact" + }, "subgraphs": [ { "name": "products", diff --git a/crates/graphql-orm-router/src/agql.rs b/crates/graphql-orm-router/src/agql.rs index f0ccfc93..89f99b50 100644 --- a/crates/graphql-orm-router/src/agql.rs +++ b/crates/graphql-orm-router/src/agql.rs @@ -19,9 +19,7 @@ impl AgqlAuthenticationProvider { /// Adapts the validator's exact or host-configured matcher to router policy. pub fn scope_matcher(&self) -> AgqlScopeMatcher { - AgqlScopeMatcher { - matcher: self.validator.scope_matcher(), - } + AgqlScopeMatcher::new(self.validator.scope_matcher()) } } @@ -60,6 +58,13 @@ pub struct AgqlScopeMatcher { matcher: Arc, } +impl AgqlScopeMatcher { + /// Adapts a host-configured `agql-auth` matcher to router policy. + pub fn new(matcher: Arc) -> Self { + Self { matcher } + } +} + impl fmt::Debug for AgqlScopeMatcher { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("AgqlScopeMatcher(..)") diff --git a/crates/graphql-orm-router/src/file_config.rs b/crates/graphql-orm-router/src/file_config.rs index 65498e47..d066cf3b 100644 --- a/crates/graphql-orm-router/src/file_config.rs +++ b/crates/graphql-orm-router/src/file_config.rs @@ -5,10 +5,16 @@ use std::{ use serde::Deserialize; +#[cfg(feature = "auth-agql")] +use agql_auth::{HierarchicalScopeMatch, HierarchicalScopeOptions}; + +#[cfg(feature = "auth-agql")] +use crate::AgqlScopeMatcher; use crate::{ - AdminConfig, JwksAuthenticationConfig, JwksAuthenticationProvider, LegacyScopeClaims, - NetworkCidr, NetworkPolicy, RequestLimits, RouterConfig, RouterError, RouterErrorKind, - RouterLogLevel, RouterTelemetryConfig, StaticSubgraph, SubscriptionConfig, TrustedSubgraph, + AdminConfig, ExactScopeMatcher, JwksAuthenticationConfig, JwksAuthenticationProvider, + LegacyScopeClaims, NetworkCidr, NetworkPolicy, RequestLimits, RouterConfig, RouterError, + RouterErrorKind, RouterLogLevel, RouterTelemetryConfig, StaticSubgraph, SubscriptionConfig, + TrustedSubgraph, }; const MAX_CONFIG_BYTES: u64 = 1024 * 1024; @@ -28,6 +34,7 @@ pub struct RouterFileConfig { #[serde(default)] anonymous_development: bool, authentication: Option, + scope_matcher: Option, subgraphs: Vec, #[serde(default)] forwarded_headers: Vec, @@ -89,6 +96,9 @@ impl RouterFileConfig { let mut config = RouterConfig::builder(listener) .with_graphql_path(self.graphql_path) .allow_anonymous_development(self.anonymous_development); + if let Some(scope_matcher) = self.scope_matcher { + config = scope_matcher.apply(config)?; + } if let Some(authentication) = self.authentication { let mut jwks = JwksAuthenticationConfig::new( authentication.jwks_url, @@ -263,6 +273,165 @@ struct FileAuthentication { allow_insecure_loopback_jwks: bool, } +/// File-owned scope policy. Omission and `kind: exact` preserve the router's +/// historical exact-string behavior. +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct FileScopeMatcher { + kind: FileScopeMatcherKind, + separator: Option, + wildcard: Option, + wildcard_matches_multi_segment: Option, + allow_universal_wildcard: Option, + #[serde(default)] + super_scopes: Vec, + #[serde(default)] + exact_only_scopes: Vec, + #[serde(default)] + exact_only_scope_patterns: Vec, +} + +#[derive(Clone, Copy, Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +enum FileScopeMatcherKind { + Exact, + Hierarchical, +} + +impl FileScopeMatcher { + fn apply(self, config: RouterConfig) -> Result { + match self.kind { + FileScopeMatcherKind::Exact => { + if self.separator.is_some() + || self.wildcard.is_some() + || self.wildcard_matches_multi_segment.is_some() + || self.allow_universal_wildcard.is_some() + || !self.super_scopes.is_empty() + || !self.exact_only_scopes.is_empty() + || !self.exact_only_scope_patterns.is_empty() + { + return Err(invalid( + "scopeMatcher kind `exact` does not accept hierarchical options", + )); + } + Ok(config.with_scope_matcher(Arc::new(ExactScopeMatcher))) + } + FileScopeMatcherKind::Hierarchical => build_hierarchical_scope_matcher( + config, + self.separator, + self.wildcard, + self.wildcard_matches_multi_segment, + self.allow_universal_wildcard, + self.super_scopes, + self.exact_only_scopes, + self.exact_only_scope_patterns, + ), + } + } +} + +#[cfg(feature = "auth-agql")] +#[allow(clippy::too_many_arguments)] +fn build_hierarchical_scope_matcher( + config: RouterConfig, + separator: Option, + wildcard: Option, + wildcard_matches_multi_segment: Option, + allow_universal_wildcard: Option, + mut super_scopes: Vec, + mut exact_only_scopes: Vec, + mut exact_only_scope_patterns: Vec, +) -> Result { + let defaults = HierarchicalScopeOptions::default(); + let separator = separator.unwrap_or(defaults.separator); + let wildcard = wildcard.unwrap_or(defaults.wildcard); + validate_scope_syntax(separator, &wildcard)?; + for (field, scopes) in [ + ("superScopes", super_scopes.as_slice()), + ("exactOnlyScopes", exact_only_scopes.as_slice()), + ( + "exactOnlyScopePatterns", + exact_only_scope_patterns.as_slice(), + ), + ] { + validate_scope_values(field, scopes)?; + } + super_scopes.sort(); + super_scopes.dedup(); + exact_only_scopes.sort(); + exact_only_scopes.dedup(); + exact_only_scope_patterns.sort(); + exact_only_scope_patterns.dedup(); + let options = HierarchicalScopeOptions::default() + .with_separator(separator) + .with_wildcard(wildcard) + .with_wildcard_matches_multi_segment( + wildcard_matches_multi_segment.unwrap_or(defaults.wildcard_matches_multi_segment), + ) + .with_allow_universal_wildcard( + allow_universal_wildcard.unwrap_or(defaults.allow_universal_wildcard), + ) + .with_super_scopes(super_scopes) + .with_exact_only_scopes(exact_only_scopes) + .with_exact_only_scope_patterns(exact_only_scope_patterns); + let matcher = HierarchicalScopeMatch::new(options).map_err(|error| { + invalid(format!( + "scopeMatcher hierarchical options are invalid: {error}" + )) + })?; + Ok(config.with_scope_matcher(Arc::new(AgqlScopeMatcher::new(Arc::new(matcher))))) +} + +#[cfg(not(feature = "auth-agql"))] +#[allow(clippy::too_many_arguments)] +fn build_hierarchical_scope_matcher( + _config: RouterConfig, + _separator: Option, + _wildcard: Option, + _wildcard_matches_multi_segment: Option, + _allow_universal_wildcard: Option, + _super_scopes: Vec, + _exact_only_scopes: Vec, + _exact_only_scope_patterns: Vec, +) -> Result { + Err(invalid( + "scopeMatcher kind `hierarchical` requires the `auth-agql` feature", + )) +} + +#[cfg(feature = "auth-agql")] +fn validate_scope_syntax(separator: char, wildcard: &str) -> Result<(), RouterError> { + if separator.is_whitespace() || separator.is_control() { + return Err(invalid("scopeMatcher separator must be visible")); + } + if wildcard.is_empty() + || wildcard.contains(separator) + || wildcard + .chars() + .any(|character| character.is_whitespace() || character.is_control()) + { + return Err(invalid( + "scopeMatcher wildcard must be a non-empty segment without whitespace", + )); + } + Ok(()) +} + +#[cfg(feature = "auth-agql")] +fn validate_scope_values(field: &str, scopes: &[String]) -> Result<(), RouterError> { + if scopes.iter().any(|scope| { + scope.is_empty() + || scope + .chars() + .any(|character| character.is_whitespace() || character.is_control()) + }) { + return Err(invalid(format!( + "scopeMatcher {field} contains an empty scope or whitespace" + ))); + } + Ok(()) +} + #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct FileSubgraph { @@ -561,6 +730,12 @@ mod tests { config.subgraphs[0].schema_headers["authorization"], "Bearer schema-secret" ); + assert!( + config + .scope_matcher + .matches("products.read", "products.read") + ); + assert!(!config.scope_matcher.matches("products.*", "products.read")); assert!(!format!("{config:?}").contains("schema-secret")); } @@ -574,4 +749,122 @@ mod tests { .is_err() ); } + + #[cfg(feature = "auth-agql")] + #[test] + fn hierarchical_file_matcher_applies_super_wildcard_and_exact_only_matrix() { + let json = FILE.replacen( + "\"authentication\":", + r#""scopeMatcher": { + "kind": "hierarchical", + "superScopes": ["platform.admin"], + "exactOnlyScopes": ["payments.credentials.release"], + "exactOnlyScopePatterns": ["payments.account.*.credentials.release"] + }, + "authentication":"#, + 1, + ); + let config = RouterFileConfig::from_json(&json) + .unwrap() + .into_router_config_with(|name| { + Ok((name == "PRODUCTS_SCHEMA_TOKEN").then(|| "Bearer secret".to_owned())) + }) + .unwrap(); + let matcher = config.scope_matcher; + + for (granted, required, expected) in [ + ("platform.admin", "orders.read", true), + ("orders.*", "orders.read", true), + ("orders.read", "orders.read", true), + ("platform.admin", "payments.credentials.release", false), + ("payments.*", "payments.credentials.release", false), + ( + "payments.credentials.release", + "payments.credentials.release", + true, + ), + ( + "platform.admin", + "payments.account.7.credentials.release", + false, + ), + ( + "payments.account.*", + "payments.account.7.credentials.release", + false, + ), + ( + "payments.account.7.credentials.release", + "payments.account.7.credentials.release", + true, + ), + ] { + assert_eq!( + matcher.matches(granted, required), + expected, + "grant {granted:?} for requirement {required:?}" + ); + } + } + + #[cfg(not(feature = "auth-agql"))] + #[test] + fn hierarchical_file_matcher_requires_auth_agql_feature() { + let json = FILE.replacen( + "\"authentication\":", + r#""scopeMatcher": {"kind": "hierarchical"}, + "authentication":"#, + 1, + ); + let error = RouterFileConfig::from_json(&json) + .unwrap() + .into_router_config_with(|name| { + Ok((name == "PRODUCTS_SCHEMA_TOKEN").then(|| "Bearer secret".to_owned())) + }) + .unwrap_err(); + assert!(error.to_string().contains("auth-agql")); + } + + #[test] + fn exact_file_matcher_rejects_hierarchical_options() { + let json = FILE.replacen( + "\"authentication\":", + r#""scopeMatcher": {"kind": "exact", "superScopes": ["platform.admin"]}, + "authentication":"#, + 1, + ); + let error = RouterFileConfig::from_json(&json) + .unwrap() + .into_router_config_with(|name| { + Ok((name == "PRODUCTS_SCHEMA_TOKEN").then(|| "Bearer secret".to_owned())) + }) + .unwrap_err(); + assert!( + error + .to_string() + .contains("kind `exact` does not accept hierarchical options") + ); + } + + #[cfg(feature = "auth-agql")] + #[test] + fn hierarchical_file_matcher_rejects_bare_wildcard_exact_only_pattern() { + let json = FILE.replacen( + "\"authentication\":", + r#""scopeMatcher": { + "kind": "hierarchical", + "allowUniversalWildcard": true, + "exactOnlyScopePatterns": ["*"] + }, + "authentication":"#, + 1, + ); + let error = RouterFileConfig::from_json(&json) + .unwrap() + .into_router_config_with(|name| { + Ok((name == "PRODUCTS_SCHEMA_TOKEN").then(|| "Bearer secret".to_owned())) + }) + .unwrap_err(); + assert!(error.to_string().contains("must not be the bare wildcard")); + } } diff --git a/crates/graphql-orm-storage/AGENTS.md b/crates/graphql-orm-storage/AGENTS.md index a506607c..8a41dc10 100644 --- a/crates/graphql-orm-storage/AGENTS.md +++ b/crates/graphql-orm-storage/AGENTS.md @@ -32,12 +32,12 @@ This crate is a reusable storage companion for applications that use `graphql-or ## Current Agent Handoff - Current crate version is `0.6.1`. -- The workspace resolves `graphql-orm` 0.22.1 and `graphql-orm-backup` 0.7.1 +- The workspace resolves `graphql-orm` 0.24.0 and `graphql-orm-backup` 0.7.1 through workspace path dependencies and one root `Cargo.lock`. Keep downstream companion packages on one reviewed monorepo revision. - `graphql-orm` owns the optional `agql-auth` integration, pinned at - `agql-auth` 0.15.0 revision - `e841ffd382082ad7419be259fe957f949b956ff7`; this crate does not depend on + `agql-auth` 0.16.0 revision + `3bc38cd94794f1e868a9cc3a5551047b95a32105`; this crate does not depend on application authorization. - The storage provider boundary is now the streaming `BlobStore` trait. - `ObjectStorage` extends `BlobStore`; custom providers must implement `BlobStore` first. diff --git a/crates/graphql-orm/Cargo.toml b/crates/graphql-orm/Cargo.toml index 3d12db14..d971757f 100644 --- a/crates/graphql-orm/Cargo.toml +++ b/crates/graphql-orm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "graphql-orm" -version = "0.23.0" +version = "0.24.0" edition = "2024" description = "Runtime support crate for graphql-orm-macros" license = "MIT" @@ -65,7 +65,7 @@ futures = "0.3" geo = { version = "0.33", optional = true, default-features = false } geo-types = { version = "0.7", optional = true } geojson = { version = "1", optional = true, default-features = true } -graphql-orm-macros = { path = "../graphql-orm-macros", version = "0.23.0", default-features = false } +graphql-orm-macros = { path = "../graphql-orm-macros", version = "0.24.0", default-features = false } graphql-orm-operation-catalog = { workspace = true } rust_decimal = { workspace = true } serde = { version = "1", features = ["derive"] } diff --git a/crates/graphql-orm/README.md b/crates/graphql-orm/README.md index 9fd6d25a..6317338c 100644 --- a/crates/graphql-orm/README.md +++ b/crates/graphql-orm/README.md @@ -29,7 +29,7 @@ backend: ```toml [dependencies] -graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", default-features = false, features = ["sqlite"] } +graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", default-features = false, features = ["sqlite"] } ``` This unpublished package has no docs.rs release. Use this Git README and the diff --git a/crates/graphql-orm/src/lib.rs b/crates/graphql-orm/src/lib.rs index 8b2ac422..849c2aae 100644 --- a/crates/graphql-orm/src/lib.rs +++ b/crates/graphql-orm/src/lib.rs @@ -508,7 +508,6 @@ pub mod types; /// pub name: String, /// } /// -/// fn main() {} /// ``` /// /// ...but generate no single-key write helpers: @@ -535,10 +534,8 @@ pub mod types; /// pub name: String, /// } /// -/// fn main() { -/// let _ = CompositeWriteRecord::create; -/// let _ = CompositeWriteRecord::update_by_id; -/// } +/// let _ = CompositeWriteRecord::create; +/// let _ = CompositeWriteRecord::update_by_id; /// ``` #[cfg(all(feature = "sqlite", not(any(feature = "postgres", feature = "mssql"))))] pub mod generated_api_absence_probes {} diff --git a/crates/graphql-orm/tests/backend_coexistence_fixture.rs b/crates/graphql-orm/tests/backend_coexistence_fixture.rs index 56e8b0cb..53c58559 100644 --- a/crates/graphql-orm/tests/backend_coexistence_fixture.rs +++ b/crates/graphql-orm/tests/backend_coexistence_fixture.rs @@ -66,13 +66,13 @@ fn assert_direct_host_dependency_resolves_one_exact_agql_auth_universe() { .filter(|package| package["name"] == "agql-auth") .collect::>(); assert_eq!(agql_auth.len(), 1, "resolved metadata:\n{metadata}"); - assert_eq!(agql_auth[0]["version"], "0.15.0"); + assert_eq!(agql_auth[0]["version"], "0.16.0"); let source = agql_auth[0]["source"] .as_str() .expect("agql-auth source must be present"); assert!( - source.contains("rev=e841ffd382082ad7419be259fe957f949b956ff7") - && source.ends_with("#e841ffd382082ad7419be259fe957f949b956ff7"), + source.contains("rev=3bc38cd94794f1e868a9cc3a5551047b95a32105") + && source.ends_with("#3bc38cd94794f1e868a9cc3a5551047b95a32105"), "unexpected agql-auth source: {source}", ); } diff --git a/crates/graphql-orm/tests/fixtures/backend-coexistence/Cargo.lock b/crates/graphql-orm/tests/fixtures/backend-coexistence/Cargo.lock index f400a5e7..9b77c1d5 100644 --- a/crates/graphql-orm/tests/fixtures/backend-coexistence/Cargo.lock +++ b/crates/graphql-orm/tests/fixtures/backend-coexistence/Cargo.lock @@ -10,8 +10,8 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "agql-auth" -version = "0.15.0" -source = "git+https://github.com/Dastari/agql-auth.git?rev=e841ffd382082ad7419be259fe957f949b956ff7#e841ffd382082ad7419be259fe957f949b956ff7" +version = "0.16.0" +source = "git+https://github.com/Dastari/agql-auth.git?rev=3bc38cd94794f1e868a9cc3a5551047b95a32105#3bc38cd94794f1e868a9cc3a5551047b95a32105" dependencies = [ "argon2", "async-graphql", @@ -1304,7 +1304,7 @@ dependencies = [ [[package]] name = "graphql-orm" -version = "0.23.0" +version = "0.24.0" dependencies = [ "agql-auth", "async-graphql", @@ -1329,7 +1329,7 @@ dependencies = [ [[package]] name = "graphql-orm-ai" -version = "0.82.0" +version = "0.89.0" dependencies = [ "agql-auth", "async-graphql", @@ -1357,7 +1357,7 @@ dependencies = [ [[package]] name = "graphql-orm-ai-tool-profiles" -version = "0.6.0" +version = "0.9.0" dependencies = [ "async-graphql", "async-graphql-parser", @@ -1372,7 +1372,7 @@ dependencies = [ [[package]] name = "graphql-orm-macros" -version = "0.23.0" +version = "0.24.0" dependencies = [ "convert_case", "proc-macro2", diff --git a/crates/graphql-orm/tests/fixtures/backend-coexistence/auth-service/Cargo.toml b/crates/graphql-orm/tests/fixtures/backend-coexistence/auth-service/Cargo.toml index a990f2bb..63a48838 100644 --- a/crates/graphql-orm/tests/fixtures/backend-coexistence/auth-service/Cargo.toml +++ b/crates/graphql-orm/tests/fixtures/backend-coexistence/auth-service/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] -agql-auth = { git = "https://github.com/Dastari/agql-auth.git", rev = "e841ffd382082ad7419be259fe957f949b956ff7", version = "0.15.0" } +agql-auth = { git = "https://github.com/Dastari/agql-auth.git", rev = "3bc38cd94794f1e868a9cc3a5551047b95a32105", version = "0.16.0" } async-graphql = { version = "7", features = ["dataloader", "uuid"] } graphql-orm = { path = "../../../../", default-features = false, features = [ "sqlite", diff --git a/crates/graphql-orm/tests/runtime_records.rs b/crates/graphql-orm/tests/runtime_records.rs index a06bc959..34553747 100644 --- a/crates/graphql-orm/tests/runtime_records.rs +++ b/crates/graphql-orm/tests/runtime_records.rs @@ -10,16 +10,16 @@ use graphql_orm::graphql::orm::{ use graphql_orm::graphql::orm::{RuntimeFieldState, RuntimeProjection}; #[cfg(feature = "sqlite")] -const _: () = assert!( +const _: [(); 1] = [(); ::RUNTIME_ROW_DECODING_SUPPORTED -); + as usize]; #[cfg(feature = "mssql")] -const _: () = assert!( +const _: [(); 1] = [(); !::RUNTIME_ROW_DECODING_SUPPORTED -); -const _: () = assert!( + as usize]; +const _: [(); 1] = [(); !::RUNTIME_ROW_DECODING_SUPPORTED -); + as usize]; fn collection_id(value: &str) -> CollectionId { CollectionId::new(value).expect("test collection ID") diff --git a/docs/plans/active/ai-production-readiness/README.md b/docs/plans/active/ai-production-readiness/README.md index f62b8685..3991e7d9 100644 --- a/docs/plans/active/ai-production-readiness/README.md +++ b/docs/plans/active/ai-production-readiness/README.md @@ -31,12 +31,12 @@ retention, or restore proofs remain closed. ## Dependencies -- `graphql-orm` 0.23.0 schema-module, transaction, fencing, operation-metadata, +- `graphql-orm` 0.24.0 schema-module, transaction, fencing, operation-metadata, and restore contracts. - `graphql-orm-backup` 0.7 snapshot, repository, verification, and restore orchestration. - `graphql-orm-storage` 0.6 streaming provider boundary. -- Exact external `agql-auth` 0.15 revision declared by the workspace. +- Exact external `agql-auth` 0.16 revision declared by the workspace. - Test-owned SQLite and disposable PostgreSQL infrastructure. ## Acceptance gates diff --git a/docs/reference/graphql-orm/agql-auth-bridge.md b/docs/reference/graphql-orm/agql-auth-bridge.md index a96ae698..2d486b36 100644 --- a/docs/reference/graphql-orm/agql-auth-bridge.md +++ b/docs/reference/graphql-orm/agql-auth-bridge.md @@ -16,13 +16,13 @@ supersedes: [] ## Dependency ```toml -graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", features = ["sqlite", "auth-agql"] } +graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", features = ["sqlite", "auth-agql"] } # Host applications may depend on agql-auth directly as well. The optional # graphql-orm auth-agql feature pins the exact upstream release: # git = "https://github.com/Dastari/agql-auth.git" -# rev = "e841ffd382082ad7419be259fe957f949b956ff7" -# version = "0.15.0" -agql-auth = { git = "https://github.com/Dastari/agql-auth.git", rev = "e841ffd382082ad7419be259fe957f949b956ff7", version = "0.15.0" } +# rev = "3bc38cd94794f1e868a9cc3a5551047b95a32105" +# version = "0.16.0" +agql-auth = { git = "https://github.com/Dastari/agql-auth.git", rev = "3bc38cd94794f1e868a9cc3a5551047b95a32105", version = "0.16.0" } ``` Both projects are intentionally Git-only. Cargo's crates.io packaging flow cannot package @@ -94,7 +94,7 @@ missing, or inconsistent assurance is omitted rather than repaired. ## Migrating from 0.7 -Update any direct `agql-auth` dependency to the exact 0.15 revision above. `AuthSubject` and +Update any direct `agql-auth` dependency to the exact 0.16 revision above. `AuthSubject` and `DbAuthContext` gained organization, correlation, and assurance fields; applications constructing either with struct literals must add the fields or use their builders/`Default` update syntax. The bridge preserves valid 0.8+ session assurance, active scope, correlation, @@ -103,7 +103,7 @@ of retaining only the older role/scope/tenant subset. ## Migrating from an Earlier Bridge Release -Update any direct `agql-auth` dependency to the exact 0.15.0 revision above at +Update any direct `agql-auth` dependency to the exact 0.16.0 revision above at the same time as `graphql-orm`. This prevents Cargo from resolving separate package/type universes. Version 0.22.0 keeps the identity, role, scope, tenant, organization, actor, correlation, token-reference, and policy-version mappings, @@ -112,7 +112,7 @@ copied, and malformed or token/session-inconsistent assurance is omitted. If a host consumed arbitrary `AuthSubject.claims.additional` values, move that data through an explicit application-owned request type instead of the ORM bridge. -Direct users of `agql-auth` must also review its migration through 0.15. Version +Direct users of `agql-auth` must also review its migration through 0.16. Version 0.11 replaces split durable rate-limit writes with the versioned atomic `AuthRateLimitStore` contract. `graphql-orm` does not implement that store and does not add a split or synthetic ORM-backed implementation. Version 0.12 adds @@ -128,6 +128,11 @@ hosts use agql-auth's `VerifiedActiveUserSessionResolver` and exact delegation binding directly. The resulting user-shaped principal continues through the ordinary bridge and resolver authorization without synthesizing a new session. +Version 0.16 adds consumer-supplied exact-only fixed requirements and patterns +to the hierarchical matcher. The ORM bridge continues projecting scopes +without choosing matcher policy; hosts opt into those semantics where they +construct their resource-server matcher. + Version 0.13 adds the policy ID, evaluation state/times, safe session status, denial categories, and policy-set contract consumed by the operation assurance evaluator. It does not change ordinary refresh eligibility. diff --git a/docs/reference/graphql-orm/backends.md b/docs/reference/graphql-orm/backends.md index 85fd0828..b022fb32 100644 --- a/docs/reference/graphql-orm/backends.md +++ b/docs/reference/graphql-orm/backends.md @@ -17,7 +17,7 @@ database schema. Schema ownership and migration behavior are controlled by runti ## Features ```toml -graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", default-features = false, features = ["sqlite"] } +graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", default-features = false, features = ["sqlite"] } ``` Available backend features: @@ -43,8 +43,8 @@ or managed RLS. See [Microsoft SQL Server](mssql.md). Optional non-backend features: -- `auth-agql` - optional one-way bridge from upstream `agql-auth` 0.15 - (`git` rev `e841ffd382082ad7419be259fe957f949b956ff7`) into `AuthSubject` / +- `auth-agql` - optional one-way bridge from upstream `agql-auth` 0.16 + (`git` rev `3bc38cd94794f1e868a9cc3a5551047b95a32105`) into `AuthSubject` / `DbAuthContext` and declared assurance evaluation. The `mssql` feature activates optional `tiberius`, `tokio-util`, and Tokio TCP support. Projects that diff --git a/docs/reference/graphql-orm/mssql.md b/docs/reference/graphql-orm/mssql.md index c7939822..1ef26a01 100644 --- a/docs/reference/graphql-orm/mssql.md +++ b/docs/reference/graphql-orm/mssql.md @@ -23,7 +23,7 @@ not provide an MSSQL driver. For a service that only uses SQL Server, select the `mssql` backend feature: ```toml -graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.23.0", default-features = false, features = ["mssql"] } +graphql-orm = { git = "https://github.com/Dastari/graphql-orm.git", rev = "", version = "0.24.0", default-features = false, features = ["mssql"] } ``` When exactly one of `sqlite`, `postgres`, or `mssql` is enabled, the legacy implicit backend remains diff --git a/docs/reference/workspace-packages.md b/docs/reference/workspace-packages.md index 9e4f1be3..1a4ca3d2 100644 --- a/docs/reference/workspace-packages.md +++ b/docs/reference/workspace-packages.md @@ -18,19 +18,19 @@ changes. | Package | Version | Path | Default features | Direct internal dependencies | | --- | --- | --- | --- | --- | -| `graphql-orm` | `0.23.0` | `crates/graphql-orm` | `sqlite` | `graphql-orm-macros`, `graphql-orm-operation-catalog`, `graphql-orm-router-protocol` (dev-only) | -| `graphql-orm-ai` | `0.88.0` | `crates/graphql-orm-ai` | `sqlite` | `graphql-orm`, `graphql-orm-ai-tool-profiles`, `graphql-orm-storage` | +| `graphql-orm` | `0.24.0` | `crates/graphql-orm` | `sqlite` | `graphql-orm-macros`, `graphql-orm-operation-catalog`, `graphql-orm-router-protocol` (dev-only) | +| `graphql-orm-ai` | `0.89.0` | `crates/graphql-orm-ai` | `sqlite` | `graphql-orm`, `graphql-orm-ai-tool-profiles`, `graphql-orm-storage` | | `graphql-orm-ai-tool-profiles` | `0.9.0` | `crates/graphql-orm-ai-tool-profiles` | none | `graphql-orm-operation-catalog`, `graphql-orm-router-protocol` (dev-only) | | `graphql-orm-backup` | `0.7.1` | `crates/graphql-orm-backup` | `local` | `graphql-orm` (optional), `graphql-orm-storage` | -| `graphql-orm-macros` | `0.23.0` | `crates/graphql-orm-macros` | `sqlite` | none | +| `graphql-orm-macros` | `0.24.0` | `crates/graphql-orm-macros` | `sqlite` | none | | `graphql-orm-operation-catalog` | `0.3.0` | `crates/graphql-orm-operation-catalog` | none | `graphql-orm-router-protocol` (optional) | -| `graphql-orm-router` | `0.1.4` | `crates/graphql-orm-router` | none | `graphql-orm-router-protocol` | +| `graphql-orm-router` | `0.2.0` | `crates/graphql-orm-router` | none | `graphql-orm-router-protocol` | | `graphql-orm-router-protocol` | `0.2.1` | `crates/graphql-orm-router-protocol` | none | none | | `graphql-orm-storage` | `0.6.1` | `crates/graphql-orm-storage` | `local` | none | External exact-revision dependency: -- `agql-auth` requirement `^0.15.0`, source `git+https://github.com/Dastari/agql-auth.git?rev=e841ffd382082ad7419be259fe957f949b956ff7`, consumed by `graphql-orm`, `graphql-orm-ai`, `graphql-orm-router`. +- `agql-auth` requirement `^0.16.0`, source `git+https://github.com/Dastari/agql-auth.git?rev=3bc38cd94794f1e868a9cc3a5551047b95a32105`, consumed by `graphql-orm`, `graphql-orm-ai`, `graphql-orm-router`.