Skip to content

refactor(core): make resource structs the single source of truth for config schemas - #638

Merged
jarvis9443 merged 8 commits into
mainfrom
refactor/model-schema-single-source
Jun 23, 2026
Merged

refactor(core): make resource structs the single source of truth for config schemas#638
jarvis9443 merged 8 commits into
mainfrom
refactor/model-schema-single-source

Conversation

@jarvis9443

@jarvis9443 jarvis9443 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Problem

Each config resource had two independently hand-maintained schema representations in aisix-core: the runtime validator (a hand-written json! in models/schema.rs) and the schemars-derived struct (published to schemas/resources/*.json and vendored downstream). Nothing gated them against each other, so they drifted. The clearest symptom: the runtime rate_limit validator's $defs listed only 5 dimensions while the RateLimit struct and the rate limiter (aisix-ratelimit) support 7 — so a model carrying rate_limit.rps/rph was accepted by the published schema but silently dropped at the DP loader.

Change

The struct is now the single source of truth for all 8 validated resources (model, api_key, provider_key, guardrail, guardrail_attachment, cache_policy, observability_exporter, rate_limit_policy). Each resource's runtime validator AND dump-schema build from one *_root_schema() producer, so published == enforced by construction — the drift class is gone.

  • Per-field constraints moved onto the structs as schemars attributes (length/range/regex/inner).
  • Cross-field invariants schemars can't derive are injected by the producer: model's direct/routing/ensemble oneOf, rate_limit_policy's at-least-one-of anyOf, object_store's cloud-identity if/then/else.
  • Closed-set String fields became Rust enums where the consumer surface is small (PolicyScope/PolicyWindow, TelemetryKind). Guardrail's 6 moderation enums stay String with a producer-injected enum (15+ aisix-guardrails read sites make conversion churn-heavy); converting them is a possible follow-up.
  • Tagged-enum gotcha: schemars drops deny_unknown_fields inside internally-tagged oneOf branches, and serde doesn't enforce it there either — so the observability producer re-closes each branch with additionalProperties:false (restoring plaintext-secret rejection) and the guardrail producer re-closes its 3 tagged sub-defs.

Behavior changes (intended, documented per commit)

  • rate_limit.rps/rph now accepted on model + api_key (previously advertised but silently dropped).
  • observability_exporter: cross-kind field leakage (e.g. a datadog exporter carrying an otlp project) now rejected; no valid config mixes kinds.
  • rate_limit_policy: unknown scope/window now rejected at deserialize instead of silently ignored.
  • guardrail_attachment is now published (schemas/resources/guardrail_attachment.schema.json).

The client-facing proxy data API is unchanged.

Tests

A characterization (golden-corpus) test was added per resource, written against the old validators (green before the refactor) and kept green after, proving the config contract is preserved except the flips above. crates/aisix-core/tests/{model_schema,resource_schema}_characterization.rs.

Compatibility / follow-ups

  • The vendored schema copies in api7/AISIX-Cloud need a re-sync (separate change).
  • User-facing rps/rph also needs a paired CP + dashboard change (CP's write-time validator still rejects them).

Refs api7/AISIX-Cloud#788 (P0-1: configuration contract single source of truth).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added strongly-typed enums for rate-limit scope/window and telemetry kind to improve validation accuracy.
    • Introduced schema support for guardrail attachments.
  • Bug Fixes

    • Updated schema generation and rendering so variant titles/constraints are validated only where applicable.
    • Tightened JSON schema validation across resources (non-empty strings, numeric bounds/ranges, stricter patterns, and stricter additional-properties/conditional rules).
  • Tests

    • Added/expanded golden-corpus characterization tests to lock in accept/reject behavior for model, resource, and nested configurations.

Fixes api7/AISIX-Cloud#788

Pins the exact accept/reject behavior of validate_model across every
constraint the hand-written model_schema() enforces (oneOf mutual
exclusion, provider pattern/length, nested object bounds, additional-
Properties). This is the guardrail for collapsing the runtime validator
onto the Model struct + schemars so the refactor can prove it did not
widen or narrow the config contract. The rate_limit.rps/rph cases encode
today's (buggy) rejection and will flip to accept in the refactor.
…e source)

The model resource had two independently hand-maintained schema
representations in this crate: the runtime validator (a json! literal in
models/schema.rs) and the schemars-derived struct (published to
schemas/resources/ and vendored downstream). Nothing gated them against
each other, so they drifted — most visibly, the runtime validator's
$defs/rate_limit omitted rps/rph while the RateLimit struct and the rate
limiter (store/local.rs, store/redis.rs) support them, so a model
carrying rate_limit.rps was accepted by the published schema but silently
dropped at the DP loader.

Make the Model struct the single source: port every per-field constraint
(provider pattern/length, minLength, minItems, numeric ranges, status-code
item bounds) onto the struct as schemars attributes, and express the one
cross-field invariant schemars cannot derive (direct/routing/ensemble
mutual exclusion) as model_one_of(), injected by the new producer
model_root_schema(). Both the runtime validator and dump-schema call that
producer, so published == enforced by construction. option_add_null_type
is disabled for the model generation so optional fields stay
plain-but-absent (matching the wire shape) rather than nullable.

Behavior is preserved exactly (40-case characterization corpus) except
the intended fix: rps/rph are now accepted on both model and apikey
rate_limit. Regenerated model/ensemble/routing schemas reflect the
constraints now carried on the structs.

Other resources still use hand-written validators; migrating them to the
same producer pattern is follow-up work.
Continues the single-source migration (after model). Both runtime
validators now build from their structs via the shared struct_root_schema
producer; dump-schema emits the same object, so published == enforced.

- apikey: keeps nullable Option representation (team_id/user_id accept
  explicit null, which cp-api sends to clear team/owner); minLength(1) on
  key_hash/team_id/user_id ported as schemars attrs. Shared RateLimit now
  exposes all 7 dims incl rps/rph.
- cache_policy: minLength/maxLength on name/applies_to and the
  ttl_seconds 1..=604800 range ported as attrs. Struct has no
  deny_unknown_fields, so additionalProperties stays open (forward-compat).

Characterization corpora (resource_schema_characterization.rs) lock the
accept/reject behavior for both.
Adds PolicyScope/PolicyWindow Rust enums (closed sets that were enforced
only by the hand-written schema's enum constraint), so scope/window are
now struct-derived and rejected at deserialize. The one cross-field rule
schemars can't express — at least one of max_requests/max_tokens — is
injected as a top-level anyOf by rate_limit_policy_root_schema(). name/
scope_ref minLength and max_requests/max_tokens range(min=1) ported as
schemars attrs.

aisix-proxy/quota.rs now matches the enums exhaustively (drops the dead
String fall-through arms). Behavior change (intended): an unknown
scope/window is now rejected at deserialize instead of silently ignored.

Characterization corpus added for rate_limit_policy.
provider_key runtime validator now builds from the ProviderKey struct.
telemetry_tags.kind becomes a closed TelemetryKind enum (catalog|byo),
so the closed set is struct-derived and rejected at deserialize; the
usage-event provider_kind emission (chat/messages) maps it via as_str().
display_name/secret gain minLength(1). Nullable Option representation
kept (true) so cp-api's explicit null on telemetry labels still passes.
observability_exporter runtime validator now builds from the
ObservabilityExporter struct. schemars renders the internally-tagged
ExporterKind as a native top-level oneOf; the producer post-processes it
to (1) re-close each branch with additionalProperties:false — schemars
drops deny_unknown_fields in tagged-enum branches and serde doesn't
enforce it there, so this restores plaintext-secret rejection — copying
the shared name/enabled into each closed branch, and (2) inject the
object_store cloud-identity cross-field rule (if/then/else) schemars
can't derive. Per-field endpoint/site regex, project/logstore/bucket/etc
minLength, content_max_bytes caps ported as schemars attrs.

Intended tightening: cross-kind field leakage (e.g. a datadog exporter
carrying an otlp 'project') is now rejected; no valid config mixes kinds.

Characterization corpus added for observability_exporter.
…om structs

Final resources in the single-source migration. Both runtime validators
now build from their structs via *_root_schema() producers used by
dump-schema too (published == enforced).

guardrail: schemars renders the internally-tagged GuardrailKind as a
native oneOf; the top level + branches stay open (unknown inner fields
are caught by serde at deserialize, matching the old schema). The
producer (1) re-closes the tagged sub-enums KeywordPattern/
BedrockAWSCredentials/BedrockLatencyMode with additionalProperties:false
(schemars drops their deny_unknown_fields), (2) injects the closed enums
for the stringly-typed moderation fields (output_type/text_source/
stream_processing_mode/on_buffer_exceeded/risk_level_threshold/categories)
— kept as String since their values flow through aisix-guardrails as
strings; converting to Rust enums would churn that crate — and (3)
republishes created_at's date-time format. Per-field length/range attrs
(name, bedrock id/version/region, endpoints, api_key, severity_threshold
0..7, window_size, max_buffer_bytes, timeout_ms u32 cap) ported to the
structs.

guardrail_attachment: struct-derived (nullable scope_id), now also
published (it had no schemas/resources file before).

Characterization corpora added for both.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f37efdd-4855-4e11-b181-7cd6d326bc6f

📥 Commits

Reviewing files that changed from the base of the PR and between 497c1e7 and 23b022c.

📒 Files selected for processing (3)
  • crates/aisix-core/src/models/observability_exporter.rs
  • crates/aisix-core/tests/resource_schema_characterization.rs
  • schemas/resources/observability_exporter.schema.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • schemas/resources/observability_exporter.schema.json
  • crates/aisix-core/src/models/observability_exporter.rs
  • crates/aisix-core/tests/resource_schema_characterization.rs

📝 Walkthrough

Walkthrough

This PR replaces hand-written JSON schema constants with schemars-derived *_root_schema() producers for all resource types, introduces PolicyScope/PolicyWindow/TelemetryKind typed enums replacing raw strings, tightens schemars validation annotations across all model structs, adds cross-field invariant helpers (model_one_of, rate_limit_policy_any_of), regenerates all output JSON schema files, and adds golden-corpus characterization tests.

Changes

Schema generation and typed policy enums

Layer / File(s) Summary
Typed PolicyScope, PolicyWindow, TelemetryKind enums and proxy callsites
crates/aisix-core/src/models/rate_limit_policy.rs, crates/aisix-core/src/models/provider_key.rs, crates/aisix-core/src/models/mod.rs, crates/aisix-core/src/lib.rs, crates/aisix-proxy/src/quota.rs, crates/aisix-proxy/src/chat.rs, crates/aisix-proxy/src/messages.rs, crates/aisix-etcd/src/loader.rs
Introduces PolicyScope and PolicyWindow enums replacing scope: String / window: String on RateLimitPolicy; introduces TelemetryKind enum replacing Option<String> on TelemetryTags. Updates quota.rs to match on enum variants in policy_to_rate_limit, reserve_layers, and reserve_model_only. Adjusts provider_kind derivation in telemetry emission to call as_str().to_owned(). Expands module re-exports to include new types.
Schemars validation annotations on all resource model structs
crates/aisix-core/src/models/apikey.rs, crates/aisix-core/src/models/cache_policy.rs, crates/aisix-core/src/models/ensemble.rs, crates/aisix-core/src/models/guardrail.rs, crates/aisix-core/src/models/model.rs, crates/aisix-core/src/models/observability_exporter.rs, crates/aisix-core/src/models/provider_key.rs, crates/aisix-core/src/models/routing.rs, crates/aisix-core/src/models/rate_limit_policy.rs
Adds #[schemars(length(...))], #[schemars(range(...))], #[schemars(regex(...))], and #[schemars(inner(...))] attributes to fields across all resource model structs. Adds model_one_of() -> Value and rate_limit_policy_any_of() -> Value cross-field invariant helpers.
Schemars-derived root schema producers in schema.rs
crates/aisix-core/src/models/schema.rs
Replaces all private *_schema() hand-written JSON schema functions with public *_root_schema() producers backed by struct_root_schema<T>(nullable_options: bool). Adds post-processing to inject cross-field invariants (oneOf for model, anyOf for rate_limit_policy, if/then/else for observability_exporter), re-close tagged enum branches with additionalProperties: false, inject closed enum sets, and restore date-time format. Updates Schemas::compile to call the new producers.
dump-schema binary update
crates/aisix-core/src/bin/dump-schema.rs
Updates main() to emit resource schemas via dump_value() using the new *_root_schema() producers; restricts the generic dump::<T>() path to nested struct types (EnsembleConfig, RateLimit, Routing). Introduces the dump_value() entry point and updates imports.
Regenerated JSON schema files
schemas/resources/api_key.schema.json, schemas/resources/cache_policy.schema.json, schemas/resources/ensemble.schema.json, schemas/resources/guardrail.schema.json, schemas/resources/guardrail_attachment.schema.json, schemas/resources/model.schema.json, schemas/resources/observability_exporter.schema.json, schemas/resources/provider_key.schema.json, schemas/resources/rate_limit_policy.schema.json, schemas/resources/routing.schema.json
Regenerates all resource JSON schema files with tighter constraints: adds additionalProperties: false, removes null unions from non-nullable fields, introduces PolicyScope/PolicyWindow/TelemetryKind enum definitions, adds minLength/maxLength/minimum/maximum/minItems/pattern constraints throughout, introduces anyOf/if/then/else cross-field rules, and adds the new guardrail_attachment.schema.json.
OpenAPI post-processing: skip if/then/else and not subschemas
crates/aisix-admin/src/openapi.rs
Adds Model oneOf variant tab titles to add_variant_titles. Stops traversal into if/then/else subschemas in collect_missing_property_descriptions and stops traversal into not subschemas in collect_untitled_schema_variants.
Golden-corpus characterization tests
crates/aisix-core/tests/model_schema_characterization.rs, crates/aisix-core/tests/resource_schema_characterization.rs
Adds model_schema_characterization.rs with accept/reject helpers and exhaustive test cases for direct/routing/ensemble shapes, provider constraints, mutual exclusion, and nested object validation. Adds resource_schema_characterization.rs with a shared check helper and corpus test functions for all other resource validators.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Security Check ❌ Error ProviderKey.secret field lacks redaction in Debug/String/MarshalLogObject implementations; derives Debug directly without custom formatter, exposing API keys when logged with {:?} or via panic mess... Implement custom Debug formatter on ProviderKey that redacts the secret field (e.g., Debug impl { write!(f, "ProviderKey {{ secret: \"***\" ... }}")} ) or use a dedicated type wrapper with redacting Debug impl.
E2e Test Quality Review ⚠️ Warning Tests added are unit tests (schema validation only), not E2E tests. They lack full business flow coverage: no integration tests with etcd loader, admin API handlers, or runtime deserialization/beha... Add integration tests verifying the schema refactor through the complete data flow: etcd loader reading configs, validation, deserialization into Rust types, and passing through to downstream consumers (admin API, proxy).
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: making resource structs the single source of truth for configuration schemas, which is the core refactoring objective.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/model-schema-single-source

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (2)
crates/aisix-core/tests/resource_schema_characterization.rs (1)

543-770: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add guardrail regression cases for the tightened/conditional fields

Please add corpus entries to explicitly pin:

  • created_at: null behavior in guardrail_corpus (accept/reject, whichever is intended contract), and
  • non-env attachments with missing/null scope_id in guardrail_attachment_corpus.

This will keep these high-impact contract edges from drifting again.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aisix-core/tests/resource_schema_characterization.rs` around lines 543
- 770, Add regression test cases to the guardrail_corpus function to explicitly
test created_at with a null value and document whether it should pass or fail
validation. Additionally, add test cases to the guardrail_attachment_corpus
function for non-env scope types (such as model, team, and api_key) with missing
or null scope_id values to ensure these high-impact contract edges are properly
validated and prevent future drift. These edge cases should be documented with
descriptive test names that clearly indicate the expected validation behavior.
crates/aisix-core/tests/model_schema_characterization.rs (1)

253-280: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin explicit null rejection for non-null optional fields.

The schema refactor removes nullable unions for many optional model fields; add a small reject test so the golden corpus catches accidental re-widening later.

Example test
+#[test]
+fn reject_explicit_null_optional_fields() {
+    for (label, value) in [
+        (
+            "timeout null",
+            json!({"display_name": "m", "provider": "openai", "model_name": "g", "provider_key_id": "pk-1", "timeout": null}),
+        ),
+        (
+            "rate_limit null",
+            json!({"display_name": "m", "provider": "openai", "model_name": "g", "provider_key_id": "pk-1", "rate_limit": null}),
+        ),
+        (
+            "routing strategy null",
+            json!({"display_name": "r", "routing": {"targets": [{"model": "x"}], "strategy": null}}),
+        ),
+    ] {
+        reject(label, value);
+    }
+}
+
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aisix-core/tests/model_schema_characterization.rs` around lines 253 -
280, Add a new reject test function following the pattern of
reject_negative_timeout and reject_non_integer_timeout that explicitly tests
rejecting null values for optional non-null fields. Create a test that calls the
reject helper function with a JSON object where one of the optional fields (such
as timeout or allowed_cidrs) is set to null, providing a description like "null
timeout" or similar. This ensures that if someone accidentally re-widens the
schema to allow nullable unions, the golden corpus test will catch it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aisix-core/src/models/model.rs`:
- Around line 168-176: The documentation comment for the `provider` field
contains issue-tracker context (`#417` bug class reference) that is not
appropriate for public API reference documentation. Remove the phrase about
re-creating the `#417` bug class from the comment for the `provider` field, and
keep only the neutral, functional explanation of why the dot character is
accepted in the vendor identity pattern. This ensures the documentation remains
focused on API usage rather than internal implementation history.

In `@crates/aisix-core/src/models/schema.rs`:
- Around line 356-368: The JSON schema validation rule for `object_store` when
`is_object_store` is true does not fully enforce the documented contract. The
"then" branch currently only constrains the provider field to ["s3", "gcs"] when
auth_mode is "cloud_identity", but it does not forbid the credential_ref field
as stated in the documentation. Update the "then" branch object in the allOf
array to also add a constraint that forbids credential_ref (e.g., using "not": {
"required": ["credential_ref"] }) so that the schema properly rejects payloads
containing both auth_mode: "cloud_identity" and credential_ref together,
matching the documented behavior that cloud_identity must not have
credential_ref.

In `@schemas/resources/guardrail_attachment.schema.json`:
- Around line 32-52: The schema currently allows scope_id to be null or omitted
for all scope_type values, but the description indicates it should only be null
when scope_type is Env. To fix this, modify the guardrail_attachment schema to
enforce that scope_id is required and non-null for non-env scope types (model,
api_key, team). Use JSON Schema conditional constraints (such as if-then
patterns based on the scope_type value) or oneOf/anyOf patterns to define
separate validation rules: one allowing nullable scope_id when scope_type is
Env, and another requiring scope_id as a non-null string when scope_type is
model, api_key, or team.

In `@schemas/resources/guardrail.schema.json`:
- Around line 518-522: The `created_at` field in the guardrail schema currently
defines `"type": "string"` which breaks backward compatibility by rejecting null
values that existed in prior payloads. Update the type definition to accept both
string and null values by changing `"type": "string"` to `"type": ["string",
"null"]` to maintain backward compatibility while keeping the RFC3339 date-time
format validation for non-null values.

In `@schemas/resources/model.schema.json`:
- Around line 519-522: Remove the internal implementation detail reference to
Resource::name() from the display_name field description in the source model
definition (not the generated schema file), keeping only the external behavior
that is relevant to API consumers. Update the description to only document what
users observe when using the display_name field through the public API
endpoints, then regenerate the schemas/resources/model.schema.json file from the
updated source model documentation.

In `@schemas/resources/observability_exporter.schema.json`:
- Around line 261-264: The credential_ref field in the
observability_exporter.schema.json schema accepts empty strings, which will fail
during credential resolution. Add a minLength constraint of 1 to the
credential_ref field definition to reject empty string values, ensuring
consistency with how SLS and Datadog credential fields handle this validation
requirement.

In `@schemas/resources/provider_key.schema.json`:
- Around line 43-70: The descriptions for default_body_fields, default_headers,
param_constraints, and param_renames properties expose internal implementation
details and helper function names that should not be in public API
documentation. Remove references to internal function names like
apply_default_body_fields, apply_default_headers, and apply_param_renames, as
well as implementation details like serde_json::Map and etcd round-trip from
these descriptions. Update the source model documentation (where this schema is
generated from) to use clear public API reference text that describes what these
fields do from a user perspective, then regenerate this schema file.

In `@schemas/resources/rate_limit_policy.schema.json`:
- Around line 17-62: The JSON schema for rate_limit_policy has two issues: the
enum descriptions for PolicyScope and PolicyWindow contain Rustdoc link syntax
(backtick-bracket notation like [`RateLimitPolicy`]) that should not appear in
public API documentation, and the main properties (max_requests, max_tokens,
name, scope, scope_ref, and window) lack descriptions entirely. Update the
source model documentation to remove the Rustdoc syntax from the PolicyScope and
PolicyWindow enum descriptions and add clear, user-facing descriptions for each
property that explain their purpose in the rate limit policy. After updating the
source model, regenerate the JSON schema from the model to ensure the schema
consumers receive proper API reference documentation.

---

Nitpick comments:
In `@crates/aisix-core/tests/model_schema_characterization.rs`:
- Around line 253-280: Add a new reject test function following the pattern of
reject_negative_timeout and reject_non_integer_timeout that explicitly tests
rejecting null values for optional non-null fields. Create a test that calls the
reject helper function with a JSON object where one of the optional fields (such
as timeout or allowed_cidrs) is set to null, providing a description like "null
timeout" or similar. This ensures that if someone accidentally re-widens the
schema to allow nullable unions, the golden corpus test will catch it.

In `@crates/aisix-core/tests/resource_schema_characterization.rs`:
- Around line 543-770: Add regression test cases to the guardrail_corpus
function to explicitly test created_at with a null value and document whether it
should pass or fail validation. Additionally, add test cases to the
guardrail_attachment_corpus function for non-env scope types (such as model,
team, and api_key) with missing or null scope_id values to ensure these
high-impact contract edges are properly validated and prevent future drift.
These edge cases should be documented with descriptive test names that clearly
indicate the expected validation behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4cfdbc41-c639-44cf-8ea5-34655037608e

📥 Commits

Reviewing files that changed from the base of the PR and between 5bebe18 and 497c1e7.

📒 Files selected for processing (30)
  • crates/aisix-admin/src/openapi.rs
  • crates/aisix-core/src/bin/dump-schema.rs
  • crates/aisix-core/src/lib.rs
  • crates/aisix-core/src/models/apikey.rs
  • crates/aisix-core/src/models/cache_policy.rs
  • crates/aisix-core/src/models/ensemble.rs
  • crates/aisix-core/src/models/guardrail.rs
  • crates/aisix-core/src/models/mod.rs
  • crates/aisix-core/src/models/model.rs
  • crates/aisix-core/src/models/observability_exporter.rs
  • crates/aisix-core/src/models/provider_key.rs
  • crates/aisix-core/src/models/rate_limit_policy.rs
  • crates/aisix-core/src/models/routing.rs
  • crates/aisix-core/src/models/schema.rs
  • crates/aisix-core/tests/model_schema_characterization.rs
  • crates/aisix-core/tests/resource_schema_characterization.rs
  • crates/aisix-etcd/src/loader.rs
  • crates/aisix-proxy/src/chat.rs
  • crates/aisix-proxy/src/messages.rs
  • crates/aisix-proxy/src/quota.rs
  • schemas/resources/api_key.schema.json
  • schemas/resources/cache_policy.schema.json
  • schemas/resources/ensemble.schema.json
  • schemas/resources/guardrail.schema.json
  • schemas/resources/guardrail_attachment.schema.json
  • schemas/resources/model.schema.json
  • schemas/resources/observability_exporter.schema.json
  • schemas/resources/provider_key.schema.json
  • schemas/resources/rate_limit_policy.schema.json
  • schemas/resources/routing.schema.json

Comment thread crates/aisix-core/src/models/model.rs
Comment thread crates/aisix-core/src/models/schema.rs
Comment thread schemas/resources/guardrail_attachment.schema.json
Comment thread schemas/resources/guardrail.schema.json
Comment thread schemas/resources/model.schema.json
Comment thread schemas/resources/observability_exporter.schema.json
Comment thread schemas/resources/provider_key.schema.json
Comment thread schemas/resources/rate_limit_policy.schema.json
…t edges

Addresses review on #638:
- ObjectStoreConfig.credential_ref regained minLength(1) (the hand-written
  obs union enforced it on the shared credential_ref; SLS/Datadog already
  had it, object_store was missed) — an empty credential_ref is rejected
  again instead of failing later at credential resolution.
- Characterization corpus pins three contract edges raised in review:
  object_store empty credential_ref (reject), guardrail created_at:null
  (reject — the runtime validator always enforced non-null; cp-api omits
  it, never sends null), and non-env guardrail_attachment with null
  scope_id (accept — the validator never conditionally required scope_id).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant