From 9a3a84c99cd79a622b27558d1c4260281a6fb218 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 24 Oct 2026 18:17:08 +0200 Subject: [PATCH] NK-WP-0049-T42: fix launcher preflight entry point; test the launcher path The MFA launcher called m.preflight() but the module only exposed pi.preflight, so its catch-all reported a generic preflight failure before any key prompt. Add preflight() and execute the launcher's own snippet in the tests. Co-Authored-By: Claude Sonnet 5.5 Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 328925@bnt-lap001 Assistant-Session: 14b795fd-c632-4c01-8d28-e7e490c7b0ed --- tests/test_isolated_privacyidea_mfa.py | 16 ++++++++++++++++ .../isolated-privacyidea-mfa.py | 7 ++++++- ...049-bootstrap-secret-free-recovery-handoff.md | 6 ++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/test_isolated_privacyidea_mfa.py b/tests/test_isolated_privacyidea_mfa.py index d036e56..ba42bc6 100644 --- a/tests/test_isolated_privacyidea_mfa.py +++ b/tests/test_isolated_privacyidea_mfa.py @@ -29,6 +29,22 @@ print(json.dumps(out)) ''' +def test_launcher_preflight_entry_point_exists_and_launcher_calls_it(): + # The launcher swallows exceptions into one message; a missing attribute once hid here. + assert callable(m.preflight) + launcher = (ROOT / 'tools/bootstrap-recovery/run-isolated-privacyidea-mfa.sh').read_text() + assert 'isolated-privacyidea-mfa.py' in launcher and 'm.preflight()' in launcher + + +def test_launcher_preflight_snippet_passes_against_the_pinned_target(): + import re + import subprocess + launcher = (ROOT / 'tools/bootstrap-recovery/run-isolated-privacyidea-mfa.sh').read_text() + snippet = re.search(r"python3 - <<'PY'\n(.*?)\nPY\n", launcher, re.S).group(1) + done = subprocess.run(['python3', '-c', snippet], cwd=ROOT, capture_output=True, text=True, timeout=120) + assert done.returncode == 0 and done.stdout.startswith('OK: exact bnt-lap001'), done.stdout + done.stderr + + def test_wrong_code_keeps_shape_but_changes_value(): assert m.different_code('123456') == '123450' assert m.different_code('123450') == '123451' diff --git a/tools/bootstrap-recovery/isolated-privacyidea-mfa.py b/tools/bootstrap-recovery/isolated-privacyidea-mfa.py index db79cbc..4ba7693 100755 --- a/tools/bootstrap-recovery/isolated-privacyidea-mfa.py +++ b/tools/bootstrap-recovery/isolated-privacyidea-mfa.py @@ -94,6 +94,11 @@ print(json.dumps(result)) ''' +def preflight(): + """The launcher calls this before any key prompt.""" + return pi.preflight() + + def worker_json(worker, script, values=None, timeout=300): args = ['docker', 'exec'] + (['-i'] if values is not None else []) + [worker, 'python3', '-c', script] raw = run(args, input=None if values is None else json.dumps(values).encode(), timeout=timeout) @@ -202,7 +207,7 @@ def main(): work = None stage = 'target_preflight' try: - result['target'] = pi.preflight() + result['target'] = preflight() stage = 'transfer_validation' transfer = json.loads(Path(args.transfer_receipt).read_text()) local.offline.validate(transfer) diff --git a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md index f3a40ad..81d689c 100644 --- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md @@ -1568,6 +1568,12 @@ validates by user and realm, so the restored LDAP resolver, its encrypted bind password and the LLDAP user lookup need a chained run (T18 phase B). This prepares T19; it is not T19 acceptance and touches no production service. +Correction 2026-10-24, found when the founder first ran the launcher: it called +`m.preflight()` on a module that only exposed `pi.preflight`, and its catch-all printed +the generic preflight message. The fixture tests had called `main()` directly and +never went through the launcher. Fixed; tests now execute the launcher's own +preflight snippet. No key was requested and nothing was consumed. + ## Accept remaining recovery and caller evidence and close the G08 handoff ```task