"""`hfmd` CLI: idempotent seed from a JSON file / env var, users add/list/set-tier/disable, keys list/rotate, --show-key discipline. No real address is hard-coded anywhere (A21).""" from __future__ import annotations import json from sqlalchemy import func, select SEED = [ {"name": "Seed One", "email": "seed-one@example.com", "tier": "free", "role": "user"}, {"name": "Seed Two", "email": "seed-two@example.com", "tier": "free", "role": "user"}, {"name": "Seed Three", "email": "seed-three@example.com", "tier": "free", "role": "user"}, {"name": "Seed Admin", "email": "seed-admin@example.com", "tier": "high_usage", "role": "admin"}, ] def run(cli, capsys, *argv) -> tuple[int, str]: rc = cli.main(list(argv)) out = capsys.readouterr() return rc, out.out + out.err def test_no_hardcoded_addresses(app): import inspect from accounts import cli src = inspect.getsource(cli) assert "gmail.com" not in src and "@spboucher.ai" not in src.split('"""', 2)[2] # author line in the docstring only def test_seed_from_file_is_idempotent(app, capsys, tmp_path): from accounts import cli from accounts.models import ApiKey, EmailToken, User from core.db import session seed_file = tmp_path / "seed.json" seed_file.write_text(json.dumps(SEED)) rc, out = run(cli, capsys, "seed", str(seed_file)) assert rc == 0, out for u in SEED: assert u["email"] in out assert "accept-invite?token=" in out and "hfmd_live_" in out assert out.count("hfmd_live_") == 4 # prefixes only, one per user assert "api_key" not in out # full keys hidden without --show-key def counts(): with session() as s: users = {u.email: u for u in s.execute(select(User)).scalars()} keys = s.execute(select(func.count()).select_from(ApiKey).where(ApiKey.status == "active", ApiKey.user_id.in_([u.id for u in users.values()]))).scalar_one() toks = s.execute(select(func.count()).select_from(EmailToken).where(EmailToken.used_at.is_(None), EmailToken.user_id.in_([u.id for u in users.values()]))).scalar_one() return users, keys, toks users, keys, toks = counts() seeded = {u["email"]: users[u["email"]] for u in SEED} assert seeded["seed-admin@example.com"].role == "admin" and seeded["seed-one@example.com"].role == "user" assert all(u.status == "invited" for u in seeded.values()) rc, out2 = run(cli, capsys, "seed", str(seed_file)) assert rc == 0 users2, keys2, toks2 = counts() assert len(users2) == len(users) and keys2 == keys and toks2 == toks # nothing duplicated # the same pending invitation links are printed again links1 = sorted(line.split()[-1] for line in out.splitlines() if "accept-invite?token=" in line) links2 = sorted(line.split()[-1] for line in out2.splitlines() if "accept-invite?token=" in line) assert links1 == links2 and len(links1) == 4 def test_seed_from_env_and_errors(app, capsys, monkeypatch, tmp_path): from accounts import cli monkeypatch.delenv(cli.SEED_ENV, raising=False) rc, out = run(cli, capsys, "seed") assert rc == 1 and "no seed" in out monkeypatch.setenv(cli.SEED_ENV, json.dumps([{"name": "Env Person", "email": "env-person@example.com"}])) rc, out = run(cli, capsys, "seed", "--no-mail") assert rc == 0 and "env-person@example.com" in out bad = tmp_path / "bad.json" bad.write_text("{not json") rc, out = run(cli, capsys, "seed", str(bad)) assert rc == 1 and "not valid JSON" in out def test_users_add_show_key_and_management(app, capsys): from accounts import cli email = "cli-person@example.com" rc, out = run(cli, capsys, "users", "add", "CLI Person", email, "--tier", "high_usage", "--show-key", "--no-mail") assert rc == 0 and email in out and "high_usage" in out full = [tok for tok in out.split() if tok.startswith("hfmd_live_") and len(tok) == 42] assert len(full) == 1 # the full key, exactly once # second add: no new key, no key printed, tier untouched rc, out = run(cli, capsys, "users", "add", "CLI Person", email, "--tier", "free", "--show-key", "--no-mail") assert rc == 0 and "high_usage" in out assert not [tok for tok in out.split() if tok.startswith("hfmd_live_") and len(tok) == 42] rc, out = run(cli, capsys, "keys", "list", email) assert rc == 0 and out.count("active") == 1 rc, out = run(cli, capsys, "keys", "rotate", email, "--show-key") assert rc == 0 and len([tok for tok in out.split() if tok.startswith("hfmd_live_") and len(tok) == 42]) == 1 rc, out = run(cli, capsys, "keys", "list", email) assert rc == 0 and out.count("active") == 1 and out.count("revoked") == 1 rc, out = run(cli, capsys, "users", "set-tier", email, "free") assert rc == 0 and "tier = free" in out rc, out = run(cli, capsys, "users", "disable", email) assert rc == 0 and "status = disabled" in out rc, out = run(cli, capsys, "users", "enable", email) assert rc == 0 and "status = active" in out rc, out = run(cli, capsys, "users", "invite-resend", email, "--no-mail") assert rc == 0 and "accept-invite?token=" in out rc, out = run(cli, capsys, "users", "list") assert rc == 0 and email in out rc, out = run(cli, capsys, "keys", "list", "nobody@example.com") assert rc == 1 and "USER_NOT_FOUND" in out