Publish curated ITWorx-ModelForge source from 990401737f96c8d46a9f7b0d84994516cadcb6a0
This commit is contained in:
1 parent
7082ab955a
commit
848f0d8f8a
434 files changed
+67298
-4315
No files matched your search
@@ -0,0 +1,283 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import uuid
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import SecretStr
|
||||
from sqlalchemy import create_engine, delete, select
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from modelforge_api.api.authorization import Principal, PrincipalRole
|
||||
from modelforge_api.db import get_session
|
||||
from modelforge_api.domain.secret_slots import (
|
||||
SLOT,
|
||||
SecretSlotRevoke,
|
||||
SecretSlotSet,
|
||||
SecretSlotVersionRequest,
|
||||
)
|
||||
from modelforge_api.main import app
|
||||
from modelforge_api.persistence.models import (
|
||||
AuditEvent,
|
||||
Base,
|
||||
SecretSlotActivation,
|
||||
SecretSlotTest,
|
||||
SecretSlotVersion,
|
||||
)
|
||||
from modelforge_api.services import secret_slots as module
|
||||
from modelforge_api.services.audit import AuditContext
|
||||
from modelforge_api.services.configuration_changes import ConfigurationService
|
||||
from modelforge_api.settings import Settings, get_settings
|
||||
|
||||
ADMIN = Principal("recovery-admin", PrincipalRole.ADMIN, "legacy_admin_token")
|
||||
TOKEN = "hf_disposable_unit_test_only" # noqa: S105 - synthetic offline test data
|
||||
REASON = "Reviewed credential lifecycle"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def session():
|
||||
engine = create_engine("sqlite://", poolclass=StaticPool,
|
||||
connect_args={"check_same_thread": False})
|
||||
Base.metadata.create_all(engine)
|
||||
with Session(engine) as connection:
|
||||
yield connection
|
||||
engine.dispose()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def settings():
|
||||
return Settings(_env_file=None, env="test", hf_token="hf_deployment_test_only", # noqa: S106
|
||||
secret_slot_root_key=base64.b64encode(bytes(range(32))).decode())
|
||||
|
||||
|
||||
def service(session, settings, principal=ADMIN):
|
||||
return module.SecretSlotService(session, settings, principal, "slot-test-42")
|
||||
|
||||
|
||||
def candidate(subject, value=TOKEN):
|
||||
return subject.set(SecretSlotSet(expected_revision=subject.metadata().revision,
|
||||
reason=REASON, value=value))
|
||||
|
||||
|
||||
def request(metadata):
|
||||
return SecretSlotVersionRequest(expected_revision=metadata.revision,
|
||||
version=metadata.candidate_version, reason=REASON)
|
||||
|
||||
|
||||
def test_full_lifecycle_encryption_and_no_fallback(session, settings, monkeypatch):
|
||||
subject = service(session, settings)
|
||||
assert module.resolve_huggingface_token(session, settings) == settings.hf_token.get_secret_value()
|
||||
first = candidate(subject)
|
||||
assert first.state == "pending" and first.active_version is None
|
||||
row = session.get(SecretSlotVersion, 1)
|
||||
assert TOKEN not in row.secret_ciphertext
|
||||
with pytest.raises(module.SecretSlotError, match="explicitly activated"):
|
||||
module.resolve_huggingface_token(session, settings)
|
||||
with pytest.raises(module.SecretSlotError, match="successful test"):
|
||||
subject.activate(request(first))
|
||||
monkeypatch.setattr(module, "test_huggingface_token", lambda token: (token == TOKEN, "HF_AUTHENTICATED"))
|
||||
tested = subject.test(request(first))
|
||||
active = subject.activate(request(tested))
|
||||
assert active.state == "active"
|
||||
assert module.resolve_huggingface_token(session, settings) == TOKEN
|
||||
rotation = candidate(subject, "hf_replacement_test_only")
|
||||
assert module.resolve_huggingface_token(session, settings) == TOKEN
|
||||
monkeypatch.setattr(module, "test_huggingface_token", lambda token: (False, "HF_AUTHENTICATION_REJECTED"))
|
||||
failed = subject.test(request(rotation))
|
||||
assert failed.versions[0].test_status == "failed" and failed.active_version == 1
|
||||
revoked = subject.revoke(SecretSlotRevoke(expected_revision=failed.revision,
|
||||
confirm_slot=SLOT, reason=REASON))
|
||||
assert revoked.state == "revoked"
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
module.resolve_huggingface_token(session, settings)
|
||||
exported = ConfigurationService(session, settings, AuditContext("operator", "test", "c")).export()
|
||||
evidence = subject.catalog().model_dump_json() + exported.model_dump_json()
|
||||
evidence += str(list(session.scalars(select(AuditEvent.details))))
|
||||
assert SLOT in exported.secret_slots
|
||||
assert TOKEN not in evidence and row.secret_ciphertext not in evidence
|
||||
|
||||
|
||||
@pytest.mark.parametrize("role", [PrincipalRole.VIEWER, PrincipalRole.OPERATOR])
|
||||
def test_non_admin_cannot_modify(session, settings, role):
|
||||
subject = service(session, settings, Principal("person", role, "named_operator_key"))
|
||||
assert subject.catalog().slot.source == "deployment"
|
||||
with pytest.raises(module.SecretSlotError) as denied:
|
||||
candidate(subject)
|
||||
assert denied.value.status_code == 403
|
||||
assert subject.metadata().revision == 0
|
||||
|
||||
|
||||
def test_test_result_cannot_bless_concurrent_replacement(session, settings, monkeypatch):
|
||||
subject = service(session, settings)
|
||||
first = candidate(subject)
|
||||
def changed(token):
|
||||
candidate(subject, "hf_newer_candidate")
|
||||
return True, "HF_AUTHENTICATED"
|
||||
monkeypatch.setattr(module, "test_huggingface_token", changed)
|
||||
with pytest.raises(module.SecretSlotError) as conflict:
|
||||
subject.test(request(first))
|
||||
assert conflict.value.code == "SECRET_SLOT_VERSION_CONFLICT"
|
||||
assert subject.metadata().versions[0].test_status == "untested"
|
||||
|
||||
|
||||
def test_root_key_binding_and_recovery_quarantine(session, settings, monkeypatch):
|
||||
subject = service(session, settings)
|
||||
first = candidate(subject)
|
||||
monkeypatch.setattr(module, "test_huggingface_token", lambda token: (True, "HF_AUTHENTICATED"))
|
||||
active = subject.activate(request(subject.test(request(first))))
|
||||
for replacement in (None, SecretStr(base64.b64encode(b"x" * 32).decode())):
|
||||
changed = settings.model_copy(update={"secret_slot_root_key": replacement})
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
module.resolve_huggingface_token(session, changed)
|
||||
wrong_id = settings.model_copy(update={"secret_slot_root_key_id": "different-key"})
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
module.resolve_huggingface_token(session, wrong_id)
|
||||
# Supported recovery clears these exact current-truth tables; real restore is PG-qualified.
|
||||
session.execute(delete(SecretSlotActivation))
|
||||
session.execute(delete(SecretSlotTest))
|
||||
session.commit()
|
||||
assert subject.metadata().state == "quarantined"
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
module.resolve_huggingface_token(session, settings)
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
subject.activate(request(active))
|
||||
refreshed = subject.test(request(subject.metadata()))
|
||||
subject.activate(request(refreshed))
|
||||
assert module.resolve_huggingface_token(session, settings) == TOKEN
|
||||
|
||||
|
||||
def test_expired_evidence_and_audit_failure_do_not_activate(session, settings, monkeypatch):
|
||||
subject = service(session, settings)
|
||||
first = candidate(subject)
|
||||
monkeypatch.setattr(module, "test_huggingface_token", lambda token: (True, "HF_AUTHENTICATED"))
|
||||
tested = subject.test(request(first))
|
||||
session.get(SecretSlotTest, 1).tested_at = datetime.now(UTC) - timedelta(minutes=6)
|
||||
session.commit()
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
subject.activate(request(tested))
|
||||
tested = subject.test(request(tested))
|
||||
def unavailable(*args, **kwargs):
|
||||
raise RuntimeError("audit unavailable")
|
||||
monkeypatch.setattr(subject.audit, "write", unavailable)
|
||||
with pytest.raises(RuntimeError):
|
||||
subject.activate(request(tested))
|
||||
assert subject.metadata().active_version is None
|
||||
assert subject.metadata().revision == tested.revision
|
||||
|
||||
|
||||
class Body(httpx.SyncByteStream):
|
||||
def __init__(self, chunks):
|
||||
self.chunks = chunks
|
||||
def __iter__(self):
|
||||
yield from self.chunks
|
||||
|
||||
|
||||
@pytest.mark.parametrize("status,headers,chunks,expected", [
|
||||
(200, {}, [b'{"name":"local-test"}'], (True, "HF_AUTHENTICATED")),
|
||||
(401, {}, [], (False, "HF_AUTHENTICATION_REJECTED")),
|
||||
(302, {"location": "https://untrusted.invalid"}, [], (False, "HF_PROVIDER_UNAVAILABLE")),
|
||||
(200, {"content-encoding": "gzip"}, [], (False, "HF_RESPONSE_INVALID")),
|
||||
(200, {}, [b"x" * 65537], (False, "HF_RESPONSE_INVALID")),
|
||||
(200, {}, [b'{}'], (False, "HF_RESPONSE_INVALID")),
|
||||
(200, {}, [b"[" * 2000 + b"0" + b"]" * 2000], (False, "HF_RESPONSE_INVALID")),
|
||||
])
|
||||
def test_provider_check_is_fixed_bounded_and_redacted(monkeypatch, status, headers, chunks, expected):
|
||||
actual_client = httpx.Client
|
||||
calls = []
|
||||
def send(request):
|
||||
calls.append(request)
|
||||
return httpx.Response(status, headers=headers, stream=Body(chunks))
|
||||
def factory(**kwargs):
|
||||
assert kwargs["follow_redirects"] is False and kwargs["trust_env"] is False
|
||||
return actual_client(transport=httpx.MockTransport(send), **kwargs)
|
||||
monkeypatch.setattr(module.httpx, "Client", factory)
|
||||
assert module.test_huggingface_token(TOKEN) == expected
|
||||
assert len(calls) == 1 and str(calls[0].url) == "https://huggingface.co/api/whoami-v2"
|
||||
assert calls[0].headers["authorization"] == f"Bearer {TOKEN}"
|
||||
|
||||
|
||||
def test_provider_stream_has_total_deadline(monkeypatch):
|
||||
actual_client = httpx.Client
|
||||
def send(request):
|
||||
return httpx.Response(200, stream=Body([b'{"name":"local-test"}']))
|
||||
monkeypatch.setattr(module.httpx, "Client", lambda **kwargs: actual_client(
|
||||
transport=httpx.MockTransport(send), **kwargs))
|
||||
moments = iter([0.0, 11.0])
|
||||
monkeypatch.setattr(module.time, "monotonic", lambda: next(moments))
|
||||
assert module.test_huggingface_token(TOKEN) == (False, "HF_PROVIDER_TIMEOUT")
|
||||
|
||||
|
||||
def test_http_write_only_validation_and_no_store(session, settings):
|
||||
settings = settings.model_copy(update={"operator_api_key": SecretStr("local-anchor")})
|
||||
prior = dict(app.dependency_overrides)
|
||||
app.dependency_overrides[get_settings] = lambda: settings
|
||||
app.dependency_overrides[get_session] = lambda: session
|
||||
try:
|
||||
client = TestClient(app)
|
||||
url = "/api/v1/configuration/secret-slots"
|
||||
assert client.get(url).status_code == 401
|
||||
headers = {"X-ModelForge-Admin-Token": "local-anchor"}
|
||||
response = client.post(url + "/huggingface_control_plane/set", headers=headers,
|
||||
json={"expected_revision": 0, "reason": REASON, "value": TOKEN})
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.headers["cache-control"] == "no-store"
|
||||
assert TOKEN not in response.text
|
||||
invalid = client.post(url + "/huggingface_control_plane/set", headers=headers,
|
||||
json={"expected_revision": 1, "reason": TOKEN, "value": TOKEN + " "})
|
||||
assert invalid.status_code == 422 and TOKEN not in invalid.text
|
||||
metadata = client.get(url, headers=headers)
|
||||
assert metadata.status_code == 200 and TOKEN not in metadata.text
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
app.dependency_overrides.update(prior)
|
||||
|
||||
|
||||
def test_both_control_plane_consumers_resolve_active_snapshot(session, settings, monkeypatch):
|
||||
from modelforge_api.api.routes.acquisition import get_acquisition_service
|
||||
from modelforge_api.api.routes.agent import get_agent_acquisition_service
|
||||
from modelforge_api.services.registry import RegistryNotFound
|
||||
|
||||
subject = service(session, settings)
|
||||
first = candidate(subject)
|
||||
for consumer in (get_acquisition_service, get_agent_acquisition_service):
|
||||
local_service = consumer(session, settings)
|
||||
# Read-only persisted history and node progress must not require upstream credentials.
|
||||
with pytest.raises(RegistryNotFound, match="model revision not found"):
|
||||
local_service.artifact_sets(uuid.uuid4())
|
||||
with pytest.raises(module.SecretSlotError):
|
||||
local_service.provider.resolve()
|
||||
monkeypatch.setattr(module, "test_huggingface_token", lambda token: (True, "HF_AUTHENTICATED"))
|
||||
subject.activate(request(subject.test(request(first))))
|
||||
for consumer in (get_acquisition_service, get_agent_acquisition_service):
|
||||
resolved = consumer(session, settings)
|
||||
assert resolved.provider.resolve().token == TOKEN
|
||||
assert resolved.credential_configured is True
|
||||
|
||||
|
||||
def test_revoked_managed_admin_cannot_start_external_test(session, settings, monkeypatch):
|
||||
from modelforge_api.domain.managed_identity import ManagedIdentityCreate, ManagedIdentityRevoke
|
||||
from modelforge_api.services.operator_identities import (
|
||||
ManagedIdentityService,
|
||||
authenticate_managed_operator,
|
||||
)
|
||||
|
||||
manager = ManagedIdentityService(session, ADMIN, "identity-check")
|
||||
issued = manager.create(ManagedIdentityCreate(slug="alpha", role="admin",
|
||||
expires_in_days=1, expected_revision=0, reason=REASON))
|
||||
manager.create(ManagedIdentityCreate(slug="beta", role="admin",
|
||||
expires_in_days=1, expected_revision=1, reason=REASON))
|
||||
principal = authenticate_managed_operator(session, issued.one_time_key)
|
||||
session.commit()
|
||||
first = candidate(service(session, settings))
|
||||
manager.revoke("alpha", ManagedIdentityRevoke(expected_version=1,
|
||||
confirm_subject="managed:alpha", reason=REASON))
|
||||
def forbidden(token):
|
||||
pytest.fail("Revoked administrator must not trigger provider I/O")
|
||||
monkeypatch.setattr(module, "test_huggingface_token", forbidden)
|
||||
with pytest.raises(module.SecretSlotError) as rejected:
|
||||
service(session, settings, principal).test(request(first))
|
||||
assert rejected.value.status_code == 403
|
||||
Reference in new issue
Block a user