-
Notifications
You must be signed in to change notification settings - Fork 2
[UPDATE PRIMITIVE] Phase 3(B): Code Scanning lifecycle, SARIF enhancements, gh extension packaging
#234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
data-douser
merged 6 commits into
next
from
copilot/advanced-security-codeql-improvements
Apr 9, 2026
Merged
[UPDATE PRIMITIVE] Phase 3(B): Code Scanning lifecycle, SARIF enhancements, gh extension packaging
#234
Changes from 2 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
eca4570
Initial plan
Copilot 32c5766
feat: Phase 3(B) β Code Scanning lifecycle, SARIF enhancements, and gβ¦
Copilot 71d8452
Fix hanging client int test for windows stdio
data-douser a9df508
fix: address review feedback β sarifClient race, dedup formula commenβ¦
Copilot 0157993
fix: address automated review feedback β error message, fingerprint rβ¦
Copilot 429c041
fix: use actual sarifPath in cache databasePath, stable queryName forβ¦
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package cmd | ||
|
|
||
| import "github.com/spf13/cobra" | ||
|
|
||
| var codeScanningCmd = &cobra.Command{ | ||
| Use: "code-scanning", | ||
| Aliases: []string{"cs"}, | ||
| Short: "Manage Code Scanning analyses and alerts", | ||
| Long: "Commands for listing, downloading, dismissing, and reopening Code Scanning analyses and alerts via the GitHub REST API.", | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| return cmd.Help() | ||
| }, | ||
| } | ||
|
|
||
| func init() { | ||
| rootCmd.AddCommand(codeScanningCmd) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
|
|
||
| gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| var downloadAnalysisCmd = &cobra.Command{ | ||
| Use: "download-analysis", | ||
| Short: "Download a Code Scanning analysis as SARIF", | ||
| RunE: runDownloadAnalysis, | ||
| } | ||
|
|
||
| var downloadAnalysisFlags struct { | ||
| repo string | ||
| analysisID int | ||
| output string | ||
| } | ||
|
|
||
| func init() { | ||
| codeScanningCmd.AddCommand(downloadAnalysisCmd) | ||
|
|
||
| f := downloadAnalysisCmd.Flags() | ||
| f.StringVar(&downloadAnalysisFlags.repo, "repo", "", "Repository in owner/repo format (required)") | ||
| f.IntVar(&downloadAnalysisFlags.analysisID, "analysis-id", 0, "Analysis ID to download (required)") | ||
| f.StringVar(&downloadAnalysisFlags.output, "output", "", "Output file path (default: sarif-downloads/<repo>/<id>.sarif)") | ||
|
|
||
| _ = downloadAnalysisCmd.MarkFlagRequired("repo") | ||
| _ = downloadAnalysisCmd.MarkFlagRequired("analysis-id") | ||
| } | ||
|
|
||
| func runDownloadAnalysis(cmd *cobra.Command, _ []string) error { | ||
| owner, repo, err := parseRepo(downloadAnalysisFlags.repo) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| client, err := gh.NewClient() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| sarif, err := client.GetAnalysisSARIF(owner, repo, downloadAnalysisFlags.analysisID) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Determine output path | ||
| outPath := downloadAnalysisFlags.output | ||
| if outPath == "" { | ||
| outPath = filepath.Join("sarif-downloads", fmt.Sprintf("%s_%s", owner, repo), | ||
| fmt.Sprintf("%d.sarif", downloadAnalysisFlags.analysisID)) | ||
| } | ||
|
|
||
| // Ensure directory exists | ||
| if err := os.MkdirAll(filepath.Dir(outPath), 0o750); err != nil { | ||
| return fmt.Errorf("create output directory: %w", err) | ||
| } | ||
|
|
||
| // Pretty-print the JSON | ||
| var pretty json.RawMessage | ||
| if err := json.Unmarshal(sarif, &pretty); err != nil { | ||
| // If not valid JSON, write as-is | ||
| if writeErr := os.WriteFile(outPath, sarif, 0o600); writeErr != nil { | ||
| return fmt.Errorf("write SARIF file: %w", writeErr) | ||
| } | ||
| } else { | ||
| formatted, _ := json.MarshalIndent(pretty, "", " ") | ||
| if err := os.WriteFile(outPath, formatted, 0o600); err != nil { | ||
| return fmt.Errorf("write SARIF file: %w", err) | ||
| } | ||
| } | ||
|
|
||
| fmt.Fprintf(cmd.OutOrStdout(), "Downloaded SARIF to %s (%d bytes)\n", outPath, len(sarif)) | ||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "text/tabwriter" | ||
|
|
||
| gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| var listAlertsCmd = &cobra.Command{ | ||
| Use: "list-alerts", | ||
| Short: "List Code Scanning alerts for a repository", | ||
| RunE: runListAlerts, | ||
| } | ||
|
|
||
| var listAlertsFlags struct { | ||
| repo string | ||
| ref string | ||
| state string | ||
| severity string | ||
| toolName string | ||
| sort string | ||
| direction string | ||
| perPage int | ||
| } | ||
|
|
||
| func init() { | ||
| codeScanningCmd.AddCommand(listAlertsCmd) | ||
|
|
||
| f := listAlertsCmd.Flags() | ||
| f.StringVar(&listAlertsFlags.repo, "repo", "", "Repository in owner/repo format (required)") | ||
| f.StringVar(&listAlertsFlags.ref, "ref", "", "Git ref to filter by") | ||
| f.StringVar(&listAlertsFlags.state, "state", "", "Alert state: open, closed, dismissed, fixed") | ||
| f.StringVar(&listAlertsFlags.severity, "severity", "", "Severity: critical, high, medium, low, warning, note, error") | ||
| f.StringVar(&listAlertsFlags.toolName, "tool-name", "", "Tool name to filter by") | ||
| f.StringVar(&listAlertsFlags.sort, "sort", "", "Sort by (created, updated)") | ||
| f.StringVar(&listAlertsFlags.direction, "direction", "", "Sort direction (asc, desc)") | ||
| f.IntVar(&listAlertsFlags.perPage, "per-page", 30, "Results per page (max 100)") | ||
|
|
||
| _ = listAlertsCmd.MarkFlagRequired("repo") | ||
| } | ||
|
|
||
| func runListAlerts(cmd *cobra.Command, _ []string) error { | ||
| owner, repo, err := parseRepo(listAlertsFlags.repo) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| client, err := gh.NewClient() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| alerts, err := client.ListAlerts(gh.ListAlertsOptions{ | ||
| Owner: owner, | ||
| Repo: repo, | ||
| Ref: listAlertsFlags.ref, | ||
| State: listAlertsFlags.state, | ||
| Severity: listAlertsFlags.severity, | ||
| ToolName: listAlertsFlags.toolName, | ||
| Sort: listAlertsFlags.sort, | ||
| Direction: listAlertsFlags.direction, | ||
| PerPage: listAlertsFlags.perPage, | ||
| }) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if OutputFormat() == "json" { | ||
| enc := json.NewEncoder(cmd.OutOrStdout()) | ||
| enc.SetIndent("", " ") | ||
| return enc.Encode(alerts) | ||
| } | ||
|
|
||
| w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 4, 2, ' ', 0) | ||
| fmt.Fprintln(w, "NUM\tSTATE\tRULE\tSEVERITY\tFILE:LINE\tCREATED") | ||
| for _, a := range alerts { | ||
| loc := a.MostRecentInstance.Location | ||
| locStr := fmt.Sprintf("%s:%d", loc.Path, loc.StartLine) | ||
| fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%s\n", | ||
| a.Number, a.State, a.Rule.ID, a.Rule.Severity, locStr, a.CreatedAt) | ||
| } | ||
| return w.Flush() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "text/tabwriter" | ||
|
|
||
| gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| var listAnalysesCmd = &cobra.Command{ | ||
| Use: "list-analyses", | ||
| Short: "List Code Scanning analyses for a repository", | ||
| RunE: runListAnalyses, | ||
| } | ||
|
|
||
| var listAnalysesFlags struct { | ||
| repo string | ||
| ref string | ||
| toolName string | ||
| sarifID string | ||
| sort string | ||
| direction string | ||
| perPage int | ||
| } | ||
|
|
||
| func init() { | ||
| codeScanningCmd.AddCommand(listAnalysesCmd) | ||
|
|
||
| f := listAnalysesCmd.Flags() | ||
| f.StringVar(&listAnalysesFlags.repo, "repo", "", "Repository in owner/repo format (required)") | ||
| f.StringVar(&listAnalysesFlags.ref, "ref", "", "Git ref to filter by") | ||
| f.StringVar(&listAnalysesFlags.toolName, "tool-name", "", "Tool name to filter by (e.g. CodeQL)") | ||
| f.StringVar(&listAnalysesFlags.sarifID, "sarif-id", "", "SARIF ID to filter by") | ||
| f.StringVar(&listAnalysesFlags.sort, "sort", "", "Sort by (created)") | ||
| f.StringVar(&listAnalysesFlags.direction, "direction", "", "Sort direction (asc, desc)") | ||
| f.IntVar(&listAnalysesFlags.perPage, "per-page", 30, "Results per page (max 100)") | ||
|
|
||
| _ = listAnalysesCmd.MarkFlagRequired("repo") | ||
| } | ||
|
|
||
| func runListAnalyses(cmd *cobra.Command, _ []string) error { | ||
| owner, repo, err := parseRepo(listAnalysesFlags.repo) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| client, err := gh.NewClient() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| analyses, err := client.ListAnalyses(gh.ListAnalysesOptions{ | ||
| Owner: owner, | ||
| Repo: repo, | ||
| Ref: listAnalysesFlags.ref, | ||
| ToolName: listAnalysesFlags.toolName, | ||
| SarifID: listAnalysesFlags.sarifID, | ||
| Sort: listAnalysesFlags.sort, | ||
| Direction: listAnalysesFlags.direction, | ||
| PerPage: listAnalysesFlags.perPage, | ||
| }) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if OutputFormat() == "json" { | ||
| enc := json.NewEncoder(cmd.OutOrStdout()) | ||
| enc.SetIndent("", " ") | ||
| return enc.Encode(analyses) | ||
| } | ||
|
|
||
| w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 4, 2, ' ', 0) | ||
| fmt.Fprintln(w, "ID\tTOOL\tREF\tCATEGORY\tRESULTS\tRULES\tCREATED") | ||
| for _, a := range analyses { | ||
| fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%d\t%s\n", | ||
| a.ID, a.Tool.Name, a.Ref, a.Category, a.ResultsCount, a.RulesCount, a.CreatedAt) | ||
| } | ||
| return w.Flush() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package cmd | ||
|
|
||
| import "github.com/spf13/cobra" | ||
|
|
||
| var sarifCmd = &cobra.Command{ | ||
| Use: "sarif", | ||
| Short: "SARIF analysis and alert comparison tools", | ||
| Long: "Commands for comparing, deduplicating, and validating SARIF alerts using MCP server tools and LLM-driven analysis.", | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| return cmd.Help() | ||
| }, | ||
| } | ||
|
|
||
| func init() { | ||
| rootCmd.AddCommand(sarifCmd) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.