1
0
Fork 0
mirror of https://github.com/imjasonh/govulncheck-action synced 2026-07-11 01:53:12 +00:00
govulncheck-action/lib/annotator.js
Jason Hall 39e329ab61
Initial implementation of govulncheck GitHub Action
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>
2025-06-06 23:41:03 -04:00

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;