Initial curated Unraid-AppOps-Gateway source from 3bd6f6fee310125bfbb4d4650389a817f498724d

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:35:57 +02:00
commit 1dfbca08a1
528 files changed
+131054

No files matched your search

+453
View File
@@ -0,0 +1,453 @@
from __future__ import annotations
import pytest
from sqlmodel import Session, SQLModel, create_engine, select
from backend.app.db.models import Enrollment, EnrollmentJob, Policy
from backend.app.schemas.enrollment import EnrollmentPlanV1, EnrollmentTrustConfigV1
from backend.app.services import enrollment_plane as enrollment_plane_module
from backend.app.services.enrollment_plane import EnrollmentPlane
from backend.app.services.secret_store import get_secret, set_secret
def _plan(**overrides):
value = {
"application_id": "wsbc-portal",
"display_name": "Windows Support Bundle Collector",
"repository": "Jens/Windows-Support-Bundle-Collector",
"revision": "a" * 40,
"profile": "internal-webapp-oidc",
"target": {"target_identity": "unraid-controller", "container_name": "wsbc-portal"},
"storage": {"runtime_uid": 1654, "runtime_gid": 1654},
"network": {"docker_network": "itworx-npm", "internal_port": 8080},
"artifact": {"release_version": "0.23.0", "image_repository": "wsbc-portal", "image_tag": "0.23.0"},
"exposure": {"hostname": "wsbc.example.com", "upstream_service": "wsbc-portal"},
"authentication": {
"mode": "native-oidc",
"redirect_path": "/signin-oidc",
"logout_path": "/signout-callback-oidc",
"roles": {"administrator": "Administrator", "support_agent": "SupportAgent", "read_only": "ReadOnly"},
},
"secrets": {"oidc_client_secret_required": True},
}
value.update(overrides)
return EnrollmentPlanV1.model_validate(value)
def _repopulse_plan(**overrides):
value = {
"application_id": "repopulse",
"display_name": "RepoPulse",
"environment": "production",
"repository": "Jens/RepoPulse",
"revision": "c" * 40,
"profile": "repopulse-authenticated",
"target": {"target_identity": "unraid-controller", "container_name": "repopulse"},
"storage": {"runtime_uid": 10001, "runtime_gid": 10001},
"network": {"docker_network": "itworx-mcp-hub-npm", "internal_port": 8000},
"artifact": {
"release_version": "1.5.0",
"image_repository": "repopulse-managed",
"image_tag": "production",
"health_path": "/health",
},
"exposure": {"hostname": "repopulse.example.com", "upstream_service": "repopulse"},
"secrets": {"additional_secret_refs": ["REPOPULSE_GITEA_TOKEN"]},
}
value.update(overrides)
return EnrollmentPlanV1.model_validate(value)
def _trust():
return EnrollmentTrustConfigV1.model_validate({
"controller_identity": "unraid-controller",
"bootstrap_secret_ref": "ENROLLMENT_BOOTSTRAP",
"approved_networks": ["itworx-npm", "itworx-mcp-hub-npm"],
"allowed_domain_suffixes": ["example.com"],
"autonomous_profiles": ["internal-webapp-oidc", "internal-webapp", "internal-service", "repopulse-authenticated"],
"repopulse_proxy_access_list_id": 42,
"oidc_issuer": "https://auth.example.com/application/o/wsbc-portal",
"administrator_group": "Administrator",
"support_agent_group": "SupportAgent",
"read_only_group": "ReadOnly",
})
class _Broker:
def is_configured(self):
return True
def enrollment_capabilities(self, *, secret):
assert secret == "b" * 64
return {"status": "ready"}
def enrollment_preflight(self, enrollment, *, secret):
assert secret == "b" * 64
assert "target_credential" not in enrollment
return {"status": "preflight_ok"}
def enroll_target(self, enrollment, *, secret, idempotency_key):
assert secret == "b" * 64
assert len(enrollment["target_credential"]) >= 48
assert enrollment["application_id"] == "wsbc-portal"
return {"status": "enrolled", "targetId": enrollment["enrollment_id"], "applicationId": "wsbc-portal"}
def configure_enrollment_runtime(self, runtime, *, secret):
assert len(secret) >= 48
assert set(runtime["values"]) == {"APPOPS_PUBLIC_URL", "OIDC_CLIENT_ID", "OIDC_CLIENT_SECRET", "OIDC_ISSUER", "OIDC_ROLE_CLAIM"}
return {"status": "configured", "enrollmentId": runtime["enrollment_id"], "applicationId": "wsbc-portal"}
class _Portainer:
def list_containers(self):
return {"status": "ok", "containers": []}
class _CollisionPortainer(_Portainer):
def list_containers(self):
return {"status": "ok", "containers": [{"name": "wsbc-portal"}]}
class _Npm:
def is_configured(self):
return True
def proxy_hosts(self):
return {"success": True, "items": []}
def ensure_managed_proxy_host(self, **kwargs):
assert kwargs["hostname"] == "wsbc.example.com"
assert kwargs["certificate_mode"] == "managed"
return {"success": True, "status": "created", "hostId": 10, "hostname": kwargs["hostname"]}
class _RepoPulseNpm(_Npm):
def __init__(self, *, access_list_ok=True):
self.access_list_ok = access_list_ok
self.validated_ids = []
self.created_host = None
def validate_managed_access_list(self, access_list_id):
self.validated_ids.append(access_list_id)
return {
"success": self.access_list_ok,
"status": "verified" if self.access_list_ok else "blocked",
"message": "required_access_list_verified" if self.access_list_ok else "required_access_list_unavailable",
**({"accessListId": access_list_id} if self.access_list_ok else {}),
}
def ensure_managed_proxy_host(self, **kwargs):
assert kwargs["hostname"] == "repopulse.example.com"
assert kwargs["forward_host"] == "repopulse"
assert kwargs["forward_port"] == 8000
assert kwargs["access_list_id"] == 42
self.created_host = dict(kwargs)
return {"success": True, "status": "created", "hostId": 10, "hostname": kwargs["hostname"]}
class _RepoPulseBroker(_Broker):
def __init__(self):
self.runtime_values = None
def enroll_target(self, enrollment, *, secret, idempotency_key):
assert secret == "b" * 64
assert enrollment["application_id"] == "repopulse"
assert enrollment["repository"] == "jens/repopulse"
assert enrollment["profile"] == "repopulse-authenticated"
assert enrollment["network"] == "itworx-mcp-hub-npm"
assert enrollment["runtime_uid"] == enrollment["runtime_gid"] == 10001
assert enrollment["image_repository"] == "repopulse-managed"
assert enrollment["image_tag"] == "production"
return {"status": "enrolled", "targetId": enrollment["enrollment_id"], "applicationId": "repopulse"}
def configure_enrollment_runtime(self, runtime, *, secret):
assert len(secret) >= 48
self.runtime_values = dict(runtime["values"])
assert set(self.runtime_values) == {
"REPOPULSE_GITEA_URL", "REPOPULSE_GITEA_TOKEN", "REPOPULSE_MAINTENANCE_TOKEN",
}
return {"status": "configured", "enrollmentId": runtime["enrollment_id"], "applicationId": "repopulse"}
class _Authentik:
def is_configured(self):
return True
def test_connection(self):
return {"status": "connected"}
def applications(self):
return {"success": True, "items": []}
def groups(self):
return {"success": True, "items": [{"name": "Administrator"}, {"name": "SupportAgent"}, {"name": "ReadOnly"}]}
def deployment_oidc_template_status(self, *, role_claim):
assert role_claim == "roles"
return {"status": "ready", "missing": []}
def ensure_deployment_oidc_application(self, **kwargs):
assert kwargs["application_slug"] == "wsbc-portal"
assert kwargs["client_secret"]
return {"success": True, "status": "created", "applicationId": "application-1", "providerId": "provider-1"}
def _session(tmp_path):
engine = create_engine(f"sqlite:///{tmp_path / 'enrollment.db'}")
SQLModel.metadata.create_all(engine)
return Session(engine)
def _plane(portainer=None, broker=None, npm=None, authentik=None):
return EnrollmentPlane(
broker=broker or _Broker(),
portainer=portainer or _Portainer(),
npm=npm or _Npm(),
authentik=authentik or _Authentik(),
)
def _configure(session):
set_secret(session, "ENROLLMENT_BOOTSTRAP", "b" * 64)
EnrollmentPlane.set_trust_config(session, _trust())
@pytest.fixture(autouse=True)
def _production_grade_secret_store(monkeypatch):
"""Plane unit tests exercise enrollment behavior with a managed key store."""
monkeypatch.setattr(
enrollment_plane_module,
"secret_storage_status",
lambda: {"status": "ready", "productionReady": True},
)
def test_enrollment_schema_rejects_plaintext_secrets_and_untrusted_topology():
raw = _plan().model_dump()
raw["target"]["command"] = "id"
try:
EnrollmentPlanV1.model_validate(raw)
except ValueError as exc:
assert "Extra inputs" in str(exc)
else: # pragma: no cover - assertion clarity
raise AssertionError("arbitrary target command must be rejected")
raw = _plan().model_dump()
raw["storage"]["appdata_subpath"] = "../etc"
try:
EnrollmentPlanV1.model_validate(raw)
except ValueError as exc:
assert "subpath" in str(exc)
else: # pragma: no cover - assertion clarity
raise AssertionError("appdata traversal must be rejected")
raw = _plan().model_dump()
raw["exposure"]["hostname"] = "*.example.com"
try:
EnrollmentPlanV1.model_validate(raw)
except ValueError as exc:
assert "hostname" in str(exc)
else: # pragma: no cover - assertion clarity
raise AssertionError("wildcard hostname must be rejected")
def test_repopulse_profile_accepts_only_its_fixed_authenticated_target():
plan = _repopulse_plan()
assert plan.application_id == "repopulse"
assert plan.repository == "jens/repopulse"
assert plan.network.docker_network == "itworx-mcp-hub-npm"
assert plan.secrets.additional_secret_refs == ("REPOPULSE_GITEA_TOKEN",)
for field, value in (
("application_id", "another-app"),
("repository", "Jens/another-app"),
("network", {"docker_network": "other-network", "internal_port": 8000}),
("artifact", {"release_version": "1.5.0", "image_repository": "repopulse-managed", "image_tag": "latest", "health_path": "/health"}),
("exposure", {"hostname": "other.example.com", "upstream_service": "repopulse"}),
("secrets", {"additional_secret_refs": ["OTHER_TOKEN"]}),
):
raw = _repopulse_plan().model_dump(mode="json")
raw[field] = value
with pytest.raises(ValueError):
EnrollmentPlanV1.model_validate(raw)
def test_repopulse_preflight_requires_existing_secret_and_trusted_npm_access_list(tmp_path):
with _session(tmp_path) as session:
_configure(session)
npm = _RepoPulseNpm(access_list_ok=False)
plane = _plane(npm=npm)
missing_secret = plane.preflight(session, _repopulse_plan())
assert missing_secret["status"] == "blocked"
assert "repopulse_gitea_token_unavailable" in missing_secret["blockers"]
assert npm.validated_ids == [42]
set_secret(session, "REPOPULSE_GITEA_TOKEN", "existing-encrypted-gitea-token")
bad_access_list = plane.preflight(session, _repopulse_plan())
assert bad_access_list["status"] == "blocked"
assert "repopulse_access_list_unavailable" in bad_access_list["blockers"]
assert session.exec(select(Enrollment)).all() == []
assert session.exec(select(EnrollmentJob)).all() == []
def test_repopulse_enrollment_seals_exact_runtime_values_without_exposing_secrets(tmp_path):
with _session(tmp_path) as session:
_configure(session)
gitea_token = "existing-encrypted-gitea-token"
set_secret(session, "REPOPULSE_GITEA_TOKEN", gitea_token)
npm = _RepoPulseNpm()
broker = _RepoPulseBroker()
result = _plane(broker=broker, npm=npm).enroll(
session, _repopulse_plan(), idempotency_key="enroll-repopulse-0001",
)
assert result["enrollment"]["status"] == "ready"
assert npm.validated_ids == [42]
assert npm.created_host["access_list_id"] == 42
assert broker.runtime_values["REPOPULSE_GITEA_URL"] == "https://gitea.example.com"
assert broker.runtime_values["REPOPULSE_GITEA_TOKEN"] == gitea_token
maintenance_token = get_secret(session, "ENROLL_REPOPULSE_MAINTENANCE_TOKEN")
assert maintenance_token and broker.runtime_values["REPOPULSE_MAINTENANCE_TOKEN"] == maintenance_token
assert gitea_token not in str(result)
assert maintenance_token not in str(result)
assert gitea_token not in str(result["job"]["evidence"])
assert maintenance_token not in str(result["job"]["evidence"])
def test_preflight_is_read_only_and_rejects_existing_container(tmp_path):
with _session(tmp_path) as session:
_configure(session)
result = _plane(_CollisionPortainer()).preflight(session, _plan())
assert result["status"] == "blocked"
assert "unmanaged_resource_collision" in result["blockers"]
assert session.exec(select(Enrollment)).all() == []
assert session.exec(select(EnrollmentJob)).all() == []
def test_preflight_rejects_the_development_secret_fallback(tmp_path, monkeypatch):
with _session(tmp_path) as session:
_configure(session)
monkeypatch.setattr(
enrollment_plane_module,
"secret_storage_status",
lambda: {"status": "ready", "productionReady": False},
)
result = _plane().preflight(session, _plan())
assert result["status"] == "blocked"
assert "secret_store" in result["blockers"]
assert session.exec(select(Enrollment)).all() == []
def test_capabilities_require_a_live_bootstrap_controller_contract(tmp_path):
with _session(tmp_path) as session:
_configure(session)
result = _plane().capabilities(session)
assert result["targetEnrollment"]["status"] == "ready"
assert result["controller"]["status"] == "ready"
def test_enrollment_creates_write_only_credentials_exact_policies_and_is_idempotent(tmp_path):
with _session(tmp_path) as session:
_configure(session)
plane = _plane()
result = plane.enroll(session, _plan(), idempotency_key="enroll-wsbc-portal-0001")
assert result["enrollment"]["status"] == "ready"
assert result["job"]["status"] == "ready"
assert result["enrollment"]["targetSecretRef"] == "ENROLL_WSBC_PORTAL_TARGET_HMAC"
assert result["enrollment"]["oidcSecretRef"] == "ENROLL_WSBC_PORTAL_OIDC_CLIENT_SECRET"
target_secret = get_secret(session, "ENROLL_WSBC_PORTAL_TARGET_HMAC")
oidc_secret = get_secret(session, "ENROLL_WSBC_PORTAL_OIDC_CLIENT_SECRET")
assert target_secret and oidc_secret
assert target_secret not in str(result)
assert oidc_secret not in str(result)
policies = session.exec(select(Policy).where(Policy.target == "wsbc-portal")).all()
assert {(policy.action, policy.target, policy.manual, policy.voice) for policy in policies} == {
("deployment.apply", "wsbc-portal", "allowed", "blocked"),
("deployment.rollback", "wsbc-portal", "allowed", "blocked"),
}
assert all(policy.provenance_json["enrollmentId"] == result["enrollment"]["id"] for policy in policies)
replay = plane.enroll(session, _plan(), idempotency_key="enroll-wsbc-portal-0001")
assert replay["idempotentReplay"] is True
assert replay["enrollment"]["id"] == result["enrollment"]["id"]
assert len(session.exec(select(Enrollment)).all()) == 1
assert len(session.exec(select(EnrollmentJob)).all()) == 1
def test_interrupted_external_enrollment_requires_explicit_recovery(tmp_path):
class InterruptedBroker(_Broker):
def enroll_target(self, _enrollment, *, secret, idempotency_key):
assert secret == "b" * 64
assert idempotency_key == "enroll-wsbc-interrupted-0001"
raise RuntimeError("controller connection interrupted after request dispatch")
with _session(tmp_path) as session:
_configure(session)
plane = _plane(broker=InterruptedBroker())
with pytest.raises(RuntimeError, match="interrupted"):
plane.enroll(session, _plan(), idempotency_key="enroll-wsbc-interrupted-0001")
job = session.exec(select(EnrollmentJob)).one()
assert job.status == "running"
assert job.stage == "registering_target"
assert job.evidence_json["intent"]["controller"]["applicationId"] == "wsbc-portal"
assert "target_credential" not in str(job.evidence_json)
recovered = plane.enroll(session, _plan(), idempotency_key="enroll-wsbc-interrupted-0001")
assert recovered["recoveryRequired"] is True
assert recovered["job"]["status"] == "recovery_required"
assert recovered["enrollment"]["status"] == "recovery_required"
def test_preflight_blocks_hostname_outside_root_trust_boundary(tmp_path):
with _session(tmp_path) as session:
_configure(session)
raw = _plan().model_dump()
raw["exposure"]["hostname"] = "wsbc.example.net"
result = _plane().preflight(session, EnrollmentPlanV1.model_validate(raw))
assert result["status"] == "blocked"
assert "hostname_not_allowed" in result["blockers"]
def test_preflight_rejects_an_oidc_role_model_outside_root_trust(tmp_path):
with _session(tmp_path) as session:
_configure(session)
raw = _plan().model_dump()
raw["authentication"]["roles"]["administrator"] = "TenantAdmin"
result = _plane().preflight(session, EnrollmentPlanV1.model_validate(raw))
assert result["status"] == "blocked"
assert "oidc_role_model" in result["blockers"]
def test_failed_identity_provisioning_compensates_only_created_resources(tmp_path):
class CompensatingBroker(_Broker):
def unenroll_target(self, target, *, secret):
assert target["application_id"] == "wsbc-portal"
assert secret == "b" * 64
return {"status": "rolled_back"}
class CompensatingNpm(_Npm):
def remove_managed_proxy_host(self, *, host_id, ownership_id):
assert host_id == 10
assert ownership_id.startswith("enr-")
return {"success": True, "status": "removed"}
class FailingAuthentik(_Authentik):
def ensure_deployment_oidc_application(self, **_kwargs):
return {"success": False, "status": "failed"}
with _session(tmp_path) as session:
_configure(session)
result = _plane(
broker=CompensatingBroker(),
npm=CompensatingNpm(),
authentik=FailingAuthentik(),
).enroll(session, _plan(), idempotency_key="enroll-wsbc-compensate-0001")
assert result["enrollment"]["status"] == "failed"
assert result["job"]["evidence"]["compensation"] == {
"completed": True,
"outcomes": {"proxy": "removed", "controller": "rolled_back"},
}
assert get_secret(session, "ENROLL_WSBC_PORTAL_TARGET_HMAC") is None
assert get_secret(session, "ENROLL_WSBC_PORTAL_OIDC_CLIENT_SECRET") is None
assert session.exec(select(Policy).where(Policy.target == "wsbc-portal")).all() == []