gemfile

package
v1.1.3 Latest Latest
Warning

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

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package gemfile provides parsing and analysis of Ruby Gemfile.lock files.

It handles:

  • Parsing Gemfile.lock (and gems.locked) files to extract gem dependencies
  • Extracting group information from Gemfile (and gems.rb) files
  • Building dependency trees (forward and reverse dependencies)
  • Analyzing gem health, outdated versions, and vulnerabilities
  • Generating reports in multiple formats (text, CSV, JSON)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DetectFramework added in v1.0.6

func DetectFramework(gf *Gemfile) (framework string, version string)

DetectFramework detects the primary framework (Rails, Sinatra, etc.) from installed gems

func ExtractBundleVersion added in v1.0.6

func ExtractBundleVersion(path string) string

ExtractBundleVersion extracts the Bundle version from Gemfile.lock

func ExtractGitHubOwnerRepo added in v1.1.0

func ExtractGitHubOwnerRepo(uri string) (owner, repo string, ok bool)

ExtractGitHubOwnerRepo extracts the GitHub owner and repository name from a URI. It handles HTTPS, HTTP, and SSH-style URIs with optional .git suffix. Returns (owner, repo, true) if extraction succeeds, ("", "", false) otherwise.

func ExtractRubyVersion added in v1.0.6

func ExtractRubyVersion(path string) string

ExtractRubyVersion extracts the Ruby version from Gemfile.lock

func FindGemfile added in v1.1.2

func FindGemfile(dir string) string

FindGemfile searches for a Ruby Gemfile in the given directory. It probes in priority order: gems.rb, Gemfile. Returns the absolute path to the Gemfile if found, empty string otherwise.

func FindLockFile added in v1.1.2

func FindLockFile(dir string) string

FindLockFile searches for a Ruby lock file in the given directory. It probes in priority order: gems.locked, Gemfile.lock. Returns the absolute path to the lock file if found, empty string otherwise.

func GetReverseDependencies

func GetReverseDependencies(gemName string, gemfile *Gemfile) []string

GetReverseDependencies returns a list of gems that directly depend on the given gem. This is a simple list of direct dependents, useful for quick lookups without building a tree.

Types

type AnalysisResult

type AnalysisResult struct {
	// TotalGems is the total number of gems (first-level and transitive dependencies)
	TotalGems int
	// OutdatedGems is a list of gem names with available updates
	OutdatedGems []string
	// VulnerableGems is a list of gem names with known CVEs
	VulnerableGems []string
	// FirstLevelGems is a list of gem names directly required (in Gemfile/Gemfile.lock DEPENDENCIES)
	FirstLevelGems []string
	// AllGems is the complete list of parsed Gem objects
	AllGems []*Gem
	// GemStatuses is detailed status information for each gem (outdated, vulnerable, health, etc.)
	GemStatuses []*GemStatus
	// Summary is a brief one-line summary of the analysis results
	Summary string
	// Details is a detailed report of all gems and their status
	Details string
}

AnalysisResult contains the results of analyzing a Gemfile.lock for vulnerabilities, outdated gems, and other quality metrics.

func Analyze

func Analyze(gemfile *Gemfile) *AnalysisResult

Analyze performs a complete security and version analysis of a parsed Gemfile. It checks each gem for known vulnerabilities and identifies first-level dependencies. It returns an AnalysisResult with summary and detailed reports. Note: outdated version checking is done separately by the UI and is not included in this initial analysis.

type DependencyInfo

type DependencyInfo struct {
	// GemName is the selected gem name
	GemName string
	// Version is the selected gem's version
	Version string
	// ForwardDeps lists the gems that this gem depends on (direct dependencies only)
	ForwardDeps []string
	// ReverseDeps lists the gems that depend on this gem (direct dependents only)
	ReverseDeps []string
	// ForwardDepsCount is the count of direct forward dependencies
	ForwardDepsCount int
	// ReverseDepsCount is the count of direct reverse dependencies
	ReverseDepsCount int
	// ForwardTree is a tree structure showing transitive dependencies of this gem
	ForwardTree *DependencyNode
	// ReverseTree is a tree structure showing what depends on this gem (up to 3 levels)
	ReverseTree *DependencyNode
}

DependencyInfo contains forward and reverse dependency information for a selected gem, including both simple lists and tree structures for visualization.

type DependencyNode

type DependencyNode struct {
	// Name is the gem name
	Name string
	// Version is the gem version at this node
	Version string
	// Children are the direct dependencies (or dependents for reverse trees)
	Children []*DependencyNode
	// Depth is the nesting level in the tree (0 for root, increments for each level)
	Depth int
}

DependencyNode represents a node in a dependency tree, used for displaying forward and reverse dependency chains with version information and nesting depth.

type DependencyResult

type DependencyResult struct {
	// SelectedGem is the name of the gem being analyzed
	SelectedGem string
	// DependencyInfo contains the dependency analysis for the selected gem
	DependencyInfo *DependencyInfo
	// AllGems is a reference to the full gem map for version lookups
	AllGems map[string]*Gem
}

DependencyResult contains the analysis result for a selected gem's dependencies.

func AnalyzeDependencies

func AnalyzeDependencies(gemfile *Gemfile, selectedGemName string) *DependencyResult

AnalyzeDependencies analyzes forward and reverse dependencies for a given gem. It returns both lists of direct dependencies and tree structures showing transitive relationships. Trees are limited to prevent circular dependencies: forward tree is capped at depth 5, reverse tree is capped at depth 3.

type Gem

type Gem struct {
	// Name is the lowercase gem name
	Name string
	// Version is the installed version string (may include platform suffixes like "x86_64-linux")
	Version string
	// Dependencies is a list of gem names that this gem depends on
	Dependencies []string
	// Groups lists the bundle groups this gem belongs to (e.g., "default", "development", "test", "production")
	Groups []string
	// IsFirstLevel is true if this gem is in the DEPENDENCIES section (directly required)
	IsFirstLevel bool
}

Gem represents a Ruby gem with its version, dependencies, and group assignments.

type GemHealth added in v1.1.0

type GemHealth struct {
	// Score is the computed health tier (Healthy, Warning, Critical, Unknown)
	Score HealthScore `json:"score"`
	// LastRelease is the timestamp of the latest gem release from RubyGems
	LastRelease time.Time `json:"last_release"`
	// GitHubPushedAt is the timestamp of the last commit pushed to the repository
	GitHubPushedAt time.Time `json:"github_pushed_at"`
	// Stars is the number of GitHub stars on the repository
	Stars int `json:"stars"`
	// OpenIssues is the number of open issues on the repository
	OpenIssues int `json:"open_issues"`
	// Archived indicates whether the GitHub repository is archived
	Archived bool `json:"archived"`
	// Disabled indicates whether the GitHub repository is disabled
	Disabled bool `json:"disabled"`
	// MaintainerCount is the number of maintainers listed on RubyGems
	MaintainerCount int `json:"maintainer_count"`
	// RateLimited indicates if GitHub API rate limit was exceeded (partial data)
	RateLimited bool `json:"rate_limited"`
	// FetchedAt is the timestamp when this health data was fetched
	FetchedAt time.Time `json:"fetched_at"`
}

GemHealth contains maintenance and activity metrics for a gem from RubyGems and GitHub.

type GemStatus

type GemStatus struct {
	// Name is the lowercase gem name
	Name string
	// Version is the currently installed version
	Version string
	// Groups lists the bundle groups this gem belongs to (e.g., "default", "development", "test")
	Groups []string
	// IsOutdated indicates whether a newer version is available
	IsOutdated bool
	// LatestVersion is the latest available version (only set if IsOutdated is true)
	LatestVersion string
	// IsVulnerable indicates whether known CVEs affect this gem version
	IsVulnerable bool
	// VulnerabilityInfo contains CVE ID and description (only set if IsVulnerable is true)
	VulnerabilityInfo string
	// HomepageURL is the gem's homepage or source code repository URL
	HomepageURL string
	// Description is the gem description from rubygems.org
	Description string
	// Health contains gem maintenance status data (nil until fetched asynchronously)
	Health *GemHealth
	// OutdatedFailed is true if the outdated version check failed with an error
	OutdatedFailed bool
}

GemStatus represents the current status and metadata of a gem, including its version, group assignments, and vulnerability/outdated status with additional information.

type Gemfile

type Gemfile struct {
	// Path is the absolute path to the Gemfile.lock file
	Path string
	// Gems is a map of all gems (by lowercase name) found in the lock file
	Gems map[string]*Gem
	// FirstLevelGems is a list of gem names that are directly required (in DEPENDENCIES section)
	FirstLevelGems []string
}

Gemfile represents the parsed contents of a Gemfile.lock file.

func Parse

func Parse(path string) (*Gemfile, error)

Parse parses a Gemfile.lock file (or gems.locked) and returns the parsed Gemfile structure. It accepts either a file path or directory path; if a directory is provided, it searches for a lock file in that directory. Expands ~/ in paths. Returns an error if the file cannot be found, opened, or parsed.

func ParseGemspec added in v1.1.2

func ParseGemspec(path string) (*Gemfile, error)

ParseGemspec parses a Ruby .gemspec file to extract gem dependencies declared via add_runtime_dependency, add_development_dependency, and add_dependency directives. It accepts either a file path or a directory path; if a directory is provided, it searches for the first .gemspec file in that directory. Version constraints from unresolved gemspec declarations are extracted but cannot be compared against actual installed versions without Gemfile.lock. Returns a Gemfile structure with all gems marked as first-level dependencies.

func (*Gemfile) GetGemCount

func (g *Gemfile) GetGemCount() int

GetGemCount returns the total number of gems in the parsed Gemfile.

func (*Gemfile) GetGemsAsList

func (g *Gemfile) GetGemsAsList() []*Gem

GetGemsAsList returns all gems in the Gemfile as a slice.

func (*Gemfile) LoadGroupsFromGemfile

func (g *Gemfile) LoadGroupsFromGemfile(gemfilePath string) error

LoadGroupsFromGemfile parses the Gemfile (or gems.rb) to extract group assignments for gems. It processes group blocks (e.g., "group :development do") and assigns those groups to gems defined within. Returns an error if the Gemfile cannot be read; returns nil if the Gemfile is not found (graceful degradation).

type HealthChecker added in v1.1.0

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

HealthChecker fetches and caches gem health data from the RubyGems and GitHub APIs. It supports batch GitHub queries via GraphQL and graceful handling of rate limiting.

func NewHealthChecker added in v1.1.0

func NewHealthChecker() *HealthChecker

NewHealthChecker creates a new HealthChecker with a 10-second HTTP timeout and empty caches.

func (*HealthChecker) FetchGitHubBatch added in v1.1.2

func (hc *HealthChecker) FetchGitHubBatch(pairs []RepoOwnerPair) error

FetchGitHubBatch fetches GitHub data for multiple repositories in batched GraphQL requests. It caches all results for use by FetchHealth. If GITHUB_TOKEN is not set, it silently returns without fetching (GitHub data is optional). Returns an error only if the API request fails.

func (*HealthChecker) FetchHealth added in v1.1.0

func (hc *HealthChecker) FetchHealth(gemName, sourceCodeURI, homepageURI, versionCreatedAtStr, ownersURL string) (*GemHealth, error)

FetchHealth fetches and computes health data for a gem from RubyGems and GitHub APIs. It uses cached GitHub data from FetchGitHubBatch when available, then falls back to individual REST calls. Returns (*GemHealth, error). If GitHub rate limited, returns partial data with RateLimited=true.

type HealthScore added in v1.1.0

type HealthScore int

HealthScore represents the maintenance health tier of a gem. Health is determined by last release date, maintainer count, activity, and repository status.

const (
	// HealthUnknown indicates health data could not be fetched (rate limited, network error, etc.)
	HealthUnknown HealthScore = iota
	// HealthHealthy indicates active gem with regular releases and multiple maintainers (🟢)
	HealthHealthy
	// HealthWarning indicates stale gem with no recent activity or single maintainer (🟡)
	HealthWarning
	// HealthCritical indicates inactive gem, archived, or disabled repository (🔴)
	HealthCritical
)

func ComputeHealthScore added in v1.1.0

func ComputeHealthScore(h *GemHealth) HealthScore

ComputeHealthScore computes a health tier from gem health metrics. Tiers: CRITICAL (archived/disabled/3+ yrs inactive), WARNING (1-3 yrs inactive or single maintainer), HEALTHY (active within 1 year with 2+ maintainers), UNKNOWN (rate limited or no data).

func (HealthScore) String added in v1.1.0

func (hs HealthScore) String() string

type OutdatedChecker

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

OutdatedChecker checks if gems have newer versions available and fetches gem metadata from the rubygems.org API. It caches all results to minimize API calls.

func NewOutdatedChecker

func NewOutdatedChecker() *OutdatedChecker

NewOutdatedChecker creates a new OutdatedChecker with a 10-second HTTP timeout and empty caches for gem metadata.

func (*OutdatedChecker) GetDescription

func (oc *OutdatedChecker) GetDescription(gemName string) string

GetDescription returns the gem's description from cache or fetches it if not cached. Returns an empty string if no description is available.

func (*OutdatedChecker) GetHomepage

func (oc *OutdatedChecker) GetHomepage(gemName string) string

GetHomepage returns the homepage URL for a gem from cache or fetches it if not cached. Returns a fallback URL to rubygems.org if no homepage is available.

func (*OutdatedChecker) GetSourceCodeURI added in v1.1.0

func (oc *OutdatedChecker) GetSourceCodeURI(gemName string) string

GetSourceCodeURI returns the source code repository URL for a gem from cache or fetches it if not cached. Returns an empty string if no source code URI is available.

func (*OutdatedChecker) GetVersionCreatedAt added in v1.1.0

func (oc *OutdatedChecker) GetVersionCreatedAt(gemName string) string

GetVersionCreatedAt returns the release timestamp of the latest version from cache or fetches it if not cached. Returns an empty string if the timestamp is not available.

func (*OutdatedChecker) IsOutdated

func (oc *OutdatedChecker) IsOutdated(gemName, currentVersion string) (bool, string, error)

IsOutdated checks if a gem has a newer version available. It handles platform suffixes and pre-release versions correctly (e.g., "1.6.3-x86_64-linux" is compared as "1.6.3"). Returns (isOutdated, latestVersion, error).

type RepoOwnerPair added in v1.1.2

type RepoOwnerPair struct {
	// GemName is the gem name
	GemName string
	// Owner is the GitHub repository owner
	Owner string
	// Repo is the GitHub repository name
	Repo string
}

RepoOwnerPair represents a gem and its GitHub repository for batch fetching. Used for efficient GraphQL batch queries to GitHub.

type RubygemeInfo

type RubygemeInfo struct {
	// Version is the latest available version of the gem
	Version string `json:"version"`
	// VersionCreatedAt is the timestamp when the latest version was released
	VersionCreatedAt string `json:"version_created_at"`
	// HomepageURI is the gem's official homepage URL
	HomepageURI string `json:"homepage_uri"`
	// SourceCodeURI is the source code repository URL
	SourceCodeURI string `json:"source_code_uri"`
	// Info is the gem's description
	Info string `json:"info"`
}

RubygemeInfo represents gem metadata from the rubygems.org API.

type Vulnerability

type Vulnerability struct {
	// GemName is the affected gem (lowercase)
	GemName string
	// AffectedVersions is a list of version specs that are vulnerable (e.g., "< 6.1.4", ">= 6.0.0, < 6.0.5")
	AffectedVersions []string
	// Description is a brief summary of the vulnerability
	Description string
	// CVE is the CVE identifier (e.g., "CVE-2021-22942")
	CVE string
}

Vulnerability represents a known CVE affecting one or more versions of a gem.

type VulnerabilityChecker

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

VulnerabilityChecker checks if gem versions have known CVEs. It maintains a static list of known vulnerabilities with version ranges.

func NewVulnerabilityChecker

func NewVulnerabilityChecker() *VulnerabilityChecker

NewVulnerabilityChecker creates a new VulnerabilityChecker with a built-in list of known CVEs affecting common Ruby gems (Rails, Devise, Rack, ActionPack, etc.). This list is static and compiled at build time; for live CVE updates, consider integrating with a dedicated vulnerability database.

func (*VulnerabilityChecker) HasVulnerability

func (vc *VulnerabilityChecker) HasVulnerability(gemName, version string) (bool, string, string)

HasVulnerability checks if a gem version has a known CVE and returns the result. Returns (hasVulnerability, cveID, description). If multiple CVEs affect the version, only the first match is returned.

Jump to

Keyboard shortcuts

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