From 6a0d09960be96619d26d080d8d4c420eb48adb25 Mon Sep 17 00:00:00 2001 From: Claude Sonnet 4.6 Date: Wed, 3 Jun 2026 00:00:00 +0000 Subject: wsgi: add create-test-users command Add create_test_users which auto-generates timestamped emails and random passwords for ephemeral test accounts, delegating DB creation to the __create_one_user__ helper introduced in the previous commit. --- gn_auth/wsgi.py | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/gn_auth/wsgi.py b/gn_auth/wsgi.py index 3b3b60b..a6d8b00 100644 --- a/gn_auth/wsgi.py +++ b/gn_auth/wsgi.py @@ -1,5 +1,7 @@ """Main entry point for project""" import os +import re +import secrets import sys import uuid import json @@ -134,6 +136,14 @@ def register_admin(): _VALID_ROLES_ = ("system-admin", "none") +_TEST_EMAIL_DOMAIN_ = "regression-tests.genenetwork.org" + + +def __normalise_name_for_email__(name: str) -> str: + """Lowercase and strip non-alphanumeric characters for use in an email.""" + return re.sub(r"[^a-z0-9]", "", name.lower()) + + def __create_one_user__(cursor, name: str, email: str, password: str, role: str) -> dict: """Create a single user in the DB and return their credential record.""" user = save_user(cursor, email, name, verified=True) @@ -236,6 +246,57 @@ def delete_users(user_ids): deleted = delete_users_by_id(conn, tuple(user_ids)) print(f"Deleted {deleted} user(s).") + +@app.cli.command() +@click.option("--session-timestamp", required=True, + help="Compact ISO 8601 UTC timestamp (e.g. 20260602T122700Z)") +@click.option("--user", "user_specs", multiple=True, + help='User spec: "name=...,role=..."') +@click.option("--output", "output_path", required=True, type=click.Path(), + help="Write credentials as JSON to this file (0600 permissions)") +def create_test_users(session_timestamp, user_specs, output_path): + """Create ephemeral test users with auto-generated email and password. + + Each --user option takes a comma-separated key=value string with the + following keys: name, role. + + Email: @regression-tests.genenetwork.org + Password: randomly generated. + + Output is written with 0600 permissions. Valid roles: system-admin, none. + """ + if not user_specs: + print("No users specified.", file=sys.stderr) + sys.exit(1) + + records = [] + with db.connection(app.config["AUTH_DB"]) as conn, db.cursor(conn) as cursor: + for spec_str in user_specs: + spec = __parse_user_spec__(spec_str) + name = spec.get("name", "").strip() + role = spec.get("role", "none").strip() + + if not name: + print(f"Missing 'name' in user spec: {spec_str!r}", file=sys.stderr) + sys.exit(1) + if role not in _VALID_ROLES_: + print( + f"Invalid role {role!r} in spec: {spec_str!r}. " + f"Valid roles: {_VALID_ROLES_}", + file=sys.stderr) + sys.exit(1) + + email = (f"{__normalise_name_for_email__(name)}" + f"{session_timestamp}@{_TEST_EMAIL_DOMAIN_}") + password = secrets.token_urlsafe(32) + + records.append( + __create_one_user__(cursor, name, email, password, role)) + + __write_output__( + {"session_timestamp": session_timestamp, "users": records}, + output_path) + ##### END: CLI Commands ##### if __name__ == '__main__': -- cgit 1.4.1