diff --git a/sso-mfa/bootstrap/reconcile-keycape-client-secret.py b/sso-mfa/bootstrap/reconcile-keycape-client-secret.py index ee29612..209dac1 100755 --- a/sso-mfa/bootstrap/reconcile-keycape-client-secret.py +++ b/sso-mfa/bootstrap/reconcile-keycape-client-secret.py @@ -52,11 +52,14 @@ def main(): print(__doc__.strip().splitlines()[-2], file=sys.stderr) return 2 root = roots[0] - phase = 'read' + phase = 'custody' try: + custody_value(root) # fail first, and distinctly, if the decrypted copy is absent + phase = 'cluster' hashed = secret_data('authelia-secrets', 'keycape_client_secret_hash') config = yaml.safe_load(secret_data('keycape-config', 'config.yaml')) live = str(config['authelia']['clientSecret']).encode() + phase = 'live-pair' if not bcrypt.checkpw(live, hashed): raise Refused() # live pair must agree first before = bcrypt.checkpw(custody_value(root), hashed) report = {'live_keycape_matches_authelia_hash': True, 'custody_matched_before': before, diff --git a/tests/test_reconcile_keycape_client_secret.py b/tests/test_reconcile_keycape_client_secret.py index 7dea1e4..e701d56 100644 --- a/tests/test_reconcile_keycape_client_secret.py +++ b/tests/test_reconcile_keycape_client_secret.py @@ -83,5 +83,13 @@ def test_refuses_when_live_pair_disagrees(case): before = env.read_bytes() result = run(case, '--apply') assert result.returncode == 1 and result.stdout == '' - assert json.loads(result.stderr) == {'result': 'unverified', 'phase': 'read', 'partial_changes_possible': False} + assert json.loads(result.stderr) == {'result': 'unverified', 'phase': 'live-pair', 'partial_changes_possible': False} assert env.read_bytes() == before + + +def test_missing_custody_copy_is_reported_as_custody(case): + private, *_ = case + import shutil; shutil.rmtree(private) + result = run(case) + assert result.returncode == 1 + assert json.loads(result.stderr)['phase'] == 'custody'