Skip to content

Commit b940bd8

Browse files
Copilotdata-douser
andauthored
[UPDATE PRIMITIVE] Phase 3(B): Code Scanning lifecycle, SARIF enhancements, gh extension packaging (#234)
* Initial plan * feat: Phase 3(B) — Code Scanning lifecycle, SARIF enhancements, and gh extension packaging Add Code Scanning subcommands (list-analyses, list-alerts, download-analysis) and SARIF parent subcommand to gh-ql-mcp-client. Add GitHub REST API client using go-gh for Code Scanning endpoints. Enhance SARIF tools with fingerprint overlap mode, sarif_store for session cache ingest, and sarif_deduplicate_rules for cross-file rule deduplication. Add comprehensive tests for all new functionality. Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/3c78cc29-8614-47cd-ad94-534e60fd6ab1 Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> * Fix hanging client int test for windows stdio * fix: address review feedback — sarifClient race, dedup formula comment, handler tests 1. Fix data race in sarifClient() by replacing nil-check with sync.Once 2. Add clarifying comment on overlap scoring formula in sarif_deduplicate_rules 3. Add 3 handler-level tests for sarif_deduplicate_rules (overlap detection, no-overlap, missing input error) Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/7aefb02d-b415-49ed-87da-f03d9f4a2b3d Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> * fix: address automated review feedback — error message, fingerprint response, dedup perf, changelog links 1. loadSarif error message updated to source-agnostic "No SARIF source provided" 2. sarif_compare_alerts response now includes fingerprintMatch/matchedFingerprints in fingerprint mode 3. sarif_deduplicate_rules precomputes per-rule extracted results before pairwise loop 4. CHANGELOG entries corrected: partialFingerprints → fingerprint, added PR #234 links Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/85233122-a70c-49a6-a247-fb01f4da6946 Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> * fix: use actual sarifPath in cache databasePath, stable queryName for sarif_store Stores the actual SARIF file path (or 'inline') in databasePath and uses a stable 'sarif_store' as queryName, instead of overloading both with the user-provided label. Rebuilt server dist. Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/81b6fb38-6dd7-45f0-ac7f-d8b5e1625eb9 Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com> Co-authored-by: Nathan Randall <data-douser@github.com>
1 parent b777fc3 commit b940bd8

19 files changed

+1727
-50
lines changed

CHANGELOG.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ _Changes on `main` since the latest tagged release that have not yet been includ
2020

2121
- **Annotation, audit, cache, and SARIF tools are now always enabled** — Removed the `ENABLE_ANNOTATION_TOOLS` opt-in gate; all annotation, audit, query result cache, and SARIF analysis tools are registered by default. The `ENABLE_ANNOTATION_TOOLS` environment variable no longer controls tool availability; when set to `false`, it only disables the related auto-caching behaviour in result processing. ([#223](https://github.com/advanced-security/codeql-development-mcp-server/pull/223))
2222
- **Go-based `ql-mcp-client` rewrite** — Replaced the Node.js `ql-mcp-client.js` integration test runner with a Go CLI (`gh-ql-mcp-client`) built with Cobra and `mcp-go`. Adds `list tools/prompts/resources` commands and assertion-based integration test validation. ([#223](https://github.com/advanced-security/codeql-development-mcp-server/pull/223))
23+
- **Code Scanning lifecycle management** — Added `code-scanning list-analyses`, `list-alerts`, and `download-analysis` subcommands to `gh-ql-mcp-client` with GitHub REST API integration via `go-gh`. Added `sarif` parent subcommand for SARIF delegation workflows. Enhanced SARIF tools with `sarif_store` (session cache ingest), `sarif_deduplicate_rules` (cross-file rule deduplication), and `fingerprint` overlap mode with automatic fallback. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234))
2324
- **Persistent MRVA workflow state and caching** — Introduced a new `SqliteStore` backend plus annotation, audit, and query result cache tools to support the next phase of MCP-assisted CodeQL development and `seclab-taskflow-agent` integration. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169))
2425
- **Rust language support** — Added first-class Rust support with `PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo`, and `CallGraphFromTo` queries, bringing the total supported languages to 10. ([#195](https://github.com/advanced-security/codeql-development-mcp-server/pull/195))
2526
- **Bug fixes and design improvements from recent evaluation sessions** — Fixed 5 bugs across `bqrs_interpret`, `bqrs_info`, `annotation_search`, `audit_add_notes`, and `query_results_cache_compare`; added `database_analyze` auto-caching and per-database mutex serialization; auto-enabled annotation tools in VS Code extension. ([#199](https://github.com/advanced-security/codeql-development-mcp-server/pull/199))
@@ -29,12 +30,13 @@ _Changes on `main` since the latest tagged release that have not yet been includ
2930

3031
#### MCP Server Tools
3132

32-
| Tool | Description |
33-
| ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34-
| `annotation_create`, `annotation_get`, `annotation_list`, `annotation_update`, `annotation_delete`, `annotation_search` | General-purpose annotation tools for creating, managing, and searching notes and bookmarks on analysis entities. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
35-
| `audit_store_findings`, `audit_list_findings`, `audit_add_notes`, `audit_clear_repo` | Repo-keyed audit tools for MRVA finding management and triage workflows. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
36-
| `query_results_cache_lookup`, `query_results_cache_retrieve`, `query_results_cache_clear`, `query_results_cache_compare` | Query result cache tools for lookup, subset retrieval, cache clearing, and cross-database comparison. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
37-
| `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `sarif_compare_alerts`, `sarif_diff_runs` | SARIF analysis tools for rule discovery, per-rule extraction, Mermaid dataflow visualization, alert overlap comparison, and cross-run behavioral diffing. ([#204](https://github.com/advanced-security/codeql-development-mcp-server/pull/204)) |
33+
| Tool | Description |
34+
| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
35+
| `annotation_create`, `annotation_get`, `annotation_list`, `annotation_update`, `annotation_delete`, `annotation_search` | General-purpose annotation tools for creating, managing, and searching notes and bookmarks on analysis entities. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
36+
| `audit_store_findings`, `audit_list_findings`, `audit_add_notes`, `audit_clear_repo` | Repo-keyed audit tools for MRVA finding management and triage workflows. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
37+
| `query_results_cache_lookup`, `query_results_cache_retrieve`, `query_results_cache_clear`, `query_results_cache_compare` | Query result cache tools for lookup, subset retrieval, cache clearing, and cross-database comparison. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169)) |
38+
| `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `sarif_compare_alerts`, `sarif_diff_runs` | SARIF analysis tools for rule discovery, per-rule extraction, Mermaid dataflow visualization, alert overlap comparison, and cross-run behavioral diffing. ([#204](https://github.com/advanced-security/codeql-development-mcp-server/pull/204)) |
39+
| `sarif_store`, `sarif_deduplicate_rules` | SARIF session cache ingest and cross-file rule deduplication tools. `sarif_compare_alerts` enhanced with `fingerprint` overlap mode with automatic fallback to full-path comparison. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234)) |
3840

3941
#### MCP Server Resources
4042

@@ -58,6 +60,8 @@ _Changes on `main` since the latest tagged release that have not yet been includ
5860

5961
- Added Rust coverage to CI and release workflows, including query unit tests and VSIX bundling. ([#195](https://github.com/advanced-security/codeql-development-mcp-server/pull/195))
6062
- Added client integration tests for the new Rust queries and for the annotation, audit, and cache tool suites, including an MRVA triage workflow end-to-end test. ([#169](https://github.com/advanced-security/codeql-development-mcp-server/pull/169), [#195](https://github.com/advanced-security/codeql-development-mcp-server/pull/195))
63+
- Added `code-scanning` and `sarif` subcommand groups to `gh-ql-mcp-client` with GitHub REST API client integration via `go-gh` for Code Scanning alert lifecycle management. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234))
64+
- Added `gh` extension packaging support with cross-compilation targets for `darwin/amd64`, `darwin/arm64`, `linux/amd64`, `linux/arm64`, `windows/amd64`. ([#234](https://github.com/advanced-security/codeql-development-mcp-server/pull/234))
6165

6266
### Changed
6367

client/cmd/code_scanning.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cmd
2+
3+
import "github.com/spf13/cobra"
4+
5+
var codeScanningCmd = &cobra.Command{
6+
Use: "code-scanning",
7+
Aliases: []string{"cs"},
8+
Short: "Manage Code Scanning analyses and alerts",
9+
Long: "Commands for listing, downloading, dismissing, and reopening Code Scanning analyses and alerts via the GitHub REST API.",
10+
RunE: func(cmd *cobra.Command, args []string) error {
11+
return cmd.Help()
12+
},
13+
}
14+
15+
func init() {
16+
rootCmd.AddCommand(codeScanningCmd)
17+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
9+
gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
var downloadAnalysisCmd = &cobra.Command{
14+
Use: "download-analysis",
15+
Short: "Download a Code Scanning analysis as SARIF",
16+
RunE: runDownloadAnalysis,
17+
}
18+
19+
var downloadAnalysisFlags struct {
20+
repo string
21+
analysisID int
22+
output string
23+
}
24+
25+
func init() {
26+
codeScanningCmd.AddCommand(downloadAnalysisCmd)
27+
28+
f := downloadAnalysisCmd.Flags()
29+
f.StringVar(&downloadAnalysisFlags.repo, "repo", "", "Repository in owner/repo format (required)")
30+
f.IntVar(&downloadAnalysisFlags.analysisID, "analysis-id", 0, "Analysis ID to download (required)")
31+
f.StringVar(&downloadAnalysisFlags.output, "output", "", "Output file path (default: sarif-downloads/<repo>/<id>.sarif)")
32+
33+
_ = downloadAnalysisCmd.MarkFlagRequired("repo")
34+
_ = downloadAnalysisCmd.MarkFlagRequired("analysis-id")
35+
}
36+
37+
func runDownloadAnalysis(cmd *cobra.Command, _ []string) error {
38+
owner, repo, err := parseRepo(downloadAnalysisFlags.repo)
39+
if err != nil {
40+
return err
41+
}
42+
43+
client, err := gh.NewClient()
44+
if err != nil {
45+
return err
46+
}
47+
48+
sarif, err := client.GetAnalysisSARIF(owner, repo, downloadAnalysisFlags.analysisID)
49+
if err != nil {
50+
return err
51+
}
52+
53+
// Determine output path
54+
outPath := downloadAnalysisFlags.output
55+
if outPath == "" {
56+
outPath = filepath.Join("sarif-downloads", fmt.Sprintf("%s_%s", owner, repo),
57+
fmt.Sprintf("%d.sarif", downloadAnalysisFlags.analysisID))
58+
}
59+
60+
// Ensure directory exists
61+
if err := os.MkdirAll(filepath.Dir(outPath), 0o750); err != nil {
62+
return fmt.Errorf("create output directory: %w", err)
63+
}
64+
65+
// Pretty-print the JSON
66+
var pretty json.RawMessage
67+
if err := json.Unmarshal(sarif, &pretty); err != nil {
68+
// If not valid JSON, write as-is
69+
if writeErr := os.WriteFile(outPath, sarif, 0o600); writeErr != nil {
70+
return fmt.Errorf("write SARIF file: %w", writeErr)
71+
}
72+
} else {
73+
formatted, _ := json.MarshalIndent(pretty, "", " ")
74+
if err := os.WriteFile(outPath, formatted, 0o600); err != nil {
75+
return fmt.Errorf("write SARIF file: %w", err)
76+
}
77+
}
78+
79+
fmt.Fprintf(cmd.OutOrStdout(), "Downloaded SARIF to %s (%d bytes)\n", outPath, len(sarif))
80+
return nil
81+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"text/tabwriter"
7+
8+
gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var listAlertsCmd = &cobra.Command{
13+
Use: "list-alerts",
14+
Short: "List Code Scanning alerts for a repository",
15+
RunE: runListAlerts,
16+
}
17+
18+
var listAlertsFlags struct {
19+
repo string
20+
ref string
21+
state string
22+
severity string
23+
toolName string
24+
sort string
25+
direction string
26+
perPage int
27+
}
28+
29+
func init() {
30+
codeScanningCmd.AddCommand(listAlertsCmd)
31+
32+
f := listAlertsCmd.Flags()
33+
f.StringVar(&listAlertsFlags.repo, "repo", "", "Repository in owner/repo format (required)")
34+
f.StringVar(&listAlertsFlags.ref, "ref", "", "Git ref to filter by")
35+
f.StringVar(&listAlertsFlags.state, "state", "", "Alert state: open, closed, dismissed, fixed")
36+
f.StringVar(&listAlertsFlags.severity, "severity", "", "Severity: critical, high, medium, low, warning, note, error")
37+
f.StringVar(&listAlertsFlags.toolName, "tool-name", "", "Tool name to filter by")
38+
f.StringVar(&listAlertsFlags.sort, "sort", "", "Sort by (created, updated)")
39+
f.StringVar(&listAlertsFlags.direction, "direction", "", "Sort direction (asc, desc)")
40+
f.IntVar(&listAlertsFlags.perPage, "per-page", 30, "Results per page (max 100)")
41+
42+
_ = listAlertsCmd.MarkFlagRequired("repo")
43+
}
44+
45+
func runListAlerts(cmd *cobra.Command, _ []string) error {
46+
owner, repo, err := parseRepo(listAlertsFlags.repo)
47+
if err != nil {
48+
return err
49+
}
50+
51+
client, err := gh.NewClient()
52+
if err != nil {
53+
return err
54+
}
55+
56+
alerts, err := client.ListAlerts(gh.ListAlertsOptions{
57+
Owner: owner,
58+
Repo: repo,
59+
Ref: listAlertsFlags.ref,
60+
State: listAlertsFlags.state,
61+
Severity: listAlertsFlags.severity,
62+
ToolName: listAlertsFlags.toolName,
63+
Sort: listAlertsFlags.sort,
64+
Direction: listAlertsFlags.direction,
65+
PerPage: listAlertsFlags.perPage,
66+
})
67+
if err != nil {
68+
return err
69+
}
70+
71+
if OutputFormat() == "json" {
72+
enc := json.NewEncoder(cmd.OutOrStdout())
73+
enc.SetIndent("", " ")
74+
return enc.Encode(alerts)
75+
}
76+
77+
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 4, 2, ' ', 0)
78+
fmt.Fprintln(w, "NUM\tSTATE\tRULE\tSEVERITY\tFILE:LINE\tCREATED")
79+
for _, a := range alerts {
80+
loc := a.MostRecentInstance.Location
81+
locStr := fmt.Sprintf("%s:%d", loc.Path, loc.StartLine)
82+
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%s\n",
83+
a.Number, a.State, a.Rule.ID, a.Rule.Severity, locStr, a.CreatedAt)
84+
}
85+
return w.Flush()
86+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"text/tabwriter"
7+
8+
gh "github.com/advanced-security/codeql-development-mcp-server/client/internal/github"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var listAnalysesCmd = &cobra.Command{
13+
Use: "list-analyses",
14+
Short: "List Code Scanning analyses for a repository",
15+
RunE: runListAnalyses,
16+
}
17+
18+
var listAnalysesFlags struct {
19+
repo string
20+
ref string
21+
toolName string
22+
sarifID string
23+
sort string
24+
direction string
25+
perPage int
26+
}
27+
28+
func init() {
29+
codeScanningCmd.AddCommand(listAnalysesCmd)
30+
31+
f := listAnalysesCmd.Flags()
32+
f.StringVar(&listAnalysesFlags.repo, "repo", "", "Repository in owner/repo format (required)")
33+
f.StringVar(&listAnalysesFlags.ref, "ref", "", "Git ref to filter by")
34+
f.StringVar(&listAnalysesFlags.toolName, "tool-name", "", "Tool name to filter by (e.g. CodeQL)")
35+
f.StringVar(&listAnalysesFlags.sarifID, "sarif-id", "", "SARIF ID to filter by")
36+
f.StringVar(&listAnalysesFlags.sort, "sort", "", "Sort by (created)")
37+
f.StringVar(&listAnalysesFlags.direction, "direction", "", "Sort direction (asc, desc)")
38+
f.IntVar(&listAnalysesFlags.perPage, "per-page", 30, "Results per page (max 100)")
39+
40+
_ = listAnalysesCmd.MarkFlagRequired("repo")
41+
}
42+
43+
func runListAnalyses(cmd *cobra.Command, _ []string) error {
44+
owner, repo, err := parseRepo(listAnalysesFlags.repo)
45+
if err != nil {
46+
return err
47+
}
48+
49+
client, err := gh.NewClient()
50+
if err != nil {
51+
return err
52+
}
53+
54+
analyses, err := client.ListAnalyses(gh.ListAnalysesOptions{
55+
Owner: owner,
56+
Repo: repo,
57+
Ref: listAnalysesFlags.ref,
58+
ToolName: listAnalysesFlags.toolName,
59+
SarifID: listAnalysesFlags.sarifID,
60+
Sort: listAnalysesFlags.sort,
61+
Direction: listAnalysesFlags.direction,
62+
PerPage: listAnalysesFlags.perPage,
63+
})
64+
if err != nil {
65+
return err
66+
}
67+
68+
if OutputFormat() == "json" {
69+
enc := json.NewEncoder(cmd.OutOrStdout())
70+
enc.SetIndent("", " ")
71+
return enc.Encode(analyses)
72+
}
73+
74+
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 4, 2, ' ', 0)
75+
fmt.Fprintln(w, "ID\tTOOL\tREF\tCATEGORY\tRESULTS\tRULES\tCREATED")
76+
for _, a := range analyses {
77+
fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%d\t%d\t%s\n",
78+
a.ID, a.Tool.Name, a.Ref, a.Category, a.ResultsCount, a.RulesCount, a.CreatedAt)
79+
}
80+
return w.Flush()
81+
}

client/cmd/root.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@ var (
2424
// rootCmd is the top-level command for the CLI.
2525
var rootCmd = &cobra.Command{
2626
Use: "gh-ql-mcp-client",
27-
Short: "CodeQL Development MCP Client — integration test runner and CLI",
28-
Long: `gh-ql-mcp-client is a CLI for running integration tests against a
29-
CodeQL Development MCP Server.
27+
Short: "CodeQL Development MCP Client — Code Scanning alert lifecycle management",
28+
Long: `gh-ql-mcp-client is a CLI for managing Code Scanning alert lifecycles.
3029
31-
It connects to a CodeQL Development MCP Server via stdio or HTTP transport
32-
and runs integration test fixtures from client/integration-tests/.
30+
It connects to a CodeQL Development MCP Server to leverage SARIF analysis tools
31+
and uses GitHub's Code Scanning REST API (via gh auth) for alert operations.
3332
3433
Use as a gh extension: gh ql-mcp-client <command> [flags]
3534
Use standalone: gh-ql-mcp-client <command> [flags]`,

client/cmd/sarif.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package cmd
2+
3+
import "github.com/spf13/cobra"
4+
5+
var sarifCmd = &cobra.Command{
6+
Use: "sarif",
7+
Short: "SARIF analysis and alert comparison tools",
8+
Long: "Commands for comparing, deduplicating, and validating SARIF alerts using MCP server tools and LLM-driven analysis.",
9+
RunE: func(cmd *cobra.Command, args []string) error {
10+
return cmd.Help()
11+
},
12+
}
13+
14+
func init() {
15+
rootCmd.AddCommand(sarifCmd)
16+
}

client/go.mod

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,29 @@ module github.com/advanced-security/codeql-development-mcp-server/client
33
go 1.25.6
44

55
require (
6+
github.com/cli/go-gh/v2 v2.13.0
67
github.com/mark3labs/mcp-go v0.47.0
78
github.com/spf13/cobra v1.10.2
89
)
910

1011
require (
12+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
13+
github.com/cli/safeexec v1.0.0 // indirect
14+
github.com/cli/shurcooL-graphql v0.0.4 // indirect
1115
github.com/google/jsonschema-go v0.4.2 // indirect
1216
github.com/google/uuid v1.6.0 // indirect
17+
github.com/henvic/httpretty v0.0.6 // indirect
1318
github.com/inconshreveable/mousetrap v1.1.0 // indirect
19+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
20+
github.com/mattn/go-isatty v0.0.20 // indirect
21+
github.com/muesli/termenv v0.16.0 // indirect
22+
github.com/rivo/uniseg v0.4.7 // indirect
1423
github.com/spf13/cast v1.7.1 // indirect
1524
github.com/spf13/pflag v1.0.9 // indirect
25+
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e // indirect
1626
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
27+
golang.org/x/sys v0.31.0 // indirect
28+
golang.org/x/term v0.30.0 // indirect
29+
golang.org/x/text v0.23.0 // indirect
30+
gopkg.in/yaml.v3 v3.0.1 // indirect
1731
)

0 commit comments

Comments
 (0)