diff --git a/README.md b/README.md index 7e0a0aa..cd630cd 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Straight-on, one shelf (or part of one) per shot, close enough that spine text i ## Bring your own shelves -This repo doubles as its author's live pipeline, so `data/` ships with his real artifacts — extracted titles, matches, and 2018 collection snapshots — and `config.toml` carries his username (your `BGG_USERNAME` in `.env` overrides it). Before running against *your* shelves, clear the data: +This repo doubles as its author's live pipeline, so `data/` ships with his real artifacts — extracted titles, matches, and 2018 collection snapshots. Before running against *your* shelves, clear the data: ```sh rm data/*.csv data/*.json data/*.xml data/STUB_DATA.marker diff --git a/config.toml b/config.toml index 2416a82..fe3d556 100644 --- a/config.toml +++ b/config.toml @@ -1,12 +1,5 @@ -# Non-secret configuration for bggpipe. Secrets (ANTHROPIC_API_KEY, -# BGG_PASSWORD, BGG_API_TOKEN) come from env vars only and must never -# appear here. - -# The BGG username isn't a secret (it's public on your profile), so it may -# live here — but BGG_USERNAME from .env OVERRIDES it, and since upload -# needs BGG_USERNAME anyway, .env alone is enough. Cloners: change or -# clear this. -bgg_username = "ewagoner" +# Non-secret knobs for bggpipe. Everything account-related — including +# your BGG username — lives in .env (see .env.example), not here. photos_dir = "photos" data_dir = "data" diff --git a/src/bggpipe/config.py b/src/bggpipe/config.py index 4be56a3..6fa8100 100644 --- a/src/bggpipe/config.py +++ b/src/bggpipe/config.py @@ -1,8 +1,9 @@ -"""Configuration: config.toml at the project root, env vars override. +"""Configuration: non-secret knobs from config.toml at the project root. -Secrets (ANTHROPIC_API_KEY, BGG_PASSWORD) are never stored here — they are -read from the environment at the point of use and must never be written to -disk or logs. +Everything account-related lives in the environment (.env via direnv): +secrets (ANTHROPIC_API_KEY, BGG_PASSWORD, BGG_API_TOKEN) because they must +never touch disk or logs, and BGG_USERNAME — public, but kept there so the +account has exactly one home. """ from __future__ import annotations @@ -46,7 +47,6 @@ def load_config(path: Path | None = None) -> Config: if p.exists(): raw = tomllib.loads(p.read_text()) known = { - "bgg_username": str, "photos_dir": Path, "data_dir": Path, "model": str, diff --git a/src/bggpipe/upload.py b/src/bggpipe/upload.py index 2c40c30..fabfcd5 100644 --- a/src/bggpipe/upload.py +++ b/src/bggpipe/upload.py @@ -499,7 +499,7 @@ def run_upload( def _run_verify(cfg: Config, client: BGGClient | None, log_path: Path) -> None: if not cfg.bgg_username: - typer.echo("--verify needs bgg_username (config.toml or BGG_USERNAME).") + typer.echo("--verify needs BGG_USERNAME in the environment.") return client = client or BGGClient(cfg.cache_dir, cfg.rate_limit_seconds) try: diff --git a/tests/test_config.py b/tests/test_config.py index 494540e..0c70644 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -13,19 +13,19 @@ def test_defaults_when_no_file(tmp_path, monkeypatch): def test_reads_toml(tmp_path, monkeypatch): monkeypatch.delenv("BGG_USERNAME", raising=False) p = tmp_path / "config.toml" - p.write_text( - 'bgg_username = "someone"\ndata_dir = "elsewhere"\nrate_limit_seconds = 3\n' - ) + p.write_text('data_dir = "elsewhere"\nrate_limit_seconds = 3\n') cfg = load_config(p) - assert cfg.bgg_username == "someone" assert cfg.data_dir == Path("elsewhere") assert cfg.rate_limit_seconds == 3.0 assert cfg.matches_path == Path("elsewhere/matches.csv") -def test_env_overrides_toml(tmp_path, monkeypatch): +def test_username_comes_from_env_only(tmp_path, monkeypatch): + # the account has exactly one home: BGG_USERNAME in the environment — + # a bgg_username key in config.toml is deliberately ignored p = tmp_path / "config.toml" p.write_text('bgg_username = "from_toml"\n') monkeypatch.setenv("BGG_USERNAME", "from_env") - cfg = load_config(p) - assert cfg.bgg_username == "from_env" + assert load_config(p).bgg_username == "from_env" + monkeypatch.delenv("BGG_USERNAME") + assert load_config(p).bgg_username == "" diff --git a/tests/test_smoke_live.py b/tests/test_smoke_live.py index 8f7ccca..3d2ae00 100644 --- a/tests/test_smoke_live.py +++ b/tests/test_smoke_live.py @@ -1,7 +1,7 @@ """The one test allowed to touch the real BGG API. Read-only, skipped by default; run with: uv run pytest --run-live -m live -Needs bgg_username in config.toml and BGG_API_TOKEN in the environment +Needs BGG_USERNAME and BGG_API_TOKEN in the environment (register at https://boardgamegeek.com/applications). """ @@ -20,7 +20,7 @@ from bggpipe.config import load_config def test_fetch_own_collection_read_only(tmp_path: Path) -> None: cfg = load_config() if not cfg.bgg_username: - pytest.skip("set bgg_username in config.toml to run the live smoke test") + pytest.skip("set BGG_USERNAME to run the live smoke test") if not os.environ.get("BGG_API_TOKEN"): pytest.skip("set BGG_API_TOKEN to run the live smoke test")