from __future__ import annotations import importlib.util import os import shutil import sys import tempfile import unittest from pathlib import Path REPO_DIR = Path(__file__).resolve().parents[1] SPEC = importlib.util.spec_from_file_location( "credential_change", REPO_DIR / "scripts/credential-change.py" ) credential_change = importlib.util.module_from_spec(SPEC) assert SPEC.loader is not None sys.modules[SPEC.name] = credential_change SPEC.loader.exec_module(credential_change) class CredentialChangeTests(unittest.TestCase): def setUp(self) -> None: self.sample = ( REPO_DIR / "credential-change-requests/CCR-2026-0001-whynot-design-npm-token.yaml" ) def test_sample_ccr_validates_with_bound_claim_warning(self) -> None: _ccr, errors, warnings = credential_change.validate_ccr(self.sample) self.assertEqual(errors, []) self.assertIn("bound claim is not confirmed", warnings[0]) def test_render_summary_contains_review_fields(self) -> None: ccr, _errors, warnings = credential_change.validate_ccr(self.sample) rendered = credential_change.render_summary(ccr, warnings) self.assertIn("whynot-design npm publish token lane", rendered) self.assertIn("platform/workloads/whynot-design/whynot-design/npm-publish", rendered) self.assertIn("approve | deny | needs_changes", rendered) def test_apply_plan_refuses_unapproved_ccr(self) -> None: with self.assertRaises(SystemExit): credential_change.command_apply_plan(type("Args", (), {"ref": str(self.sample)})()) def test_approve_records_comment_but_unconfirmed_claim_still_blocks_apply(self) -> None: with tempfile.TemporaryDirectory() as tmp: tmp_path = Path(tmp) ccr_dir = tmp_path / "ccrs" ccr_dir.mkdir() copied = ccr_dir / self.sample.name shutil.copy2(self.sample, copied) old_ccr_dir = os.environ.get("CCR_DIR") os.environ["CCR_DIR"] = str(ccr_dir) try: credential_change.append_decision( copied, "approved", "unit-test", "looks right" ) ccr, errors, _warnings = credential_change.validate_ccr(copied) self.assertEqual(errors, []) self.assertEqual(ccr["status"], "approved") self.assertEqual(ccr["review"]["comments"][-1]["comment"], "looks right") with self.assertRaises(SystemExit): credential_change.command_apply_plan( type("Args", (), {"ref": "CCR-2026-0001"})() ) finally: if old_ccr_dir is None: os.environ.pop("CCR_DIR", None) else: os.environ["CCR_DIR"] = old_ccr_dir def test_generated_policy_is_narrow(self) -> None: ccr, _errors, _warnings = credential_change.validate_ccr(self.sample) policy = credential_change.generated_policy_hcl(ccr) self.assertIn('path "platform/data/workloads/whynot-design/whynot-design/npm-publish"', policy) self.assertNotIn("*", policy) self.assertNotIn("delete", policy) if __name__ == "__main__": unittest.main()