Skip to content

server: stop passing seed passwords as command-line arguments #535

Description

@peteski22

Background

Follow-up agreed in #526 (review thread). The seed targets pass the password as a command-line argument; #526 deliberately kept its existing interface rather than change it, because reworking it touches the Docker path and the documented commands too. Quoting the thread:

The password exposure concern remains valid, but this PR does not need to make that cross-workflow interface decision. A follow-up should define the protected-input interface and update the scripts, Make targets, DEVELOPMENT.md, and the quickstart together.

Problem

PASS reaches the seed scripts as an argv value, which exposes it three ways:

  1. Make echoes the recipe. No seed recipe is @-prefixed and there is no .SILENT, so the full command — password included — is printed to the terminal and into any CI log:

    $ make seed-users USER=demo PASS=hunter2
    docker compose exec cq-server /app/.venv/bin/python /app/scripts/seed-users.py --username "demo" --password "hunter2"
  2. Process arguments are world-readable. While the script runs, the password is visible in ps output to any user on the host.

  3. Shell expansion can alter it before the script sees it. The recipes interpolate $(PASS) into a double-quoted shell word, so a password containing `, $(, or ${ is expanded rather than passed through — the user silently gets an account with a different password than they typed.

Scope

Both interfaces take it as a required argument:

Script Argument
server/scripts/seed-users.py --password (required=True)
server/scripts/seed-kus.py --pass → dest="password" (required=True)

Six Make targets pass it — the Docker trio and the local trio added in #526:

Target Line
seed-users Makefile:127
seed-kus Makefile:137
seed-all Makefile:147-148
dev-seed-users Makefile:173
dev-seed-kus Makefile:189
dev-seed-all Makefile:202-203

Note seed-all and dev-seed-all re-pass PASS to their sub-makes, so the value appears more than once per run.

Docs to update in the same change:

  • README.md:94 (quickstart)
  • DEVELOPMENT.md:63, :73-75, and the Docker Compose table at :137-139

Suggested approach

Define one protected-input interface and apply it across both scripts and all six targets, rather than fixing them piecemeal:

  • Read the password from an env var (e.g. CQ_SEED_PASSWORD) and/or from stdin, keeping --password/--pass only if there's a reason to (if kept, it should probably warn).
  • Fall back to getpass.getpass() when the input is a TTY and nothing was supplied, so the interactive path needs no flag at all.
  • @-prefix the seed recipes so the command stops being echoed regardless.
  • Pass the value through the environment rather than interpolating it into a shell word, which fixes the expansion problem in (3) as a side effect.

This is a breaking change to a documented command interface, so it wants a deliberate decision on whether PASS= keeps working (deprecated but accepted) or is removed outright.

Also worth folding in

seed-users / seed-kus / seed-all guard USER with ifndef USER, which never fires because every POSIX shell exports USER — they silently seed an account named after whoever ran the command. #526 fixed this for the dev- trio only (via $(origin USER) plus an empty-value check) and left the Docker trio alone to stay scoped. Already tracked separately in #530, but the two overlap in the same recipes, so they may be worth doing together.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    infraDocker, CI, MakefileserverFor issues or PRs related to the 'server' component.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions