Store password/token hashes in .env by default too
triggershell users add/add-token now generate a TRIGGERSHELL_USER_<name>_
PASSWORD_HASH / TRIGGERSHELL_TOKEN_<name>_HASH variable in .env (creating
or updating it idempotently) and print a ${VAR} snippet to paste into
auth.users/auth.tokens, instead of printing the raw hash. Pass --inline to
get the old behavior, since a hash - unlike sessionSecret - is safe to
store directly in the config (same trust model as /etc/shadow); this just
gives people who don't want it there at all an easy option.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import dotenv_values
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from triggershell.cli import _slug, app
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
|
||||
def test_slug_normalizes_to_env_var_style() -> None:
|
||||
assert _slug("ci-bot") == "CI_BOT"
|
||||
assert _slug("Admin User") == "ADMIN_USER"
|
||||
assert _slug("__weird--name__") == "WEIRD_NAME"
|
||||
|
||||
|
||||
def test_users_add_stores_hash_in_dotenv(tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "triggershell.yml"
|
||||
config_path.write_text("scripts: []\n")
|
||||
|
||||
result = runner.invoke(app, ["users", "add", "admin", "--config", str(config_path)], input="s3cret\ns3cret\n")
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
env_path = tmp_path / ".env"
|
||||
assert env_path.exists()
|
||||
values = dotenv_values(env_path)
|
||||
assert values["TRIGGERSHELL_USER_ADMIN_PASSWORD_HASH"].startswith("$argon2id$")
|
||||
assert "${TRIGGERSHELL_USER_ADMIN_PASSWORD_HASH}" in result.output
|
||||
assert "$argon2id$" not in result.output.split("Stored")[0] # raw hash not printed pre-storage
|
||||
|
||||
|
||||
def test_users_add_inline_does_not_touch_dotenv(tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "triggershell.yml"
|
||||
config_path.write_text("scripts: []\n")
|
||||
|
||||
result = runner.invoke(
|
||||
app, ["users", "add", "admin", "--config", str(config_path), "--inline"], input="s3cret\ns3cret\n"
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert not (tmp_path / ".env").exists()
|
||||
assert "$argon2id$" in result.output
|
||||
|
||||
|
||||
def test_users_add_token_overwrites_existing_var(tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "triggershell.yml"
|
||||
config_path.write_text("scripts: []\n")
|
||||
|
||||
first = runner.invoke(app, ["users", "add-token", "ci-bot", "--config", str(config_path)])
|
||||
assert first.exit_code == 0, first.output
|
||||
first_hash = dotenv_values(tmp_path / ".env")["TRIGGERSHELL_TOKEN_CI_BOT_HASH"]
|
||||
|
||||
second = runner.invoke(app, ["users", "add-token", "ci-bot", "--config", str(config_path)])
|
||||
assert second.exit_code == 0, second.output
|
||||
values = dotenv_values(tmp_path / ".env")
|
||||
second_hash = values["TRIGGERSHELL_TOKEN_CI_BOT_HASH"]
|
||||
|
||||
assert first_hash != second_hash
|
||||
env_content = (tmp_path / ".env").read_text()
|
||||
assert env_content.count("TRIGGERSHELL_TOKEN_CI_BOT_HASH") == 1
|
||||
Reference in New Issue
Block a user