gorisk
Behavioral supply-chain risk intelligence from code structure.
Maps what your dependencies can do — network access, exec, filesystem writes, unsafe pointers — not just what CVEs they carry.
Why gorisk
| Tool |
CVEs |
Capabilities |
Evidence |
Upgrade risk |
Blast radius |
Polyglot |
Offline |
Free |
| govulncheck |
✅ |
❌ |
❌ |
❌ |
❌ |
❌ |
✅ |
✅ |
| Snyk |
✅ |
❌ |
❌ |
partial |
❌ |
partial |
❌ |
SaaS |
| goda |
❌ |
❌ |
❌ |
❌ |
partial |
❌ |
✅ |
✅ |
| GoSurf |
❌ |
❌ |
❌ |
❌ |
❌ |
❌ |
✅ |
✅ |
| gorisk |
via OSV |
✅ |
✅ |
✅ |
✅ |
✅ |
✅ |
✅ |
Key differentiators:
- Polyglot — pluggable
Analyzer interface; ships with Go, Node.js, and PHP (Composer/Laravel) today; Python, Rust, Java, and Ruby on the roadmap.
- Capability detection — detect which packages can read files, make network calls, spawn processes, or use
unsafe/eval. Know what your dependencies can do before they're in production.
- Evidence + confidence — every capability detection is backed by file path, line number, match context, and a confidence score (import = 90%, call site = 60%, install script = 85%).
- Capability diff — compare two versions of a dependency and detect capability escalation. If
v1.2.3 → v1.3.0 quietly added exec or network, gorisk flags it as a supply chain risk signal.
- Deterministic output — all output is sorted; every scan produces a short SHA-256 graph checksum so CI can detect silent graph changes between runs.
- CVE listing — full list of OSV vulnerability IDs per module, not just a count.
- Blast radius — simulate removing a module and see exactly which packages and binaries break, plus LOC impact.
- Upgrade risk — diff exported symbols between versions to detect breaking API changes before you upgrade.
- Health scoring — combines commit activity, release cadence, archived status, and CVE count into a single score (parallel, 10 workers).
- Reachability — prove a capability is reachable from
main via callgraph (Go) or import graph (Node.js). Supports --entry to target a specific binary.
- History + trend — snapshot risk over time, diff between snapshots, view score sparklines per module.
- CI-native — SARIF output compatible with GitHub Code Scanning. Exit codes for policy gating.
--timings flag for build profiling.
Install
go install github.com/1homsi/gorisk/cmd/gorisk@latest
Language support
gorisk auto-detects the language from the project directory. Use --lang to override.
gorisk scan # auto-detect
gorisk scan --lang go # force Go
gorisk scan --lang node # force Node.js
gorisk scan --lang php # force PHP
When both go.mod and package.json are present (monorepo), both analyzers run and their dependency graphs are merged.
Supported languages
| Language |
--lang |
Status |
Detection signal |
Lockfile / manifest |
| Go |
go |
✅ stable |
go.mod |
go.mod + go list |
| Node.js |
node |
✅ stable |
package.json |
package-lock.json v1/v2/v3, yarn.lock, pnpm-lock.yaml; npm/yarn/pnpm workspaces (monorepos) |
| PHP |
php |
✅ stable |
composer.json / composer.lock |
composer.lock; Laravel, Symfony, and bare Composer projects |
| Python |
python |
🗓 planned |
requirements.txt / pyproject.toml |
poetry.lock, Pipfile.lock, uv.lock |
| Rust |
rust |
🗓 planned |
Cargo.toml |
Cargo.lock |
| Java |
java |
🗓 planned |
pom.xml / build.gradle |
Maven, Gradle lock files |
| Ruby |
ruby |
🗓 planned |
Gemfile |
Gemfile.lock |
Want to add a language? The Analyzer interface is a single Load(dir string) (*graph.DependencyGraph, error) method — see Contributing.
Capability taxonomy
All languages map to the same 9 capabilities. Risk level is derived from the total weight: LOW < 10, MEDIUM ≥ 10, HIGH ≥ 30.
| Capability |
Weight |
Meaning |
fs:read |
5 |
Reads from the filesystem |
fs:write |
10 |
Writes to or deletes files |
network |
15 |
Makes outbound network connections |
exec |
20 |
Spawns subprocesses or shell commands |
env |
5 |
Reads environment variables |
crypto |
5 |
Uses cryptographic primitives |
reflect |
5 |
Uses runtime reflection |
unsafe |
25 |
Bypasses memory/type safety (unsafe, eval, vm) |
plugin |
20 |
Loads or executes external code at runtime |
Capability detection per language
Go
Detects capabilities via static AST analysis of .go source files. Every detection records the source file, line number, the matched import path or call pattern, whether it was detected as an import or callSite, and a confidence score.
| Import / call |
Capabilities |
Confidence |
os, io/fs |
fs:read, fs:write |
90% (import) |
net, net/http |
network |
90% (import) |
os/exec |
exec |
90% (import) |
os.Getenv |
env |
90% (import) |
unsafe |
unsafe |
90% (import) |
crypto/* |
crypto |
90% (import) |
reflect |
reflect |
90% (import) |
plugin |
plugin |
90% (import) |
exec.Command( |
exec |
60% (callSite) |
http.Get(, http.Post( |
network |
60% (callSite) |
Node.js
Scans .js, .ts, .tsx, .mjs, .cjs files for require(), ESM import, and dynamic import() patterns. Also scans package.json install scripts (preinstall, install, postinstall) for shell invocations. Covers 120+ popular npm packages (AWS SDK, Firebase, Prisma, Stripe, socket.io, etc.).
| Import / call |
Capabilities |
Confidence |
fs, node:fs, fs/promises |
fs:read, fs:write |
90% (import) |
http, https, net, tls |
network |
90% (import) |
child_process, worker_threads, cluster |
exec |
90% (import) |
os, process |
env |
90% (import) |
crypto |
crypto |
90% (import) |
vm |
unsafe |
90% (import) |
module, dynamic import() |
plugin |
90% (import) |
eval(, new Function( |
unsafe |
60% (callSite) |
exec(, spawn(, fork( |
exec |
60% (callSite) |
fetch(, axios., got( |
network |
60% (callSite) |
readFile, writeFile, unlink( |
fs:read / fs:write |
60% (callSite) |
process.env |
env |
60% (callSite) |
preinstall/postinstall with curl/wget/bash |
exec + network |
85% (installScript) |
PHP
Scans .php source files for function call patterns and use statements. Parses composer.lock for the full dependency tree. Covers 80+ Composer packages and 150+ call-site patterns.
| Import / call |
Capabilities |
Confidence |
aws/aws-sdk-php |
network, fs:read, fs:write |
90% (import) |
laravel/framework |
network, fs:read, fs:write, env, exec, crypto |
90% (import) |
guzzlehttp/guzzle |
network |
90% (import) |
firebase/php-jwt, lcobucci/jwt |
crypto |
90% (import) |
symfony/process |
exec |
90% (import) |
monolog/monolog |
fs:write, network |
90% (import) |
exec(, shell_exec(, system( |
exec |
75% (callSite) |
eval(, unserialize(, parse_str(, extract( |
unsafe |
75% (callSite) |
curl_init(, fsockopen(, new PDO(, mysqli_connect( |
network |
75% (callSite) |
file_get_contents(, fopen(, glob( |
fs:read |
75% (callSite) |
file_put_contents(, unlink(, mkdir( |
fs:write |
75% (callSite) |
openssl_encrypt(, password_hash(, random_bytes( |
crypto |
75% (callSite) |
$_ENV, $_SERVER, getenv(, $_GET, $_POST, $_COOKIE |
env |
75% (callSite) |
Laravel facades: Storage::, Http::, Mail::, DB::, Artisan:: |
various |
75% (callSite) |
Cache::, Crypt::, Hash::, Log::, File::, Process:: |
various |
75% (callSite) |
dispatch(, event(, broadcast( |
exec / network |
75% (callSite) |
Commands
gorisk scan
Full scan: capabilities + health scoring + CVE listing + CI gate. Prints a graph checksum for reproducibility.
# Basic
gorisk scan
# Force language
gorisk scan --lang go
gorisk scan --lang node
# Output formats
gorisk scan --json
gorisk scan --sarif > results.sarif
# CI failure threshold
gorisk scan --fail-on medium # fail if any MEDIUM+ risk package
gorisk scan --fail-on low # strictest: fail on any capability
# Policy file (see Policy section below)
gorisk scan --policy .gorisk-policy.json
# Performance instrumentation
gorisk scan --timings
# Combination
gorisk scan --policy policy.json --fail-on high --json
Output (text):
graph checksum: a3f2b1c9d5e78f01
=== Capability Report ===
PACKAGE MODULE CAPABILITIES SCORE RISK
─────────────────────────────────────────────────────────────────────────────────
golang.org/x/net/http2 golang.org/x/net network 15 MEDIUM
os/exec stdlib exec 20 HIGH
=== Health Report ===
MODULE VERSION SCORE CVEs STATUS
─────────────────────────────────────────────────
golang.org/x/net v0.25.0 85 0 OK
✓ PASSED
--timings output (appended after normal output):
=== Timings ===
graph load 1.23s
capability detect 0.08s
health scoring 4.51s (24 modules, 10 workers)
github API 3.92s (48 calls)
osv API 0.59s (24 calls)
output formatting 0.01s
────────────────────────────────────────
total 5.83s
--json adds:
"graph_checksum" — short SHA-256 of the dependency graph for diffing between CI runs
gorisk scan --json | jq .graph_checksum
--sarif produces SARIF 2.1.0 compatible with GitHub Code Scanning (rules GORISK001 = high-risk capability, GORISK002 = low health score).
Exit codes: 0 = passed, 1 = policy failure, 2 = error.
gorisk explain
Show the evidence behind each capability detection — the exact file, line number, matched pattern, detection method, and confidence score.
# Show all capability evidence
gorisk explain
# Filter to a specific capability
gorisk explain --cap exec
gorisk explain --cap network
gorisk explain --cap unsafe
# Language-specific
gorisk explain --lang node
# JSON output (structured evidence for tooling)
gorisk explain --json
gorisk explain --cap exec --json
Text output:
=== Capability Evidence ===
exec
github.com/foo/bar
vendor/bar/run.go:42 exec.Command [callSite 60%]
vendor/bar/run.go:88 import "os/exec" [import 90%]
network
golang.org/x/net
net/http.go:12 import "net/http" [import 90%]
--json output: array of objects, one per (package, capability) pair:
[
{
"package": "github.com/foo/bar",
"module": "github.com/foo/bar",
"capability": "exec",
"evidence": [
{
"file": "/abs/path/run.go",
"line": 42,
"context": "exec.Command",
"via": "callSite",
"confidence": 0.6
}
]
}
]
via values:
import — the capability was detected from an import statement (confidence: 0.90)
callSite — detected from a function call pattern (confidence: 0.60)
installScript — detected in package.json install scripts (confidence: 0.85)
gorisk capabilities
List all packages and their detected capabilities with risk scores.
gorisk capabilities
gorisk capabilities --lang node
gorisk capabilities --lang go
# Filter by minimum risk level
gorisk capabilities --min-risk low # show everything (default)
gorisk capabilities --min-risk medium # MEDIUM and HIGH only
gorisk capabilities --min-risk high # HIGH only
# JSON output
gorisk capabilities --json
Text output:
=== Capability Report ===
PACKAGE MODULE CAPABILITIES SCORE RISK
─────────────────────────────────────────────────────────────────────────────────────────────────────────
golang.org/x/net/http2 golang.org/x/net network 15 MEDIUM
Exit code: 1 if any HIGH risk package was found (useful for set -e pipelines).
gorisk reachability
Proves whether risky capabilities are actually reachable from your code — not just present in a transitive dependency.
- Go: uses SSA callgraph analysis (Rapid Type Analysis) starting from all
main() and init() functions.
- Node.js: traces
require/import/import() paths from your project source files through the full dependency graph.
# Analyze all entrypoints
gorisk reachability
gorisk reachability --lang node
# Filter by minimum risk level
gorisk reachability --min-risk high # only show HIGH risk packages
gorisk reachability --min-risk medium
# Target a specific binary (Go)
gorisk reachability --entry cmd/server/main.go
gorisk reachability --entry cmd/worker/main.go
# Target a specific entrypoint (Node.js)
gorisk reachability --entry src/app.ts
gorisk reachability --entry src/worker.js
# Combine flags
gorisk reachability --entry cmd/server/main.go --min-risk high
gorisk reachability --lang node --entry src/app.ts --json
# JSON output
gorisk reachability --json
Text output:
golang.org/x/net/http2 HIGH REACHABLE
caps: network
os/exec HIGH unreachable
caps: exec
- REACHABLE (coloured by risk) — the capability is exercised from your
main() or entry file.
- unreachable (grey) — the package is in the graph but not called from your code.
--entry use case: In a monorepo with multiple binaries (cmd/api, cmd/worker, cmd/cron), each binary has a different reachable set. Targeting cmd/api/main.go shows only the capabilities reachable from the API service, helping you scope risk per binary.
--json output:
[
{
"package": "golang.org/x/net/http2",
"reachable": true,
"risk": "HIGH",
"score": 15,
"capabilities": ["network"]
}
]
gorisk graph
Compute transitive risk scores across the full dependency tree. Uses depth-weighted scoring: effective = direct + transitive/2 (capped at 100).
gorisk graph
gorisk graph --lang node
# Filter by minimum risk level
gorisk graph --min-risk medium
gorisk graph --min-risk high
# JSON output
gorisk graph --json
Output columns: Module | Direct score | Transitive score | Effective score | Depth | Risk level
gorisk diff
Compare capabilities between two versions of a dependency. Detects supply chain risk from capability escalation — if an update quietly added exec or network, this catches it.
gorisk diff golang.org/x/net@v0.20.0 golang.org/x/net@v0.25.0
gorisk diff --lang node lodash@4.17.20 lodash@4.17.21
gorisk diff --json golang.org/x/net@v0.20.0 golang.org/x/net@v0.25.0
Output: per-package diff showing capabilities added (+) and removed (-).
Exit codes: 0 = no escalation, 1 = escalation detected (exec/network/unsafe/plugin added).
gorisk upgrade
Check for breaking API changes before upgrading a dependency. Diffs exported function signatures between the current and target version.
gorisk upgrade golang.org/x/tools@v0.29.0
gorisk upgrade --lang node express@5.0.0
gorisk upgrade --json golang.org/x/tools@v0.29.0
Output: list of breaking changes (removed symbols, signature changes) and new transitive dependencies introduced by the upgrade.
gorisk impact
Simulate removing a module and compute its blast radius — how many packages and binaries depend on it, and how many lines of code are transitively affected.
gorisk impact golang.org/x/tools
gorisk impact golang.org/x/tools@v0.29.0 # specific version
gorisk impact --json golang.org/x/tools
gorisk impact --lang node lodash
Output:
=== Blast Radius Report ===
Module: golang.org/x/tools
Affected Packages: 42
Affected Binaries: 3
LOC Touched: 18200
Max Graph Depth: 5
Affected Binaries:
cmd/gorisk/main.go
cmd/scanner/main.go
cmd/indexer/main.go
gorisk sbom
Export a CycloneDX 1.4 SBOM with gorisk-specific extensions: capabilities per component, health score, and risk level.
gorisk sbom > sbom.json
gorisk sbom --lang node > sbom.json
gorisk sbom --format cyclonedx > sbom.json
Integrates with enterprise security platforms (Dependency-Track, FOSSA, etc.).
gorisk licenses
Detect license risk across all dependencies via GitHub API. Flags copyleft and unknown licenses.
gorisk licenses
gorisk licenses --lang node
gorisk licenses --json
# Fail pipeline if risky licenses found
gorisk licenses --fail-on-risky
Risky licenses (exit 1 with --fail-on-risky): GPL-2.0, GPL-3.0, AGPL-3.0, LGPL-2.1, LGPL-3.0, and unknown.
gorisk viz
Generate an interactive dependency risk graph as a single self-contained HTML file. No server required — works offline and is shareable by email or as a PR comment attachment.
gorisk viz > graph.html
gorisk viz --min-risk medium > graph.html
gorisk viz --lang node > graph.html
open graph.html
Graph features:
- Nodes coloured by risk — 🔴 HIGH ≥ 30 · 🟡 MEDIUM ≥ 10 · 🟢 LOW < 10
- Node size scales with risk score
- Hover a node to see its capabilities, score, file count, and import counts, with its edges highlighted
- Click a node to enter focus mode — neighbours animate into a ring around it, everything else dims; click again or empty space to exit
- Blast radius mode — highlights everything that depends on a clicked node (reverse reachability BFS)
- Path finder mode — click source then target to highlight the shortest dependency path
- Module cluster hulls — convex hulls group packages by module for visual organisation
- Capability filter — chip buttons to show only packages with specific capabilities (exec, network, fs:write, …)
- Dark mode — toggle in the settings panel (⚙)
- Filter by risk level using the chip buttons in the header
- Toggle edge visibility; edges shown faintly by default (hidden for very large graphs)
- Search packages by name or module
- Scroll to zoom, drag to pan, drag a node to pin it, double-click to unpin
- Reset button (⊙) zooms to fit all nodes
Large graphs (> 300 packages) use a phyllotaxis initial layout and freeze physics after settling to prevent jitter.
gorisk pr
Detects dependency changes between two git refs and reports new capabilities, capability escalation, and removed modules. Designed for pull request checks.
gorisk pr # diffs origin/main...HEAD
gorisk pr --lang node
gorisk pr --base origin/main --head HEAD
gorisk pr --json
Exit code: 1 if a new HIGH risk dependency was introduced (ideal as a CI gate on PRs).
gorisk history
Track dependency risk over time. Snapshots are stored in .gorisk-history.json (add to .gitignore). Up to 100 snapshots are retained.
gorisk history record
Snapshot the current risk state.
gorisk history record
gorisk history record --lang node
gorisk history record --lang go
Captures: timestamp, git commit hash, all modules with risk level, effective score, and capabilities.
gorisk history show
List all recorded snapshots with a trend column showing how HIGH-risk module count changed from the previous snapshot.
gorisk history show
gorisk history show --json
Text output:
# TIMESTAMP COMMIT MODULES HIGH MEDIUM LOW TREND
──────────────────────────────────────────────────────────────────────────────────────
1 2026-01-01T10:00:00Z a1b2c3d 12 2 4 6 —
2 2026-01-15T14:22:11Z f4e5d6c 13 3 5 5 ↑ +1H
3 2026-02-01T09:45:30Z 9a8b7c6 13 2 5 6 ↓ -1H
TREND column:
— — first snapshot or no HIGH-risk change from previous
↑ +NH (red) — HIGH-risk module count increased by N
↓ -NH (green) — HIGH-risk module count decreased by N
→ (grey) — same HIGH count, no change
gorisk history diff
Diff two snapshots to see what changed between them.
gorisk history diff # diff the last two snapshots
gorisk history diff N # diff snapshot N vs the latest
gorisk history diff N M # diff snapshot N vs snapshot M
gorisk history diff --json # JSON output
Text output:
drift 2026-01-01T10:00:00Z → 2026-02-01T09:45:30Z
+ github.com/some/new-dep MEDIUM
- github.com/old/removed-dep
↑ github.com/escalated/dep LOW → HIGH
↓ github.com/improved/dep HIGH → MEDIUM
added=1 removed=1 escalated=1 improved=1
Change types:
+ — new module (not in previous snapshot)
- — removed module
↑ — risk escalated (higher risk level or higher effective score)
↓ — risk improved (lower risk level or lower effective score)
gorisk history trend
Per-module score sparkline table showing how each module's effective risk score has evolved across the last 10 snapshots.
gorisk history trend
gorisk history trend --module redis # filter by module name substring
gorisk history trend --json
Text output:
MODULE TREND (last 10) FIRST LAST CHANGE
────────────────────────────────────────────────────────────────────────────────
github.com/redis/go-redis ▁▂▂▃▃▃▅▆▆▇ 12 45 +33 ↑
github.com/stretchr/testify ████████████ 8 8 0 →
golang.org/x/net ▃▃▂▂▂▁▁▁▁▁ 30 10 -20 ↓
Sparkline: 8 unicode block characters ▁▂▃▄▅▆▇█ represent score bands from 0–100.
--json output:
[
{
"module": "github.com/redis/go-redis",
"scores": [12, 18, 18, 24, 24, 24, 35, 40, 40, 45],
"first_score": 12,
"last_score": 45,
"change": 33
}
]
gorisk trace
Runtime execution tracing — instruments a Go package and records which capabilities are exercised at runtime (as opposed to statically detected).
gorisk trace <package> [args...]
gorisk trace --timeout 10s github.com/foo/bar
gorisk trace --json github.com/foo/bar
gorisk version
Print the gorisk version string.
gorisk version
Policy file
gorisk can enforce rules automatically via a JSON policy file. Unknown fields are rejected at parse time.
{
"version": 1,
"fail_on": "high",
"min_health_score": 0,
"max_health_score": 30,
"block_archived": false,
"deny_capabilities": ["exec", "plugin"],
"allow_exceptions": [
{ "package": "github.com/my/tool", "capabilities": ["exec"] }
],
"max_dep_depth": 0,
"exclude_packages": []
}
| Field |
Type |
Description |
version |
int |
Schema version — currently 1. Unsupported versions are rejected at startup. |
fail_on |
string |
Fail threshold: "low", "medium", or "high" (default: "high") |
min_health_score |
int |
Fail if any module's health score is below this (0 = disabled) |
max_health_score |
int |
Legacy field; kept for compatibility |
block_archived |
bool |
Fail if any dependency is archived on GitHub |
deny_capabilities |
[]string |
Block any package with these capabilities (e.g. ["exec", "network"]) |
allow_exceptions |
[]object |
Per-package exemptions from deny_capabilities |
max_dep_depth |
int |
Maximum allowed dependency depth (0 = unlimited) |
exclude_packages |
[]string |
Packages to skip entirely during scan |
allow_exceptions schema:
{ "package": "github.com/my/tool", "capabilities": ["exec", "network"] }
Graph checksum
Every gorisk scan computes a short, deterministic SHA-256 digest of the dependency graph:
graph checksum: a3f2b1c9d5e78f01
The checksum covers: all non-main module paths and versions, all package import paths, capability sets, and dependency edges — all sorted for stability across runs.
Use case: Detect silent graph changes between CI runs without diffing full output:
# Run on main
gorisk scan --json | jq -r .graph_checksum > checksum-main.txt
# Run on PR branch
gorisk scan --json | jq -r .graph_checksum > checksum-pr.txt
# Alert if different
diff checksum-main.txt checksum-pr.txt && echo "graph unchanged" || echo "graph changed!"
CI integration
GitHub Actions (official action)
- uses: 1homsi/gorisk@main
with:
fail-on: high # low | medium | high (default: high)
sarif: true # upload to GitHub Security tab (default: true)
lang: auto # auto | go | node (default: auto)
policy-file: '' # optional path to policy.json
Manual SARIF upload (GitHub Code Scanning)
- name: gorisk scan
run: gorisk scan --sarif --lang auto > gorisk.sarif || true
- uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: gorisk.sarif
PR gate (GitHub Actions)
- name: gorisk PR check
run: gorisk pr --lang auto
Full CI pipeline example
name: gorisk
on: [push, pull_request]
jobs:
gorisk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: stable }
- name: Install gorisk
run: go install github.com/1homsi/gorisk/cmd/gorisk@latest
- name: Scan with policy
run: gorisk scan --policy .gorisk-policy.json --sarif > gorisk.sarif
- uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: gorisk.sarif
- name: Record history snapshot
run: gorisk history record
- name: PR capability diff
if: github.event_name == 'pull_request'
run: gorisk pr
All commands that produce structured output support --json. The gorisk scan command additionally supports --sarif.
gorisk scan --json
{
"graph_checksum": "a3f2b1c9d5e78f01",
"Capabilities": [
{
"Package": "golang.org/x/net/http2",
"Module": "golang.org/x/net",
"Capabilities": { "Score": 15 },
"RiskLevel": "MEDIUM"
}
],
"Health": [
{
"Module": "golang.org/x/net",
"Version": "v0.25.0",
"Score": 85,
"Archived": false,
"CVECount": 0,
"CVEs": null,
"Signals": { "release_frequency": 15, "commit_age": 0 }
}
],
"Passed": true,
"FailReason": ""
}
gorisk explain --json
[
{
"package": "golang.org/x/net/http2",
"module": "golang.org/x/net",
"capability": "network",
"evidence": [
{
"file": "/path/to/h2_bundle.go",
"line": 47,
"context": "import \"net\"",
"via": "import",
"confidence": 0.9
}
]
}
]
gorisk reachability --json
[
{
"package": "golang.org/x/net/http2",
"reachable": true,
"risk": "HIGH",
"score": 15,
"capabilities": ["network"]
}
]
gorisk history trend --json
[
{
"module": "github.com/redis/go-redis",
"scores": [12, 18, 24, 30, 45],
"first_score": 12,
"last_score": 45,
"change": 33
}
]
Environment variables
| Variable |
Purpose |
GORISK_GITHUB_TOKEN |
GitHub personal access token for health scoring (higher API rate limits) |
Without a token, the GitHub API rate limit is 60 requests/hour. With a token, it is 5000/hour.
Setup for development
git clone https://github.com/1homsi/gorisk
cd gorisk
make setup # installs git hooks (runs golangci-lint on commit)
make build
make test
Contributing
Adding a new language requires two steps:
1. Graph loader — internal/adapters/<lang>/adapter.go
Implement the Analyzer interface:
type Analyzer interface {
Name() string
Load(dir string) (*graph.DependencyGraph, error)
}
Register it in internal/analyzer/analyzer.go → ForLang() switch and add a detection signal to detect().
To add capability evidence, call CapabilitySet.AddWithEvidence(cap, CapabilityEvidence{...}) instead of Add():
cs.AddWithEvidence(capability.CapExec, capability.CapabilityEvidence{
File: filePath,
Line: lineNo,
Context: "exec.Command(",
Via: "callSite",
Confidence: 0.60,
})
2. Feature implementations
Each feature package defines an interface + per-language structs:
| Package |
Interface |
Example impl |
internal/reachability |
Analyzer |
GoAnalyzer, NodeAnalyzer |
internal/upgrade |
Upgrader |
GoUpgrader, NodeUpgrader |
internal/upgrade |
CapDiffer |
GoCapDiffer, NodeCapDiffer |
internal/prdiff |
Differ |
GoDiffer, NodeDiffer |
The reachability.Analyzer interface has two methods:
type Analyzer interface {
Analyze(dir string) ([]ReachabilityReport, error)
AnalyzeFrom(dir, entryFile string) ([]ReachabilityReport, error)
}
Analyze should call AnalyzeFrom(dir, "").
Register everything in internal/analyzer/analyzer.go:
var registry = map[string]LangFeatures{
"go": { ... },
"node": { ... },
"rust": { // your new entry
Upgrade: upgrade.RustUpgrader{},
CapDiff: upgrade.RustCapDiffer{},
PRDiff: prdiff.RustDiffer{},
Reachability: reachability.RustAnalyzer{},
},
}
The capability taxonomy, all output formats, explain evidence, history tracking, and CLI flags come for free.