feat: operator-only user export (moshcode export users [--clean]) - #532
Merged
Merged
Conversation
- app: GET /api/admin/users/export?format=csv|json, gated by a new ADMIN_EMAILS allowlist (API key or session). Returns email, display_name, created_at (ISO), id and signup_method for accounts with an email, plus counts of the rest. password_hash and coinpay_sub are never selected. - cli: `moshcode export users [--clean] [--format csv|json] [-o file]` and `/export users` in the pit. Files are 0600 and backed up before overwrite; the pit always writes a file and prints only its path and counts. - --clean pipes the CSV through cli-tools' email-cleaner (fails if it is not on PATH), keeps the valid rows, and writes <name>.rejected.csv with reasons. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ThreatCrush Security Scan7 finding(s) in the 13 file(s) this pull request changes. MEDIUM: 7
94 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 8 | **MEDIUM**: 75 | **LOW**: 11Not introduced by this pull request. The full set is in the Security tab.
…and 74 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces reading the prod DB by hand to get the signup list.
App (apps/pwa)
GET /api/admin/users/export?format=csv|json: email, display_name, created_at (ISO), id, signup_method (password / passkey / coinpay) for every account with an email, oldest first. Accounts without an email are counted (by method), never listed. JSON addscounts; CSV carries them inX-Users-*headers.Cache-Control: no-store.ADMIN_EMAILSallowlist (comma-separated, case-insensitive), checked against the API key's user (Bearer wins when sent) or the browser session. Unset means nobody: 403 for all. 401 with no/bad key.password_hashorcoinpay_sub, onlyIS NOT NULLflags. Display names that look like spreadsheet formulas are prefixed with'.[admin] <operator> exported N users.CLI
moshcode export users [--clean [cleaner flags]] [--format csv|json] [-o file]. CSV to stdout, or to-owith mode 0600 (an existing file is copied to<name>.bak-NNN.<ext>first). Counts and paths go to stderr, so stdout stays clean CSV./export usersin the pit: always writes a file (~/.moshcode/exports/users-<time>.csvunless-o), prints only the path and counts, never addresses.--cleanrunsemail-cleaner - --format json --report [flags]from cli-tools with the CSV on stdin. It passes through--allow-role --allow-disposable --allow-duplicates --allow-unlikely --allow-no-website --no-dns --fix-typos. Ifemail-cleaneris not on PATH it fails with one line saying to install cli-tools, before any request. Kept rows come out in the same columns (a--fix-typoscorrection replaces the address). With-o, rejected rows go to<name>.rejected.csvwithreasonsandsuggestioncolumns. Prints total / kept / rejected by reason.Tests
apps/pwa/test/admin-users-export.test.mjs: 401 / 403 (non-operator, unset allowlist, other operator), CSV shape and order, formula neutralising, no secrets in CSV or JSON, JSON counts, bad format 400. Skips cleanly without PWA deps (checked).test/export-users.test.mjs: arg grammar, CSV, missing email-cleaner,--cleanplumbing against a stubemail-cleaneron PATH (argv + stdin asserted),--fix-typos, pit mode never prints addresses, 0600 + backups, 403 handling, and an end-to-end run of the real binary against a fake app.Deploy note
Set
ADMIN_EMAILSon the Railwaymoshcodeservice (e.g.anthony@profullstack.com) or every export returns 403. The CLI half needs a release beforemoshcode exportexists for installed users.🤖 Generated with Claude Code