61 lines
2.6 KiB
Python
61 lines
2.6 KiB
Python
"""Ensure maintenance cannot echo credentials or change Secret data."""
|
|
import importlib.util
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
PATH = Path(__file__).resolve().parents[1] / "docs/changes/CUST-WP-0073/secret_annotation_maintenance.py"
|
|
spec = importlib.util.spec_from_file_location("maintenance", PATH)
|
|
maintenance = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(maintenance)
|
|
|
|
|
|
def test_failure_does_not_return_raw_secret_output():
|
|
responses = [subprocess.CompletedProcess([], 0, "sso example\n", ""),
|
|
subprocess.CompletedProcess([], 0, "namespace/sso\n", ""),
|
|
subprocess.CompletedProcess([], 1, "SENSITIVE-STDOUT", "SENSITIVE-STDERR")]
|
|
with patch.object(maintenance.subprocess, "run", side_effect=responses):
|
|
report = maintenance.maintain()
|
|
assert report["complete"] is False
|
|
assert "SENSITIVE" not in json.dumps(report)
|
|
|
|
|
|
def test_clean_only_removes_annotation_and_checks_result():
|
|
responses = ["sso example", "namespace/sso", "HAS-ANNOTATION", "secret/example patched", "clean"]
|
|
calls = []
|
|
def fake(args):
|
|
calls.append(args)
|
|
return responses.pop(0)
|
|
with patch.object(maintenance, "run", side_effect=fake):
|
|
report = maintenance.maintain(clean=True)
|
|
assert report["complete"] and report["cleaned"] == ["sso/example"]
|
|
operation = json.loads(calls[3][-1])
|
|
assert operation == [{"op": "remove", "path": "/metadata/annotations/kubectl.kubernetes.io~1last-applied-configuration"}]
|
|
assert calls[2] == calls[4]
|
|
|
|
|
|
def test_inspect_never_patches_and_rejects_unexpected_template_output():
|
|
with patch.object(maintenance, "run", side_effect=["sso example", "namespace/sso", "SENSITIVE-DUMP"]):
|
|
report = maintenance.maintain()
|
|
assert not report["complete"]
|
|
assert "SENSITIVE" not in json.dumps(report)
|
|
|
|
|
|
def test_inventory_rejects_untrusted_arguments():
|
|
with patch.object(maintenance, "run", return_value="sso --help"):
|
|
try:
|
|
maintenance.maintain(clean=True)
|
|
except RuntimeError:
|
|
pass
|
|
else:
|
|
raise AssertionError("unsafe identity accepted")
|
|
|
|
|
|
def test_orphan_namespace_is_explicit_and_never_deleted_or_claimed_clean():
|
|
with patch.object(maintenance, "run", side_effect=["gone orphan\nsso normal", "namespace/sso", "clean"]) as mocked:
|
|
report = maintenance.maintain(clean=True)
|
|
assert report["orphaned_namespace"] == ["gone/orphan"]
|
|
assert not report["complete"]
|
|
assert report["active_namespace_scan_complete"]
|
|
assert mocked.call_count == 3
|