Skip to content

Improve Quick fix#1702

Open
5byuri wants to merge 27 commits intomainfrom
Improve-Quick-Fix
Open

Improve Quick fix#1702
5byuri wants to merge 27 commits intomainfrom
Improve-Quick-Fix

Conversation

@5byuri
Copy link
Member

@5byuri 5byuri commented Feb 13, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 13, 2026 15:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a prototype “quick fix” workflow under cmd/devguard-cli/test/ to fetch package metadata from registries (npm/crates) and attempt to validate whether updating a dependency chain results in a vulnerable package version being at/above a fixed version.

Changes:

  • Add npm registry response type definitions for JSON unmarshalling.
  • Add registry helper functions (npm/crates) and a quickfix CLI that walks a dependency chain.
  • Add semver parsing/recommendation logic to select newer versions within the same major band.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 13 comments.

File Description
cmd/devguard-cli/test/types.go Introduces structs for npm registry JSON responses.
cmd/devguard-cli/test/quickfix.go Implements the dependency-chain “quick fix” logic and a main() driver.
cmd/devguard-cli/test/package_manager_functions.go Adds registry request helpers for npm/crates and a version existence check.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +238 to +241
// Parse versions to compare
vulnParts := parseVersion(vulnVersion)
fixedParts := parseVersion(fixedVersion)

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

fixedVersion is parsed with parseVersion but never validated as semver. If it’s not in x.y.z form, parseVersion returns 0.0.0 and the comparison can incorrectly report a fix. Consider validating fixedVersion (similar to vulnVersion) and returning an error when invalid.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 13
// Copyright 2026 larshermges
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The file header uses an Apache-2.0 license block, but the repository (including other cmd/devguard-cli files) is AGPL-3.0. Mixing license headers like this is inconsistent and can create licensing/compliance issues; please align this file’s header with the project’s standard AGPL header.

Suggested change
// Copyright 2026 larshermges
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Copyright (C) 2026 larshermges
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,298 @@
// Copyright 2026 larshermges @ l3montree GmbH
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

This new file is missing the standard AGPL-3.0 license header used throughout the repo (it currently only has a copyright line). Please add the same AGPL header block as other Go files under cmd/devguard-cli to keep licensing consistent.

Suggested change
// Copyright 2026 larshermges @ l3montree GmbH
// Copyright 2026 larshermges @ l3montree GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,79 @@
// Copyright 2026 larshermges @ l3montree GmbH
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

This new file is missing the standard AGPL-3.0 license header used throughout the repo (it currently only has a copyright line). Please add the same AGPL header block as other Go files under cmd/devguard-cli to keep licensing consistent.

Suggested change
// Copyright 2026 larshermges @ l3montree GmbH
// This file is part of DevGuard.
// Copyright (C) 2026 larshermges @ l3montree GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

Copilot uses AI. Check for mistakes.
return vi[2] > vj[2]
})

fmt.Println(recommended)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

fmt.Println(recommended) looks like leftover debug output. This will produce noisy stdout for any consumer of the function; please remove it or gate it behind an explicit verbose/debug flag.

Suggested change
fmt.Println(recommended)

Copilot uses AI. Check for mistakes.
Comment on lines 15 to 17
func getPackageManager(Package string) string {
// insert future Package Managers later
switch Package {
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Parameter names in Go should be lowerCamelCase. getPackageManager(Package string) should use a lower-case name (e.g., pkgManager/pkg) to match Go conventions and the rest of this codebase.

Suggested change
func getPackageManager(Package string) string {
// insert future Package Managers later
switch Package {
func getPackageManager(pkg string) string {
// insert future Package Managers later
switch pkg {

Copilot uses AI. Check for mistakes.
Comment on lines 38 to 40
}
// add more in the future
return nil, nil
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

getVersion returns (nil, nil) for unsupported package managers. Callers like fetchPackageMetadata unconditionally dereference resp.Body, which will panic if an unsupported manager is passed (e.g., getPackageManager can return "python"). Return a non-nil error for unsupported managers and/or guard against a nil response in fetchPackageMetadata.

Suggested change
}
// add more in the future
return nil, nil
default:
// add more package managers in the future; for now, treat others as unsupported
return nil, fmt.Errorf("unsupported package manager: %s", packageManager)
}

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +74
if major == currentMajor {
if minor >= currentMinor {
if patch >= currentPatch {
recommended = append(recommended, versionStr)
}
}
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The version filtering logic is incorrect for semver ordering. For example, when minor > currentMinor, patch does not need to be >= currentPatch (1.5.0 should be considered newer than 1.4.9). This should compare full semver tuples and select versions strictly greater than the current version within the same major.

Suggested change
if major == currentMajor {
if minor >= currentMinor {
if patch >= currentPatch {
recommended = append(recommended, versionStr)
}
}
}
if major == currentMajor && (minor > currentMinor || (minor == currentMinor && patch > currentPatch)) {
recommended = append(recommended, versionStr)
}

Copilot uses AI. Check for mistakes.
Comment on lines 101 to 107
// single node in the dependency tree
type DependencyNode struct {
Name string
Version string
Dependencies map[string]*DependencyNode
}

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

DependencyNode is declared but never used. With golangci-lint’s unused linter enabled in this repo, this will likely fail CI; please remove it or use it as part of the implementation/tests.

Suggested change
// single node in the dependency tree
type DependencyNode struct {
Name string
Version string
Dependencies map[string]*DependencyNode
}

Copilot uses AI. Check for mistakes.
Comment on lines 169 to 175
func checkVulnerabilityFixChain(purls []string, fixedVersion string) (bool, error) {

packages := make([]struct {
name string
version string
}, len(purls))

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

checkVulnerabilityFixChain will panic on an empty purls slice because it later accesses packages[len(packages)-1]. Add an early validation for len(purls) > 0 (and possibly >= 2 if a chain is required) and return a clear error instead.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 13 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 127 to 131
purl = strings.TrimPrefix(purl, "pkg:npm/")
parts := strings.Split(purl, "@")
if len(parts) != 2 {
return "", "", fmt.Errorf("invalid purl format: %s", purl)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Splitting on "@" here breaks for valid npm scoped purls (they may contain an "@" for the scope) and for URL-escaped forms. The repo already uses github.com/package-url/packageurl-go; consider parsing with packageurl.FromString and extracting the .Version instead of manual string splitting.

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +35
if req.StatusCode != 200 {
return nil, fmt.Errorf("failed to fetch data for %s: %s", pkg.Dependency, req.Status)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

When req.StatusCode != 200, this returns an error without closing req.Body, which leaks connections and can exhaust the HTTP client's transport. Ensure the response body is closed on all non-nil responses before returning an error (both in the versioned and unversioned branches).

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +55
if req.StatusCode != 200 {
return nil, fmt.Errorf("failed to fetch data for %s: %s", pkg.Dependency, req.Status)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Same connection leak here: on non-200 responses, req.Body is not closed before returning the error. Close the body on all error paths to avoid leaking TCP connections/file descriptors.

Copilot uses AI. Check for mistakes.
var req *http.Response
var err error

normalizedVersion := strings.Trim(pkg.Version, "/") // remove quotes if present
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The comment says "remove quotes if present", but strings.Trim(pkg.Version, "/") removes slashes, not quotes. Either adjust the trimming to match the intended behavior (e.g., trim quotes/whitespace) or update the comment to avoid misleading future changes.

Suggested change
normalizedVersion := strings.Trim(pkg.Version, "/") // remove quotes if present
normalizedVersion := strings.Trim(pkg.Version, " \"'") // remove surrounding quotes/whitespace if present

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +27
if pkg.Version != "" {
req, err = http.Get("https://registry.npmjs.org/" + pkg.Dependency + "/" + normalizedVersion)
} else {
req, err = http.Get("https://registry.npmjs.org/" + pkg.Dependency)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

These registry calls use http.Get with the default client (no timeout). If a registry is slow/hangs, the CLI can block indefinitely. Consider using an http.Client with a reasonable timeout and/or context-aware requests.

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +88
if minor >= currentMinor {
if patch >= currentPatch {
recommended = append(recommended, versionStr)
}
}
}
}

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

This semver comparison is incorrect for candidates where minor > currentMinor: it still requires patch >= currentPatch, which will exclude valid upgrades like 1.3.0 when current is 1.2.9. Consider using a proper semver comparison (or lexicographic compare of major/minor/patch) to include any strictly newer version within the same major.

Suggested change
if minor >= currentMinor {
if patch >= currentPatch {
recommended = append(recommended, versionStr)
}
}
}
}
if minor > currentMinor || (minor == currentMinor && patch >= currentPatch) {
recommended = append(recommended, versionStr)
}
}
}
}

Copilot uses AI. Check for mistakes.
}

func normalizeVersion(version string) string {
return strings.Trim(version, "^~\"")
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

normalizeVersion only strips ^, ~, and quotes. Dependency specs commonly include ranges like >=1.2.3, <2, 1.2.x, or complex ranges, which will propagate into packages[i+1].version and later fail IsValidSemver, causing false negatives/errors. Consider using a semver range parser (or existing normalization utilities in the repo) instead of simple trimming.

Suggested change
return strings.Trim(version, "^~\"")
// Trim common decorators and surrounding whitespace first.
trimmed := strings.TrimSpace(strings.Trim(version, "^~\""))
// If it's already a valid semver, return as-is.
if IsValidSemver(trimmed) {
return trimmed
}
// Handle simple wildcard patterns like "1.2.x" or "1.2.*" by
// converting them to "1.2.0".
wildcardPattern := regexp.MustCompile(`^(\d+)\.(\d+)\.(x|\*)$`)
if matches := wildcardPattern.FindStringSubmatch(trimmed); matches != nil {
candidate := fmt.Sprintf("%s.%s.0", matches[1], matches[2])
if IsValidSemver(candidate) {
return candidate
}
}
// Extract the first concrete semver (e.g., from ">=1.2.3 <2" or "1.2.3 || 2.0.0").
semverPattern := regexp.MustCompile(`\d+\.\d+\.\d+`)
if match := semverPattern.FindString(trimmed); match != "" {
if IsValidSemver(match) {
return match
}
}
// Fallback: return the trimmed value (preserves previous behavior for
// cases we don't explicitly handle).
return trimmed

Copilot uses AI. Check for mistakes.
Comment on lines +258 to +266

body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("error reading response for %s@%s: %w", dep, version, err)
}

var npmResp NPMResponse
if err := json.Unmarshal(body, &npmResp); err != nil {
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

io.ReadAll(resp.Body) reads the full registry response into memory; npm metadata can be large for popular packages with many versions. Consider decoding via json.NewDecoder(resp.Body) (streaming) and defer resp.Body.Close() to reduce peak memory and improve robustness.

Suggested change
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("error reading response for %s@%s: %w", dep, version, err)
}
var npmResp NPMResponse
if err := json.Unmarshal(body, &npmResp); err != nil {
defer resp.Body.Close()
// Ensure the io import is used even if no other code in this file references it.
// This has no functional impact and avoids compilation issues due to an unused import.
_ = io.EOF
var npmResp NPMResponse
if err := json.NewDecoder(resp.Body).Decode(&npmResp); err != nil {

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,61 @@
// Copyright 2026 larshermges @ l3montree GmbH
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

This file header is inconsistent with the AGPL license header used across most of the Go codebase (e.g., cmd/devguard-cli/commands/root.go). If this file is meant to be committed as non-generated source, consider adding the standard license header for consistency and compliance.

Suggested change
// Copyright 2026 larshermges @ l3montree GmbH
// Copyright (C) 2026 l3montree GmbH
// SPDX-License-Identifier: AGPL-3.0-or-later

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +52
case "crates":
return GetCratesRegistry(pkg)
default:
return nil, fmt.Errorf("unsupported package manager: %s", packageManager)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

getPackageManager can return values like "python", but getVersion currently only supports "node" and "crates" and otherwise errors. Either implement the missing registry client(s) or keep getPackageManager aligned with the supported cases to avoid inconsistent behavior when new inputs are introduced.

Copilot uses AI. Check for mistakes.
@5byuri
Copy link
Member Author

5byuri commented Feb 13, 2026

	purls := []string{
		"pkg:npm/@sentry/nextjs@9.38.0",
		"pkg:npm/next@15.4.7",
	}

	// in component_fixed_version in database
	fixedVersion := "15.4.9"
image

This actually works and gives a recommended version to update @sentry/nextjs to @sentry/nextjs@9.47.1, at least with the simplification method, removing ^,>,~

image

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +81 to +84
if minor >= currentMinor {
if patch >= currentPatch {
recommended = append(recommended, versionStr)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The version filter is incorrect: when minor > currentMinor, a version like 1.3.0 will be excluded if currentPatch is higher (because patch >= currentPatch is still required). This can cause the algorithm to miss valid newer versions within the same major. Adjust the comparison to treat (minor > currentMinor) as automatically acceptable, and only compare patches when minor == currentMinor.

Suggested change
if minor >= currentMinor {
if patch >= currentPatch {
recommended = append(recommended, versionStr)
}
if minor > currentMinor || (minor == currentMinor && patch >= currentPatch) {
recommended = append(recommended, versionStr)

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +35
if req.StatusCode != 200 {
return nil, fmt.Errorf("failed to fetch data for %s: %s", pkg.Dependency, req.Status)
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

When StatusCode != 200, the response body is not closed before returning the error. This leaks connections (especially problematic in loops). Ensure the body is closed on all paths once the response is obtained.

Copilot uses AI. Check for mistakes.
Comment on lines +275 to +283

body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("error reading response for %s@%s: %w", dep, version, err)
}

var npmResp NPMResponse
if err := json.Unmarshal(body, &npmResp); err != nil {
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

fetchPackageMetadata reads the entire registry response into memory with io.ReadAll. NPM package metadata can be very large; this can cause unnecessary memory spikes. Prefer json.NewDecoder(resp.Body).Decode(&npmResp) (and keep defer resp.Body.Close()) to stream decode.

Suggested change
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, fmt.Errorf("error reading response for %s@%s: %w", dep, version, err)
}
var npmResp NPMResponse
if err := json.Unmarshal(body, &npmResp); err != nil {
defer resp.Body.Close()
var npmResp NPMResponse
if err := json.NewDecoder(resp.Body).Decode(&npmResp); err != nil {

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +56
if req.StatusCode != 200 {
return nil, fmt.Errorf("failed to fetch data for %s: %s", pkg.Dependency, req.Status)
}
return req, nil
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Same issue here: on non-200 responses, the response body is not closed before returning, which can leak connections. Close the body (or defer close after a successful http.Get).

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +120
func IsValidSemver(version string) bool {

pattern := `^\d+\.\d+\.\d+$`
matched, _ := regexp.MatchString(pattern, version)
return matched
}

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

regexp.MatchString recompiles the pattern on every call. Since this is used in loops, consider compiling the regex once (package-level var semverRe = regexp.MustCompile(...)) and using semverRe.MatchString(version).

Suggested change
func IsValidSemver(version string) bool {
pattern := `^\d+\.\d+\.\d+$`
matched, _ := regexp.MatchString(pattern, version)
return matched
}
var semverRe = regexp.MustCompile(`^\d+\.\d+\.\d+$`)
func IsValidSemver(version string) bool {
return semverRe.MatchString(version)
}

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,61 @@
// Copyright 2026 larshermges @ l3montree GmbH
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Possible typo in the copyright holder name: other files use "lars hermges" (with a space), but this header has "larshermges".

Suggested change
// Copyright 2026 larshermges @ l3montree GmbH
// Copyright 2026 lars hermges @ l3montree GmbH

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +80 to +84
type Dist struct {
Shasum string `json:"shasum"`
Tarball string `json:"tarball"`
Integrity string `json:"integrity"`
Signatures []Signatures `json:"signatures"`
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The element type for Dist.Signatures is named Signatures (plural), which makes usages read oddly ([]Signatures). Consider renaming the struct type to singular (e.g., Signature) while keeping the field plural for clearer Go naming.

Copilot uses AI. Check for mistakes.
}

fmt.Printf("Found newer version for %s: %s to %s\n", pkgName, currentVersion, latestVersion)

Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

checkVulnerabilityFixChain selects a latestVersion but never assigns it back to packages[i].version. This makes the reported fixing version incorrect (it can return the original top-level version even when an upgrade was required). Persist the selected upgrade version in the tracked package list (or return pkgName@latestVersion directly).

Suggested change
// update the tracked version for the current package to the selected latest version
packages[i].version = latestVersion

Copilot uses AI. Check for mistakes.
}

if isFixed {
fixingVersion := packages[0].name + "@" + packages[0].version
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

When isFixed is true, the function returns packages[0].name + "@" + packages[0].version, but packages[0].version is never updated to the chosen upgrade version. This can return an incorrect recommendation. Return the actual upgraded version you validated (e.g., the selected latestVersion).

Suggested change
fixingVersion := packages[0].name + "@" + packages[0].version
fixingVersion := packages[0].name + "@" + fixedVersion

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant