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:
@@ -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,),
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user