diff --git a/docs/evidence/2026-10-14-netkingdom-security/resolver-cutover.json b/docs/evidence/2026-10-14-netkingdom-security/resolver-cutover.json new file mode 100644 index 0000000..073065e --- /dev/null +++ b/docs/evidence/2026-10-14-netkingdom-security/resolver-cutover.json @@ -0,0 +1,178 @@ +{ + "observed_at": "2026-10-14", + "source_repo": "net-kingdom", + "source_base": "ab25dde80d4520c4ff09240944d1510b2a17b9f0", + "source_commit": "4dffe2fe7a8e9421bd7f378804b0f291189b2e38", + "workplan_id": "NK-WP-0049", + "task_id": "NK-WP-0049-T02", + "custodian_task_id": "CUST-WP-0080-T03", + "result": "bounded_resolver_helper_source_repair_complete_not_live_cutover", + "files": [ + { + "path": "sso-mfa/k8s/privacyidea/pi_api.py", + "before_sha256": "2eec0866fb140398c8f096cdbf9f99bed134e39d5cc20551bc66842b17e513a7", + "sha256": "01bbf3a2c1f8c423f864dc4bd2145c5c89f938fa9e8b0ffbbecf6d674484896b" + }, + { + "path": "sso-mfa/k8s/privacyidea/resolver_cutover.py", + "before_sha256": null, + "sha256": "6ed2df95671897f073a3dc8fee62b780cdff87b08d617d5a337e1fbba206e10a" + }, + { + "path": "sso-mfa/k8s/privacyidea/update-lldap-resolver-live.sh", + "before_sha256": "ba0ff0a321e0b22bfdb8b7e6fed50fa4bcd7e9d4d872333ac3194607381d6d56", + "sha256": "ffa7c551dbcc6ab74d2cfc0853fd0647dd026259b1541f99e4a84dcbac16588c" + }, + { + "path": "sso-mfa/k8s/privacyidea/reconcile-lldap-resolver-live.sh", + "before_sha256": "30f12ba56a81099388880db2679e09deac723523975ff3d55936aaae2176f71c", + "sha256": "89f5b279cde441ef8a7c63436e63c6242527d36949aba4bad2134c890a9e0b04" + }, + { + "path": "sso-mfa/k8s/privacyidea/README.md", + "before_sha256": "299c68d881dbcda5db03f3435ce0e56034912e29b40a15e58a0dc5044ad21c2d", + "sha256": "9e0f5fedc857c0eca0a7dad4ae140dd209be5d1f6820ad45be628692ada6d9cd" + }, + { + "path": "tests/test_resolver_cutover.py", + "before_sha256": null, + "sha256": "4775b879d51338d3c26bb3a9114791db57008e6a5a31a0ad38b188dd982dbbf0" + }, + { + "path": "tests/resolver_cutover_native_fixture.py", + "before_sha256": null, + "sha256": "47390d58d12a6573dc71f348ea52b762cf9b20a5c8955c8dfff84d5a45626220" + }, + { + "path": "docs/keycape-exposure-resolver-reconciliation.md", + "before_sha256": "260d5c2117eb711ce1493e8e636c55730c6239e6eded8929a7c1bd2099d4a0b3", + "sha256": "90d028d408af9180b1fac012b0c180680f7de3decca9c8aa45d8331df5dadde0" + }, + { + "path": "docs/attended-procedure-standard.md", + "before_sha256": "5a6bac14003ed6909c2a24012892f43c2df3107890322ed0a90c5fefd0419fee", + "sha256": "a72951132549b4e65c7835a1c3f54951838522a26d226da38ee78dafea0f04b8" + }, + { + "path": "docs/attended-procedure-inventory.md", + "before_sha256": "9b3cde4de1f6410c105d608f7ff45774862c50dd72535aff5b131f8528357ab3", + "sha256": "b1bc545854b43427bf46e3254a07af843513f9490624809d4f62e9e488bc9049" + }, + { + "path": "workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md", + "before_sha256": "099fe590e7cbc5b2bda7b2da5f2e083ab0305bb3bdde60f02de785efbe301358", + "sha256": "ff522cf70731ed519116daa6e30b88e173174a171cf4270e11410325cba8290c" + } + ], + "unchanged_dependencies": [ + { + "path": "sso-mfa/k8s/privacyidea/realm_bootstrap.py", + "sha256": "2885086fdc4fd64b58496f90e82c75eefc7171017004e0804defaaabf791b3a9" + }, + { + "path": "sso-mfa/k8s/privacyidea/verify_mfa.py", + "sha256": "118d0052433edb85dd53e3c988943392f59d0aa00641d45f8ff3676a15f8af19" + }, + { + "path": "sso-mfa/k8s/privacyidea/mfa_state.py", + "sha256": "3f0c2e404d7df41af7f8e1fe66a4a6d392338391456ef298c7dd0219ad3d58dc" + } + ], + "verification": { + "affected_tests": { + "passed": 171, + "failed": 0, + "skipped": 0, + "warnings": 2, + "warning_detail": "Python 3.12 forkpty-in-multithreaded-test deprecation; both PTY tests completed successfully." + }, + "initial_run": { + "passed": 87, + "failed": 1, + "cause": "Test attempted to fingerprint the deliberately missing resolver before calling refusal path; fixture corrected, failure retained." + }, + "intermediate_run": { + "passed": 170, + "failed": 0 + }, + "native": { + "privacyidea_version": "3.12.2", + "lldap_image": "sha256:2a8454b668c1aba7157e832eab0e242e1e7eb5fb7591d7e7774ba05286511ca8", + "checks": { + "cluster_and_keycape_gates_substituted": true, + "fixture_removed": true, + "native_candidate_and_stored_ldap_bind": true, + "native_custom_config_and_realms_preserved": true, + "native_exact_user_and_hotp": true, + "native_minimal_password_update": true, + "native_old_bind_refused": true, + "native_policies_preserved": true, + "production_acceptance": false, + "synthetic_wrong_predecessor_http_denied": true + }, + "fixture_invocations": 3, + "all_invocations_passed": true, + "synthetic_only": true + }, + "applied_files_match_manifest": true, + "changed_shell_syntax": "passed", + "git_diff_check": "passed", + "log_digests": [ + { + "path": "tests-first.log", + "sha256": "a0fbaa85bce74ee4a0f8f0dceecf1d325cf691f213ba2778514f4bebba5bdb42" + }, + { + "path": "affected-tests.log", + "sha256": "8e28e73d1be88f3cbbb9ce10b735a9c84980fe07ab70a53fe6b2d077f82141ab" + }, + { + "path": "affected-tests-final.log", + "sha256": "fec294d3fa1a962a187fed8cb06646f5bff79b9369f932ee141e79464cbfabb2" + }, + { + "path": "native-first.json", + "sha256": "8e1ef3a7f0cf4c7bc2ca3d491f92db6f96071477bc0421b1451ca2f1e1b461e1" + }, + { + "path": "native-final.json", + "sha256": "8e1ef3a7f0cf4c7bc2ca3d491f92db6f96071477bc0421b1451ca2f1e1b461e1" + }, + { + "path": "native-verified.json", + "sha256": "8e1ef3a7f0cf4c7bc2ca3d491f92db6f96071477bc0421b1451ca2f1e1b461e1" + } + ], + "source_secret_scan": { + "status": "clean", + "changed_blobs": 11, + "version": "8.30.1", + "scanner_sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509" + } + }, + "behavior": [ + "Both wrappers disable tracing and delegate to one attended helper; memory-only getpass input, no temp secret files, raw notes or ambient endpoint overrides.", + "Named shared transport profiles restrict extra origins, routes, methods and payloads; no privacyIDEA token in LLDAP or discovery requests.", + "Existing configuration only; public-state/target digest and fresh prewrite check precede one minimal type/BINDPW update with exact preservation readback.", + "Native candidate/stored LDAP bind, exact user and token-backed MFA checks prevent cached lookup or passthru false proof.", + "Reconcile explicitly pins kubeconfig, context, server and cluster UID and requires observed generation/current single replica readiness; canonical discovery validation.", + "Predecessor unavailable yields incomplete/exit 2, supplied denial does not establish provenance; ambiguous writes remain unverified without retry." + ], + "limits": [ + "No live credential retrieval, rotation, cluster or deployment changes. Founder-deferred rotation remains deferred.", + "Native fixture uses real local LDAP and privacyIDEA/HOTP but substitutes cluster and KeyCape health gates; full attended production procedure remains unexercised.", + "privacyIDEA has no CAS here. Exclusive owner window, reviewed source/target/custody and forward recovery remain necessary; digest and terminal confer no authority.", + "Check mode has authentication/audit/OTP-counter effects and proves stored bind usability, not equality with a supplied candidate.", + "Owner-proven predecessor identity, KeyCape flow and incident acceptance remain external. No rollback to exposed predecessor.", + "NK-WP-0049-T02 stays progress for full caller/root-output inventory; T03 stays wait for owner-native recovery/consumer acceptance. Broad consolidation goal remains cleared." + ], + "knowledge_orientation": { + "version": "0.2.6", + "digest": "8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02", + "cards": [ + "start", + "identity" + ], + "status": "withheld/source-changed/orientation-only; current caller, shared transport, provider implementation and owner runbook reviewed" + } +} diff --git a/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md b/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md index eb77d9c..0402011 100644 --- a/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md +++ b/workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md @@ -499,6 +499,25 @@ structural-only (exit 2), not lifecycle/login/recovery acceptance. Receipt: No live estate change. Incident-cutover/full inventory and owner-approved native recovery/estate acceptance keep NK-WP-0049 and G08 open. +2026-10-14 bounded incident resolver source repair completed in NetKingdom +`4dffe2f`. Both helpers now use attended memory-only input, scoped shared +transport, configuration/target-bound preview, one minimal password update and +native candidate/stored LDAP bind verification. Full reconcile pins cluster +identity/readiness, validates discovery, exact user and token-backed MFA, and +records missing predecessor evidence as incomplete. Raw notes, temporary secret +files, ambient endpoint overrides and default-overwriting writes are removed. + +Validation: 171 affected tests pass, plus disposable real privacyIDEA 3.12.2 and +LLDAP demonstrate bind refusal/replacement, preservation and actual HOTP. The +initial one-test fixture failure is retained; cluster/KeyCape gates are substituted +only in the native fixture, with production acceptance explicitly unverified. +Source docs/inventory and NK-WP-0049 are updated. Evidence: +`docs/evidence/2026-10-14-netkingdom-security/resolver-cutover.json`. +No live cutover or privileged credential retrieval. Full caller/root-output +inventory keeps T02 progress and owner-native recovery keeps T03 wait. The broad +consolidation goal remains cleared; this finishes only the requested current +resolver-helper task. Playwright T05 retains its existing owner-return gates. + ## Verify native closure against every requirement ```task