Skip to content

test: cover manage.py, the offline recovery CLI (0% → 59%) - #64

Merged
FMSMITH91 merged 2 commits into
mainfrom
test/manage-cli
Aug 9, 2026
Merged

test: cover manage.py, the offline recovery CLI (0% → 59%)#64
FMSMITH91 merged 2 commits into
mainfrom
test/manage-cli

Conversation

@FMSMITH91

Copy link
Copy Markdown
Owner

The tool you reach for when the web UI can't help — forgotten password, deactivated sole admin, lost 2FA device — had no tests at all. Bad place for a gap: its whole job is to work on the day nothing else does.

21 checks across four properties, each mutation-verified:

property why it matters mutation
lock-out guard deactivating/demoting the last active superadmin is refused and rolled back; an inactive admin isn't cover; a second admin makes it allowed removing the guard → 5 fail
session revocation a reset bumps auth_epoch, or a stolen cookie outlives the reset meant to kill it 1 fail
2FA disable-2fa wipes the secret, not just the flag — otherwise re-enabling silently restores the old device 1 fail
no guessing with no terminal it defaults to the sole superadmin and otherwise refuses; disable-2fa never defaults at all 1 fail

Plus create-admin refusing to clobber, a weak --password rejected before anything is written, unknown usernames refused, and the interactive menu accepting a number, a name, or a retry.

The harness now admits when it crashes

Writing this I hit three of my own bugs — a wrong helper name, assigning to the read-only sys.stdin.isatty, and calling a DB function outside an app context. Each one just made the suite print fewer checks and still say "all passed." That's the same failure mode that let a broken dashboard.js through earlier today. A crash is now a failure, with its traceback.

Wired into tools/run-tests.sh (so CI runs it) and the coverage job.

🤖 Generated with Claude Code

The tool you reach for when the web UI cannot help — forgotten password,
deactivated sole admin, a lost 2FA device — had no tests at all. That is a
bad place for a gap: its whole job is to work on the day nothing else does.

21 checks, four properties, each mutation-verified:

  the lock-out guard   deactivating or demoting the LAST active superadmin is
                       refused AND rolled back, an inactive admin does not
                       count as cover, and a second admin makes it allowed.
                       Removing the guard fails 5 checks.
  session revocation   a password reset bumps auth_epoch, or a stolen cookie
                       outlives the reset meant to kill it. Fails 1.
  2fa                  disable-2fa wipes the SECRET, not just the flag —
                       otherwise re-enabling silently restores the old
                       device. Fails 1.
  no guessing          with no terminal it defaults to the sole superadmin
                       and otherwise refuses; disable-2fa never defaults at
                       all. Fails 1.

Plus create-admin (refuses to clobber), weak --password rejected before
anything is written, unknown username refused, and the interactive menu
accepting a number, a name, or a retry.

The harness reports a mid-run crash instead of hiding it. Writing this, three
of my own bugs — a wrong helper name, assigning to the read-only
sys.stdin.isatty, and calling a DB function with no app context — each just
made the suite print fewer checks and still say "all passed". A crash is a
failure and prints its traceback now.

Wired into tools/run-tests.sh (so CI runs it) and into the coverage job.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codacy-production

codacy-production Bot commented Aug 8, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Coverage ∅ diff coverage · +0.59% coverage variation

Metric Results
Coverage variation +0.59% coverage variation (-1.00%)
Diff coverage diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (29346ff) 11928 5670 47.54%
Head commit (3bafea5) 11928 (+0) 5740 (+70) 48.12% (+0.59%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#64) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

… corpus repo exists

cflite_pr.yml fuzzes what a PR changed, for three minutes, starting from the
committed seeds every time. These add the other half: nightly across all five
targets for 15 minutes, and a weekly prune plus a coverage report showing
which lines the fuzzers actually reach.

The reason those modes were left out is that they need somewhere to keep the
corpus between runs, which is a separate repo and a token. So every job is
guarded by `if: env.CFL_STORAGE_REPO != ''` — with no secret they are skipped
and green, and they start working by themselves the moment one is added. Same
shape as the Codacy upload: nothing to remember, nothing red in the meantime.

Also `if: github.repository == ...` so a fork never burns its own minutes on
this, and language: python on run_fuzzers, which defaults to c++ and does not
inherit it from the build step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@FMSMITH91
FMSMITH91 merged commit baa15c0 into main Aug 9, 2026
21 checks passed
@FMSMITH91
FMSMITH91 deleted the test/manage-cli branch August 9, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant