Publish curated Unraid-AppOps-Gateway source from 68878c3167dacf2b424c16780e60e0d60815e477
This commit is contained in:
1 parent
837c263cd8
commit
551de41e9f
18 files changed
+1183
-58
No files matched your search
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from sqlmodel import Session, SQLModel, create_engine
|
||||
|
||||
from backend.app.db.models import Policy
|
||||
@@ -28,6 +29,7 @@ def _plan(**overrides):
|
||||
"proxy": {"hostname": "support.example.com"},
|
||||
"oidc": {
|
||||
"application_slug": "wsbc-portal",
|
||||
"role_claim": "roles",
|
||||
"client_secret_ref": "WSBC_PORTAL_OIDC_CLIENT_SECRET",
|
||||
"roles": {
|
||||
"administrator_group": "Administrator",
|
||||
@@ -72,6 +74,18 @@ class _Npm:
|
||||
|
||||
|
||||
class _Authentik:
|
||||
def configure_deployment_oidc_template(self, config, *, issuer_origin=None):
|
||||
self.template_config = config
|
||||
self.template_issuer = issuer_origin
|
||||
|
||||
def validate_deployment_oidc_template(self, *, role_claim, role_groups):
|
||||
assert role_claim == "roles"
|
||||
assert role_groups == ("Administrator", "SupportAgent", "ReadOnly")
|
||||
return {"status": "ready"}
|
||||
|
||||
def groups(self):
|
||||
return {"success": True, "items": [{"name": name} for name in ("Administrator", "SupportAgent", "ReadOnly")]}
|
||||
|
||||
def test_connection(self):
|
||||
return {"status": "connected"}
|
||||
|
||||
@@ -343,3 +357,138 @@ def test_deployment_evidence_uses_allowlists_and_never_persists_connector_secret
|
||||
assert "broker-secret" not in str(result)
|
||||
assert "npm-secret" not in str(result)
|
||||
assert "oidc-secret" not in str(result)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("swapped_roles", [False, True])
|
||||
def test_saved_root_template_is_used_by_existing_deployment_plan(tmp_path, monkeypatch, swapped_roles):
|
||||
from uuid import uuid4
|
||||
from backend.app.core.config import settings
|
||||
from backend.app.db.models import AppSetting
|
||||
from backend.app.schemas.enrollment import EnrollmentTrustConfigV1
|
||||
from backend.app.services.enrollment_oidc_settings import EnrollmentOidcProfileV1, TEMPLATE_FIELDS
|
||||
|
||||
monkeypatch.setattr(settings, "authentik_issuer", "https://auth.example.com/application/o/appops-users/")
|
||||
profile = EnrollmentOidcProfileV1(issuer="https://auth.example.com", **{field: uuid4() for field in TEMPLATE_FIELDS})
|
||||
|
||||
class SavedTemplateAuthentik(_Authentik):
|
||||
def validate_deployment_oidc_template(self, **kwargs):
|
||||
assert self.template_config == profile.template_config()
|
||||
# Authentik emits the same filtered set for any permutation. The
|
||||
# orchestrator must separately preserve named root role meanings.
|
||||
assert kwargs["role_claim"] == "roles"
|
||||
assert set(kwargs["role_groups"]) == {"Administrator", "SupportAgent", "ReadOnly"}
|
||||
return {"status": "ready"}
|
||||
|
||||
def ensure_deployment_oidc_application(self, **kwargs):
|
||||
assert self.template_config == profile.template_config()
|
||||
return super().ensure_deployment_oidc_application(**kwargs)
|
||||
|
||||
with _session(tmp_path) as session:
|
||||
trust = EnrollmentTrustConfigV1(
|
||||
controller_identity="unraid-controller", bootstrap_secret_ref="ENROLLMENT_BOOTSTRAP",
|
||||
approved_networks=("itworx-npm",), allowed_domain_suffixes=("example.com",),
|
||||
oidc_issuer=profile.issuer, administrator_group="Administrator",
|
||||
support_agent_group="SupportAgent", read_only_group="ReadOnly",
|
||||
)
|
||||
session.add(AppSetting(key="deployment_enrollment:trust", value_json=trust.model_dump(mode="json")))
|
||||
session.add(AppSetting(key="deployment_enrollment:oidc_template", value_json=profile.model_dump(mode="json")))
|
||||
session.commit()
|
||||
plane = _plane()
|
||||
plane.authentik = SavedTemplateAuthentik()
|
||||
plan = _plan()
|
||||
if swapped_roles:
|
||||
oidc = plan.oidc.model_dump()
|
||||
oidc["roles"].update(administrator_group="ReadOnly", read_only_group="Administrator")
|
||||
plan = _plan(oidc=oidc)
|
||||
# Exercise both consumers; the integration can also run on an async
|
||||
# controller completion where this instance never performed preflight.
|
||||
preflight = plane.preflight(session, plan)
|
||||
if swapped_roles:
|
||||
assert "oidc_template" in preflight["blockers"]
|
||||
plane.authentik = SavedTemplateAuthentik()
|
||||
set_secret(session, "WSBC_PORTAL_OIDC_CLIENT_SECRET", "b" * 32)
|
||||
success, evidence, _ = plane._complete_external_integrations(session, plan)
|
||||
assert success is not swapped_roles
|
||||
if swapped_roles:
|
||||
assert evidence == {}
|
||||
else:
|
||||
assert evidence["oidc"]["status"] == "created"
|
||||
|
||||
|
||||
def test_invalid_oidc_template_prevents_controller_apply(tmp_path):
|
||||
class UnavailableAuthentik(_Authentik):
|
||||
def validate_deployment_oidc_template(self, **kwargs):
|
||||
return {"status": "unavailable", "reason": "remote-secret-sentinel"}
|
||||
|
||||
class NoApplyBroker(_Broker):
|
||||
def apply(self, *args, **kwargs):
|
||||
raise AssertionError("Invalid template must fail before controller apply")
|
||||
|
||||
with _session(tmp_path) as session:
|
||||
set_secret(session, "WSBC_PORTAL_DEPLOYMENT_BROKER", "a" * 32)
|
||||
set_secret(session, "WSBC_PORTAL_OIDC_CLIENT_SECRET", "b" * 32)
|
||||
session.add(Policy(id="allow-invalid-template-test", action="deployment.apply", target="wsbc-portal", manual="allowed", voice="blocked", risk="high", reason="Test"))
|
||||
session.commit()
|
||||
plane = _plane()
|
||||
plane.authentik = UnavailableAuthentik()
|
||||
plane.broker = NoApplyBroker()
|
||||
result = plane.execute(session, plan=_plan(), idempotency_key="invalid-template-0001", operation="apply")
|
||||
assert result["status"] == "preflight_failed"
|
||||
assert "oidc_template" in result["preflight"]["blockers"]
|
||||
assert "remote-secret-sentinel" not in str(result)
|
||||
|
||||
|
||||
def test_oidc_template_drift_after_preflight_prevents_provider_write(tmp_path):
|
||||
class ChangedAuthentik(_Authentik):
|
||||
def validate_deployment_oidc_template(self, **kwargs):
|
||||
return {"status": "unavailable", "reason": "secret-sentinel"}
|
||||
|
||||
def ensure_deployment_oidc_application(self, **kwargs):
|
||||
raise AssertionError("Unverified template must never create a provider")
|
||||
|
||||
with _session(tmp_path) as session:
|
||||
set_secret(session, "WSBC_PORTAL_OIDC_CLIENT_SECRET", "b" * 32)
|
||||
plane = _plane()
|
||||
plane.authentik = ChangedAuthentik()
|
||||
success, evidence, message = plane._complete_external_integrations(session, _plan())
|
||||
assert not success
|
||||
assert evidence == {}
|
||||
assert "secret-sentinel" not in message
|
||||
|
||||
|
||||
@pytest.mark.parametrize("claim,administrator", [("groups", "Administrator"), ("roles", "OtherAdmin")])
|
||||
def test_preflight_verifies_requested_claim_and_groups(tmp_path, claim, administrator):
|
||||
class RequestedContractAuthentik(_Authentik):
|
||||
def validate_deployment_oidc_template(self, *, role_claim, role_groups):
|
||||
assert role_claim == claim
|
||||
assert role_groups == (administrator, "SupportAgent", "ReadOnly")
|
||||
return {"status": "unavailable", "reason": "private-template-diagnostic"}
|
||||
|
||||
oidc = _plan().oidc.model_dump()
|
||||
oidc["role_claim"] = claim
|
||||
oidc["roles"]["administrator_group"] = administrator
|
||||
with _session(tmp_path) as session:
|
||||
plane = _plane()
|
||||
plane.authentik = RequestedContractAuthentik()
|
||||
result = plane.preflight(session, _plan(oidc=oidc))
|
||||
assert "oidc_template" in result["blockers"]
|
||||
assert "private-template-diagnostic" not in str(result)
|
||||
|
||||
|
||||
def test_missing_role_group_blocks_provider_write(tmp_path):
|
||||
class MissingGroupAuthentik(_Authentik):
|
||||
def groups(self):
|
||||
return {"success": True, "items": [{"name": "Administrator"}, {"name": "SupportAgent"}]}
|
||||
|
||||
def ensure_deployment_oidc_application(self, **kwargs):
|
||||
raise AssertionError("Missing group must fail before provider write")
|
||||
|
||||
with _session(tmp_path) as session:
|
||||
set_secret(session, "WSBC_PORTAL_OIDC_CLIENT_SECRET", "b" * 32)
|
||||
plane = _plane()
|
||||
plane.authentik = MissingGroupAuthentik()
|
||||
result = plane.preflight(session, _plan())
|
||||
assert "oidc_template" in result["blockers"]
|
||||
success, evidence, _ = plane._complete_external_integrations(session, _plan())
|
||||
assert not success
|
||||
assert evidence == {}
|
||||
Reference in new issue
Block a user