Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Makefile linguist-vendored
17 changes: 17 additions & 0 deletions .github/workflows/lint.go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Lint
permissions:
contents: read
on:
pull_request:
jobs:
lint:
name: Go Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Run Go golangci-lint
run: make lint
33 changes: 33 additions & 0 deletions .github/workflows/test.go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Test
permissions:
contents: read
on:
pull_request:
workflow_dispatch:
env:
OSV_VERSION: 'v2.2.2'
jobs:
test-x86:
name: Go Test
runs-on: ubuntu-latest
steps:
- name: apt-get update
run: |
sudo apt-get update
- name: install curl
run: |
sudo apt-get install -y curl
- name: install osv-scanner
run: |
echo "Installing OSV-Scanner version: ${{ env.OSV_VERSION }}"
curl -L --output /usr/local/bin/osv-scanner https://github.com/google/osv-scanner/releases/download/${{ env.OSV_VERSION }}/osv-scanner_linux_amd64
chmod +x /usr/local/bin/osv-scanner
echo "Verifying installation:"
osv-scanner --version
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Run Go tests
run: make test
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Ignore everything
*

# But not these files...
!.gitignore
!.gitattributes
!.github/**
!.vscode/*
!cmd/**
!docs/*
!examples/**
!wraith/**
!pkg/**

!*.go
!go.sum
!go.mod

!README.md
!LICENSE
!Makefile

# ...even if they are in subdirectories
!*/
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"cwd": "${workspaceFolder}",
"args": ["pkg/testdata/lockfiles/uv.lock"]
}
]
}
47 changes: 47 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Wraith Package Scanner Makefile
default: help

# Build configuration
BINARY_NAME = wraith
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
LDFLAGS = -ldflags "-X main.version=$(VERSION)"

.PHONY: help
help: ## Show this help
@echo "Usage: make [target]\n"
@cat ${MAKEFILE_LIST} | grep "[#]# " | grep -v grep | sort | column -t -s '##' | sed -e 's/^/ /'
@echo ""

.PHONY: deps
deps: ## Install Go dependencies
go mod download
go mod tidy

.PHONY: clean
clean: ## Clean test cache and tidy module
go clean -testcache
go mod tidy

.PHONY: test-all
test-all: ## Run all tests (unit + integration)
go test -v ./...

.PHONY: test
test: ## Run unit tests only (fast, no OSV-Scanner required)
go test -v ./pkg/... -short

.PHONY: test-integration
test-integration: ## Run integration tests (requires OSV-Scanner)
@which osv-scanner || (echo "❌ osv-scanner not found in PATH." && exit 1)
go test -v ./pkg/... -run "Integration"

.PHONY: test-demo
test-demo: ## Run live demo with real lockfiles
@which osv-scanner || (echo "❌ osv-scanner not found in PATH." && exit 1)
go test -v ./pkg/... -run "QuickScan"

.PHONY: lint
lint: ## Run linter
@which golangci-lint || go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
golangci-lint run

118 changes: 116 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,116 @@
# wraith
AI powered vulnerability scanner for package dependencies
![Wraith Logo](./docs/wraith.png)

# Wraith - Resurrected

A vulnerability scanner for package dependencies.

### Features

Just a wrapper around [osv-scanner](https://github.com/google/osv-scanner) with some convenience functions.

### Installation

```bash
go get github.com/ghostsecurity/wraith
```

### Basic Usage

```go
package main

import (
"fmt"
"log"

"github.com/ghostsecurity/wraith/pkg"
)

func main() {
// Quick scan - simplest usage
result, err := wraith.QuickScan("go.mod")
if err != nil {
log.Fatalf("Scan failed: %v", err)
}

fmt.Printf("Found %d packages with %d vulnerabilities\n",
result.GetPackageCount(),
result.GetVulnerabilityCount())
}
```

### Advanced Usage

```go
package main

import (
"fmt"
"log"
"time"

"github.com/ghostsecurity/wraith/pkg"
)

func main() {
// Create scanner with custom timeout
scanner, err := wraith.NewScanner()
if err != nil {
log.Fatalf("Failed to create scanner: %v", err)
}

// Set custom timeout
scanner.SetTimeout(10 * time.Minute)

// Scan lockfile
result, err := scanner.ScanLockfile("poetry.lock")
if err != nil {
log.Fatalf("Scan failed: %v", err)
}

// Process results
for _, pkg := range result.GetPackagesWithVulnerabilities() {
fmt.Printf("Package: %s v%s (%s)\n",
pkg.Package.Name,
pkg.Package.Version,
pkg.Package.Ecosystem)

for _, vuln := range pkg.Vulnerabilities {
fmt.Printf(" 🚨 %s: %s\n", vuln.ID, vuln.Summary)
}
}
}
```

### Pipeline Integration

```go
package main

import (
"log"

"github.com/ghostsecurity/wraith/pkg"
)

func analyzeLockfile(lockfilePath string) {
result, err := wraith.QuickScan(lockfilePath)
if err != nil {
log.Printf("ERROR: Failed to scan %s: %v", lockfilePath, err)
return
}

// Convert to simplified format for logging
simplified := result.ToSimplifiedResults()
for _, pkg := range simplified {
for _, vuln := range pkg.FoundVulnerabilities {
log.Printf("VULNERABILITY: %s in %s v%s (%s) - %s",
vuln.ID, pkg.Package, pkg.Version, pkg.Ecosystem, vuln.Summary)
}
}

if result.GetVulnerabilityCount() == 0 {
log.Printf("INFO: No vulnerabilities found in %s", lockfilePath)
}
}
```
74 changes: 74 additions & 0 deletions cmd/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Wraith Library Example

This example demonstrates how to import and use the wraith library.

## Running the Example

### Quick Start

```bash
go run ./cmd/example/main.go
```

### Scan a Specific Lockfile

```bash
# Scan a specific lockfile
go run ./cmd/example/main.go /path/to/go.mod
go run ./cmd/example/main.go /path/to/poetry.lock
go run ./cmd/example/main.go /path/to/yarn.lock
```

## What the Example Demonstrates

### 1. Quick Scan (Simplest Usage)

```go
result, err := wraith.QuickScan("go.mod")
```

### 2. Advanced Scanner Usage

```go
scanner, err := wraith.NewScanner()
scanner.SetTimeout(2 * time.Minute)
result, err := scanner.ScanLockfile("go.mod")
```

### 3. Detailed Vulnerability Analysis

- Package information
- Vulnerability details
- Severity levels
- CVE extraction

### 4. Simplified Results for Pipeline Integration

```go
simplified := result.ToSimplifiedResults()
```

## Expected Output

The example will show:

- Scan timing and performance
- Package and vulnerability counts
- Detailed vulnerability information
- Pipeline-ready simplified output
- Exit codes (0 = clean, 1 = vulnerabilities found)

## Integration Pattern

This example shows the recommended pattern for integrating wraith into your analysis pipeline:

1. **Quick Scan**: For simple vulnerability detection
2. **Advanced Scanner**: For custom timeouts and configuration
3. **Detailed Analysis**: For security reporting
4. **Simplified Output**: For logging and alerting systems

## Requirements

- Go 1.24.3+
- OSV-Scanner in PATH (`brew install osv-scanner`)
- A lockfile to scan (go.mod, poetry.lock, etc.)
Loading
Loading