From 545b420ff8804a1fdaf05320f75ed60048380451 Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Tue, 1 Jul 2025 14:10:30 +0200 Subject: [PATCH 1/8] Transform `extension` and `filename` qualifiers into `path` qualifier --- pkg/cmd/search/code/code.go | 33 ++++++++++++++++-- pkg/cmd/search/code/code_test.go | 60 +++++++++++++++++++++++++++++--- pkg/search/query.go | 1 + 3 files changed, 88 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index d51ec8fa6be..944d11795d6 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -6,6 +6,8 @@ import ( "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/internal/browser" + "github.com/cli/cli/v2/internal/gh" + "github.com/cli/cli/v2/internal/ghinstance" "github.com/cli/cli/v2/internal/text" "github.com/cli/cli/v2/pkg/cmd/search/shared" "github.com/cli/cli/v2/pkg/cmdutil" @@ -16,6 +18,7 @@ import ( type CodeOptions struct { Browser browser.Browser + Config func() (gh.Config, error) Exporter cmdutil.Exporter IO *iostreams.IOStreams Query search.Query @@ -26,6 +29,7 @@ type CodeOptions struct { func NewCmdCode(f *cmdutil.Factory, runF func(*CodeOptions) error) *cobra.Command { opts := &CodeOptions{ Browser: f.Browser, + Config: f.Config, IO: f.IOStreams, Query: search.Query{Kind: search.KindCode}, } @@ -104,8 +108,33 @@ func NewCmdCode(f *cmdutil.Factory, runF func(*CodeOptions) error) *cobra.Comman func codeRun(opts *CodeOptions) error { io := opts.IO if opts.WebMode { - // FIXME: convert legacy `filename` and `extension` ES qualifiers to Blackbird's `path` qualifier - // when opening web search, otherwise the Blackbird search UI will complain. + // Convert legacy `filename` and `extension` elasticsearch qualifiers to Blackbird's `path` + // qualifier when opening web search. + if opts.Query.Qualifiers.Filename != "" || opts.Query.Qualifiers.Extension != "" { + cfg, err := opts.Config() + if err != nil { + return err + } + host, _ := cfg.Authentication().DefaultHost() + // FIXME: Remove this check once GHES supports Blackbird. + if host == ghinstance.Default() { + filename, extension, _ := strings.Cut(opts.Query.Qualifiers.Filename, ".") + if filename == "" { + filename = "*" + } + // Prioritize file extension that may have been provided with the `--filename` flag. + if extension == "" { + if opts.Query.Qualifiers.Extension != "" { + extension, _ = strings.CutPrefix(opts.Query.Qualifiers.Extension, ".") + } else { + extension = "*" + } + } + opts.Query.Qualifiers.Filename = "" + opts.Query.Qualifiers.Extension = "" + opts.Query.Qualifiers.Path = fmt.Sprintf("%s.%s", filename, extension) + } + } url := opts.Searcher.URL(opts.Query) if io.IsStdoutTTY() { fmt.Fprintf(io.ErrOut, "Opening %s in your browser.\n", text.DisplayURL(url)) diff --git a/pkg/cmd/search/code/code_test.go b/pkg/cmd/search/code/code_test.go index 4b493c6d5c4..a484a227c01 100644 --- a/pkg/cmd/search/code/code_test.go +++ b/pkg/cmd/search/code/code_test.go @@ -6,6 +6,9 @@ import ( "testing" "github.com/cli/cli/v2/internal/browser" + "github.com/cli/cli/v2/internal/config" + "github.com/cli/cli/v2/internal/gh" + ghmock "github.com/cli/cli/v2/internal/gh/mock" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/search" @@ -146,6 +149,7 @@ func TestCodeRun(t *testing.T) { wantErr bool wantStderr string wantStdout string + wantBrowse string }{ { name: "displays results tty", @@ -294,8 +298,7 @@ func TestCodeRun(t *testing.T) { { name: "opens browser for web mode tty", opts: &CodeOptions{ - Browser: &browser.Stub{}, - Query: query, + Query: query, Searcher: &search.SearcherMock{ URLFunc: func(query search.Query) string { return "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli" @@ -305,12 +308,12 @@ func TestCodeRun(t *testing.T) { }, tty: true, wantStderr: "Opening https://github.com/search in your browser.\n", + wantBrowse: "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli", }, { name: "opens browser for web mode notty", opts: &CodeOptions{ - Browser: &browser.Stub{}, - Query: query, + Query: query, Searcher: &search.SearcherMock{ URLFunc: func(query search.Query) string { return "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli" @@ -318,6 +321,52 @@ func TestCodeRun(t *testing.T) { }, WebMode: true, }, + wantBrowse: "https://github.com/search?type=code&q=map+repo%3Acli%2Fcli", + }, + { + name: "converts filename and extension qualifiers for github.com web search", + opts: &CodeOptions{ + Config: func() (gh.Config, error) { return config.NewBlankConfig(), nil }, + Query: search.Query{ + Keywords: []string{"map"}, + Kind: "code", + Limit: 30, + Qualifiers: search.Qualifiers{ + Filename: "testing", + Extension: "go", + }, + }, + Searcher: search.NewSearcher(nil, "github.com"), + WebMode: true, + }, + wantBrowse: "https://github.com/search?q=map+path%3Atesting.go&type=code", + }, + { + name: "does not convert filename and extension qualifiers for GHES web search", + opts: &CodeOptions{ + Config: func() (gh.Config, error) { + cfg := &ghmock.ConfigMock{ + AuthenticationFunc: func() gh.AuthConfig { + authCfg := &config.AuthConfig{} + authCfg.SetDefaultHost("example.com", "GH_HOST") + return authCfg + }, + } + return cfg, nil + }, + Query: search.Query{ + Keywords: []string{"map"}, + Kind: "code", + Limit: 30, + Qualifiers: search.Qualifiers{ + Filename: "testing", + Extension: "go", + }, + }, + Searcher: search.NewSearcher(nil, "example.com"), + WebMode: true, + }, + wantBrowse: "https://example.com/search?q=map+extension%3Ago+filename%3Atesting&type=code", }, } @@ -327,6 +376,8 @@ func TestCodeRun(t *testing.T) { ios.SetStdoutTTY(tt.tty) ios.SetStderrTTY(tt.tty) tt.opts.IO = ios + browser := &browser.Stub{} + tt.opts.Browser = browser t.Run(tt.name, func(t *testing.T) { err := codeRun(tt.opts) if tt.wantErr { @@ -337,6 +388,7 @@ func TestCodeRun(t *testing.T) { } assert.Equal(t, tt.wantStdout, stdout.String()) assert.Equal(t, tt.wantStderr, stderr.String()) + browser.Verify(t, tt.wantBrowse) }) } } diff --git a/pkg/search/query.go b/pkg/search/query.go index 0181a2240ab..31d728618ac 100644 --- a/pkg/search/query.go +++ b/pkg/search/query.go @@ -64,6 +64,7 @@ type Qualifiers struct { Milestone string No []string Parent string + Path string Project string Pushed string Reactions string From d068696c4d5363ad31de38d5b120e449a48e1050 Mon Sep 17 00:00:00 2001 From: ejahnGithub Date: Wed, 9 Jul 2025 15:55:41 -0400 Subject: [PATCH 2/8] add tenancy aware for san matcher --- pkg/cmd/release/shared/attestation.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/release/shared/attestation.go b/pkg/cmd/release/shared/attestation.go index 4e0377fed99..b4490373b6f 100644 --- a/pkg/cmd/release/shared/attestation.go +++ b/pkg/cmd/release/shared/attestation.go @@ -46,7 +46,7 @@ func (v *AttestationVerifier) VerifyAttestation(art *artifact.DigestedArtifact, return nil, err } - policy := buildVerificationPolicy(*art) + policy := buildVerificationPolicy(*art, td) sigstoreVerified, err := verifier.Verify([]*api.Attestation{att}, policy) if err != nil { return nil, err @@ -99,9 +99,13 @@ func FilterAttestationsByFileDigest(attestations []*api.Attestation, fileDigest } // buildVerificationPolicy constructs a verification policy for GitHub releases -func buildVerificationPolicy(a artifact.DigestedArtifact) verify.PolicyBuilder { +func buildVerificationPolicy(a artifact.DigestedArtifact, trustDomain string) verify.PolicyBuilder { + // If no trust domain is specified, default to "dotcom" + if trustDomain == "" { + trustDomain = "dotcom" + } // SAN must match the GitHub releases domain. No issuer extension (match anything) - sanMatcher, _ := verify.NewSANMatcher("", "^https://.*\\.releases\\.github\\.com$") + sanMatcher, _ := verify.NewSANMatcher("", fmt.Sprintf("^https://%s\\.releases\\.github\\.com$", trustDomain)) issuerMatcher, _ := verify.NewIssuerMatcher("", ".*") certId, _ := verify.NewCertificateIdentity(sanMatcher, issuerMatcher, certificate.Extensions{}) From f87451ff56362dee05eb87ad9b03565a692cf34d Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Thu, 10 Jul 2025 12:33:08 +0200 Subject: [PATCH 3/8] Simplify path qualifier building logic --- pkg/cmd/search/code/code.go | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index 944d11795d6..a2e152960f0 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -7,12 +7,12 @@ import ( "github.com/MakeNowJust/heredoc" "github.com/cli/cli/v2/internal/browser" "github.com/cli/cli/v2/internal/gh" - "github.com/cli/cli/v2/internal/ghinstance" "github.com/cli/cli/v2/internal/text" "github.com/cli/cli/v2/pkg/cmd/search/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/search" + ghauth "github.com/cli/go-gh/v2/pkg/auth" "github.com/spf13/cobra" ) @@ -117,22 +117,15 @@ func codeRun(opts *CodeOptions) error { } host, _ := cfg.Authentication().DefaultHost() // FIXME: Remove this check once GHES supports Blackbird. - if host == ghinstance.Default() { - filename, extension, _ := strings.Cut(opts.Query.Qualifiers.Filename, ".") - if filename == "" { - filename = "*" - } - // Prioritize file extension that may have been provided with the `--filename` flag. - if extension == "" { - if opts.Query.Qualifiers.Extension != "" { - extension, _ = strings.CutPrefix(opts.Query.Qualifiers.Extension, ".") - } else { - extension = "*" - } + if !ghauth.IsEnterprise(host) { + filename := opts.Query.Qualifiers.Filename + extension := opts.Query.Qualifiers.Extension + if extension != "" && !strings.HasPrefix(extension, ".") { + extension = "." + extension } opts.Query.Qualifiers.Filename = "" opts.Query.Qualifiers.Extension = "" - opts.Query.Qualifiers.Path = fmt.Sprintf("%s.%s", filename, extension) + opts.Query.Qualifiers.Path = fmt.Sprintf("%s%s", filename, extension) } } url := opts.Searcher.URL(opts.Query) From 7a691e4c44000bae61468eeb951446044cfb92d9 Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:14:48 -0600 Subject: [PATCH 4/8] feat(comment): add automated feature request response --- .github/workflows/feature-request-comment.yml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/feature-request-comment.yml diff --git a/.github/workflows/feature-request-comment.yml b/.github/workflows/feature-request-comment.yml new file mode 100644 index 00000000000..48d4ea9e2cd --- /dev/null +++ b/.github/workflows/feature-request-comment.yml @@ -0,0 +1,36 @@ +name: Add feature-request comment +on: + issues: + types: + - labeled + +permissions: + issues: write + +jobs: + add-comment-to-feature-request-issues: + if: github.event.label.name == 'feature-request' + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.issue.number }} + BODY: > + Thank you for your issue! We have categorized it as a feature request, + and it has been added to our backlog. In doing so, **we are not + committing to implementing this feature at this time**, but, we will + consider it for future releases based on community feedback and our own + product roadmap. + + + Unless you see the + https://github.com/cli/cli/labels/help%20wanted label, we are + not currently looking for external contributions for this feature. + + + **If you come across this issue and would like to see it implemented, + please add a thumbs up!** This will help us prioritize the feature. + Please only comment if you have additional information or viewpoints to + contribute. + steps: + - run: gh issue comment "$NUMBER" --body "$BODY" From e2b444452d06dfe1d7366457b9c2b3ee6edccfdc Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Thu, 17 Jul 2025 17:32:48 +0200 Subject: [PATCH 5/8] Add additional test case for when extension is prefixed with a dot --- pkg/cmd/search/code/code_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/cmd/search/code/code_test.go b/pkg/cmd/search/code/code_test.go index a484a227c01..efb5f4b5740 100644 --- a/pkg/cmd/search/code/code_test.go +++ b/pkg/cmd/search/code/code_test.go @@ -341,6 +341,24 @@ func TestCodeRun(t *testing.T) { }, wantBrowse: "https://github.com/search?q=map+path%3Atesting.go&type=code", }, + { + name: "properly handles extension with dot prefix when converting to path qualifier", + opts: &CodeOptions{ + Config: func() (gh.Config, error) { return config.NewBlankConfig(), nil }, + Query: search.Query{ + Keywords: []string{"map"}, + Kind: "code", + Limit: 30, + Qualifiers: search.Qualifiers{ + Filename: "testing", + Extension: ".cpp", + }, + }, + Searcher: search.NewSearcher(nil, "github.com"), + WebMode: true, + }, + wantBrowse: "https://github.com/search?q=map+path%3Atesting.cpp&type=code", + }, { name: "does not convert filename and extension qualifiers for GHES web search", opts: &CodeOptions{ From f06c46de95f4fb77e163d36c244c125de85311d6 Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:58:05 -0600 Subject: [PATCH 6/8] Potential fix for code scanning alert no. 169: Workflow does not contain permissions Co-Authored-By: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/triage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 3ed27a5f2ba..a2ca1716068 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -1,5 +1,6 @@ name: Discussion Triage run-name: ${{ github.event_name == 'issues' && github.event.issue.title || github.event.pull_request.title }} +permissions: {} on: issues: types: From 7f97bcfcd67f7806e04f749d9636788066270fbc Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:00:17 -0600 Subject: [PATCH 7/8] doc: remove codenames from code comments --- pkg/cmd/search/code/code.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/cmd/search/code/code.go b/pkg/cmd/search/code/code.go index 481c417bfe6..d03526c4d9e 100644 --- a/pkg/cmd/search/code/code.go +++ b/pkg/cmd/search/code/code.go @@ -108,15 +108,15 @@ func NewCmdCode(f *cmdutil.Factory, runF func(*CodeOptions) error) *cobra.Comman func codeRun(opts *CodeOptions) error { io := opts.IO if opts.WebMode { - // Convert legacy `filename` and `extension` elasticsearch qualifiers to Blackbird's `path` - // qualifier when opening web search. + // Convert `filename` and `extension` legacy search qualifiers to the new code search's `path` + // qualifier when used with `--web` because they are incompatible. if opts.Query.Qualifiers.Filename != "" || opts.Query.Qualifiers.Extension != "" { cfg, err := opts.Config() if err != nil { return err } host, _ := cfg.Authentication().DefaultHost() - // FIXME: Remove this check once GHES supports Blackbird. + // FIXME: Remove this check once GHES supports the new `path` search qualifier. if !ghauth.IsEnterprise(host) { filename := opts.Query.Qualifiers.Filename extension := opts.Query.Qualifiers.Extension From e35a9748926d4f2b45a4393818d254ad7b2bb409 Mon Sep 17 00:00:00 2001 From: Kynan Ware <47394200+BagToad@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:11:30 -0600 Subject: [PATCH 8/8] Update .github/workflows/feature-request-comment.yml --- .github/workflows/feature-request-comment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/feature-request-comment.yml b/.github/workflows/feature-request-comment.yml index 48d4ea9e2cd..8426d7af2d9 100644 --- a/.github/workflows/feature-request-comment.yml +++ b/.github/workflows/feature-request-comment.yml @@ -9,7 +9,7 @@ permissions: jobs: add-comment-to-feature-request-issues: - if: github.event.label.name == 'feature-request' + if: github.event.label.name == 'enhancement' runs-on: ubuntu-latest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}