Skip to content

Commit 2221efa

Browse files
committed
More
1 parent 4f91da8 commit 2221efa

File tree

5 files changed

+75
-29
lines changed

5 files changed

+75
-29
lines changed

packages/gg_api_core/src/gg_api_core/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ async def _ensure_oauth_token(self):
250250
return
251251

252252
logger.warning("Acquired OAuth lock, proceeding with authentication")
253-
logger.info(f" Client API URL: {self.api_url}")
253+
logger.info(f" Client API URL: {self.api_url}") # TODO(TIM)
254254
logger.info(f" Client Dashboard URL: {self.dashboard_url}")
255255
logger.info(f" Client Server Name: {getattr(self, 'server_name', 'None')}")
256256

packages/gg_api_core/src/gg_api_core/tools/list_repo_occurrences.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,8 @@
3535
] # We exclude "INVALID" ones
3636

3737

38-
class ListRepoOccurrencesParams(BaseModel):
39-
"""Parameters for listing repository occurrences."""
40-
repository_name: str | None = Field(
41-
default=None,
42-
description="The full repository name. For example, for https://github.com/GitGuardian/gg-mcp.git the full name is GitGuardian/gg-mcp. Pass the current repository name if not provided. Not required if source_id is provided."
43-
)
44-
source_id: str | None = Field(
45-
default=None,
46-
description="The GitGuardian source ID to filter by. Can be obtained using find_current_source_id. If provided, repository_name is not required."
47-
)
48-
ordering: str | None = Field(default=None, description="Sort field (e.g., 'date', '-date' for descending)")
49-
per_page: int = Field(default=20, description="Number of results per page (default: 20, min: 1, max: 100)")
50-
cursor: str | None = Field(default=None, description="Pagination cursor for fetching next page of results")
51-
get_all: bool = Field(default=False, description="If True, fetch all results using cursor-based pagination")
52-
53-
# Filters
38+
class ListRepoOccurrencesFilters(BaseModel):
39+
"""Filters for listing repository occurrences."""
5440
from_date: str | None = Field(
5541
default=None, description="Filter occurrences created after this date (ISO format: YYYY-MM-DD)"
5642
)
@@ -68,6 +54,26 @@ class ListRepoOccurrencesParams(BaseModel):
6854
validity: list[str] | None = Field(default=DEFAULT_VALIDITIES, description="Filter by validity (list of validity names)")
6955

7056

57+
class ListRepoOccurrencesBaseParams(BaseModel):
58+
"""Parameters for listing repository occurrences."""
59+
repository_name: str | None = Field(
60+
default=None,
61+
description="The full repository name. For example, for https://github.com/GitGuardian/gg-mcp.git the full name is GitGuardian/gg-mcp. Pass the current repository name if not provided. Not required if source_id is provided."
62+
)
63+
source_id: str | None = Field(
64+
default=None,
65+
description="The GitGuardian source ID to filter by. Can be obtained using find_current_source_id. If provided, repository_name is not required."
66+
)
67+
ordering: str | None = Field(default=None, description="Sort field (e.g., 'date', '-date' for descending)")
68+
per_page: int = Field(default=20, description="Number of results per page (default: 20, min: 1, max: 100)")
69+
cursor: str | None = Field(default=None, description="Pagination cursor for fetching next page of results")
70+
get_all: bool = Field(default=False, description="If True, fetch all results using cursor-based pagination")
71+
72+
73+
class ListRepoOccurrencesParams(ListRepoOccurrencesFilters, ListRepoOccurrencesBaseParams):
74+
pass
75+
76+
7177
def _build_filter_info(params: ListRepoOccurrencesParams) -> dict[str, Any]:
7278
"""Build a dictionary describing the filters applied to the query."""
7379
filters = {}

packages/gg_api_core/src/gg_api_core/tools/remediate_secret_incidents.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@
55

66
from gg_api_core.client import TagNames
77
from gg_api_core.utils import get_client
8-
from .list_repo_occurrences import list_repo_occurrences, ListRepoOccurrencesParams
8+
from .list_repo_occurrences import list_repo_occurrences, ListRepoOccurrencesParams, ListRepoOccurrencesFilters
99
from .list_repo_incidents import list_repo_incidents
1010

1111
logger = logging.getLogger(__name__)
1212

1313

14-
class RemediateSecretIncidentsParams(BaseModel):
14+
class RemediateOccurrencesFilters(ListRepoOccurrencesFilters):
15+
tags: list[str] = Field(
16+
default=[TagNames.DEFAULT_BRANCH.value],
17+
description="List of tags to filter incidents by. Default to DEFAULT_BRANCH to avoid requiring a git checkout for the fix",
18+
)
19+
20+
21+
class RemediateSecretIncidentsParams(RemediateOccurrencesFilters):
1522
"""Parameters for remediating secret incidents."""
1623
repository_name: str = Field(
1724
description="The full repository name. For example, for https://github.com/GitGuardian/gg-mcp.git the full name is GitGuardian/gg-mcp. Pass the current repository name if not provided.",
@@ -21,20 +28,24 @@ class RemediateSecretIncidentsParams(BaseModel):
2128
description="The source ID of the repository. Pass the current repository source ID if not provided.",
2229
default=None
2330
)
31+
get_all: bool = Field(default=True, description="Whether to get all incidents or just the first page")
32+
mine: bool = Field(
33+
default=False,
34+
description="If True, fetch only incidents assigned to the current user. Set to False to get all incidents.",
35+
)
36+
37+
# Behaviour
2438
include_git_commands: bool = Field(
2539
default=True, description="Whether to include git commands to fix incidents in git history"
2640
)
2741
create_env_example: bool = Field(
2842
default=True, description="Whether to create a .env.example file with placeholders for detected secrets"
2943
)
30-
get_all: bool = Field(default=True, description="Whether to get all incidents or just the first page")
31-
mine: bool = Field(
32-
default=False,
33-
description="If True, fetch only incidents assigned to the current user. Set to False to get all incidents.",
34-
)
35-
tags: list[str] = Field(
36-
default=[TagNames.DEFAULT_BRANCH.value],
37-
description="List of tags to filter incidents by. Default to DEFAULT_BRANCH to avoid requiring a git checkout for the fix",
44+
45+
# sub tools
46+
list_repo_occurrences_params: RemediateOccurrencesFilters = Field(
47+
default_factory=RemediateOccurrencesFilters,
48+
description="Parameters for listing repository occurrences",
3849
)
3950

4051
@model_validator(mode="after")
@@ -86,11 +97,14 @@ async def remediate_secret_incidents(params: RemediateSecretIncidentsParams) ->
8697

8798
try:
8899
# Get detailed occurrences with exact match locations
100+
# Extract filter parameters from list_repo_occurrences_params
101+
filter_params = params.list_repo_occurrences_params.model_dump(exclude_none=True)
102+
89103
occurrences_params = ListRepoOccurrencesParams(
90104
repository_name=params.repository_name,
91105
source_id=params.source_id,
92106
get_all=params.get_all,
93-
tags=params.tags,
107+
**filter_params, # Spread the filter parameters
94108
)
95109
occurrences_result = await list_repo_occurrences(occurrences_params)
96110

tests/tools/test_list_repo_occurrences.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ async def test_list_repo_occurrences_with_repository_name(
6767
assert result["repository"] == "GitGuardian/test-repo"
6868
assert result["occurrences_count"] == 1
6969
assert len(result["occurrences"]) == 1
70+
assert "applied_filters" in result
71+
assert "suggestion" in result
7072

7173
@pytest.mark.asyncio
7274
async def test_list_repo_occurrences_with_source_id(self, mock_gitguardian_client):
@@ -101,6 +103,8 @@ async def test_list_repo_occurrences_with_source_id(self, mock_gitguardian_clien
101103

102104
# Verify response
103105
assert result["occurrences_count"] == 1
106+
assert "applied_filters" in result
107+
assert "suggestion" in result
104108

105109
@pytest.mark.asyncio
106110
async def test_list_repo_occurrences_with_filters(self, mock_gitguardian_client):
@@ -169,6 +173,8 @@ async def test_list_repo_occurrences_get_all(self, mock_gitguardian_client):
169173
# Verify response
170174
assert result["occurrences_count"] == 2
171175
assert len(result["occurrences"]) == 2
176+
assert "applied_filters" in result
177+
assert "suggestion" in result
172178

173179
@pytest.mark.asyncio
174180
async def test_list_repo_occurrences_no_repository_or_source(
@@ -285,6 +291,8 @@ async def test_list_repo_occurrences_empty_response(self, mock_gitguardian_clien
285291
# Verify response
286292
assert result["occurrences_count"] == 0
287293
assert len(result["occurrences"]) == 0
294+
assert "applied_filters" in result
295+
assert "suggestion" in result
288296

289297
@pytest.mark.asyncio
290298
async def test_list_repo_occurrences_unexpected_response_type(
@@ -307,3 +315,5 @@ async def test_list_repo_occurrences_unexpected_response_type(
307315
# Verify response defaults to empty
308316
assert result["occurrences_count"] == 0
309317
assert result["occurrences"] == []
318+
assert "applied_filters" in result
319+
assert "suggestion" in result

tests/tools/test_remediate_secret_incidents.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ async def test_remediate_secret_incidents_success(self, mock_gitguardian_client)
9797
},
9898
}
9999
],
100+
"applied_filters": {},
101+
"suggestion": "",
100102
}
101103

102104
# Mock get_current_token_info for filtering by assignee
@@ -143,7 +145,11 @@ async def test_remediate_secret_incidents_no_occurrences(
143145
THEN: A message indicating no occurrences is returned
144146
"""
145147
# Mock list_repo_occurrences to return empty occurrences
146-
mock_occurrences = {"occurrences": []}
148+
mock_occurrences = {
149+
"occurrences": [],
150+
"applied_filters": {"tags_exclude": ["TEST_FILE"]},
151+
"suggestion": "No occurrences matched the applied filters.",
152+
}
147153

148154
# Patch list_repo_occurrences
149155
with patch(
@@ -161,6 +167,8 @@ async def test_remediate_secret_incidents_no_occurrences(
161167
assert "message" in result
162168
assert "No secret occurrences found" in result["message"]
163169
assert result["remediation_steps"] == []
170+
assert "applied_filters" in result
171+
assert "suggestion" in result
164172

165173
@pytest.mark.asyncio
166174
async def test_remediate_secret_incidents_error(self, mock_gitguardian_client):
@@ -221,6 +229,8 @@ async def test_remediate_secret_incidents_mine_false(
221229
},
222230
}
223231
],
232+
"applied_filters": {},
233+
"suggestion": "",
224234
}
225235

226236
# Patch list_repo_occurrences
@@ -270,6 +280,8 @@ async def test_remediate_secret_incidents_no_git_commands(
270280
},
271281
}
272282
],
283+
"applied_filters": {},
284+
"suggestion": "",
273285
}
274286

275287
# Mock get_current_token_info
@@ -326,6 +338,8 @@ async def test_remediate_secret_incidents_no_env_example(
326338
},
327339
}
328340
],
341+
"applied_filters": {},
342+
"suggestion": "",
329343
}
330344

331345
# Mock get_current_token_info
@@ -401,6 +415,8 @@ async def test_remediate_secret_incidents_multiple_files(
401415
},
402416
},
403417
],
418+
"applied_filters": {},
419+
"suggestion": "",
404420
}
405421

406422
# Mock get_current_token_info

0 commit comments

Comments
 (0)