All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m32s
CD Pipeline / build-and-deploy (push) Successful in 8m2s
CD Pipeline / post-deploy-checks (push) Successful in 2m22s
Restore D037 durable incident readback without weakening database failure semantics. Fence Agent99 dispatch and terminal learning to canonical identities, durable leases, verifier receipts, and reconciler-owned checkpoints. Drain backup and restore legacy receipts in bounded cohorts with strict transport, claim, projection, and no-false-green controls. Keep SSH service refusal visible while separating it from broker network-policy reachability.
164 lines
6.0 KiB
Python
164 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from src.services.alert_approval_guard import guard_alert_approval_action
|
|
from src.services.resource_resolver import ResolveResult, set_resource_resolver
|
|
from src.utils.k8s_naming import ResourceType
|
|
|
|
|
|
class StubResolver:
|
|
def __init__(self, *, success: bool, candidates: list[str] | None = None) -> None:
|
|
self.success = success
|
|
self.candidates = candidates or []
|
|
self.calls: list[dict[str, str]] = []
|
|
|
|
async def resolve(
|
|
self,
|
|
raw_resource: str,
|
|
namespace: str = "awoooi-prod",
|
|
resource_kind: str = "deployment",
|
|
) -> ResolveResult:
|
|
self.calls.append(
|
|
{
|
|
"raw_resource": raw_resource,
|
|
"namespace": namespace,
|
|
"resource_kind": resource_kind,
|
|
}
|
|
)
|
|
return ResolveResult(
|
|
success=self.success,
|
|
resource_name=raw_resource if self.success else None,
|
|
namespace=namespace,
|
|
resource_type=ResourceType(resource_kind)
|
|
if resource_kind in ResourceType._value2member_map_
|
|
else ResourceType.UNKNOWN,
|
|
confidence=1.0 if self.success else 0.0,
|
|
candidates=self.candidates,
|
|
original_input=raw_resource,
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_llm_kubectl_default_namespace_for_prod_alert() -> None:
|
|
result = await guard_alert_approval_action(
|
|
action="kubectl logs deployment/sentry-self-hosted-snuba-metrics-consumer-1 -n default",
|
|
alert_namespace="awoooi-prod",
|
|
alertname="SentryRpsZero",
|
|
alert_category="infrastructure",
|
|
)
|
|
|
|
assert result.blocked is True
|
|
assert result.action.startswith("NO_ACTION - INVALID_TARGET")
|
|
assert result.reason == "namespace_not_allowed:default"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cold_start_invalid_k8s_target_becomes_fail_closed_agent99_candidate() -> None:
|
|
result = await guard_alert_approval_action(
|
|
action="kubectl scale deployment/cold-start-gate --replicas=2 -n default",
|
|
alert_namespace="default",
|
|
alertname="ColdStartGateBlocked",
|
|
alert_category="general",
|
|
target_resource="cold-start-gate",
|
|
)
|
|
|
|
assert result.blocked is True
|
|
assert result.reason == "namespace_not_allowed:default"
|
|
assert result.action == (
|
|
"DRAFT_READY - CONTROLLED_AGENT99_RECOVERY: "
|
|
"agent99-mode Recover controlledApply=true"
|
|
)
|
|
assert result.metadata["blocked_action"].startswith("kubectl scale")
|
|
assert result.metadata["controlled_target_reroute"] is True
|
|
assert result.metadata["controlled_target_executor"] == "Agent99"
|
|
|
|
contract = result.metadata["repair_candidate_promotion_contract"]
|
|
assert contract["route_id"] == "agent99_recover_after_owner_review"
|
|
assert contract["status"] == "controlled_route_candidate_pending_receipts"
|
|
assert contract["runtime_execution_authorized"] is False
|
|
assert contract["runtime_write_allowed"] is False
|
|
assert contract["completion_status"] == "partial"
|
|
assert contract["blocked_count"] > 0
|
|
assert "dispatch_receipt" in contract["blocked_fields"]
|
|
assert "post_apply_verifier" in contract["blocked_fields"]
|
|
assert "km_writeback" in contract["blocked_fields"]
|
|
assert "playbook_trust_writeback" in contract["blocked_fields"]
|
|
assert "kubectl_for_host_control_plane_target" in contract["forbidden_operations"]
|
|
assert "generic_ansible_keyword_fallback" in contract["forbidden_operations"]
|
|
|
|
closure = contract["controlled_automation_closure"]
|
|
stages = {row["stage"]: row["status"] for row in closure["stages"]}
|
|
assert stages == {
|
|
"sensor": "pending",
|
|
"normalize": "passed",
|
|
"check": "pending",
|
|
"controlled_apply": "pending",
|
|
"verify": "pending",
|
|
"learn_writeback": "pending",
|
|
}
|
|
assert {row["asset_type"] for row in closure["automation_asset_ledger"]} == {
|
|
"Sensor",
|
|
"PlayBook",
|
|
"Verifier",
|
|
"KM",
|
|
}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cold_start_valid_namespace_still_cannot_become_fake_k8s_action() -> None:
|
|
result = await guard_alert_approval_action(
|
|
action=(
|
|
"kubectl rollout restart deployment/cold-start-gate "
|
|
"-n awoooi-prod"
|
|
),
|
|
alert_namespace="awoooi-prod",
|
|
alertname="ColdStartGateBlocked",
|
|
alert_category="general",
|
|
target_resource="cold-start-gate",
|
|
)
|
|
|
|
assert result.blocked is True
|
|
assert result.reason == "kubernetes_action_not_applicable:control_plane_recovery"
|
|
assert result.metadata["controlled_target_executor"] == "Agent99"
|
|
assert result.action.startswith("DRAFT_READY - CONTROLLED_AGENT99_RECOVERY")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_hallucinated_mutating_k8s_resource() -> None:
|
|
resolver = StubResolver(success=False, candidates=["awoooi-api"])
|
|
set_resource_resolver(resolver)
|
|
try:
|
|
result = await guard_alert_approval_action(
|
|
action="kubectl scale deployment flywheelexecutionratemissing --replicas=5 -n awoooi-prod",
|
|
alert_namespace="awoooi-prod",
|
|
alertname="FlywheelExecutionRateMissing",
|
|
alert_category="infrastructure",
|
|
)
|
|
finally:
|
|
set_resource_resolver(None)
|
|
|
|
assert result.blocked is True
|
|
assert result.reason == "k8s_resource_not_found:deployment/flywheelexecutionratemissing"
|
|
assert result.metadata["candidates"] == ["awoooi-api"]
|
|
assert resolver.calls == [
|
|
{
|
|
"raw_resource": "flywheelexecutionratemissing",
|
|
"namespace": "awoooi-prod",
|
|
"resource_kind": "deployment",
|
|
}
|
|
]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_allows_sane_readonly_cluster_inventory() -> None:
|
|
result = await guard_alert_approval_action(
|
|
action="kubectl get pods -n awoooi-prod",
|
|
alert_namespace="awoooi-prod",
|
|
alertname="ColdStartCheck",
|
|
alert_category="infrastructure",
|
|
)
|
|
|
|
assert result.blocked is False
|
|
assert result.action == "kubectl get pods -n awoooi-prod"
|