Commit Graph
624 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Fable 5 b885573315 fix: make the test-profile generator hermetic and re-runnable
test_profile_init_integration failed on any machine with a generated test
profile already present. Two causes, both real bugs rather than test noise:

- scripts/generate_test_profile.py mutated constants.APP_DIR at import time
  to append "tests". The value was captured when constants was first
  imported -- long before a test can monkeypatch Path.home -- so the script
  read the developer's real ~/.seedpass/tests, and a reload appended another
  "tests" segment. The mutation also leaked into every other importer of
  constants in the same process. The tests directory is now derived per call
  from constants.APP_DIR instead.

- initialize_profile assumed add_fingerprint returns None for an existing
  profile, which is what its docstring still promises; it actually raises
  ValueError. Re-running the generator against an existing profile therefore
  crashed. It now treats "already exists" as the ordinary case.

test_profile_init_integration also repoints constants.APP_DIR so it no
longer depends on the developer's home directory, and
test_generate_test_profile asserts against the derived tests directory
rather than the mutated global.

Verified hermetic: the test passes repeatedly and touches nothing under the
real ~/.seedpass. Full Python suite: 1178 passed, 16 skipped, 0 failed.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-14 21:16:24 -04:00
thePR0M3TH3ANandClaude Fable 5 5dcd779a6f fix(python): TOTP codes must honor the entry's period and digits
TotpManager built pyotp.TOTP(secret) with library defaults (6 digits, 30s)
and ignored what the entry recorded, so any imported or derived entry using
other values produced codes the issuing service rejects. The service was
configured from the entry's values -- those govern the code.

- current_code_from_secret and current_code take period/digits
- EntryManager.get_totp_code passes the entry's values for both the
  derived and imported paths
- display_service, menu_handler (totp_list now carries digits) and the GUI
  updated at every call site
- regression tests for imported and deterministic entries with custom
  parameters, asserting against pyotp with the matching interval/digits,
  and confirming default entries are byte-identical to before

Found by scripts/cross_impl_check.py, which flagged it as a divergence
against the TypeScript port. That allowance is now removed: the suite
asserts TOTP equality and reports 30/30 with zero divergences.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-14 16:41:04 -04:00
thePR0M3TH3ANandClaude Opus 5 786106b15b Fix the 15 remaining test failures; suite is green
1176 passed, 0 failed. These were all reachable only after 9e0f045 stopped
the runner exiting early, and every one had a distinct cause.

One real bug, in index0.py. _build_children_view sorted entry ids with
int(str(id)), which raised ValueError on any id that is not a decimal
string. That happens inside view building during index load, so a single
malformed id made the whole vault fail to open -- for a password manager
that is indistinguishable from data loss. Non-numeric ids now sort after
numeric ones rather than crashing; a bad id should degrade the ordering, not
brick the index.

Eight stale assertions against a schema that moved on. The index now carries
a machine-managed _system.index0 block (canonical views, writer ids, scope
paths) added on load, so tests that saved a literal dict and compared it
back always differed by exactly that key -- the round trips themselves were
correct the whole time. Adds helpers.user_data() to drop it, and uses it in
the export/import, legacy-migration and nostr-fallback tests. Those tests
are about user data surviving; asserting on _system would pin an
implementation detail they are not about.

Three checksum tests patched seams that no longer exist. They stubbed
manager.verify_checksum (gone) and manager.calculate_checksum, which
handle_verify_checksum no longer reaches -- it now asks
_script_checksum_status, which returns early on a launch-target mismatch
before any checksum is computed. Rewritten against that seam, plus a new
case for the target-mismatch verdict, which nothing covered.

Two tests stubbed builtins.input but not sys.stdin.isatty. Both code paths
refuse a non-TTY before ever calling input, so they returned early under
pytest. Uses the isatty stub the rest of the suite already uses.

One test asserted the opposite of the intended contract.
test_setup_encryption_manager_rejects_wrong_argon2_params expected a seed to
be UNREADABLE when the profile's argon2_time_cost differs from the one it
was written with. But encrypt_parent_seed stores its KdfConfig and
setup_encryption_manager tries those stored params first, deliberately: the
profile config says how to derive NEW keys, and refusing an existing seed
because a preference changed would lock a user out of their own vault.
Renamed and inverted to assert the real behaviour.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
2026-07-31 22:48:38 -04:00
thePR0M3TH3ANandClaude Opus 5 9e0f045ccb Stop the test suite exiting 0 after 10% of its tests
`pytest src/tests` died at 123 of 1170 tests with exit code 0 -- no summary,
no coverage report, and a shell that saw success. Four tests reach code
paths that call os._exit(0), which skips interpreter finalization and takes
pytest with it.

The os._exit is deliberate and stays: some builds with native extensions
intermittently SIGSEGV during teardown after an otherwise clean shutdown,
which is why _exit_as_main_process exists. But that reasoning applies to the
real process exit, not to a function under test. Adds _terminate(), which
raises SystemExit when PYTEST_CURRENT_TEST is set and calls os._exit
otherwise, and routes the three in-process exit paths through it.

This restores a contract the tests already assumed:
test_auto_sync_triggers_post asserts `pytest.raises(SystemExit)`. It was
written when display_menu raised, and the later switch to os._exit did not
fail that test -- it killed the runner instead, which is why nobody noticed.

The suite now runs to completion: 1160 passed, 15 failed, 16 skipped, and it
exits 1 rather than claiming success.

Those 15 were always failing; they were simply never reached. Five of them
were mine, and this is the uncomfortable part: the gen_version argument
added in 2aed95a broke more FakePasswordGenerator doubles than I found,
because the earlier regression run stopped before reaching them and I
concluded "no new failures" from a truncated result. All 20 remaining
doubles now take **_, so they absorb gen_version and anything added later
rather than needing a sweep each time the real signature grows.

The other 10 are pre-existing and unrelated -- legacy-migration and
checksum-backup failures, an index0.py int-parsing bug
(`invalid literal for int() with base 10: 'temp'`), and one that needs a TTY
this environment lacks.

Determinism gate still green.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
2026-07-31 22:31:19 -04:00
thePR0M3TH3ANandClaude Opus 5 3192c9f306 Offer a 24-word master seed, and put the entropy draw beyond reach of any handler
L2: generate_bip85_seed and create_profile_from_generated_seed now take
words_num, accepting 12 or 24 and rejecting anything else with a clear
message. The default stays 12 -- every existing profile uses it, 128 bits is
entirely adequate, and moving the default would change nothing about
existing vaults while surprising anyone creating a new one. 24 is offered
because the master seed protects the whole vault and was the one secret
shorter than the seeds derived beneath it, which already default to 24.

L3: fixed structurally rather than by narrowing exception types.
os.urandom(32) now sits OUTSIDE the try block, so no handler can stand
between the entropy draw and the caller -- an entropy failure is unreachable
by anything that could substitute a value. Also removes a redundant
`except Exception` whose body was identical to the `Bip85Error` branch above
it.

The structural form is stronger than an exception list, and the test says so
precisely: it asserts the OSError reaching the caller is the SAME OBJECT
os.urandom threw, which holds only if nothing caught and repackaged it.
Listing exception types would still leave a handler in the path for someone
to widen later.

Adds five tests: the identity assertion above, 12- and 24-word generation,
the default staying 12, and rejection of 0/11/18/25/-12.

Determinism gate green (89 tests, up from 84). The seed/profile regression
subset is 143 passed with one failure --
test_profile_export_import_round_trip -- confirmed against the pre-change
baseline as pre-existing.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
2026-07-31 17:43:24 -04:00
thePR0M3TH3ANandClaude Opus 5 2aed95a687 Version password generation; freeze v1, add v2 without the class quota
Passwords are never stored -- they are re-derived on demand from
(seed, index, length, policy) -- and entries carried no algorithm version.
Any change to generate_password therefore changed every existing password in
every vault, unrecoverably. This adds the version field that makes such
changes possible at all, then makes three.

Safety net first (M4). test_entropy_integrity.py freezes 18 v1 vectors
spanning every policy and both sides of the 32-byte stream-wrap boundary,
and asserts the RNG fails closed: os.urandom raising must abort seed
generation, short reads must abort, AES-GCM nonces must be fresh. Each guard
was mutation-verified rather than assumed -- removing _balance_distribution,
perturbing the stream wrap, or altering the character mapping each turns all
18 vectors red, and adding a hash-of-timestamp fallback to
generate_bip85_seed turns the fail-closed test red.

generate_password now takes gen_version, defaulting to 1. Existing entries
carry no field and keep deriving v1 byte-identically; the argument is only
forwarded when non-legacy, so all 13 call sites across CLI, API and both
TUIs are untouched. New password entries are stamped gen_version 2. An
unreadable version raises rather than guessing which algorithm produced a
password.

v2 fixes three findings:
- M1: drops the forced equal-quarters class quota. 1 -> 82 distinct class
  compositions at length 16 over 200 samples; per-character entropy
  6.42 -> 6.53 bits against a 6.555 ceiling.
- M2: rejection sampling instead of byte % len(alphabet). Chi-square 96.1
  against df=93 (p<0.001 critical value ~147).
- M3: an unbounded HMAC-expanded stream instead of cycling a 32-byte key,
  which was a repeating pad for passwords over 32 characters. Lag-32 repeat
  rate now sits within one standard error of chance.

Dropping the quota removed an accidental backstop: v1's minimum enforcement
overwrites uniformly random positions, so raising one class minimum could
destroy another, and only the quota's near-total rewrite hid it. v2 chooses
donor positions solely from classes that currently have a surplus, and
rejects a policy whose minima cannot fit the requested length.

Also removes a dead HKDF derivation whose result was discarded while the
docstrings named it as the algorithm in use (L1); PBKDF2 was and remains the
real one. Verified as a negative control -- the vectors stayed green.

Six test doubles are updated to the real generate_password signature; they
began receiving gen_version once new entries carried it.

Existing entries stay on v1 by design. An opt-in per-entry upgrade, with a
confirmation making the consequence unmissable, is still to come.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01HtNMsKzzFTPURemX7tT19u
2026-07-31 16:27:23 -04:00
thePR0M3TH3AN 6cd33b7ea8 fix: update profile removal assertion to match new intro text 2026-03-10 16:09:30 -04:00
thePR0M3TH3ANandClaude Sonnet 4.6 3b031eb365 feat(tui-v3): sort/filter keyboard shortcuts, active-state toolbar, clear filter
- Add keyboard bindings: n=sort label_asc, r=sort modified_desc, k=sort kind, f=clear filter
- Add action_sort_label/recent/kind/clear_filter actions to app.py
- GridToolbar: add 'Kind' sort button, '[X] Clear' button
- GridToolbar: visual active-state via .active CSS class (synced via watchers)
- Add 5 new smoke tests: keyboard sort, clear button, clear shortcut, state persistence, toolbar active class

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-10 08:23:35 -04:00
thePR0M3TH3AN 96f64d00bc tui3: guard against non-interactive stdin with TTY check
Add _stdin_is_tty() helper and check at start of _launch_tui3_or_exit.
When stdin is not a TTY, emit a clear error message and exit 1 instead
of propagating an EOF exception from seed setup prompts.
Add test for non-interactive stdin error path; patch _stdin_is_tty in
existing tests that expect tui3 launch to proceed.

Fixes SeedPass-6d26
2026-03-09 12:45:34 -04:00
thePR0M3TH3ANandClaude Sonnet 4.6 44fe1c630a v3 polish: rename Profiles button, improve restore guidance
- action_bar.py: rename 'Remove Seed' label to 'Profiles' for clarity
- app.py: add warning prefix (⚠) to nostr/backup restore pre-action
  status messages; add success message to generate flow; improve
  import success message wording
- test_tui_v3_parity.py: update label assertions from 'Remove Seed'
  to 'Profiles' (two tests)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-07 08:08:56 -05:00
thePR0M3TH3AN 41f000e802 Merge branch 'overstory/builder-action-strip/SeedPass-57f6' into beta
# Conflicts:
#	src/tests/test_tui_v3_parity.py
2026-03-06 13:47:40 -05:00
thePR0M3TH3AN a6c7391f78 Merge branch 'overstory/builder-app-cmds/SeedPass-865f' into beta 2026-03-06 13:47:35 -05:00
thePR0M3TH3AN 1a58c63658 Merge branch 'overstory/builder-settings-inspector/SeedPass-865f' into beta 2026-03-06 13:47:31 -05:00
thePR0M3TH3AN 00b1b7d3ec feat(tui-v3): migrate legacy utility/maintenance commands to v3 CommandProcessor 2026-03-06 13:44:07 -05:00
thePR0M3TH3ANandClaude Sonnet 4.6 ea5ad1f093 Fix managed_account QR exclusion and bare except in action_bar
- Remove 'qr' from managed_account context actions (accounts don't expose
  a QR-scannable key like seeds/nostr do)
- Change bare 'except:' to 'except Exception:' on vault manager check
- Add test_v3_action_bar_managed_account_excludes_qr in parity tests

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-06 13:41:24 -05:00
thePR0M3TH3ANandClaude Sonnet 4.6 446d1ef2b8 TUI v3: tighten action strip + restore/import guidance (SeedPass-57f6)
action_bar.py:
- Fix global row broken handlers: Remove Seed → open_profile_management,
  Backup Data → open_backup_parent_seed, Export/Import Data → open_palette
  (export/import need a path argument, palette is the right entry point)

add.py:
- seedplus-hint: mention BIP-85 explicitly, reference Seed+ (C) action
- AddEntryScreen success notify: include reveal/copy shortcut hint
- SeedPlusScreen: add #seedplus-warning label explaining deterministic
  derivation and index uniqueness requirement
- SeedPlusScreen success notify: mention index and parent seed

app.py:
- RecoverProfileScreen: set success status before bootstrap fires
- CreateProfileScreen: add intent messaging for nostr/backup restore modes
  with progress description and post-success status

grid.py:
- Add stored_password to secrets filter kind_map (was missing)

tests:
- test_tui_v3_parity: add test_v3_action_bar_global_row_uses_correct_handlers
- test_tui_v3_smoke: add seedplus-hint BIP-85 check, seedplus-warning label
  check, recover success-status check

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-06 13:36:34 -05:00
thePR0M3TH3ANandClaude Sonnet 4.6 02c4ef9e24 feat(tui-v3): add settings utility section and inspector kind-specific hints
Settings screen now renders a UTILITY & MAINTENANCE card listing stats,
db-export, db-import, checksum-verify/update, totp-export, and offline
mode commands. Renders gracefully when config service is offline (no
early return — all sections including utility always display).

Inspector adds UtilityHintsBar widget that persists across board swaps
via a #board-slot Vertical. Hints update to show kind-appropriate
palette commands (copy, reveal keybinds, QR, npub, managed-load, etc.).
BoardContainer now routes managed_account to its own SeedBoard hint set.

Two new smoke tests verify the utility section renders and that hints
update correctly for password, nostr, and idle states.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-06 13:35:49 -05:00
thePR0M3TH3ANandClaude Sonnet 4.6 50d7b1827d Polish TUI v3 maintenance and profile screens
- maintenance.py: refine CSS visual hierarchy (rounded intro card borders,
  red-tinted danger buttons, consistent panel/footer margins)
- profile.py: clearer label text, improved intro and confirmation messages
- security.py: updated intro text and footer hints for both screens
- pubkey.py: rename DEFAULT_CSS to CSS, update intro and footer text
- relays.py: rename DEFAULT_CSS to CSS, add intro card, update footer/status
- test_tui_v3_smoke.py: update assertions to match new text

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-03-06 13:30:08 -05:00
thePR0M3TH3AN 46ffff577b Improve v3 grid navigation and graph browsing 2026-03-06 07:10:36 -05:00
thePR0M3TH3AN 4011464c31 Advance v3 search, atlas, and comms planning 2026-03-05 23:26:05 -05:00
thePR0M3TH3AN e8a2b81e7b Make TUI v3 the default and add index0 foundations 2026-03-05 21:52:39 -05:00
thePR0M3TH3AN 033870f2df fix: harden legacy/tui3 non-tty flows and shutdown stability 2026-03-03 21:56:55 -05:00
thePR0M3TH3AN 538ce42338 chore: format codebase and harden v3 CLI/CI gates 2026-03-03 21:22:19 -05:00
thePR0M3TH3AN c822eeb602 feat(tui-v3): implement core functional parity (Phase A/B)
- Implement secure data parity (Reveal/QR/Copy) for SSH, PGP, Nostr, Key-Value, and Documents.
- Update derive_pgp_key and API to support PGP Public Key retrieval and copying.
- Implement managed account loading/exiting (ml/mx) with reactive profile updates.
- Integrate semantic search (keyword/hybrid/semantic) into the entry grid.
- Create AddEntryScreen (unified wizard), SeedPlusScreen (BIP-85), and DocumentEditScreen.
- Add grid filter presets (secrets, docs, keys, 2fa) and archive view toggle.
- Update ActionBar and GridMetrics to be dynamic and context-aware.
- Add comprehensive v3 parity tests and update existing core tests for PGP tuple changes.
2026-03-03 07:40:34 -05:00
thePR0M3TH3AN d3920ccc4c Update TUI v3 plan and land parity fixes with smoke tests 2026-03-02 23:43:07 -05:00
thePR0M3TH3AN 4eeb936e6d docs(test): centralize test infrastructure and add interactive agent harness
Added docs/TEST_INVENTORY.md as a central index for all tests and runners.
Created scripts/interactive_agent_tui_test.py for password-free TUI v2
exploratory testing. Integrated standalone permission tests into main
suite and fixed TUI v2 parity regression tests broken by auto-selection
removal. Updated AGENTS.md and CLAUDE.md with strategic plan references.
2026-03-02 22:26:35 -05:00
thePR0M3TH3ANandClaude Opus 4.6 165c825d9e feat(tui-v2): shorten wide action lines and add exploratory walkthrough tests
Shorten TOTP Actions line from 99→78 chars and Seed/Managed from 91→75
chars to fit standard terminal widths. Add 12-test exploratory walkthrough
covering all 9 entry types, archive/restore lifecycle, managed sessions,
vault lock/unlock, density modes, filters, links, card frames, error
handling, search, and a full user journey.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 21:44:51 -05:00
thePR0M3TH3AN 2691387e83 Merge pull request #976 from PR0M3TH3AN/agents/daily/decompose-agent-15790542744234676036
Run daily decompose-agent
2026-03-02 21:33:12 -05:00
thePR0M3TH3ANandClaude Opus 4.6 6f2b9a6d18 fix(tui-v2): handle non-existent entries and tree nav focus feedback
Opening a non-existent entry now shows "Entry not found" instead of
rendering a broken empty board. Tree navigation commands now give
clear feedback when focus is on wrong pane or sidebar is collapsed.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 21:26:30 -05:00
thePR0M3TH3ANandClaude Opus 4.6 08e71bd1b4 feat(tui-v2): cap card width, fix hint casing, verb-first compact strip
Add max_width=72 to _board_card so Content cards don't stretch across
viewport. Capitalize Nostr QR Private hint. Compact mode global strip
now uses verb-first labels matching normal and dense modes.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 21:07:20 -05:00
thePR0M3TH3ANandClaude Opus 4.6 de12289d3e feat(tui-v2): tighten action strip labels and board hint lines
Normal-mode global row now uses verb-first labels with key hints.
Seed and TOTP action hints shortened from raw palette commands to
user-facing verbs for consistent readability.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 21:02:40 -05:00
thePR0M3TH3ANandClaude Opus 4.6 5af052499b feat(tui-v2): tighten board density by removing redundant headers
Remove plain-text section labels above card frames since card titles
are self-descriptive. Remove compact-mode noise line. Cap note preview
at 100 chars. Saves 2-4 lines per board for better viewport fit.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 20:59:37 -05:00
thePR0M3TH3ANandClaude Opus 4.6 d1807ddab6 feat(tui-v2): extend card framing to all remaining inspector boards
TOTP, SSH, PGP, Nostr, and Seed/Managed Account boards now use
_board_card sections matching Password/Note treatment for consistent
visual language across all 9 board types.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-03-02 20:54:17 -05:00
thePR0M3TH3AN 0ec4b86076 feat(tui-v2): polish action strip copy and rebalance dense layout 2026-03-02 20:24:58 -05:00
thePR0M3TH3AN 64971851ae fix(tui-v2): restore managed session flow and dynamic action strip 2026-03-02 19:55:11 -05:00
thePR0M3TH3AN c32d5e84a7 tui2: fix dense grid labels and profile-tree visibility 2026-03-02 19:26:11 -05:00
thePR0M3TH3AN 64a8b9f8b5 tui2: harden pane-state flow and dense layout parity 2026-03-02 19:03:21 -05:00
thePR0M3TH3AN 9fc8abccc8 tui2: add profile-aware filter menu and sensitive-state UX polish 2026-03-02 17:52:43 -05:00
thePR0M3TH3AN 8e3aaa8653 cli: restore legacy launch compatibility and fix tui v2 header rendering 2026-03-02 15:51:25 -05:00
thePR0M3TH3AN a4de52ae4a tui v2: close 2fa url parity and advance strict mockup closeout 2026-03-02 15:41:35 -05:00
google-labs-jules[bot]andPR0M3TH3AN 1123807d7b fix: resolve ci failures
- fix unformatted test file src/tests/test_nostr_resilience_failure_modes.py
- fix missing PYTHONPATH and use poetry run in scripts/tui2_check_smoke.sh
- fix failing test test_legacy_index_reinit_syncs_once_when_confirmed by updating sync call assertion
- configure run_ci_tests.sh to use proper python binary

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-03-02 19:04:11 +00:00
thePR0M3TH3AN f0c120f84d feat: add semantic search modes across cli api and tuis 2026-03-02 12:28:24 -05:00
thePR0M3TH3AN ec407c611a feat: wire semantic controls into legacy and tui v2 interfaces 2026-03-02 11:52:30 -05:00
thePR0M3TH3AN 165e2db204 feat: add semantic index scaffolding, cli/api surfaces, and tui tree nav polish 2026-03-02 11:44:17 -05:00
thePR0M3TH3AN a67ee2d9da tui2: add export-field actions and density/tree ui polish 2026-03-02 11:04:20 -05:00
thePR0M3TH3AN 93cf78b2c8 tui2: default profiles online and add phase4 inspector boards 2026-03-02 10:11:56 -05:00
thePR0M3TH3AN 8f7075c39b tui2: add onboarding flow and session parity affordances 2026-03-02 09:44:25 -05:00
thePR0M3TH3AN 5c524b2086 tui2: add quickstart and stats parity UX flows 2026-03-02 09:31:56 -05:00
thePR0M3TH3AN 3f0d4a8d89 tui2: add full in-app palette command reference 2026-03-02 09:20:04 -05:00
thePR0M3TH3AN 45cd27ea4f tests: add deterministic nostr sync failure-mode coverage 2026-03-02 09:06:26 -05:00