Externalize auth secrets to .env and rename default config to triggershell.yml

sessionSecret was previously baked directly into the scaffolded config file;
`triggershell init` now generates a .env with TRIGGERSHELL_SESSION_SECRET
instead and references it via ${VAR} interpolation, keeping the actual
secret out of the (often committed) config file. `triggershell dev/start/
validate` load that .env automatically without overriding real env vars.

Also renames the default config filename from triggershell.config.yaml to
triggershell.yml throughout the CLI, app, docs, and examples.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 19:15:03 +02:00
co-authored by Claude Sonnet 5
parent ced99a8e75
commit 80c11d3bd3
12 changed files with 126 additions and 31 deletions
+44 -3
View File
@@ -7,6 +7,7 @@ from triggershell.bootstrap import (
BootstrapError,
check_node,
ensure_dependencies_installed,
load_dotenv_for_config,
needs_build,
record_build_stamp,
)
@@ -73,7 +74,7 @@ def test_ensure_dependencies_installed_runs_when_stale(tmp_path: Path) -> None:
def test_needs_build_true_when_no_stamp(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
(app_dir / "src").mkdir(parents=True)
config_path = tmp_path / "triggershell.config.yaml"
config_path = tmp_path / "triggershell.yml"
config_path.write_text("scripts: []")
assert needs_build(app_dir, config_path) is True
@@ -82,7 +83,7 @@ def test_needs_build_true_when_no_stamp(tmp_path: Path) -> None:
def test_needs_build_false_after_stamp_recorded(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
(app_dir / "src").mkdir(parents=True)
config_path = tmp_path / "triggershell.config.yaml"
config_path = tmp_path / "triggershell.yml"
config_path.write_text("scripts: []")
record_build_stamp(app_dir, config_path)
@@ -95,7 +96,7 @@ def test_needs_build_true_after_config_touched(tmp_path: Path) -> None:
app_dir = tmp_path / "app"
(app_dir / "src").mkdir(parents=True)
config_path = tmp_path / "triggershell.config.yaml"
config_path = tmp_path / "triggershell.yml"
config_path.write_text("scripts: []")
record_build_stamp(app_dir, config_path)
@@ -107,3 +108,43 @@ def test_needs_build_true_after_config_touched(tmp_path: Path) -> None:
os.utime(config_path, (future, future))
assert needs_build(app_dir, config_path) is True
def test_load_dotenv_for_config_noop_when_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
import os
monkeypatch.delenv("TRIGGERSHELL_SESSION_SECRET", raising=False)
config_path = tmp_path / "triggershell.yml"
config_path.write_text("scripts: []")
load_dotenv_for_config(config_path)
assert "TRIGGERSHELL_SESSION_SECRET" not in os.environ
def test_load_dotenv_for_config_loads_values(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
import os
monkeypatch.delenv("TRIGGERSHELL_SESSION_SECRET", raising=False)
config_path = tmp_path / "triggershell.yml"
config_path.write_text("scripts: []")
(tmp_path / ".env").write_text("TRIGGERSHELL_SESSION_SECRET=from-dotenv-file\n")
load_dotenv_for_config(config_path)
assert os.environ["TRIGGERSHELL_SESSION_SECRET"] == "from-dotenv-file"
def test_load_dotenv_for_config_does_not_override_existing_env(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setenv("TRIGGERSHELL_SESSION_SECRET", "from-shell")
config_path = tmp_path / "triggershell.yml"
config_path.write_text("scripts: []")
(tmp_path / ".env").write_text("TRIGGERSHELL_SESSION_SECRET=from-dotenv-file\n")
load_dotenv_for_config(config_path)
import os
assert os.environ["TRIGGERSHELL_SESSION_SECRET"] == "from-shell"