From ffb64bbd16c9e8d1f920865dceec6bea487c9fce Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Mon, 13 Apr 2026 10:14:17 -0700 Subject: [PATCH] tools/find-pkg-importer: Tool to find what imports a Go package Advisories in the Go vulnerability database often identify specific Go packages or even specific symbols within Go packages that the advisory applies to. Therefore when we are evaluating the impact of an advisory on OpenTofu we often need to ask the question "what parts of OpenTofu are using that affected package?" This new tool is a small wrapper around the "go list" command which takes a package path of interest and returns all of the packages in OpenTofu's package import graph that directly import the given package. The results can include both OpenTofu's own packages and packages from upstream modules or the Go standard library. Signed-off-by: Martin Atkins --- go.mod | 1 + tools/find-pkg-importer/main.go | 82 +++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tools/find-pkg-importer/main.go diff --git a/go.mod b/go.mod index c6b3795042..ca7a7140a1 100644 --- a/go.mod +++ b/go.mod @@ -312,6 +312,7 @@ tool ( github.com/mitchellh/gox github.com/opentofu/opentofu/cmd/tofu github.com/opentofu/opentofu/tools/find-dep-upgrades + github.com/opentofu/opentofu/tools/find-pkg-importer github.com/opentofu/opentofu/tools/loggraphdiff github.com/opentofu/opentofu/tools/protobuf-compile github.com/opentofu/opentofu/tools/selected-go-version diff --git a/tools/find-pkg-importer/main.go b/tools/find-pkg-importer/main.go new file mode 100644 index 0000000000..38ae20a70c --- /dev/null +++ b/tools/find-pkg-importer/main.go @@ -0,0 +1,82 @@ +// Copyright (c) The OpenTofu Authors +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) 2023 HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// find-pkg-importer is a utility for finding which packages in our dependency +// graph import a given package path. +// +// Run this from the root of your work tree for the OpenTofu repository so +// that it can find the project's "go.mod" file in the current working +// directory. For example, to find which packages import "html/template": +// +// go tool find-pkg-importer html/template +// +// Note that this tool deals in individual packages rather than whole modules, +// so that we can use it to evaluate our exposure to advisories from the Go +// vulnerability database which describes specific packages and symbols that +// are affected. Use "go mod graph" or "go mod why" to answer similar questions +// about entire modules. +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "os" + "os/exec" + "slices" +) + +func main() { + // We don't have any options, but this'll report an error if someone tries to use one + flag.Usage = func() { + fmt.Fprintln(os.Stderr, "Usage: go tool find-pkg-importer ") + } + flag.Parse() + if len(os.Args) != 2 { + flag.Usage() + os.Exit(1) + } + wantPkg := os.Args[1] + + cmd := exec.Command("go", "list", "-json=ImportPath,Imports", "all") + out, err := cmd.StdoutPipe() + if err != nil { + fatalf("Can't open pipe for child process stdout: %s", out) + } + dec := json.NewDecoder(out) + err = cmd.Start() + if err != nil { + fatalf("Failed to run 'go list': %s", err) + } + defer func() { + // Error intentionally ignored becuse there's nothing useful we could + // do about it anyway. + _ = cmd.Wait() + }() + + type Candidate struct { + ImportPath string `json:"ImportPath"` + Imports []string `json:"Imports"` + } + for { + var candidate Candidate + err := dec.Decode(&candidate) + if err == io.EOF { + break + } + if err != nil { + fatalf("Failed to parse record from 'go list': %s", err) + } + if slices.Contains(candidate.Imports, wantPkg) { + fmt.Println(candidate.ImportPath) + } + } +} + +func fatalf(format string, a ...any) { + fmt.Fprintf(os.Stderr, format+"\n", a...) + os.Exit(1) +}