Finish WP-0025 SSO cutover except group allowlist residual.
Mark T03–T05 and T07–T08 done after live Authelia/TLS verification, prefer SSO principal in ops UI copy and audits, and document break-glass port-forward. Leave T06 waiting on net-kingdom LLDAP/Authelia group rules.
This commit is contained in:
parent
27c087bcb4
commit
91353df7d0
8 changed files with 151 additions and 67 deletions
|
|
@ -67,6 +67,53 @@ async def test_trigger_requires_token(ops_app: FastAPI, monkeypatch: pytest.Monk
|
|||
assert res.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_trigger_with_sso_principal(
|
||||
ops_app: FastAPI, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""SSO Remote-User is preferred; audit must record sso:<user>, never the token."""
|
||||
def_id = uuid.uuid4()
|
||||
row = MagicMock()
|
||||
row.name = "Weekly SBOM"
|
||||
row.context_sources = []
|
||||
row.task_templates = []
|
||||
row.trigger_config = {"trigger_type": "cron", "cron_expression": "0 9 * * 1"}
|
||||
|
||||
session = AsyncMock()
|
||||
session.get = AsyncMock(return_value=row)
|
||||
session.__aenter__ = AsyncMock(return_value=session)
|
||||
session.__aexit__ = AsyncMock(return_value=None)
|
||||
ops_app.state.session_factory.return_value = session
|
||||
|
||||
handle = MagicMock()
|
||||
handle.id = f"activity-{def_id}:manual-sso"
|
||||
ops_app.state.temporal.start_workflow = AsyncMock(return_value=handle)
|
||||
|
||||
captured: dict[str, Any] = {}
|
||||
|
||||
async def capture_audit(**kwargs: Any) -> dict[str, Any]:
|
||||
captured.update(kwargs)
|
||||
return {
|
||||
"action": kwargs["action"],
|
||||
"audit_id": "sso-a1",
|
||||
"principal": kwargs["principal"],
|
||||
}
|
||||
|
||||
monkeypatch.setattr("activity_core.ops_api.record_ops_audit", capture_audit)
|
||||
|
||||
transport = ASGITransport(app=ops_app)
|
||||
async with AsyncClient(transport=transport, base_url="http://test") as client:
|
||||
res = await client.post(
|
||||
f"/ops/automations/{def_id}/trigger",
|
||||
headers={"Remote-User": "alice.operator"},
|
||||
json={},
|
||||
)
|
||||
assert res.status_code == 200
|
||||
assert res.json()["audit"]["principal"] == "sso:alice.operator"
|
||||
assert captured["principal"] == "sso:alice.operator"
|
||||
assert "token" not in str(res.json()).lower() or "test-token" not in str(res.json())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_trigger_with_token(ops_app: FastAPI, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def_id = uuid.uuid4()
|
||||
|
|
@ -216,7 +263,7 @@ async def test_ui_index_renders(ops_app: FastAPI, monkeypatch: pytest.MonkeyPatc
|
|||
res = await client.get("/ops/ui/")
|
||||
assert res.status_code == 200
|
||||
assert "Daily Triage" in res.text
|
||||
assert "Operator token" in res.text
|
||||
assert "SSO" in res.text or "Break-glass" in res.text
|
||||
assert "Temporal UI" in res.text
|
||||
assert "temporal.coulomb.social" in res.text
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue