Files
acdl/tests/test_route_halt_artifact.py
T
Jon Chery e15eea067b docs(milestone): complete v1.15 — Nova Rebrand (tag v1.15.4)
P5 final-review-ship complete: dual-read fallback removed (REQ-164) —
core/env.py NOVA-only, .env.secrets load paths NOVA-only (G-106 retired),
nova_tagging.py hard-fails any acdl:* tag, legacy ACDL_* Gitea secrets
deleted, ACDL_LIFECYCLE_MODE/ACDL_LOCAL_TIER/ACDL_HITL_* exports removed
from scripts, SNS subject → Nova SoD halt (P1-2), bootstrap scripts
NOVA-only. Review: 2 P0 auto-fixed (duplicate delenv), P1-1/P1-2 resolved,
doc-drift fixed. Audit: tags v1.15.0-4 exist; traceability REQ-155..164
all complete; ARCHITECTURE naming table matches codebase. 615 pytest PASS;
run_ci.sh 3-stage PASS. NOVA_MIGRATION.md marked COMPLETE.

---ci---
project: acdl
phase: 5
milestone: v1.15
status: complete
phase_role: final
requirements:
  covered: [REQ-155, REQ-156, REQ-157, REQ-158, REQ-159, REQ-160, REQ-161, REQ-162, REQ-163, REQ-164]
  partial: []
---/ci---
2026-07-30 02:23:55 +00:00

70 lines
3.1 KiB
Python

"""REQ-107: route_halt_artifact is a real implementation (SNS + outbox fallback)."""
import json
import os
import sys
from pathlib import Path
from unittest import mock
import pytest
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
from core.separation_of_duties import route_halt_artifact
def test_route_halt_publishes_to_sns_when_arn_set(monkeypatch):
"""With NOVA_SOD_HALT_TOPIC_ARN set, the SNS client receives the publish."""
monkeypatch.setenv("NOVA_SOD_HALT_TOPIC_ARN", "arn:aws:sns:us-east-1:000000000000:nova-sod-halt")
sns_client = mock.MagicMock()
route_halt_artifact("contract-123", "SEPARATION_OF_DUTIES_VIOLATION: x==y",
oncall_client=sns_client)
sns_client.publish.assert_called_once()
call = sns_client.publish.call_args
assert call.kwargs["TopicArn"] == "arn:aws:sns:us-east-1:000000000000:nova-sod-halt"
assert "contract-123" in call.kwargs["Message"]
assert "SEPARATION_OF_DUTIES_VIOLATION" in call.kwargs["Message"]
assert call.kwargs["Subject"] == "Nova SoD halt"
def test_route_halt_falls_back_to_stderr_when_arn_unset(monkeypatch, capsys):
"""Without NOVA_SOD_HALT_TOPIC_ARN, a stderr emission occurs."""
# P5 (REQ-164): ACDL_* fallback removed — NOVA_* only.
monkeypatch.delenv("NOVA_SOD_HALT_TOPIC_ARN", raising=False)
# Mock outbox_writer.write_event to avoid AWS calls.
with mock.patch("core.outbox_writer.write_event", return_value=None):
route_halt_artifact("contract-456", "violation", oncall_client=None)
captured = capsys.readouterr()
assert "contract-456" in captured.err
assert "violation" in captured.err
def test_route_halt_outbox_fallback_writes_event(monkeypatch):
"""Without the SNS ARN, the outbox fallback writes a SEPARATION_OF_DUTIES_VIOLATION event."""
# P5 (REQ-164): ACDL_* fallback removed — NOVA_* only.
monkeypatch.delenv("NOVA_SOD_HALT_TOPIC_ARN", raising=False)
with mock.patch("core.outbox_writer.write_event") as mock_write:
route_halt_artifact("contract-789", "sod violation", oncall_client=None)
mock_write.assert_called_once()
event = mock_write.call_args[0][0]
assert event["contractId"] == "contract-789"
assert event["eventType"] == "SEPARATION_OF_DUTIES_VIOLATION"
assert "sod violation" in event["reason"]
def test_route_halt_sns_failure_falls_back_to_outbox(monkeypatch):
"""If SNS publish raises, the outbox fallback is used."""
monkeypatch.setenv("NOVA_SOD_HALT_TOPIC_ARN", "arn:aws:sns:us-east-1:000000000000:nova-sod-halt")
sns_client = mock.MagicMock()
sns_client.publish.side_effect = Exception("SNS down")
with mock.patch("core.outbox_writer.write_event") as mock_write:
route_halt_artifact("contract-fail", "violation", oncall_client=sns_client)
mock_write.assert_called_once()
def test_sns_topic_defined_in_terraform():
"""terraform/platform/main.tf defines the nova-sod-halt SNS topic."""
tf = (ROOT / "terraform" / "platform" / "main.tf").read_text()
assert "aws_sns_topic" in tf
assert "nova-sod-halt" in tf
assert "nova_sod_halt_topic_arn" in tf