graph

package
v0.0.0-...-1a28f28 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 22, 2026 License: MIT Imports: 49 Imported by: 0

Documentation

Overview

Package graph provides dependency graph construction, analysis, and visualization.

A dependency graph represents the relationships between packages in a software project. Nodes represent packages, and directed edges represent "depends on" relationships (from dependent to dependency).

Graph Construction

Graphs can be constructed from multiple sources:

  • Inventory extraction: FromInventory creates a graph from extracted packages, but without edge information (suitable for flat listing).

  • Lockfile parsing: Ecosystem-specific EdgeResolver implementations parse lockfiles to extract dependency relationships. The ResolverRegistry provides a unified interface for multi-ecosystem resolution:

    | Ecosystem | Resolver | Lockfile(s) | Strategy | |--------------|--------------------|-----------------------------------------|-----------------------------| | Go | GoResolver | go.mod | vendor -> proxy -> git | | npm | NpmResolver | package-lock.json, npm-shrinkwrap.json | parse lockfile tree | | Cargo | CargoResolver | Cargo.lock | parse lockfile | | PyPI | PyPIResolver | poetry.lock, uv.lock, requirements.txt | parse lockfile or flat list | | RubyGems | RubyGemsResolver | Gemfile.lock | parse lockfile |

  • SBOM import: Parse CycloneDX/SPDX relationship data to reconstruct edges.

  • Container images: Layer attribution provides implicit relationships between packages and the layers that introduced them.

Analysis Operations

Once constructed, graphs support several analysis operations:

  • Path finding: Graph.PathsTo finds all paths from root to a target package, answering "why is X in my dependencies?" (analogous to `go mod why`).

  • Reverse lookup: Graph.Ancestors finds all packages that depend on a target, answering "what depends on X?" (useful for vulnerability impact analysis).

  • Subgraph extraction: Graph.Subgraph extracts a subtree rooted at a package, answering "what does X bring in?"

  • Vulnerability annotation: Graph.AnnotateVulns attaches vulnerability findings to affected nodes for security-focused visualization.

Visualization

Graphs can be rendered to multiple formats via Graph.Render:

  • FormatText: ASCII tree view (CLI-friendly)
  • FormatDOT: Graphviz DOT format
  • FormatMermaid: Mermaid.js flowchart
  • FormatD3: D3.js force-directed graph JSON
  • FormatJSON: Full graph structure as JSON

Render options control output:

Architecture

The graph subsystem is designed around these principles:

  1. Ecosystem-agnostic core: The Graph, Node, and Edge types work across all ecosystems. Ecosystem-specific logic lives in EdgeResolver implementations.

  2. Incremental construction: Graphs can be built incrementally, adding nodes from inventory extraction first, then edges from lockfile parsing.

  3. Target-polymorphic: The same graph types work for directories, git repos, container images, SBOMs, and individual PURLs.

  4. Offline-first: Edge resolution should work from local lockfiles without network calls when possible. deps.dev API is a fallback for ecosystems without parseable lockfiles.

Thread Safety

Graph instances are not safe for concurrent modification. However, read operations (queries, iteration, rendering) can be performed concurrently after construction is complete.

Package graph provides extended dependency graph capabilities.

Package graph provides dependency graph operations.

The graph package uses Protocol Buffer types from graphv1 as its internal representation, enabling seamless serialization and RPC without conversion. The Graph struct provides utility methods for traversal, filtering, and analysis.

Index

Constants

ImportStatus constants re-exported from proto.

View Source
const (
	ScopeUnspecified = graphv1.Scope_SCOPE_UNSPECIFIED
	ScopeRuntime     = graphv1.Scope_SCOPE_RUNTIME
	ScopeDev         = graphv1.Scope_SCOPE_DEV
	ScopeOptional    = graphv1.Scope_SCOPE_OPTIONAL
	ScopeBuild       = graphv1.Scope_SCOPE_BUILD
	ScopeTest        = graphv1.Scope_SCOPE_TEST
)

Scope constants re-exported from proto for convenience.

View Source
const (
	// DepthSyntheticRoot marks synthetic root nodes (e.g., the main module itself).
	// These nodes represent the project being scanned rather than actual dependencies.
	DepthSyntheticRoot int32 = -1

	// DepthDisconnected marks nodes with no path from any root.
	// This typically means the node was discovered (e.g., in go.sum or a binary)
	// but no dependency path could be resolved to it.
	DepthDisconnected int32 = 999
)

Depth constants for node positioning in the dependency graph.

View Source
const (
	// DefaultGoProxy is the default Go module proxy.
	DefaultGoProxy = "https://proxy.golang.org"
)

Variables

View Source
var KnownBOMs = map[string]BOMInfo{

	"org.springframework.boot": {
		GroupID:    "org.springframework.boot",
		ArtifactID: "spring-boot-dependencies",
	},

	"com.google.protobuf": {
		GroupID:    "com.google.protobuf",
		ArtifactID: "protobuf-bom",
	},

	"com.fasterxml.jackson": {
		GroupID:    "com.fasterxml.jackson",
		ArtifactID: "jackson-bom",
	},

	"org.junit": {
		GroupID:    "org.junit",
		ArtifactID: "junit-bom",
	},

	"io.micronaut.application": {
		GroupID:    "io.micronaut.platform",
		ArtifactID: "micronaut-platform",
	},

	"io.quarkus": {
		GroupID:    "io.quarkus.platform",
		ArtifactID: "quarkus-bom",
	},
}

KnownBOMs maps common Gradle plugins to their corresponding BOMs. This allows automatic BOM detection from build.gradle plugin declarations.

Functions

func GoListMAll

func GoListMAll(ctx context.Context, dir string) (map[string]string, error)

GoListMAll returns a best-effort approximation of modules that may be in the build.

IMPORTANT: go.sum is NOT equivalent to `go list -m all`. go.sum is a security cache of cryptographic checksums, not a dependency list. It may contain:

  • Modules from historical dependencies that are no longer used
  • Multiple versions of the same module (from different transitive paths)
  • Modules that were fetched but are not in the final build

For accurate build list, use `go list -m all` when the Go CLI is available. This function provides a CLI-free approximation by parsing go.sum and selecting the highest version seen for each module (which often matches MVS selection, but is not guaranteed).

See: https://words.filippo.io/gosum/ - "go.sum Is Not a Lockfile"

func GradleProjectDependencies

func GradleProjectDependencies(ctx context.Context, files FileReader) ([]gradlex.MavenDependency, error)

GradleProjectDependencies extracts all dependencies from a Gradle project. This is a convenience function for use outside the resolver context.

func InitGradleBOMResolver

func InitGradleBOMResolver()

InitGradleBOMResolver initializes and registers the global BOM resolver with the gradlex package. This should be called during application startup or when the first Gradle extraction occurs.

func IsPublicModule

func IsPublicModule(modulePath string) bool

IsPublicModule checks if a module path looks like it would be available on the public proxy. Private modules (internal paths, etc.) return false.

func MergeExtendedIntoGraph

func MergeExtendedIntoGraph(g *Graph, extended *ExtendedGraphResult)

MergeExtendedIntoGraph adds declared-only modules to an existing graph, marking them with IMPORT_STATUS_DECLARED.

This enriches a standard graph (from inventory extraction) with the full supply chain surface area visible in `go mod graph`.

func ParseGoListMAll

func ParseGoListMAll(output string) map[string]string

ParseGoListMAll parses the output of `go list -m all`. Each line is "module version" or just "module" for the main module.

func ParseGoSum

func ParseGoSum(content string) map[string]string

ParseGoSum parses a go.sum file and returns a map of module path to version.

go.sum format: module version h1:hash (and module version/go.mod h1:hash) Each module may have two entries: one for the module content and one for its go.mod.

Note: go.sum is a checksum cache, not a dependency list. It may contain modules that are no longer used. When multiple versions exist for the same module, we keep the highest version as a best approximation of MVS selection.

func PathsToProto

func PathsToProto(paths []Path) []*graphv1.DependencyPath

PathsToProto converts multiple paths to proto DependencyPath messages.

func ResolveManagedVersions

func ResolveManagedVersions(ctx context.Context, boms []BOMCoordinate) map[string]string

ResolveManagedVersions resolves versions for dependencies using BOMs. This is a convenience function that:

  1. Gets the global BOM resolver
  2. Resolves all provided BOMs
  3. Returns a map of "groupId:artifactId" -> version

Parameters:

  • ctx: Context for cancellation
  • boms: List of BOMs to resolve (groupID, artifactID, version tuples)

Returns a map of managed versions, or an empty map if resolution fails.

func SupportedEcosystems

func SupportedEcosystems() []string

SupportedEcosystems returns the list of ecosystems with edge resolution support.

func ToID

func ToID(n *Node) dependency.ID

ToID converts a Node to a dependency.ID for compatibility with other packages. Note: dependency.ID doesn't include Version; version is embedded in the PURL.

Types

type BOMCoordinate

type BOMCoordinate struct {
	GroupID    string
	ArtifactID string
	Version    string
}

BOMCoordinate represents a BOM's Maven coordinates.

type BOMInfo

type BOMInfo struct {
	GroupID    string
	ArtifactID string
}

BOMInfo identifies a Maven BOM artifact.

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder resolves dependency graph edges from inventory. It wraps the ResolverRegistry with configuration options.

func NewBuilder

func NewBuilder(opts BuilderOptions) *Builder

NewBuilder creates a Builder configured from options.

func (*Builder) Build

func (b *Builder) Build(
	ctx context.Context,
	pkgs []*extractor.Package,
	direct map[string]bool,
	findings []vulnerability.Finding,
	advisories map[string]*vulnerabilityv1.Advisory,
	files FileReader,
) (*Graph, error)

Build constructs a dependency graph from inventory and resolves edges. The returned graph includes vulnerability annotations when findings are provided.

func (*Builder) BuildFromWorkspace

func (b *Builder) BuildFromWorkspace(
	ctx context.Context,
	pkgs []*extractor.Package,
	direct map[string]bool,
	findings []vulnerability.Finding,
	advisories map[string]*vulnerabilityv1.Advisory,
	ws workspace.FS,
) (*Graph, error)

BuildFromWorkspace is a convenience method that creates a FileReader from a workspace.

type BuilderOptions

type BuilderOptions struct {
	// UseProxy enables fetching module metadata from package registries
	// (e.g., proxy.golang.org for Go).
	UseProxy bool

	// UseGit enables cloning repositories for private module resolution.
	UseGit bool

	// PrivatePatterns specifies glob patterns for private modules
	// (similar to GOPRIVATE).
	PrivatePatterns []string

	// UseDepsDevTransitives enables deps.dev for resolving transitive dependencies
	// for Maven/Gradle packages. This provides complete dependency graphs.
	UseDepsDevTransitives bool
}

BuilderOptions configures graph construction.

type CargoResolver

type CargoResolver struct {
	// contains filtered or unexported fields
}

CargoResolver resolves dependency edges for Rust/Cargo packages by parsing Cargo.lock. Cargo.lock contains the complete dependency graph with exact versions and dependencies.

Supported files:

  • Cargo.lock (dependency lockfile with full graph)
  • Cargo.toml (manifest for direct dependency detection)

The resolver parses Cargo.lock's [[package]] sections which list each package's dependencies explicitly, making edge resolution precise without external fetches.

func NewCargoResolver

func NewCargoResolver(opts ...CargoResolverOption) *CargoResolver

NewCargoResolver creates a new Cargo edge resolver.

func (*CargoResolver) Ecosystem

func (r *CargoResolver) Ecosystem() string

Ecosystem returns "crates.io" as the ecosystem identifier.

func (*CargoResolver) ResolveEdges

func (r *CargoResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses Cargo.lock to add dependency edges to the graph.

type CargoResolverOption

type CargoResolverOption func(*CargoResolver)

CargoResolverOption configures a CargoResolver.

func WithCargoConcurrency

func WithCargoConcurrency(n int) CargoResolverOption

WithCargoConcurrency sets the maximum concurrency for Cargo resolution.

type Dependencies

type Dependencies = pb.Dependencies

Dependencies is an alias for the deps.dev response type.

type DepsDevClient

type DepsDevClient struct {
	// contains filtered or unexported fields
}

DepsDevClient fetches dependency information from deps.dev. This is significantly faster than fetching individual go.mod files because deps.dev has precomputed dependency graphs.

The client uses a bounded LRU cache with TTL to prevent unbounded memory growth in long-running processes while maintaining good performance.

func NewDepsDevClient

func NewDepsDevClient() (*DepsDevClient, error)

NewDepsDevClient creates a client for the deps.dev API.

func (*DepsDevClient) CacheStats

func (c *DepsDevClient) CacheStats() memory.Stats

CacheStats returns cache statistics for monitoring and debugging.

func (*DepsDevClient) Close

func (c *DepsDevClient) Close() error

Close closes the gRPC connection.

func (*DepsDevClient) GetDependencies

func (c *DepsDevClient) GetDependencies(ctx context.Context, system pb.System, name, version string) (*pb.Dependencies, error)

GetDependencies fetches the dependency graph for a package. The response contains all transitive dependencies with their relationships.

type DepsDevEdgeResolver

type DepsDevEdgeResolver struct {
	// contains filtered or unexported fields
}

DepsDevEdgeResolver resolves edges using deps.dev bulk dependency data. This is much faster than individual go.mod fetches because: 1. deps.dev has precomputed graphs 2. One API call returns all transitive deps 3. We can parallelize across direct dependencies

func NewDepsDevEdgeResolver

func NewDepsDevEdgeResolver(client *DepsDevClient) *DepsDevEdgeResolver

NewDepsDevEdgeResolver creates an edge resolver using deps.dev.

func (*DepsDevEdgeResolver) ResolveGoEdges

func (r *DepsDevEdgeResolver) ResolveGoEdges(ctx context.Context, g *Graph, mf *modfile.File) error

ResolveGoEdges adds edges to the graph using deps.dev data. This is much faster than the proxy-based approach because deps.dev returns full dependency graphs in single API calls.

type DepsDevFetcher

type DepsDevFetcher struct {
	// contains filtered or unexported fields
}

DepsDevFetcher implements ModuleGoModFetcher using deps.dev. Instead of fetching actual go.mod files, it synthesizes them from deps.dev dependency data, which is much faster.

func NewDepsDevFetcher

func NewDepsDevFetcher(client *DepsDevClient) *DepsDevFetcher

NewDepsDevFetcher creates a fetcher backed by deps.dev.

func (*DepsDevFetcher) FetchGoMod

func (f *DepsDevFetcher) FetchGoMod(ctx context.Context, modulePath, version string) (*modfile.File, error)

FetchGoMod returns a synthesized go.mod based on deps.dev data. This doesn't return actual go.mod content but rather the dependency information we need for edge resolution.

type Edge

type Edge = graphv1.Edge

Re-export proto types for convenience. These allow consumers to use graph.Node instead of graphv1.Node.

func CloneEdge

func CloneEdge(e *Edge) *Edge

CloneEdge creates a copy of an edge.

type EdgeResolver

type EdgeResolver interface {
	// Ecosystem returns the ecosystem this resolver handles (e.g., "Go", "npm").
	Ecosystem() string

	// ResolveEdges adds edges to the graph based on ecosystem-specific logic.
	// It receives the graph (with nodes already populated), and a file reader
	// for accessing lockfiles and manifests.
	//
	// The resolver should:
	//  1. Identify relevant lockfiles/manifests in the file system
	//  2. Parse dependency relationships from those files
	//  3. Add edges to the graph via g.AddEdge()
	//  4. Update node depths based on the resolved tree
	//
	// Errors are typically non-fatal; resolvers should add as many edges as
	// possible even if some files fail to parse.
	ResolveEdges(ctx context.Context, g *Graph, files FileReader) error
}

EdgeResolver computes dependency relationships for a specific ecosystem. Implementations parse lockfiles, manifests, or other sources to determine which packages depend on which.

type ExtendedGraphResult

type ExtendedGraphResult struct {
	// FullGraph is the complete module requirement graph.
	FullGraph *ModGraph

	// SelectedModules are modules in the final build (go list -m all).
	SelectedModules map[string]string

	// DeclaredOnlyModules are modules in the graph but not selected by MVS.
	// These are "phantom" dependencies - latent supply chain risk.
	DeclaredOnlyModules map[string][]string
}

ExtendedGraphResult contains the results of extended graph analysis.

func AnalyzeExtendedGraph

func AnalyzeExtendedGraph(ctx context.Context, dir string) (*ExtendedGraphResult, error)

AnalyzeExtendedGraph runs both `go mod graph` and `go list -m all` to determine which modules are declared vs. actually selected.

type FileReader

type FileReader interface {
	ReadFile(path string) ([]byte, error)
}

FileReader provides access to files for edge resolution. This abstraction allows resolvers to work with workspaces, git commits, or other sources.

type Format

type Format string

Format specifies the output format for graph rendering.

const (
	// FormatDOT renders as Graphviz DOT format.
	FormatDOT Format = "dot"

	// FormatMermaid renders as Mermaid.js flowchart format.
	FormatMermaid Format = "mermaid"

	// FormatD3 renders as D3.js force-directed graph JSON.
	FormatD3 Format = "d3"

	// FormatText renders as ASCII tree format.
	FormatText Format = "text"

	// FormatJSON renders as JSON (full graph structure).
	FormatJSON Format = "json"
)

type GitModuleFetcher

type GitModuleFetcher struct {
	// contains filtered or unexported fields
}

GitModuleFetcher fetches go.mod files directly from Git repositories. This is used for private modules that aren't available on the public proxy, mimicking what `go get` does for GOPRIVATE modules.

The fetcher uses a bounded LRU cache with TTL to prevent unbounded memory growth in long-running processes.

func NewGitModuleFetcher

func NewGitModuleFetcher() *GitModuleFetcher

NewGitModuleFetcher creates a fetcher that retrieves go.mod from Git repos.

func (*GitModuleFetcher) CacheStats

func (f *GitModuleFetcher) CacheStats() memory.Stats

CacheStats returns cache statistics for monitoring and debugging.

func (*GitModuleFetcher) FetchGoMod

func (f *GitModuleFetcher) FetchGoMod(ctx context.Context, modulePath, version string) (*modfile.File, error)

FetchGoMod fetches the go.mod file for a module directly from its Git repository. It uses the same resolution logic as the Go toolchain: 1. For known hosts (github.com, gitlab.com, etc.), construct the repo URL directly 2. For other hosts, use go-import meta tag discovery

type GoProxyClient

type GoProxyClient struct {
	// contains filtered or unexported fields
}

GoProxyClient fetches module metadata from Go module proxies. It provides access to go.mod files for any public Go module, enabling accurate dependency graph resolution.

The client uses a bounded LRU cache with TTL to prevent unbounded memory growth in long-running processes while maintaining good performance.

func NewGoProxyClient

func NewGoProxyClient(proxyURL string) *GoProxyClient

NewGoProxyClient creates a client for fetching Go module metadata. If proxyURL is empty, it defaults to proxy.golang.org. Uses SafeDialer for SSRF protection against DNS rebinding attacks.

func (*GoProxyClient) CacheStats

func (c *GoProxyClient) CacheStats() memory.Stats

CacheStats returns cache statistics for monitoring and debugging.

func (*GoProxyClient) FetchGoMod

func (c *GoProxyClient) FetchGoMod(ctx context.Context, modulePath, version string) (*modfile.File, error)

FetchGoMod fetches the go.mod file for a module at a specific version. Results are cached to avoid redundant network requests.

func (*GoProxyClient) GetAllDependencies

func (c *GoProxyClient) GetAllDependencies(ctx context.Context, modulePath, version string) (direct, indirect []module.Version, err error)

GetAllDependencies returns all dependencies (direct and indirect) from a module's go.mod.

func (*GoProxyClient) GetDependencies

func (c *GoProxyClient) GetDependencies(ctx context.Context, modulePath, version string) ([]module.Version, error)

GetDependencies returns the direct dependencies declared in a module's go.mod. This is the key method for building accurate dependency graphs.

type GoResolver

type GoResolver struct {
	// contains filtered or unexported fields
}

GoResolver resolves dependency edges for Go modules by parsing go.mod files. It identifies direct dependencies from the require directives and builds edges from the root module to its direct dependencies.

For accurate transitive dependency resolution, GoResolver uses a chain of fetchers to obtain go.mod files:

  1. Vendor directory (if present) - local copy, most precise
  2. Module proxy (proxy.golang.org) - for public modules
  3. Git repository fetch - for private modules (like GOPRIVATE)

Note: deps.dev doesn't provide dependency graphs for Go modules (Go uses MVS at build time rather than a lockfile), so we fetch go.mod files directly.

Performance: Fetches are parallelized for speed while maintaining precision.

func NewGoResolver

func NewGoResolver(opts ...GoResolverOption) *GoResolver

NewGoResolver creates a new Go module edge resolver. By default, it uses heuristic-based resolution from the local go.mod. Use WithProxy() to enable accurate resolution via the module proxy.

func (*GoResolver) Ecosystem

func (r *GoResolver) Ecosystem() string

Ecosystem returns "Go" as the ecosystem identifier.

func (*GoResolver) ResolveEdges

func (r *GoResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses go.mod files to add dependency edges to the graph. It processes all go.mod files found via the FileReader, extracting both direct and indirect dependencies, and creating appropriate edges.

type GoResolverOption

type GoResolverOption func(*GoResolver)

GoResolverOption configures a GoResolver.

func WithConcurrency

func WithConcurrency(n int) GoResolverOption

WithConcurrency sets the maximum number of concurrent proxy requests.

func WithGit

func WithGit() GoResolverOption

WithGit enables fetching go.mod files directly from Git repositories. This is used for private modules that aren't available on the public proxy. When enabled, modules matching privatePatterns (or not found on proxy) will be fetched directly from their Git repositories.

func WithPrivatePatterns

func WithPrivatePatterns(patterns ...string) GoResolverOption

WithPrivatePatterns sets glob patterns for private module paths. Modules matching any pattern will skip proxy and use Git directly. Patterns support path.Match syntax (e.g., "github.com/mycompany/*"). This is similar to the GOPRIVATE environment variable.

func WithProxy

func WithProxy(proxyURL string) GoResolverOption

WithProxy enables fetching go.mod files from the module proxy for accurate dependency resolution.

type GradleBOMResolver

type GradleBOMResolver struct {
	// contains filtered or unexported fields
}

GradleBOMResolver implements gradlex.BOMVersionResolver using deps.dev. This adapter allows the graph package to provide BOM resolution to the gradlex extractors without creating an import cycle.

func NewGradleBOMResolver

func NewGradleBOMResolver(resolver *MavenBOMResolver) *GradleBOMResolver

NewGradleBOMResolver creates a new Gradle BOM resolver.

type GradleResolver

type GradleResolver struct {
	// contains filtered or unexported fields
}

GradleResolver resolves dependency edges for Gradle projects.

This resolver performs static analysis of Gradle build files and uses deps.dev to fetch transitive dependencies. It supports:

  • Multi-module projects via settings.gradle
  • Version catalogs (libs.versions.toml)
  • Property substitution from gradle.properties and ext blocks
  • BOM/platform dependencies

The resolver prioritizes lockfiles when available, falling back to static analysis of build scripts with deps.dev resolution for transitives.

func NewGradleResolver

func NewGradleResolver(opts ...GradleResolverOption) *GradleResolver

NewGradleResolver creates a new Gradle edge resolver.

func (*GradleResolver) Ecosystem

func (r *GradleResolver) Ecosystem() string

Ecosystem returns "Maven" as the ecosystem identifier. Gradle dependencies are Maven packages.

func (*GradleResolver) ResolveEdges

func (r *GradleResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses Gradle project files and adds dependency edges to the graph.

type GradleResolverOption

type GradleResolverOption func(*GradleResolver)

GradleResolverOption configures a GradleResolver.

func WithGradleConcurrency

func WithGradleConcurrency(n int) GradleResolverOption

WithGradleConcurrency sets the maximum concurrency for Gradle resolution.

func WithGradleDepsDevClient

func WithGradleDepsDevClient(client *DepsDevClient) GradleResolverOption

WithGradleDepsDevClient sets the deps.dev client for transitive resolution.

type Graph

type Graph struct {
	// contains filtered or unexported fields
}

Graph represents a dependency graph with nodes (packages) and edges (dependencies). It uses proto types internally for seamless serialization.

func FromInventory

func FromInventory(pkgs []*extractor.Package, direct map[string]bool) *Graph

FromInventory constructs a graph from inventory extraction results. The direct map indicates which packages are direct dependencies. For Go packages, the map keys are module roots (e.g., "github.com/google/osv-scalibr"). For other ecosystems, keys are PURL strings.

func FromProto

func FromProto(nodes []*Node, edges []*Edge, roots []string) *Graph

FromProto constructs a Graph from proto components. This is useful when deserializing a graph from RPC responses.

func New

func New() *Graph

New creates an empty graph.

func ResolveGradleWithDepsdev

func ResolveGradleWithDepsdev(ctx context.Context, files FileReader, client *DepsDevClient) (*Graph, error)

ResolveGradleWithDepsdev resolves a Gradle project's dependencies using deps.dev. Returns a Graph with all direct and transitive dependencies.

func (*Graph) AddEdge

func (g *Graph) AddEdge(e *Edge)

AddEdge adds an edge to the graph.

func (*Graph) AddNode

func (g *Graph) AddNode(n *Node)

AddNode adds a node to the graph. If a node with the same PURL exists, it is replaced.

func (*Graph) Ancestors

func (g *Graph) Ancestors(purl string) iter.Seq[*Node]

Ancestors returns an iterator over all packages that transitively depend on the given PURL.

func (*Graph) AnnotateVulns

func (g *Graph) AnnotateVulns(findings []vulnerability.Finding, advisories map[string]*vulnerabilityv1.Advisory)

AnnotateVulns adds vulnerability information to graph nodes.

func (*Graph) Children

func (g *Graph) Children(purl string) iter.Seq[*Node]

Children returns an iterator over nodes that are direct dependencies of the given PURL. Uses cached adjacency index for O(1) lookup after first access.

func (*Graph) Clone

func (g *Graph) Clone() *Graph

Clone returns a deep copy of the graph.

func (*Graph) CountImportStatuses

func (g *Graph) CountImportStatuses() *ImportStatusCounts

CountImportStatuses returns counts of nodes by import status.

func (*Graph) DeclaredOnlyNodes

func (g *Graph) DeclaredOnlyNodes() iter.Seq[*Node]

DeclaredOnlyNodes returns an iterator over nodes with DECLARED import status. These are "phantom" dependencies - in the module graph but not the final build.

func (*Graph) Descendants

func (g *Graph) Descendants(purl string) iter.Seq[*Node]

Descendants returns an iterator over all transitive dependencies of the given PURL.

func (*Graph) Direct

func (g *Graph) Direct() iter.Seq[*Node]

Direct returns an iterator over direct dependency nodes.

func (*Graph) Edges

func (g *Graph) Edges() iter.Seq[*Edge]

Edges returns an iterator over all edges in the graph.

func (*Graph) Empty

func (g *Graph) Empty() bool

Empty reports whether the graph has no nodes.

func (*Graph) Filter

func (g *Graph) Filter(pred func(*Node) bool) *Graph

Filter returns a new graph containing only nodes matching the predicate. Edges are included if both endpoints match.

func (*Graph) FilterByImportStatus

func (g *Graph) FilterByImportStatus(statuses ...ImportStatus) *Graph

FilterByImportStatus returns a new graph containing only nodes with the specified import statuses.

func (*Graph) GetEdgesSlice

func (g *Graph) GetEdgesSlice() []*Edge

GetEdgesSlice returns all edges as a slice (for proto serialization).

func (*Graph) GetNodesSlice

func (g *Graph) GetNodesSlice() []*Node

GetNodesSlice returns all nodes as a slice (for proto serialization).

func (*Graph) GetRoots

func (g *Graph) GetRoots() []string

GetRoots returns the root PURLs (for proto serialization).

func (*Graph) Node

func (g *Graph) Node(purl string) *Node

Node returns the node with the given PURL, or nil if not found.

func (*Graph) Nodes

func (g *Graph) Nodes() iter.Seq[*Node]

Nodes returns an iterator over all nodes in the graph.

func (*Graph) NodesSorted

func (g *Graph) NodesSorted() iter.Seq[*Node]

NodesSorted returns nodes sorted by PURL for deterministic output.

func (*Graph) Package

func (g *Graph) Package(purl string) *extractor.Package

Package returns the underlying extractor package for a node, if available.

func (*Graph) Parents

func (g *Graph) Parents(purl string) iter.Seq[*Node]

Parents returns an iterator over nodes that depend on the given PURL. Uses cached adjacency index for O(1) lookup after first access.

func (*Graph) PathsBetween

func (g *Graph) PathsBetween(source, target string) []Path

PathsBetween finds all paths from source to target.

func (*Graph) PathsTo

func (g *Graph) PathsTo(target string) []Path

PathsTo finds all paths from root nodes to the target PURL.

func (*Graph) Render

func (g *Graph) Render(w io.Writer, format Format, opts ...RenderOption) error

Render writes the graph in the specified format.

func (*Graph) RequiredOnlyNodes

func (g *Graph) RequiredOnlyNodes() iter.Seq[*Node]

RequiredOnlyNodes returns an iterator over nodes with REQUIRED import status. These are in go.mod but may not be directly imported by user code.

func (*Graph) Roots

func (g *Graph) Roots() iter.Seq[*Node]

Roots returns an iterator over root (direct dependency) nodes.

func (*Graph) Size

func (g *Graph) Size() int

Size returns the number of nodes in the graph.

func (*Graph) Sort

func (g *Graph) Sort(cmpFunc func(a, b *Node) int) []*Node

Sort returns nodes sorted by the given comparison function.

func (*Graph) SortByDepth

func (g *Graph) SortByDepth() []*Node

SortByDepth returns nodes sorted by depth (direct first, then transitive).

func (*Graph) SortByVulns

func (g *Graph) SortByVulns() []*Node

SortByVulns returns nodes sorted by vulnerability count (highest first).

func (*Graph) Stats

func (g *Graph) Stats() *graphv1.GraphStats

Stats returns statistics about the graph as a proto message.

func (*Graph) Subgraph

func (g *Graph) Subgraph(root string) *Graph

Subgraph returns a subgraph rooted at the given PURL, including all descendants.

func (*Graph) ToD3JSON

func (g *Graph) ToD3JSON(opts ...RenderOption) []byte

ToD3JSON returns the graph as D3.js force-directed JSON.

func (*Graph) ToDOT

func (g *Graph) ToDOT(opts ...RenderOption) string

ToDOT returns the graph in Graphviz DOT format.

func (*Graph) ToMermaid

func (g *Graph) ToMermaid(opts ...RenderOption) string

ToMermaid returns the graph in Mermaid.js format.

func (*Graph) ToText

func (g *Graph) ToText(opts ...RenderOption) string

ToText returns the graph as an ASCII tree.

func (*Graph) Transitive

func (g *Graph) Transitive() iter.Seq[*Node]

Transitive returns an iterator over transitive (non-direct) dependency nodes.

func (*Graph) UpdateDepths

func (g *Graph) UpdateDepths()

UpdateDepths recalculates node depths using BFS from direct dependencies. This should be called after edges have been added to ensure depth values reflect the actual graph structure. Direct dependencies have depth 0, their immediate dependencies have depth 1, and so on. Disconnected nodes (not reachable from any direct dependency) get DepthDisconnected.

func (*Graph) VulnerableNodes

func (g *Graph) VulnerableNodes() iter.Seq[*Node]

VulnerableNodes returns an iterator over nodes that have vulnerabilities.

func (*Graph) VulnerablePaths

func (g *Graph) VulnerablePaths() []Path

VulnerablePaths returns all unique paths from root nodes to vulnerable packages. This is useful for understanding which dependency chains expose vulnerabilities.

Paths are deduplicated by package name sequence (not version), so if the same logical path exists with different versions, only one is returned.

Example use case: finding which direct dependencies transitively pull in a vulnerable package, to identify the best remediation target.

type HexResolver

type HexResolver struct {
	// contains filtered or unexported fields
}

HexResolver resolves dependency edges for Elixir/Erlang packages by parsing mix.lock. The mix.lock file contains all resolved dependencies with their exact versions.

Supported files:

  • mix.lock (Mix lockfile for Elixir/Erlang projects)

Mix.lock lists all dependencies (direct and transitive) but doesn't explicitly encode the dependency tree. Direct dependencies are determined from mix.exs, which this resolver does not parse. Instead, it marks all dependencies and relies on the inventory for direct/transitive flags.

func NewHexResolver

func NewHexResolver(opts ...HexResolverOption) *HexResolver

NewHexResolver creates a new Hex edge resolver.

func (*HexResolver) Ecosystem

func (r *HexResolver) Ecosystem() string

Ecosystem returns "Hex" as the ecosystem identifier.

func (*HexResolver) ResolveEdges

func (r *HexResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses mix.lock to add dependency nodes to the graph. Note: mix.lock doesn't encode the dependency tree, so edges aren't resolved from this file alone. This resolver ensures all packages are in the graph.

type HexResolverOption

type HexResolverOption func(*HexResolver)

HexResolverOption configures a HexResolver.

func WithHexConcurrency

func WithHexConcurrency(n int) HexResolverOption

WithHexConcurrency sets the maximum concurrency for Hex resolution.

type ImportStatus

type ImportStatus = graphv1.ImportStatus

ImportStatus re-exports the proto enum for convenience.

type ImportStatusCounts

type ImportStatusCounts = graphv1.ImportStatusCounts

ImportStatusCounts re-exports the proto type for convenience.

type MavenBOMResolver

type MavenBOMResolver struct {
	// contains filtered or unexported fields
}

MavenBOMResolver resolves Maven BOM (Bill of Materials) dependency management using the deps.dev API. It provides fast, accurate version resolution for dependencies managed by published BOMs like Spring Boot, gRPC, and others.

The resolver handles:

  • Recursive BOM imports (e.g., Spring Boot imports Jackson BOM)
  • Property interpolation (e.g., ${jackson.version} -> 2.15.3)
  • Caching to minimize API calls

Limitations:

  • Only works for published artifacts (not SNAPSHOT or local)
  • Cannot resolve custom property overrides in build files
  • Requires network access to deps.dev

func GetGlobalBOMResolver

func GetGlobalBOMResolver() (*MavenBOMResolver, error)

GetGlobalBOMResolver returns the shared BOM resolver instance. Returns nil and an error if deps.dev is unavailable.

func NewMavenBOMResolver

func NewMavenBOMResolver(client *DepsDevClient) *MavenBOMResolver

NewMavenBOMResolver creates a new BOM resolver using the provided deps.dev client.

func (*MavenBOMResolver) ResolveBOM

func (r *MavenBOMResolver) ResolveBOM(ctx context.Context, groupID, artifactID, version string) (*ResolvedBOM, error)

ResolveBOM fetches and resolves a BOM, returning all managed versions. The coordinate should be in the format "groupId:artifactId:version".

func (*MavenBOMResolver) ResolveVersion

func (r *MavenBOMResolver) ResolveVersion(bom *ResolvedBOM, groupID, artifactID string) (string, bool)

ResolveVersion looks up the managed version for a dependency. Returns the version and true if found, or empty string and false if not managed.

type MavenResolver

type MavenResolver struct {
	// contains filtered or unexported fields
}

MavenResolver resolves dependency edges for Maven/Gradle packages. It supports multiple lockfile formats:

  • pom.xml (Maven project files with dependency declarations)
  • gradle.lockfile (Gradle dependency lockfiles)
  • buildscript-gradle.lockfile (Gradle buildscript lockfiles)

For pom.xml files, the resolver parses the XML structure to find dependencies. For Gradle lockfiles, it parses the simple "group:artifact:version=checksum" format.

When a DepsDevClient is provided, the resolver can fetch transitive dependency information from deps.dev to build more complete graphs.

func NewMavenResolver

func NewMavenResolver(opts ...MavenResolverOption) *MavenResolver

NewMavenResolver creates a new Maven edge resolver.

func (*MavenResolver) Ecosystem

func (r *MavenResolver) Ecosystem() string

Ecosystem returns "Maven" as the ecosystem identifier.

func (*MavenResolver) ResolveEdges

func (r *MavenResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses Maven/Gradle files to add dependency edges to the graph.

type MavenResolverOption

type MavenResolverOption func(*MavenResolver)

MavenResolverOption configures a MavenResolver.

func WithMavenConcurrency

func WithMavenConcurrency(n int) MavenResolverOption

WithMavenConcurrency sets the maximum concurrency for Maven resolution.

func WithMavenDepsDevClient

func WithMavenDepsDevClient(client *DepsDevClient) MavenResolverOption

WithMavenDepsDevClient sets the deps.dev client for transitive resolution.

type ModGraph

type ModGraph struct {
	// Edges contains all requirement relationships.
	Edges []ModGraphEdge

	// Modules maps module path to a list of versions seen in the graph.
	// Multiple versions can exist because different modules may require
	// different versions before MVS selects one.
	Modules map[string][]string

	// MainModule is the root module (the project being scanned).
	MainModule string
}

ModGraph represents the full module requirement graph from `go mod graph`. This includes all modules that could potentially be pulled in, not just those selected by MVS for the current build.

func BuildModGraphFromFiles

func BuildModGraphFromFiles(ctx context.Context, mf *modfile.File, goSumData []byte) (*ModGraph, error)

BuildModGraphFromFiles builds a ModGraph by parsing go.mod, go.sum, and fetching transitive dependency information from the module proxy. This is equivalent to `go mod graph` but doesn't require the Go CLI.

func ParseGoModGraph

func ParseGoModGraph(ctx context.Context, dir string) (*ModGraph, error)

ParseGoModGraph builds the module requirement graph by reading go.mod and go.sum files and fetching transitive dependencies from the module proxy. This approach does not require the Go CLI to be installed.

func ParseGoModGraphOutput

func ParseGoModGraphOutput(output string) (*ModGraph, error)

ParseGoModGraphOutput parses the output of `go mod graph`. Each line is "parent@version child@version" or "parent child" for the main module.

type ModGraphEdge

type ModGraphEdge struct {
	// From is the requiring module (parent).
	FromModule  string
	FromVersion string

	// To is the required module (child).
	ToModule  string
	ToVersion string
}

ModGraphEdge represents a single edge from `go mod graph` output. Format: "parent@version child@version"

type ModuleGoModFetcher

type ModuleGoModFetcher interface {
	// FetchGoMod returns the parsed go.mod for a module at a version.
	// Returns nil, nil if the module is not available from this source.
	FetchGoMod(ctx context.Context, modulePath, version string) (*modfile.File, error)
}

ModuleGoModFetcher defines how to fetch a go.mod for a module. This abstraction allows using multiple sources: proxy, vendor, local filesystem.

type Node

type Node = graphv1.Node

Re-export proto types for convenience. These allow consumers to use graph.Node instead of graphv1.Node.

func CloneNode

func CloneNode(n *Node) *Node

CloneNode creates a deep copy of a node.

type NpmResolver

type NpmResolver struct {
	// contains filtered or unexported fields
}

NpmResolver resolves dependency edges for npm/yarn/pnpm packages by parsing lockfiles. Unlike Go modules, npm lockfiles contain the complete dependency tree with explicit parent-child relationships, making edge resolution precise without external fetches.

Supported lockfiles:

  • package-lock.json (npm v2/v3 format with "packages" field)
  • yarn.lock (parsed as flat list, edges from package.json)
  • pnpm-lock.yaml (parsed as structured YAML)

Note: This resolver does not use deps.dev because npm lockfiles already contain the complete dependency graph. deps.dev would be redundant and slower.

func NewNpmResolver

func NewNpmResolver(opts ...NpmResolverOption) *NpmResolver

NewNpmResolver creates a new npm edge resolver.

func (*NpmResolver) Ecosystem

func (r *NpmResolver) Ecosystem() string

Ecosystem returns "npm" as the ecosystem identifier.

func (*NpmResolver) ResolveEdges

func (r *NpmResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses npm/yarn/pnpm lockfiles to add dependency edges to the graph.

type NpmResolverOption

type NpmResolverOption func(*NpmResolver)

NpmResolverOption configures an NpmResolver.

func WithNpmConcurrency

func WithNpmConcurrency(n int) NpmResolverOption

WithNpmConcurrency sets the maximum concurrency for npm resolution.

type NuGetResolver

type NuGetResolver struct {
	// contains filtered or unexported fields
}

NuGetResolver resolves dependency edges for .NET/NuGet packages. It supports multiple formats:

  • packages.lock.json (NuGet PackageReference lockfile with full dependency info)
  • packages.config (legacy NuGet format with package list)

The packages.lock.json format is preferred as it contains resolved versions and dependency relationships. The packages.config format only lists packages.

When a DepsDevClient is provided, the resolver can fetch transitive dependency information from deps.dev to build more complete graphs.

func NewNuGetResolver

func NewNuGetResolver(opts ...NuGetResolverOption) *NuGetResolver

NewNuGetResolver creates a new NuGet edge resolver.

func (*NuGetResolver) Ecosystem

func (r *NuGetResolver) Ecosystem() string

Ecosystem returns "NuGet" as the ecosystem identifier.

func (*NuGetResolver) ResolveEdges

func (r *NuGetResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses NuGet files to add dependency edges to the graph.

type NuGetResolverOption

type NuGetResolverOption func(*NuGetResolver)

NuGetResolverOption configures a NuGetResolver.

func WithNuGetConcurrency

func WithNuGetConcurrency(n int) NuGetResolverOption

WithNuGetConcurrency sets the maximum concurrency for NuGet resolution.

func WithNuGetDepsDevClient

func WithNuGetDepsDevClient(client *DepsDevClient) NuGetResolverOption

WithNuGetDepsDevClient sets the deps.dev client for transitive resolution.

type Path

type Path []*Node

Path represents a sequence of nodes from root to target.

func PathFromProto

func PathFromProto(p *graphv1.DependencyPath) Path

PathFromProto converts a proto DependencyPath to a Path.

func PathsFromProto

func PathsFromProto(paths []*graphv1.DependencyPath) []Path

PathsFromProto converts proto DependencyPaths to a Path slice.

func PathsToVulnerability

func PathsToVulnerability(g *Graph, vulnID string) []Path

PathsToVulnerability returns all paths to packages affected by a specific vulnerability ID.

func ShortestPathToVulnerability

func ShortestPathToVulnerability(g *Graph, vulnID string) Path

ShortestPathToVulnerability returns the shortest path to any package affected by the given vulnerability ID.

func (Path) Contains

func (p Path) Contains(purl string) bool

Contains reports whether the path contains a node with the given PURL.

func (Path) Len

func (p Path) Len() int

Len returns the path length (number of edges, not nodes).

func (Path) PURLs

func (p Path) PURLs() []string

PURLs returns the PURLs of all nodes in the path.

func (Path) String

func (p Path) String() string

String returns a human-readable representation of the path.

func (Path) ToProto

func (p Path) ToProto() *graphv1.DependencyPath

ToProto converts a Path to a graphv1.DependencyPath proto message.

type PubResolver

type PubResolver struct {
	// contains filtered or unexported fields
}

PubResolver resolves dependency edges for Dart/Flutter packages by parsing pubspec.lock. The pubspec.lock file contains all resolved dependencies with their exact versions.

Supported files:

  • pubspec.lock (Dart/Flutter lockfile)

The lockfile indicates whether dependencies are "direct main", "direct dev", or "transitive", allowing accurate direct/transitive classification.

func NewPubResolver

func NewPubResolver(opts ...PubResolverOption) *PubResolver

NewPubResolver creates a new Pub edge resolver.

func (*PubResolver) Ecosystem

func (r *PubResolver) Ecosystem() string

Ecosystem returns "Pub" as the ecosystem identifier.

func (*PubResolver) ResolveEdges

func (r *PubResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses pubspec.lock to add dependency nodes to the graph.

type PubResolverOption

type PubResolverOption func(*PubResolver)

PubResolverOption configures a PubResolver.

func WithPubConcurrency

func WithPubConcurrency(n int) PubResolverOption

WithPubConcurrency sets the maximum concurrency for Pub resolution.

type PyPIResolver

type PyPIResolver struct {
	// contains filtered or unexported fields
}

PyPIResolver resolves dependency edges for Python packages by parsing lockfiles. Unlike npm or Cargo, Python has multiple package managers with different formats:

Supported lockfiles:

  • poetry.lock (Poetry - explicit dependencies field per package)
  • Pipfile.lock (Pipenv - dependencies in "default" and "develop" sections)
  • uv.lock (uv - TOML format with dependencies list)
  • requirements.txt (pip - flat list, no edges, all marked direct)

Note: requirements.txt does not contain dependency relationships, only package versions. For requirements.txt, all packages are marked as direct dependencies. For real edge resolution, use poetry.lock, Pipfile.lock, or uv.lock.

func NewPyPIResolver

func NewPyPIResolver(opts ...PyPIResolverOption) *PyPIResolver

NewPyPIResolver creates a new PyPI edge resolver.

func (*PyPIResolver) Ecosystem

func (r *PyPIResolver) Ecosystem() string

Ecosystem returns "PyPI" as the ecosystem identifier.

func (*PyPIResolver) ResolveEdges

func (r *PyPIResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses Python lockfiles to add dependency edges to the graph.

type PyPIResolverOption

type PyPIResolverOption func(*PyPIResolver)

PyPIResolverOption configures a PyPIResolver.

func WithPyPIConcurrency

func WithPyPIConcurrency(n int) PyPIResolverOption

WithPyPIConcurrency sets the maximum concurrency for PyPI resolution.

type RegistryOption

type RegistryOption func(*registryConfig)

RegistryOption configures a ResolverRegistry.

func WithDepsDevTransitives

func WithDepsDevTransitives() RegistryOption

WithDepsDevTransitives enables deps.dev for resolving transitive dependencies. This provides accurate dependency graphs for Maven/Gradle packages.

func WithGoGitEnabled

func WithGoGitEnabled() RegistryOption

WithGoGitEnabled enables Git fetching for private Go modules.

func WithGoPrivate

func WithGoPrivate(patterns ...string) RegistryOption

WithGoPrivate sets patterns for private Go modules (similar to GOPRIVATE).

func WithGoProxyEnabled

func WithGoProxyEnabled(proxyURL string) RegistryOption

WithGoProxy enables Go module proxy fetching for accurate transitive resolution. This is slower but provides precise dependency edges.

func WithGoResolverConcurrency

func WithGoResolverConcurrency(n int) RegistryOption

WithGoConcurrency sets the concurrency for Go module fetching.

type RenderOption

type RenderOption func(*renderConfig)

RenderOption configures graph rendering behavior.

func WithCollapsed

func WithCollapsed(purls ...string) RenderOption

WithCollapsed collapses subtrees rooted at the given PURLs.

func WithDirection

func WithDirection(dir string) RenderOption

WithDirection sets the graph direction (TB, LR, BT, RL).

func WithFilter

func WithFilter(pred func(*Node) bool) RenderOption

WithFilter includes only nodes matching the predicate.

func WithHighlightVulns

func WithHighlightVulns(minSeverity string) RenderOption

WithHighlightVulns highlights vulnerable nodes in the output.

func WithMaxDepth

func WithMaxDepth(n int) RenderOption

WithMaxDepth limits rendering to nodes within the given depth from roots.

func WithVersions

func WithVersions(show bool) RenderOption

WithVersions controls whether versions are shown in node labels.

func WithVulnCounts

func WithVulnCounts(show bool) RenderOption

WithVulnCounts controls whether vulnerability counts are shown.

type ResolvedBOM

type ResolvedBOM struct {
	// ManagedVersions maps "groupId:artifactId" to resolved version
	ManagedVersions map[string]string

	// Properties maps property names to resolved values
	Properties map[string]string
}

ResolvedBOM contains the fully resolved dependency management from a BOM.

type ResolverRegistry

type ResolverRegistry struct {
	// contains filtered or unexported fields
}

ResolverRegistry manages edge resolvers for multiple ecosystems. It provides a unified interface for resolving edges across all supported ecosystems in a single pass.

func NewResolverRegistry

func NewResolverRegistry(opts ...RegistryOption) *ResolverRegistry

NewResolverRegistry creates a registry with the default set of resolvers. For Go, the resolver is configured without proxy/git by default for speed. Use WithGoProxy() option to enable accurate transitive resolution.

func (*ResolverRegistry) ForEcosystem

func (r *ResolverRegistry) ForEcosystem(ecosystem string) EdgeResolver

ForEcosystem returns the resolver for a specific ecosystem, or nil if not found.

func (*ResolverRegistry) Register

func (r *ResolverRegistry) Register(resolver EdgeResolver)

Register adds a custom edge resolver to the registry. This allows extending graph resolution to additional ecosystems without modifying the default registry.

func (*ResolverRegistry) ResolveAll

func (r *ResolverRegistry) ResolveAll(ctx context.Context, g *Graph, files FileReader) error

ResolveAll runs all resolvers on the graph. Each resolver processes the ecosystem-specific lockfiles it finds. Errors from individual resolvers are logged but don't stop processing, allowing partial resolution when some ecosystems fail. Returns a combined error if any resolvers failed.

func (*ResolverRegistry) ResolveEcosystem

func (r *ResolverRegistry) ResolveEcosystem(ctx context.Context, g *Graph, files FileReader, ecosystem string) error

ResolveEcosystem runs only the resolver for a specific ecosystem.

func (*ResolverRegistry) Resolvers

func (r *ResolverRegistry) Resolvers() []EdgeResolver

Resolvers returns all registered edge resolvers.

type RubyGemsResolver

type RubyGemsResolver struct {
	// contains filtered or unexported fields
}

RubyGemsResolver resolves dependency edges for Ruby packages by parsing Gemfile.lock. Gemfile.lock contains the complete dependency tree with exact versions.

Supported files:

  • Gemfile.lock (Bundler lockfile with full dependency graph)
  • gems.locked (alternative lockfile name)

The lockfile format groups dependencies under their parent, making edge resolution precise without external fetches.

func NewRubyGemsResolver

func NewRubyGemsResolver(opts ...RubyGemsResolverOption) *RubyGemsResolver

NewRubyGemsResolver creates a new RubyGems edge resolver.

func (*RubyGemsResolver) Ecosystem

func (r *RubyGemsResolver) Ecosystem() string

Ecosystem returns "RubyGems" as the ecosystem identifier.

func (*RubyGemsResolver) ResolveEdges

func (r *RubyGemsResolver) ResolveEdges(ctx context.Context, g *Graph, files FileReader) error

ResolveEdges parses Gemfile.lock to add dependency edges to the graph.

type RubyGemsResolverOption

type RubyGemsResolverOption func(*RubyGemsResolver)

RubyGemsResolverOption configures a RubyGemsResolver.

func WithRubyGemsConcurrency

func WithRubyGemsConcurrency(n int) RubyGemsResolverOption

WithRubyGemsConcurrency sets the maximum concurrency for RubyGems resolution.

type Scope

type Scope = graphv1.Scope

Re-export proto types for convenience. These allow consumers to use graph.Node instead of graphv1.Node.

type VulnerabilityCount

type VulnerabilityCount = graphv1.VulnerabilityCount

Re-export proto types for convenience. These allow consumers to use graph.Node instead of graphv1.Node.

type WorkspaceFileReader

type WorkspaceFileReader struct {
	// contains filtered or unexported fields
}

WorkspaceFileReader adapts a workspace.ReadableFS to the FileReader interface. This allows edge resolvers to access files from any workspace implementation.

func NewWorkspaceFileReader

func NewWorkspaceFileReader(ws interface {
	ReadFile(name string) ([]byte, error)
}) *WorkspaceFileReader

NewWorkspaceFileReader creates a FileReader from a workspace ReadableFS.

func (*WorkspaceFileReader) Open

func (w *WorkspaceFileReader) Open(name string) (fs.File, error)

Open implements fs.FS for directory walking support.

func (*WorkspaceFileReader) ReadDir

func (w *WorkspaceFileReader) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir implements fs.ReadDirFS for directory listing.

func (*WorkspaceFileReader) ReadFile

func (w *WorkspaceFileReader) ReadFile(name string) ([]byte, error)

ReadFile implements FileReader.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL