| 329 | } |
| 330 | |
| 331 | func GetGlobalSecurityAdvisory(t translations.TranslationHelperFunc) inventory.ServerTool { |
| 332 | return NewTool( |
| 333 | ToolsetMetadataSecurityAdvisories, |
| 334 | mcp.Tool{ |
| 335 | Name: "get_global_security_advisory", |
| 336 | Description: t("TOOL_GET_GLOBAL_SECURITY_ADVISORY_DESCRIPTION", "Get a global security advisory"), |
| 337 | Annotations: &mcp.ToolAnnotations{ |
| 338 | Title: t("TOOL_GET_GLOBAL_SECURITY_ADVISORY_USER_TITLE", "Get a global security advisory"), |
| 339 | ReadOnlyHint: true, |
| 340 | }, |
| 341 | InputSchema: &jsonschema.Schema{ |
| 342 | Type: "object", |
| 343 | Properties: map[string]*jsonschema.Schema{ |
| 344 | "ghsaId": { |
| 345 | Type: "string", |
| 346 | Description: "GitHub Security Advisory ID (format: GHSA-xxxx-xxxx-xxxx).", |
| 347 | }, |
| 348 | }, |
| 349 | Required: []string{"ghsaId"}, |
| 350 | }, |
| 351 | }, |
| 352 | []scopes.Scope{scopes.SecurityEvents}, |
| 353 | func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) { |
| 354 | client, err := deps.GetClient(ctx) |
| 355 | if err != nil { |
| 356 | return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err) |
| 357 | } |
| 358 | |
| 359 | ghsaID, err := RequiredParam[string](args, "ghsaId") |
| 360 | if err != nil { |
| 361 | return utils.NewToolResultError(fmt.Sprintf("invalid ghsaId: %v", err)), nil, nil |
| 362 | } |
| 363 | |
| 364 | advisory, resp, err := client.SecurityAdvisories.GetGlobalSecurityAdvisories(ctx, ghsaID) |
| 365 | if err != nil { |
| 366 | return nil, nil, fmt.Errorf("failed to get advisory: %w", err) |
| 367 | } |
| 368 | defer func() { _ = resp.Body.Close() }() |
| 369 | |
| 370 | if resp.StatusCode != http.StatusOK { |
| 371 | body, err := io.ReadAll(resp.Body) |
| 372 | if err != nil { |
| 373 | return nil, nil, fmt.Errorf("failed to read response body: %w", err) |
| 374 | } |
| 375 | return ghErrors.NewGitHubAPIStatusErrorResponse(ctx, "failed to get advisory", resp, body), nil, nil |
| 376 | } |
| 377 | |
| 378 | r, err := json.Marshal(advisory) |
| 379 | if err != nil { |
| 380 | return nil, nil, fmt.Errorf("failed to marshal advisory: %w", err) |
| 381 | } |
| 382 | |
| 383 | result := utils.NewToolResultText(string(r)) |
| 384 | // A global advisory is world-readable (public) but externally |
| 385 | // authored (untrusted). |
| 386 | result = attachStaticIFCLabel(ctx, deps, result, ifc.LabelGlobalSecurityAdvisory()) |
| 387 | return result, nil, nil |
| 388 | }, |