Skip to content

Commit 5dbfaa8

Browse files
committed
adding wip for tests
1 parent f14f0b3 commit 5dbfaa8

File tree

4 files changed

+247
-1
lines changed

4 files changed

+247
-1
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
.idea
22
cmd/github-mcp-server/github-mcp-server
3+
4+
# VSCode
35
.vscode/mcp.json
6+
47
# Added by goreleaser init:
58
dist/
6-
__debug_bin*
9+
__debug_bin*
10+
11+
# Go
12+
vendor

pkg/github/secret_scanning.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
func GetSecretScanningAlert(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
1717
return mcp.NewTool(
1818
"get_secret_scanning_alert",
19+
mcp.WithDescription(t("TOOL_GET_SECRET_SCANNING_ALERT_DESCRIPTION", "Get details of a specific secret scanning alert in a GitHub repository.")),
1920
mcp.WithString("owner",
2021
mcp.Required(),
2122
mcp.Description("The owner of the repository."),
@@ -74,6 +75,7 @@ func GetSecretScanningAlert(getClient GetClientFn, t translations.TranslationHel
7475
func ListSecretScanningAlerts(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
7576
return mcp.NewTool(
7677
"list_secret_scanning_alerts",
78+
mcp.WithDescription(t("TOOL_LIST_SECRET_SCANNING_ALERTS_DESCRIPTION", "List secret scanning alerts in a GitHub repository.")),
7779
mcp.WithString("owner",
7880
mcp.Required(),
7981
mcp.Description("The owner of the repository."),

pkg/github/secret_scanning_test.go

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,233 @@
11
package github
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"net/http"
7+
"testing"
8+
9+
"github.com/github/github-mcp-server/pkg/translations"
10+
"github.com/google/go-github/v69/github"
11+
"github.com/migueleliasweb/go-github-mock/src/mock"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func Test_GetSecretScanningAlert(t *testing.T) {
17+
mockClient := github.NewClient(nil)
18+
tool, _ := GetSecretScanningAlert(stubGetClientFn(mockClient), translations.NullTranslationHelper)
19+
20+
assert.Equal(t, "get_secret_scanning_alert", tool.Name)
21+
assert.NotEmpty(t, tool.Description)
22+
assert.Contains(t, tool.InputSchema.Properties, "owner")
23+
assert.Contains(t, tool.InputSchema.Properties, "repo")
24+
assert.Contains(t, tool.InputSchema.Properties, "alertNumber")
25+
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "alertNumber"})
26+
27+
// Setup mock alert for success case
28+
mockAlert := &github.SecretScanningAlert{
29+
Number: github.Ptr(42),
30+
State: github.Ptr("open"),
31+
HTMLURL: github.Ptr("https://github.com/owner/private-repo/security/secret-scanning/42"),
32+
}
33+
34+
tests := []struct {
35+
name string
36+
mockedClient *http.Client
37+
requestArgs map[string]interface{}
38+
expectError bool
39+
expectedAlert *github.SecretScanningAlert
40+
expectedErrMsg string
41+
}{
42+
{
43+
name: "successful alert fetch",
44+
mockedClient: mock.NewMockedHTTPClient(
45+
mock.WithRequestMatch(
46+
mock.GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber,
47+
mockAlert,
48+
),
49+
),
50+
requestArgs: map[string]interface{}{
51+
"owner": "owner",
52+
"repo": "repo",
53+
"alertNumber": float64(42),
54+
},
55+
expectError: false,
56+
expectedAlert: mockAlert,
57+
},
58+
{
59+
name: "alert fetch fails",
60+
mockedClient: mock.NewMockedHTTPClient(
61+
mock.WithRequestMatchHandler(
62+
mock.GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber,
63+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
64+
w.WriteHeader(http.StatusNotFound)
65+
_, _ = w.Write([]byte(`{"message": "Not Found"}`))
66+
}),
67+
),
68+
),
69+
requestArgs: map[string]interface{}{
70+
"owner": "owner",
71+
"repo": "repo",
72+
"alertNumber": float64(9999),
73+
},
74+
expectError: true,
75+
expectedErrMsg: "failed to get alert",
76+
},
77+
}
78+
79+
for _, tc := range tests {
80+
t.Run(tc.name, func(t *testing.T) {
81+
// Setup client with mock
82+
client := github.NewClient(tc.mockedClient)
83+
_, handler := GetSecretScanningAlert(stubGetClientFn(client), translations.NullTranslationHelper)
84+
85+
// Create call request
86+
request := createMCPRequest(tc.requestArgs)
87+
88+
// Call handler
89+
result, err := handler(context.Background(), request)
90+
91+
// Verify results
92+
if tc.expectError {
93+
require.Error(t, err)
94+
assert.Contains(t, err.Error(), tc.expectedErrMsg)
95+
return
96+
}
97+
98+
require.NoError(t, err)
99+
100+
// Parse the result and get the text content if no error
101+
textContent := getTextResult(t, result)
102+
103+
// Unmarshal and verify the result
104+
var returnedAlert github.Alert
105+
err = json.Unmarshal([]byte(textContent.Text), &returnedAlert)
106+
assert.NoError(t, err)
107+
assert.Equal(t, *tc.expectedAlert.Number, *returnedAlert.Number)
108+
assert.Equal(t, *tc.expectedAlert.State, *returnedAlert.State)
109+
assert.Equal(t, *tc.expectedAlert.HTMLURL, *returnedAlert.HTMLURL)
110+
111+
})
112+
}
113+
}
114+
115+
func Test_ListSecretScanningAlerts(t *testing.T) {
116+
// Verify tool definition once
117+
mockClient := github.NewClient(nil)
118+
tool, _ := ListSecretScanningAlerts(stubGetClientFn(mockClient), translations.NullTranslationHelper)
119+
120+
assert.Equal(t, "list_secret_scanning_alerts", tool.Name)
121+
assert.NotEmpty(t, tool.Description)
122+
assert.Contains(t, tool.InputSchema.Properties, "owner")
123+
assert.Contains(t, tool.InputSchema.Properties, "repo")
124+
assert.Contains(t, tool.InputSchema.Properties, "state")
125+
assert.Contains(t, tool.InputSchema.Properties, "secret_type")
126+
assert.Contains(t, tool.InputSchema.Properties, "resolution")
127+
assert.Contains(t, tool.InputSchema.Properties, "sort")
128+
assert.Contains(t, tool.InputSchema.Properties, "direction")
129+
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
130+
131+
// Setup mock alerts for success case
132+
mockAlerts := []*github.SecretScanningAlert{
133+
{
134+
Number: github.Ptr(42),
135+
State: github.Ptr("open"),
136+
HTMLURL: github.Ptr("https://github.com/owner/repo/security/code-scanning/42"),
137+
},
138+
{
139+
Number: github.Ptr(43),
140+
State: github.Ptr("fixed"),
141+
HTMLURL: github.Ptr("https://github.com/owner/repo/security/code-scanning/43"),
142+
},
143+
}
144+
145+
tests := []struct {
146+
name string
147+
mockedClient *http.Client
148+
requestArgs map[string]interface{}
149+
expectError bool
150+
expectedAlerts []*github.SecretScanningAlert
151+
expectedErrMsg string
152+
}{
153+
{
154+
name: "successful alerts listing",
155+
mockedClient: mock.NewMockedHTTPClient(
156+
mock.WithRequestMatchHandler(
157+
mock.GetReposSecretScanningAlertsByOwnerByRepoByAlertNumber,
158+
expectQueryParams(t, map[string]string{
159+
"ref": "main",
160+
"state": "open",
161+
"severity": "high",
162+
}).andThen(
163+
mockResponse(t, http.StatusOK, mockAlerts),
164+
),
165+
),
166+
),
167+
requestArgs: map[string]interface{}{
168+
"owner": "owner",
169+
"repo": "repo",
170+
"ref": "main",
171+
"state": "open",
172+
"severity": "high",
173+
},
174+
expectError: false,
175+
expectedAlerts: mockAlerts,
176+
},
177+
{
178+
name: "alerts listing fails",
179+
mockedClient: mock.NewMockedHTTPClient(
180+
mock.WithRequestMatchHandler(
181+
mock.GetReposSecretScanningAlertsByOwnerByRepo,
182+
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
183+
w.WriteHeader(http.StatusUnauthorized)
184+
_, _ = w.Write([]byte(`{"message": "Unauthorized access"}`))
185+
}),
186+
),
187+
),
188+
requestArgs: map[string]interface{}{
189+
"owner": "owner",
190+
"repo": "repo",
191+
},
192+
expectError: true,
193+
expectedErrMsg: "failed to list alerts",
194+
},
195+
}
196+
197+
for _, tc := range tests {
198+
t.Run(tc.name, func(t *testing.T) {
199+
// Setup client with mock
200+
client := github.NewClient(tc.mockedClient)
201+
_, handler := ListSecretScanningAlerts(stubGetClientFn(client), translations.NullTranslationHelper)
202+
203+
// Create call request
204+
request := createMCPRequest(tc.requestArgs)
205+
206+
// Call handler
207+
result, err := handler(context.Background(), request)
208+
209+
// Verify results
210+
if tc.expectError {
211+
require.Error(t, err)
212+
assert.Contains(t, err.Error(), tc.expectedErrMsg)
213+
return
214+
}
215+
216+
require.NoError(t, err)
217+
218+
// Parse the result and get the text content if no error
219+
textContent := getTextResult(t, result)
220+
221+
// Unmarshal and verify the result
222+
var returnedAlerts []*github.Alert
223+
err = json.Unmarshal([]byte(textContent.Text), &returnedAlerts)
224+
assert.NoError(t, err)
225+
assert.Len(t, returnedAlerts, len(tc.expectedAlerts))
226+
for i, alert := range returnedAlerts {
227+
assert.Equal(t, *tc.expectedAlerts[i].Number, *alert.Number)
228+
assert.Equal(t, *tc.expectedAlerts[i].State, *alert.State)
229+
assert.Equal(t, *tc.expectedAlerts[i].HTMLURL, *alert.HTMLURL)
230+
}
231+
})
232+
}
233+
}

pkg/github/tools.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ func InitToolsets(passedToolsets []string, readOnly bool, getClient GetClientFn,
7373
toolsets.NewServerTool(GetCodeScanningAlert(getClient, t)),
7474
toolsets.NewServerTool(ListCodeScanningAlerts(getClient, t)),
7575
)
76+
secretSecurity := toolsets.NewToolset("secret_security", "Secret security related tools, such as GitHub Secret Scanning").
77+
AddReadTools(
78+
toolsets.NewServerTool(GetSecretScanningAlert(getClient, t)),
79+
toolsets.NewServerTool(ListSecretScanningAlerts(getClient, t)),
80+
)
7681
// Keep experiments alive so the system doesn't error out when it's always enabled
7782
experiments := toolsets.NewToolset("experiments", "Experimental features that are not considered stable yet")
7883

@@ -82,6 +87,7 @@ func InitToolsets(passedToolsets []string, readOnly bool, getClient GetClientFn,
8287
tsg.AddToolset(users)
8388
tsg.AddToolset(pullRequests)
8489
tsg.AddToolset(codeSecurity)
90+
tsg.AddToolset(secretSecurity)
8591
tsg.AddToolset(experiments)
8692
// Enable the requested features
8793

0 commit comments

Comments
 (0)