From 63ad5ec37d910ad0f23b49543949bbf5dfe0755c Mon Sep 17 00:00:00 2001 From: data-engineer Date: Wed, 20 May 2026 09:53:12 -0700 Subject: [PATCH] fix(tests): isolate cloud-sync HOME so dev ~/.gradata/key doesn't leak (closes #216) CloudClient.enabled falls through to _resolved_credential() which reads ~/.gradata/key. The TestCloudClient test fixtures didn't isolate HOME, so on any dev machine that had actually run 'gradata cloud enable', the real keyfile leaked into the test and two 'should-be-disabled' tests failed: - TestCloudClient::test_client_disabled_by_default - TestCloudClient::test_client_disabled_without_token Add an autouse fixture on TestCloudClient that: 1. Points HOME at a per-test tmp dir 2. Drops GRADATA_API_KEY from the env 3. Redirects the module-level KEYFILE_DIR/KEYFILE_PATH in gradata.cloud._credentials (those are captured at import time via Path.home(), so /home/olive alone isn't enough) Tests that rely on enabled=True still pass because they pass an explicit token on CloudConfig, which short-circuits the keyfile lookup. --- Gradata/tests/test_cloud_sync.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Gradata/tests/test_cloud_sync.py b/Gradata/tests/test_cloud_sync.py index ba295d97..221390c6 100644 --- a/Gradata/tests/test_cloud_sync.py +++ b/Gradata/tests/test_cloud_sync.py @@ -6,6 +6,8 @@ from pathlib import Path from unittest.mock import patch +import pytest + from gradata.cloud.sync import ( CloudClient, CloudConfig, @@ -98,6 +100,30 @@ def test_conflict_threshold_garbage_falls_back(self, tmp_path: Path): class TestCloudClient: + @pytest.fixture(autouse=True) + def isolate_credential_resolution(self, monkeypatch, tmp_path): + """Prevent dev's real ~/.gradata/key from leaking into these tests. + + CloudClient.enabled falls through to _resolved_credential() which + reads ~/.gradata/key. Without isolation, any dev who has actually + used Gradata locally would see test_client_disabled_* tests fail. + See GitHub issue #216. + + The keyfile module captures ``Path.home() / ".gradata" / "key"`` at + import time, so just setting $HOME isn't enough — we redirect the + module-level KEYFILE_PATH/KEYFILE_DIR directly. + """ + from gradata.cloud import _credentials + + fake_home = tmp_path / "home" + fake_home.mkdir() + monkeypatch.setenv("HOME", str(fake_home)) + monkeypatch.delenv("GRADATA_API_KEY", raising=False) + monkeypatch.setattr(_credentials, "KEYFILE_DIR", fake_home / ".gradata") + monkeypatch.setattr( + _credentials, "KEYFILE_PATH", fake_home / ".gradata" / "key" + ) + def test_client_disabled_by_default(self, tmp_path: Path): client = CloudClient(tmp_path) assert client.enabled is False