import os from pathlib import Path import subprocess import unittest ROOT = Path(__file__).resolve().parents[1] class BackupCredentialTests(unittest.TestCase): def run_shell(self, body): env = {k: v for k, v in os.environ.items() if not k.startswith("RAILIANCE_BACKUP_")} return subprocess.run( ["bash", "-c", 'source lib/railiance-backup-common.sh\n' + body], cwd=ROOT, env=env, text=True, capture_output=True, ) def test_missing_credentials_fail_with_safe_error(self): result = self.run_shell( 'bao() { return 1; }\nrailiance_backup_require_openbao_lane' ) self.assertNotEqual(result.returncode, 0) self.assertEqual(result.stdout, "") self.assertIn("governed backup credential unavailable", result.stderr) self.assertNotIn("unbound variable", result.stderr) def test_explicit_governed_credentials_need_no_bao(self): result = self.run_shell(''' bao() { echo unexpected-bao >&2; return 1; } RAILIANCE_BACKUP_NC_TOKEN=test-only-placeholder RAILIANCE_BACKUP_NC_WEBDAV_URL=https://example.invalid/upload railiance_backup_require_openbao_lane ''') self.assertEqual(result.returncode, 0) self.assertEqual(result.stdout + result.stderr, "") def test_openbao_lane_supplies_missing_credentials(self): result = self.run_shell(''' bao() { case "$*" in "kv metadata get "*) return 0 ;; "kv get -field=NC_WEBDAV_TOKEN "*) echo test-only-placeholder ;; "kv get -field=NC_WEBDAV_URL "*) echo https://example.invalid/upload ;; *) return 1 ;; esac } railiance_backup_require_openbao_lane [[ "$RAILIANCE_BACKUP_NC_TOKEN" == test-only-placeholder ]] [[ "$RAILIANCE_BACKUP_NC_WEBDAV_URL" == https://example.invalid/upload ]] ''') self.assertEqual(result.returncode, 0) self.assertEqual(result.stdout + result.stderr, "")