from __future__ import annotations import base64 import hashlib import json import threading import pytest from sqlmodel import Session, SQLModel, create_engine, select from backend.app.core.config import settings from backend.app.core.time import utc_now from backend.app.db.models import DeploymentJob, Policy from backend.app.schemas.enrollment import EnrollmentTrustConfigV1 from backend.app.schemas.forge_bootstrap_apply import ForgeBootstrapApplyV1 from backend.app.services.enrollment_plane import EnrollmentPlane from backend.app.services.forge_bootstrap_apply import ( ForgeBootstrapApplyError, ForgeBootstrapApplyService, canonical_preflight_receipt, forge_oidc_attestation_matches, ) from backend.app.services.secret_store import set_secret _REVISION = "a" * 40 _WORKSPACE_DIGEST = "sha256:" + "b" * 64 _FRONTDOOR_DIGEST = "sha256:" + "c" * 64 _PREFLIGHT_ID = "forge-preflight-0123456789abcdef" _SERVICE_HEALTH = ["api", "dashboard", "itworx-forge", "postgres", "worker"] _OIDC_OPENID_MAPPING_ID = "01234567-89ab-4cde-8fab-0123456789ab" _OIDC_EMAIL_MAPPING_ID = "21234567-89ab-4cde-8fab-0123456789ab" _OIDC_PROFILE_MAPPING_ID = "31234567-89ab-4cde-8fab-0123456789ab" _OIDC_PROVIDER_ID = "456" _OIDC_SIGNING_KEY_ID = "11234567-89ab-4cde-8fab-0123456789ab" _OIDC_FINGERPRINT = "ab" * 32 _OIDC_KEY_KID = base64.urlsafe_b64encode(bytes(range(64))).decode("ascii").rstrip("=") _OIDC_MAPPING_IDS = { "openid": _OIDC_OPENID_MAPPING_ID, "email": _OIDC_EMAIL_MAPPING_ID, "profile": _OIDC_PROFILE_MAPPING_ID, } _OIDC_MAPPING_EXPRESSION_SHA256 = { "openid": "38e58da331cc5378d4f269389242aecb80adf30093c405524dc1ab5aab9d452f", "email": "d1200eabeffc3b7f379e9c1636367b69befb0b1ac2b5d82b7be20e78667f2b94", "profile": "648b3f6dbf2212940309a581b239c9996562ca017a89be22bcfa93f9aa2c26ae", } _FORGE_PRIVATE_OWNER = "itworx-forge-private" _FORGE_SOURCE_URL = "https://gitea.example.com/Jens/itworx-forge" @pytest.fixture(autouse=True) def _forge_oidc_protected_pins(monkeypatch): apis = dict(settings.apis) apis["AUTHENTIK_FORGE_OIDC_BINDING_VALID"] = True apis["AUTHENTIK_FORGE_OIDC_PROVIDER_ID"] = _OIDC_PROVIDER_ID apis["AUTHENTIK_FORGE_OIDC_OPENID_CLAIM_MAPPING"] = _OIDC_OPENID_MAPPING_ID apis["AUTHENTIK_FORGE_OIDC_EMAIL_CLAIM_MAPPING"] = _OIDC_EMAIL_MAPPING_ID apis["AUTHENTIK_FORGE_OIDC_PROFILE_CLAIM_MAPPING"] = _OIDC_PROFILE_MAPPING_ID apis["AUTHENTIK_FORGE_OIDC_SIGNING_KEY_ID"] = _OIDC_SIGNING_KEY_ID apis["AUTHENTIK_OIDC_AUTHORIZATION_FLOW"] = "default-provider-authorization-implicit-consent" apis["AUTHENTIK_OIDC_INVALIDATION_FLOW"] = "default-provider-invalidation-flow" apis["FORGE_PRIVATE_PACKAGE_OWNER"] = _FORGE_PRIVATE_OWNER monkeypatch.setattr(settings, "apis", apis) def _oidc_attestation(): return { "issuer": "https://auth.example-host.com/application/o/itworx-forge/", "audience": "itworx-forge", "clientId": "itworx-forge", "clientType": "confidential", "callback": "https://forge.example.com/auth/callback", "applicationId": "41234567-89ab-4cde-8fab-0123456789ab", "providerId": _OIDC_PROVIDER_ID, "clientSecretMatched": True, "authorizationFlowId": "default-provider-authorization-implicit-consent", "invalidationFlowId": "default-provider-invalidation-flow", "roleGroups": ["forge-owners", "forge-operators", "forge-viewers"], "scopeMappingIds": _OIDC_MAPPING_IDS.copy(), "scopeMappingExpressionSha256": _OIDC_MAPPING_EXPRESSION_SHA256.copy(), "profileMappingName": "ITWorx Forge profile and groups claim v1", "standardMappingsManaged": True, "supportedScopes": ["email", "openid", "profile"], "authorizationCodeFlowSupported": True, "signingKeyId": _OIDC_SIGNING_KEY_ID, "signingKeyType": "RSA", "signingKeyPrivateAvailable": True, "signingKeyFingerprintSha256": _OIDC_FINGERPRINT, "signingKeyKid": _OIDC_KEY_KID, "tokenSigningAlgorithm": "RS256", "jwksKid": _OIDC_KEY_KID, } def _profile(**overrides): value = { "api_version": "itworx.forge-first-install/v1", "revision": _REVISION, "workspace_image_digest": _WORKSPACE_DIGEST, "frontdoor_image_digest": _FRONTDOOR_DIGEST, "preflight_job_id": _PREFLIGHT_ID, "preflight_sha256": "d" * 64, } value.update(overrides) return ForgeBootstrapApplyV1.model_validate(value) def _session(tmp_path): engine = create_engine(f"sqlite:///{tmp_path / 'forge-first-install.db'}") SQLModel.metadata.create_all(engine) return Session(engine) def _passed_preflight(session): profile = { "api_version": "itworx.forge-bootstrap-preflight/v1", "revision": _REVISION, "workspace_image_digest": _WORKSPACE_DIGEST, "frontdoor_image_digest": _FRONTDOOR_DIGEST, } check_names = { "deployment_apply_policy", "controller_trust", "managed_appdata_root_selection", "exact_main", "source_manifest", "managed_appdata", "proxy_network", "resource_collisions", "push_validation", "image_registry", "oidc", "secret_delivery", } job = DeploymentJob( id=_PREFLIGHT_ID, application_id="itworx-forge", repository="jens/itworx-forge", revision=_REVISION, plan_sha256=hashlib.sha256( json.dumps(profile, sort_keys=True, separators=(",", ":")).encode() ).hexdigest(), idempotency_sha256="e" * 64, status="preflight_succeeded", stage="preflight_complete", completed_at=utc_now(), plan_json=profile, preflight_json={ "apiVersion": "itworx.forge-bootstrap-preflight/v1", "status": "passed", "blockers": [], "unknowns": [], "checks": [{"name": name, "status": "passed", "detail": "passed"} for name in sorted(check_names)], }, evidence_json={ "profile": "forge-production-bootstrap", "policyId": "forge-apply-policy", "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, "controller": { "mainRevision": _REVISION, "attestations": { "push_validation": { "context": "Managed validation / full (push)", "conclusion": "success", "revision": _REVISION, }, "image_registry": { "owner": _FORGE_PRIVATE_OWNER, "ownerVisibility": "private", "workspaceDigest": _WORKSPACE_DIGEST, "frontdoorDigest": _FRONTDOOR_DIGEST, "workspacePullable": True, "frontdoorPullable": True, "workspaceSource": _FORGE_SOURCE_URL, "workspaceRevision": _REVISION, "frontdoorSource": _FORGE_SOURCE_URL, "frontdoorRevision": _REVISION, }, "oidc": _oidc_attestation(), "secret_delivery": { "requiredFilesReady": True, "metadataSha256": "f" * 64, }, }, }, }, ) session.add(job) session.commit() return job def _trust(session, *, controller_identity="unraid-controller"): EnrollmentPlane.set_trust_config( session, EnrollmentTrustConfigV1( controller_identity=controller_identity, bootstrap_secret_ref="CONTROLLER_BOOTSTRAP", trusted_appdata_root="/var/lib/docker/volumes/itworx-managed-appdata/_data", managed_appdata_backup_acknowledged=True, approved_networks=("itworx-mcp-hub-npm",), ), ) set_secret(session, "FORGE_DEPLOYMENT_BROKER", "f" * 40, commit=True) def _policy(session, *, manual="allowed"): session.add( Policy( id="forge-apply-policy", action="deployment.apply", target="itworx-forge", voice="blocked", manual=manual, risk="high", reason="explicit exact target", ) ) session.commit() def _success(request_id): return { "apiVersion": "itworx.forge-first-install/v1", "status": "deployed", "request": request_id, "repository": "jens/itworx-forge", "revision": _REVISION, "operation": "forge_first_install", "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, "receipt": { "revision": _REVISION, "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, "migration": {"service": "migrate", "status": "completed", "result": "succeeded"}, "health": {"status": "healthy", "services": _SERVICE_HEALTH}, }, } def _needs_credentials(request_id): return { "apiVersion": "itworx.forge-first-install/v1", "status": "needs_database_credentials", "request": request_id, "repository": "jens/itworx-forge", "revision": _REVISION, "operation": "forge_first_install", "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, } class _Broker: def __init__(self, response=None, status_response=None): self.response = response self.status_response = status_response self.apply_calls = [] self.status_calls = [] self.resume_calls = [] self.session = None def forge_bootstrap_apply(self, profile, *, idempotency_key, secret): assert self.session is not None request_id = ForgeBootstrapApplyService.request_id(profile, idempotency_key) rows = self.session.exec( select(DeploymentJob).where(DeploymentJob.broker_request_id == request_id) ).all() assert len(rows) == 1 assert rows[0].status == "applying" self.apply_calls.append((profile.model_dump(mode="json"), idempotency_key, secret)) if isinstance(self.response, Exception): raise self.response return self.response(request_id) if callable(self.response) else self.response def forge_bootstrap_status(self, request_id, *, secret): self.status_calls.append((request_id, secret)) if isinstance(self.status_response, Exception): raise self.status_response return self.status_response(request_id) if callable(self.status_response) else self.status_response def forge_bootstrap_resume(self, request_id, *, secret): rows = self.session.exec( select(DeploymentJob).where(DeploymentJob.broker_request_id == request_id) ).all() assert len(rows) == 1 assert rows[0].status == "applying" assert rows[0].stage == "resume_request_pending" self.resume_calls.append((request_id, secret)) if isinstance(self.response, Exception): raise self.response return self.response(request_id) if callable(self.response) else self.response def _service(session, broker): broker.session = session return ForgeBootstrapApplyService(broker=broker) def test_apply_profile_rejects_any_caller_selected_runtime_input(): _profile() for field, value in ( ("target", "other-host"), ("endpoint", "https://attacker.invalid"), ("secret_ref", "OTHER_SECRET"), ("command", "docker compose up"), ("host_path", "/etc"), ): with pytest.raises(ValueError): _profile(**{field: value}) def test_apply_rejects_preflight_hash_mismatch_before_controller_call(tmp_path): with _session(tmp_path) as session: job = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256="0" * 64) with pytest.raises(ForgeBootstrapApplyError, match="preflight receipt"): _service(session, broker).apply(session, profile, idempotency_key="forge-first-0001") assert broker.apply_calls == [] assert session.get(DeploymentJob, job.id) is not None assert len(session.exec(select(DeploymentJob).where(DeploymentJob.id.startswith("forge-install-"))).all()) == 0 def test_blocked_or_unknown_stored_preflight_cannot_submit_apply(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) preflight.preflight_json = { **preflight.preflight_json, "unknowns": ["image_registry"], } session.add(preflight) session.commit() _trust(session) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) with pytest.raises(ForgeBootstrapApplyError, match="no unknown checks"): _service(session, broker).apply(session, profile, idempotency_key="forge-first-0007") assert broker.apply_calls == [] def test_preflight_policy_binding_must_still_match_at_apply(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) session.delete(session.get(Policy, "forge-apply-policy")) session.add( Policy( id="changed-forge-apply-policy", action="deployment.apply", target="itworx-forge", voice="blocked", manual="allowed", risk="high", ) ) session.commit() broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) with pytest.raises(ForgeBootstrapApplyError, match="policy changed after preflight"): _service(session, broker).apply(session, profile, idempotency_key="forge-first-0008") assert broker.apply_calls == [] def test_stored_managed_root_trust_and_fixed_secret_are_required(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) with pytest.raises(ForgeBootstrapApplyError, match="managed-root trust"): _service(session, broker).apply(session, profile, idempotency_key="forge-first-0010") assert broker.apply_calls == [] @pytest.mark.parametrize("controller_identity", ["tower-deployment-controller", "other-controller"]) def test_foreign_controller_identity_blocks_before_install_intent(tmp_path, controller_identity): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session, controller_identity=controller_identity) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) with pytest.raises(ForgeBootstrapApplyError, match="managed-root trust"): _service(session, broker).apply( session, profile, idempotency_key="forge-controller-identity-0001" ) assert broker.apply_calls == [] assert session.exec(select(DeploymentJob)).all() == [preflight] @pytest.mark.parametrize( ("owner", "visibility"), [("another-owner", "private"), (_FORGE_PRIVATE_OWNER, "public")], ) def test_apply_rejects_registry_attestation_without_fixed_private_owner( tmp_path, owner, visibility ): with _session(tmp_path) as session: preflight = _passed_preflight(session) evidence = json.loads(json.dumps(preflight.evidence_json)) evidence["controller"]["attestations"]["image_registry"]["owner"] = owner evidence["controller"]["attestations"]["image_registry"]["ownerVisibility"] = visibility preflight.evidence_json = evidence session.add(preflight) session.commit() _trust(session) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) with pytest.raises(ForgeBootstrapApplyError, match="verified controller attestations"): _service(session, broker).apply( session, profile, idempotency_key="forge-first-private-owner-0001" ) assert broker.apply_calls == [] def test_apply_persists_before_post_and_only_marks_deployed_with_full_receipt(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) result = _service(session, broker).apply( session, profile, idempotency_key="forge-first-0002" ) assert result["status"] == "deployed" assert len(broker.apply_calls) == 1 request_id = result["request"] assert len(request_id) == 64 row = session.get(DeploymentJob, result["id"]) assert row is not None and row.broker_request_id == request_id assert row.evidence_json["controller"]["receipt"]["migration"]["result"] == "succeeded" def test_wrong_digest_or_incomplete_health_receipt_never_marks_deployed(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) response = _success("will-be-replaced") response["receipt"]["health"]["services"] = ["api", "dashboard", "itworx-forge", "postgres"] broker = _Broker(response=lambda request_id: {**response, "request": request_id}) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) result = _service(session, broker).apply( session, profile, idempotency_key="forge-first-0009" ) assert result["status"] == "outcome_unknown" assert result["evidence"]["controller"] == {} def test_same_idempotency_key_cannot_be_rebound_to_a_different_profile(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker(response=lambda request_id: _success(request_id)) service = _service(session, broker) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) service.apply(session, profile, idempotency_key="forge-first-0011") with pytest.raises(ForgeBootstrapApplyError, match="different Forge first-install profile"): service.apply( session, _profile(preflight_sha256="e" * 64), idempotency_key="forge-first-0011", ) assert len(broker.apply_calls) == 1 @pytest.mark.parametrize( ("application_id", "repository"), ( ("other-application", "jens/itworx-forge"), ("itworx-forge", "other/repository"), ), ) def test_idempotency_replay_rejects_existing_job_for_another_target( tmp_path, application_id, repository ): with _session(tmp_path) as session: profile = _profile() key = "forge-crossjob-0001" idempotency_digest = hashlib.sha256( f"forge-first-install:{key}".encode() ).hexdigest() plan = profile.model_dump(mode="json") session.add( DeploymentJob( id="unrelated-deployment-job", application_id=application_id, repository=repository, revision=_REVISION, plan_sha256=hashlib.sha256( json.dumps(plan, sort_keys=True, separators=(",", ":")).encode() ).hexdigest(), idempotency_sha256=idempotency_digest, status="failed", stage="complete", plan_json=plan, ) ) session.commit() broker = _Broker() with pytest.raises(ForgeBootstrapApplyError, match="different application or repository"): _service(session, broker).apply(session, profile, idempotency_key=key) assert broker.apply_calls == [] assert broker.status_calls == [] def test_integrity_error_replay_rejects_raced_job_for_another_target(tmp_path, monkeypatch): from sqlalchemy.exc import IntegrityError engine = create_engine(f"sqlite:///{tmp_path / 'forge-integrity-replay.db'}") SQLModel.metadata.create_all(engine) with Session(engine) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) key = "race-" + "replay-" + "fixture" idempotency_digest = hashlib.sha256( f"forge-first-install:{key}".encode() ).hexdigest() job_id = f"forge-install-{idempotency_digest}" plan = profile.model_dump(mode="json") broker = _Broker() original_commit = session.commit def insert_foreign_race_then_conflict(): session.rollback() with Session(engine) as competing_session: competing_session.add( DeploymentJob( id=job_id, application_id="itworx-forge", repository="other/repository", revision=_REVISION, plan_sha256=hashlib.sha256( json.dumps(plan, sort_keys=True, separators=(",", ":")).encode() ).hexdigest(), idempotency_sha256=idempotency_digest, status="failed", stage="complete", plan_json=plan, ) ) competing_session.commit() raise IntegrityError("simulated concurrent insert", {}, RuntimeError("duplicate")) monkeypatch.setattr(session, "commit", insert_foreign_race_then_conflict) with pytest.raises(ForgeBootstrapApplyError, match="different application or repository"): _service(session, broker).apply(session, profile, idempotency_key=key) assert broker.apply_calls == [] assert broker.status_calls == [] monkeypatch.setattr(session, "commit", original_commit) def test_broker_uses_fixed_forge_apply_resume_and_status_routes(monkeypatch): from backend.app.services.deployment_broker import DeploymentBrokerClient client = DeploymentBrokerClient(base_url="https://controller.example", verify_tls=True) calls = [] def request(method, path, **kwargs): calls.append((method, path, kwargs)) return {"status": "accepted"} monkeypatch.setattr(client, "_request", request) profile = _profile() client.forge_bootstrap_apply( profile, idempotency_key="forge-broker-0001", secret="s" * 40 ) client.forge_bootstrap_status("a" * 64, secret="s" * 40) client.forge_bootstrap_resume("a" * 64, secret="s" * 40) assert [(method, path) for method, path, _kwargs in calls] == [ ("POST", "/v1/appops/forge/bootstrap/apply"), ("GET", "/v1/appops/forge/bootstrap/status/" + "a" * 64), ("POST", "/v1/appops/forge/bootstrap/resume/" + "a" * 64), ] assert calls[0][2]["payload"] == { "profile": profile.model_dump(mode="json"), "idempotencyKey": "forge-broker-0001", } assert calls[2][2]["payload"] == {} def test_unknown_apply_outcome_reconciles_by_get_without_resubmitting(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker(response={"status": "unreachable"}) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) service = _service(session, broker) first = service.apply(session, profile, idempotency_key="forge-first-0003") assert first["status"] == "outcome_unknown" request_id = first["request"] broker.status_response = lambda _request_id: _success(request_id) reconciled = service.apply(session, profile, idempotency_key="forge-first-0003") assert reconciled["status"] == "deployed" assert len(broker.apply_calls) == 1 assert broker.status_calls == [(request_id, "f" * 40)] def test_preflight_changed_is_recorded_as_no_mutation(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker() profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) broker.response = lambda request_id: { "apiVersion": "itworx.forge-first-install/v1", "status": "preflight_changed", "request": request_id, "repository": "jens/itworx-forge", "revision": _REVISION, "operation": "forge_first_install", "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, "noMutation": True, } result = _service(session, broker).apply( session, profile, idempotency_key="forge-first-0004" ) assert result["status"] == "preflight_changed" assert result["evidence"]["controller"]["noMutation"] is True assert result["result"] == "Controller rejected changed Forge first-install preflight before mutation." def test_database_credentials_state_requires_explicit_resume_and_never_reposts_apply(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker() profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) service = _service(session, broker) broker.response = lambda request_id: _needs_credentials(request_id) first = service.apply(session, profile, idempotency_key="forge-first-0005") assert first["status"] == "needs_database_credentials" request_id = first["request"] assert len(broker.apply_calls) == 1 # Replaying apply only asks the durable read-only status endpoint. broker.status_response = lambda request: _needs_credentials(request) replay = service.apply(session, profile, idempotency_key="forge-first-0005") assert replay["status"] == "needs_database_credentials" assert len(broker.apply_calls) == 1 # Only the explicit resume call may submit the controller's one-shot resume. broker.response = lambda request: _success(request) resumed = service.resume(session, first["id"]) assert resumed["status"] == "deployed" assert len(broker.apply_calls) == 1 assert broker.resume_calls == [(request_id, "f" * 40)] def test_concurrent_explicit_resume_claims_only_once(tmp_path): engine = create_engine(f"sqlite:///{tmp_path / 'forge-concurrent-resume.db'}") SQLModel.metadata.create_all(engine) with Session(engine) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) initial_broker = _Broker(response=lambda request_id: _needs_credentials(request_id)) initial_broker.session = session profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) initial = ForgeBootstrapApplyService(broker=initial_broker).apply( session, profile, idempotency_key="forge-concurrent-resume-0001" ) assert initial["status"] == "needs_database_credentials" status_barrier = threading.Barrier(2) class ConcurrentBroker: def __init__(self): self.status_calls = [] self.resume_calls = [] self.lock = threading.Lock() def forge_bootstrap_status(self, request_id, *, secret): with self.lock: self.status_calls.append((request_id, secret)) status_barrier.wait(timeout=10) return _needs_credentials(request_id) def forge_bootstrap_resume(self, request_id, *, secret): with self.lock: self.resume_calls.append((request_id, secret)) return { "apiVersion": "itworx.forge-first-install/v1", "status": "accepted", "request": request_id, "repository": "jens/itworx-forge", "revision": _REVISION, "operation": "forge_first_install", "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, } broker = ConcurrentBroker() service = ForgeBootstrapApplyService(broker=broker) results = [] errors = [] def resume_in_own_session(): try: with Session(engine) as session: results.append(service.resume(session, initial["id"])) except Exception as exc: # noqa: BLE001 - surface thread failures in the assertion below. errors.append(exc) threads = [threading.Thread(target=resume_in_own_session) for _ in range(2)] for thread in threads: thread.start() for thread in threads: thread.join(timeout=20) assert all(not thread.is_alive() for thread in threads) assert errors == [] assert len(broker.status_calls) == 2 assert len(broker.resume_calls) == 1 assert all(result["status"] == "applying" for result in results) def test_stale_needs_credentials_get_cannot_reopen_claimed_resume(tmp_path): engine = create_engine(f"sqlite:///{tmp_path / 'forge-stale-resume-status.db'}") SQLModel.metadata.create_all(engine) with Session(engine) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) initial_broker = _Broker(response=lambda request_id: _needs_credentials(request_id)) initial_broker.session = session profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) initial = ForgeBootstrapApplyService(broker=initial_broker).apply( session, profile, idempotency_key="forge-stale-resume-0001" ) assert initial["status"] == "needs_database_credentials" post_started = threading.Event() release_post = threading.Event() class DelayedResumeBroker: def __init__(self): self.status_calls = [] self.resume_calls = [] def forge_bootstrap_status(self, request_id, *, secret): self.status_calls.append((request_id, secret)) return _needs_credentials(request_id) def forge_bootstrap_resume(self, request_id, *, secret): self.resume_calls.append((request_id, secret)) post_started.set() assert release_post.wait(timeout=10) return { "apiVersion": "itworx.forge-first-install/v1", "status": "accepted", "request": request_id, "repository": "jens/itworx-forge", "revision": _REVISION, "operation": "forge_first_install", "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, } broker = DelayedResumeBroker() service = ForgeBootstrapApplyService(broker=broker) first_result = [] first_errors = [] def first_resume(): try: with Session(engine) as session: first_result.append(service.resume(session, initial["id"])) except Exception as exc: # noqa: BLE001 - surface thread failures in the assertion below. first_errors.append(exc) first_thread = threading.Thread(target=first_resume) first_thread.start() assert post_started.wait(timeout=10) # The controller has not processed the first POST yet and still answers # needs_database_credentials. That stale observation cannot reset the # persisted local claim or authorize another resume POST. with Session(engine) as session: second_result = service.resume(session, initial["id"]) assert second_result["status"] == "outcome_unknown" assert second_result["stage"] == "resume_status_unresolved" release_post.set() first_thread.join(timeout=15) assert not first_thread.is_alive() assert first_errors == [] assert first_result[0]["status"] == "outcome_unknown" assert len(broker.status_calls) == 2 assert len(broker.resume_calls) == 1 def test_resume_refuses_without_signed_pre_migration_credentials_state(tmp_path): with _session(tmp_path) as session: preflight = _passed_preflight(session) _trust(session) _policy(session) broker = _Broker(response=lambda request: _success(request)) profile = _profile(preflight_sha256=canonical_preflight_receipt(preflight)) service = _service(session, broker) first = service.apply(session, profile, idempotency_key="forge-first-0006") assert first["status"] == "deployed" result = service.resume(session, first["id"]) assert result["status"] == "deployed" assert broker.resume_calls == [] def test_preflight_serialization_exposes_server_computed_receipt_digest(tmp_path): from backend.app.services.forge_bootstrap_preflight import ( ForgeBootstrapPreflightService, ) with _session(tmp_path) as session: job = _passed_preflight(session) serialized = ForgeBootstrapPreflightService.serialize_job(job) assert serialized["preflightSha256"] == canonical_preflight_receipt(job) def test_controller_passed_checks_require_profile_bound_attestations(monkeypatch): from backend.app.schemas.forge_bootstrap import ForgeBootstrapPreflightV1 from backend.app.services.forge_bootstrap_apply import _attestations_ready from backend.app.services.forge_bootstrap_preflight import ( _checked_controller_result, ) profile = ForgeBootstrapPreflightV1.model_validate( { "api_version": "itworx.forge-bootstrap-preflight/v1", "revision": _REVISION, "workspace_image_digest": _WORKSPACE_DIGEST, "frontdoor_image_digest": _FRONTDOOR_DIGEST, } ) checks = { name: {"status": "passed"} for name in ( "exact_main", "source_manifest", "managed_appdata", "proxy_network", "resource_collisions", "push_validation", "image_registry", "oidc", "secret_delivery", ) } result = { "apiVersion": "itworx.forge-bootstrap-preflight/v1", "status": "preflight_ok", "revision": _REVISION, "workspaceImageDigest": _WORKSPACE_DIGEST, "frontdoorImageDigest": _FRONTDOOR_DIGEST, "checks": checks, "evidence": {}, } assert _checked_controller_result(result, profile) is None result["evidence"] = { "attestations": { "push_validation": { "context": "Managed validation / full (push)", "conclusion": "success", "revision": _REVISION, }, "image_registry": { "owner": _FORGE_PRIVATE_OWNER, "ownerVisibility": "private", "workspaceDigest": _WORKSPACE_DIGEST, "frontdoorDigest": _FRONTDOOR_DIGEST, "workspacePullable": True, "frontdoorPullable": True, "workspaceSource": _FORGE_SOURCE_URL, "workspaceRevision": _REVISION, "frontdoorSource": _FORGE_SOURCE_URL, "frontdoorRevision": _REVISION, }, "oidc": _oidc_attestation(), "secret_delivery": {"requiredFilesReady": True, "metadataSha256": "f" * 64}, } } parsed = _checked_controller_result(result, profile) assert parsed is not None assert parsed[1]["attestations"]["image_registry"]["workspaceDigest"] == _WORKSPACE_DIGEST assert parsed[1]["attestations"]["oidc"] == _oidc_attestation() assert _attestations_ready(parsed[1], _profile()) for protected_owner in (None, "Jens", "owner.with.dot", "a" * 40): monkeypatch.setitem(settings.apis, "FORGE_PRIVATE_PACKAGE_OWNER", protected_owner) assert not _attestations_ready(parsed[1], _profile()) monkeypatch.setitem(settings.apis, "FORGE_PRIVATE_PACKAGE_OWNER", _FORGE_PRIVATE_OWNER) # A positive controller OIDC status is downgraded unless the signed proof # matches the independently configured AppOps mapping and signing-key IDs. result["evidence"]["attestations"]["oidc"]["scopeMappingIds"]["profile"] = "41234567-89ab-4cde-8fab-0123456789ab" parsed = _checked_controller_result(result, profile) assert parsed is not None assert next(item for item in parsed[0] if item["name"] == "oidc")["status"] == "blocked" assert "oidc" not in parsed[1].get("attestations", {}) result["evidence"]["attestations"]["oidc"] = _oidc_attestation() monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_PROFILE_CLAIM_MAPPING", None) parsed = _checked_controller_result(result, profile) assert parsed is not None assert next(item for item in parsed[0] if item["name"] == "oidc")["status"] == "blocked" monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_PROFILE_CLAIM_MAPPING", _OIDC_PROFILE_MAPPING_ID) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_SIGNING_KEY_ID", None) assert not _attestations_ready( {"attestations": {"oidc": _oidc_attestation()}}, _profile() ) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_SIGNING_KEY_ID", _OIDC_SIGNING_KEY_ID) for field, value in ( ("clientSecretMatched", False), ("scopeMappingExpressionSha256", {**_OIDC_MAPPING_EXPRESSION_SHA256, "profile": "0" * 64}), ("signingKeyPrivateAvailable", False), ("jwksKid", "attacker-kid"), ): original = _oidc_attestation() result["evidence"]["attestations"]["oidc"] = {**original, field: value} parsed = _checked_controller_result(result, profile) assert parsed is not None assert next(item for item in parsed[0] if item["name"] == "oidc")["status"] == "blocked" result["evidence"]["attestations"]["oidc"] = _oidc_attestation() result["evidence"]["attestations"]["image_registry"]["ownerVisibility"] = "public" assert _checked_controller_result(result, profile) is None result["evidence"]["attestations"]["image_registry"]["ownerVisibility"] = "private" result["evidence"]["attestations"]["image_registry"]["owner"] = "unreviewed-owner" assert _checked_controller_result(result, profile) is None result["evidence"]["attestations"]["image_registry"]["owner"] = _FORGE_PRIVATE_OWNER result["evidence"]["attestations"]["image_registry"]["workspaceSource"] = "https://attacker.invalid/repo" assert _checked_controller_result(result, profile) is None result["evidence"]["attestations"]["image_registry"]["workspaceSource"] = _FORGE_SOURCE_URL result["evidence"]["attestations"]["image_registry"]["frontdoorRevision"] = "d" * 40 assert _checked_controller_result(result, profile) is None result["evidence"]["attestations"]["image_registry"]["frontdoorRevision"] = _REVISION result["evidence"]["attestations"]["image_registry"]["workspaceDigest"] = _FRONTDOOR_DIGEST assert _checked_controller_result(result, profile) is None result["evidence"]["attestations"]["image_registry"]["workspaceDigest"] = _WORKSPACE_DIGEST result["evidence"]["attestations"]["secret_delivery"]["metadataSha256"] = "not-a-digest" assert _checked_controller_result(result, profile) is None def test_controller_oidc_attestation_accepts_authentik_legacy_kid(): legacy_kid = "8cf5f32a6c6d9a876fd0284980a25ce0" attestation = { **_oidc_attestation(), "signingKeyKid": legacy_kid, "jwksKid": legacy_kid, } assert forge_oidc_attestation_matches(attestation) def test_controller_oidc_attestation_binds_exact_scope_mappings_and_discovery(): valid = _oidc_attestation() assert forge_oidc_attestation_matches(valid) for invalid in ( {**valid, "mappingId": _OIDC_PROFILE_MAPPING_ID}, {**valid, "mappingName": "legacy claim"}, {**valid, "mappingScope": "groups"}, {**valid, "mappingExpressionSha256": "0" * 64}, {**valid, "scopeMappingIds": {"openid": _OIDC_OPENID_MAPPING_ID}}, { **valid, "scopeMappingIds": { "openid": _OIDC_EMAIL_MAPPING_ID, "email": _OIDC_OPENID_MAPPING_ID, "profile": _OIDC_PROFILE_MAPPING_ID, }, }, {**valid, "scopeMappingIds": {**_OIDC_MAPPING_IDS, "profile": _OIDC_EMAIL_MAPPING_ID}}, {**valid, "scopeMappingIds": {**_OIDC_MAPPING_IDS, "email": _OIDC_OPENID_MAPPING_ID}}, {**valid, "supportedScopes": ["email", "groups", "openid", "profile"]}, {**valid, "supportedScopes": ["email", "openid"]}, {**valid, "authorizationCodeFlowSupported": 1}, {**valid, "standardMappingsManaged": 1}, {**valid, "profileMappingName": "stock profile"}, {**valid, "applicationId": "123"}, {**valid, "providerId": "457"}, ): assert not forge_oidc_attestation_matches(invalid) def test_controller_oidc_attestation_requires_current_protected_scope_binding(monkeypatch): attestation = _oidc_attestation() assert forge_oidc_attestation_matches(attestation) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_BINDING_VALID", 1) assert not forge_oidc_attestation_matches(attestation) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_BINDING_VALID", True) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_PROVIDER_ID", "0456") assert not forge_oidc_attestation_matches(attestation) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_PROVIDER_ID", _OIDC_PROVIDER_ID) monkeypatch.setitem(settings.apis, "AUTHENTIK_FORGE_OIDC_EMAIL_CLAIM_MAPPING", _OIDC_OPENID_MAPPING_ID) assert not forge_oidc_attestation_matches(attestation) def test_controller_oidc_attestation_requires_canonical_sha512_kid(): assert forge_oidc_attestation_matches(_oidc_attestation()) noncanonical_kid = "A" * 85 + "B" assert not forge_oidc_attestation_matches( { **_oidc_attestation(), "signingKeyKid": noncanonical_kid, "jwksKid": noncanonical_kid, } )