import textwrap import pytest from steward.config import load_bootstrap, _resolve_secret_key def test_load_bootstrap_from_yaml(tmp_path): cfg_file = tmp_path / "config.yaml" cfg_file.write_text(textwrap.dedent("""\ database: url: postgresql+asyncpg://user:pass@localhost/steward secret_key: test-secret """)) cfg = load_bootstrap(cfg_file) assert cfg["database_url"] == "postgresql+asyncpg://user:pass@localhost/steward" assert cfg["secret_key"] == "test-secret" def test_env_var_database_url_overrides_yaml(tmp_path, monkeypatch): cfg_file = tmp_path / "config.yaml" cfg_file.write_text("database:\n url: original\nsecret_key: s\n") monkeypatch.setenv("STEWARD_DATABASE_URL", "overridden") cfg = load_bootstrap(cfg_file) assert cfg["database_url"] == "overridden" def test_env_var_secret_key_overrides_yaml(tmp_path, monkeypatch): cfg_file = tmp_path / "config.yaml" cfg_file.write_text("database:\n url: x\nsecret_key: from-yaml\n") monkeypatch.setenv("STEWARD_SECRET_KEY", "from-env") cfg = load_bootstrap(cfg_file) assert cfg["secret_key"] == "from-env" def test_missing_database_url_raises(tmp_path): cfg_file = tmp_path / "config.yaml" cfg_file.write_text("secret_key: s\n") with pytest.raises(ValueError, match="Database URL is required"): load_bootstrap(cfg_file) # ── secret key resolution ────────────────────────────────────────────────────── def test_secret_key_existing_file_is_reused(tmp_path, monkeypatch): key_file = tmp_path / "secret.key" key_file.write_text("persisted-key\n") monkeypatch.setattr("steward.config._SECRET_KEY_FILE", key_file) monkeypatch.delenv("STEWARD_SECRET_KEY", raising=False) assert _resolve_secret_key({}) == "persisted-key" def test_secret_key_generated_and_persisted_when_writable(tmp_path, monkeypatch): key_file = tmp_path / "sub" / "secret.key" # parent doesn't exist yet monkeypatch.setattr("steward.config._SECRET_KEY_FILE", key_file) monkeypatch.delenv("STEWARD_SECRET_KEY", raising=False) key = _resolve_secret_key({}) assert key and key_file.read_text().strip() == key def test_secret_key_unpersistable_raises_instead_of_ephemeral(tmp_path, monkeypatch): # A file sits where a directory is needed, so mkdir/write fails → must raise # (an ephemeral key would silently orphan every encrypted secret). blocker = tmp_path / "blocker" blocker.write_text("not a dir") monkeypatch.setattr("steward.config._SECRET_KEY_FILE", blocker / "secret.key") monkeypatch.delenv("STEWARD_SECRET_KEY", raising=False) with pytest.raises(RuntimeError, match="could not persist"): _resolve_secret_key({}) # ── database connect timeout (bootstrap-only: it governs reaching the DB) ──── def test_db_connect_timeout_defaults_when_unset(tmp_path, monkeypatch): from steward.database import DB_CONNECT_TIMEOUT_SECONDS cfg_file = tmp_path / "config.yaml" cfg_file.write_text("database:\n url: x\nsecret_key: s\n") monkeypatch.delenv("STEWARD_DB_CONNECT_TIMEOUT", raising=False) cfg = load_bootstrap(cfg_file) assert cfg["db_connect_timeout"] == DB_CONNECT_TIMEOUT_SECONDS def test_db_connect_timeout_from_yaml(tmp_path, monkeypatch): cfg_file = tmp_path / "config.yaml" cfg_file.write_text( "database:\n url: x\n connect_timeout: 120\nsecret_key: s\n") monkeypatch.delenv("STEWARD_DB_CONNECT_TIMEOUT", raising=False) assert load_bootstrap(cfg_file)["db_connect_timeout"] == 120.0 def test_db_connect_timeout_env_overrides_yaml(tmp_path, monkeypatch): cfg_file = tmp_path / "config.yaml" cfg_file.write_text( "database:\n url: x\n connect_timeout: 120\nsecret_key: s\n") monkeypatch.setenv("STEWARD_DB_CONNECT_TIMEOUT", "5") assert load_bootstrap(cfg_file)["db_connect_timeout"] == 5.0 def test_db_connect_timeout_garbage_falls_back_to_default(tmp_path, monkeypatch): from steward.database import DB_CONNECT_TIMEOUT_SECONDS cfg_file = tmp_path / "config.yaml" cfg_file.write_text("database:\n url: x\nsecret_key: s\n") monkeypatch.setenv("STEWARD_DB_CONNECT_TIMEOUT", "not-a-number") cfg = load_bootstrap(cfg_file) assert cfg["db_connect_timeout"] == DB_CONNECT_TIMEOUT_SECONDS def test_db_connect_timeout_non_positive_falls_back_to_default(tmp_path, monkeypatch): # 0 would mean "never wait", reinstating the crash this setting exists to fix. from steward.database import DB_CONNECT_TIMEOUT_SECONDS cfg_file = tmp_path / "config.yaml" cfg_file.write_text("database:\n url: x\nsecret_key: s\n") monkeypatch.setenv("STEWARD_DB_CONNECT_TIMEOUT", "0") cfg = load_bootstrap(cfg_file) assert cfg["db_connect_timeout"] == DB_CONNECT_TIMEOUT_SECONDS