fix(model-registry): close review gaps in save-time validation

- add the missing rule-8 counterexample test: declared capabilities
  exceeding the adapter protocol are rejected with
  CAPABILITY_UNSUPPORTED_BY_ADAPTER (all eight section 9.2 checks now
  have at least one negative test)
- raise CREDENTIAL_NOT_CONFIGURED explicitly in _check_enabled_model
  when a required credential reference is null instead of relying on
  resolve_parameters call ordering
This commit is contained in:
m4
2026-07-21 09:38:37 +08:00
parent dbb6b7abde
commit 940db565b3
2 changed files with 42 additions and 1 deletions
+14 -1
View File
@@ -273,7 +273,20 @@ def _check_enabled_model(
)
auth_spec = spec.auth_specs[provider.auth.mode]
credential_revision = 0
if auth_spec.credential_required and provider.auth.credential_id is not None:
if auth_spec.credential_required:
if provider.auth.credential_id is None:
# resolve_parameters already rejects this case; raise explicitly
# here so the five-tuple check never depends on call ordering.
raise ModelRegistryError(
CREDENTIAL_NOT_CONFIGURED,
f"Auth mode {provider.auth.mode!r} requires a credential reference.",
details=[
{
"path": "auth.credential_id",
"code": CREDENTIAL_NOT_CONFIGURED,
}
],
)
row = connection.execute(
"SELECT current_revision FROM credential_pointers WHERE credential_id = ?",
(provider.auth.credential_id,),
+28
View File
@@ -443,6 +443,34 @@ def test_put_registry_rejects_unsupported_auth_mode(active_client):
assert response.json()["code"] == "AUTH_MODE_UNSUPPORTED"
def test_put_registry_rejects_capability_unsupported_by_adapter(active_client):
# Rule 8: declared capabilities must not exceed the adapter contract's
# protocol capabilities — the glm-5.2 contract declares vision=False.
registry = _current_registry(active_client)["registry"]
registry["providers"][0]["models"][0]["runtime"]["declared_capabilities"][
"vision"
] = True
response = _put(active_client, registry)
assert response.status_code == 422
body = response.json()
assert body["code"] == "CAPABILITY_UNSUPPORTED_BY_ADAPTER"
assert "providers[0].models[0]" in body["details"][0]["path"]
def test_put_registry_rejects_missing_credential_reference(active_client):
# The api_key AuthSpec requires a credential: credential_id=None must
# fail with CREDENTIAL_NOT_CONFIGURED, not a verification-tuple miss.
registry = _current_registry(active_client)["registry"]
registry["providers"][0]["auth"] = {"mode": "api_key", "credential_id": None}
response = _put(active_client, registry)
assert response.status_code == 422
body = response.json()
assert body["code"] == "CREDENTIAL_NOT_CONFIGURED"
assert "auth.credential_id" in body["details"][0]["path"]
def test_put_registry_rejects_defaults_to_disabled_model(active_client):
# With a bootstrap-state payload the schema-level check does not fire, so
# the store's rule-7 guard (enforced on every save) is what rejects it.