mirror of
https://github.com/imjasonh/govulncheck-action
synced 2026-07-11 01:53:12 +00:00
This action runs govulncheck on Go projects and creates GitHub annotations for vulnerabilities found in dependencies and code paths. Features: - Automated vulnerability scanning with govulncheck - Smart annotations on go.mod for vulnerable dependencies - Annotations on source code lines that call vulnerable functions - Configurable working directory - Output variables for vulnerability detection The implementation includes: - Modular architecture with separate concerns (execution, parsing, annotation) - Comprehensive test suite with 100% function coverage - Example vulnerable Go module for demonstration - GitHub workflow example - Full documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
87 lines
No EOL
2.4 KiB
JavaScript
87 lines
No EOL
2.4 KiB
JavaScript
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
|
|
class AnnotationCreator {
|
|
constructor(core, fsModule = fs) {
|
|
this.core = core;
|
|
this.fs = fsModule;
|
|
}
|
|
|
|
async createAnnotations(vulnerabilities, parser, workingDirectory = '.') {
|
|
const modules = parser.extractUniqueModules(vulnerabilities);
|
|
const callSites = parser.extractCallSites(vulnerabilities);
|
|
|
|
// Annotate go.mod for vulnerable modules
|
|
await this.annotateGoMod(modules, vulnerabilities, workingDirectory);
|
|
|
|
// Annotate source files for call sites
|
|
this.annotateCallSites(callSites);
|
|
}
|
|
|
|
async annotateGoMod(modules, vulnerabilities, workingDirectory) {
|
|
if (modules.length === 0) return;
|
|
|
|
const goModPath = path.join(workingDirectory, 'go.mod');
|
|
let goModContent = '';
|
|
|
|
try {
|
|
goModContent = await this.fs.readFile(goModPath, 'utf8');
|
|
} catch (error) {
|
|
this.core.warning(`Could not read go.mod: ${error.message}`);
|
|
return;
|
|
}
|
|
|
|
const goModLines = goModContent.split('\n');
|
|
|
|
for (const module of modules) {
|
|
// Find the vulnerability info for this module
|
|
const vuln = vulnerabilities.find(v =>
|
|
v.finding.trace &&
|
|
v.finding.trace[0] &&
|
|
v.finding.trace[0].module === module
|
|
);
|
|
|
|
// Find line in go.mod
|
|
for (let i = 0; i < goModLines.length; i++) {
|
|
if (goModLines[i].includes(module)) {
|
|
const annotation = {
|
|
path: 'go.mod',
|
|
start_line: i + 1,
|
|
end_line: i + 1,
|
|
annotation_level: 'warning',
|
|
message: `Vulnerable module: ${module}`,
|
|
title: 'Security Vulnerability'
|
|
};
|
|
|
|
if (vuln && vuln.finding.osv) {
|
|
annotation.message += ` (${vuln.finding.osv})`;
|
|
}
|
|
|
|
this.core.warning(annotation.message, annotation);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
annotateCallSites(callSites) {
|
|
for (const site of callSites) {
|
|
const annotation = {
|
|
path: site.filename,
|
|
start_line: site.line,
|
|
end_line: site.line,
|
|
annotation_level: 'warning',
|
|
message: `Vulnerable code path: ${site.function}`,
|
|
title: 'Security Vulnerability'
|
|
};
|
|
|
|
if (site.osv) {
|
|
annotation.message += ` (${site.osv})`;
|
|
}
|
|
|
|
this.core.warning(annotation.message, annotation);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = AnnotationCreator; |