diff --git a/tests/commands/test_scope.py b/tests/commands/test_scope.py index 9b09042..e80e344 100644 --- a/tests/commands/test_scope.py +++ b/tests/commands/test_scope.py @@ -269,14 +269,22 @@ def test_attest_writes_none_when_no_current_credential_resolves( db_path: Path, valid_config_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: _at_a_terminal(monkeypatch, yes=False) + # STATED, not inherited from the machine (#742). This asserted that the real + # `current_credential_fingerprint` resolves to None, which is true only when the process + # environment, the `.env` at `default_env_path()` and the OS keychain are ALL empty -- true + # in CI, false for any contributor with a configured deployment, where `CDP_API_KEY` + # resolves from the `.env` and this failed. The behaviour under test is what the command + # WRITES when nothing resolves, so the "nothing resolves" half belongs in the fixture. + monkeypatch.setattr( + "keel.commands.scope.current_credential_fingerprint", lambda venue: None + ) result = _run( db_path, valid_config_path, "scope", "attest", "--read-only", "--venue", "coinbase", ) assert result.exit_code == 0, result.output record = _repo_at(db_path).get_venue_trade_scope("coinbase") assert record is not None - # No credentials are configured in this test's environment, so the real - # `current_credential_fingerprint` resolves to None -- written as-is, not defaulted away. + # An unresolvable credential is written AS None, not defaulted away. assert record.credential_fingerprint is None diff --git a/tests/execution/test_executor.py b/tests/execution/test_executor.py index c792c72..73f700f 100644 --- a/tests/execution/test_executor.py +++ b/tests/execution/test_executor.py @@ -3636,8 +3636,22 @@ def test_confirming_replaces_a_stale_fingerprint_rather_than_carrying_it_forward credential_fingerprint="stale" + "0" * 27, ) - with mock.patch.object( - executor, "current_credential_fingerprint", return_value="fresh" + "0" * 27 + # BOTH import sites, and they are patched to DIFFERENT values on purpose (#742). + # `current_credential_fingerprint` is imported independently by `execution/guards.py` + # (rail 20) and by `execution/executor.py`. This test is about what the EXECUTOR writes on + # confirmation, so rail 20 must not veto first -- and it vetoes on a resolvable fingerprint + # that disagrees with the stored "stale000...". `None` is exactly the "no evidence to + # disagree with" case that lets the entry through to the confirm step. + # + # That None was previously supplied by the machine rather than the test: CI has no + # credentials, so the unpatched `guards` call returned None and the test passed. On a + # contributor's box with a `.env`, it returned a real fingerprint, rail 20 vetoed, `execute` + # never reached the confirm, and this assertion failed with the fingerprint still stale. + with ( + mock.patch.object( + executor, "current_credential_fingerprint", return_value="fresh" + "0" * 27 + ), + mock.patch.object(guards, "current_credential_fingerprint", return_value=None), ): execute(_enter_signal(), FakeBroker(), repo, _config(), mode="autonomous", now_ts=NOW_TS)