fix(google_chat): harden oauth credential persistence with atomic private writes (#24788)

This commit is contained in:
Zyrix
2026-05-24 17:58:52 -07:00
committed by GitHub
parent bf2f3b2469
commit 782681f904
2 changed files with 129 additions and 22 deletions
+79
View File
@@ -1516,6 +1516,13 @@ class TestSetupFilesSlashCommand:
class TestUserOAuthHelper:
@staticmethod
def _assert_private_json_file(path, expected):
assert json.loads(path.read_text(encoding="utf-8")) == expected
assert list(path.parent.glob(f"{path.stem}.tmp.*")) == []
if os.name != "nt":
assert (path.stat().st_mode & 0o777) == 0o600
def test_load_user_credentials_returns_none_when_no_token(self, tmp_path, monkeypatch):
"""Missing token file is the expected no-op case (user hasn't
run /setup-files yet). Must NOT raise."""
@@ -1610,6 +1617,78 @@ class TestUserOAuthHelper:
assert a != legacy
assert "google_chat_user_oauth_pending" in str(a.parent)
def test_persist_credentials_writes_private_json(self, tmp_path, monkeypatch):
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
from plugins.platforms.google_chat.oauth import _persist_credentials, _token_path
creds = type(
"Creds",
(),
{
"to_json": lambda self: json.dumps(
{
"client_id": "cid",
"client_secret": "secret",
"refresh_token": "rtok",
"token": "atok",
}
)
},
)()
path = _token_path("alice@example.com")
_persist_credentials(creds, path)
self._assert_private_json_file(
path,
{
"client_id": "cid",
"client_secret": "secret",
"refresh_token": "rtok",
"token": "atok",
"type": "authorized_user",
},
)
def test_store_client_secret_writes_private_json(self, tmp_path, monkeypatch):
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
src = tmp_path / "client_secret.json"
payload = {"installed": {"client_id": "cid", "client_secret": "secret"}}
src.write_text(json.dumps(payload), encoding="utf-8")
from plugins.platforms.google_chat.oauth import (
_client_secret_path,
store_client_secret,
)
store_client_secret(str(src))
self._assert_private_json_file(_client_secret_path(), payload)
def test_save_pending_auth_writes_private_json(self, tmp_path, monkeypatch):
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
from plugins.platforms.google_chat.oauth import (
_REDIRECT_URI,
_pending_auth_path,
_save_pending_auth,
)
_save_pending_auth(
state="state-123",
code_verifier="verifier-abc",
email="alice@example.com",
)
self._assert_private_json_file(
_pending_auth_path("alice@example.com"),
{
"state": "state-123",
"code_verifier": "verifier-abc",
"redirect_uri": _REDIRECT_URI,
"email": "alice@example.com",
},
)
class TestPerUserAttachmentRouting:
"""The bot must use the *requesting user's* OAuth token when sending