Skip to content

Conversation

@SirGFM
Copy link

@SirGFM SirGFM commented May 30, 2025

This PR adds to SCFW the ability to verify go packages:

$ scfw run go get gorm.io/gorm
go: downloading gorm.io/gorm v1.30.0
go: downloading github.com/jinzhu/now v1.1.5
go: downloading golang.org/x/text v0.20.0
go: downloading github.com/jinzhu/inflection v1.0.0
go: added github.com/jinzhu/inflection v1.0.0
go: added github.com/jinzhu/now v1.1.5
go: added golang.org/x/text v0.20.0
go: added gorm.io/gorm v1.30.0

$ scfw run go get github.com/gofiber/fiber/[email protected]
Package golang.org/x/[email protected]:
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * [Critical] https://osv.dev/vulnerability/GHSA-v778-237x-gjrc
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * [High] https://osv.dev/vulnerability/GHSA-hcg3-q754-cr77
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * [Medium] https://osv.dev/vulnerability/GHSA-45x7-px36-x8w8
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2024-3321
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2023-2402
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2025-3487
Package golang.org/x/[email protected]:
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * [Medium] https://osv.dev/vulnerability/GHSA-qxp5-gwg8-xv66
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * [Medium] https://osv.dev/vulnerability/GHSA-vvgc-356p-c3xw
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * [Medium] https://osv.dev/vulnerability/GHSA-4v7x-pqxf-cx7m
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2025-3503
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2025-3595
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2024-2687
  - An OSV.dev advisory exists for package golang.org/x/[email protected]:
      * https://osv.dev/vulnerability/GO-2024-3333
[?] Proceed with installation? (y/N): n

The installation request was aborted. No changes have been made.

Although go has some commands that explicitly install dependencies (e.g., go get <pkg> and go mod download), go also automatically downloads dependencies whenever it deems necessary. For example, if you've just cloned a repository and try to execute it (e.g., go run ./main.go), it would automatically download any missing dependency. Additionally, go mod tidy may be used to both update go.mod and go.sum based on the imports being used in the project as well as to download those dependencies.

Considering all that, this implementation creates a temporary directory where it initially downloads anything that would be required by command. For go get commands, it only downloads the requested package(s) and its dependencies, if any. For other commands (go install <pkg>, go run <pkg>, go mod *, etc), verifies every dependency used by the package. This temporary directory is deleted when the analysis of the packages that will be installed finishes, alongside any cache used by go.

An important detail is that since go mod tidy may add more dependencies to go.mod, it must run on the project itself. Therefore, for that specific command both go.mod and go.sum are saved in a temporarily directory and the changes are applied directly to the current project, restoring those files when the analysis finishes.

Currently this only checks for vulnerabilities, as the database would need to be updated with information about malicious go packages.

I'm opening this mainly as as suggestion, as I know that this implementation doesn't follow the SCFW's principles of not installing anything until it has been verified.

Copy link
Collaborator

@ikretz ikretz left a comment

Choose a reason for hiding this comment

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

Looks great! Thank for for making this PR so clean and high-quality: it was very easy to review. I just had a couple questions here and there but am ready to approve.

The main branch has gotten a little ahead of this one, but it shouldn't be too bad to resynchronize. The main thing we'll need to do is implement the new list_installed_packages() method of PackageManager for the Go class. This was added to support the new audit feature in bcedd7d. This is the only reason why I selected "Request changes" instead of "Approve", since all package managers have to support both modes.

I am happy to help with resolving conflicts or anything else related to getting this merged. Thanks again, @SirGFM!

Comment on lines +183 to +184
if platform.system() == "Windows":
separator = ";"
Copy link
Collaborator

Choose a reason for hiding this comment

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

We currently do not support Windows so we can remove this for now.

Good to know for down the road, though!

if self._original_dir is None:
raise GoModNotFoundError("Failed to find a 'go.mod' file to operate on")

mod_file = self._original_dir / "go.mod"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see on line 260 that you're checking whether the go.sum file exists. Do we need to do a similar check here for go.mod or is it safe to assume it exists?

Comment on lines +278 to +279
if len(command) > 2 and command[1] == "mod" and not command[2] in INSPECTED_MOD_COMMANDS:
return []
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there the potential to have optional command-line arguments that could change the indices for these tokens? It doesn't look like it based on the help messages but I thought I would confirm.

Comment on lines +291 to +292
is_tidy = len(command) > 2 and command[1] == "mod" and command[2] == "tidy"
for param in command[2 if not is_tidy else 3:]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same question about indices and optional command-line arguments as above.

Comment on lines +310 to +316
if is_tidy:
tmp.duplicate_go_mod()
tmp.run(["mod", "tidy"], True)

if is_tidy or len(local_packages) > 0:
dry_run = tmp.run(["list", "-m", "all"], True)
packages.update(set(filter(None, map(line_to_package, dry_run.stdout.split('\n')))))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be possible/desirable to always duplicate the current project into the temporary directory and then run the given command in there? I think this wouldn't have any unintended effects on the "real" project, right?

@ikretz
Copy link
Collaborator

ikretz commented Jul 10, 2025

I thought of one more thing we'll want to do: add matrix tests in CI for Go across all supported versions of the package manager.

@SirGFM SirGFM force-pushed the sirgfm/add-go-support branch from 6765c3f to dc61de6 Compare September 15, 2025 15:15
@SirGFM SirGFM force-pushed the sirgfm/add-go-support branch from dc61de6 to 5af9e8b Compare September 15, 2025 15:22
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.

2 participants