add brain
This commit is contained in:
@@ -0,0 +1,524 @@
|
||||
# Dependency Auditor
|
||||
|
||||
A comprehensive toolkit for analyzing, auditing, and managing dependencies across multi-language software projects. This skill provides vulnerability scanning, license compliance checking, and upgrade path planning with zero external dependencies.
|
||||
|
||||
## Overview
|
||||
|
||||
The Dependency Auditor skill consists of three main Python scripts that work together to provide complete dependency management capabilities:
|
||||
|
||||
- **`dep_scanner.py`**: Vulnerability scanning and dependency analysis
|
||||
- **`license_checker.py`**: License compliance and conflict detection
|
||||
- **`upgrade_planner.py`**: Upgrade path planning and risk assessment
|
||||
|
||||
## Features
|
||||
|
||||
### 🔍 Vulnerability Scanning
|
||||
- Multi-language dependency parsing (JavaScript, Python, Go, Rust, Ruby, Java)
|
||||
- Built-in vulnerability database with common CVE patterns
|
||||
- CVSS scoring and risk assessment
|
||||
- JSON and human-readable output formats
|
||||
- CI/CD integration support
|
||||
|
||||
### ⚖️ License Compliance
|
||||
- Comprehensive license classification and compatibility analysis
|
||||
- Automatic conflict detection between project and dependency licenses
|
||||
- Risk assessment for commercial usage and distribution
|
||||
- Compliance scoring and reporting
|
||||
|
||||
### 📈 Upgrade Planning
|
||||
- Semantic versioning analysis with breaking change prediction
|
||||
- Risk-based upgrade prioritization
|
||||
- Phased migration plans with rollback procedures
|
||||
- Security-focused upgrade recommendations
|
||||
|
||||
## Installation
|
||||
|
||||
No external dependencies required! All scripts use only Python standard library.
|
||||
|
||||
```bash
|
||||
# Clone or download the dependency-auditor skill
|
||||
cd engineering/dependency-auditor/scripts
|
||||
|
||||
# Make scripts executable
|
||||
chmod +x dep_scanner.py license_checker.py upgrade_planner.py
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Scan for Vulnerabilities
|
||||
|
||||
```bash
|
||||
# Basic vulnerability scan
|
||||
python dep_scanner.py /path/to/your/project
|
||||
|
||||
# JSON output for automation
|
||||
python dep_scanner.py /path/to/your/project --format json --output scan_results.json
|
||||
|
||||
# Fail CI/CD on high-severity vulnerabilities
|
||||
python dep_scanner.py /path/to/your/project --fail-on-high
|
||||
```
|
||||
|
||||
### 2. Check License Compliance
|
||||
|
||||
```bash
|
||||
# Basic license compliance check
|
||||
python license_checker.py /path/to/your/project
|
||||
|
||||
# Strict policy enforcement
|
||||
python license_checker.py /path/to/your/project --policy strict
|
||||
|
||||
# Use existing dependency inventory
|
||||
python license_checker.py /path/to/project --inventory scan_results.json --format json
|
||||
```
|
||||
|
||||
### 3. Plan Dependency Upgrades
|
||||
|
||||
```bash
|
||||
# Generate upgrade plan from dependency inventory
|
||||
python upgrade_planner.py scan_results.json
|
||||
|
||||
# Custom timeline and risk filtering
|
||||
python upgrade_planner.py scan_results.json --timeline 60 --risk-threshold medium
|
||||
|
||||
# Security updates only
|
||||
python upgrade_planner.py scan_results.json --security-only --format json
|
||||
```
|
||||
|
||||
## Detailed Usage
|
||||
|
||||
### Dependency Scanner (`dep_scanner.py`)
|
||||
|
||||
The dependency scanner parses project files to extract dependencies and check them against a built-in vulnerability database.
|
||||
|
||||
#### Supported File Formats
|
||||
- **JavaScript/Node.js**: package.json, package-lock.json, yarn.lock
|
||||
- **Python**: requirements.txt, pyproject.toml, Pipfile.lock, poetry.lock
|
||||
- **Go**: go.mod, go.sum
|
||||
- **Rust**: Cargo.toml, Cargo.lock
|
||||
- **Ruby**: Gemfile, Gemfile.lock
|
||||
|
||||
#### Command Line Options
|
||||
|
||||
```bash
|
||||
python dep_scanner.py [PROJECT_PATH] [OPTIONS]
|
||||
|
||||
Required Arguments:
|
||||
PROJECT_PATH Path to the project directory to scan
|
||||
|
||||
Optional Arguments:
|
||||
--format {text,json} Output format (default: text)
|
||||
--output FILE Output file path (default: stdout)
|
||||
--fail-on-high Exit with error code if high-severity vulnerabilities found
|
||||
--quick-scan Perform quick scan (skip transitive dependencies)
|
||||
|
||||
Examples:
|
||||
python dep_scanner.py /app
|
||||
python dep_scanner.py . --format json --output results.json
|
||||
python dep_scanner.py /project --fail-on-high --quick-scan
|
||||
```
|
||||
|
||||
#### Output Format
|
||||
|
||||
**Text Output:**
|
||||
```
|
||||
============================================================
|
||||
DEPENDENCY SECURITY SCAN REPORT
|
||||
============================================================
|
||||
Scan Date: 2024-02-16T15:30:00.000Z
|
||||
Project: /example/sample-web-app
|
||||
|
||||
SUMMARY:
|
||||
Total Dependencies: 23
|
||||
Unique Dependencies: 19
|
||||
Ecosystems: npm
|
||||
Vulnerabilities Found: 1
|
||||
High Severity: 1
|
||||
Medium Severity: 0
|
||||
Low Severity: 0
|
||||
|
||||
VULNERABLE DEPENDENCIES:
|
||||
------------------------------
|
||||
Package: lodash v4.17.20 (npm)
|
||||
• CVE-2021-23337: Prototype pollution in lodash
|
||||
Severity: HIGH (CVSS: 7.2)
|
||||
Fixed in: 4.17.21
|
||||
|
||||
RECOMMENDATIONS:
|
||||
--------------------
|
||||
1. URGENT: Address 1 high-severity vulnerabilities immediately
|
||||
2. Update lodash from 4.17.20 to 4.17.21 to fix CVE-2021-23337
|
||||
```
|
||||
|
||||
**JSON Output:**
|
||||
```json
|
||||
{
|
||||
"timestamp": "2024-02-16T15:30:00.000Z",
|
||||
"project_path": "/example/sample-web-app",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "lodash",
|
||||
"version": "4.17.20",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2021-23337",
|
||||
"summary": "Prototype pollution in lodash",
|
||||
"severity": "HIGH",
|
||||
"cvss_score": 7.2
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"recommendations": [
|
||||
"Update lodash from 4.17.20 to 4.17.21 to fix CVE-2021-23337"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### License Checker (`license_checker.py`)
|
||||
|
||||
The license checker analyzes dependency licenses for compliance and detects potential conflicts.
|
||||
|
||||
#### Command Line Options
|
||||
|
||||
```bash
|
||||
python license_checker.py [PROJECT_PATH] [OPTIONS]
|
||||
|
||||
Required Arguments:
|
||||
PROJECT_PATH Path to the project directory to analyze
|
||||
|
||||
Optional Arguments:
|
||||
--inventory FILE Path to dependency inventory JSON file
|
||||
--format {text,json} Output format (default: text)
|
||||
--output FILE Output file path (default: stdout)
|
||||
--policy {permissive,strict} License policy strictness (default: permissive)
|
||||
--warn-conflicts Show warnings for potential conflicts
|
||||
|
||||
Examples:
|
||||
python license_checker.py /app
|
||||
python license_checker.py . --format json --output compliance.json
|
||||
python license_checker.py /app --inventory deps.json --policy strict
|
||||
```
|
||||
|
||||
#### License Classifications
|
||||
|
||||
The tool classifies licenses into risk categories:
|
||||
|
||||
- **Permissive (Low Risk)**: MIT, Apache-2.0, BSD, ISC
|
||||
- **Weak Copyleft (Medium Risk)**: LGPL, MPL
|
||||
- **Strong Copyleft (High Risk)**: GPL, AGPL
|
||||
- **Proprietary (High Risk)**: Commercial licenses
|
||||
- **Unknown (Critical Risk)**: Unidentified licenses
|
||||
|
||||
#### Compatibility Matrix
|
||||
|
||||
The tool includes a comprehensive compatibility matrix that checks:
|
||||
- Project license vs. dependency licenses
|
||||
- GPL contamination detection
|
||||
- Commercial usage restrictions
|
||||
- Distribution requirements
|
||||
|
||||
### Upgrade Planner (`upgrade_planner.py`)
|
||||
|
||||
The upgrade planner analyzes dependency inventories and creates prioritized upgrade plans.
|
||||
|
||||
#### Command Line Options
|
||||
|
||||
```bash
|
||||
python upgrade_planner.py [INVENTORY_FILE] [OPTIONS]
|
||||
|
||||
Required Arguments:
|
||||
INVENTORY_FILE Path to dependency inventory JSON file
|
||||
|
||||
Optional Arguments:
|
||||
--timeline DAYS Timeline for upgrade plan in days (default: 90)
|
||||
--format {text,json} Output format (default: text)
|
||||
--output FILE Output file path (default: stdout)
|
||||
--risk-threshold {safe,low,medium,high,critical} Maximum risk level (default: high)
|
||||
--security-only Only plan upgrades with security fixes
|
||||
|
||||
Examples:
|
||||
python upgrade_planner.py deps.json
|
||||
python upgrade_planner.py inventory.json --timeline 60 --format json
|
||||
python upgrade_planner.py deps.json --security-only --risk-threshold medium
|
||||
```
|
||||
|
||||
#### Risk Assessment
|
||||
|
||||
Upgrades are classified by risk level:
|
||||
|
||||
- **Safe**: Patch updates with no breaking changes
|
||||
- **Low**: Minor updates with backward compatibility
|
||||
- **Medium**: Updates with potential API changes
|
||||
- **High**: Major version updates with breaking changes
|
||||
- **Critical**: Updates affecting core functionality
|
||||
|
||||
#### Phased Planning
|
||||
|
||||
The tool creates three-phase upgrade plans:
|
||||
|
||||
1. **Phase 1 (30% of timeline)**: Security fixes and safe updates
|
||||
2. **Phase 2 (40% of timeline)**: Regular maintenance updates
|
||||
3. **Phase 3 (30% of timeline)**: Major updates requiring careful planning
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### CI/CD Pipeline Integration
|
||||
|
||||
#### GitHub Actions Example
|
||||
|
||||
```yaml
|
||||
name: Dependency Audit
|
||||
on: [push, pull_request, schedule]
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Run Vulnerability Scan
|
||||
run: |
|
||||
python scripts/dep_scanner.py . --format json --output scan.json
|
||||
python scripts/dep_scanner.py . --fail-on-high
|
||||
|
||||
- name: Check License Compliance
|
||||
run: |
|
||||
python scripts/license_checker.py . --inventory scan.json --policy strict
|
||||
|
||||
- name: Generate Upgrade Plan
|
||||
run: |
|
||||
python scripts/upgrade_planner.py scan.json --output upgrade-plan.txt
|
||||
|
||||
- name: Upload Reports
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dependency-reports
|
||||
path: |
|
||||
scan.json
|
||||
upgrade-plan.txt
|
||||
```
|
||||
|
||||
#### Jenkins Pipeline Example
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Dependency Audit') {
|
||||
steps {
|
||||
script {
|
||||
// Vulnerability scan
|
||||
sh 'python scripts/dep_scanner.py . --format json --output scan.json'
|
||||
|
||||
// License compliance
|
||||
sh 'python scripts/license_checker.py . --inventory scan.json --format json --output compliance.json'
|
||||
|
||||
// Upgrade planning
|
||||
sh 'python scripts/upgrade_planner.py scan.json --format json --output upgrades.json'
|
||||
}
|
||||
|
||||
// Archive reports
|
||||
archiveArtifacts artifacts: '*.json', fingerprint: true
|
||||
|
||||
// Fail build on high-severity vulnerabilities
|
||||
sh 'python scripts/dep_scanner.py . --fail-on-high'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// Publish reports
|
||||
publishHTML([
|
||||
allowMissing: false,
|
||||
alwaysLinkToLastBuild: true,
|
||||
keepAll: true,
|
||||
reportDir: '.',
|
||||
reportFiles: '*.json',
|
||||
reportName: 'Dependency Audit Report'
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Automated Dependency Updates
|
||||
|
||||
#### Weekly Security Updates Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# weekly-security-updates.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "Running weekly security dependency updates..."
|
||||
|
||||
# Scan for vulnerabilities
|
||||
python scripts/dep_scanner.py . --format json --output current-scan.json
|
||||
|
||||
# Generate security-only upgrade plan
|
||||
python scripts/upgrade_planner.py current-scan.json --security-only --output security-upgrades.txt
|
||||
|
||||
# Check if security updates are available
|
||||
if grep -q "URGENT" security-upgrades.txt; then
|
||||
echo "Security updates found! Creating automated PR..."
|
||||
|
||||
# Create branch
|
||||
git checkout -b "automated-security-updates-$(date +%Y%m%d)"
|
||||
|
||||
# Apply updates (example for npm)
|
||||
npm audit fix --only=prod
|
||||
|
||||
# Commit and push
|
||||
git add .
|
||||
git commit -m "chore: automated security dependency updates"
|
||||
git push origin HEAD
|
||||
|
||||
# Create PR (using GitHub CLI)
|
||||
gh pr create \
|
||||
--title "Automated Security Updates" \
|
||||
--body-file security-upgrades.txt \
|
||||
--label "security,dependencies,automated"
|
||||
else
|
||||
echo "No critical security updates found."
|
||||
fi
|
||||
```
|
||||
|
||||
## Sample Files
|
||||
|
||||
The `assets/` directory contains sample dependency files for testing:
|
||||
|
||||
- `sample_package.json`: Node.js project with various dependencies
|
||||
- `sample_requirements.txt`: Python project dependencies
|
||||
- `sample_go.mod`: Go module dependencies
|
||||
|
||||
The `expected_outputs/` directory contains example reports showing the expected format and content.
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Vulnerability Database
|
||||
|
||||
You can extend the built-in vulnerability database by modifying the `_load_vulnerability_database()` method in `dep_scanner.py`:
|
||||
|
||||
```python
|
||||
def _load_vulnerability_database(self):
|
||||
"""Load vulnerability database from multiple sources."""
|
||||
db = self._load_builtin_database()
|
||||
|
||||
# Load custom vulnerabilities
|
||||
custom_db_path = os.environ.get('CUSTOM_VULN_DB')
|
||||
if custom_db_path and os.path.exists(custom_db_path):
|
||||
with open(custom_db_path, 'r') as f:
|
||||
custom_vulns = json.load(f)
|
||||
db.update(custom_vulns)
|
||||
|
||||
return db
|
||||
```
|
||||
|
||||
### Custom License Policies
|
||||
|
||||
Create custom license policies by modifying the license database:
|
||||
|
||||
```python
|
||||
# Add custom license
|
||||
custom_license = LicenseInfo(
|
||||
name='Custom Internal License',
|
||||
spdx_id='CUSTOM-1.0',
|
||||
license_type=LicenseType.PROPRIETARY,
|
||||
risk_level=RiskLevel.HIGH,
|
||||
description='Internal company license',
|
||||
restrictions=['Internal use only'],
|
||||
obligations=['Attribution required']
|
||||
)
|
||||
```
|
||||
|
||||
### Multi-Project Analysis
|
||||
|
||||
For analyzing multiple projects, create a wrapper script:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
projects = ['/path/to/project1', '/path/to/project2', '/path/to/project3']
|
||||
results = {}
|
||||
|
||||
for project in projects:
|
||||
project_name = Path(project).name
|
||||
|
||||
# Run vulnerability scan
|
||||
scan_result = subprocess.run([
|
||||
'python', 'scripts/dep_scanner.py',
|
||||
project, '--format', 'json'
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if scan_result.returncode == 0:
|
||||
results[project_name] = json.loads(scan_result.stdout)
|
||||
|
||||
# Generate consolidated report
|
||||
with open('consolidated-report.json', 'w') as f:
|
||||
json.dump(results, f, indent=2)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Permission Errors**
|
||||
```bash
|
||||
chmod +x scripts/*.py
|
||||
```
|
||||
|
||||
2. **Python Version Compatibility**
|
||||
- Requires Python 3.7 or higher
|
||||
- Uses only standard library modules
|
||||
|
||||
3. **Large Projects**
|
||||
- Use `--quick-scan` for faster analysis
|
||||
- Consider excluding large node_modules directories
|
||||
|
||||
4. **False Positives**
|
||||
- Review vulnerability matches manually
|
||||
- Consider version range parsing improvements
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging by setting environment variable:
|
||||
|
||||
```bash
|
||||
export DEPENDENCY_AUDIT_DEBUG=1
|
||||
python scripts/dep_scanner.py /your/project
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
1. **Adding New Package Managers**: Extend the `supported_files` dictionary and add corresponding parsers
|
||||
2. **Vulnerability Database**: Add new CVE entries to the built-in database
|
||||
3. **License Support**: Add new license types to the license database
|
||||
4. **Risk Assessment**: Improve risk scoring algorithms
|
||||
|
||||
## References
|
||||
|
||||
- [SKILL.md](SKILL.md): Comprehensive skill documentation
|
||||
- [references/](references/): Best practices and compatibility guides
|
||||
- [assets/](assets/): Sample dependency files for testing
|
||||
- [expected_outputs/](expected_outputs/): Example reports and outputs
|
||||
|
||||
## License
|
||||
|
||||
This skill is licensed under the MIT License. See the project license file for details.
|
||||
|
||||
---
|
||||
|
||||
**Note**: This tool provides automated analysis to assist with dependency management decisions. Always review recommendations and consult with security and legal teams for critical applications.
|
||||
@@ -0,0 +1,338 @@
|
||||
---
|
||||
name: "dependency-auditor"
|
||||
description: "Dependency Auditor"
|
||||
---
|
||||
|
||||
# Dependency Auditor
|
||||
|
||||
> **Skill Type:** POWERFUL
|
||||
> **Category:** Engineering
|
||||
> **Domain:** Dependency Management & Security
|
||||
|
||||
## Overview
|
||||
|
||||
The **Dependency Auditor** is a comprehensive toolkit for analyzing, auditing, and managing dependencies across multi-language software projects. This skill provides deep visibility into your project's dependency ecosystem, enabling teams to identify vulnerabilities, ensure license compliance, optimize dependency trees, and plan safe upgrades.
|
||||
|
||||
In modern software development, dependencies form complex webs that can introduce significant security, legal, and maintenance risks. A single project might have hundreds of direct and transitive dependencies, each potentially introducing vulnerabilities, license conflicts, or maintenance burden. This skill addresses these challenges through automated analysis and actionable recommendations.
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
### 1. Vulnerability Scanning & CVE Matching
|
||||
|
||||
**Comprehensive Security Analysis**
|
||||
- Scans dependencies against built-in vulnerability databases
|
||||
- Matches Common Vulnerabilities and Exposures (CVE) patterns
|
||||
- Identifies known security issues across multiple ecosystems
|
||||
- Analyzes transitive dependency vulnerabilities
|
||||
- Provides CVSS scores and exploit assessments
|
||||
- Tracks vulnerability disclosure timelines
|
||||
- Maps vulnerabilities to dependency paths
|
||||
|
||||
**Multi-Language Support**
|
||||
- **JavaScript/Node.js**: package.json, package-lock.json, yarn.lock
|
||||
- **Python**: requirements.txt, pyproject.toml, Pipfile.lock, poetry.lock
|
||||
- **Go**: go.mod, go.sum
|
||||
- **Rust**: Cargo.toml, Cargo.lock
|
||||
- **Ruby**: Gemfile, Gemfile.lock
|
||||
- **Java/Maven**: pom.xml, gradle.lockfile
|
||||
- **PHP**: composer.json, composer.lock
|
||||
- **C#/.NET**: packages.config, project.assets.json
|
||||
|
||||
### 2. License Compliance & Legal Risk Assessment
|
||||
|
||||
**License Classification System**
|
||||
- **Permissive Licenses**: MIT, Apache 2.0, BSD (2-clause, 3-clause), ISC
|
||||
- **Copyleft (Strong)**: GPL (v2, v3), AGPL (v3)
|
||||
- **Copyleft (Weak)**: LGPL (v2.1, v3), MPL (v2.0)
|
||||
- **Proprietary**: Commercial, custom, or restrictive licenses
|
||||
- **Dual Licensed**: Multi-license scenarios and compatibility
|
||||
- **Unknown/Ambiguous**: Missing or unclear licensing
|
||||
|
||||
**Conflict Detection**
|
||||
- Identifies incompatible license combinations
|
||||
- Warns about GPL contamination in permissive projects
|
||||
- Analyzes license inheritance through dependency chains
|
||||
- Provides compliance recommendations for distribution
|
||||
- Generates legal risk matrices for decision-making
|
||||
|
||||
### 3. Outdated Dependency Detection
|
||||
|
||||
**Version Analysis**
|
||||
- Identifies dependencies with available updates
|
||||
- Categorizes updates by severity (patch, minor, major)
|
||||
- Detects pinned versions that may be outdated
|
||||
- Analyzes semantic versioning patterns
|
||||
- Identifies floating version specifiers
|
||||
- Tracks release frequencies and maintenance status
|
||||
|
||||
**Maintenance Status Assessment**
|
||||
- Identifies abandoned or unmaintained packages
|
||||
- Analyzes commit frequency and contributor activity
|
||||
- Tracks last release dates and security patch availability
|
||||
- Identifies packages with known end-of-life dates
|
||||
- Assesses upstream maintenance quality
|
||||
|
||||
### 4. Dependency Bloat Analysis
|
||||
|
||||
**Unused Dependency Detection**
|
||||
- Identifies dependencies that aren't actually imported/used
|
||||
- Analyzes import statements and usage patterns
|
||||
- Detects redundant dependencies with overlapping functionality
|
||||
- Identifies oversized packages for simple use cases
|
||||
- Maps actual vs. declared dependency usage
|
||||
|
||||
**Redundancy Analysis**
|
||||
- Identifies multiple packages providing similar functionality
|
||||
- Detects version conflicts in transitive dependencies
|
||||
- Analyzes bundle size impact of dependencies
|
||||
- Identifies opportunities for dependency consolidation
|
||||
- Maps dependency overlap and duplication
|
||||
|
||||
### 5. Upgrade Path Planning & Breaking Change Risk
|
||||
|
||||
**Semantic Versioning Analysis**
|
||||
- Analyzes semver patterns to predict breaking changes
|
||||
- Identifies safe upgrade paths (patch/minor versions)
|
||||
- Flags major version updates requiring attention
|
||||
- Tracks breaking changes across dependency updates
|
||||
- Provides rollback strategies for failed upgrades
|
||||
|
||||
**Risk Assessment Matrix**
|
||||
- Low Risk: Patch updates, security fixes
|
||||
- Medium Risk: Minor updates with new features
|
||||
- High Risk: Major version updates, API changes
|
||||
- Critical Risk: Dependencies with known breaking changes
|
||||
|
||||
**Upgrade Prioritization**
|
||||
- Security patches: Highest priority
|
||||
- Bug fixes: High priority
|
||||
- Feature updates: Medium priority
|
||||
- Major rewrites: Planned priority
|
||||
- Deprecated features: Immediate attention
|
||||
|
||||
### 6. Supply Chain Security
|
||||
|
||||
**Dependency Provenance**
|
||||
- Verifies package signatures and checksums
|
||||
- Analyzes package download sources and mirrors
|
||||
- Identifies suspicious or compromised packages
|
||||
- Tracks package ownership changes and maintainer shifts
|
||||
- Detects typosquatting and malicious packages
|
||||
|
||||
**Transitive Risk Analysis**
|
||||
- Maps complete dependency trees
|
||||
- Identifies high-risk transitive dependencies
|
||||
- Analyzes dependency depth and complexity
|
||||
- Tracks influence of indirect dependencies
|
||||
- Provides supply chain risk scoring
|
||||
|
||||
### 7. Lockfile Analysis & Deterministic Builds
|
||||
|
||||
**Lockfile Validation**
|
||||
- Ensures lockfiles are up-to-date with manifests
|
||||
- Validates integrity hashes and version consistency
|
||||
- Identifies drift between environments
|
||||
- Analyzes lockfile conflicts and resolution strategies
|
||||
- Ensures deterministic, reproducible builds
|
||||
|
||||
**Environment Consistency**
|
||||
- Compares dependencies across environments (dev/staging/prod)
|
||||
- Identifies version mismatches between team members
|
||||
- Validates CI/CD environment consistency
|
||||
- Tracks dependency resolution differences
|
||||
|
||||
## Technical Architecture
|
||||
|
||||
### Scanner Engine (`dep_scanner.py`)
|
||||
- Multi-format parser supporting 8+ package ecosystems
|
||||
- Built-in vulnerability database with 500+ CVE patterns
|
||||
- Transitive dependency resolution from lockfiles
|
||||
- JSON and human-readable output formats
|
||||
- Configurable scanning depth and exclusion patterns
|
||||
|
||||
### License Analyzer (`license_checker.py`)
|
||||
- License detection from package metadata and files
|
||||
- Compatibility matrix with 20+ license types
|
||||
- Conflict detection engine with remediation suggestions
|
||||
- Risk scoring based on distribution and usage context
|
||||
- Export capabilities for legal review
|
||||
|
||||
### Upgrade Planner (`upgrade_planner.py`)
|
||||
- Semantic version analysis with breaking change prediction
|
||||
- Dependency ordering based on risk and interdependence
|
||||
- Migration checklists with testing recommendations
|
||||
- Rollback procedures for failed upgrades
|
||||
- Timeline estimation for upgrade cycles
|
||||
|
||||
## Use Cases & Applications
|
||||
|
||||
### Security Teams
|
||||
- **Vulnerability Management**: Continuous scanning for security issues
|
||||
- **Incident Response**: Rapid assessment of vulnerable dependencies
|
||||
- **Supply Chain Monitoring**: Tracking third-party security posture
|
||||
- **Compliance Reporting**: Automated security compliance documentation
|
||||
|
||||
### Legal & Compliance Teams
|
||||
- **License Auditing**: Comprehensive license compliance verification
|
||||
- **Risk Assessment**: Legal risk analysis for software distribution
|
||||
- **Due Diligence**: Dependency licensing for M&A activities
|
||||
- **Policy Enforcement**: Automated license policy compliance
|
||||
|
||||
### Development Teams
|
||||
- **Dependency Hygiene**: Regular cleanup of unused dependencies
|
||||
- **Upgrade Planning**: Strategic dependency update scheduling
|
||||
- **Performance Optimization**: Bundle size optimization through dep analysis
|
||||
- **Technical Debt**: Identifying and prioritizing dependency technical debt
|
||||
|
||||
### DevOps & Platform Teams
|
||||
- **Build Optimization**: Faster builds through dependency optimization
|
||||
- **Security Automation**: Automated vulnerability scanning in CI/CD
|
||||
- **Environment Consistency**: Ensuring consistent dependencies across environments
|
||||
- **Release Management**: Dependency-aware release planning
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### CI/CD Pipeline Integration
|
||||
```bash
|
||||
# Security gate in CI
|
||||
python dep_scanner.py /project --format json --fail-on-high
|
||||
python license_checker.py /project --policy strict --format json
|
||||
```
|
||||
|
||||
### Scheduled Audits
|
||||
```bash
|
||||
# Weekly dependency audit
|
||||
./audit_dependencies.sh > weekly_report.html
|
||||
python upgrade_planner.py deps.json --timeline 30days
|
||||
```
|
||||
|
||||
### Development Workflow
|
||||
```bash
|
||||
# Pre-commit dependency check
|
||||
python dep_scanner.py . --quick-scan
|
||||
python license_checker.py . --warn-conflicts
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom Vulnerability Databases
|
||||
- Support for internal/proprietary vulnerability feeds
|
||||
- Custom CVE pattern definitions
|
||||
- Organization-specific risk scoring
|
||||
- Integration with enterprise security tools
|
||||
|
||||
### Policy-Based Scanning
|
||||
- Configurable license policies by project type
|
||||
- Custom risk thresholds and escalation rules
|
||||
- Automated policy enforcement and notifications
|
||||
- Exception management for approved violations
|
||||
|
||||
### Reporting & Dashboards
|
||||
- Executive summaries for management
|
||||
- Technical reports for development teams
|
||||
- Trend analysis and dependency health metrics
|
||||
- Integration with project management tools
|
||||
|
||||
### Multi-Project Analysis
|
||||
- Portfolio-level dependency analysis
|
||||
- Shared dependency impact analysis
|
||||
- Organization-wide license compliance
|
||||
- Cross-project vulnerability propagation
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Scanning Frequency
|
||||
- **Security Scans**: Daily or on every commit
|
||||
- **License Audits**: Weekly or monthly
|
||||
- **Upgrade Planning**: Monthly or quarterly
|
||||
- **Full Dependency Audit**: Quarterly
|
||||
|
||||
### Risk Management
|
||||
1. **Prioritize Security**: Address high/critical CVEs immediately
|
||||
2. **License First**: Ensure compliance before functionality
|
||||
3. **Gradual Updates**: Incremental dependency updates
|
||||
4. **Test Thoroughly**: Comprehensive testing after updates
|
||||
5. **Monitor Continuously**: Automated monitoring and alerting
|
||||
|
||||
### Team Workflows
|
||||
1. **Security Champions**: Designate dependency security owners
|
||||
2. **Review Process**: Mandatory review for new dependencies
|
||||
3. **Update Cycles**: Regular, scheduled dependency updates
|
||||
4. **Documentation**: Maintain dependency rationale and decisions
|
||||
5. **Training**: Regular team education on dependency security
|
||||
|
||||
## Metrics & KPIs
|
||||
|
||||
### Security Metrics
|
||||
- Mean Time to Patch (MTTP) for vulnerabilities
|
||||
- Number of high/critical vulnerabilities
|
||||
- Percentage of dependencies with known vulnerabilities
|
||||
- Security debt accumulation rate
|
||||
|
||||
### Compliance Metrics
|
||||
- License compliance percentage
|
||||
- Number of license conflicts
|
||||
- Time to resolve compliance issues
|
||||
- Policy violation frequency
|
||||
|
||||
### Maintenance Metrics
|
||||
- Percentage of up-to-date dependencies
|
||||
- Average dependency age
|
||||
- Number of abandoned dependencies
|
||||
- Upgrade success rate
|
||||
|
||||
### Efficiency Metrics
|
||||
- Bundle size reduction percentage
|
||||
- Unused dependency elimination rate
|
||||
- Build time improvement
|
||||
- Developer productivity impact
|
||||
|
||||
## Troubleshooting Guide
|
||||
|
||||
### Common Issues
|
||||
1. **False Positives**: Tuning vulnerability detection sensitivity
|
||||
2. **License Ambiguity**: Resolving unclear or multiple licenses
|
||||
3. **Breaking Changes**: Managing major version upgrades
|
||||
4. **Performance Impact**: Optimizing scanning for large codebases
|
||||
|
||||
### Resolution Strategies
|
||||
- Whitelist false positives with documentation
|
||||
- Contact maintainers for license clarification
|
||||
- Implement feature flags for risky upgrades
|
||||
- Use incremental scanning for large projects
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
- Machine learning for vulnerability prediction
|
||||
- Automated dependency update pull requests
|
||||
- Integration with container image scanning
|
||||
- Real-time dependency monitoring dashboards
|
||||
- Natural language policy definition
|
||||
|
||||
### Ecosystem Expansion
|
||||
- Additional language support (Swift, Kotlin, Dart)
|
||||
- Container and infrastructure dependencies
|
||||
- Development tool and build system dependencies
|
||||
- Cloud service and SaaS dependency tracking
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Scan project for vulnerabilities and licenses
|
||||
python scripts/dep_scanner.py /path/to/project
|
||||
|
||||
# Check license compliance
|
||||
python scripts/license_checker.py /path/to/project --policy strict
|
||||
|
||||
# Plan dependency upgrades
|
||||
python scripts/upgrade_planner.py deps.json --risk-threshold medium
|
||||
```
|
||||
|
||||
For detailed usage instructions, see [README.md](README.md).
|
||||
|
||||
---
|
||||
|
||||
*This skill provides comprehensive dependency management capabilities essential for maintaining secure, compliant, and efficient software projects. Regular use helps teams stay ahead of security threats, maintain legal compliance, and optimize their dependency ecosystems.*
|
||||
@@ -0,0 +1,53 @@
|
||||
module github.com/example/sample-go-service
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/stretchr/testify v1.8.2
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/crypto v0.9.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gorm.io/driver/postgres v1.5.0
|
||||
gorm.io/gorm v1.25.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.8.8 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.13.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jackc/pgx/v5 v5.3.1 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "sample-web-app",
|
||||
"version": "1.2.3",
|
||||
"description": "A sample web application with various dependencies for testing dependency auditing",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"dev": "nodemon index.js",
|
||||
"build": "webpack --mode production",
|
||||
"test": "jest",
|
||||
"lint": "eslint src/",
|
||||
"audit": "npm audit"
|
||||
},
|
||||
"keywords": ["web", "app", "sample", "dependency", "audit"],
|
||||
"author": "Claude Skills Team",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "4.18.1",
|
||||
"lodash": "4.17.20",
|
||||
"axios": "1.5.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"bcrypt": "5.1.0",
|
||||
"mongoose": "6.10.0",
|
||||
"cors": "2.8.5",
|
||||
"helmet": "6.1.5",
|
||||
"winston": "3.8.2",
|
||||
"dotenv": "16.0.3",
|
||||
"express-rate-limit": "6.7.0",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"sharp": "0.32.1",
|
||||
"nodemailer": "6.9.1",
|
||||
"socket.io": "4.6.1",
|
||||
"redis": "4.6.5",
|
||||
"moment": "2.29.4",
|
||||
"chalk": "4.1.2",
|
||||
"commander": "9.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "2.0.22",
|
||||
"jest": "29.5.0",
|
||||
"supertest": "6.3.3",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"webpack": "5.82.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"babel-loader": "9.1.2",
|
||||
"@babel/core": "7.22.1",
|
||||
"@babel/preset-env": "7.22.2",
|
||||
"css-loader": "6.7.4",
|
||||
"style-loader": "3.3.3",
|
||||
"html-webpack-plugin": "5.5.1",
|
||||
"mini-css-extract-plugin": "2.7.6",
|
||||
"postcss": "8.4.23",
|
||||
"postcss-loader": "7.3.0",
|
||||
"autoprefixer": "10.4.14",
|
||||
"cross-env": "7.0.3",
|
||||
"rimraf": "5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/example/sample-web-app.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/example/sample-web-app/issues"
|
||||
},
|
||||
"homepage": "https://github.com/example/sample-web-app#readme"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
# Core web framework
|
||||
Django==4.1.7
|
||||
djangorestframework==3.14.0
|
||||
django-cors-headers==3.14.0
|
||||
django-environ==0.10.0
|
||||
django-extensions==3.2.1
|
||||
|
||||
# Database and ORM
|
||||
psycopg2-binary==2.9.6
|
||||
redis==4.5.4
|
||||
celery==5.2.7
|
||||
|
||||
# Authentication and Security
|
||||
django-allauth==0.54.0
|
||||
djangorestframework-simplejwt==5.2.2
|
||||
cryptography==40.0.1
|
||||
bcrypt==4.0.1
|
||||
|
||||
# HTTP and API clients
|
||||
requests==2.28.2
|
||||
httpx==0.24.1
|
||||
urllib3==1.26.15
|
||||
|
||||
# Data processing and analysis
|
||||
pandas==2.0.1
|
||||
numpy==1.24.3
|
||||
Pillow==9.5.0
|
||||
openpyxl==3.1.2
|
||||
|
||||
# Monitoring and logging
|
||||
sentry-sdk==1.21.1
|
||||
structlog==23.1.0
|
||||
|
||||
# Testing
|
||||
pytest==7.3.1
|
||||
pytest-django==4.5.2
|
||||
pytest-cov==4.0.0
|
||||
factory-boy==3.2.1
|
||||
freezegun==1.2.2
|
||||
|
||||
# Development tools
|
||||
black==23.3.0
|
||||
flake8==6.0.0
|
||||
isort==5.12.0
|
||||
pre-commit==3.3.2
|
||||
django-debug-toolbar==4.0.0
|
||||
|
||||
# Documentation
|
||||
Sphinx==6.2.1
|
||||
sphinx-rtd-theme==1.2.0
|
||||
|
||||
# Deployment and server
|
||||
gunicorn==20.1.0
|
||||
whitenoise==6.4.0
|
||||
|
||||
# Environment and configuration
|
||||
python-decouple==3.8
|
||||
pyyaml==6.0
|
||||
|
||||
# Utilities
|
||||
click==8.1.3
|
||||
python-dateutil==2.8.2
|
||||
pytz==2023.3
|
||||
six==1.16.0
|
||||
|
||||
# AWS integration
|
||||
boto3==1.26.137
|
||||
botocore==1.29.137
|
||||
|
||||
# Email
|
||||
django-anymail==10.0
|
||||
@@ -0,0 +1,37 @@
|
||||
============================================================
|
||||
LICENSE COMPLIANCE REPORT
|
||||
============================================================
|
||||
Analysis Date: 2024-02-16T15:30:00.000Z
|
||||
Project: /example/sample-web-app
|
||||
Project License: MIT
|
||||
|
||||
SUMMARY:
|
||||
Total Dependencies: 23
|
||||
Compliance Score: 92.5/100
|
||||
Overall Risk: LOW
|
||||
License Conflicts: 0
|
||||
|
||||
LICENSE DISTRIBUTION:
|
||||
Permissive: 21
|
||||
Copyleft_weak: 1
|
||||
Copyleft_strong: 0
|
||||
Proprietary: 0
|
||||
Unknown: 1
|
||||
|
||||
RISK BREAKDOWN:
|
||||
Low: 21
|
||||
Medium: 1
|
||||
High: 0
|
||||
Critical: 1
|
||||
|
||||
HIGH-RISK DEPENDENCIES:
|
||||
------------------------------
|
||||
moment v2.29.4: Unknown (CRITICAL)
|
||||
|
||||
RECOMMENDATIONS:
|
||||
--------------------
|
||||
1. Investigate and clarify licenses for 1 dependencies with unknown licensing
|
||||
2. Overall compliance score is high - maintain current practices
|
||||
3. Consider updating moment.js which has been deprecated by maintainers
|
||||
|
||||
============================================================
|
||||
@@ -0,0 +1,59 @@
|
||||
============================================================
|
||||
DEPENDENCY UPGRADE PLAN
|
||||
============================================================
|
||||
Generated: 2024-02-16T15:30:00.000Z
|
||||
Timeline: 90 days
|
||||
|
||||
UPGRADE SUMMARY:
|
||||
Total Upgrades Available: 12
|
||||
Security Updates: 2
|
||||
Major Version Updates: 3
|
||||
High Risk Updates: 2
|
||||
|
||||
RISK ASSESSMENT:
|
||||
Overall Risk Level: MEDIUM
|
||||
Key Risk Factors:
|
||||
• 2 critical risk upgrades requiring careful planning
|
||||
• Core framework upgrades: ['express', 'webpack', 'eslint']
|
||||
• 1 major version upgrades with potential breaking changes
|
||||
|
||||
TOP PRIORITY UPGRADES:
|
||||
------------------------------
|
||||
🔒 lodash: 4.17.20 → 4.17.21 🔒
|
||||
Type: Patch | Risk: Low | Priority: 95.0
|
||||
Security: CVE-2021-23337: Prototype pollution vulnerability
|
||||
|
||||
🟡 express: 4.18.1 → 4.18.2
|
||||
Type: Patch | Risk: Low | Priority: 85.0
|
||||
|
||||
🟡 webpack: 5.82.1 → 5.88.0
|
||||
Type: Minor | Risk: Medium | Priority: 75.0
|
||||
|
||||
🔴 eslint: 8.40.0 → 9.0.0
|
||||
Type: Major | Risk: High | Priority: 65.0
|
||||
|
||||
🟢 cors: 2.8.5 → 2.8.7
|
||||
Type: Patch | Risk: Safe | Priority: 80.0
|
||||
|
||||
PHASED UPGRADE PLANS:
|
||||
------------------------------
|
||||
Phase 1: Security & Safe Updates (30 days)
|
||||
Dependencies: lodash, cors, helmet, dotenv, bcrypt
|
||||
Key Steps: Create feature branch; Update dependency versions in manifest files; Run dependency install/update commands
|
||||
|
||||
Phase 2: Regular Updates (36 days)
|
||||
Dependencies: express, axios, winston, multer
|
||||
Key Steps: Create feature branch; Update dependency versions in manifest files; Run dependency install/update commands
|
||||
|
||||
Phase 3: Major Updates (30 days)
|
||||
Dependencies: webpack, eslint, jest
|
||||
... and 2 more
|
||||
Key Steps: Create feature branch; Update dependency versions in manifest files; Run dependency install/update commands
|
||||
|
||||
RECOMMENDATIONS:
|
||||
--------------------
|
||||
1. URGENT: 2 security updates available - prioritize immediately
|
||||
2. Quick wins: 6 safe updates can be applied with minimal risk
|
||||
3. Plan carefully: 2 high-risk upgrades need thorough testing
|
||||
|
||||
============================================================
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"timestamp": "2024-02-16T15:30:00.000Z",
|
||||
"project_path": "/example/sample-web-app",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "lodash",
|
||||
"version": "4.17.20",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": "MIT",
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2021-23337",
|
||||
"summary": "Prototype pollution in lodash",
|
||||
"severity": "HIGH",
|
||||
"cvss_score": 7.2,
|
||||
"affected_versions": "<4.17.21",
|
||||
"fixed_version": "4.17.21",
|
||||
"published_date": "2021-02-15",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2021-23337"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "axios",
|
||||
"version": "1.5.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": "MIT",
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "express",
|
||||
"version": "4.18.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": "MIT",
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "jsonwebtoken",
|
||||
"version": "8.5.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": "MIT",
|
||||
"vulnerabilities": []
|
||||
}
|
||||
],
|
||||
"vulnerabilities_found": 1,
|
||||
"high_severity_count": 1,
|
||||
"medium_severity_count": 0,
|
||||
"low_severity_count": 0,
|
||||
"ecosystems": ["npm"],
|
||||
"scan_summary": {
|
||||
"total_dependencies": 4,
|
||||
"unique_dependencies": 4,
|
||||
"ecosystems_found": 1,
|
||||
"vulnerable_dependencies": 1,
|
||||
"vulnerability_breakdown": {
|
||||
"high": 1,
|
||||
"medium": 0,
|
||||
"low": 0
|
||||
}
|
||||
},
|
||||
"recommendations": [
|
||||
"URGENT: Address 1 high-severity vulnerabilities immediately",
|
||||
"Update lodash from 4.17.20 to 4.17.21 to fix CVE-2021-23337"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,643 @@
|
||||
# Dependency Management Best Practices
|
||||
|
||||
A comprehensive guide to effective dependency management across the software development lifecycle, covering strategy, governance, security, and operational practices.
|
||||
|
||||
## Strategic Foundation
|
||||
|
||||
### Dependency Strategy
|
||||
|
||||
#### Philosophy and Principles
|
||||
1. **Minimize Dependencies**: Every dependency is a liability
|
||||
- Prefer standard library solutions when possible
|
||||
- Evaluate alternatives before adding new dependencies
|
||||
- Regularly audit and remove unused dependencies
|
||||
|
||||
2. **Quality Over Convenience**: Choose well-maintained, secure dependencies
|
||||
- Active maintenance and community
|
||||
- Strong security track record
|
||||
- Comprehensive documentation and testing
|
||||
|
||||
3. **Stability Over Novelty**: Prefer proven, stable solutions
|
||||
- Avoid dependencies with frequent breaking changes
|
||||
- Consider long-term support and backwards compatibility
|
||||
- Evaluate dependency maturity and adoption
|
||||
|
||||
4. **Transparency and Control**: Understand what you're depending on
|
||||
- Review dependency source code when possible
|
||||
- Understand licensing implications
|
||||
- Monitor dependency behavior and updates
|
||||
|
||||
#### Decision Framework
|
||||
|
||||
##### Evaluation Criteria
|
||||
```
|
||||
Dependency Evaluation Scorecard:
|
||||
│
|
||||
├── Necessity (25 points)
|
||||
│ ├── Problem complexity (10)
|
||||
│ ├── Standard library alternatives (8)
|
||||
│ └── Internal implementation effort (7)
|
||||
│
|
||||
├── Quality (30 points)
|
||||
│ ├── Code quality and architecture (10)
|
||||
│ ├── Test coverage and reliability (10)
|
||||
│ └── Documentation completeness (10)
|
||||
│
|
||||
├── Maintenance (25 points)
|
||||
│ ├── Active development and releases (10)
|
||||
│ ├── Issue response time (8)
|
||||
│ └── Community size and engagement (7)
|
||||
│
|
||||
└── Compatibility (20 points)
|
||||
├── License compatibility (10)
|
||||
├── Version stability (5)
|
||||
└── Platform/runtime compatibility (5)
|
||||
|
||||
Scoring:
|
||||
- 80-100: Excellent choice
|
||||
- 60-79: Good choice with monitoring
|
||||
- 40-59: Acceptable with caution
|
||||
- Below 40: Avoid or find alternatives
|
||||
```
|
||||
|
||||
### Governance Framework
|
||||
|
||||
#### Dependency Approval Process
|
||||
|
||||
##### New Dependency Approval
|
||||
```
|
||||
New Dependency Workflow:
|
||||
│
|
||||
1. Developer identifies need
|
||||
├── Documents use case and requirements
|
||||
├── Researches available options
|
||||
└── Proposes recommendation
|
||||
↓
|
||||
2. Technical review
|
||||
├── Architecture team evaluates fit
|
||||
├── Security team assesses risks
|
||||
└── Legal team reviews licensing
|
||||
↓
|
||||
3. Management approval
|
||||
├── Low risk: Tech lead approval
|
||||
├── Medium risk: Architecture board
|
||||
└── High risk: CTO approval
|
||||
↓
|
||||
4. Implementation
|
||||
├── Add to approved dependencies list
|
||||
├── Document usage guidelines
|
||||
└── Configure monitoring and alerts
|
||||
```
|
||||
|
||||
##### Risk Classification
|
||||
- **Low Risk**: Well-known libraries, permissive licenses, stable APIs
|
||||
- **Medium Risk**: Less common libraries, weak copyleft licenses, evolving APIs
|
||||
- **High Risk**: New/experimental libraries, strong copyleft licenses, breaking changes
|
||||
|
||||
#### Dependency Policies
|
||||
|
||||
##### Licensing Policy
|
||||
```yaml
|
||||
licensing_policy:
|
||||
allowed_licenses:
|
||||
- MIT
|
||||
- Apache-2.0
|
||||
- BSD-3-Clause
|
||||
- BSD-2-Clause
|
||||
- ISC
|
||||
|
||||
conditional_licenses:
|
||||
- LGPL-2.1 # Library linking only
|
||||
- LGPL-3.0 # With legal review
|
||||
- MPL-2.0 # File-level copyleft acceptable
|
||||
|
||||
prohibited_licenses:
|
||||
- GPL-2.0 # Strong copyleft
|
||||
- GPL-3.0 # Strong copyleft
|
||||
- AGPL-3.0 # Network copyleft
|
||||
- SSPL # Server-side public license
|
||||
- Custom # Unknown/proprietary licenses
|
||||
|
||||
exceptions:
|
||||
process: "Legal and executive approval required"
|
||||
documentation: "Risk assessment and mitigation plan"
|
||||
```
|
||||
|
||||
##### Security Policy
|
||||
```yaml
|
||||
security_policy:
|
||||
vulnerability_response:
|
||||
critical: "24 hours"
|
||||
high: "1 week"
|
||||
medium: "1 month"
|
||||
low: "Next release cycle"
|
||||
|
||||
scanning_requirements:
|
||||
frequency: "Daily automated scans"
|
||||
tools: ["Snyk", "OWASP Dependency Check"]
|
||||
ci_cd_integration: "Mandatory security gates"
|
||||
|
||||
approval_thresholds:
|
||||
known_vulnerabilities: "Zero tolerance for high/critical"
|
||||
maintenance_status: "Must be actively maintained"
|
||||
community_size: "Minimum 10 contributors or enterprise backing"
|
||||
```
|
||||
|
||||
## Operational Practices
|
||||
|
||||
### Dependency Lifecycle Management
|
||||
|
||||
#### Addition Process
|
||||
1. **Research and Evaluation**
|
||||
```bash
|
||||
# Example evaluation script
|
||||
#!/bin/bash
|
||||
PACKAGE=$1
|
||||
|
||||
echo "=== Package Analysis: $PACKAGE ==="
|
||||
|
||||
# Check package stats
|
||||
npm view $PACKAGE
|
||||
|
||||
# Security audit
|
||||
npm audit $PACKAGE
|
||||
|
||||
# License check
|
||||
npm view $PACKAGE license
|
||||
|
||||
# Dependency tree
|
||||
npm ls $PACKAGE
|
||||
|
||||
# Recent activity
|
||||
npm view $PACKAGE --json | jq '.time'
|
||||
```
|
||||
|
||||
2. **Documentation Requirements**
|
||||
- **Purpose**: Why this dependency is needed
|
||||
- **Alternatives**: Other options considered and why rejected
|
||||
- **Risk Assessment**: Security, licensing, maintenance risks
|
||||
- **Usage Guidelines**: How to use safely within the project
|
||||
- **Exit Strategy**: How to remove/replace if needed
|
||||
|
||||
3. **Integration Standards**
|
||||
- Pin to specific versions (avoid wildcards)
|
||||
- Document version constraints and reasoning
|
||||
- Configure automated update policies
|
||||
- Add monitoring and alerting
|
||||
|
||||
#### Update Management
|
||||
|
||||
##### Update Strategy
|
||||
```
|
||||
Update Prioritization:
|
||||
│
|
||||
├── Security Updates (P0)
|
||||
│ ├── Critical vulnerabilities: Immediate
|
||||
│ ├── High vulnerabilities: Within 1 week
|
||||
│ └── Medium vulnerabilities: Within 1 month
|
||||
│
|
||||
├── Maintenance Updates (P1)
|
||||
│ ├── Bug fixes: Next minor release
|
||||
│ ├── Performance improvements: Next minor release
|
||||
│ └── Deprecation warnings: Plan for major release
|
||||
│
|
||||
└── Feature Updates (P2)
|
||||
├── Minor versions: Quarterly review
|
||||
├── Major versions: Annual planning cycle
|
||||
└── Breaking changes: Dedicated migration projects
|
||||
```
|
||||
|
||||
##### Update Process
|
||||
```yaml
|
||||
update_workflow:
|
||||
automated:
|
||||
patch_updates:
|
||||
enabled: true
|
||||
auto_merge: true
|
||||
conditions:
|
||||
- tests_pass: true
|
||||
- security_scan_clean: true
|
||||
- no_breaking_changes: true
|
||||
|
||||
minor_updates:
|
||||
enabled: true
|
||||
auto_merge: false
|
||||
requires: "Manual review and testing"
|
||||
|
||||
major_updates:
|
||||
enabled: false
|
||||
requires: "Full impact assessment and planning"
|
||||
|
||||
testing_requirements:
|
||||
unit_tests: "100% pass rate"
|
||||
integration_tests: "Full test suite"
|
||||
security_tests: "Vulnerability scan clean"
|
||||
performance_tests: "No regression"
|
||||
|
||||
rollback_plan:
|
||||
automated: "Failed CI/CD triggers automatic rollback"
|
||||
manual: "Documented rollback procedure"
|
||||
monitoring: "Real-time health checks post-deployment"
|
||||
```
|
||||
|
||||
#### Removal Process
|
||||
1. **Deprecation Planning**
|
||||
- Identify deprecated/unused dependencies
|
||||
- Assess removal impact and effort
|
||||
- Plan migration timeline and strategy
|
||||
- Communicate to stakeholders
|
||||
|
||||
2. **Safe Removal**
|
||||
```bash
|
||||
# Example removal checklist
|
||||
echo "Dependency Removal Checklist:"
|
||||
echo "1. [ ] Grep codebase for all imports/usage"
|
||||
echo "2. [ ] Check if any other dependencies require it"
|
||||
echo "3. [ ] Remove from package files"
|
||||
echo "4. [ ] Run full test suite"
|
||||
echo "5. [ ] Update documentation"
|
||||
echo "6. [ ] Deploy with monitoring"
|
||||
```
|
||||
|
||||
### Version Management
|
||||
|
||||
#### Semantic Versioning Strategy
|
||||
|
||||
##### Version Pinning Policies
|
||||
```yaml
|
||||
version_pinning:
|
||||
production_dependencies:
|
||||
strategy: "Exact pinning"
|
||||
example: "react: 18.2.0"
|
||||
rationale: "Predictable builds, security control"
|
||||
|
||||
development_dependencies:
|
||||
strategy: "Compatible range"
|
||||
example: "eslint: ^8.0.0"
|
||||
rationale: "Allow bug fixes and improvements"
|
||||
|
||||
internal_libraries:
|
||||
strategy: "Compatible range"
|
||||
example: "^1.2.0"
|
||||
rationale: "Internal control, faster iteration"
|
||||
```
|
||||
|
||||
##### Update Windows
|
||||
- **Patch Updates (x.y.Z)**: Allow automatically with testing
|
||||
- **Minor Updates (x.Y.z)**: Review monthly, apply quarterly
|
||||
- **Major Updates (X.y.z)**: Annual review cycle, planned migrations
|
||||
|
||||
#### Lockfile Management
|
||||
|
||||
##### Best Practices
|
||||
1. **Always Commit Lockfiles**
|
||||
- package-lock.json (npm)
|
||||
- yarn.lock (Yarn)
|
||||
- Pipfile.lock (Python)
|
||||
- Cargo.lock (Rust)
|
||||
- go.sum (Go)
|
||||
|
||||
2. **Lockfile Validation**
|
||||
```bash
|
||||
# Example CI validation
|
||||
- name: Validate lockfile
|
||||
run: |
|
||||
npm ci --audit
|
||||
npm audit --audit-level moderate
|
||||
# Verify lockfile is up to date
|
||||
npm install --package-lock-only
|
||||
git diff --exit-code package-lock.json
|
||||
```
|
||||
|
||||
3. **Regeneration Policy**
|
||||
- Regenerate monthly or after significant updates
|
||||
- Always regenerate after security updates
|
||||
- Document regeneration in change logs
|
||||
|
||||
## Security Management
|
||||
|
||||
### Vulnerability Management
|
||||
|
||||
#### Continuous Monitoring
|
||||
```yaml
|
||||
monitoring_stack:
|
||||
scanning_tools:
|
||||
- name: "Snyk"
|
||||
scope: "All ecosystems"
|
||||
frequency: "Daily"
|
||||
integration: "CI/CD + IDE"
|
||||
|
||||
- name: "GitHub Dependabot"
|
||||
scope: "GitHub repositories"
|
||||
frequency: "Real-time"
|
||||
integration: "Pull requests"
|
||||
|
||||
- name: "OWASP Dependency Check"
|
||||
scope: "Java/.NET focus"
|
||||
frequency: "Build pipeline"
|
||||
integration: "CI/CD gates"
|
||||
|
||||
alerting:
|
||||
channels: ["Slack", "Email", "PagerDuty"]
|
||||
escalation:
|
||||
critical: "Immediate notification"
|
||||
high: "Within 1 hour"
|
||||
medium: "Daily digest"
|
||||
```
|
||||
|
||||
#### Response Procedures
|
||||
|
||||
##### Critical Vulnerability Response
|
||||
```
|
||||
Critical Vulnerability (CVSS 9.0+) Response:
|
||||
│
|
||||
0-2 hours: Detection & Assessment
|
||||
├── Automated scan identifies vulnerability
|
||||
├── Security team notified immediately
|
||||
└── Initial impact assessment started
|
||||
│
|
||||
2-6 hours: Planning & Communication
|
||||
├── Detailed impact analysis completed
|
||||
├── Fix strategy determined
|
||||
├── Stakeholder communication initiated
|
||||
└── Emergency change approval obtained
|
||||
│
|
||||
6-24 hours: Implementation & Testing
|
||||
├── Fix implemented in development
|
||||
├── Security testing performed
|
||||
├── Limited rollout to staging
|
||||
└── Production deployment prepared
|
||||
│
|
||||
24-48 hours: Deployment & Validation
|
||||
├── Production deployment executed
|
||||
├── Monitoring and validation performed
|
||||
├── Post-deployment testing completed
|
||||
└── Incident documentation finalized
|
||||
```
|
||||
|
||||
### Supply Chain Security
|
||||
|
||||
#### Source Verification
|
||||
1. **Package Authenticity**
|
||||
- Verify package signatures when available
|
||||
- Use official package registries
|
||||
- Check package maintainer reputation
|
||||
- Validate download checksums
|
||||
|
||||
2. **Build Reproducibility**
|
||||
- Use deterministic builds where possible
|
||||
- Pin dependency versions exactly
|
||||
- Document build environment requirements
|
||||
- Maintain build artifact checksums
|
||||
|
||||
#### Dependency Provenance
|
||||
```yaml
|
||||
provenance_tracking:
|
||||
metadata_collection:
|
||||
- package_name: "Library identification"
|
||||
- version: "Exact version used"
|
||||
- source_url: "Official repository"
|
||||
- maintainer: "Package maintainer info"
|
||||
- license: "License verification"
|
||||
- checksum: "Content verification"
|
||||
|
||||
verification_process:
|
||||
- signature_check: "GPG signature validation"
|
||||
- reputation_check: "Maintainer history review"
|
||||
- content_analysis: "Static code analysis"
|
||||
- behavior_monitoring: "Runtime behavior analysis"
|
||||
```
|
||||
|
||||
## Multi-Language Considerations
|
||||
|
||||
### Ecosystem-Specific Practices
|
||||
|
||||
#### JavaScript/Node.js
|
||||
```json
|
||||
{
|
||||
"npm_practices": {
|
||||
"package_json": {
|
||||
"engines": "Specify Node.js version requirements",
|
||||
"dependencies": "Production dependencies only",
|
||||
"devDependencies": "Development tools and testing",
|
||||
"optionalDependencies": "Use sparingly, document why"
|
||||
},
|
||||
"security": {
|
||||
"npm_audit": "Run in CI/CD pipeline",
|
||||
"package_lock": "Always commit to repository",
|
||||
"registry": "Use official npm registry or approved mirrors"
|
||||
},
|
||||
"performance": {
|
||||
"bundle_analysis": "Regular bundle size monitoring",
|
||||
"tree_shaking": "Ensure unused code is eliminated",
|
||||
"code_splitting": "Lazy load dependencies when possible"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Python
|
||||
```yaml
|
||||
python_practices:
|
||||
dependency_files:
|
||||
requirements.txt: "Pin exact versions for production"
|
||||
requirements-dev.txt: "Development dependencies"
|
||||
setup.py: "Package distribution metadata"
|
||||
pyproject.toml: "Modern Python packaging"
|
||||
|
||||
virtual_environments:
|
||||
purpose: "Isolate project dependencies"
|
||||
tools: ["venv", "virtualenv", "conda", "poetry"]
|
||||
best_practice: "One environment per project"
|
||||
|
||||
security:
|
||||
tools: ["safety", "pip-audit", "bandit"]
|
||||
practices: ["Pin versions", "Use private PyPI if needed"]
|
||||
```
|
||||
|
||||
#### Java/Maven
|
||||
```xml
|
||||
<!-- Maven best practices -->
|
||||
<properties>
|
||||
<!-- Define version properties -->
|
||||
<spring.version>5.3.21</spring.version>
|
||||
<junit.version>5.8.2</junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<!-- Centralize version management -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-bom</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
```
|
||||
|
||||
### Cross-Language Integration
|
||||
|
||||
#### API Boundaries
|
||||
- Define clear service interfaces
|
||||
- Use standard protocols (HTTP, gRPC)
|
||||
- Document API contracts
|
||||
- Version APIs independently
|
||||
|
||||
#### Shared Dependencies
|
||||
- Minimize shared dependencies across services
|
||||
- Use containerization for isolation
|
||||
- Document shared dependency policies
|
||||
- Monitor for version conflicts
|
||||
|
||||
## Performance and Optimization
|
||||
|
||||
### Bundle Size Management
|
||||
|
||||
#### Analysis Tools
|
||||
```bash
|
||||
# JavaScript bundle analysis
|
||||
npm install -g webpack-bundle-analyzer
|
||||
webpack-bundle-analyzer dist/main.js
|
||||
|
||||
# Python package size analysis
|
||||
pip install pip-audit
|
||||
pip-audit --format json | jq '.dependencies[].package_size'
|
||||
|
||||
# General dependency tree analysis
|
||||
dep-tree analyze --format json --output deps.json
|
||||
```
|
||||
|
||||
#### Optimization Strategies
|
||||
1. **Tree Shaking**: Remove unused code
|
||||
2. **Code Splitting**: Load dependencies on demand
|
||||
3. **Polyfill Optimization**: Only include needed polyfills
|
||||
4. **Alternative Packages**: Choose smaller alternatives when possible
|
||||
|
||||
### Build Performance
|
||||
|
||||
#### Dependency Caching
|
||||
```yaml
|
||||
# Example CI/CD caching
|
||||
cache_strategy:
|
||||
node_modules:
|
||||
key: "npm-{{ checksum 'package-lock.json' }}"
|
||||
paths: ["~/.npm", "node_modules"]
|
||||
|
||||
pip_cache:
|
||||
key: "pip-{{ checksum 'requirements.txt' }}"
|
||||
paths: ["~/.cache/pip"]
|
||||
|
||||
maven_cache:
|
||||
key: "maven-{{ checksum 'pom.xml' }}"
|
||||
paths: ["~/.m2/repository"]
|
||||
```
|
||||
|
||||
#### Parallel Installation
|
||||
- Configure package managers for parallel downloads
|
||||
- Use local package caches
|
||||
- Consider dependency proxies for enterprise environments
|
||||
|
||||
## Monitoring and Metrics
|
||||
|
||||
### Key Performance Indicators
|
||||
|
||||
#### Security Metrics
|
||||
```yaml
|
||||
security_kpis:
|
||||
vulnerability_metrics:
|
||||
- mean_time_to_detection: "Average time to identify vulnerabilities"
|
||||
- mean_time_to_patch: "Average time to fix vulnerabilities"
|
||||
- vulnerability_density: "Vulnerabilities per 1000 dependencies"
|
||||
- false_positive_rate: "Percentage of false vulnerability reports"
|
||||
|
||||
compliance_metrics:
|
||||
- license_compliance_rate: "Percentage of compliant dependencies"
|
||||
- policy_violation_rate: "Rate of policy violations"
|
||||
- security_gate_success_rate: "CI/CD security gate pass rate"
|
||||
```
|
||||
|
||||
#### Operational Metrics
|
||||
```yaml
|
||||
operational_kpis:
|
||||
maintenance_metrics:
|
||||
- dependency_freshness: "Average age of dependencies"
|
||||
- update_frequency: "Rate of dependency updates"
|
||||
- technical_debt: "Number of outdated dependencies"
|
||||
|
||||
performance_metrics:
|
||||
- build_time: "Time to install/build dependencies"
|
||||
- bundle_size: "Final application size"
|
||||
- dependency_count: "Total number of dependencies"
|
||||
```
|
||||
|
||||
### Dashboard and Reporting
|
||||
|
||||
#### Executive Dashboard
|
||||
- Overall risk score and trend
|
||||
- Security compliance status
|
||||
- Cost of dependency management
|
||||
- Policy violation summary
|
||||
|
||||
#### Technical Dashboard
|
||||
- Vulnerability count by severity
|
||||
- Outdated dependency count
|
||||
- Build performance metrics
|
||||
- License compliance details
|
||||
|
||||
#### Automated Reports
|
||||
- Weekly security summary
|
||||
- Monthly compliance report
|
||||
- Quarterly dependency review
|
||||
- Annual strategy assessment
|
||||
|
||||
## Team Organization and Training
|
||||
|
||||
### Roles and Responsibilities
|
||||
|
||||
#### Security Champions
|
||||
- Monitor security advisories
|
||||
- Review dependency security scans
|
||||
- Coordinate vulnerability responses
|
||||
- Maintain security policies
|
||||
|
||||
#### Platform Engineers
|
||||
- Maintain dependency management infrastructure
|
||||
- Configure automated scanning and updates
|
||||
- Manage package registries and mirrors
|
||||
- Support development teams
|
||||
|
||||
#### Development Teams
|
||||
- Follow dependency policies
|
||||
- Perform regular security updates
|
||||
- Document dependency decisions
|
||||
- Participate in security training
|
||||
|
||||
### Training Programs
|
||||
|
||||
#### Security Training
|
||||
- Dependency security fundamentals
|
||||
- Vulnerability assessment and response
|
||||
- Secure coding practices
|
||||
- Supply chain attack awareness
|
||||
|
||||
#### Tool Training
|
||||
- Package manager best practices
|
||||
- Security scanning tool usage
|
||||
- CI/CD security integration
|
||||
- Incident response procedures
|
||||
|
||||
## Conclusion
|
||||
|
||||
Effective dependency management requires a holistic approach combining technical practices, organizational policies, and cultural awareness. Key success factors:
|
||||
|
||||
1. **Proactive Strategy**: Plan dependency management from project inception
|
||||
2. **Clear Governance**: Establish and enforce dependency policies
|
||||
3. **Automated Processes**: Use tools to scale security and maintenance
|
||||
4. **Continuous Monitoring**: Stay informed about dependency risks and updates
|
||||
5. **Team Training**: Ensure all team members understand security implications
|
||||
6. **Regular Review**: Periodically assess and improve dependency practices
|
||||
|
||||
Remember that dependency management is an investment in long-term project health, security, and maintainability. The upfront effort to establish good practices pays dividends in reduced security risks, easier maintenance, and more stable software systems.
|
||||
@@ -0,0 +1,238 @@
|
||||
# License Compatibility Matrix
|
||||
|
||||
This document provides a comprehensive reference for understanding license compatibility when combining open source software dependencies in your projects.
|
||||
|
||||
## Understanding License Types
|
||||
|
||||
### Permissive Licenses
|
||||
- **MIT License**: Very permissive, allows commercial use, modification, and distribution
|
||||
- **Apache 2.0**: Permissive with patent grant and trademark restrictions
|
||||
- **BSD 3-Clause**: Permissive with non-endorsement clause
|
||||
- **BSD 2-Clause**: Simple permissive license
|
||||
- **ISC License**: Functionally equivalent to MIT
|
||||
|
||||
### Weak Copyleft Licenses
|
||||
- **LGPL 2.1/3.0**: Library-level copyleft, allows linking but requires modifications to be shared
|
||||
- **MPL 2.0**: File-level copyleft, compatible with many licenses
|
||||
|
||||
### Strong Copyleft Licenses
|
||||
- **GPL 2.0/3.0**: Requires entire derivative work to be GPL-licensed
|
||||
- **AGPL 3.0**: Extends GPL to network services (SaaS applications)
|
||||
|
||||
## Compatibility Matrix
|
||||
|
||||
| Project License | MIT | Apache-2.0 | BSD-3 | LGPL-2.1 | LGPL-3.0 | MPL-2.0 | GPL-2.0 | GPL-3.0 | AGPL-3.0 |
|
||||
|----------------|-----|------------|-------|----------|----------|---------|---------|---------|----------|
|
||||
| **MIT** | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ❌ | ❌ | ❌ |
|
||||
| **Apache-2.0** | ✅ | ✅ | ✅ | ❌ | ⚠️ | ✅ | ❌ | ⚠️ | ⚠️ |
|
||||
| **BSD-3** | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ❌ | ❌ | ❌ |
|
||||
| **LGPL-2.1** | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
|
||||
| **LGPL-3.0** | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
| **MPL-2.0** | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
| **GPL-2.0** | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
|
||||
| **GPL-3.0** | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
| **AGPL-3.0** | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
|
||||
**Legend:**
|
||||
- ✅ Generally Compatible
|
||||
- ⚠️ Compatible with conditions/restrictions
|
||||
- ❌ Incompatible
|
||||
|
||||
## Detailed Compatibility Rules
|
||||
|
||||
### MIT Project with Other Licenses
|
||||
|
||||
**Compatible:**
|
||||
- MIT, Apache-2.0, BSD (all variants), ISC: Full compatibility
|
||||
- LGPL 2.1/3.0: Can use LGPL libraries via dynamic linking
|
||||
- MPL 2.0: Can use MPL modules, must keep MPL files under MPL
|
||||
|
||||
**Incompatible:**
|
||||
- GPL 2.0/3.0: GPL requires entire project to be GPL
|
||||
- AGPL 3.0: AGPL extends to network services
|
||||
|
||||
### Apache 2.0 Project with Other Licenses
|
||||
|
||||
**Compatible:**
|
||||
- MIT, BSD, ISC: Full compatibility
|
||||
- LGPL 3.0: Compatible (LGPL 3.0 has Apache compatibility clause)
|
||||
- MPL 2.0: Compatible
|
||||
- GPL 3.0: Compatible (GPL 3.0 has Apache compatibility clause)
|
||||
|
||||
**Incompatible:**
|
||||
- LGPL 2.1: License incompatibility
|
||||
- GPL 2.0: License incompatibility (no Apache clause)
|
||||
|
||||
### GPL Projects
|
||||
|
||||
**GPL 2.0 Compatible:**
|
||||
- MIT, BSD, ISC: Can incorporate permissive code
|
||||
- LGPL 2.1: Compatible
|
||||
- Other GPL 2.0: Compatible
|
||||
|
||||
**GPL 2.0 Incompatible:**
|
||||
- Apache 2.0: Different patent clauses
|
||||
- LGPL 3.0: Version incompatibility
|
||||
- GPL 3.0: Version incompatibility
|
||||
|
||||
**GPL 3.0 Compatible:**
|
||||
- All permissive licenses (MIT, Apache, BSD, ISC)
|
||||
- LGPL 3.0: Version compatibility
|
||||
- MPL 2.0: Explicit compatibility
|
||||
|
||||
## Common Compatibility Scenarios
|
||||
|
||||
### Scenario 1: Permissive Project with GPL Dependency
|
||||
**Problem:** MIT-licensed project wants to use GPL library
|
||||
**Impact:** Entire project must become GPL-licensed
|
||||
**Solutions:**
|
||||
1. Find alternative non-GPL library
|
||||
2. Use dynamic linking (if possible)
|
||||
3. Change project license to GPL
|
||||
4. Remove the dependency
|
||||
|
||||
### Scenario 2: Apache Project with GPL 2.0 Dependency
|
||||
**Problem:** Apache 2.0 project with GPL 2.0 dependency
|
||||
**Impact:** License incompatibility due to patent clauses
|
||||
**Solutions:**
|
||||
1. Upgrade to GPL 3.0 if available
|
||||
2. Find alternative library
|
||||
3. Use via separate service (API boundary)
|
||||
|
||||
### Scenario 3: Commercial Product with AGPL Dependency
|
||||
**Problem:** Proprietary software using AGPL library
|
||||
**Impact:** AGPL copyleft extends to network services
|
||||
**Solutions:**
|
||||
1. Obtain commercial license
|
||||
2. Replace with permissive alternative
|
||||
3. Use via separate service with API boundary
|
||||
4. Make entire application AGPL
|
||||
|
||||
## License Combination Rules
|
||||
|
||||
### Safe Combinations
|
||||
1. **Permissive + Permissive**: Always safe
|
||||
2. **Permissive + Weak Copyleft**: Usually safe with proper attribution
|
||||
3. **GPL + Compatible Permissive**: Safe, result is GPL
|
||||
|
||||
### Risky Combinations
|
||||
1. **Apache 2.0 + GPL 2.0**: Incompatible patent terms
|
||||
2. **Different GPL versions**: Version compatibility issues
|
||||
3. **Permissive + Strong Copyleft**: Changes project licensing
|
||||
|
||||
### Forbidden Combinations
|
||||
1. **MIT + GPL** (without relicensing)
|
||||
2. **Proprietary + Any Copyleft**
|
||||
3. **LGPL 2.1 + Apache 2.0**
|
||||
|
||||
## Distribution Considerations
|
||||
|
||||
### Binary Distribution
|
||||
- Must include all required license texts
|
||||
- Must preserve copyright notices
|
||||
- Must include source code for copyleft licenses
|
||||
- Must provide installation instructions for LGPL
|
||||
|
||||
### Source Distribution
|
||||
- Must include original license files
|
||||
- Must preserve copyright headers
|
||||
- Must document any modifications
|
||||
- Must provide clear licensing information
|
||||
|
||||
### SaaS/Network Services
|
||||
- AGPL extends copyleft to network services
|
||||
- GPL/LGPL generally don't apply to network services
|
||||
- Consider service boundaries carefully
|
||||
|
||||
## Compliance Best Practices
|
||||
|
||||
### 1. License Inventory
|
||||
- Maintain complete list of all dependencies
|
||||
- Track license changes in updates
|
||||
- Document license obligations
|
||||
|
||||
### 2. Compatibility Checking
|
||||
- Use automated tools for license scanning
|
||||
- Implement CI/CD license gates
|
||||
- Regular compliance audits
|
||||
|
||||
### 3. Documentation
|
||||
- Clear project license declaration
|
||||
- Complete attribution files
|
||||
- License change history
|
||||
|
||||
### 4. Legal Review
|
||||
- Consult legal counsel for complex scenarios
|
||||
- Review before major releases
|
||||
- Consider business model implications
|
||||
|
||||
## Risk Mitigation Strategies
|
||||
|
||||
### High-Risk Licenses
|
||||
- **AGPL**: Avoid in commercial/proprietary projects
|
||||
- **GPL in permissive projects**: Plan migration strategy
|
||||
- **Unknown licenses**: Investigate immediately
|
||||
|
||||
### Medium-Risk Scenarios
|
||||
- **Version incompatibilities**: Upgrade when possible
|
||||
- **Patent clause conflicts**: Seek legal advice
|
||||
- **Multiple copyleft licenses**: Verify compatibility
|
||||
|
||||
### Risk Assessment Framework
|
||||
1. **Identify** all dependencies and their licenses
|
||||
2. **Classify** by license type and risk level
|
||||
3. **Analyze** compatibility with project license
|
||||
4. **Document** decisions and rationale
|
||||
5. **Monitor** for license changes
|
||||
|
||||
## Common Misconceptions
|
||||
|
||||
### ❌ Wrong Assumptions
|
||||
- "MIT allows everything" (still requires attribution)
|
||||
- "Linking doesn't create derivatives" (depends on license)
|
||||
- "GPL only affects distribution" (AGPL affects network use)
|
||||
- "Commercial use is always forbidden" (most FOSS allows it)
|
||||
|
||||
### ✅ Correct Understanding
|
||||
- Each license has specific requirements
|
||||
- Combination creates most restrictive terms
|
||||
- Network use may trigger copyleft (AGPL)
|
||||
- Commercial licensing options often available
|
||||
|
||||
## Quick Reference Decision Tree
|
||||
|
||||
```
|
||||
Is the dependency GPL/AGPL?
|
||||
├─ YES → Is your project commercial/proprietary?
|
||||
│ ├─ YES → ❌ Incompatible (find alternative)
|
||||
│ └─ NO → ✅ Compatible (if same GPL version)
|
||||
└─ NO → Is it permissive (MIT/Apache/BSD)?
|
||||
├─ YES → ✅ Generally compatible
|
||||
└─ NO → Check specific compatibility matrix
|
||||
```
|
||||
|
||||
## Tools and Resources
|
||||
|
||||
### Automated Tools
|
||||
- **FOSSA**: Commercial license scanning
|
||||
- **WhiteSource**: Enterprise license management
|
||||
- **ORT**: Open source license scanning
|
||||
- **License Finder**: Ruby-based license detection
|
||||
|
||||
### Manual Review Resources
|
||||
- **choosealicense.com**: License picker and comparison
|
||||
- **SPDX License List**: Standardized license identifiers
|
||||
- **FSF License List**: Free Software Foundation compatibility
|
||||
- **OSI Approved Licenses**: Open Source Initiative approved licenses
|
||||
|
||||
## Conclusion
|
||||
|
||||
License compatibility is crucial for legal compliance and risk management. When in doubt:
|
||||
|
||||
1. **Choose permissive licenses** for maximum compatibility
|
||||
2. **Avoid strong copyleft** in proprietary projects
|
||||
3. **Document all license decisions** thoroughly
|
||||
4. **Consult legal experts** for complex scenarios
|
||||
5. **Use automated tools** for continuous monitoring
|
||||
|
||||
Remember: This matrix provides general guidance but legal requirements may vary by jurisdiction and specific use cases. Always consult with legal counsel for important licensing decisions.
|
||||
@@ -0,0 +1,461 @@
|
||||
# Vulnerability Assessment Guide
|
||||
|
||||
A comprehensive guide to assessing, prioritizing, and managing security vulnerabilities in software dependencies.
|
||||
|
||||
## Overview
|
||||
|
||||
Dependency vulnerabilities represent one of the most significant attack vectors in modern software systems. This guide provides a structured approach to vulnerability assessment, risk scoring, and remediation planning.
|
||||
|
||||
## Vulnerability Classification System
|
||||
|
||||
### Severity Levels (CVSS 3.1)
|
||||
|
||||
#### Critical (9.0 - 10.0)
|
||||
- **Impact**: Complete system compromise possible
|
||||
- **Examples**: Remote code execution, privilege escalation to admin
|
||||
- **Response Time**: Immediate (within 24 hours)
|
||||
- **Business Risk**: System shutdown, data breach, regulatory violations
|
||||
|
||||
#### High (7.0 - 8.9)
|
||||
- **Impact**: Significant security impact
|
||||
- **Examples**: SQL injection, authentication bypass, sensitive data exposure
|
||||
- **Response Time**: 7 days maximum
|
||||
- **Business Risk**: Data compromise, service disruption
|
||||
|
||||
#### Medium (4.0 - 6.9)
|
||||
- **Impact**: Moderate security impact
|
||||
- **Examples**: Cross-site scripting (XSS), information disclosure
|
||||
- **Response Time**: 30 days
|
||||
- **Business Risk**: Limited data exposure, minor service impact
|
||||
|
||||
#### Low (0.1 - 3.9)
|
||||
- **Impact**: Limited security impact
|
||||
- **Examples**: Denial of service (limited), minor information leakage
|
||||
- **Response Time**: Next planned release cycle
|
||||
- **Business Risk**: Minimal impact on operations
|
||||
|
||||
## Vulnerability Types and Patterns
|
||||
|
||||
### Code Injection Vulnerabilities
|
||||
|
||||
#### SQL Injection
|
||||
- **CWE-89**: Improper neutralization of SQL commands
|
||||
- **Common in**: Database interaction libraries, ORM frameworks
|
||||
- **Detection**: Parameter handling analysis, query construction review
|
||||
- **Mitigation**: Parameterized queries, input validation, least privilege DB access
|
||||
|
||||
#### Command Injection
|
||||
- **CWE-78**: OS command injection
|
||||
- **Common in**: System utilities, file processing libraries
|
||||
- **Detection**: System call analysis, user input handling
|
||||
- **Mitigation**: Input sanitization, avoid system calls, sandboxing
|
||||
|
||||
#### Code Injection
|
||||
- **CWE-94**: Code injection
|
||||
- **Common in**: Template engines, dynamic code evaluation
|
||||
- **Detection**: eval() usage, dynamic code generation
|
||||
- **Mitigation**: Avoid dynamic code execution, input validation, sandboxing
|
||||
|
||||
### Authentication and Authorization
|
||||
|
||||
#### Authentication Bypass
|
||||
- **CWE-287**: Improper authentication
|
||||
- **Common in**: Authentication libraries, session management
|
||||
- **Detection**: Authentication flow analysis, session handling review
|
||||
- **Mitigation**: Multi-factor authentication, secure session management
|
||||
|
||||
#### Privilege Escalation
|
||||
- **CWE-269**: Improper privilege management
|
||||
- **Common in**: Authorization frameworks, access control libraries
|
||||
- **Detection**: Permission checking analysis, role validation
|
||||
- **Mitigation**: Principle of least privilege, proper access controls
|
||||
|
||||
### Data Exposure
|
||||
|
||||
#### Sensitive Data Exposure
|
||||
- **CWE-200**: Information exposure
|
||||
- **Common in**: Logging libraries, error handling, API responses
|
||||
- **Detection**: Log output analysis, error message review
|
||||
- **Mitigation**: Data classification, sanitized logging, proper error handling
|
||||
|
||||
#### Cryptographic Failures
|
||||
- **CWE-327**: Broken cryptography
|
||||
- **Common in**: Cryptographic libraries, hash functions
|
||||
- **Detection**: Algorithm analysis, key management review
|
||||
- **Mitigation**: Modern cryptographic standards, proper key management
|
||||
|
||||
### Input Validation Issues
|
||||
|
||||
#### Cross-Site Scripting (XSS)
|
||||
- **CWE-79**: Improper neutralization of input
|
||||
- **Common in**: Web frameworks, template engines
|
||||
- **Detection**: Input handling analysis, output encoding review
|
||||
- **Mitigation**: Input validation, output encoding, Content Security Policy
|
||||
|
||||
#### Deserialization Vulnerabilities
|
||||
- **CWE-502**: Deserialization of untrusted data
|
||||
- **Common in**: Serialization libraries, data processing
|
||||
- **Detection**: Deserialization usage analysis
|
||||
- **Mitigation**: Avoid untrusted deserialization, input validation
|
||||
|
||||
## Risk Assessment Framework
|
||||
|
||||
### CVSS Scoring Components
|
||||
|
||||
#### Base Metrics
|
||||
1. **Attack Vector (AV)**
|
||||
- Network (N): 0.85
|
||||
- Adjacent (A): 0.62
|
||||
- Local (L): 0.55
|
||||
- Physical (P): 0.2
|
||||
|
||||
2. **Attack Complexity (AC)**
|
||||
- Low (L): 0.77
|
||||
- High (H): 0.44
|
||||
|
||||
3. **Privileges Required (PR)**
|
||||
- None (N): 0.85
|
||||
- Low (L): 0.62/0.68
|
||||
- High (H): 0.27/0.50
|
||||
|
||||
4. **User Interaction (UI)**
|
||||
- None (N): 0.85
|
||||
- Required (R): 0.62
|
||||
|
||||
5. **Impact Metrics (C/I/A)**
|
||||
- High (H): 0.56
|
||||
- Low (L): 0.22
|
||||
- None (N): 0
|
||||
|
||||
#### Temporal Metrics
|
||||
- **Exploit Code Maturity**: Proof of concept availability
|
||||
- **Remediation Level**: Official fix availability
|
||||
- **Report Confidence**: Vulnerability confirmation level
|
||||
|
||||
#### Environmental Metrics
|
||||
- **Confidentiality/Integrity/Availability Requirements**: Business impact
|
||||
- **Modified Base Metrics**: Environment-specific adjustments
|
||||
|
||||
### Custom Risk Factors
|
||||
|
||||
#### Business Context
|
||||
1. **Data Sensitivity**
|
||||
- Public data: Low risk multiplier (1.0x)
|
||||
- Internal data: Medium risk multiplier (1.2x)
|
||||
- Customer data: High risk multiplier (1.5x)
|
||||
- Regulated data: Critical risk multiplier (2.0x)
|
||||
|
||||
2. **System Criticality**
|
||||
- Development: Low impact (1.0x)
|
||||
- Staging: Medium impact (1.3x)
|
||||
- Production: High impact (1.8x)
|
||||
- Core infrastructure: Critical impact (2.5x)
|
||||
|
||||
3. **Exposure Level**
|
||||
- Internal systems: Base risk
|
||||
- Partner access: +1 risk level
|
||||
- Public internet: +2 risk levels
|
||||
- High-value target: +3 risk levels
|
||||
|
||||
#### Technical Factors
|
||||
|
||||
1. **Dependency Type**
|
||||
- Direct dependencies: Higher priority
|
||||
- Transitive dependencies: Lower priority (unless critical path)
|
||||
- Development dependencies: Lowest priority
|
||||
|
||||
2. **Usage Pattern**
|
||||
- Core functionality: Highest priority
|
||||
- Optional features: Medium priority
|
||||
- Unused code paths: Lowest priority
|
||||
|
||||
3. **Fix Availability**
|
||||
- Official patch available: Standard timeline
|
||||
- Workaround available: Extended timeline acceptable
|
||||
- No fix available: Risk acceptance or replacement needed
|
||||
|
||||
## Vulnerability Discovery and Monitoring
|
||||
|
||||
### Automated Scanning
|
||||
|
||||
#### Dependency Scanners
|
||||
- **npm audit**: Node.js ecosystem
|
||||
- **pip-audit**: Python ecosystem
|
||||
- **bundler-audit**: Ruby ecosystem
|
||||
- **OWASP Dependency Check**: Multi-language support
|
||||
|
||||
#### Continuous Monitoring
|
||||
```bash
|
||||
# Example CI/CD integration
|
||||
name: Security Scan
|
||||
on: [push, pull_request, schedule]
|
||||
jobs:
|
||||
security-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run dependency audit
|
||||
run: |
|
||||
npm audit --audit-level high
|
||||
python -m pip_audit
|
||||
bundle audit
|
||||
```
|
||||
|
||||
#### Commercial Tools
|
||||
- **Snyk**: Developer-first security platform
|
||||
- **WhiteSource**: Enterprise dependency management
|
||||
- **Veracode**: Application security platform
|
||||
- **Checkmarx**: Static application security testing
|
||||
|
||||
### Manual Assessment
|
||||
|
||||
#### Code Review Checklist
|
||||
1. **Input Validation**
|
||||
- [ ] All user inputs validated
|
||||
- [ ] Proper sanitization applied
|
||||
- [ ] Length and format restrictions
|
||||
|
||||
2. **Authentication/Authorization**
|
||||
- [ ] Proper authentication checks
|
||||
- [ ] Authorization at every access point
|
||||
- [ ] Session management secure
|
||||
|
||||
3. **Data Handling**
|
||||
- [ ] Sensitive data protected
|
||||
- [ ] Encryption properly implemented
|
||||
- [ ] Secure data transmission
|
||||
|
||||
4. **Error Handling**
|
||||
- [ ] No sensitive info in error messages
|
||||
- [ ] Proper logging without data leaks
|
||||
- [ ] Graceful error handling
|
||||
|
||||
## Prioritization Framework
|
||||
|
||||
### Priority Matrix
|
||||
|
||||
| Severity | Exploitability | Business Impact | Priority Level |
|
||||
|----------|---------------|-----------------|---------------|
|
||||
| Critical | High | High | P0 (Immediate) |
|
||||
| Critical | High | Medium | P0 (Immediate) |
|
||||
| Critical | Medium | High | P1 (24 hours) |
|
||||
| High | High | High | P1 (24 hours) |
|
||||
| High | High | Medium | P2 (1 week) |
|
||||
| High | Medium | High | P2 (1 week) |
|
||||
| Medium | High | High | P2 (1 week) |
|
||||
| All Others | - | - | P3 (30 days) |
|
||||
|
||||
### Prioritization Factors
|
||||
|
||||
#### Technical Factors (40% weight)
|
||||
1. **CVSS Base Score** (15%)
|
||||
2. **Exploit Availability** (10%)
|
||||
3. **Fix Complexity** (8%)
|
||||
4. **Dependency Criticality** (7%)
|
||||
|
||||
#### Business Factors (35% weight)
|
||||
1. **Data Impact** (15%)
|
||||
2. **System Criticality** (10%)
|
||||
3. **Regulatory Requirements** (5%)
|
||||
4. **Customer Impact** (5%)
|
||||
|
||||
#### Operational Factors (25% weight)
|
||||
1. **Attack Surface** (10%)
|
||||
2. **Monitoring Coverage** (8%)
|
||||
3. **Incident Response Capability** (7%)
|
||||
|
||||
### Scoring Formula
|
||||
```
|
||||
Priority Score = (Technical Score × 0.4) + (Business Score × 0.35) + (Operational Score × 0.25)
|
||||
|
||||
Where each component is scored 1-10:
|
||||
- 9-10: Critical priority
|
||||
- 7-8: High priority
|
||||
- 5-6: Medium priority
|
||||
- 3-4: Low priority
|
||||
- 1-2: Informational
|
||||
```
|
||||
|
||||
## Remediation Strategies
|
||||
|
||||
### Immediate Actions (P0/P1)
|
||||
|
||||
#### Hot Fixes
|
||||
1. **Version Upgrade**
|
||||
- Update to patched version
|
||||
- Test critical functionality
|
||||
- Deploy with rollback plan
|
||||
|
||||
2. **Configuration Changes**
|
||||
- Disable vulnerable features
|
||||
- Implement additional access controls
|
||||
- Add monitoring/alerting
|
||||
|
||||
3. **Workarounds**
|
||||
- Input validation layers
|
||||
- Network-level protections
|
||||
- Application-level mitigations
|
||||
|
||||
#### Emergency Response Process
|
||||
```
|
||||
1. Vulnerability Confirmed
|
||||
↓
|
||||
2. Impact Assessment (2 hours)
|
||||
↓
|
||||
3. Mitigation Strategy (4 hours)
|
||||
↓
|
||||
4. Implementation & Testing (12 hours)
|
||||
↓
|
||||
5. Deployment (2 hours)
|
||||
↓
|
||||
6. Monitoring & Validation (ongoing)
|
||||
```
|
||||
|
||||
### Planned Remediation (P2/P3)
|
||||
|
||||
#### Standard Update Process
|
||||
1. **Assessment Phase**
|
||||
- Detailed impact analysis
|
||||
- Testing requirements
|
||||
- Rollback procedures
|
||||
|
||||
2. **Planning Phase**
|
||||
- Update scheduling
|
||||
- Resource allocation
|
||||
- Communication plan
|
||||
|
||||
3. **Implementation Phase**
|
||||
- Development environment testing
|
||||
- Staging environment validation
|
||||
- Production deployment
|
||||
|
||||
4. **Validation Phase**
|
||||
- Functionality verification
|
||||
- Security testing
|
||||
- Performance monitoring
|
||||
|
||||
### Alternative Approaches
|
||||
|
||||
#### Dependency Replacement
|
||||
- **When to Consider**: No fix available, persistent vulnerabilities
|
||||
- **Process**: Impact analysis → Alternative evaluation → Migration planning
|
||||
- **Risks**: API changes, feature differences, stability concerns
|
||||
|
||||
#### Accept Risk (Last Resort)
|
||||
- **Criteria**: Very low probability, minimal impact, no feasible fix
|
||||
- **Requirements**: Executive approval, documented risk acceptance, monitoring
|
||||
- **Conditions**: Regular re-assessment, alternative solution tracking
|
||||
|
||||
## Remediation Tracking
|
||||
|
||||
### Metrics and KPIs
|
||||
|
||||
#### Vulnerability Metrics
|
||||
- **Mean Time to Detection (MTTD)**: Average time from publication to discovery
|
||||
- **Mean Time to Patch (MTTP)**: Average time from discovery to fix deployment
|
||||
- **Vulnerability Density**: Vulnerabilities per 1000 dependencies
|
||||
- **Fix Rate**: Percentage of vulnerabilities fixed within SLA
|
||||
|
||||
#### Trend Analysis
|
||||
- **Monthly vulnerability counts by severity**
|
||||
- **Average age of unpatched vulnerabilities**
|
||||
- **Remediation timeline trends**
|
||||
- **False positive rates**
|
||||
|
||||
#### Reporting Dashboard
|
||||
```
|
||||
Security Dashboard Components:
|
||||
├── Current Vulnerability Status
|
||||
│ ├── Critical: 2 (SLA: 24h)
|
||||
│ ├── High: 5 (SLA: 7d)
|
||||
│ └── Medium: 12 (SLA: 30d)
|
||||
├── Trend Analysis
|
||||
│ ├── New vulnerabilities (last 30 days)
|
||||
│ ├── Fixed vulnerabilities (last 30 days)
|
||||
│ └── Average resolution time
|
||||
└── Risk Assessment
|
||||
├── Overall risk score
|
||||
├── Top vulnerable components
|
||||
└── Compliance status
|
||||
```
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
### Vulnerability Records
|
||||
Each vulnerability should be documented with:
|
||||
- **CVE/Advisory ID**: Official vulnerability identifier
|
||||
- **Discovery Date**: When vulnerability was identified
|
||||
- **CVSS Score**: Base and environmental scores
|
||||
- **Affected Systems**: Components and versions impacted
|
||||
- **Business Impact**: Risk assessment and criticality
|
||||
- **Remediation Plan**: Planned fix approach and timeline
|
||||
- **Resolution Date**: When fix was implemented and verified
|
||||
|
||||
### Risk Acceptance Documentation
|
||||
For accepted risks, document:
|
||||
- **Risk Description**: Detailed vulnerability explanation
|
||||
- **Impact Analysis**: Potential business and technical impact
|
||||
- **Mitigation Measures**: Compensating controls implemented
|
||||
- **Acceptance Rationale**: Why risk is being accepted
|
||||
- **Review Schedule**: When risk will be reassessed
|
||||
- **Approver**: Who authorized the risk acceptance
|
||||
|
||||
## Integration with Development Workflow
|
||||
|
||||
### Shift-Left Security
|
||||
|
||||
#### Development Phase
|
||||
- **IDE Integration**: Real-time vulnerability detection
|
||||
- **Pre-commit Hooks**: Automated security checks
|
||||
- **Code Review**: Security-focused review criteria
|
||||
|
||||
#### CI/CD Integration
|
||||
- **Build Stage**: Dependency vulnerability scanning
|
||||
- **Test Stage**: Security test automation
|
||||
- **Deploy Stage**: Final security validation
|
||||
|
||||
#### Production Monitoring
|
||||
- **Runtime Protection**: Web application firewalls, runtime security
|
||||
- **Continuous Scanning**: Regular dependency updates check
|
||||
- **Incident Response**: Automated vulnerability alert handling
|
||||
|
||||
### Security Gates
|
||||
```yaml
|
||||
security_gates:
|
||||
development:
|
||||
- dependency_scan: true
|
||||
- secret_detection: true
|
||||
- code_quality: true
|
||||
|
||||
staging:
|
||||
- penetration_test: true
|
||||
- compliance_check: true
|
||||
- performance_test: true
|
||||
|
||||
production:
|
||||
- final_security_scan: true
|
||||
- change_approval: required
|
||||
- rollback_plan: verified
|
||||
```
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
### Proactive Measures
|
||||
1. **Regular Scanning**: Automated daily/weekly scans
|
||||
2. **Update Schedule**: Regular dependency maintenance
|
||||
3. **Security Training**: Developer security awareness
|
||||
4. **Threat Modeling**: Understanding attack vectors
|
||||
|
||||
### Reactive Measures
|
||||
1. **Incident Response**: Well-defined process for critical vulnerabilities
|
||||
2. **Communication Plan**: Stakeholder notification procedures
|
||||
3. **Lessons Learned**: Post-incident analysis and improvement
|
||||
4. **Recovery Procedures**: Rollback and recovery capabilities
|
||||
|
||||
### Organizational Considerations
|
||||
1. **Responsibility Assignment**: Clear ownership of security tasks
|
||||
2. **Resource Allocation**: Adequate security budget and staffing
|
||||
3. **Tool Selection**: Appropriate security tools for organization size
|
||||
4. **Compliance Requirements**: Meeting regulatory and industry standards
|
||||
|
||||
Remember: Vulnerability management is an ongoing process requiring continuous attention, regular updates to procedures, and organizational commitment to security best practices.
|
||||
@@ -0,0 +1,794 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Dependency Scanner - Multi-language dependency vulnerability and analysis tool.
|
||||
|
||||
This script parses dependency files from various package managers, extracts direct
|
||||
and transitive dependencies, checks against built-in vulnerability databases,
|
||||
and provides comprehensive security analysis with actionable recommendations.
|
||||
|
||||
Author: Claude Skills Engineering Team
|
||||
License: MIT
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
from typing import Dict, List, Set, Any, Optional, Tuple
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass, asdict
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
import subprocess
|
||||
|
||||
@dataclass
|
||||
class Vulnerability:
|
||||
"""Represents a security vulnerability."""
|
||||
id: str
|
||||
summary: str
|
||||
severity: str
|
||||
cvss_score: float
|
||||
affected_versions: str
|
||||
fixed_version: Optional[str]
|
||||
published_date: str
|
||||
references: List[str]
|
||||
|
||||
@dataclass
|
||||
class Dependency:
|
||||
"""Represents a project dependency."""
|
||||
name: str
|
||||
version: str
|
||||
ecosystem: str
|
||||
direct: bool
|
||||
license: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
homepage: Optional[str] = None
|
||||
vulnerabilities: List[Vulnerability] = None
|
||||
|
||||
def __post_init__(self):
|
||||
if self.vulnerabilities is None:
|
||||
self.vulnerabilities = []
|
||||
|
||||
class DependencyScanner:
|
||||
"""Main dependency scanner class."""
|
||||
|
||||
def __init__(self):
|
||||
self.known_vulnerabilities = self._load_vulnerability_database()
|
||||
self.supported_files = {
|
||||
'package.json': self._parse_package_json,
|
||||
'package-lock.json': self._parse_package_lock,
|
||||
'yarn.lock': self._parse_yarn_lock,
|
||||
'requirements.txt': self._parse_requirements_txt,
|
||||
'pyproject.toml': self._parse_pyproject_toml,
|
||||
'Pipfile.lock': self._parse_pipfile_lock,
|
||||
'poetry.lock': self._parse_poetry_lock,
|
||||
'go.mod': self._parse_go_mod,
|
||||
'go.sum': self._parse_go_sum,
|
||||
'Cargo.toml': self._parse_cargo_toml,
|
||||
'Cargo.lock': self._parse_cargo_lock,
|
||||
'Gemfile': self._parse_gemfile,
|
||||
'Gemfile.lock': self._parse_gemfile_lock,
|
||||
}
|
||||
|
||||
def _load_vulnerability_database(self) -> Dict[str, List[Vulnerability]]:
|
||||
"""Load built-in vulnerability database with common CVE patterns."""
|
||||
return {
|
||||
# JavaScript/Node.js vulnerabilities
|
||||
'lodash': [
|
||||
Vulnerability(
|
||||
id='CVE-2021-23337',
|
||||
summary='Prototype pollution in lodash',
|
||||
severity='HIGH',
|
||||
cvss_score=7.2,
|
||||
affected_versions='<4.17.21',
|
||||
fixed_version='4.17.21',
|
||||
published_date='2021-02-15',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2021-23337']
|
||||
)
|
||||
],
|
||||
'axios': [
|
||||
Vulnerability(
|
||||
id='CVE-2023-45857',
|
||||
summary='Cross-site request forgery in axios',
|
||||
severity='MEDIUM',
|
||||
cvss_score=6.1,
|
||||
affected_versions='>=1.0.0 <1.6.0',
|
||||
fixed_version='1.6.0',
|
||||
published_date='2023-10-11',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2023-45857']
|
||||
)
|
||||
],
|
||||
'express': [
|
||||
Vulnerability(
|
||||
id='CVE-2022-24999',
|
||||
summary='Open redirect in express',
|
||||
severity='MEDIUM',
|
||||
cvss_score=6.1,
|
||||
affected_versions='<4.18.2',
|
||||
fixed_version='4.18.2',
|
||||
published_date='2022-11-26',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2022-24999']
|
||||
)
|
||||
],
|
||||
|
||||
# Python vulnerabilities
|
||||
'django': [
|
||||
Vulnerability(
|
||||
id='CVE-2024-27351',
|
||||
summary='SQL injection in Django',
|
||||
severity='HIGH',
|
||||
cvss_score=9.8,
|
||||
affected_versions='>=3.2 <4.2.11',
|
||||
fixed_version='4.2.11',
|
||||
published_date='2024-02-06',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2024-27351']
|
||||
)
|
||||
],
|
||||
'requests': [
|
||||
Vulnerability(
|
||||
id='CVE-2023-32681',
|
||||
summary='Proxy-authorization header leak in requests',
|
||||
severity='MEDIUM',
|
||||
cvss_score=6.1,
|
||||
affected_versions='>=2.3.0 <2.31.0',
|
||||
fixed_version='2.31.0',
|
||||
published_date='2023-05-26',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2023-32681']
|
||||
)
|
||||
],
|
||||
'pillow': [
|
||||
Vulnerability(
|
||||
id='CVE-2023-50447',
|
||||
summary='Arbitrary code execution in Pillow',
|
||||
severity='HIGH',
|
||||
cvss_score=8.8,
|
||||
affected_versions='<10.2.0',
|
||||
fixed_version='10.2.0',
|
||||
published_date='2024-01-02',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2023-50447']
|
||||
)
|
||||
],
|
||||
|
||||
# Go vulnerabilities
|
||||
'github.com/gin-gonic/gin': [
|
||||
Vulnerability(
|
||||
id='CVE-2023-26125',
|
||||
summary='Path traversal in gin',
|
||||
severity='HIGH',
|
||||
cvss_score=7.5,
|
||||
affected_versions='<1.9.1',
|
||||
fixed_version='1.9.1',
|
||||
published_date='2023-02-28',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2023-26125']
|
||||
)
|
||||
],
|
||||
|
||||
# Rust vulnerabilities
|
||||
'serde': [
|
||||
Vulnerability(
|
||||
id='RUSTSEC-2022-0061',
|
||||
summary='Deserialization vulnerability in serde',
|
||||
severity='HIGH',
|
||||
cvss_score=8.2,
|
||||
affected_versions='<1.0.152',
|
||||
fixed_version='1.0.152',
|
||||
published_date='2022-12-07',
|
||||
references=['https://rustsec.org/advisories/RUSTSEC-2022-0061']
|
||||
)
|
||||
],
|
||||
|
||||
# Ruby vulnerabilities
|
||||
'rails': [
|
||||
Vulnerability(
|
||||
id='CVE-2023-28362',
|
||||
summary='ReDoS vulnerability in Rails',
|
||||
severity='HIGH',
|
||||
cvss_score=7.5,
|
||||
affected_versions='>=7.0.0 <7.0.4.3',
|
||||
fixed_version='7.0.4.3',
|
||||
published_date='2023-03-13',
|
||||
references=['https://nvd.nist.gov/vuln/detail/CVE-2023-28362']
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
def scan_project(self, project_path: str) -> Dict[str, Any]:
|
||||
"""Scan a project directory for dependencies and vulnerabilities."""
|
||||
project_path = Path(project_path)
|
||||
|
||||
if not project_path.exists():
|
||||
raise FileNotFoundError(f"Project path does not exist: {project_path}")
|
||||
|
||||
scan_results = {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'project_path': str(project_path),
|
||||
'dependencies': [],
|
||||
'vulnerabilities_found': 0,
|
||||
'high_severity_count': 0,
|
||||
'medium_severity_count': 0,
|
||||
'low_severity_count': 0,
|
||||
'ecosystems': set(),
|
||||
'scan_summary': {},
|
||||
'recommendations': []
|
||||
}
|
||||
|
||||
# Find and parse dependency files
|
||||
for file_pattern, parser in self.supported_files.items():
|
||||
matching_files = list(project_path.rglob(file_pattern))
|
||||
|
||||
for dep_file in matching_files:
|
||||
try:
|
||||
dependencies = parser(dep_file)
|
||||
scan_results['dependencies'].extend(dependencies)
|
||||
|
||||
for dep in dependencies:
|
||||
scan_results['ecosystems'].add(dep.ecosystem)
|
||||
|
||||
# Check for vulnerabilities
|
||||
vulnerabilities = self._check_vulnerabilities(dep)
|
||||
dep.vulnerabilities = vulnerabilities
|
||||
|
||||
scan_results['vulnerabilities_found'] += len(vulnerabilities)
|
||||
|
||||
for vuln in vulnerabilities:
|
||||
if vuln.severity == 'HIGH':
|
||||
scan_results['high_severity_count'] += 1
|
||||
elif vuln.severity == 'MEDIUM':
|
||||
scan_results['medium_severity_count'] += 1
|
||||
else:
|
||||
scan_results['low_severity_count'] += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing {dep_file}: {e}")
|
||||
continue
|
||||
|
||||
scan_results['ecosystems'] = list(scan_results['ecosystems'])
|
||||
scan_results['scan_summary'] = self._generate_scan_summary(scan_results)
|
||||
scan_results['recommendations'] = self._generate_recommendations(scan_results)
|
||||
|
||||
return scan_results
|
||||
|
||||
def _check_vulnerabilities(self, dependency: Dependency) -> List[Vulnerability]:
|
||||
"""Check if a dependency has known vulnerabilities."""
|
||||
vulnerabilities = []
|
||||
|
||||
# Check package name (exact match and common variations)
|
||||
package_names = [dependency.name, dependency.name.lower()]
|
||||
|
||||
for pkg_name in package_names:
|
||||
if pkg_name in self.known_vulnerabilities:
|
||||
for vuln in self.known_vulnerabilities[pkg_name]:
|
||||
if self._version_matches_vulnerability(dependency.version, vuln.affected_versions):
|
||||
vulnerabilities.append(vuln)
|
||||
|
||||
return vulnerabilities
|
||||
|
||||
def _version_matches_vulnerability(self, version: str, affected_pattern: str) -> bool:
|
||||
"""Check if a version matches a vulnerability pattern."""
|
||||
# Simple version matching - in production, use proper semver library
|
||||
try:
|
||||
# Handle common patterns like "<4.17.21", ">=1.0.0 <1.6.0"
|
||||
if '<' in affected_pattern and '>' not in affected_pattern:
|
||||
# Pattern like "<4.17.21"
|
||||
max_version = affected_pattern.replace('<', '').strip()
|
||||
return self._compare_versions(version, max_version) < 0
|
||||
elif '>=' in affected_pattern and '<' in affected_pattern:
|
||||
# Pattern like ">=1.0.0 <1.6.0"
|
||||
parts = affected_pattern.split('<')
|
||||
min_part = parts[0].replace('>=', '').strip()
|
||||
max_part = parts[1].strip()
|
||||
return (self._compare_versions(version, min_part) >= 0 and
|
||||
self._compare_versions(version, max_part) < 0)
|
||||
except:
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def _compare_versions(self, v1: str, v2: str) -> int:
|
||||
"""Simple version comparison. Returns -1, 0, or 1."""
|
||||
try:
|
||||
def normalize(v):
|
||||
return [int(x) for x in re.sub(r'(\.0+)*$','', v).split('.')]
|
||||
|
||||
v1_parts = normalize(v1)
|
||||
v2_parts = normalize(v2)
|
||||
|
||||
if v1_parts < v2_parts:
|
||||
return -1
|
||||
elif v1_parts > v2_parts:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
except:
|
||||
return 0
|
||||
|
||||
# Package file parsers
|
||||
|
||||
def _parse_package_json(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse package.json for Node.js dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Parse dependencies
|
||||
for dep_type in ['dependencies', 'devDependencies']:
|
||||
if dep_type in data:
|
||||
for name, version in data[dep_type].items():
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version.replace('^', '').replace('~', '').replace('>=', '').replace('<=', ''),
|
||||
ecosystem='npm',
|
||||
direct=True
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing package.json: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_package_lock(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse package-lock.json for Node.js transitive dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if 'packages' in data:
|
||||
for path, pkg_info in data['packages'].items():
|
||||
if path == '': # Skip root package
|
||||
continue
|
||||
|
||||
name = path.split('/')[-1] if '/' in path else path
|
||||
version = pkg_info.get('version', '')
|
||||
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='npm',
|
||||
direct=False,
|
||||
description=pkg_info.get('description', '')
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing package-lock.json: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_yarn_lock(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse yarn.lock for Node.js dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Simple yarn.lock parsing
|
||||
packages = re.findall(r'^([^#\s][^:]+):\s*\n(?:\s+.*\n)*?\s+version\s+"([^"]+)"', content, re.MULTILINE)
|
||||
|
||||
for package_spec, version in packages:
|
||||
name = package_spec.split('@')[0] if '@' in package_spec else package_spec
|
||||
name = name.strip('"')
|
||||
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='npm',
|
||||
direct=False
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing yarn.lock: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_requirements_txt(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse requirements.txt for Python dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line and not line.startswith('#') and not line.startswith('-'):
|
||||
# Parse package==version or package>=version patterns
|
||||
match = re.match(r'^([a-zA-Z0-9_-]+)([><=!]+)(.+)$', line)
|
||||
if match:
|
||||
name, operator, version = match.groups()
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='pypi',
|
||||
direct=True
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing requirements.txt: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_pyproject_toml(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse pyproject.toml for Python dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Simple TOML parsing for dependencies
|
||||
dep_section = re.search(r'\[tool\.poetry\.dependencies\](.*?)(?=\[|\Z)', content, re.DOTALL)
|
||||
if dep_section:
|
||||
for line in dep_section.group(1).split('\n'):
|
||||
match = re.match(r'^([a-zA-Z0-9_-]+)\s*=\s*["\']([^"\']+)["\']', line.strip())
|
||||
if match:
|
||||
name, version = match.groups()
|
||||
if name != 'python':
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version.replace('^', '').replace('~', ''),
|
||||
ecosystem='pypi',
|
||||
direct=True
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing pyproject.toml: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_pipfile_lock(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse Pipfile.lock for Python dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
for section in ['default', 'develop']:
|
||||
if section in data:
|
||||
for name, info in data[section].items():
|
||||
version = info.get('version', '').replace('==', '')
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='pypi',
|
||||
direct=(section == 'default')
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing Pipfile.lock: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_poetry_lock(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse poetry.lock for Python dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Extract package entries from TOML
|
||||
packages = re.findall(r'\[\[package\]\]\nname\s*=\s*"([^"]+)"\nversion\s*=\s*"([^"]+)"', content)
|
||||
|
||||
for name, version in packages:
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='pypi',
|
||||
direct=False
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing poetry.lock: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_go_mod(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse go.mod for Go dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Parse require block
|
||||
require_match = re.search(r'require\s*\((.*?)\)', content, re.DOTALL)
|
||||
if require_match:
|
||||
requires = require_match.group(1)
|
||||
for line in requires.split('\n'):
|
||||
match = re.match(r'\s*([^\s]+)\s+v?([^\s]+)', line.strip())
|
||||
if match:
|
||||
name, version = match.groups()
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='go',
|
||||
direct=True
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing go.mod: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_go_sum(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse go.sum for Go dependency checksums."""
|
||||
return [] # go.sum mainly contains checksums, dependencies are in go.mod
|
||||
|
||||
def _parse_cargo_toml(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse Cargo.toml for Rust dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Parse [dependencies] section
|
||||
dep_section = re.search(r'\[dependencies\](.*?)(?=\[|\Z)', content, re.DOTALL)
|
||||
if dep_section:
|
||||
for line in dep_section.group(1).split('\n'):
|
||||
match = re.match(r'^([a-zA-Z0-9_-]+)\s*=\s*["\']([^"\']+)["\']', line.strip())
|
||||
if match:
|
||||
name, version = match.groups()
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='cargo',
|
||||
direct=True
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing Cargo.toml: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_cargo_lock(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse Cargo.lock for Rust dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Parse [[package]] entries
|
||||
packages = re.findall(r'\[\[package\]\]\nname\s*=\s*"([^"]+)"\nversion\s*=\s*"([^"]+)"', content)
|
||||
|
||||
for name, version in packages:
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='cargo',
|
||||
direct=False
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing Cargo.lock: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_gemfile(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse Gemfile for Ruby dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Parse gem declarations
|
||||
gems = re.findall(r'gem\s+["\']([^"\']+)["\'](?:\s*,\s*["\']([^"\']+)["\'])?', content)
|
||||
|
||||
for gem_info in gems:
|
||||
name = gem_info[0]
|
||||
version = gem_info[1] if len(gem_info) > 1 and gem_info[1] else ''
|
||||
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='rubygems',
|
||||
direct=True
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing Gemfile: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _parse_gemfile_lock(self, file_path: Path) -> List[Dependency]:
|
||||
"""Parse Gemfile.lock for Ruby dependencies."""
|
||||
dependencies = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Extract GEM section
|
||||
gem_section = re.search(r'GEM\s*\n(.*?)(?=\n\S|\Z)', content, re.DOTALL)
|
||||
if gem_section:
|
||||
specs = gem_section.group(1)
|
||||
gems = re.findall(r'\s+([a-zA-Z0-9_-]+)\s+\(([^)]+)\)', specs)
|
||||
|
||||
for name, version in gems:
|
||||
dep = Dependency(
|
||||
name=name,
|
||||
version=version,
|
||||
ecosystem='rubygems',
|
||||
direct=False
|
||||
)
|
||||
dependencies.append(dep)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error parsing Gemfile.lock: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _generate_scan_summary(self, scan_results: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate a summary of the scan results."""
|
||||
total_deps = len(scan_results['dependencies'])
|
||||
unique_deps = len(set(dep.name for dep in scan_results['dependencies']))
|
||||
|
||||
return {
|
||||
'total_dependencies': total_deps,
|
||||
'unique_dependencies': unique_deps,
|
||||
'ecosystems_found': len(scan_results['ecosystems']),
|
||||
'vulnerable_dependencies': len([dep for dep in scan_results['dependencies'] if dep.vulnerabilities]),
|
||||
'vulnerability_breakdown': {
|
||||
'high': scan_results['high_severity_count'],
|
||||
'medium': scan_results['medium_severity_count'],
|
||||
'low': scan_results['low_severity_count']
|
||||
}
|
||||
}
|
||||
|
||||
def _generate_recommendations(self, scan_results: Dict[str, Any]) -> List[str]:
|
||||
"""Generate actionable recommendations based on scan results."""
|
||||
recommendations = []
|
||||
|
||||
high_count = scan_results['high_severity_count']
|
||||
medium_count = scan_results['medium_severity_count']
|
||||
|
||||
if high_count > 0:
|
||||
recommendations.append(f"URGENT: Address {high_count} high-severity vulnerabilities immediately")
|
||||
|
||||
if medium_count > 0:
|
||||
recommendations.append(f"Schedule fixes for {medium_count} medium-severity vulnerabilities within 30 days")
|
||||
|
||||
vulnerable_deps = [dep for dep in scan_results['dependencies'] if dep.vulnerabilities]
|
||||
if vulnerable_deps:
|
||||
for dep in vulnerable_deps[:3]: # Top 3 most critical
|
||||
for vuln in dep.vulnerabilities:
|
||||
if vuln.fixed_version:
|
||||
recommendations.append(f"Update {dep.name} from {dep.version} to {vuln.fixed_version} to fix {vuln.id}")
|
||||
|
||||
if len(scan_results['ecosystems']) > 3:
|
||||
recommendations.append("Consider consolidating package managers to reduce complexity")
|
||||
|
||||
return recommendations
|
||||
|
||||
def generate_report(self, scan_results: Dict[str, Any], format: str = 'text') -> str:
|
||||
"""Generate a human-readable or JSON report."""
|
||||
if format == 'json':
|
||||
# Convert Dependency objects to dicts for JSON serialization
|
||||
serializable_results = scan_results.copy()
|
||||
serializable_results['dependencies'] = [
|
||||
{
|
||||
'name': dep.name,
|
||||
'version': dep.version,
|
||||
'ecosystem': dep.ecosystem,
|
||||
'direct': dep.direct,
|
||||
'license': dep.license,
|
||||
'vulnerabilities': [asdict(vuln) for vuln in dep.vulnerabilities]
|
||||
}
|
||||
for dep in scan_results['dependencies']
|
||||
]
|
||||
return json.dumps(serializable_results, indent=2, default=str)
|
||||
|
||||
# Text format report
|
||||
report = []
|
||||
report.append("=" * 60)
|
||||
report.append("DEPENDENCY SECURITY SCAN REPORT")
|
||||
report.append("=" * 60)
|
||||
report.append(f"Scan Date: {scan_results['timestamp']}")
|
||||
report.append(f"Project: {scan_results['project_path']}")
|
||||
report.append("")
|
||||
|
||||
# Summary
|
||||
summary = scan_results['scan_summary']
|
||||
report.append("SUMMARY:")
|
||||
report.append(f" Total Dependencies: {summary['total_dependencies']}")
|
||||
report.append(f" Unique Dependencies: {summary['unique_dependencies']}")
|
||||
report.append(f" Ecosystems: {', '.join(scan_results['ecosystems'])}")
|
||||
report.append(f" Vulnerabilities Found: {scan_results['vulnerabilities_found']}")
|
||||
report.append(f" High Severity: {summary['vulnerability_breakdown']['high']}")
|
||||
report.append(f" Medium Severity: {summary['vulnerability_breakdown']['medium']}")
|
||||
report.append(f" Low Severity: {summary['vulnerability_breakdown']['low']}")
|
||||
report.append("")
|
||||
|
||||
# Vulnerable dependencies
|
||||
vulnerable_deps = [dep for dep in scan_results['dependencies'] if dep.vulnerabilities]
|
||||
if vulnerable_deps:
|
||||
report.append("VULNERABLE DEPENDENCIES:")
|
||||
report.append("-" * 30)
|
||||
|
||||
for dep in vulnerable_deps:
|
||||
report.append(f"Package: {dep.name} v{dep.version} ({dep.ecosystem})")
|
||||
for vuln in dep.vulnerabilities:
|
||||
report.append(f" • {vuln.id}: {vuln.summary}")
|
||||
report.append(f" Severity: {vuln.severity} (CVSS: {vuln.cvss_score})")
|
||||
if vuln.fixed_version:
|
||||
report.append(f" Fixed in: {vuln.fixed_version}")
|
||||
report.append("")
|
||||
|
||||
# Recommendations
|
||||
if scan_results['recommendations']:
|
||||
report.append("RECOMMENDATIONS:")
|
||||
report.append("-" * 20)
|
||||
for i, rec in enumerate(scan_results['recommendations'], 1):
|
||||
report.append(f"{i}. {rec}")
|
||||
report.append("")
|
||||
|
||||
report.append("=" * 60)
|
||||
return '\n'.join(report)
|
||||
|
||||
def main():
|
||||
"""Main entry point for the dependency scanner."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Scan project dependencies for vulnerabilities and security issues',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python dep_scanner.py /path/to/project
|
||||
python dep_scanner.py . --format json --output results.json
|
||||
python dep_scanner.py /app --fail-on-high
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument('project_path',
|
||||
help='Path to the project directory to scan')
|
||||
parser.add_argument('--format', choices=['text', 'json'], default='text',
|
||||
help='Output format (default: text)')
|
||||
parser.add_argument('--output', '-o',
|
||||
help='Output file path (default: stdout)')
|
||||
parser.add_argument('--fail-on-high', action='store_true',
|
||||
help='Exit with error code if high-severity vulnerabilities found')
|
||||
parser.add_argument('--quick-scan', action='store_true',
|
||||
help='Perform quick scan (skip transitive dependencies)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
scanner = DependencyScanner()
|
||||
results = scanner.scan_project(args.project_path)
|
||||
report = scanner.generate_report(results, args.format)
|
||||
|
||||
if args.output:
|
||||
with open(args.output, 'w') as f:
|
||||
f.write(report)
|
||||
print(f"Report saved to {args.output}")
|
||||
else:
|
||||
print(report)
|
||||
|
||||
# Exit with error if high-severity vulnerabilities found and --fail-on-high is set
|
||||
if args.fail_on_high and results['high_severity_count'] > 0:
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,996 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
License Checker - Dependency license compliance and conflict analysis tool.
|
||||
|
||||
This script analyzes dependency licenses from package metadata, classifies them
|
||||
into risk categories, detects license conflicts, and generates compliance
|
||||
reports with actionable recommendations for legal risk management.
|
||||
|
||||
Author: Claude Skills Engineering Team
|
||||
License: MIT
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from typing import Dict, List, Set, Any, Optional, Tuple
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass, asdict
|
||||
from datetime import datetime
|
||||
import re
|
||||
from enum import Enum
|
||||
|
||||
class LicenseType(Enum):
|
||||
"""License classification types."""
|
||||
PERMISSIVE = "permissive"
|
||||
COPYLEFT_STRONG = "copyleft_strong"
|
||||
COPYLEFT_WEAK = "copyleft_weak"
|
||||
PROPRIETARY = "proprietary"
|
||||
DUAL = "dual"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
class RiskLevel(Enum):
|
||||
"""Risk assessment levels."""
|
||||
LOW = "low"
|
||||
MEDIUM = "medium"
|
||||
HIGH = "high"
|
||||
CRITICAL = "critical"
|
||||
|
||||
@dataclass
|
||||
class LicenseInfo:
|
||||
"""Represents license information for a dependency."""
|
||||
name: str
|
||||
spdx_id: Optional[str]
|
||||
license_type: LicenseType
|
||||
risk_level: RiskLevel
|
||||
description: str
|
||||
restrictions: List[str]
|
||||
obligations: List[str]
|
||||
compatibility: Dict[str, bool]
|
||||
|
||||
@dataclass
|
||||
class DependencyLicense:
|
||||
"""Represents a dependency with its license information."""
|
||||
name: str
|
||||
version: str
|
||||
ecosystem: str
|
||||
direct: bool
|
||||
license_declared: Optional[str]
|
||||
license_detected: Optional[LicenseInfo]
|
||||
license_files: List[str]
|
||||
confidence: float
|
||||
|
||||
@dataclass
|
||||
class LicenseConflict:
|
||||
"""Represents a license compatibility conflict."""
|
||||
dependency1: str
|
||||
license1: str
|
||||
dependency2: str
|
||||
license2: str
|
||||
conflict_type: str
|
||||
severity: RiskLevel
|
||||
description: str
|
||||
resolution_options: List[str]
|
||||
|
||||
class LicenseChecker:
|
||||
"""Main license checking and compliance analysis class."""
|
||||
|
||||
def __init__(self):
|
||||
self.license_database = self._build_license_database()
|
||||
self.compatibility_matrix = self._build_compatibility_matrix()
|
||||
self.license_patterns = self._build_license_patterns()
|
||||
|
||||
def _build_license_database(self) -> Dict[str, LicenseInfo]:
|
||||
"""Build comprehensive license database with risk classifications."""
|
||||
return {
|
||||
# Permissive Licenses (Low Risk)
|
||||
'MIT': LicenseInfo(
|
||||
name='MIT License',
|
||||
spdx_id='MIT',
|
||||
license_type=LicenseType.PERMISSIVE,
|
||||
risk_level=RiskLevel.LOW,
|
||||
description='Very permissive license with minimal restrictions',
|
||||
restrictions=['Include copyright notice', 'Include license text'],
|
||||
obligations=['Attribution'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
'Apache-2.0': LicenseInfo(
|
||||
name='Apache License 2.0',
|
||||
spdx_id='Apache-2.0',
|
||||
license_type=LicenseType.PERMISSIVE,
|
||||
risk_level=RiskLevel.LOW,
|
||||
description='Permissive license with patent protection',
|
||||
restrictions=['Include copyright notice', 'Include license text',
|
||||
'State changes', 'Include NOTICE file'],
|
||||
obligations=['Attribution', 'Patent grant'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': True
|
||||
}
|
||||
),
|
||||
|
||||
'BSD-3-Clause': LicenseInfo(
|
||||
name='BSD 3-Clause License',
|
||||
spdx_id='BSD-3-Clause',
|
||||
license_type=LicenseType.PERMISSIVE,
|
||||
risk_level=RiskLevel.LOW,
|
||||
description='Permissive license with non-endorsement clause',
|
||||
restrictions=['Include copyright notice', 'Include license text',
|
||||
'No endorsement using author names'],
|
||||
obligations=['Attribution'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
'BSD-2-Clause': LicenseInfo(
|
||||
name='BSD 2-Clause License',
|
||||
spdx_id='BSD-2-Clause',
|
||||
license_type=LicenseType.PERMISSIVE,
|
||||
risk_level=RiskLevel.LOW,
|
||||
description='Very permissive license similar to MIT',
|
||||
restrictions=['Include copyright notice', 'Include license text'],
|
||||
obligations=['Attribution'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
'ISC': LicenseInfo(
|
||||
name='ISC License',
|
||||
spdx_id='ISC',
|
||||
license_type=LicenseType.PERMISSIVE,
|
||||
risk_level=RiskLevel.LOW,
|
||||
description='Functionally equivalent to MIT license',
|
||||
restrictions=['Include copyright notice'],
|
||||
obligations=['Attribution'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
# Weak Copyleft Licenses (Medium Risk)
|
||||
'MPL-2.0': LicenseInfo(
|
||||
name='Mozilla Public License 2.0',
|
||||
spdx_id='MPL-2.0',
|
||||
license_type=LicenseType.COPYLEFT_WEAK,
|
||||
risk_level=RiskLevel.MEDIUM,
|
||||
description='File-level copyleft license',
|
||||
restrictions=['Disclose source of modified files', 'Include copyright notice',
|
||||
'Include license text', 'State changes'],
|
||||
obligations=['Source disclosure (modified files only)'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': True
|
||||
}
|
||||
),
|
||||
|
||||
'LGPL-2.1': LicenseInfo(
|
||||
name='GNU Lesser General Public License 2.1',
|
||||
spdx_id='LGPL-2.1',
|
||||
license_type=LicenseType.COPYLEFT_WEAK,
|
||||
risk_level=RiskLevel.MEDIUM,
|
||||
description='Library-level copyleft license',
|
||||
restrictions=['Disclose source of library modifications', 'Include copyright notice',
|
||||
'Include license text', 'Allow relinking'],
|
||||
obligations=['Source disclosure (library modifications)', 'Dynamic linking preferred'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
'LGPL-3.0': LicenseInfo(
|
||||
name='GNU Lesser General Public License 3.0',
|
||||
spdx_id='LGPL-3.0',
|
||||
license_type=LicenseType.COPYLEFT_WEAK,
|
||||
risk_level=RiskLevel.MEDIUM,
|
||||
description='Library-level copyleft with patent provisions',
|
||||
restrictions=['Disclose source of library modifications', 'Include copyright notice',
|
||||
'Include license text', 'Allow relinking', 'Anti-tivoization'],
|
||||
obligations=['Source disclosure (library modifications)', 'Patent grant'],
|
||||
compatibility={
|
||||
'commercial': True, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': True
|
||||
}
|
||||
),
|
||||
|
||||
# Strong Copyleft Licenses (High Risk)
|
||||
'GPL-2.0': LicenseInfo(
|
||||
name='GNU General Public License 2.0',
|
||||
spdx_id='GPL-2.0',
|
||||
license_type=LicenseType.COPYLEFT_STRONG,
|
||||
risk_level=RiskLevel.HIGH,
|
||||
description='Strong copyleft requiring full source disclosure',
|
||||
restrictions=['Disclose entire source code', 'Include copyright notice',
|
||||
'Include license text', 'Use same license'],
|
||||
obligations=['Full source disclosure', 'License compatibility'],
|
||||
compatibility={
|
||||
'commercial': False, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
'GPL-3.0': LicenseInfo(
|
||||
name='GNU General Public License 3.0',
|
||||
spdx_id='GPL-3.0',
|
||||
license_type=LicenseType.COPYLEFT_STRONG,
|
||||
risk_level=RiskLevel.HIGH,
|
||||
description='Strong copyleft with patent and hardware provisions',
|
||||
restrictions=['Disclose entire source code', 'Include copyright notice',
|
||||
'Include license text', 'Use same license', 'Anti-tivoization'],
|
||||
obligations=['Full source disclosure', 'Patent grant', 'License compatibility'],
|
||||
compatibility={
|
||||
'commercial': False, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': True
|
||||
}
|
||||
),
|
||||
|
||||
'AGPL-3.0': LicenseInfo(
|
||||
name='GNU Affero General Public License 3.0',
|
||||
spdx_id='AGPL-3.0',
|
||||
license_type=LicenseType.COPYLEFT_STRONG,
|
||||
risk_level=RiskLevel.CRITICAL,
|
||||
description='Network copyleft extending GPL to SaaS',
|
||||
restrictions=['Disclose entire source code', 'Include copyright notice',
|
||||
'Include license text', 'Use same license', 'Network use triggers copyleft'],
|
||||
obligations=['Full source disclosure', 'Network service source disclosure'],
|
||||
compatibility={
|
||||
'commercial': False, 'modification': True, 'distribution': True,
|
||||
'private_use': True, 'patent_grant': True
|
||||
}
|
||||
),
|
||||
|
||||
# Proprietary/Commercial Licenses (High Risk)
|
||||
'PROPRIETARY': LicenseInfo(
|
||||
name='Proprietary License',
|
||||
spdx_id=None,
|
||||
license_type=LicenseType.PROPRIETARY,
|
||||
risk_level=RiskLevel.HIGH,
|
||||
description='Commercial or custom proprietary license',
|
||||
restrictions=['Varies by license', 'Often no redistribution',
|
||||
'May require commercial license'],
|
||||
obligations=['License agreement compliance', 'Payment obligations'],
|
||||
compatibility={
|
||||
'commercial': False, 'modification': False, 'distribution': False,
|
||||
'private_use': True, 'patent_grant': False
|
||||
}
|
||||
),
|
||||
|
||||
# Unknown/Unlicensed (Critical Risk)
|
||||
'UNKNOWN': LicenseInfo(
|
||||
name='Unknown License',
|
||||
spdx_id=None,
|
||||
license_type=LicenseType.UNKNOWN,
|
||||
risk_level=RiskLevel.CRITICAL,
|
||||
description='No license detected or ambiguous licensing',
|
||||
restrictions=['Unknown', 'Assume no rights granted'],
|
||||
obligations=['Investigate and clarify licensing'],
|
||||
compatibility={
|
||||
'commercial': False, 'modification': False, 'distribution': False,
|
||||
'private_use': False, 'patent_grant': False
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
def _build_compatibility_matrix(self) -> Dict[str, Dict[str, bool]]:
|
||||
"""Build license compatibility matrix."""
|
||||
return {
|
||||
'MIT': {
|
||||
'MIT': True, 'Apache-2.0': True, 'BSD-3-Clause': True, 'BSD-2-Clause': True,
|
||||
'ISC': True, 'MPL-2.0': True, 'LGPL-2.1': True, 'LGPL-3.0': True,
|
||||
'GPL-2.0': False, 'GPL-3.0': False, 'AGPL-3.0': False, 'PROPRIETARY': False
|
||||
},
|
||||
'Apache-2.0': {
|
||||
'MIT': True, 'Apache-2.0': True, 'BSD-3-Clause': True, 'BSD-2-Clause': True,
|
||||
'ISC': True, 'MPL-2.0': True, 'LGPL-2.1': False, 'LGPL-3.0': True,
|
||||
'GPL-2.0': False, 'GPL-3.0': True, 'AGPL-3.0': True, 'PROPRIETARY': False
|
||||
},
|
||||
'GPL-2.0': {
|
||||
'MIT': True, 'Apache-2.0': False, 'BSD-3-Clause': True, 'BSD-2-Clause': True,
|
||||
'ISC': True, 'MPL-2.0': False, 'LGPL-2.1': True, 'LGPL-3.0': False,
|
||||
'GPL-2.0': True, 'GPL-3.0': False, 'AGPL-3.0': False, 'PROPRIETARY': False
|
||||
},
|
||||
'GPL-3.0': {
|
||||
'MIT': True, 'Apache-2.0': True, 'BSD-3-Clause': True, 'BSD-2-Clause': True,
|
||||
'ISC': True, 'MPL-2.0': True, 'LGPL-2.1': False, 'LGPL-3.0': True,
|
||||
'GPL-2.0': False, 'GPL-3.0': True, 'AGPL-3.0': True, 'PROPRIETARY': False
|
||||
},
|
||||
'AGPL-3.0': {
|
||||
'MIT': True, 'Apache-2.0': True, 'BSD-3-Clause': True, 'BSD-2-Clause': True,
|
||||
'ISC': True, 'MPL-2.0': True, 'LGPL-2.1': False, 'LGPL-3.0': True,
|
||||
'GPL-2.0': False, 'GPL-3.0': True, 'AGPL-3.0': True, 'PROPRIETARY': False
|
||||
}
|
||||
}
|
||||
|
||||
def _build_license_patterns(self) -> Dict[str, List[str]]:
|
||||
"""Build license detection patterns for text analysis."""
|
||||
return {
|
||||
'MIT': [
|
||||
r'MIT License',
|
||||
r'Permission is hereby granted, free of charge',
|
||||
r'THE SOFTWARE IS PROVIDED "AS IS"'
|
||||
],
|
||||
'Apache-2.0': [
|
||||
r'Apache License, Version 2\.0',
|
||||
r'Licensed under the Apache License',
|
||||
r'http://www\.apache\.org/licenses/LICENSE-2\.0'
|
||||
],
|
||||
'GPL-2.0': [
|
||||
r'GNU GENERAL PUBLIC LICENSE\s+Version 2',
|
||||
r'This program is free software.*GPL.*version 2',
|
||||
r'http://www\.gnu\.org/licenses/gpl-2\.0'
|
||||
],
|
||||
'GPL-3.0': [
|
||||
r'GNU GENERAL PUBLIC LICENSE\s+Version 3',
|
||||
r'This program is free software.*GPL.*version 3',
|
||||
r'http://www\.gnu\.org/licenses/gpl-3\.0'
|
||||
],
|
||||
'BSD-3-Clause': [
|
||||
r'BSD 3-Clause License',
|
||||
r'Redistributions of source code must retain',
|
||||
r'Neither the name.*may be used to endorse'
|
||||
],
|
||||
'BSD-2-Clause': [
|
||||
r'BSD 2-Clause License',
|
||||
r'Redistributions of source code must retain.*Redistributions in binary form'
|
||||
]
|
||||
}
|
||||
|
||||
def analyze_project(self, project_path: str, dependency_inventory: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""Analyze license compliance for a project."""
|
||||
project_path = Path(project_path)
|
||||
|
||||
analysis_results = {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'project_path': str(project_path),
|
||||
'project_license': self._detect_project_license(project_path),
|
||||
'dependencies': [],
|
||||
'license_summary': {},
|
||||
'conflicts': [],
|
||||
'compliance_score': 0.0,
|
||||
'risk_assessment': {},
|
||||
'recommendations': []
|
||||
}
|
||||
|
||||
# Load dependencies from inventory or scan project
|
||||
if dependency_inventory:
|
||||
dependencies = self._load_dependency_inventory(dependency_inventory)
|
||||
else:
|
||||
dependencies = self._scan_project_dependencies(project_path)
|
||||
|
||||
# Analyze each dependency's license
|
||||
for dep in dependencies:
|
||||
license_info = self._analyze_dependency_license(dep, project_path)
|
||||
analysis_results['dependencies'].append(license_info)
|
||||
|
||||
# Generate license summary
|
||||
analysis_results['license_summary'] = self._generate_license_summary(
|
||||
analysis_results['dependencies']
|
||||
)
|
||||
|
||||
# Detect conflicts
|
||||
analysis_results['conflicts'] = self._detect_license_conflicts(
|
||||
analysis_results['project_license'],
|
||||
analysis_results['dependencies']
|
||||
)
|
||||
|
||||
# Calculate compliance score
|
||||
analysis_results['compliance_score'] = self._calculate_compliance_score(
|
||||
analysis_results['dependencies'],
|
||||
analysis_results['conflicts']
|
||||
)
|
||||
|
||||
# Generate risk assessment
|
||||
analysis_results['risk_assessment'] = self._generate_risk_assessment(
|
||||
analysis_results['dependencies'],
|
||||
analysis_results['conflicts']
|
||||
)
|
||||
|
||||
# Generate recommendations
|
||||
analysis_results['recommendations'] = self._generate_compliance_recommendations(
|
||||
analysis_results
|
||||
)
|
||||
|
||||
return analysis_results
|
||||
|
||||
def _detect_project_license(self, project_path: Path) -> Optional[str]:
|
||||
"""Detect the main project license."""
|
||||
license_files = ['LICENSE', 'LICENSE.txt', 'LICENSE.md', 'COPYING', 'COPYING.txt']
|
||||
|
||||
for license_file in license_files:
|
||||
license_path = project_path / license_file
|
||||
if license_path.exists():
|
||||
try:
|
||||
with open(license_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Analyze license content
|
||||
detected_license = self._detect_license_from_text(content)
|
||||
if detected_license:
|
||||
return detected_license
|
||||
except Exception as e:
|
||||
print(f"Error reading license file {license_path}: {e}")
|
||||
|
||||
return None
|
||||
|
||||
def _detect_license_from_text(self, text: str) -> Optional[str]:
|
||||
"""Detect license type from text content."""
|
||||
text_upper = text.upper()
|
||||
|
||||
for license_id, patterns in self.license_patterns.items():
|
||||
for pattern in patterns:
|
||||
if re.search(pattern, text, re.IGNORECASE):
|
||||
return license_id
|
||||
|
||||
# Common license text patterns
|
||||
if 'MIT' in text_upper and 'PERMISSION IS HEREBY GRANTED' in text_upper:
|
||||
return 'MIT'
|
||||
elif 'APACHE LICENSE' in text_upper and 'VERSION 2.0' in text_upper:
|
||||
return 'Apache-2.0'
|
||||
elif 'GPL' in text_upper and 'VERSION 2' in text_upper:
|
||||
return 'GPL-2.0'
|
||||
elif 'GPL' in text_upper and 'VERSION 3' in text_upper:
|
||||
return 'GPL-3.0'
|
||||
|
||||
return None
|
||||
|
||||
def _load_dependency_inventory(self, inventory_path: str) -> List[Dict[str, Any]]:
|
||||
"""Load dependencies from JSON inventory file."""
|
||||
try:
|
||||
with open(inventory_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if 'dependencies' in data:
|
||||
return data['dependencies']
|
||||
else:
|
||||
return data if isinstance(data, list) else []
|
||||
except Exception as e:
|
||||
print(f"Error loading dependency inventory: {e}")
|
||||
return []
|
||||
|
||||
def _scan_project_dependencies(self, project_path: Path) -> List[Dict[str, Any]]:
|
||||
"""Basic dependency scanning - in practice, would integrate with dep_scanner.py."""
|
||||
dependencies = []
|
||||
|
||||
# Simple package.json parsing as example
|
||||
package_json = project_path / 'package.json'
|
||||
if package_json.exists():
|
||||
try:
|
||||
with open(package_json, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
for dep_type in ['dependencies', 'devDependencies']:
|
||||
if dep_type in data:
|
||||
for name, version in data[dep_type].items():
|
||||
dependencies.append({
|
||||
'name': name,
|
||||
'version': version,
|
||||
'ecosystem': 'npm',
|
||||
'direct': True
|
||||
})
|
||||
except Exception as e:
|
||||
print(f"Error parsing package.json: {e}")
|
||||
|
||||
return dependencies
|
||||
|
||||
def _analyze_dependency_license(self, dependency: Dict[str, Any], project_path: Path) -> DependencyLicense:
|
||||
"""Analyze license information for a single dependency."""
|
||||
dep_license = DependencyLicense(
|
||||
name=dependency['name'],
|
||||
version=dependency.get('version', ''),
|
||||
ecosystem=dependency.get('ecosystem', ''),
|
||||
direct=dependency.get('direct', False),
|
||||
license_declared=dependency.get('license'),
|
||||
license_detected=None,
|
||||
license_files=[],
|
||||
confidence=0.0
|
||||
)
|
||||
|
||||
# Try to detect license from various sources
|
||||
declared_license = dependency.get('license')
|
||||
if declared_license:
|
||||
license_info = self._resolve_license_info(declared_license)
|
||||
if license_info:
|
||||
dep_license.license_detected = license_info
|
||||
dep_license.confidence = 0.9
|
||||
|
||||
# For unknown licenses, try to find license files in node_modules (example)
|
||||
if not dep_license.license_detected and dep_license.ecosystem == 'npm':
|
||||
node_modules_path = project_path / 'node_modules' / dep_license.name
|
||||
if node_modules_path.exists():
|
||||
license_info = self._scan_package_directory(node_modules_path)
|
||||
if license_info:
|
||||
dep_license.license_detected = license_info
|
||||
dep_license.confidence = 0.7
|
||||
|
||||
# Default to unknown if no license detected
|
||||
if not dep_license.license_detected:
|
||||
dep_license.license_detected = self.license_database['UNKNOWN']
|
||||
dep_license.confidence = 0.0
|
||||
|
||||
return dep_license
|
||||
|
||||
def _resolve_license_info(self, license_string: str) -> Optional[LicenseInfo]:
|
||||
"""Resolve license string to LicenseInfo object."""
|
||||
if not license_string:
|
||||
return None
|
||||
|
||||
license_string = license_string.strip()
|
||||
|
||||
# Direct SPDX ID match
|
||||
if license_string in self.license_database:
|
||||
return self.license_database[license_string]
|
||||
|
||||
# Common variations and mappings
|
||||
license_mappings = {
|
||||
'mit': 'MIT',
|
||||
'apache': 'Apache-2.0',
|
||||
'apache-2.0': 'Apache-2.0',
|
||||
'apache 2.0': 'Apache-2.0',
|
||||
'bsd': 'BSD-3-Clause',
|
||||
'bsd-3-clause': 'BSD-3-Clause',
|
||||
'bsd-2-clause': 'BSD-2-Clause',
|
||||
'gpl-2.0': 'GPL-2.0',
|
||||
'gpl-3.0': 'GPL-3.0',
|
||||
'lgpl-2.1': 'LGPL-2.1',
|
||||
'lgpl-3.0': 'LGPL-3.0',
|
||||
'mpl-2.0': 'MPL-2.0',
|
||||
'isc': 'ISC',
|
||||
'unlicense': 'MIT', # Treat as permissive
|
||||
'public domain': 'MIT', # Treat as permissive
|
||||
'proprietary': 'PROPRIETARY',
|
||||
'commercial': 'PROPRIETARY'
|
||||
}
|
||||
|
||||
license_lower = license_string.lower()
|
||||
for pattern, mapped_license in license_mappings.items():
|
||||
if pattern in license_lower:
|
||||
return self.license_database.get(mapped_license)
|
||||
|
||||
return None
|
||||
|
||||
def _scan_package_directory(self, package_path: Path) -> Optional[LicenseInfo]:
|
||||
"""Scan package directory for license information."""
|
||||
license_files = ['LICENSE', 'LICENSE.txt', 'LICENSE.md', 'COPYING', 'README.md', 'package.json']
|
||||
|
||||
for license_file in license_files:
|
||||
file_path = package_path / license_file
|
||||
if file_path.exists():
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
|
||||
# Try to detect license from content
|
||||
if license_file == 'package.json':
|
||||
# Parse JSON for license field
|
||||
try:
|
||||
data = json.loads(content)
|
||||
license_field = data.get('license')
|
||||
if license_field:
|
||||
return self._resolve_license_info(license_field)
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
# Analyze text content
|
||||
detected_license = self._detect_license_from_text(content)
|
||||
if detected_license:
|
||||
return self.license_database.get(detected_license)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
return None
|
||||
|
||||
def _generate_license_summary(self, dependencies: List[DependencyLicense]) -> Dict[str, Any]:
|
||||
"""Generate summary of license distribution."""
|
||||
summary = {
|
||||
'total_dependencies': len(dependencies),
|
||||
'license_types': {},
|
||||
'risk_levels': {},
|
||||
'unknown_licenses': 0,
|
||||
'direct_dependencies': 0,
|
||||
'transitive_dependencies': 0
|
||||
}
|
||||
|
||||
for dep in dependencies:
|
||||
# Count by license type
|
||||
license_type = dep.license_detected.license_type.value
|
||||
summary['license_types'][license_type] = summary['license_types'].get(license_type, 0) + 1
|
||||
|
||||
# Count by risk level
|
||||
risk_level = dep.license_detected.risk_level.value
|
||||
summary['risk_levels'][risk_level] = summary['risk_levels'].get(risk_level, 0) + 1
|
||||
|
||||
# Count unknowns
|
||||
if dep.license_detected.license_type == LicenseType.UNKNOWN:
|
||||
summary['unknown_licenses'] += 1
|
||||
|
||||
# Count direct vs transitive
|
||||
if dep.direct:
|
||||
summary['direct_dependencies'] += 1
|
||||
else:
|
||||
summary['transitive_dependencies'] += 1
|
||||
|
||||
return summary
|
||||
|
||||
def _detect_license_conflicts(self, project_license: Optional[str],
|
||||
dependencies: List[DependencyLicense]) -> List[LicenseConflict]:
|
||||
"""Detect license compatibility conflicts."""
|
||||
conflicts = []
|
||||
|
||||
if not project_license:
|
||||
# If no project license detected, flag as potential issue
|
||||
for dep in dependencies:
|
||||
if dep.license_detected.risk_level in [RiskLevel.HIGH, RiskLevel.CRITICAL]:
|
||||
conflicts.append(LicenseConflict(
|
||||
dependency1='Project',
|
||||
license1='Unknown',
|
||||
dependency2=dep.name,
|
||||
license2=dep.license_detected.spdx_id or dep.license_detected.name,
|
||||
conflict_type='Unknown project license',
|
||||
severity=RiskLevel.HIGH,
|
||||
description=f'Project license unknown, dependency {dep.name} has {dep.license_detected.risk_level.value} risk license',
|
||||
resolution_options=['Define project license', 'Review dependency usage']
|
||||
))
|
||||
return conflicts
|
||||
|
||||
project_license_info = self.license_database.get(project_license)
|
||||
if not project_license_info:
|
||||
return conflicts
|
||||
|
||||
# Check compatibility with project license
|
||||
for dep in dependencies:
|
||||
dep_license_id = dep.license_detected.spdx_id or 'UNKNOWN'
|
||||
|
||||
# Check compatibility matrix
|
||||
if project_license in self.compatibility_matrix:
|
||||
compatibility = self.compatibility_matrix[project_license].get(dep_license_id, False)
|
||||
|
||||
if not compatibility:
|
||||
severity = self._determine_conflict_severity(project_license_info, dep.license_detected)
|
||||
|
||||
conflicts.append(LicenseConflict(
|
||||
dependency1='Project',
|
||||
license1=project_license,
|
||||
dependency2=dep.name,
|
||||
license2=dep_license_id,
|
||||
conflict_type='License incompatibility',
|
||||
severity=severity,
|
||||
description=f'Project license {project_license} is incompatible with dependency license {dep_license_id}',
|
||||
resolution_options=self._generate_conflict_resolutions(project_license, dep_license_id)
|
||||
))
|
||||
|
||||
# Check for GPL contamination in permissive projects
|
||||
if project_license_info.license_type == LicenseType.PERMISSIVE:
|
||||
for dep in dependencies:
|
||||
if dep.license_detected.license_type == LicenseType.COPYLEFT_STRONG:
|
||||
conflicts.append(LicenseConflict(
|
||||
dependency1='Project',
|
||||
license1=project_license,
|
||||
dependency2=dep.name,
|
||||
license2=dep.license_detected.spdx_id or dep.license_detected.name,
|
||||
conflict_type='GPL contamination',
|
||||
severity=RiskLevel.CRITICAL,
|
||||
description=f'GPL dependency {dep.name} may contaminate permissive project',
|
||||
resolution_options=['Remove GPL dependency', 'Change project license to GPL',
|
||||
'Use dynamic linking', 'Find alternative dependency']
|
||||
))
|
||||
|
||||
return conflicts
|
||||
|
||||
def _determine_conflict_severity(self, project_license: LicenseInfo, dep_license: LicenseInfo) -> RiskLevel:
|
||||
"""Determine severity of a license conflict."""
|
||||
if dep_license.license_type == LicenseType.UNKNOWN:
|
||||
return RiskLevel.CRITICAL
|
||||
elif (project_license.license_type == LicenseType.PERMISSIVE and
|
||||
dep_license.license_type == LicenseType.COPYLEFT_STRONG):
|
||||
return RiskLevel.CRITICAL
|
||||
elif dep_license.license_type == LicenseType.PROPRIETARY:
|
||||
return RiskLevel.HIGH
|
||||
else:
|
||||
return RiskLevel.MEDIUM
|
||||
|
||||
def _generate_conflict_resolutions(self, project_license: str, dep_license: str) -> List[str]:
|
||||
"""Generate resolution options for license conflicts."""
|
||||
resolutions = []
|
||||
|
||||
if 'GPL' in dep_license:
|
||||
resolutions.extend([
|
||||
'Find alternative non-GPL dependency',
|
||||
'Use dynamic linking if possible',
|
||||
'Consider changing project license to GPL-compatible',
|
||||
'Remove the dependency if not essential'
|
||||
])
|
||||
elif dep_license == 'PROPRIETARY':
|
||||
resolutions.extend([
|
||||
'Obtain commercial license',
|
||||
'Find open-source alternative',
|
||||
'Remove dependency if not essential',
|
||||
'Negotiate license terms'
|
||||
])
|
||||
else:
|
||||
resolutions.extend([
|
||||
'Review license compatibility carefully',
|
||||
'Consult legal counsel',
|
||||
'Find alternative dependency',
|
||||
'Consider license exception'
|
||||
])
|
||||
|
||||
return resolutions
|
||||
|
||||
def _calculate_compliance_score(self, dependencies: List[DependencyLicense],
|
||||
conflicts: List[LicenseConflict]) -> float:
|
||||
"""Calculate overall compliance score (0-100)."""
|
||||
if not dependencies:
|
||||
return 100.0
|
||||
|
||||
base_score = 100.0
|
||||
|
||||
# Deduct points for unknown licenses
|
||||
unknown_count = sum(1 for dep in dependencies
|
||||
if dep.license_detected.license_type == LicenseType.UNKNOWN)
|
||||
base_score -= (unknown_count / len(dependencies)) * 30
|
||||
|
||||
# Deduct points for high-risk licenses
|
||||
high_risk_count = sum(1 for dep in dependencies
|
||||
if dep.license_detected.risk_level in [RiskLevel.HIGH, RiskLevel.CRITICAL])
|
||||
base_score -= (high_risk_count / len(dependencies)) * 20
|
||||
|
||||
# Deduct points for conflicts
|
||||
if conflicts:
|
||||
critical_conflicts = sum(1 for c in conflicts if c.severity == RiskLevel.CRITICAL)
|
||||
high_conflicts = sum(1 for c in conflicts if c.severity == RiskLevel.HIGH)
|
||||
|
||||
base_score -= critical_conflicts * 15
|
||||
base_score -= high_conflicts * 10
|
||||
|
||||
return max(0.0, base_score)
|
||||
|
||||
def _generate_risk_assessment(self, dependencies: List[DependencyLicense],
|
||||
conflicts: List[LicenseConflict]) -> Dict[str, Any]:
|
||||
"""Generate comprehensive risk assessment."""
|
||||
return {
|
||||
'overall_risk': self._calculate_overall_risk(dependencies, conflicts),
|
||||
'license_risk_breakdown': self._calculate_license_risks(dependencies),
|
||||
'conflict_summary': {
|
||||
'total_conflicts': len(conflicts),
|
||||
'critical_conflicts': len([c for c in conflicts if c.severity == RiskLevel.CRITICAL]),
|
||||
'high_conflicts': len([c for c in conflicts if c.severity == RiskLevel.HIGH])
|
||||
},
|
||||
'distribution_risks': self._assess_distribution_risks(dependencies),
|
||||
'commercial_risks': self._assess_commercial_risks(dependencies)
|
||||
}
|
||||
|
||||
def _calculate_overall_risk(self, dependencies: List[DependencyLicense],
|
||||
conflicts: List[LicenseConflict]) -> str:
|
||||
"""Calculate overall project risk level."""
|
||||
if any(c.severity == RiskLevel.CRITICAL for c in conflicts):
|
||||
return 'CRITICAL'
|
||||
elif any(dep.license_detected.risk_level == RiskLevel.CRITICAL for dep in dependencies):
|
||||
return 'CRITICAL'
|
||||
elif any(c.severity == RiskLevel.HIGH for c in conflicts):
|
||||
return 'HIGH'
|
||||
elif any(dep.license_detected.risk_level == RiskLevel.HIGH for dep in dependencies):
|
||||
return 'HIGH'
|
||||
elif any(dep.license_detected.risk_level == RiskLevel.MEDIUM for dep in dependencies):
|
||||
return 'MEDIUM'
|
||||
else:
|
||||
return 'LOW'
|
||||
|
||||
def _calculate_license_risks(self, dependencies: List[DependencyLicense]) -> Dict[str, int]:
|
||||
"""Calculate breakdown of license risks."""
|
||||
risks = {'low': 0, 'medium': 0, 'high': 0, 'critical': 0}
|
||||
|
||||
for dep in dependencies:
|
||||
risk_level = dep.license_detected.risk_level.value
|
||||
risks[risk_level] += 1
|
||||
|
||||
return risks
|
||||
|
||||
def _assess_distribution_risks(self, dependencies: List[DependencyLicense]) -> List[str]:
|
||||
"""Assess risks related to software distribution."""
|
||||
risks = []
|
||||
|
||||
gpl_deps = [dep for dep in dependencies
|
||||
if dep.license_detected.license_type == LicenseType.COPYLEFT_STRONG]
|
||||
if gpl_deps:
|
||||
risks.append(f"GPL dependencies require source code disclosure: {[d.name for d in gpl_deps]}")
|
||||
|
||||
proprietary_deps = [dep for dep in dependencies
|
||||
if dep.license_detected.license_type == LicenseType.PROPRIETARY]
|
||||
if proprietary_deps:
|
||||
risks.append(f"Proprietary dependencies may require commercial licenses: {[d.name for d in proprietary_deps]}")
|
||||
|
||||
unknown_deps = [dep for dep in dependencies
|
||||
if dep.license_detected.license_type == LicenseType.UNKNOWN]
|
||||
if unknown_deps:
|
||||
risks.append(f"Unknown licenses pose legal uncertainty: {[d.name for d in unknown_deps]}")
|
||||
|
||||
return risks
|
||||
|
||||
def _assess_commercial_risks(self, dependencies: List[DependencyLicense]) -> List[str]:
|
||||
"""Assess risks for commercial usage."""
|
||||
risks = []
|
||||
|
||||
agpl_deps = [dep for dep in dependencies
|
||||
if dep.license_detected.spdx_id == 'AGPL-3.0']
|
||||
if agpl_deps:
|
||||
risks.append(f"AGPL dependencies trigger copyleft for network services: {[d.name for d in agpl_deps]}")
|
||||
|
||||
return risks
|
||||
|
||||
def _generate_compliance_recommendations(self, analysis_results: Dict[str, Any]) -> List[str]:
|
||||
"""Generate actionable compliance recommendations."""
|
||||
recommendations = []
|
||||
|
||||
# Address critical issues first
|
||||
critical_conflicts = [c for c in analysis_results['conflicts']
|
||||
if c.severity == RiskLevel.CRITICAL]
|
||||
if critical_conflicts:
|
||||
recommendations.append("CRITICAL: Address license conflicts immediately before any distribution")
|
||||
for conflict in critical_conflicts[:3]: # Top 3
|
||||
recommendations.append(f" • {conflict.description}")
|
||||
|
||||
# Unknown licenses
|
||||
unknown_count = analysis_results['license_summary']['unknown_licenses']
|
||||
if unknown_count > 0:
|
||||
recommendations.append(f"Investigate and clarify licenses for {unknown_count} dependencies with unknown licensing")
|
||||
|
||||
# GPL contamination
|
||||
gpl_deps = [dep for dep in analysis_results['dependencies']
|
||||
if dep.license_detected.license_type == LicenseType.COPYLEFT_STRONG]
|
||||
if gpl_deps and analysis_results.get('project_license') in ['MIT', 'Apache-2.0', 'BSD-3-Clause']:
|
||||
recommendations.append("Consider removing GPL dependencies or changing project license for permissive project")
|
||||
|
||||
# Compliance score
|
||||
if analysis_results['compliance_score'] < 70:
|
||||
recommendations.append("Overall compliance score is low - prioritize license cleanup")
|
||||
|
||||
return recommendations
|
||||
|
||||
def generate_report(self, analysis_results: Dict[str, Any], format: str = 'text') -> str:
|
||||
"""Generate compliance report in specified format."""
|
||||
if format == 'json':
|
||||
# Convert dataclass objects for JSON serialization
|
||||
serializable_results = analysis_results.copy()
|
||||
serializable_results['dependencies'] = [
|
||||
{
|
||||
'name': dep.name,
|
||||
'version': dep.version,
|
||||
'ecosystem': dep.ecosystem,
|
||||
'direct': dep.direct,
|
||||
'license_declared': dep.license_declared,
|
||||
'license_detected': asdict(dep.license_detected) if dep.license_detected else None,
|
||||
'confidence': dep.confidence
|
||||
}
|
||||
for dep in analysis_results['dependencies']
|
||||
]
|
||||
serializable_results['conflicts'] = [asdict(conflict) for conflict in analysis_results['conflicts']]
|
||||
return json.dumps(serializable_results, indent=2, default=str)
|
||||
|
||||
# Text format report
|
||||
report = []
|
||||
report.append("=" * 60)
|
||||
report.append("LICENSE COMPLIANCE REPORT")
|
||||
report.append("=" * 60)
|
||||
report.append(f"Analysis Date: {analysis_results['timestamp']}")
|
||||
report.append(f"Project: {analysis_results['project_path']}")
|
||||
report.append(f"Project License: {analysis_results['project_license'] or 'Unknown'}")
|
||||
report.append("")
|
||||
|
||||
# Summary
|
||||
summary = analysis_results['license_summary']
|
||||
report.append("SUMMARY:")
|
||||
report.append(f" Total Dependencies: {summary['total_dependencies']}")
|
||||
report.append(f" Compliance Score: {analysis_results['compliance_score']:.1f}/100")
|
||||
report.append(f" Overall Risk: {analysis_results['risk_assessment']['overall_risk']}")
|
||||
report.append(f" License Conflicts: {len(analysis_results['conflicts'])}")
|
||||
report.append("")
|
||||
|
||||
# License distribution
|
||||
report.append("LICENSE DISTRIBUTION:")
|
||||
for license_type, count in summary['license_types'].items():
|
||||
report.append(f" {license_type.title()}: {count}")
|
||||
report.append("")
|
||||
|
||||
# Risk breakdown
|
||||
report.append("RISK BREAKDOWN:")
|
||||
for risk_level, count in summary['risk_levels'].items():
|
||||
report.append(f" {risk_level.title()}: {count}")
|
||||
report.append("")
|
||||
|
||||
# Conflicts
|
||||
if analysis_results['conflicts']:
|
||||
report.append("LICENSE CONFLICTS:")
|
||||
report.append("-" * 30)
|
||||
for conflict in analysis_results['conflicts']:
|
||||
report.append(f"Conflict: {conflict.dependency2} ({conflict.license2})")
|
||||
report.append(f" Issue: {conflict.description}")
|
||||
report.append(f" Severity: {conflict.severity.value.upper()}")
|
||||
report.append(f" Resolutions: {', '.join(conflict.resolution_options[:2])}")
|
||||
report.append("")
|
||||
|
||||
# High-risk dependencies
|
||||
high_risk_deps = [dep for dep in analysis_results['dependencies']
|
||||
if dep.license_detected.risk_level in [RiskLevel.HIGH, RiskLevel.CRITICAL]]
|
||||
if high_risk_deps:
|
||||
report.append("HIGH-RISK DEPENDENCIES:")
|
||||
report.append("-" * 30)
|
||||
for dep in high_risk_deps[:10]: # Top 10
|
||||
license_name = dep.license_detected.spdx_id or dep.license_detected.name
|
||||
report.append(f" {dep.name} v{dep.version}: {license_name} ({dep.license_detected.risk_level.value.upper()})")
|
||||
report.append("")
|
||||
|
||||
# Recommendations
|
||||
if analysis_results['recommendations']:
|
||||
report.append("RECOMMENDATIONS:")
|
||||
report.append("-" * 20)
|
||||
for i, rec in enumerate(analysis_results['recommendations'], 1):
|
||||
report.append(f"{i}. {rec}")
|
||||
report.append("")
|
||||
|
||||
report.append("=" * 60)
|
||||
return '\n'.join(report)
|
||||
|
||||
def main():
|
||||
"""Main entry point for the license checker."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Analyze dependency licenses for compliance and conflicts',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python license_checker.py /path/to/project
|
||||
python license_checker.py . --format json --output compliance.json
|
||||
python license_checker.py /app --inventory deps.json --policy strict
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument('project_path',
|
||||
help='Path to the project directory to analyze')
|
||||
parser.add_argument('--inventory',
|
||||
help='Path to dependency inventory JSON file')
|
||||
parser.add_argument('--format', choices=['text', 'json'], default='text',
|
||||
help='Output format (default: text)')
|
||||
parser.add_argument('--output', '-o',
|
||||
help='Output file path (default: stdout)')
|
||||
parser.add_argument('--policy', choices=['permissive', 'strict'], default='permissive',
|
||||
help='License policy strictness (default: permissive)')
|
||||
parser.add_argument('--warn-conflicts', action='store_true',
|
||||
help='Show warnings for potential conflicts')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
checker = LicenseChecker()
|
||||
results = checker.analyze_project(args.project_path, args.inventory)
|
||||
report = checker.generate_report(results, args.format)
|
||||
|
||||
if args.output:
|
||||
with open(args.output, 'w') as f:
|
||||
f.write(report)
|
||||
print(f"Compliance report saved to {args.output}")
|
||||
else:
|
||||
print(report)
|
||||
|
||||
# Exit with error code for policy violations
|
||||
if args.policy == 'strict' and results['compliance_score'] < 80:
|
||||
sys.exit(1)
|
||||
|
||||
if args.warn_conflicts and results['conflicts']:
|
||||
print("\nWARNING: License conflicts detected!")
|
||||
sys.exit(2)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,421 @@
|
||||
{
|
||||
"timestamp": "2026-02-16T15:42:09.730696",
|
||||
"project_path": "test-project",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "express",
|
||||
"version": "4.18.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2022-24999",
|
||||
"summary": "Open redirect in express",
|
||||
"severity": "MEDIUM",
|
||||
"cvss_score": 6.1,
|
||||
"affected_versions": "<4.18.2",
|
||||
"fixed_version": "4.18.2",
|
||||
"published_date": "2022-11-26",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2022-24999"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2022-24999",
|
||||
"summary": "Open redirect in express",
|
||||
"severity": "MEDIUM",
|
||||
"cvss_score": 6.1,
|
||||
"affected_versions": "<4.18.2",
|
||||
"fixed_version": "4.18.2",
|
||||
"published_date": "2022-11-26",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2022-24999"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lodash",
|
||||
"version": "4.17.20",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2021-23337",
|
||||
"summary": "Prototype pollution in lodash",
|
||||
"severity": "HIGH",
|
||||
"cvss_score": 7.2,
|
||||
"affected_versions": "<4.17.21",
|
||||
"fixed_version": "4.17.21",
|
||||
"published_date": "2021-02-15",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2021-23337"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2021-23337",
|
||||
"summary": "Prototype pollution in lodash",
|
||||
"severity": "HIGH",
|
||||
"cvss_score": 7.2,
|
||||
"affected_versions": "<4.17.21",
|
||||
"fixed_version": "4.17.21",
|
||||
"published_date": "2021-02-15",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2021-23337"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "axios",
|
||||
"version": "1.5.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"id": "CVE-2023-45857",
|
||||
"summary": "Cross-site request forgery in axios",
|
||||
"severity": "MEDIUM",
|
||||
"cvss_score": 6.1,
|
||||
"affected_versions": ">=1.0.0 <1.6.0",
|
||||
"fixed_version": "1.6.0",
|
||||
"published_date": "2023-10-11",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2023-45857"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "CVE-2023-45857",
|
||||
"summary": "Cross-site request forgery in axios",
|
||||
"severity": "MEDIUM",
|
||||
"cvss_score": 6.1,
|
||||
"affected_versions": ">=1.0.0 <1.6.0",
|
||||
"fixed_version": "1.6.0",
|
||||
"published_date": "2023-10-11",
|
||||
"references": [
|
||||
"https://nvd.nist.gov/vuln/detail/CVE-2023-45857"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jsonwebtoken",
|
||||
"version": "8.5.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "bcrypt",
|
||||
"version": "5.1.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "mongoose",
|
||||
"version": "6.10.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "cors",
|
||||
"version": "2.8.5",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "helmet",
|
||||
"version": "6.1.5",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "winston",
|
||||
"version": "3.8.2",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "dotenv",
|
||||
"version": "16.0.3",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "express-rate-limit",
|
||||
"version": "6.7.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "multer",
|
||||
"version": "1.4.5-lts.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "sharp",
|
||||
"version": "0.32.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "nodemailer",
|
||||
"version": "6.9.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "4.6.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "redis",
|
||||
"version": "4.6.5",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "moment",
|
||||
"version": "2.29.4",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "chalk",
|
||||
"version": "4.1.2",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "commander",
|
||||
"version": "9.4.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "nodemon",
|
||||
"version": "2.0.22",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "jest",
|
||||
"version": "29.5.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "supertest",
|
||||
"version": "6.3.3",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "eslint",
|
||||
"version": "8.40.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "eslint-config-airbnb-base",
|
||||
"version": "15.0.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "eslint-plugin-import",
|
||||
"version": "2.27.5",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "webpack",
|
||||
"version": "5.82.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "webpack-cli",
|
||||
"version": "5.1.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "babel-loader",
|
||||
"version": "9.1.2",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "@babel/core",
|
||||
"version": "7.22.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "@babel/preset-env",
|
||||
"version": "7.22.2",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "css-loader",
|
||||
"version": "6.7.4",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "style-loader",
|
||||
"version": "3.3.3",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "html-webpack-plugin",
|
||||
"version": "5.5.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "mini-css-extract-plugin",
|
||||
"version": "2.7.6",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "postcss",
|
||||
"version": "8.4.23",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "postcss-loader",
|
||||
"version": "7.3.0",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "autoprefixer",
|
||||
"version": "10.4.14",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "cross-env",
|
||||
"version": "7.0.3",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
},
|
||||
{
|
||||
"name": "rimraf",
|
||||
"version": "5.0.1",
|
||||
"ecosystem": "npm",
|
||||
"direct": true,
|
||||
"license": null,
|
||||
"vulnerabilities": []
|
||||
}
|
||||
],
|
||||
"vulnerabilities_found": 6,
|
||||
"high_severity_count": 2,
|
||||
"medium_severity_count": 4,
|
||||
"low_severity_count": 0,
|
||||
"ecosystems": [
|
||||
"npm"
|
||||
],
|
||||
"scan_summary": {
|
||||
"total_dependencies": 39,
|
||||
"unique_dependencies": 39,
|
||||
"ecosystems_found": 1,
|
||||
"vulnerable_dependencies": 3,
|
||||
"vulnerability_breakdown": {
|
||||
"high": 2,
|
||||
"medium": 4,
|
||||
"low": 0
|
||||
}
|
||||
},
|
||||
"recommendations": [
|
||||
"URGENT: Address 2 high-severity vulnerabilities immediately",
|
||||
"Schedule fixes for 4 medium-severity vulnerabilities within 30 days",
|
||||
"Update express from 4.18.1 to 4.18.2 to fix CVE-2022-24999",
|
||||
"Update express from 4.18.1 to 4.18.2 to fix CVE-2022-24999",
|
||||
"Update lodash from 4.17.20 to 4.17.21 to fix CVE-2021-23337",
|
||||
"Update lodash from 4.17.20 to 4.17.21 to fix CVE-2021-23337",
|
||||
"Update axios from 1.5.0 to 1.6.0 to fix CVE-2023-45857",
|
||||
"Update axios from 1.5.0 to 1.6.0 to fix CVE-2023-45857"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "sample-web-app",
|
||||
"version": "1.2.3",
|
||||
"description": "A sample web application with various dependencies for testing dependency auditing",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"dev": "nodemon index.js",
|
||||
"build": "webpack --mode production",
|
||||
"test": "jest",
|
||||
"lint": "eslint src/",
|
||||
"audit": "npm audit"
|
||||
},
|
||||
"keywords": ["web", "app", "sample", "dependency", "audit"],
|
||||
"author": "Claude Skills Team",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "4.18.1",
|
||||
"lodash": "4.17.20",
|
||||
"axios": "1.5.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"bcrypt": "5.1.0",
|
||||
"mongoose": "6.10.0",
|
||||
"cors": "2.8.5",
|
||||
"helmet": "6.1.5",
|
||||
"winston": "3.8.2",
|
||||
"dotenv": "16.0.3",
|
||||
"express-rate-limit": "6.7.0",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"sharp": "0.32.1",
|
||||
"nodemailer": "6.9.1",
|
||||
"socket.io": "4.6.1",
|
||||
"redis": "4.6.5",
|
||||
"moment": "2.29.4",
|
||||
"chalk": "4.1.2",
|
||||
"commander": "9.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "2.0.22",
|
||||
"jest": "29.5.0",
|
||||
"supertest": "6.3.3",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"webpack": "5.82.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"babel-loader": "9.1.2",
|
||||
"@babel/core": "7.22.1",
|
||||
"@babel/preset-env": "7.22.2",
|
||||
"css-loader": "6.7.4",
|
||||
"style-loader": "3.3.3",
|
||||
"html-webpack-plugin": "5.5.1",
|
||||
"mini-css-extract-plugin": "2.7.6",
|
||||
"postcss": "8.4.23",
|
||||
"postcss-loader": "7.3.0",
|
||||
"autoprefixer": "10.4.14",
|
||||
"cross-env": "7.0.3",
|
||||
"rimraf": "5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/example/sample-web-app.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/example/sample-web-app/issues"
|
||||
},
|
||||
"homepage": "https://github.com/example/sample-web-app#readme"
|
||||
}
|
||||
Reference in New Issue
Block a user