Skip to content

Thank you for contributing to GitHub CLI! - #1

Merged
HIHACK1911 merged 1164 commits into
HIHACK1911:trunkfrom
cli:trunk
Aug 8, 2026
Merged

HIHACK1911 merged 1164 commits into
HIHACK1911:trunkfrom
cli:trunk

Conversation

@HIHACK1911

@HIHACK1911 HIHACK1911 commented Feb 13, 2026 •

Copy link
Copy Markdown
Owner

User description


PR Type

Enhancement, Tests, Bug fix


Description

  • Implemented GitHub Copilot CLI integration with download, extraction, checksum validation, and removal functionality supporting multiple platforms and archive formats

  • Added dynamic search functionality for PR reviewers and assignees with GraphQL mutations and queries for suggestions, including support for users, bots, and teams

  • Introduced multi-select with search capability to the prompter interface with persistent options and cascading quota system for reviewer suggestions

  • Added --actions flag to browse command for navigating to repository actions with mutual exclusivity validation

  • Implemented git remote name resolution in set-default command to accept remote names as arguments

  • Added validation to prevent PR creation with identical head and base branches

  • Separated Copilot logins for assignees and reviewers with distinct constants and replacer implementations

  • Fixed null project item handling in GraphQL queries for issues and pull requests

  • Improved error messages in reference parsing with better context information

  • Allowed --ref flag to work with --all in cache deletion command

  • Migrated GoReleaser configuration to v2 format with updated deployment workflow and signing configuration

  • Updated Go version to 1.25.7 and expanded golangci-lint linter configuration

  • Removed unused Google Cloud dependencies and updated third-party licenses

  • Enhanced test coverage across multiple commands including PR edit, Copilot, cache deletion, browse, and extension registration


Diagram Walkthrough

flowchart LR
  A["PR/Issue Commands"] -->|"Add search functions"| B["Dynamic Reviewer/Assignee Search"]
  B -->|"GraphQL mutations"| C["RequestReviewsByLogin Mutation"]
  C -->|"Support bots & teams"| D["Copilot as Reviewer"]
  E["Prompter Interface"] -->|"New method"| F["MultiSelectWithSearch"]
  F -->|"Cascading quota"| G["Suggested Reviewers"]
  H["Copilot Command"] -->|"Download & extract"| I["Copilot CLI Binary"]
  I -->|"Checksum validation"| J["Secure Installation"]
  K["Browse Command"] -->|"Add flag"| L["--actions Support"]
  M["Cache Delete"] -->|"Allow combination"| N["--all with --ref"]
  O["PR Create"] -->|"Add validation"| P["Prevent Same Branch PRs"]
Loading

File Walkthrough

Relevant files
Tests
15 files
edit_test.go
Update PR edit tests for new reviewer mutation and metadata handling

pkg/cmd/pr/edit/edit_test.go

  • Updated test cases to use shared.EditableReviewers wrapper type
    instead of direct shared.EditableSlice for reviewer fields
  • Changed mock HTTP stubs to use mockRequestReviewsByLogin mutation
    instead of mockPullRequestAddReviewers for non-interactive reviewer
    updates
  • Added new test case "remove all reviewers sends empty slices to
    mutation" to verify empty slices properly clear all reviewer types
  • Updated test expectations to reflect that non-interactive Add/Remove
    operations don't require reviewer metadata fetching
  • Added test cases for GHES legacy flows without search functions for
    both assignees and reviewers
  • Enhanced interactive test cases with metadata population to simulate
    search function behavior
+263/-48
copilot_test.go
Add comprehensive test suite for Copilot CLI command         

pkg/cmd/copilot/copilot_test.go

  • Added comprehensive test suite for Copilot CLI command with 12 test
    cases covering argument parsing, removal, and download functionality
  • Implemented helper functions createTarGzBuffer and createZipBuffer for
    creating test archives
  • Added tests for tar.gz and zip extraction with path traversal security
    validation
  • Included tests for checksum validation, HTTP error handling, and
    missing binary detection
  • Added tests for Windows zip downloads and cross-platform architecture
    support
+588/-0 
queries_pr_test.go
Add tests for suggested reviewer actors GraphQL query       

api/queries_pr_test.go

  • Added mockReviewerResponse() helper function to generate GraphQL
    responses for reviewer suggestion tests
  • Implemented TestSuggestedReviewerActors() with 9 test cases covering
    cascading quota logic, deduplication, and edge cases
  • Added tests for author exclusion, bot reviewers, personal repos
    without organization teams, and error handling
+226/-0 
accessible_prompter_test.go
Add tests for MultiSelectWithSearch prompter functionality

internal/prompter/accessible_prompter_test.go

  • Added four new test cases for MultiSelectWithSearch functionality
    covering basic flow, default pre-selection, persistence between
    searches, and error propagation
  • Tests verify search function integration, option selection, and proper
    handling of search results
+214/-0 
prompter_mock.go
Add mock support for multi-select search method                   

internal/prompter/prompter_mock.go

  • Added MultiSelectWithSearchFunc field to PrompterMock for mocking
    search functionality
  • Added call tracking for MultiSelectWithSearch method with all
    parameters
  • Added corresponding lock for thread-safe call tracking
  • Updated mock implementation to support the new search interface
+77/-9   
delete_test.go
Add tests for cache deletion with ref parameter                   

pkg/cmd/cache/delete/delete_test.go

  • Changed test case expectation from error to success for --all --ref
    combination
  • Added three new test cases for deleting caches with ref parameter
  • Tests cover successful deletion, no caches found, and
    success-on-no-caches scenarios
+79/-3   
create_test.go
Add tests for same head/base branch validation                     

pkg/cmd/pr/create/create_test.go

  • Added two test cases validating that same head and base branches
    produce errors
  • Added Test_isSameRef function with comprehensive test cases for ref
    comparison logic
  • Tests cover same branch in same repo, different branches, cross-repo
    PRs, and fork scenarios
+95/-0   
setdefault_test.go
Add tests for git remote name resolution                                 

pkg/cmd/repo/setdefault/setdefault_test.go

  • Added remotes field to test struct for mocking git remotes
  • Added test cases for remote name argument and repo argument with
    matching remote name
  • Updated test setup to provide Remotes function to factory
  • Moved git repository check earlier in test execution
+48/-5   
extension_registration_test.go
Add tests for extension command conflict detection             

pkg/cmd/root/extension_registration_test.go

  • Created new test file for extension registration functionality
  • Tests verify that extensions conflicting with core commands are
    skipped
  • Tests cover single conflicts, multiple extensions, and no conflicts
    scenarios
+97/-0   
browse_test.go
Add tests for browse actions flag                                               

pkg/cmd/browse/browse_test.go

  • Added test case for --actions flag
  • Added test case for mutually exclusive --actions --wiki combination
  • Added test case for mutually exclusive argument with --actions flag
  • Updated assertions to verify ActionsFlag field
+31/-0   
test.go
Add mock support for multi-select search in tests               

internal/prompter/test.go

  • Added multiSelectWithSearchStubs field to MockPrompter for test stubs
  • Implemented MultiSelectWithSearch method for mock prompter
  • Added RegisterMultiSelectWithSearch method for test setup
+19/-4   
queries_projects_v2_test.go
Add tests for null project item handling                                 

api/queries_projects_v2_test.go

  • Added test case for skipping null project items in issue queries
  • Added test case for skipping null project items in pull request
    queries
+22/-0   
params_test.go
Add tests for Copilot reviewer replacer                                   

pkg/cmd/pr/shared/params_test.go

  • Added TestCopilotReviewerReplacer_ReplaceSlice test function
  • Tests verify replacement of @copilot with reviewer login
  • Tests cover case-insensitive handling and no mentions scenarios
+31/-0   
finder_test.go
Add test for large number parsing error                                   

pkg/cmd/pr/shared/finder_test.go

  • Added test case for invalid reference with number exceeding int64
    range
  • Test verifies proper error message including strconv.Atoi error
    details
+5/-0     
zip_test.go
Update tests for zip package rename                                           

internal/zip/zip_test.go

  • Changed package name from download to zip
  • Updated function call from extractZip to ExtractZip
+2/-2     
Enhancement
17 files
queries_pr.go
Add GraphQL mutations and queries for reviewer/assignee suggestions

api/queries_pr.go

  • Added DisplayName() method to RequestedReviewer for user-friendly
    reviewer names, with special handling for Copilot bot
  • Added DisplayNames() method to ReviewRequests to return display names
    for all reviewers
  • Implemented extractTeamSlugs() helper to extract slug portion from
    "org/slug" team identifiers
  • Implemented toGitHubV4Strings() helper to convert string slices to
    GraphQL string types with optional suffix
  • Added RequestReviewsByLogin() GraphQL mutation function for setting
    reviewers on github.com with support for users, bots, and teams
  • Added SuggestedAssignableActors() query function to fetch suggested
    assignees for an issue or PR
  • Added reviewer candidate types (ReviewerCandidate, ReviewerUser,
    ReviewerBot, ReviewerTeam) with display name methods
  • Implemented SuggestedReviewerActors() query with cascading quota
    system to fetch up to 15 suggested reviewers from multiple sources
  • Updated AddPullRequestReviews() and RemovePullRequestReviews() to use
    extractTeamSlugs() for proper team slug handling
+413/-9 
copilot.go
Implement GitHub Copilot CLI integration command                 

pkg/cmd/copilot/copilot.go

  • Implemented new copilot command with support for downloading and
    running GitHub Copilot CLI
  • Added CopilotOptions struct with configuration for HTTP client,
    prompter, and command arguments
  • Implemented downloadCopilot() function with checksum validation and
    platform-specific archive extraction
  • Added extractTarGz() and extractZip() functions with path traversal
    security checks using safepaths
  • Implemented fetchExpectedChecksum() to parse SHA256SUMS.txt files from
    release downloads
  • Added findCopilotBinary() to locate Copilot in PATH or gh's data
    directory
  • Implemented removeCopilot() to uninstall downloaded Copilot CLI
  • Added support for --remove flag and interactive installation prompts
+455/-0 
edit.go
Add dynamic search functions and GraphQL mutation for reviewers

pkg/cmd/pr/edit/edit.go

  • Added assigneeSearchFunc() to provide dynamic assignee search with
    metadata population for ID resolution
  • Added reviewerSearchFunc() to provide dynamic reviewer search
    supporting users, bots, and teams
  • Updated reviewer flag help text to document @copilot support for
    add/remove operations
  • Modified updatePullRequestReviews() to use GraphQL mutation on
    github.com and REST API on GHES
  • Implemented updatePullRequestReviewsGraphQL() using new
    RequestReviewsByLogin mutation
  • Implemented updatePullRequestReviewsREST() for legacy GHES
    compatibility
  • Updated partitionUsersAndTeams() to partitionReviewersByType() to
    separately identify bots and teams
  • Added @copilot replacement logic for non-interactive reviewer
    operations
  • Wired up search functions when ActorIsAssignable feature is enabled
+174/-24
delete.go
Allow --ref flag to work with --all for cache deletion     

pkg/cmd/cache/delete/delete.go

  • Removed mutual exclusivity check between --all and --ref flags to
    allow using them together
  • Updated validation to allow --ref with --all for deleting all caches
    for a specific ref
  • Modified GetCaches() call to pass Ref option when DeleteAll is true
  • Updated flag help text and example documentation to reflect new
    combined usage
+6/-10   
editable.go
Add dynamic search support for reviewers and assignees     

pkg/cmd/pr/shared/editable.go

  • Added ReviewerSearchFunc and AssigneeSearchFunc fields to Editable
    struct for dynamic search functionality
  • Created new EditableReviewers type with DefaultLogins field similar to
    EditableAssignees
  • Added MultiSelectWithSearch method to EditPrompter interface
  • Updated EditFieldsSurvey to use search-based selection when search
    functions are available
  • Modified FetchOptions to conditionally fetch reviewers/assignees based
    on search function availability
+94/-23 
prompter.go
Implement multi-select with dynamic search functionality 

internal/prompter/prompter.go

  • Added MultiSelectWithSearch method to Prompter interface with
    comprehensive documentation
  • Implemented multiSelectWithSearch function supporting dynamic search
    results with persistent options
  • Added MultiSelectSearchResult struct to return search results with
    keys, labels, and more results count
  • Implemented method in both accessiblePrompter and surveyPrompter types
+167/-0 
prompter.go
Add preview command support for multi-select search           

pkg/cmd/preview/prompter/prompter.go

  • Added multiSelectWithSearchPrompt constant and corresponding handler
    function
  • Implemented runMultiSelectWithSearch demonstration function with
    search callback
  • Updated prompt type map and order to include the new search prompt
    type
  • Added documentation for the new prompt type in help text
+69/-18 
root.go
Add copilot command and extension conflict detection         

pkg/cmd/root/root.go

  • Added import for copilotCmd package
  • Reorganized command registration to group root commands with
    standalone functionality
  • Added copilotCmd.NewCmdCopilot to root command
  • Added extension conflict detection to prevent extension commands from
    overriding core commands
+13/-2   
browse.go
Add actions flag to browse command                                             

pkg/cmd/browse/browse.go

  • Added ActionsFlag field to BrowseOptions struct
  • Added --actions flag definition with short form -a
  • Updated mutual exclusivity checks to include ActionsFlag
  • Added actions section handling in parseSection function
+8/-2     
setdefault.go
Support git remote names in set-default command                   

pkg/cmd/repo/setdefault/setdefault.go

  • Moved git repository check to beginning of command execution
  • Added logic to resolve git remote names when repo argument parsing
    fails
  • Added error message clarifying that argument can be repo or remote
    name
  • Added documentation example for setting default via remote name
+19/-7   
params.go
Support different Copilot logins for assignees and reviewers

pkg/cmd/pr/shared/params.go

  • Added copilotLogin field to CopilotReplacer struct
  • Created NewCopilotReviewerReplacer function for reviewer-specific
    Copilot handling
  • Updated NewCopilotReplacer to use api.CopilotAssigneeLogin constant
  • Modified replace method to use instance-specific copilotLogin field
+15/-2   
survey.go
Add multi-select search to prompt interface                           

pkg/cmd/pr/shared/survey.go

  • Added MultiSelectWithSearch method to Prompt interface
  • Added import for prompter package
  • Updated method signatures with explicit parameter names for clarity
+7/-5     
create.go
Add validation to prevent same head/base branch PRs           

pkg/cmd/pr/create/create.go

  • Added isSameRef function to check if head and base refs point to same
    location
  • Added validation in createRun to prevent PR creation with identical
    head and base branches
  • Function handles cross-repository PRs by checking for owner prefix in
    qualified ref
+14/-0   
queries_repo.go
Separate Copilot logins for assignees and reviewers           

api/queries_repo.go

  • Renamed CopilotActorLogin constant to CopilotAssigneeLogin
  • Added new CopilotReviewerLogin constant for pull request reviewers
  • Updated DisplayName method to use CopilotAssigneeLogin for comparison
  • Updated comments to clarify different Copilot logins for different
    contexts
+6/-5     
http.go
Use public zip extraction function                                             

pkg/cmd/run/download/http.go

  • Added import for ghzip package alias
  • Changed extractZip function call to ghzip.ExtractZip
+2/-1     
zip.go
Rename zip package and export extraction function               

internal/zip/zip.go

  • Changed package name from download to zip
  • Renamed extractZip function to ExtractZip (exported)
  • Added comprehensive documentation for the function
+6/-2     
query_builder.go
Add Bot support to pull request review requests query       

api/query_builder.go

  • Added ...on Bot{login} to prReviewRequests query to support Copilot as
    reviewer
  • Added name field to ...on User fragment in review requests
  • Added comment explaining Bot support for Copilot on github.com and
    GHES compatibility
+5/-1     
Bug fix
3 files
queries_projects_v2.go
Handle null project items in GraphQL queries                         

api/queries_projects_v2.go

  • Added null check to skip null project item nodes in issue query
    results
  • Added null check to skip null project item nodes in pull request query
    results
  • Fixed typo in comment from "dont" to "don't"
+7/-1     
edit_test.go
Fix mock data login case                                                                 

pkg/cmd/issue/edit/edit_test.go

  • Changed login value from "MonaLisa" to "monalisa" in mock response
+1/-1     
finder.go
Improve error message in reference parsing                             

pkg/cmd/pr/shared/finder.go

  • Fixed error message in ParseFullReference to include the original
    string and wrapped error
  • Changed from printing number to printing string s in error format
+1/-1     
Dependencies
3 files
go.mod
Update Go version and dependencies                                             

go.mod

  • Updated Go version from 1.25.0 to 1.25.7
  • Removed toolchain directive
  • Updated multiple dependencies to newer versions
  • Removed several unused transitive dependencies
+54/-112
third-party-licenses.windows.md
Update third-party licenses and remove unused dependencies

third-party-licenses.windows.md

  • Removed 10 Google Cloud dependencies (cel.dev/expr,
    cloud.google.com/go packages, GoogleCloudPlatform packages)
  • Updated multiple dependency versions to newer releases
    (charmbracelet/bubbletea, charmbracelet/x/ansi, cli/oauth,
    gdamore/tcell/v2, go-openapi packages, sigstore packages, etc.)
  • Changed license information for some packages from Apache-2.0 to
    Unknown (cyberphone/json-canonicalization, in-toto packages)
  • Removed numerous unused dependencies (cespare/xxhash, envoyproxy
    packages, fsnotify, go-jose, go-chi, googleapis packages, and others)
+65/-116
third-party-licenses.linux.md
Update third-party licenses and remove unused dependencies

third-party-licenses.linux.md

  • Removed 10 Google Cloud dependencies (cel.dev/expr,
    cloud.google.com/go packages, GoogleCloudPlatform packages)
  • Updated multiple dependency versions to newer releases
    (charmbracelet/bubbletea, charmbracelet/x/ansi, cli/oauth,
    gdamore/tcell/v2, go-openapi packages, sigstore packages, etc.)
  • Changed license information for some packages from Apache-2.0 to
    Unknown (cyberphone/json-canonicalization, in-toto packages)
  • Removed numerous unused dependencies (cespare/xxhash, envoyproxy
    packages, fsnotify, go-jose, go-chi, googleapis packages, and others)
+65/-116
Configuration changes
4 files
deployment.yml
Update deployment workflow for GoReleaser v2 and signing 

.github/workflows/deployment.yml

  • Updated GoReleaser action to v6.4.0 with pinned version v2.13.1
  • Added temporary git tag creation before building release binaries
  • Updated Azure Code Signing client to Microsoft.Trusted.Signing.Client
    v1.0.95
  • Changed Azure Code Signing endpoint to wus3.codesigning.azure.net
  • Updated artifact upload/download actions to v6 and v7
  • Updated attest-build-provenance action to v3.2.0
  • Fixed Windows build directory paths for GoReleaser v2 compatibility
+41/-15 
.goreleaser.yml
Migrate GoReleaser configuration to v2 format                       

.goreleaser.yml

  • Added version: 2 directive for GoReleaser v2 format
  • Changed goarch values to strings (e.g., "386" instead of 386)
  • Updated archive configuration from builds to ids field
  • Changed format to formats array syntax
  • Removed rlcp option (deprecated in v2)
  • Updated nfpms configuration to use ids field
+12/-12 
.golangci.yml
Expand golangci-lint linter configuration                               

.golangci.yml

  • Changed linter configuration from default to explicit enable list
  • Added 14 new linters including asasalint, asciicheck, bidichk,
    exptostd, fatcontext, and others
  • Removed default linter set in favor of curated selection
+21/-8   
lint.yml
Update lint workflow dependencies                                               

.github/workflows/lint.yml

  • Updated golangci-lint-action to v9.2.0
  • Updated go-licenses installation to use v2 version
+2/-2     
Documentation
6 files
LICENSE
Add license for yaml v3 package                                                   

third-party/go.yaml.in/yaml/v3/LICENSE

  • Added new license file for go.yaml.in/yaml/v3 package
  • Includes both MIT and Apache license terms
  • Documents original libyaml C files and Go port copyright
+50/-0   
NOTICE
Add notice file for jsonpointer package                                   

third-party/github.com/go-openapi/jsonpointer/NOTICE

  • Added new NOTICE file documenting go-openapi/jsonpointer licensing
  • Includes copyright information and Apache 2.0 license terms
+39/-0   
NOTICE
Add notice file for jsonreference package                               

third-party/github.com/go-openapi/jsonreference/NOTICE

  • Added new NOTICE file documenting go-openapi/jsonreference licensing
  • Includes copyright information and Apache 2.0 license terms
+39/-0   
CONTRIBUTING.md
Update contribution guidelines                                                     

.github/CONTRIBUTING.md

  • Updated contribution guidelines to focus on help wanted labeled issues
  • Simplified language around proposing changes
  • Changed "Please _do not_" to "Please _do NOT_" for consistency
+3/-3     
source.md
Improve documentation formatting                                                 

docs/source.md

  • Added blank lines for better formatting between sections
  • Improved readability of Unix-like and Windows installation
    instructions
+6/-0     
install_linux.md
Update Debian package documentation link                                 

docs/install_linux.md

  • Updated Debian package link from bookworm to stable
+1/-1     
Additional files
101 files
bump-go.yml +1/-0     
go.sum +203/-1747
goBinWorkflow.yml +1/-1     
otherBinWorkflow.yml +1/-1     
licenses +1/-1     
licenses-check +1/-1     
pkgmacos +1/-1     
third-party-licenses.darwin.md +65/-116
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE +0/-202 
LICENSE.txt +0/-22   
LICENSE +1/-1     
LICENSE +0/-13   
LICENSE +0/-201 
LICENSE +0/-202 
LICENSE.txt +0/-19   
LICENSE +0/-25   
LICENSE +0/-20   
LICENSE +0/-202 
LICENSE +0/-27   
LICENSE +0/-1     
LICENSE +0/-191 
LICENSE +0/-27   
LICENSE.md +0/-202 
LICENSE +0/-202 
LICENSE +0/-27   
ci.yml +0/-42   
.golangci.yml +0/-46   
2q.go +0/-267 
2q_test.go +0/-375 
LICENSE +0/-364 
README.md +0/-79   
doc.go +0/-24   
expirable_lru.go +0/-338 
expirable_lru_test.go +0/-573 
go.mod +0/-3     
list.go +0/-142 
lru.go +0/-250 
lru_test.go +0/-443 
LICENSE_list +0/-29   
lru.go +0/-177 
lru_interface.go +0/-46   
lru_test.go +0/-255 
testing_test.go +0/-19   
LICENSE +0/-13   
LICENSE +0/-21   
license.md +0/-21   
.dockerignore +0/-2     
FUNDING.yml +0/-1     
dependabot.yml +0/-21   
issue_template.md +0/-21   
boulder-ci.yml +0/-164 
check-iana-registries.yml +0/-53   
codeql.yml +0/-27   
cps-review.yml +0/-69   
issue-for-sre-handoff.yml +0/-55   
merged-to-main-or-release-branch.yml +0/-17   
release.yml +0/-66   
try-release.yml +0/-47   
.golangci.yml +0/-89   
.typos.toml +0/-38   
CODEOWNERS +0/-1     
LICENSE.txt +0/-375 
Makefile +0/-61   
README.md +0/-286 
cache-client.go +0/-402 
cache-client_test.go +0/-275 
akamai.pb.go +0/-137 
akamai.proto +0/-14   
akamai_grpc.pb.go +0/-122 
main.go +0/-43   
main_test.go +0/-109 
dns.go +0/-586 
dns_test.go +0/-891 
mocks.go +0/-124 
problem.go +0/-159 
problem_test.go +0/-92   
servers.go +0/-325 
servers_test.go +0/-103 
ca.go +0/-696 
ca_test.go +0/-1144
crl.go +0/-203 
crl_test.go +0/-271 
ocsp.go +0/-253 
ocsp_test.go +0/-235 
ca.pb.go +0/-597 
ca.proto +0/-78   
ca_grpc.pb.go +0/-339 
bad_algorithm.der.csr [link]   
cn_and_san.der.csr [link]   
Additional files not shown


Open in Devin Review

@qodo-code-review

qodo-code-review Bot commented Feb 13, 2026 •

Copy link
Copy Markdown

Warning

/compliance is deprecated. Use /agentic_review instead (removal date not yet scheduled).

PR Compliance Guide 🔍

(Compliance updated until commit 0274077)

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
⚪
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
⚪
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
⚪
No custom compliance provided

Follow the guide to enable custom compliance check.

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit 4e65637
Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
⚪
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
⚪
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

⚪
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logging: The new reviewer/assignee mutation path (including RequestReviewsByLogin) is not shown
emitting any audit-relevant log entries, but audit logging may be handled elsewhere
outside this diff.

Referred Code
func updatePullRequestReviews(httpClient *http.Client, repo ghrepo.Interface, prID string, number int, editable shared.Editable) error {
	if !editable.Reviewers.Edited {
		return nil
	}

	client := api.NewClientFromHTTP(httpClient)

	// Rebuild the Value slice from non-interactive flag input.
	if len(editable.Reviewers.Add) != 0 || len(editable.Reviewers.Remove) != 0 {
		add := editable.Reviewers.Add
		remove := editable.Reviewers.Remove

		// Replace @copilot with the Copilot reviewer login (only on github.com).
		// Also use DefaultLogins (not Default display names) for computing the set.
		var defaultLogins []string
		if editable.Assignees.ActorAssignees {
			copilotReplacer := shared.NewCopilotReviewerReplacer()
			add = copilotReplacer.ReplaceSlice(add)
			remove = copilotReplacer.ReplaceSlice(remove)
			defaultLogins = editable.Reviewers.DefaultLogins
		} else {


 ... (clipped 52 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Brittle error check: The new SuggestedReviewerActors flow determines whether to ignore an error by
substring-matching err.Error() which may be fragile and could miss edge cases or
localized/changed error messages.

Referred Code
var result responseData
err := client.Query(repo.RepoHost(), "SuggestedReviewerActors", &result, variables)
// Handle the case where the owner is not an organization - the query still returns
// partial data (repository, node), so we can continue processing.
if err != nil && !strings.Contains(err.Error(), errorResolvingOrganization) {
	return nil, 0, err
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Raw error surfaced: The new MultiSelectWithSearch can return underlying searchFunc errors directly (or
wrapped) which may expose internal API details depending on how/where these errors are
displayed to end users.

Referred Code
func multiSelectWithSearch(p Prompter, prompt, searchPrompt string, defaultValues, persistentValues []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
	selectedOptions := defaultValues

	// The optionKeyLabels map is used to uniquely identify optionKeyLabels
	// and provide optional display labels.
	optionKeyLabels := make(map[string]string)
	for _, k := range selectedOptions {
		optionKeyLabels[k] = k
	}

	searchResult := searchFunc("")
	if searchResult.Err != nil {
		return nil, fmt.Errorf("failed to search: %w", searchResult.Err)
	}
	searchResultKeys := searchResult.Keys
	searchResultLabels := searchResult.Labels
	moreResults := searchResult.MoreResults

	for i, k := range searchResultKeys {
		optionKeyLabels[k] = searchResultLabels[i]
	}


 ... (clipped 120 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Team slug parsing: extractTeamSlugs accepts arbitrary strings and falls back to using the last path segment,
which may allow malformed team identifiers to be sent onward unless upstream validation
guarantees org/slug formatting.

Referred Code
// extractTeamSlugs extracts just the slug portion from team identifiers.
// Team identifiers can be in "org/slug" format; this returns just the slug.
func extractTeamSlugs(teams []string) []string {
	slugs := make([]string, 0, len(teams))
	for _, t := range teams {
		if t == "" {
			continue
		}
		s := strings.SplitN(t, "/", 2)
		slugs = append(slugs, s[len(s)-1])
	}
	return slugs
}

Learn more about managing compliance generic rules or creating your own custom rules

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @HIHACK1911, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces significant enhancements to the GitHub CLI, focusing on integrating the GitHub Copilot CLI, improving interactive workflows for managing pull request reviewers and assignees, and refining various core commands. It also includes comprehensive updates to development dependencies and build configurations, ensuring better code quality and release processes. The changes aim to streamline developer experience and expand the CLI's capabilities.

Highlights

  • GitHub Copilot CLI Integration: Introduced a new gh copilot command that allows users to run the GitHub Copilot CLI. This command handles downloading, installing, and removing the Copilot CLI, and supports passing arguments directly to it. It also includes logic to prevent conflicts with existing core commands.
  • Enhanced Reviewer/Assignee Management: Implemented dynamic search functionality for selecting reviewers and assignees in interactive gh pr edit and gh issue edit commands. This includes support for displaying user-friendly names, handling bot reviewers (like Copilot), and using GraphQL mutations for more efficient updates on github.com.
  • Updated Contribution Guidelines: Modified the CONTRIBUTING.md file to clarify that pull requests are primarily accepted for issues labeled help wanted, encouraging issues and discussion posts for other contributions.
  • Build and Dependency Updates: Upgraded the Go version to 1.25.7 and updated numerous Go module dependencies. The .golangci.yml configuration was expanded with many new linters, and .goreleaser.yml was updated for improved release packaging, including changes to goarch formatting and archive/NFPMS IDs.
  • New gh browse Flag: Added a new --actions flag to the gh browse command, allowing users to directly open the repository's Actions page in their browser.
  • Improved gh cache delete Functionality: The gh cache delete command now supports using the --ref flag in conjunction with --all, enabling users to delete all caches associated with a specific Git reference.
  • Pull Request Creation Validation: Added a check to prevent the creation of pull requests where the head branch is the same as the base branch, ensuring valid PR configurations.
  • Refined Repository Default Setting: The gh repo set-default command now accepts a Git remote name as an argument, providing more flexibility in specifying the default repository.
Changelog
  • .github/CONTRIBUTING.md
    • Updated guidelines to specify that pull requests are accepted for issues labeled 'help wanted' and encourage issues/discussions for other contributions.
  • .golangci.yml
    • Enabled several new linters to enforce stricter code quality and style standards.
  • .goreleaser.yml
    • Updated goreleaser configuration to version 2.
    • Modified goarch entries to be quoted strings (e.g., '386').
    • Changed builds field to ids in archive and NFPMS configurations for compatibility with goreleaser v2.
  • api/queries_pr.go
    • Imported the strings package.
    • Defined botTypeName constant for reviewer types.
    • Added DisplayName() method to RequestedReviewer to provide user-friendly names, including 'Copilot (AI)' for bot reviewers.
    • Implemented DisplayNames() method for ReviewRequests to return a slice of user-friendly names.
    • Introduced extractTeamSlugs helper function to extract team slugs from 'org/slug' format.
    • Added toGitHubV4Strings helper function to convert string slices to githubv4.String slices with optional suffixes.
    • Modified AddPullRequestReviews to use extractTeamSlugs for team reviewers and removed redundant teams == nil checks.
    • Added RequestReviewsByLogin GraphQL mutation for managing pull request reviewers (users, bots, teams) with a union option.
    • Implemented SuggestedAssignableActors GraphQL query to fetch suggested assignees (users and bots).
    • Defined ReviewerCandidate interface and concrete types (ReviewerUser, ReviewerBot, ReviewerTeam) for suggested reviewers.
    • Added SuggestedReviewerActors GraphQL query with cascading quota logic to fetch suggested reviewers from multiple sources.
  • api/queries_pr_test.go
    • Imported fmt and strings packages.
    • Added mockReviewerResponse helper function to generate GraphQL responses for SuggestedReviewerActors tests.
    • Added comprehensive test cases for SuggestedReviewerActors covering various scenarios like cascading quotas, author exclusion, deduplication, personal repositories, and bot reviewers.
  • api/queries_projects_v2.go
    • Added a nil check for projectItemNode in ProjectsV2ItemsForIssue and ProjectsV2ItemsForPullRequest loops to prevent panics.
    • Corrected a typo in a comment from 'dont' to 'don't'.
  • api/queries_projects_v2_test.go
    • Added test cases to ensure nil project items are correctly skipped when fetching project items for issues and pull requests.
  • api/queries_repo.go
    • Renamed CopilotActorLogin to CopilotAssigneeLogin to clarify its purpose for assignees.
    • Introduced CopilotReviewerLogin constant to distinguish the login for Copilot as a pull request reviewer.
    • Updated AssignableBot.DisplayName() to use CopilotAssigneeLogin.
  • api/query_builder.go
    • Modified the prReviewRequests GraphQL fragment to include name for users and login for bots in the requestedReviewer union, supporting display names for reviewers.
  • docs/install_linux.md
    • Updated the Debian community package link from bookworm to stable.
  • docs/source.md
    • Added blank lines within code blocks for improved readability and consistent formatting.
  • go.mod
    • Updated Go version to 1.25.7.
    • Updated github.com/cli/oauth from v1.2.0 to v1.2.2.
    • Updated github.com/gdamore/tcell/v2 from v2.13.1 to v2.13.8.
    • Updated github.com/microsoft/dev-tunnels from v0.1.13 to v0.1.19.
    • Updated github.com/spf13/cobra from v1.10.1 to v1.10.2.
    • Updated github.com/theupdateframework/go-tuf/v2 from v2.3.0 to v2.4.1.
    • Updated github.com/yuin/goldmark from v1.7.13 to v1.7.16.
    • Updated golang.org/x/crypto from v0.45.0 to v0.47.0.
    • Updated golang.org/x/sync from v0.18.0 to v0.19.0.
    • Updated golang.org/x/term from v0.37.0 to v0.39.0.
    • Updated golang.org/x/text from v0.31.0 to v0.33.0.
    • Updated google.golang.org/grpc from v1.77.0 to v1.78.0.
    • Updated google.golang.org/protobuf from v1.36.10 to v1.36.11.
    • Removed various indirect dependencies related to Google Cloud Platform and HashiCorp LRU cache.
  • internal/prompter/accessible_prompter_test.go
    • Added test cases for MultiSelectWithSearch covering basic flow, default pre-selection, persistence of selections between searches, and error propagation.
  • internal/prompter/prompter.go
    • Added MultiSelectWithSearch method to the Prompter interface.
    • Implemented MultiSelectWithSearch for accessiblePrompter and surveyPrompter.
    • Defined MultiSelectSearchResult struct to encapsulate search results for MultiSelectWithSearch.
  • internal/prompter/prompter_mock.go
    • Updated PrompterMock to include MultiSelectWithSearchFunc and corresponding call tracking.
  • internal/prompter/test.go
    • Added multiSelectWithSearchStub struct and its registration to MockPrompter for testing MultiSelectWithSearch.
  • internal/zip/zip.go
    • Renamed from pkg/cmd/run/download/zip.go and moved to internal/zip package.
    • Made extractZip function public as ExtractZip and added documentation.
  • internal/zip/zip_test.go
    • Renamed from pkg/cmd/run/download/zip_test.go and moved to internal/zip package.
    • Updated test cases to use the new ExtractZip function.
  • pkg/cmd/browse/browse.go
    • Added ActionsFlag to BrowseOptions struct.
    • Updated mutual exclusivity checks to include the new --actions flag.
    • Added logic to parseSection to handle the --actions flag and construct the corresponding URL.
  • pkg/cmd/browse/browse_test.go
    • Added test cases for the new --actions flag, including its usage and mutual exclusivity with other flags.
  • pkg/cmd/cache/delete/delete.go
    • Updated example usage in help text to show --all with --ref.
    • Removed mutual exclusivity check between --ref and --all.
    • Modified logic to allow --ref to be used with --all when fetching caches.
  • pkg/cmd/cache/delete/delete_test.go
    • Updated test case for --ref with --all to reflect the new allowed behavior.
    • Added test cases for deleting all caches with a specific ref, and handling scenarios with no caches.
  • pkg/cmd/copilot/copilot.go
    • Added new command gh copilot for managing and running the GitHub Copilot CLI.
    • Implemented logic to find, download, install, and remove the Copilot CLI.
    • Included checksum validation for downloaded binaries.
    • Added support for tar.gz and zip archive extraction.
    • Disabled flag parsing for gh copilot to allow passing flags directly to the Copilot CLI.
  • pkg/cmd/copilot/copilot_test.go
    • Added test cases for gh copilot command, covering argument parsing, --remove flag, and download/extraction scenarios.
  • pkg/cmd/extension/ext_tmpls/goBinWorkflow.yml
    • Updated actions/checkout action to v6.
  • pkg/cmd/extension/ext_tmpls/otherBinWorkflow.yml
    • Updated actions/checkout action to v6.
  • pkg/cmd/issue/edit/edit_test.go
    • Updated a mock user login from MonaLisa to monalisa for consistency.
  • pkg/cmd/pr/create/create.go
    • Added isSameRef helper function to check if head and base branches are identical.
    • Implemented a check in createRun to prevent creating a pull request if the head and base branches are the same.
  • pkg/cmd/pr/create/create_test.go
    • Added test cases to verify that creating a pull request with identical head and base branches results in an error.
  • pkg/cmd/pr/edit/edit.go
    • Updated help text for --add-reviewer and --remove-reviewer flags to mention @copilot support.
    • Modified editRun to use DisplayName() for reviewers and DefaultLogins for internal logic when ActorIsAssignable is enabled.
    • Introduced assigneeSearchFunc and reviewerSearchFunc to provide dynamic search capabilities for interactive prompts, updating editable metadata for ID resolution.
    • Refactored updatePullRequestReviews to use GraphQL mutation (RequestReviewsByLogin) for github.com and fallback to REST API for GHES.
    • Updated partitionUsersAndTeams to partitionReviewersByType to correctly separate users, bots, and teams, and handle 'org/slug' format for teams.
  • pkg/cmd/pr/edit/edit_test.go
    • Updated test cases for gh pr edit to reflect changes in reviewer/assignee handling, including @copilot support and GraphQL mutation usage.
    • Added tests for interactive GHES flows, ensuring legacy assignee/reviewer fetching is used without search functions.
    • Updated mock data to reflect monalisa login change.
  • pkg/cmd/pr/shared/editable.go
    • Added ReviewerSearchFunc and AssigneeSearchFunc fields to the Editable struct, both of type func(string) prompter.MultiSelectSearchResult.
    • Introduced EditableReviewers struct, embedding EditableSlice and adding DefaultLogins for disambiguating actors.
    • Added clone() method for EditableReviewers.
  • pkg/cmd/pr/shared/finder.go
    • Improved error message for ParseFullReference when strconv.Atoi fails, including the original string and the underlying error.
  • pkg/cmd/pr/shared/finder_test.go
    • Added a test case for ParseFullReference with an invalid (too large) PR number, expecting a specific error message.
  • pkg/cmd/pr/shared/params.go
    • Introduced copilotLogin field to CopilotReplacer to differentiate between assignee and reviewer bot logins.
    • Added NewCopilotReviewerReplacer function to create a replacer specifically for reviewer @copilot references.
  • pkg/cmd/pr/shared/params_test.go
    • Added test cases for NewCopilotReviewerReplacer to verify correct replacement of @copilot with the reviewer bot login.
  • pkg/cmd/pr/shared/survey.go
    • Updated Prompt interface to include MultiSelectWithSearch method.
    • Modified EditFieldsSurvey to conditionally use MultiSelectWithSearch for reviewers and assignees if corresponding search functions are provided.
    • Updated FetchOptions to conditionally fetch reviewer and assignee metadata based on the presence of search functions and interactive/non-interactive modes.
  • pkg/cmd/preview/prompter/prompter.go
    • Added multiSelectWithSearchPrompt constant and runMultiSelectWithSearch function for demonstrating the new multi-select with search prompt type.
  • pkg/cmd/repo/setdefault/setdefault.go
    • Updated help text examples to include setting a default repository using a Git remote name.
    • Modified argument parsing logic to attempt resolving the argument as a Git remote name if it's not a valid OWNER/REPO format.
  • pkg/cmd/repo/setdefault/setdefault_test.go
    • Added test cases for setting a default repository using a remote name and for handling invalid arguments.
  • pkg/cmd/root/extension_registration_test.go
    • Added new test file to verify extension registration logic, ensuring extensions do not override core commands or their aliases.
  • pkg/cmd/root/root.go
    • Added copilotCmd.NewCmdCopilot(f, nil) to the root commands.
    • Modified extension registration loop to skip registering an extension command if its name conflicts with an existing core command or alias.
  • pkg/cmd/run/download/http.go
    • Updated downloadArtifact to use ghzip.ExtractZip from the new internal/zip package.
  • script/licenses
    • Updated go install command for github.com/google/go-licenses to use v2.
  • script/licenses-check
    • Updated go install command for github.com/google/go-licenses to use v2.
  • script/pkgmacos
    • Updated the arm64_bin path from macos_darwin_arm64 to macos_darwin_arm64_v8.0 for macOS packaging.
  • script/release
    • Modified goreleaser command to use --skip validate,publish,announce instead of --skip-validate --skip-publish.
  • third-party-licenses.darwin.md
    • Removed license entries for cel.dev/expr, cloud.google.com/go and its sub-packages, github.com/GoogleCloudPlatform related packages, github.com/cncf/xds/go, github.com/felixge/httpsnoop, github.com/fsnotify/fsnotify, github.com/go-chi/chi/v5, github.com/go-jose/go-jose/v4 and its sub-packages, github.com/golang/groupcache/lru, github.com/google/s2a-go, github.com/googleapis/enterprise-certificate-proxy/client, github.com/googleapis/gax-go/v2, github.com/hashicorp/golang-lru/v2 and its sub-packages, github.com/jedisct1/go-minisign, github.com/josharian/intern, github.com/letsencrypt/boulder and its sub-packages, github.com/mailru/easyjson, github.com/mitchellh/mapstructure, github.com/pelletier/go-toml/v2, github.com/sagikazarmark/locafero, github.com/sassoftware/relic/lib, github.com/sourcegraph/conc, github.com/spf13/afero, github.com/spf13/viper, github.com/spiffe/go-spiffe/v2, github.com/subosito/gotenv, github.com/theupdateframework/go-tuf, github.com/titanous/rocacheck, github.com/transparency-dev/tessera, go.opencensus.io, go.opentelemetry.io/contrib related packages, go.uber.org/multierr, go.uber.org/zap, golang.org/x/exp, golang.org/x/oauth2, golang.org/x/time/rate, google.golang.org/api and its sub-packages, google.golang.org/genproto and its sub-packages, and k8s.io/klog/v2.
    • Updated license entries for github.com/charmbracelet/bubbletea (v1.3.6 to v1.3.10), github.com/charmbracelet/x/ansi (v0.9.3 to v0.10.2), github.com/cli/oauth (v1.2.0 to v1.2.2), github.com/gdamore/tcell/v2 (v2.13.1 to v2.13.8), github.com/grpc-ecosystem/grpc-gateway/v2 (v2.27.2 to v2.27.3), github.com/microsoft/dev-tunnels (v0.1.13 to v0.1.19), github.com/mattn/go-runewidth (v0.0.16 to v0.0.17), github.com/secure-systems-lab/go-securesystemslib (v0.9.1 to v0.10.0), github.com/sigstore/rekor (v1.4.2 to v1.5.0), github.com/sigstore/rekor-tiles (v0.1.11 to v2.0.1), github.com/sigstore/sigstore (v1.9.6 to v1.10.4), github.com/sigstore/timestamp-authority (v1.2.9 to v2.0.3), github.com/transparency-dev/formats (v0.0.0-20250421220931-bb8ad4d07c26 to v0.0.0-20251017110053-404c0d5b696c), github.com/yuin/goldmark (v1.7.13 to v1.7.16), and go.mongodb.org/mongo-driver (v1.17.4 to v1.17.6).
  • third-party-licenses.linux.md
    • Removed license entries for cel.dev/expr, cloud.google.com/go and its sub-packages, github.com/GoogleCloudPlatform related packages, github.com/cncf/xds/go, github.com/felixge/httpsnoop, github.com/fsnotify/fsnotify, github.com/go-chi/chi/v5, github.com/go-jose/go-jose/v4 and its sub-packages, github.com/golang/groupcache/lru, github.com/google/s2a-go, github.com/googleapis/enterprise-certificate-proxy/client, github.com/googleapis/gax-go/v2, github.com/hashicorp/golang-lru/v2 and its sub-packages, github.com/jedisct1/go-minisign, github.com/josharian/intern, github.com/letsencrypt/boulder and its sub-packages, github.com/mailru/easyjson, github.com/mitchellh/mapstructure, github.com/pelletier/go-toml/v2, github.com/sagikazarmark/locafero, github.com/sassoftware/relic/lib, github.com/sourcegraph/conc, github.com/spf13/afero, github.com/spf13/viper, github.com/spiffe/go-spiffe/v2, github.com/subosito/gotenv, github.com/theupdateframework/go-tuf, github.com/titanous/rocacheck, github.com/transparency-dev/tessera, go.opencensus.io, go.opentelemetry.io/contrib related packages, go.uber.org/multierr, go.uber.org/zap, golang.org/x/exp, golang.org/x/oauth2, golang.org/x/time/rate, google.golang.org/api and its sub-packages, google.golang.org/genproto and its sub-packages, and k8s.io/klog/v2.
    • Updated license entries for github.com/charmbracelet/bubbletea (v1.3.6 to v1.3.10), github.com/charmbracelet/x/ansi (v0.9.3 to v0.10.2), github.com/cli/oauth (v1.2.0 to v1.2.2), github.com/gdamore/tcell/v2 (v2.13.1 to v2.13.8), github.com/grpc-ecosystem/grpc-gateway/v2 (v2.27.2 to v2.27.3), github.com/microsoft/dev-tunnels (v0.1.13 to v0.1.19), github.com/mattn/go-runewidth (v0.0.16 to v0.0.17), github.com/secure-systems-lab/go-securesystemslib (v0.9.1 to v0.10.0), github.com/sigstore/rekor (v1.4.2 to v1.5.0), github.com/sigstore/rekor-tiles (v0.1.11 to v2.0.1), github.com/sigstore/sigstore (v1.9.6 to v1.10.4), github.com/sigstore/timestamp-authority (v1.2.9 to v2.0.3), github.com/transparency-dev/formats (v0.0.0-20250421220931-bb8ad4d07c26 to v0.0.0-20251017110053-404c0d5b696c), github.com/yuin/goldmark (v1.7.13 to v1.7.16), and go.mongodb.org/mongo-driver (v1.17.4 to v1.17.6).
  • third-party-licenses.windows.md
    • Removed license entries for cel.dev/expr, cloud.google.com/go and its sub-packages, github.com/GoogleCloudPlatform related packages, github.com/cncf/xds/go, github.com/felixge/httpsnoop, github.com/fsnotify/fsnotify, github.com/go-chi/chi/v5, github.com/go-jose/go-jose/v4 and its sub-packages, github.com/golang/groupcache/lru, github.com/google/s2a-go, github.com/googleapis/enterprise-certificate-proxy/client, github.com/googleapis/gax-go/v2, github.com/hashicorp/golang-lru/v2 and its sub-packages, github.com/jedisct1/go-minisign, github.com/josharian/intern, github.com/letsencrypt/boulder and its sub-packages, github.com/mailru/easyjson, github.com/mitchellh/mapstructure, github.com/pelletier/go-toml/v2, github.com/sagikazarmark/locafero, github.com/sassoftware/relic/lib, github.com/sourcegraph/conc, github.com/spf13/afero, github.com/spf13/viper, github.com/spiffe/go-spiffe/v2, github.com/subosito/gotenv, github.com/theupdateframework/go-tuf, github.com/titanous/rocacheck, github.com/transparency-dev/tessera, go.opencensus.io, go.opentelemetry.io/contrib related packages, go.uber.org/multierr, go.uber.org/zap, golang.org/x/exp, golang.org/x/oauth2, golang.org/x/time/rate, google.golang.org/api and its sub-packages, google.golang.org/genproto and its sub-packages, and k8s.io/klog/v2.
    • Updated license entries for github.com/charmbracelet/bubbletea (v1.3.6 to v1.3.10), github.com/charmbracelet/x/ansi (v0.9.3 to v0.10.2), github.com/cli/oauth (v1.2.0 to v1.2.2), github.com/gdamore/tcell/v2 (v2.13.1 to v2.13.8), github.com/grpc-ecosystem/grpc-gateway/v2 (v2.27.2 to v2.27.3), github.com/microsoft/dev-tunnels (v0.1.13 to v0.1.19), github.com/mattn/go-runewidth (v0.0.16 to v0.0.17), github.com/secure-systems-lab/go-securesystemslib (v0.9.1 to v0.10.0), github.com/sigstore/rekor (v1.4.2 to v1.5.0), github.com/sigstore/rekor-tiles (v0.1.11 to v2.0.1), github.com/sigstore/sigstore (v1.9.6 to v1.10.4), github.com/sigstore/timestamp-authority (v1.2.9 to v2.0.3), github.com/transparency-dev/formats (v0.0.0-20250421220931-bb8ad4d07c26 to v0.0.0-20251017110053-404c0d5b696c), github.com/yuin/goldmark (v1.7.13 to v1.7.16), and go.mongodb.org/mongo-driver (v1.17.4 to v1.17.6).
Ignored Files
  • Ignored by pattern: .github/workflows/** (3)
    • .github/workflows/bump-go.yml
    • .github/workflows/deployment.yml
    • .github/workflows/lint.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@qodo-code-review

qodo-code-review Bot commented Feb 13, 2026 •

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Prioritize git remote over repository name

Reverse the logic for parsing the repository argument to first check if it's a
git remote name before attempting to parse it as a full repository name
(OWNER/REPO).

pkg/cmd/repo/setdefault/setdefault.go [91-106]

 			if len(args) > 0 {
-				var err error
-				opts.Repo, err = ghrepo.FromFullName(args[0])
+				arg := args[0]
+				remotes, err := opts.Remotes()
 				if err != nil {
-					remotes, remoteErr := opts.Remotes()
-					if remoteErr != nil {
-						return remoteErr
-					}
+					return err
+				}
 
-					remote, findErr := remotes.FindByName(args[0])
-					if findErr != nil {
+				// First, try to resolve the argument as a remote name.
+				if remote, findErr := remotes.FindByName(arg); findErr == nil {
+					opts.Repo = remote.Repo
+				} else {
+					// If it's not a remote, fall back to parsing as a full repo name.
+					opts.Repo, err = ghrepo.FromFullName(arg)
+					if err != nil {
 						return fmt.Errorf("given arg is not a valid repo or git remote: %w", err)
 					}
-					opts.Repo = remote.Repo
 				}
 			}
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a logic flaw where a remote name matching a repo format would be misinterpreted, and proposes reversing the check order to prioritize local remotes, which aligns better with user expectations.

Medium
Improve same-ref check for forks

Improve the isSameRef function to correctly handle pull requests from forks by
comparing the full repository information for both head and base refs, not just
the branch names.

pkg/cmd/pr/create/create.go [169-177]

 // isSameRef checks if the head and base refs point to the same ref in the same repository.
-// For cross-repository PRs (e.g., from a fork), the qualified head ref will contain
-// an owner prefix (owner:branch), so even if branch names match, they refer to different repos.
 func isSameRef(refs creationRefs) bool {
+	// The pushableRefs type provides full repository info for both head and base.
+	// This is the most reliable way to check for same-ref scenarios.
+	if pr, ok := refs.(pushableRefs); ok {
+		return pr.baseRepo.RepoOwner() == pr.headRepo.RepoOwner() &&
+			pr.baseRepo.RepoName() == pr.headRepo.RepoName() &&
+			pr.baseBranchName == pr.headBranchName
+	}
+
+	// For other ref types, fall back to the original logic.
+	// For cross-repository PRs (e.g., from a fork), the qualified head ref will contain
+	// an owner prefix (owner:branch), so even if branch names match, they refer to different repos.
 	if strings.Contains(refs.QualifiedHeadRef(), ":") {
 		return false
 	}
 	return refs.UnqualifiedHeadRef() == refs.BaseRef()
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies an edge case where the isSameRef logic is insufficient and proposes a more robust implementation by checking repository ownership and name, preventing incorrect PR creation blocks.

Medium
Skip git‐repo check in view mode

Modify the logic to skip the local git repository check when the --view flag is
used, allowing users to view the default repository from any directory.

pkg/cmd/repo/setdefault/setdefault.go [85-89]

-if isLocal, err := opts.GitClient.IsLocalGitRepo(cmd.Context()); err != nil {
-    return err
-} else if !isLocal {
-    return errors.New("must be run from inside a git repository")
+if !opts.ViewMode {
+    if isLocal, err := opts.GitClient.IsLocalGitRepo(cmd.Context()); err != nil {
+        return err
+    } else if !isLocal {
+        return errors.New("must be run from inside a git repository")
+    }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that checking the default repository with --view should not require being inside a git repository, improving the command's usability.

Medium
Use case-insensitive duplicate check for options

Use a case-insensitive comparison when checking for duplicate options in search
results to prevent the same option from appearing twice due to different casing.

internal/prompter/prompter.go [410-423]

 		// 3. Search results
 		for _, k := range searchResultKeys {
 			// It's already selected or persistent, if we add here we'll have duplicates.
-			if slices.Contains(selectedOptions, k) || slices.Contains(persistentValues, k) {
+			isDuplicate := slices.ContainsFunc(selectedOptions, func(s string) bool {
+				return strings.EqualFold(s, k)
+			}) || slices.ContainsFunc(persistentValues, func(s string) bool {
+				return strings.EqualFold(s, k)
+			})
+
+			if isDuplicate {
 				continue
 			}
 
 			l := optionKeyLabels[k]
 			if l == "" {
 				l = k
 			}
 			optionKeys = append(optionKeys, k)
 			optionLabels = append(optionLabels, l)
 		}
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential UI bug where case-differences in usernames could lead to duplicate entries, and the proposed fix using slices.ContainsFunc is appropriate and robust.

Low
General
Remove redundant progress stop

Remove the redundant explicit call to StopProgressIndicator as it is already
handled by a deferred call.

pkg/cmd/copilot/copilot.go [256-282]

 ios.StartProgressIndicatorWithLabel(fmt.Sprintf("Downloading Copilot CLI from %s", archiveURL))
 defer ios.StopProgressIndicator()
 ...
 if _, err := io.Copy(tmpFile, io.TeeReader(resp.Body, hasher)); err != nil {
   return "", fmt.Errorf("failed to download: %w", err)
 }
-ios.StopProgressIndicator()

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: This is a valid and good catch. The explicit call to StopProgressIndicator is redundant due to the deferred call and should be removed for cleaner code.

Low
Disallow cache ID with --all

Add a validation check to prevent users from providing a cache ID argument when
using the --all flag, as the ID would be ignored.

pkg/cmd/cache/delete/delete.go [86-88]

+if opts.DeleteAll && len(args) > 0 {
+    return cmdutil.FlagErrorf("cache ID cannot be used with --all")
+}
 if opts.Ref != "" && len(args) == 0 && !opts.DeleteAll {
     return cmdutil.FlagErrorf("must provide a cache key")
 }
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion adds a useful validation to prevent a confusing combination of arguments (--all with a cache ID), improving the command's user experience by providing immediate feedback.

Low
Handle directory entries explicitly

Explicitly handle tar.TypeDir in extractTarGz to ensure empty directories and
their permissions from the archive are preserved.

pkg/cmd/copilot/copilot.go [401-424]

 for {
   header, err := tr.Next()
   if err == io.EOF {
     break
   }
   if err != nil {
     return fmt.Errorf("failed to read tar: %w", err)
   }
   absFilePath, err := absDestDirPath.Join(header.Name)
   if err != nil {
     return err
   }
   target := absFilePath.String()
-  if header.Typeflag == tar.TypeReg {
+  switch header.Typeflag {
+  case tar.TypeDir:
+    if err := os.MkdirAll(target, os.FileMode(header.Mode)&0777); err != nil {
+      return fmt.Errorf("failed to create directory: %w", err)
+    }
+  case tar.TypeReg:
     if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
       return fmt.Errorf("failed to create parent directory: %w", err)
     }
     if err := extractFile(target, os.FileMode(header.Mode)&0777, tr); err != nil {
       return err
     }
   }
 }
  • Apply / Chat
Suggestion importance[1-10]: 3

__

Why: The suggestion correctly points out that empty directories are not explicitly handled, but the impact is low as the current code implicitly creates necessary directories and the archive is not expected to contain meaningful empty directories.

Low
  • Update

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This impressive pull request introduces significant new features, including Copilot CLI integration and dynamic reviewer search, alongside numerous enhancements, bug fixes, and dependency updates. The migration to GoReleaser v2 and expanded linters enhance maintainability. The code is well-structured and thoroughly tested. No security vulnerabilities were identified in the audited files, and there is one minor suggestion to improve code consistency.

Comment thread api/queries_pr.go Outdated
return fmt.Sprintf("%s/%s", r.Organization.Login, r.Slug)
}
if r.TypeName == botTypeName && r.Login == CopilotReviewerLogin {
return "Copilot (AI)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with ReviewerBot.DisplayName(), it would be better to construct this display name using the CopilotActorName constant rather than hardcoding the string "Copilot (AI)". This improves maintainability in case the actor name for Copilot ever changes.

Suggested change
return "Copilot (AI)"
return fmt.Sprintf("%s (AI)", CopilotActorName)

@HIHACK1911
HIHACK1911 marked this pull request as draft March 24, 2026 15:05
@qodo-code-review

qodo-code-review Bot commented May 17, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (4) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Em dashes added in docs ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
New content introduces em dashes (—) in multiple files, which is explicitly forbidden and can
break search/formatting conventions. These must be replaced with regular hyphens (-) or rewritten
phrasing.
Code

AGENTS.md[8]

+make                                       # Build (Unix) — outputs bin/gh
Evidence
PR Compliance ID 9 forbids using em dashes anywhere. The diff adds — in newly introduced lines
across documentation, workflow YAML, acceptance testdata, and Go comments.

AGENTS.md: Do Not Use Em Dashes in Code, Comments, or Documentation
AGENTS.md[8-8]
internal/agents/detect.go[49-49]
.github/workflows/triage-pull-requests.yml[6-6]
acceptance/testdata/skills/skills-install-force.txtar[5-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Em dashes (`—`) were added in repository content, which violates the repo typography rule.

## Issue Context
The compliance checklist forbids any em dash characters in code, comments, or documentation; use `-` or rewrite the sentence.

## Fix Focus Areas
- AGENTS.md[8-8]
- internal/agents/detect.go[49-49]
- .github/workflows/triage-pull-requests.yml[6-6]
- acceptance/testdata/skills/skills-install-force.txtar[5-5]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. PullRequestReviewStatus lacks godoc 📘 Rule violation ⚙ Maintainability
Description
A new exported type was introduced without a preceding godoc comment, reducing API documentation
quality and potentially failing linting rules. Exported identifiers should have intent-focused
comments.
Code

api/queries_pr_review.go[R97-101]

+type PullRequestReviewStatus struct {
+	ChangesRequested bool
+	Approved         bool
+	ReviewRequired   bool
+}
Evidence
PR Compliance ID 8 requires godoc comments for exported identifiers. The diff adds the exported type
PullRequestReviewStatus without any doc comment immediately above its declaration.

AGENTS.md: Exported Identifiers Must Have Godoc Comments; Avoid Redundant Comments
api/queries_pr_review.go[96-104]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New exported identifiers were added without godoc comments.

## Issue Context
Go linting and project conventions require exported types/functions/constants to have doc comments that start with the identifier name.

## Fix Focus Areas
- api/queries_pr_review.go[97-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Checksum filename prefix mismatch 🐞 Bug ≡ Correctness
Description
fetchExpectedChecksum compares archiveName to the raw second token in each SHA256SUMS line, so
common formats like "<sum>  *<filename>" won't match and installation fails with "checksum not
found". This makes Copilot installation fragile even when checksums are correct.
Code

pkg/cmd/copilot/copilot.go[R353-360]

+		fields := strings.Fields(line)
+		if len(fields) >= 2 {
+			checksum := fields[0]
+			filename := fields[1]
+			if filename == archiveName {
+				return checksum, nil
+			}
+		}
Evidence
The code takes the second whitespace-delimited token as the filename and requires exact equality
with archiveName; any leading marker characters (like '*') remain in the token and will prevent a
match.

pkg/cmd/copilot/copilot.go[347-360]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`fetchExpectedChecksum` parses SHA256SUMS lines using `strings.Fields` and compares `fields[1]` directly to `archiveName`. If the checksum file uses a common convention like `*filename` (binary-mode marker), the comparison fails and the installer errors out with "checksum not found".

## Issue Context
Copilot installation depends on this lookup to proceed. A mismatch here prevents installation even though the downloaded archive checksum may be correct.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[347-366]

## Implementation notes
- Normalize the parsed filename before comparing, e.g.:
 - `filename = strings.TrimPrefix(filename, "*")`
 - optionally also trim surrounding whitespace (already handled) and handle potential leading `./` if needed.
- Keep returning the checksum string exactly as parsed (first field).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (4)
4. reg.Verify(t) missing in test 📘 Rule violation ☼ Reliability
Description
A test creates an httpmock.Registry and registers responders but never calls reg.Verify(t), so
unused stubs would not be detected. This can allow tests to pass without exercising expected HTTP
interactions.
Code

internal/featuredetection/feature_detection_test.go[R818-826]

+			reg := &httpmock.Registry{}
+			if tt.httpStubs != nil {
+				tt.httpStubs(reg)
+			}
+			httpClient := &http.Client{}
+			httpmock.ReplaceTripper(httpClient, reg)
+
+			detector := NewDetector(httpClient, tt.hostname)
+
Evidence
PR Compliance ID 5 requires tests using httpmock.Registry to include defer reg.Verify(t). In
TestActionsFeatures, the registry is created and used as the transport, but no verification is
deferred.

AGENTS.md: HTTP-Mocking Tests Must Verify All Stubs Are Called
internal/featuredetection/feature_detection_test.go[818-826]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A test uses `httpmock.Registry` without verifying that all registered stubs were called.

## Issue Context
The compliance checklist requires `defer reg.Verify(t)` for tests using `httpmock.Registry` to ensure responders are exercised.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[818-824]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Uses assert.NoError for errors 📘 Rule violation ☼ Reliability
Description
New tests use assert.NoError/assert.Error for error checks, which can allow the test to continue
in an invalid state after a failure. Error checks must use require to fail fast.
Code

internal/featuredetection/feature_detection_test.go[R645-650]

+			if tt.wantErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			assert.Equal(t, tt.wantFeatures, gotFeatures)
Evidence
PR Compliance ID 6 requires require (not assert) for error checks. The added code uses
assert.Error(t, err) and assert.NoError(t, err) when validating the result of
detector.ProjectFeatures().

AGENTS.md: Tests Must Use testify/require for Error Checks
internal/featuredetection/feature_detection_test.go[645-650]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Tests use `assert.*` for error checks instead of `require.*`, which should halt the test immediately when an error expectation fails.

## Issue Context
The repo’s test conventions require `require.NoError` / `require.Error` for error assertions.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[645-650]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Missing TODO above ProjectItemQuery 📘 Rule violation ⚙ Maintainability
Description
A new feature-detection conditional (if !features.ProjectItemQuery) was added without the required
immediately-preceding // TODO <cleanupIdentifier> comment. This violates the mandated pattern for
feature-detection fallbacks and may fail lint expectations.
Code

pkg/cmd/project/item-list/item_list.go[R116-117]

+		if !features.ProjectItemQuery {
+			return fmt.Errorf("the `--query` flag is not supported on this GitHub host")
Evidence
PR Compliance ID 11 requires a // TODO <cleanupIdentifier> line immediately above any if
branching on feature detection. The added if !features.ProjectItemQuery { ... } has no preceding
TODO marker.

AGENTS.md: Feature-Detection Conditionals Must Include a TODO Cleanup Identifier Comment
pkg/cmd/project/item-list/item_list.go[111-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A feature-detection `if` conditional was added without the required `// TODO <cleanupIdentifier>` comment directly above it.

## Issue Context
The code branches on host capabilities (`features.ProjectItemQuery`), which is tracked as a temporary fallback and must be marked for cleanup.

## Fix Focus Areas
- pkg/cmd/project/item-list/item_list.go[116-117]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. os.Exit bypasses telemetry flush 🐞 Bug ☼ Reliability
Description
runCopilot calls os.Exit on exec.ExitError, which skips deferred cleanup in internal/ghcmd
(including telemetryService.Flush and updateCancel). This can drop telemetry and bypass the standard
external-command exit-code propagation path.
Code

pkg/cmd/copilot/copilot.go[R179-184]

+	if err := runExternalCmdFunc(externalCmd); err != nil {
+		if exitErr, ok := err.(*exec.ExitError); ok {
+			// We terminate with os.Exit here, preserving the exit code from Copilot CLI,
+			// and also preventing stdio writes by callers up the stack.
+			os.Exit(exitErr.ExitCode())
+		}
Evidence
The Copilot command uses os.Exit on subprocess exit, which skips deferred telemetry flushing and
centralized exit-code handling in internal/ghcmd; internal/ghcmd explicitly relies on defers for
telemetry flushing and has a special-case error type for passing through external command exit
codes.

pkg/cmd/copilot/copilot.go[179-184]
internal/ghcmd/cmd.go[130-145]
internal/ghcmd/cmd.go[194-223]
pkg/cmd/root/extension.go[43-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`pkg/cmd/copilot/runCopilot` calls `os.Exit(exitErr.ExitCode())` when the Copilot subprocess exits non-zero. This exits the process immediately, skipping deferred cleanups in `internal/ghcmd` (notably `telemetryService.Flush()`), and bypassing the existing centralized exit-code propagation mechanism used for extensions/aliases.

## Issue Context
`internal/ghcmd/cmd.go` uses `defer telemetryService.Flush()` before executing the root command. Because `os.Exit` does not run defers, non-zero exits from Copilot will prevent telemetry from flushing.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[179-184]
- internal/ghcmd/cmd.go[130-145]
- internal/ghcmd/cmd.go[194-223]
- pkg/cmd/root/extension.go[43-50]

## Implementation notes
- Avoid `os.Exit` inside command code.
- Instead, return an error that carries an exit code and is handled centrally.
 - Option A (recommended): update `internal/ghcmd/cmd.go` to detect `interface{ ExitCode() int }` (or a shared cmdutil error type) and return `exitCode(...)` for it.
 - Option B: refactor/move the existing `root.ExternalCommandExitError` (or a new shared type) to a package that `copilot` can import without cycles, and use it here.
- Ensure the error path remains silent (no extra printing) while preserving Copilot’s exit code.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

8. Non-atomic tar extraction 🐞 Bug ⛨ Security
Description
extractTarGz writes files directly into installDir using os.O_TRUNC, so an error mid-copy can leave
a corrupted Copilot binary and it overwrites any existing file at that path. This can break
subsequent runs with "permission denied"/"exec format"/corruption-style failures after partial
installs.
Code

pkg/cmd/copilot/copilot.go[R449-456]

+	out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
+	if err != nil {
+		return fmt.Errorf("failed to create file: %w", err)
+	}
+	defer func() {
+		if cerr := out.Close(); err == nil && cerr != nil {
+			err = fmt.Errorf("failed to close file: %w", cerr)
+		}
Evidence
The installer extracts into the final install directory and the tar extraction opens destination
files with O_TRUNC, meaning existing files are truncated before a successful copy is guaranteed.

pkg/cmd/copilot/copilot.go[313-325]
pkg/cmd/copilot/copilot.go[404-440]
pkg/cmd/copilot/copilot.go[447-460]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The tar.gz extraction path writes directly to the final destination using `os.O_TRUNC`. This is non-atomic: if copying fails, the target is already truncated and left corrupted. It also follows any pre-existing filesystem object at that path (including symlinks), which is unsafe.

## Issue Context
This affects Copilot installation/updates on linux/darwin.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[404-445]
- pkg/cmd/copilot/copilot.go[447-462]
- pkg/cmd/copilot/copilot.go[313-325]

## Implementation notes
- Write each extracted file to a temp file within the same directory (e.g., `copilot.tmp-*`) using safe flags (consider `O_EXCL`) and then `os.Rename` to the final target.
- Consider validating that the target path is not a symlink before replacing.
- Optionally remove/clean the installDir before extraction (or extract into a new temp dir then swap) to keep installs consistent and rollback-safe.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread AGENTS.md Resolved
Comment on lines +116 to +117
if !features.ProjectItemQuery {
return fmt.Errorf("the `--query` flag is not supported on this GitHub host")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Missing todo above projectitemquery 📘 Rule violation ⚙ Maintainability

A new feature-detection conditional (if !features.ProjectItemQuery) was added without the required
immediately-preceding // TODO <cleanupIdentifier> comment. This violates the mandated pattern for
feature-detection fallbacks and may fail lint expectations.
Agent Prompt
## Issue description
A feature-detection `if` conditional was added without the required `// TODO <cleanupIdentifier>` comment directly above it.

## Issue Context
The code branches on host capabilities (`features.ProjectItemQuery`), which is tracked as a temporary fallback and must be marked for cleanup.

## Fix Focus Areas
- pkg/cmd/project/item-list/item_list.go[116-117]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +818 to +826
reg := &httpmock.Registry{}
if tt.httpStubs != nil {
tt.httpStubs(reg)
}
httpClient := &http.Client{}
httpmock.ReplaceTripper(httpClient, reg)

detector := NewDetector(httpClient, tt.hostname)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. reg.verify(t) missing in test 📘 Rule violation ☼ Reliability

A test creates an httpmock.Registry and registers responders but never calls reg.Verify(t), so
unused stubs would not be detected. This can allow tests to pass without exercising expected HTTP
interactions.
Agent Prompt
## Issue description
A test uses `httpmock.Registry` without verifying that all registered stubs were called.

## Issue Context
The compliance checklist requires `defer reg.Verify(t)` for tests using `httpmock.Registry` to ensure responders are exercised.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[818-824]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +645 to +650
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wantFeatures, gotFeatures)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Uses assert.noerror for errors 📘 Rule violation ☼ Reliability

New tests use assert.NoError/assert.Error for error checks, which can allow the test to continue
in an invalid state after a failure. Error checks must use require to fail fast.
Agent Prompt
## Issue description
Tests use `assert.*` for error checks instead of `require.*`, which should halt the test immediately when an error expectation fails.

## Issue Context
The repo’s test conventions require `require.NoError` / `require.Error` for error assertions.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[645-650]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread api/queries_pr_review.go
Comment on lines +97 to +101
type PullRequestReviewStatus struct {
ChangesRequested bool
Approved bool
ReviewRequired bool
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. pullrequestreviewstatus lacks godoc 📘 Rule violation ⚙ Maintainability

A new exported type was introduced without a preceding godoc comment, reducing API documentation
quality and potentially failing linting rules. Exported identifiers should have intent-focused
comments.
Agent Prompt
## Issue description
New exported identifiers were added without godoc comments.

## Issue Context
Go linting and project conventions require exported types/functions/constants to have doc comments that start with the identifier name.

## Fix Focus Areas
- api/queries_pr_review.go[97-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +179 to +184
if err := runExternalCmdFunc(externalCmd); err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
// We terminate with os.Exit here, preserving the exit code from Copilot CLI,
// and also preventing stdio writes by callers up the stack.
os.Exit(exitErr.ExitCode())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

6. Os.exit bypasses telemetry flush 🐞 Bug ☼ Reliability

runCopilot calls os.Exit on exec.ExitError, which skips deferred cleanup in internal/ghcmd
(including telemetryService.Flush and updateCancel). This can drop telemetry and bypass the standard
external-command exit-code propagation path.
Agent Prompt
## Issue description
`pkg/cmd/copilot/runCopilot` calls `os.Exit(exitErr.ExitCode())` when the Copilot subprocess exits non-zero. This exits the process immediately, skipping deferred cleanups in `internal/ghcmd` (notably `telemetryService.Flush()`), and bypassing the existing centralized exit-code propagation mechanism used for extensions/aliases.

## Issue Context
`internal/ghcmd/cmd.go` uses `defer telemetryService.Flush()` before executing the root command. Because `os.Exit` does not run defers, non-zero exits from Copilot will prevent telemetry from flushing.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[179-184]
- internal/ghcmd/cmd.go[130-145]
- internal/ghcmd/cmd.go[194-223]
- pkg/cmd/root/extension.go[43-50]

## Implementation notes
- Avoid `os.Exit` inside command code.
- Instead, return an error that carries an exit code and is handled centrally.
  - Option A (recommended): update `internal/ghcmd/cmd.go` to detect `interface{ ExitCode() int }` (or a shared cmdutil error type) and return `exitCode(...)` for it.
  - Option B: refactor/move the existing `root.ExternalCommandExitError` (or a new shared type) to a package that `copilot` can import without cycles, and use it here.
- Ensure the error path remains silent (no extra printing) while preserving Copilot’s exit code.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +353 to +360
fields := strings.Fields(line)
if len(fields) >= 2 {
checksum := fields[0]
filename := fields[1]
if filename == archiveName {
return checksum, nil
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

7. Checksum filename prefix mismatch 🐞 Bug ≡ Correctness

fetchExpectedChecksum compares archiveName to the raw second token in each SHA256SUMS line, so
common formats like "<sum>  *<filename>" won't match and installation fails with "checksum not
found". This makes Copilot installation fragile even when checksums are correct.
Agent Prompt
## Issue description
`fetchExpectedChecksum` parses SHA256SUMS lines using `strings.Fields` and compares `fields[1]` directly to `archiveName`. If the checksum file uses a common convention like `*filename` (binary-mode marker), the comparison fails and the installer errors out with "checksum not found".

## Issue Context
Copilot installation depends on this lookup to proceed. A mismatch here prevents installation even though the downloaded archive checksum may be correct.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[347-366]

## Implementation notes
- Normalize the parsed filename before comparing, e.g.:
  - `filename = strings.TrimPrefix(filename, "*")`
  - optionally also trim surrounding whitespace (already handled) and handle potential leading `./` if needed.
- Keep returning the checksum string exactly as parsed (first field).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
18 Security Hotspots
15.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

1 similar comment
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
18 Security Hotspots
15.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@HIHACK1911 HIHACK1911 self-assigned this Jun 20, 2026
babakks and others added 18 commits June 30, 2026 15:14
…er/goreleaser-action-7.2.3

chore(deps): bump goreleaser/goreleaser-action from 7.2.2 to 7.2.3
…ples

docs(search): add examples for multiple qualifiers
Introduce a dry_run input (default true) to the deployment workflow so
artifacts are built and signed but no GitHub Release is created and no
site is published. Rename DO_PUBLISH to DO_SIGN_ARTIFACTS for the
Windows signing path so signing remains driven solely by environment,
independent of publish gating, and set it on the MSI signing step.

Co-authored-by: Copilot <[email protected]>
Rework the macOS deployment signing to use App Store Connect API key
based notarization and a Developer ID certificate identifier.

- Use a single consistent keychain (build.keychain) for signing and
  notarization; the notarization credentials previously targeted a
  keychain that was never created.
- Gate the App Store Connect API key and notarization credential steps
  on the production environment so non-production builds (with empty
  secrets) no longer fail.

Co-authored-by: Copilot <[email protected]>
Convert the deployment workflow from reusable `workflow_call` to manual `workflow_dispatch`, removing the extra `repository` input and forwarded secret declarations. Drop per-job deploy app token generation and custom checkout token/repository overrides, relying on the default checkout context instead. Update release publishing to use `secrets.GITHUB_TOKEN` for GH CLI authentication.
Net-new draft agentic issue-triage labeller for cli/cli built with gh-aw.
On a newly opened issue (or manual workflow_dispatch) an agent reads the
issue and, only when confident, applies a small allowlist of existing
cli/cli labels and posts one short rationale comment via native
issue-intents safe outputs. Conservative starting point for discussion,
not a final triage configuration.

Inert until issue_intents is enabled for the org/repo and a repo admin sets
the GH_AW_RUNTIME_FEATURES=issue_intents repository variable.

Co-authored-by: Copilot App <[email protected]>
Rework the draft workflow to follow gh-cli-and-desktop triage-process.md:
the objective is to drive an issue toward removing needs-triage by landing
the minimal correct end-state labels, surfaced for maintainer approval via
issue-intents rationale and confidence rather than silent auto-apply.

- Prompt now follows the documented issues decision tree (closeable /
  duplicate / spam / abuse / off-topic / no-help-wanted-issue, then bug +
  priority or unable-to-reproduce, then enhancement or more-info-needed).
- add-labels allowlist switched to the real cli/cli triage taxonomy:
  bug, priority-1/2/3, enhancement, more-info-needed, unable-to-reproduce,
  off-topic, no-help-wanted-issue, invalid, suspected-spam, duplicate.
  needs-triage is intentionally excluded (the agent must not add it).
- max labels 3, add-comment max 1; engine copilot, strict:false,
  permissions contents:read + issues:read, github toolset [issues],
  triggers issues:opened + workflow_dispatch, timeout 10m, intents wiring
  unchanged.

Co-authored-by: Copilot App <[email protected]>
Helps debug 'no identity found' failures by printing the codesigning
identities available in the build keychain, so DEVELOPER_ID_CERT_IDENTIFIER
can be verified against the actual imported certificate.

Co-authored-by: Copilot <[email protected]>
Reflects the reworked macOS code-signing/notarization flow (dedicated
build.keychain, App Store Connect API key, notarytool keychain profile,
DEVELOPER_ID_CERT_IDENTIFIER/MAC_APP_SIGNING_IDENTITY), documents the new
dry_run input and its publishing gates, the ref input and per-job
timeouts, the Windows DO_SIGN_ARTIFACTS flag, and the GitHub App site
deploy token replacing SITE_DEPLOY_PAT.

Co-authored-by: Copilot <[email protected]>
The deployment workflow's dry_run input defaults to true so manual UI
dispatches are safe by default. script/release, however, is used to
initiate real releases, so it now passes -f dry_run=false and exposes an
opt-in --dry-run flag. Without this, releases triggered via script/release
silently became no-ops (no attestation, no GitHub Release, no site push).

Co-authored-by: Copilot <[email protected]>
williammartin and others added 22 commits August 5, 2026 16:30
The evidence rule told the agent that a dependency in the first
`require` block is direct. That is a `go mod tidy` formatting convention,
not the semantics. What actually marks a requirement indirect is the
trailing `// indirect` comment on its own line, and Go's parser reads it
that way regardless of block: put a commented and an uncommented require
in the same block and `go mod edit -json` still reports Indirect true and
false respectively.

The two agree in this repository today, so nothing was misclassified.
But the rule would break on a reorganised or hand-edited file, and
misreporting a direct dependency as indirect is precisely the error the
required-evidence section exists to prevent.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 190d246d-0b1f-4ce6-9aa6-dee10d3d4cf8
Adding a custom pre-agent `steps:` block made the compiler wrap it in a
DIFC proxy, because a guard policy is configured. That proxy applies
`min-integrity` but not `trusted-users`, which are resolved at runtime
after it starts. The pre-flight finds its dedup marker by reading back
its own `cli-triage[bot]` comments, and those are precisely what
`min-integrity: approved` filters out - the app posts with
author_association NONE, which is why `trusted-users` exists here at all.

So the marker was never found, every open Dependabot PR looked unassessed
on every run, and the workflow would have re-triaged and re-commented on
all of them hourly: the exact failure this design was written to prevent,
moved from the agent to a place with no model to notice it.

Turning the proxy off does not widen the injection surface. The pre-flight
hands nothing it reads to the model - it extracts PR numbers, head SHAs and
CI states - and it matches the marker only inside comments already narrowed
to the app's own login. That login check, not integrity, is what stops a
third party forging a marker. The agent still runs under the full policy
via the MCP gateway.

Verified against cli/cli: all seven open Dependabot PRs are correctly
recognised as already assessed at their current head, and a run with the
login filter pointed at a non-existent bot correctly reports them as
needing assessment.

Three smaller corrections ride along, all fallout from the same review:

- Silence no-op issue reporting. gh-aw posts a comment to a shared "no-op
  runs" issue on every noop, and noop is now the routine idle outcome of
  an hourly reconciler, so that would have been roughly 24 comments a day
  forever. The run log already records why a run did nothing.
- Drop CI state from the required-evidence count. The pre-flight now
  guarantees terminal CI, so the agent never gathers it and it could never
  be the missing item that caps confidence. Counting it made the gate for
  High confidence four items dressed up as five.
- Log which PRs the terminal-CI gate excluded. A check that never reports
  would otherwise keep a PR out of triage permanently and silently.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 18bc01f9-9498-4bd8-9fd0-70308491b695
`statusCheckRollup` contexts are CheckRun and StatusContext objects, which
sit behind the `checks` and `statuses` scopes. The workflow token had
neither, so the field would have come back unreadable at runtime even
though it reads fine with a developer token, which is what I tested with.

The dangerous part was not the missing permission but how the gate reacted
to it. `[.statusCheckRollup[]? | select(pending)] | length == 0` cannot
tell "this PR has no checks" from "I could not read this PR's checks", so
an unreadable rollup counted as terminal CI and the PR would have been
assessed while its CI was still running. Silently wrong beats loudly
broken only from the outside.

So the classification now treats a null rollup as pending and names it in
the skip log, and the permissions are granted. The gate fails safe if
either is ever dropped again.

Also warn when the listing hits the 100-PR cap. gh truncates silently and
the ordering is stable, so PRs past the cap would never be reached on a
later run either. Paginating for a case that far outside anything this
repository has seen, and well above the 20-comment safe-output cap, is not
worth the extra requests, but the condition should not be invisible.

Reported by Copilot review on #14079.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 18bc01f9-9498-4bd8-9fd0-70308491b695
Make Dependabot triage cheaper and more decisive
…igstore/sigstore-go-1.3.0

chore(deps): bump github.com/sigstore/sigstore-go from 1.2.2 to 1.3.0
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.21.7 to 0.21.8.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Commits](google/go-containerregistry@v0.21.7...v0.21.8)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-version: 0.21.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.82.1 to 1.83.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](grpc/grpc-go@v1.82.1...v1.83.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.83.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
…ctions-432e0d4de6

chore(deps): bump the codeql-actions group across 1 directory with 3 updates
…g.org/grpc-1.83.0

chore(deps): bump google.golang.org/grpc from 1.82.1 to 1.83.0
…oogle/go-containerregistry-0.21.8

chore(deps): bump github.com/google/go-containerregistry from 0.21.7 to 0.21.8
Co-authored-by: Copilot App <[email protected]>
Copilot-Session: cd6661ad-7e77-46d0-b0e7-0a296f4e252b
Co-authored-by: Copilot App <[email protected]>
Copilot-Session: 18bc01f9-9498-4bd8-9fd0-70308491b695
Copilot-Session: e00d0ec3-c3d6-4ee7-9100-a7f294fe2402
…attest-4.2.1

chore(deps): bump actions/attest from 4.2.0 to 4.2.1
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Copilot-Session: 7db06537-cb57-48b9-b09c-e0ea393c3734
Copilot-Session: 6dba8ad8-2a85-4cda-a057-cf91b58a158e
Co-authored-by: Copilot App <[email protected]>
Copilot-Session: db48c8cb-9607-4607-8000-121b01833106
Agents were filling "How did you test this change?" with unit test
output, which duplicates CI and tells reviewers nothing about whether
the change actually works for a user. Spell out the acceptable forms
instead: screenshots/GIFs, Given/When/Then, or a plain walkthrough.

Co-authored-by: Copilot App <[email protected]>
Copilot-Session: af0c0477-c30c-4c0f-b198-42ce0cd450f3
Co-authored-by: Copilot App <[email protected]>
Copilot-Session: db48c8cb-9607-4607-8000-121b01833106
Clarify what belongs in the PR template's testing section
@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
15.1% Duplication on New Code (required ≤ 3%)
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@HIHACK1911
HIHACK1911 marked this pull request as ready for review August 8, 2026 23:00
@HIHACK1911
HIHACK1911 merged commit f353a94 into HIHACK1911:trunk Aug 8, 2026
0 of 3 checks passed
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add gh skill suite, SafeURL/content sanitization, agent detection, and CI/release hardening

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Adds a new gh skill/gh skills command suite to install/manage agent skills across supported
 agents.
• Introduces SafeURL + ContentOut/Untrusted primitives to prevent URL-path traversal and ANSI
 injection; updates key commands to use them.
• Adds agent detection and telemetry plumbing (including UA Agent/), plus new root-wired commands
 and help topics.
• Adds CodeQL queries/tests to enforce the new security patterns.
• Hardens deployment workflow (dry-run gating, macOS signing/notarization fixes, pinned actions) and
 bumps Go/toolchain/dependencies; updates docs and acceptance fixtures.
Diagram

graph TD
  CLIRoot["gh root cmd"] --> SkillsCmd["gh skill suite"] --> Registry["skills registry"]
  CLIRoot --> Cmds["commands"] --> SafeURL["safeurl"]
  Cmds --> IO["IOStreams"] --> ContentOut["ContentOut"] --> Sanitizer[(ANSI sanitize)]
  Cmds --> ApiHTTP["api/http client"] --> GH["GitHub API"]
  AgentDetect["agents.Detect"] --> ApiHTTP
  CodeQL["CodeQL queries"] -.enforce.-> SafeURL
  CodeQL -.enforce.-> ContentOut
  DeployWF["deployment workflow"] --> GH
  subgraph Legend
    direction LR
    _m([Module]) ~~~ _db[(Sanitizer)] ~~~ _ext{{External}}
  end
Loading
High-Level Assessment

The approach is appropriate for a large codebase: introduce small, composable safety primitives (SafeURL, ContentOut/Untrusted) and backstop adoption with CodeQL so migrations are incremental and regressions are caught. Runtime-only sanitization or ad-hoc escaping at call sites would be harder to audit and maintain long-term.

Files changed (22) +3445 / -264

Enhancement (11) +1592 / -25
skills.goAdd top-level 'gh skill' command +62/-0

Add top-level 'gh skill' command

• Introduces 'NewCmdSkills' with 'skill'/'skills' aliases and subcommands (install, list, preview, publish, search, update) and enables full telemetry sampling for the command group.

pkg/cmd/skills/skills.go

registry.goAdd skills registry for supported agent hosts +460/-0

Add skills registry for supported agent hosts

• Defines 'AgentHost' and 'Scope' plus a curated list of supported agents (Copilot, Claude Code, Cursor, Codex, Gemini, Antigravity variants, etc.) and their project/user install directories.

internal/skills/registry/registry.go

safeurl.goIntroduce SafeURL helpers for REST URL building +164/-0

Introduce SafeURL helpers for REST URL building

• Adds a sealed 'SafeURL' interface with 'MutableSafeURL' (percent-encodes components and rejects '..') and 'ImmutableSafeURL' for trusted prebuilt URLs; includes strict 'RepoPartsFromNWO' parsing.

internal/safeurl/safeurl.go

untrusted.goAdd 'Untrusted' wrapper for safe string printing +95/-0

Add 'Untrusted' wrapper for safe string printing

• Introduces 'Untrusted' with a sanitizing 'String()' (fmt-safe) and explicit raw accessors ('Raw', 'RawBytes') plus JSON marshal/unmarshal support to preserve provenance through decoding.

pkg/iostreams/untrusted.go

content.goAdd helpers to guard terminal output of external content +92/-0

Add helpers to guard terminal output of external content

• Adds 'ContainsEscapeSequence', 'BinaryContentType', and 'CopyGuardedContent' which refuses binary-to-terminal output and blocks ANSI escapes before writing.

pkg/iostreams/content.go

iostreams.goAdd 'ContentOut' and content sanitization toggles +56/-11

Add 'ContentOut' and content sanitization toggles

• Extends 'IOStreams' with 'ContentOut' and 'SetContentSanitization', wiring a sanitizing transform by default and reinitializing it when pager starts.

pkg/iostreams/iostreams.go

detect.goAdd environment-based agent detection +181/-0

Add environment-based agent detection

• Implements 'agents.Detect' to infer the invoking AI agent (e.g., Amp, Codex, Gemini CLI, Claude Code, Cursor, etc.) with validation safe for header usage.

internal/agents/detect.go

http_client.goEnhance HTTP client UA and add external-client constructor +74/-2

Enhance HTTP client UA and add external-client constructor

• Adds optional 'InvokingAgent' UA suffix and API version header, plus a 'TelemetryDisabler' transport for enterprise hosts and a 'NewExternalHTTPClient' without GitHub-specific headers/tokens.

api/http_client.go

read_file.goAdd 'gh repo read-file' preview command +304/-0

Add 'gh repo read-file' preview command

• Implements reading repository file contents via the Contents API with '--ref', '--output/--clobber', JSON field export, pager behavior in TTY, and escape-sequence guarding unless explicitly allowed.

pkg/cmd/repo/read-file/read_file.go

run.goUse SafeURL and surface created workflow run details +67/-9

Use SafeURL and surface created workflow run details

• Builds workflow dispatch URL via 'safeurl.JoinPath', optionally requests run details when supported, and prints the run URL / suggests 'gh run view' when an ID is returned.

pkg/cmd/workflow/run/run.go

root.goWire new commands and telemetry into root command +37/-3

Wire new commands and telemetry into root command

• Updates root command creation to accept a telemetry recorder, registers new commands (skills, copilot, discussion, licenses, send-telemetry), avoids extension name conflicts, registers official extension stubs, and enables telemetry recording for subcommands.

pkg/cmd/root/root.go

Bug fix (2) +46 / -22
client.goAdd GitHub API version header and unify REST error handling +4/-7

Add GitHub API version header and unify REST error handling

• Introduces 'X-GitHub-Api-Version: 2022-11-28' and routes RESTWithNext failures through centralized response handling.

api/client.go

api.goHarden 'gh api' output against binary/ANSI injection +42/-15

Harden 'gh api' output against binary/ANSI injection

• Adds '--allow-escape-sequences' and routes raw non-JSON bodies through 'CopyGuardedContent' and 'ContentOut'; refactors JSON content-type detection and passes invoking agent into HTTP client options.

pkg/cmd/api/api.go

Documentation (2) +34 / -1
help_topic.goExpand environment/telemetry documentation in help topics +19/-0

Expand environment/telemetry documentation in help topics

• Documents 'GH_EXTENSION', 'GH_TELEMETRY', and 'DO_NOT_TRACK', and adds a new 'telemetry' help topic linking to CLI telemetry docs.

pkg/cmd/root/help_topic.go

README.mdDocument agent skills and immutable releases +15/-1

Document agent skills and immutable releases

• Adds an Agent skills section with 'gh skill install/update' examples and notes about immutable releases in the verification section.

README.md

Other (7) +1773 / -216
safeurl_test.goAdd SafeURL unit tests +317/-0

Add SafeURL unit tests

• Covers NWO parsing validation, traversal rejection, encoding behavior, and host-prefix/query rendering edge cases.

internal/safeurl/safeurl_test.go

content_test.goTest guarded-content helpers +152/-0

Test guarded-content helpers

• Validates binary detection, escape detection, refusal semantics (no partial writes), and behavior across TTY/non-TTY and read-error scenarios.

pkg/iostreams/content_test.go

read_file_test.goAdd 'repo read-file' tests +759/-0

Add 'repo read-file' tests

• Adds extensive tests for flag parsing, JSON output, URL escaping of path/ref, API error propagation, paging behavior, and safe output-path handling.

pkg/cmd/repo/read-file/read_file_test.go

unsanitized-response-to-terminal.qlAdd CodeQL query for unsafe terminal output from HTTP responses +239/-0

Add CodeQL query for unsafe terminal output from HTTP responses

• Adds a taint-tracking query that flags HTTP response bytes reaching terminal writers without 'ContentOut' or sanitizer barriers, including cross-function flows and base64 decode sources.

.github/codeql/queries/unsanitized-response-to-terminal.ql

SafeURLPathConstruction.qlAdd CodeQL query requiring SafeURL for HTTP URL arguments +73/-0

Add CodeQL query requiring SafeURL for HTTP URL arguments

• Flags HTTP requests (including 'api.Client.REST*' and 'net/http' entrypoints) whose URL argument is not directly produced by 'safeurl.SafeURL.String()'.

.github/codeql/queries/SafeURLPathConstruction.ql

deployment.ymlAdd dry-run gating and fix macOS signing/notarization flow +138/-69

Add dry-run gating and fix macOS signing/notarization flow

• Adds 'dry_run' input (default true), pins Actions by SHA, creates temporary git tags for version embedding, fixes macOS keychain usage and gates signing/notarization to production using App Store Connect API key notarization.

.github/workflows/deployment.yml

go.modBump Go toolchain and dependencies +95/-147

Bump Go toolchain and dependencies

• Updates to Go 1.26/toolchain 1.26.5, adds charm.land v2 UI deps, and bumps many libraries (oauth, containerregistry, sigstore, cobra, go-tuf, grpc, x/*, etc.).

go.mod

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (4) 📜 Skill insights (0)

Grey Divider


Action required

1. Symlink overwrite on extract 🐞 Bug ⛨ Security ⭐ New
Description
Copilot tarball extraction validates only lexical traversal via safepaths.Join but then writes files
with os.OpenFile(O_TRUNC), which follows any pre-existing symlink under the install directory and
can overwrite files outside it. Because downloadCopilot reuses an existing installDir (MkdirAll
without cleanup), a local attacker who can plant symlinks in that directory can redirect writes
during gh copilot install.
Code

pkg/cmd/copilot/copilot.go[R454-456]

+func extractFile(target string, mode os.FileMode, r io.Reader) (err error) {
+	out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
+	if err != nil {
Evidence
The tar extraction computes a destination path using safepaths.Join (lexical traversal-only) and
then writes using OpenFile with O_TRUNC, which follows existing symlinks. safepaths.Join explicitly
does not handle symlinks, and installation extracts into an existing directory, making symlink
planting feasible.

pkg/cmd/copilot/copilot.go[319-330]
pkg/cmd/copilot/copilot.go[420-446]
pkg/cmd/copilot/copilot.go[453-467]
internal/safepaths/absolute.go[35-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Copilot tar.gz extraction prevents `../` traversal but does not defend against symlink traversal. Writing with `os.OpenFile(..., O_TRUNC, ...)` can follow a pre-existing symlink and overwrite arbitrary files outside the install directory.

### Issue Context
`safepaths.Absolute.Join` explicitly does not handle symlinks, and `downloadCopilot` extracts into an existing directory without first removing/atomically replacing it.

### Fix Focus Areas
- pkg/cmd/copilot/copilot.go[319-330]
- pkg/cmd/copilot/copilot.go[413-468]
- internal/safepaths/absolute.go[35-57]

### Implementation guidance
- Extract into a new empty temp directory under `config.DataDir()` and atomically `Rename` into place (after removing/renaming any prior install dir), OR delete `installDir` before extraction.
- Additionally, harden file creation:
 - On Unix, consider `O_NOFOLLOW` (via `unix.Open`) for the final path component.
 - Reject symlinks in any path component (walk parents with `Lstat`), or write only into a directory tree that you just created.
- Consider using `O_EXCL` semantics when possible to avoid clobbering existing filesystem objects.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Em dashes added in docs ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
New content introduces em dashes (—) in multiple files, which is explicitly forbidden and can
break search/formatting conventions. These must be replaced with regular hyphens (-) or rewritten
phrasing.
Code

AGENTS.md[8]

+make                                       # Build (Unix) — outputs bin/gh
Evidence
PR Compliance ID 9 forbids using em dashes anywhere. The diff adds — in newly introduced lines
across documentation, workflow YAML, acceptance testdata, and Go comments.

AGENTS.md: Do Not Use Em Dashes in Code, Comments, or Documentation
AGENTS.md[8-8]
internal/agents/detect.go[49-49]
.github/workflows/triage-pull-requests.yml[6-6]
acceptance/testdata/skills/skills-install-force.txtar[5-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Em dashes (`—`) were added in repository content, which violates the repo typography rule.

## Issue Context
The compliance checklist forbids any em dash characters in code, comments, or documentation; use `-` or rewrite the sentence.

## Fix Focus Areas
- AGENTS.md[8-8]
- internal/agents/detect.go[49-49]
- .github/workflows/triage-pull-requests.yml[6-6]
- acceptance/testdata/skills/skills-install-force.txtar[5-5]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. PullRequestReviewStatus lacks godoc 📘 Rule violation ⚙ Maintainability
Description
A new exported type was introduced without a preceding godoc comment, reducing API documentation
quality and potentially failing linting rules. Exported identifiers should have intent-focused
comments.
Code

api/queries_pr_review.go[R97-101]

+type PullRequestReviewStatus struct {
+	ChangesRequested bool
+	Approved         bool
+	ReviewRequired   bool
+}
Evidence
PR Compliance ID 8 requires godoc comments for exported identifiers. The diff adds the exported type
PullRequestReviewStatus without any doc comment immediately above its declaration.

AGENTS.md: Exported Identifiers Must Have Godoc Comments; Avoid Redundant Comments
api/queries_pr_review.go[96-104]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New exported identifiers were added without godoc comments.

## Issue Context
Go linting and project conventions require exported types/functions/constants to have doc comments that start with the identifier name.

## Fix Focus Areas
- api/queries_pr_review.go[97-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (5)
4. Checksum filename prefix mismatch 🐞 Bug ≡ Correctness
Description
fetchExpectedChecksum compares archiveName to the raw second token in each SHA256SUMS line, so
common formats like "<sum>  *<filename>" won't match and installation fails with "checksum not
found". This makes Copilot installation fragile even when checksums are correct.
Code

pkg/cmd/copilot/copilot.go[R353-360]

+		fields := strings.Fields(line)
+		if len(fields) >= 2 {
+			checksum := fields[0]
+			filename := fields[1]
+			if filename == archiveName {
+				return checksum, nil
+			}
+		}
Evidence
The code takes the second whitespace-delimited token as the filename and requires exact equality
with archiveName; any leading marker characters (like '*') remain in the token and will prevent a
match.

pkg/cmd/copilot/copilot.go[347-360]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`fetchExpectedChecksum` parses SHA256SUMS lines using `strings.Fields` and compares `fields[1]` directly to `archiveName`. If the checksum file uses a common convention like `*filename` (binary-mode marker), the comparison fails and the installer errors out with "checksum not found".

## Issue Context
Copilot installation depends on this lookup to proceed. A mismatch here prevents installation even though the downloaded archive checksum may be correct.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[347-366]

## Implementation notes
- Normalize the parsed filename before comparing, e.g.:
 - `filename = strings.TrimPrefix(filename, "*")`
 - optionally also trim surrounding whitespace (already handled) and handle potential leading `./` if needed.
- Keep returning the checksum string exactly as parsed (first field).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. reg.Verify(t) missing in test 📘 Rule violation ☼ Reliability
Description
A test creates an httpmock.Registry and registers responders but never calls reg.Verify(t), so
unused stubs would not be detected. This can allow tests to pass without exercising expected HTTP
interactions.
Code

internal/featuredetection/feature_detection_test.go[R818-826]

+			reg := &httpmock.Registry{}
+			if tt.httpStubs != nil {
+				tt.httpStubs(reg)
+			}
+			httpClient := &http.Client{}
+			httpmock.ReplaceTripper(httpClient, reg)
+
+			detector := NewDetector(httpClient, tt.hostname)
+
Evidence
PR Compliance ID 5 requires tests using httpmock.Registry to include defer reg.Verify(t). In
TestActionsFeatures, the registry is created and used as the transport, but no verification is
deferred.

AGENTS.md: HTTP-Mocking Tests Must Verify All Stubs Are Called
internal/featuredetection/feature_detection_test.go[818-826]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A test uses `httpmock.Registry` without verifying that all registered stubs were called.

## Issue Context
The compliance checklist requires `defer reg.Verify(t)` for tests using `httpmock.Registry` to ensure responders are exercised.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[818-824]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Uses assert.NoError for errors 📘 Rule violation ☼ Reliability
Description
New tests use assert.NoError/assert.Error for error checks, which can allow the test to continue
in an invalid state after a failure. Error checks must use require to fail fast.
Code

internal/featuredetection/feature_detection_test.go[R645-650]

+			if tt.wantErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			assert.Equal(t, tt.wantFeatures, gotFeatures)
Evidence
PR Compliance ID 6 requires require (not assert) for error checks. The added code uses
assert.Error(t, err) and assert.NoError(t, err) when validating the result of
detector.ProjectFeatures().

AGENTS.md: Tests Must Use testify/require for Error Checks
internal/featuredetection/feature_detection_test.go[645-650]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Tests use `assert.*` for error checks instead of `require.*`, which should halt the test immediately when an error expectation fails.

## Issue Context
The repo’s test conventions require `require.NoError` / `require.Error` for error assertions.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[645-650]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Missing TODO above ProjectItemQuery 📘 Rule violation ⚙ Maintainability
Description
A new feature-detection conditional (if !features.ProjectItemQuery) was added without the required
immediately-preceding // TODO <cleanupIdentifier> comment. This violates the mandated pattern for
feature-detection fallbacks and may fail lint expectations.
Code

pkg/cmd/project/item-list/item_list.go[R116-117]

+		if !features.ProjectItemQuery {
+			return fmt.Errorf("the `--query` flag is not supported on this GitHub host")
Evidence
PR Compliance ID 11 requires a // TODO <cleanupIdentifier> line immediately above any if
branching on feature detection. The added if !features.ProjectItemQuery { ... } has no preceding
TODO marker.

AGENTS.md: Feature-Detection Conditionals Must Include a TODO Cleanup Identifier Comment
pkg/cmd/project/item-list/item_list.go[111-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A feature-detection `if` conditional was added without the required `// TODO <cleanupIdentifier>` comment directly above it.

## Issue Context
The code branches on host capabilities (`features.ProjectItemQuery`), which is tracked as a temporary fallback and must be marked for cleanup.

## Fix Focus Areas
- pkg/cmd/project/item-list/item_list.go[116-117]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. os.Exit bypasses telemetry flush 🐞 Bug ☼ Reliability
Description
runCopilot calls os.Exit on exec.ExitError, which skips deferred cleanup in internal/ghcmd
(including telemetryService.Flush and updateCancel). This can drop telemetry and bypass the standard
external-command exit-code propagation path.
Code

pkg/cmd/copilot/copilot.go[R179-184]

+	if err := runExternalCmdFunc(externalCmd); err != nil {
+		if exitErr, ok := err.(*exec.ExitError); ok {
+			// We terminate with os.Exit here, preserving the exit code from Copilot CLI,
+			// and also preventing stdio writes by callers up the stack.
+			os.Exit(exitErr.ExitCode())
+		}
Evidence
The Copilot command uses os.Exit on subprocess exit, which skips deferred telemetry flushing and
centralized exit-code handling in internal/ghcmd; internal/ghcmd explicitly relies on defers for
telemetry flushing and has a special-case error type for passing through external command exit
codes.

pkg/cmd/copilot/copilot.go[179-184]
internal/ghcmd/cmd.go[130-145]
internal/ghcmd/cmd.go[194-223]
pkg/cmd/root/extension.go[43-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`pkg/cmd/copilot/runCopilot` calls `os.Exit(exitErr.ExitCode())` when the Copilot subprocess exits non-zero. This exits the process immediately, skipping deferred cleanups in `internal/ghcmd` (notably `telemetryService.Flush()`), and bypassing the existing centralized exit-code propagation mechanism used for extensions/aliases.

## Issue Context
`internal/ghcmd/cmd.go` uses `defer telemetryService.Flush()` before executing the root command. Because `os.Exit` does not run defers, non-zero exits from Copilot will prevent telemetry from flushing.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[179-184]
- internal/ghcmd/cmd.go[130-145]
- internal/ghcmd/cmd.go[194-223]
- pkg/cmd/root/extension.go[43-50]

## Implementation notes
- Avoid `os.Exit` inside command code.
- Instead, return an error that carries an exit code and is handled centrally.
 - Option A (recommended): update `internal/ghcmd/cmd.go` to detect `interface{ ExitCode() int }` (or a shared cmdutil error type) and return `exitCode(...)` for it.
 - Option B: refactor/move the existing `root.ExternalCommandExitError` (or a new shared type) to a package that `copilot` can import without cycles, and use it here.
- Ensure the error path remains silent (no extra printing) while preserving Copilot’s exit code.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

9. Accessible prompter ignored 🐞 Bug ≡ Correctness ⭐ New
Description
internal/prompter.New prioritizes ExperimentalPrompterEnabled over AccessiblePrompterEnabled, so
when both GH_EXPERIMENTAL_PROMPTER and GH_ACCESSIBLE_PROMPTER are enabled the non-accessible
huhPrompter is selected and accessibility mode is silently bypassed. This PR also wires both env
vars independently, making the conflict reachable.
Code

internal/prompter/prompter.go[R56-59]

+	if io.ExperimentalPrompterEnabled() {
+		return &huhPrompter{
+			stdin:     io.In,
+			stdout:    io.Out,
Evidence
newIOStreams enables both flags independently from env/config; prompter.New checks experimental
first; and huhPrompter does not enable accessible mode while accessiblePrompter does, so choosing
huhPrompter breaks accessibility behavior in that configuration.

internal/ghcmd/cmd.go[360-374]
internal/prompter/prompter.go[55-72]
internal/prompter/huh_prompter.go[22-27]
internal/prompter/prompter.go[90-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
When both accessibility and experimental prompter flags are enabled, `prompter.New` returns `huhPrompter` first, bypassing `accessiblePrompter` and losing `WithAccessible(true)` behavior.

### Issue Context
This PR introduces `GH_EXPERIMENTAL_PROMPTER` wiring alongside `GH_ACCESSIBLE_PROMPTER`, but does not define precedence or prevent both from being enabled simultaneously.

### Fix Focus Areas
- internal/prompter/prompter.go[55-72]
- internal/ghcmd/cmd.go[360-374]
- internal/prompter/huh_prompter.go[22-27]

### Implementation guidance
Choose one of:
1) Give accessibility precedence:
- In `prompter.New`, check `io.AccessiblePrompterEnabled()` before `io.ExperimentalPrompterEnabled()`.

2) Enforce mutual exclusivity:
- In `newIOStreams` (or earlier), if both env vars/configs are enabled, either:
 - disable experimental automatically when accessible is enabled, or
 - emit a clear warning/error and pick a deterministic default.

(1) is safest for users relying on accessibility features.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Same-branch check bypass 🐞 Bug ≡ Correctness ⭐ New
Description
isSameRef treats any QualifiedHeadRef containing ':' as cross-repo and returns false, but
QualifiedHeadRef parsing allows <owner>:<branch> without validating that owner differs from the
base repo owner. As a result, --head <baseOwner>:<baseBranch> can bypass the new same-branch
prevention and proceed to an avoidable PR-creation failure later.
Code

pkg/cmd/pr/create/create.go[R173-176]

+func isSameRef(refs creationRefs) bool {
+	if strings.Contains(refs.QualifiedHeadRef(), ":") {
+		return false
+	}
Evidence
The new guard uses the presence of ':' as the only fork discriminator. But QualifiedHeadRef
explicitly supports and preserves the <owner>:<branch> format without validating that the owner
differs from the base repo, so a same-repo qualified ref can exist and will bypass the guard.

pkg/cmd/pr/create/create.go[170-178]
pkg/cmd/pr/shared/find_refs_resolution.go[46-66]
pkg/cmd/pr/shared/find_refs_resolution.go[68-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`isSameRef` assumes any `:` in the qualified head ref implies a fork, and therefore skips same-branch detection. However, qualified refs can legally include an owner even when referring to the same repository.

### Issue Context
`ParseQualifiedHeadRef` explicitly accepts both `<branch>` and `<owner>:<branch>` forms without checking repo relationships, and `QualifiedHeadRef.String()` preserves the owner prefix when present.

### Fix Focus Areas
- pkg/cmd/pr/create/create.go[170-178]
- pkg/cmd/pr/shared/find_refs_resolution.go[46-75]

### Implementation guidance
- Replace the `strings.Contains(..., ":")` heuristic with proper parsing:
 - Parse the qualified head ref into `(owner?, branch)`.
 - If branch != baseRef: return false.
 - If owner is absent: treat as same-repo and return true.
 - If owner is present: only treat as cross-repo when `owner != baseRepoOwner`; if `owner == baseRepoOwner`, treat it as same-repo and return true.
- (Optional) If you can access the resolved head repo, compare repositories instead of only owner strings.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Non-atomic tar extraction 🐞 Bug ⛨ Security
Description
extractTarGz writes files directly into installDir using os.O_TRUNC, so an error mid-copy can leave
a corrupted Copilot binary and it overwrites any existing file at that path. This can break
subsequent runs with "permission denied"/"exec format"/corruption-style failures after partial
installs.
Code

pkg/cmd/copilot/copilot.go[R449-456]

+	out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
+	if err != nil {
+		return fmt.Errorf("failed to create file: %w", err)
+	}
+	defer func() {
+		if cerr := out.Close(); err == nil && cerr != nil {
+			err = fmt.Errorf("failed to close file: %w", cerr)
+		}
Evidence
The installer extracts into the final install directory and the tar extraction opens destination
files with O_TRUNC, meaning existing files are truncated before a successful copy is guaranteed.

pkg/cmd/copilot/copilot.go[313-325]
pkg/cmd/copilot/copilot.go[404-440]
pkg/cmd/copilot/copilot.go[447-460]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The tar.gz extraction path writes directly to the final destination using `os.O_TRUNC`. This is non-atomic: if copying fails, the target is already truncated and left corrupted. It also follows any pre-existing filesystem object at that path (including symlinks), which is unsafe.

## Issue Context
This affects Copilot installation/updates on linux/darwin.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[404-445]
- pkg/cmd/copilot/copilot.go[447-462]
- pkg/cmd/copilot/copilot.go[313-325]

## Implementation notes
- Write each extracted file to a temp file within the same directory (e.g., `copilot.tmp-*`) using safe flags (consider `O_EXCL`) and then `os.Rename` to the final target.
- Consider validating that the target path is not a symlink before replacing.
- Optionally remove/clean the installDir before extraction (or extract into a new temp dir then swap) to keep installs consistent and rollback-safe.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Previous review results

Review updated until commit 9fc0f70 ⚖️ Balanced

Results up to commit f1c10e0


🐞 Bugs (3) 📘 Rule violations (4) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Missing TODO above ProjectItemQuery 📘 Rule violation ⚙ Maintainability
Description
A new feature-detection conditional (if !features.ProjectItemQuery) was added without the required
immediately-preceding // TODO <cleanupIdentifier> comment. This violates the mandated pattern for
feature-detection fallbacks and may fail lint expectations.
Code

pkg/cmd/project/item-list/item_list.go[R116-117]

+		if !features.ProjectItemQuery {
+			return fmt.Errorf("the `--query` flag is not supported on this GitHub host")
Evidence
PR Compliance ID 11 requires a // TODO <cleanupIdentifier> line immediately above any if
branching on feature detection. The added if !features.ProjectItemQuery { ... } has no preceding
TODO marker.

AGENTS.md: Feature-Detection Conditionals Must Include a TODO Cleanup Identifier Comment
pkg/cmd/project/item-list/item_list.go[111-118]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A feature-detection `if` conditional was added without the required `// TODO <cleanupIdentifier>` comment directly above it.

## Issue Context
The code branches on host capabilities (`features.ProjectItemQuery`), which is tracked as a temporary fallback and must be marked for cleanup.

## Fix Focus Areas
- pkg/cmd/project/item-list/item_list.go[116-117]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. reg.Verify(t) missing in test 📘 Rule violation ☼ Reliability
Description
A test creates an httpmock.Registry and registers responders but never calls reg.Verify(t), so
unused stubs would not be detected. This can allow tests to pass without exercising expected HTTP
interactions.
Code

internal/featuredetection/feature_detection_test.go[R818-826]

+			reg := &httpmock.Registry{}
+			if tt.httpStubs != nil {
+				tt.httpStubs(reg)
+			}
+			httpClient := &http.Client{}
+			httpmock.ReplaceTripper(httpClient, reg)
+
+			detector := NewDetector(httpClient, tt.hostname)
+
Evidence
PR Compliance ID 5 requires tests using httpmock.Registry to include defer reg.Verify(t). In
TestActionsFeatures, the registry is created and used as the transport, but no verification is
deferred.

AGENTS.md: HTTP-Mocking Tests Must Verify All Stubs Are Called
internal/featuredetection/feature_detection_test.go[818-826]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A test uses `httpmock.Registry` without verifying that all registered stubs were called.

## Issue Context
The compliance checklist requires `defer reg.Verify(t)` for tests using `httpmock.Registry` to ensure responders are exercised.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[818-824]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Uses assert.NoError for errors 📘 Rule violation ☼ Reliability
Description
New tests use assert.NoError/assert.Error for error checks, which can allow the test to continue
in an invalid state after a failure. Error checks must use require to fail fast.
Code

internal/featuredetection/feature_detection_test.go[R645-650]

+			if tt.wantErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			assert.Equal(t, tt.wantFeatures, gotFeatures)
Evidence
PR Compliance ID 6 requires require (not assert) for error checks. The added code uses
assert.Error(t, err) and assert.NoError(t, err) when validating the result of
detector.ProjectFeatures().

AGENTS.md: Tests Must Use testify/require for Error Checks
internal/featuredetection/feature_detection_test.go[645-650]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Tests use `assert.*` for error checks instead of `require.*`, which should halt the test immediately when an error expectation fails.

## Issue Context
The repo’s test conventions require `require.NoError` / `require.Error` for error assertions.

## Fix Focus Areas
- internal/featuredetection/feature_detection_test.go[645-650]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (4)
4. PullRequestReviewStatus lacks godoc 📘 Rule violation ⚙ Maintainability
Description
A new exported type was introduced without a preceding godoc comment, reducing API documentation
quality and potentially failing linting rules. Exported identifiers should have intent-focused
comments.
Code

api/queries_pr_review.go[R97-101]

+type PullRequestReviewStatus struct {
+	ChangesRequested bool
+	Approved         bool
+	ReviewRequired   bool
+}
Evidence
PR Compliance ID 8 requires godoc comments for exported identifiers. The diff adds the exported type
PullRequestReviewStatus without any doc comment immediately above its declaration.

AGENTS.md: Exported Identifiers Must Have Godoc Comments; Avoid Redundant Comments
api/queries_pr_review.go[96-104]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New exported identifiers were added without godoc comments.

## Issue Context
Go linting and project conventions require exported types/functions/constants to have doc comments that start with the identifier name.

## Fix Focus Areas
- api/queries_pr_review.go[97-114]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. os.Exit bypasses telemetry flush 🐞 Bug ☼ Reliability
Description
runCopilot calls os.Exit on exec.ExitError, which skips deferred cleanup in internal/ghcmd
(including telemetryService.Flush and updateCancel). This can drop telemetry and bypass the standard
external-command exit-code propagation path.
Code

pkg/cmd/copilot/copilot.go[R179-184]

+	if err := runExternalCmdFunc(externalCmd); err != nil {
+		if exitErr, ok := err.(*exec.ExitError); ok {
+			// We terminate with os.Exit here, preserving the exit code from Copilot CLI,
+			// and also preventing stdio writes by callers up the stack.
+			os.Exit(exitErr.ExitCode())
+		}
Evidence
The Copilot command uses os.Exit on subprocess exit, which skips deferred telemetry flushing and
centralized exit-code handling in internal/ghcmd; internal/ghcmd explicitly relies on defers for
telemetry flushing and has a special-case error type for passing through external command exit
codes.

pkg/cmd/copilot/copilot.go[179-184]
internal/ghcmd/cmd.go[130-145]
internal/ghcmd/cmd.go[194-223]
pkg/cmd/root/extension.go[43-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`pkg/cmd/copilot/runCopilot` calls `os.Exit(exitErr.ExitCode())` when the Copilot subprocess exits non-zero. This exits the process immediately, skipping deferred cleanups in `internal/ghcmd` (notably `telemetryService.Flush()`), and bypassing the existing centralized exit-code propagation mechanism used for extensions/aliases.

## Issue Context
`internal/ghcmd/cmd.go` uses `defer telemetryService.Flush()` before executing the root command. Because `os.Exit` does not run defers, non-zero exits from Copilot will prevent telemetry from flushing.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[179-184]
- internal/ghcmd/cmd.go[130-145]
- internal/ghcmd/cmd.go[194-223]
- pkg/cmd/root/extension.go[43-50]

## Implementation notes
- Avoid `os.Exit` inside command code.
- Instead, return an error that carries an exit code and is handled centrally.
 - Option A (recommended): update `internal/ghcmd/cmd.go` to detect `interface{ ExitCode() int }` (or a shared cmdutil error type) and return `exitCode(...)` for it.
 - Option B: refactor/move the existing `root.ExternalCommandExitError` (or a new shared type) to a package that `copilot` can import without cycles, and use it here.
- Ensure the error path remains silent (no extra printing) while preserving Copilot’s exit code.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Checksum filename prefix mismatch 🐞 Bug ≡ Correctness
Description
fetchExpectedChecksum compares archiveName to the raw second token in each SHA256SUMS line, so
common formats like "<sum>  *<filename>" won't match and installation fails with "checksum not
found". This makes Copilot installation fragile even when checksums are correct.
Code

pkg/cmd/copilot/copilot.go[R353-360]

+		fields := strings.Fields(line)
+		if len(fields) >= 2 {
+			checksum := fields[0]
+			filename := fields[1]
+			if filename == archiveName {
+				return checksum, nil
+			}
+		}
Evidence
The code takes the second whitespace-delimited token as the filename and requires exact equality
with archiveName; any leading marker characters (like '*') remain in the token and will prevent a
match.

pkg/cmd/copilot/copilot.go[347-360]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`fetchExpectedChecksum` parses SHA256SUMS lines using `strings.Fields` and compares `fields[1]` directly to `archiveName`. If the checksum file uses a common convention like `*filename` (binary-mode marker), the comparison fails and the installer errors out with "checksum not found".

## Issue Context
Copilot installation depends on this lookup to proceed. A mismatch here prevents installation even though the downloaded archive checksum may be correct.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[347-366]

## Implementation notes
- Normalize the parsed filename before comparing, e.g.:
 - `filename = strings.TrimPrefix(filename, "*")`
 - optionally also trim surrounding whitespace (already handled) and handle potential leading `./` if needed.
- Keep returning the checksum string exactly as parsed (first field).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Em dashes added in docs ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
New content introduces em dashes (—) in multiple files, which is explicitly forbidden and can
break search/formatting conventions. These must be replaced with regular hyphens (-) or rewritten
phrasing.
Code

AGENTS.md[8]

+make                                       # Build (Unix) — outputs bin/gh
Evidence
PR Compliance ID 9 forbids using em dashes anywhere. The diff adds — in newly introduced lines
across documentation, workflow YAML, acceptance testdata, and Go comments.

AGENTS.md: Do Not Use Em Dashes in Code, Comments, or Documentation
AGENTS.md[8-8]
internal/agents/detect.go[49-49]
.github/workflows/triage-pull-requests.yml[6-6]
acceptance/testdata/skills/skills-install-force.txtar[5-5]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Em dashes (`—`) were added in repository content, which violates the repo typography rule.

## Issue Context
The compliance checklist forbids any em dash characters in code, comments, or documentation; use `-` or rewrite the sentence.

## Fix Focus Areas
- AGENTS.md[8-8]
- internal/agents/detect.go[49-49]
- .github/workflows/triage-pull-requests.yml[6-6]
- acceptance/testdata/skills/skills-install-force.txtar[5-5]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
8. Non-atomic tar extraction 🐞 Bug ⛨ Security
Description
extractTarGz writes files directly into installDir using os.O_TRUNC, so an error mid-copy can leave
a corrupted Copilot binary and it overwrites any existing file at that path. This can break
subsequent runs with "permission denied"/"exec format"/corruption-style failures after partial
installs.
Code

pkg/cmd/copilot/copilot.go[R449-456]

+	out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
+	if err != nil {
+		return fmt.Errorf("failed to create file: %w", err)
+	}
+	defer func() {
+		if cerr := out.Close(); err == nil && cerr != nil {
+			err = fmt.Errorf("failed to close file: %w", cerr)
+		}
Evidence
The installer extracts into the final install directory and the tar extraction opens destination
files with O_TRUNC, meaning existing files are truncated before a successful copy is guaranteed.

pkg/cmd/copilot/copilot.go[313-325]
pkg/cmd/copilot/copilot.go[404-440]
pkg/cmd/copilot/copilot.go[447-460]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The tar.gz extraction path writes directly to the final destination using `os.O_TRUNC`. This is non-atomic: if copying fails, the target is already truncated and left corrupted. It also follows any pre-existing filesystem object at that path (including symlinks), which is unsafe.

## Issue Context
This affects Copilot installation/updates on linux/darwin.

## Fix Focus Areas
- pkg/cmd/copilot/copilot.go[404-445]
- pkg/cmd/copilot/copilot.go[447-462]
- pkg/cmd/copilot/copilot.go[313-325]

## Implementation notes
- Write each extracted file to a temp file within the same directory (e.g., `copilot.tmp-*`) using safe flags (consider `O_EXCL`) and then `os.Rename` to the final target.
- Consider validating that the target path is not a symlink before replacing.
- Optionally remove/clean the installDir before extraction (or extract into a new temp dir then swap) to keep installs consistent and rollback-safe.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment on lines +454 to +456
func extractFile(target string, mode os.FileMode, r io.Reader) (err error) {
out, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
if err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Symlink overwrite on extract 🐞 Bug ⛨ Security

Copilot tarball extraction validates only lexical traversal via safepaths.Join but then writes files
with os.OpenFile(O_TRUNC), which follows any pre-existing symlink under the install directory and
can overwrite files outside it. Because downloadCopilot reuses an existing installDir (MkdirAll
without cleanup), a local attacker who can plant symlinks in that directory can redirect writes
during gh copilot install.
Agent Prompt
### Issue description
Copilot tar.gz extraction prevents `../` traversal but does not defend against symlink traversal. Writing with `os.OpenFile(..., O_TRUNC, ...)` can follow a pre-existing symlink and overwrite arbitrary files outside the install directory.

### Issue Context
`safepaths.Absolute.Join` explicitly does not handle symlinks, and `downloadCopilot` extracts into an existing directory without first removing/atomically replacing it.

### Fix Focus Areas
- pkg/cmd/copilot/copilot.go[319-330]
- pkg/cmd/copilot/copilot.go[413-468]
- internal/safepaths/absolute.go[35-57]

### Implementation guidance
- Extract into a new empty temp directory under `config.DataDir()` and atomically `Rename` into place (after removing/renaming any prior install dir), OR delete `installDir` before extraction.
- Additionally, harden file creation:
  - On Unix, consider `O_NOFOLLOW` (via `unix.Open`) for the final path component.
  - Reject symlinks in any path component (walk parents with `Lstat`), or write only into a directory tree that you just created.
- Consider using `O_EXCL` semantics when possible to avoid clobbering existing filesystem objects.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +56 to +59
if io.ExperimentalPrompterEnabled() {
return &huhPrompter{
stdin: io.In,
stdout: io.Out,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. Accessible prompter ignored 🐞 Bug ≡ Correctness

internal/prompter.New prioritizes ExperimentalPrompterEnabled over AccessiblePrompterEnabled, so
when both GH_EXPERIMENTAL_PROMPTER and GH_ACCESSIBLE_PROMPTER are enabled the non-accessible
huhPrompter is selected and accessibility mode is silently bypassed. This PR also wires both env
vars independently, making the conflict reachable.
Agent Prompt
### Issue description
When both accessibility and experimental prompter flags are enabled, `prompter.New` returns `huhPrompter` first, bypassing `accessiblePrompter` and losing `WithAccessible(true)` behavior.

### Issue Context
This PR introduces `GH_EXPERIMENTAL_PROMPTER` wiring alongside `GH_ACCESSIBLE_PROMPTER`, but does not define precedence or prevent both from being enabled simultaneously.

### Fix Focus Areas
- internal/prompter/prompter.go[55-72]
- internal/ghcmd/cmd.go[360-374]
- internal/prompter/huh_prompter.go[22-27]

### Implementation guidance
Choose one of:
1) Give accessibility precedence:
- In `prompter.New`, check `io.AccessiblePrompterEnabled()` before `io.ExperimentalPrompterEnabled()`.

2) Enforce mutual exclusivity:
- In `newIOStreams` (or earlier), if both env vars/configs are enabled, either:
  - disable experimental automatically when accessible is enabled, or
  - emit a clear warning/error and pick a deterministic default.

(1) is safest for users relying on accessibility features.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +173 to +176
func isSameRef(refs creationRefs) bool {
if strings.Contains(refs.QualifiedHeadRef(), ":") {
return false
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Same-branch check bypass 🐞 Bug ≡ Correctness

isSameRef treats any QualifiedHeadRef containing ':' as cross-repo and returns false, but
QualifiedHeadRef parsing allows <owner>:<branch> without validating that owner differs from the
base repo owner. As a result, --head <baseOwner>:<baseBranch> can bypass the new same-branch
prevention and proceed to an avoidable PR-creation failure later.
Agent Prompt
### Issue description
`isSameRef` assumes any `:` in the qualified head ref implies a fork, and therefore skips same-branch detection. However, qualified refs can legally include an owner even when referring to the same repository.

### Issue Context
`ParseQualifiedHeadRef` explicitly accepts both `<branch>` and `<owner>:<branch>` forms without checking repo relationships, and `QualifiedHeadRef.String()` preserves the owner prefix when present.

### Fix Focus Areas
- pkg/cmd/pr/create/create.go[170-178]
- pkg/cmd/pr/shared/find_refs_resolution.go[46-75]

### Implementation guidance
- Replace the `strings.Contains(..., ":")` heuristic with proper parsing:
  - Parse the qualified head ref into `(owner?, branch)`.
  - If branch != baseRef: return false.
  - If owner is absent: treat as same-repo and return true.
  - If owner is present: only treat as cross-repo when `owner != baseRepoOwner`; if `owner == baseRepoOwner`, treat it as same-repo and return true.
- (Optional) If you can access the resolved head repo, compare repositories instead of only owner strings.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

This branch had an error being deployed

1 failed deployment
cli-automation — 9fc0f70e Deployed Aug 8, 2026 by HIHACK1911 via pr-auto #24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.