fix: redact identity secrets through a public hook and mask issued agm_ tokens
ci / gitleaks (push) Successful in 8s
ci / docs-check (push) Failing after 30s
ci / lint (push) Successful in 42s
ci / test-integration (push) Successful in 46s
ci / security (push) Failing after 27s
ci / test-mcp (push) Successful in 1m16s
ci / test-unit (push) Successful in 2m17s
ci / build-and-push (push) Successful in 17s

Identity gains a redact field that the executor honours, so the OAuth
resolver no longer needs an executor subclass overriding private
internals. Opaque agm_ tokens issued by our authorization server are now
masked by the secret patterns wherever they appear in content.
This commit is contained in:
Latte committed 2026-10-14 16:45:36 +02:00
1 parent e02cede9f2
commit ce5ae6caa5
8 files changed
+37 -38

No files matched your search

+3 -7
View File
@@ -11,13 +11,12 @@ from mcp.server.auth.provider import AccessToken
from aegis_gitea_mcp.auth import STATIC_CLIENT_ID
from aegis_gitea_mcp.errors import ToolError
from aegis_gitea_mcp.gitea import GiteaExecutor
from aegis_gitea_mcp.identity import Identity
from aegis_gitea_mcp.oauth.resolver import (
OAUTH_ONLY,
SIGN_IN_AGAIN,
OAuthGiteaExecutor,
OAuthIdentityResolver,
SessionIdentity,
)
from aegis_gitea_mcp.oauth.store import OAuthStore, SessionRecord, TokenRecord
from aegis_gitea_mcp.oauth.upstream import UpstreamError, UpstreamInvalidGrant, UpstreamTokens
@@ -108,7 +107,6 @@ async def test_oauth_token_resolves_to_the_session_user(tmp_path: Path) -> None:
clock = FakeClock()
identity = await resolver(make_store(tmp_path, clock), clock=clock).resolve(oauth_access())
assert isinstance(identity, SessionIdentity)
assert (identity.login, identity.mode, identity.token) == ("alice", "oauth", USER_TOKEN)
assert identity.redact == (USER_REFRESH,)
assert USER_TOKEN not in repr(identity) and USER_REFRESH not in repr(identity)
@@ -341,14 +339,12 @@ async def test_audit_failure_does_not_block_ending_a_session(
async def test_executor_redacts_session_secrets(httpx_mock: Any) -> None:
executor = OAuthGiteaExecutor(oauth_settings(), extra_secrets=[ENCRYPTION_KEY])
executor = GiteaExecutor(oauth_settings(), extra_secrets=[ENCRYPTION_KEY])
httpx_mock.add_response(
url="https://gitea.example.com/api/v1/version",
json={"a": USER_REFRESH, "b": ENCRYPTION_KEY, "c": USER_TOKEN},
)
identity = SessionIdentity(
login="alice", mode="oauth", token=USER_TOKEN, redact=(USER_REFRESH,)
)
identity = Identity(login="alice", mode="oauth", token=USER_TOKEN, redact=(USER_REFRESH,))
outcome = await executor.request("GET", "/version", identity)
await executor.aclose()