1
0
Fork 0
mirror of https://github.com/imjasonh/another-checkov-action synced 2026-07-07 00:22:57 +00:00

Merge pull request #3 from imjasonh/flags

take flags
This commit is contained in:
Jason Hall 2025-11-10 10:50:08 -05:00 committed by GitHub
commit 392af04cb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 142 additions and 116 deletions

View file

@ -12,7 +12,7 @@ on:
permissions: {}
jobs:
checkov-strict:
use-action:
runs-on: ubuntu-latest
name: Checkov Security Scan
@ -25,3 +25,5 @@ jobs:
fetch-depth: 0 # Need full history for git diff
- uses: ./
with:
fail-on-error: false

View file

@ -9,36 +9,13 @@ Run [Checkov](https://www.checkov.io/) security scans on your infrastructure cod
```yaml
- uses: imjasonh/another-checkov-action@...
with:
directory: '.' # Directory to scan (default: '.')
framework: 'all' # Framework to scan: terraform, kubernetes, dockerfile, or all (default: 'all')
fail-on-error: 'true' # Fail workflow on security issues (default: 'true')
config-file: '' # Path to .checkov.yaml config (auto-detected if exists)
# These are the defaults, you can run this without any flags.
checkov-flags: '' # Flags to pass to checkov (e.g., '--directory . --framework terraform')
fail-on-error: 'true' # Fail workflow on security issues (default: 'true')
checkov-version: 'latest' # Checkov version to install (default: 'latest')
```
## Example Workflow
```yaml
name: Security Scan
on:
pull_request:
paths:
- '**.tf'
- '**.yaml'
- '**/Dockerfile'
permissions:
contents: read
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: imjasonh/another-checkov-action@...
```
By default, Checkov scans the current directory for all supported frameworks. Use `checkov-flags` to customize the scan (e.g., `--directory examples`, `--framework terraform`, `--skip-check CKV_AWS_1`, etc.).
## Features
@ -54,14 +31,37 @@ See the [examples/](examples/) directory for intentionally misconfigured files t
## Configuration
Create a `.checkov.yaml` in your repository root to customize scanning:
### Using checkov-flags
Pass any Checkov CLI flags via the `checkov-flags` input:
```yaml
- uses: imjasonh/another-checkov-action@...
with:
checkov-flags: |
--framework terraform
--skip-check CKV_AWS_126 --compact
```
### Using a config file
Create a `.checkov.yaml` in your repository root:
```yaml
skip-check:
- CKV_AWS_126 # Skip specific checks
- CKV_AWS_126
```
See [Checkov documentation](https://www.checkov.io/2.Basics/Suppressing%20and%20Skipping%20Policies.html) for more configuration options.
Then reference it:
```yaml
- uses: imjasonh/another-checkov-action@...
with:
checkov-flags: |
--config-file .checkov.yaml
```
See [Checkov documentation](https://www.checkov.io/2.Basics/CLI-Command-Reference.html) for all available flags.
## Limitations

View file

@ -6,14 +6,6 @@ branding:
color: 'blue'
inputs:
directory:
description: 'Directory to scan (default: current directory)'
required: false
default: '.'
framework:
description: 'Filter scan to specific frameworks (e.g., terraform, kubernetes, dockerfile)'
required: false
default: 'all'
fail-on-error:
description: 'Fail the action if security issues are found'
required: false
@ -22,14 +14,10 @@ inputs:
description: 'Version of checkov to install (default: latest)'
required: false
default: 'latest'
config-file:
description: 'Path to Checkov config file (default: .checkov.yaml if it exists)'
checkov-flags:
description: 'Flags to pass to checkov (e.g., "--directory . --framework terraform --skip-check CKV_AWS_1")'
required: false
default: ''
output-format:
description: 'Output format for checkov (default: json)'
required: false
default: 'json'
outputs:
results:

88
dist/index.js vendored
View file

@ -29986,7 +29986,7 @@ async function addAnnotations(results, context) {
}
}
// Check if this file was changed in the PR
// Only annotate files that were changed in the PR
if (matchedPath) {
const properties = {
title: `${check.checkId}: ${check.checkName}`,
@ -30006,8 +30006,6 @@ async function addAnnotations(results, context) {
// Create error annotations for all failed checks
core.error(message, properties);
annotationCount++;
} else {
core.warning(`No match for file: ${check.file} (tried variations but none matched changed files)`);
}
}
@ -32205,31 +32203,17 @@ const { addAnnotations } = __nccwpck_require__(5111);
async function run() {
try {
// Get inputs
const directory = core.getInput('directory') || '.';
const framework = core.getInput('framework') || 'all';
const failOnError = core.getInput('fail-on-error') !== 'false';
const checkovVersion = core.getInput('checkov-version') || 'latest';
let configFile = core.getInput('config-file') || '';
// Check for default config file if not specified
if (!configFile) {
const defaultConfigs = ['.checkov.yaml', '.checkov.yml'];
for (const defaultConfig of defaultConfigs) {
if (fs.existsSync(defaultConfig)) {
configFile = defaultConfig;
core.info(`Using config file: ${configFile}`);
break;
}
}
}
const checkovFlags = core.getInput('checkov-flags') || '';
core.info('Installing Checkov...');
await installCheckov(checkovVersion);
core.info(`Running Checkov scan on directory: ${directory}`);
core.info('Running Checkov scan...');
const outputFile = path.join(process.env.RUNNER_TEMP || '/tmp', 'checkov-results.json');
const exitCode = await runCheckov(directory, framework, outputFile, configFile);
const exitCode = await runCheckov(outputFile, checkovFlags);
// Read and parse results
let results = null;
@ -32251,15 +32235,22 @@ async function run() {
if (github.context.eventName === 'pull_request') {
await addAnnotations(results, github.context);
}
}
// Handle failure
if (exitCode !== 0 && failOnError) {
core.setFailed(`Checkov found security issues (exit code: ${exitCode})`);
// Handle failure based on results (not exit code, since we use --soft-fail)
if (results.summary.failed > 0 && failOnError) {
core.setFailed(`Checkov found ${results.summary.failed} security issue${results.summary.failed > 1 ? 's' : ''}`);
} else if (results.summary.failed > 0) {
core.warning(`Checkov found ${results.summary.failed} security issue${results.summary.failed > 1 ? 's' : ''} but fail-on-error is disabled`);
} else {
core.info('Checkov scan completed successfully with no issues');
}
} else if (exitCode !== 0) {
core.warning(`Checkov found security issues but fail-on-error is disabled`);
} else {
core.info('Checkov scan completed successfully with no issues');
// Fallback if we couldn't parse results
if (failOnError) {
core.setFailed(`Checkov exited with code ${exitCode}`);
} else {
core.warning(`Checkov exited with code ${exitCode} but fail-on-error is disabled`);
}
}
} catch (error) {
@ -32275,20 +32266,47 @@ async function installCheckov(version) {
await exec.exec(pipCommand[0], pipCommand.slice(1));
}
async function runCheckov(directory, framework, outputFile, configFile) {
async function runCheckov(outputFile, checkovFlags) {
let userFlags = [];
// Parse user flags if provided
if (checkovFlags) {
userFlags = checkovFlags.trim().split(/\s+/).filter(f => f);
// Check if user specified --output and warn/remove it
const outputIndex = userFlags.findIndex(f => f === '--output' || f === '-o');
if (outputIndex !== -1) {
core.warning('Overriding --output flag (must be JSON for parsing)');
userFlags.splice(outputIndex, 2); // Remove --output and its value
}
// Check if user specified --soft-fail and remove it (we manage this)
const softFailIndex = userFlags.findIndex(f => f === '--soft-fail');
if (softFailIndex !== -1) {
core.info('Removing redundant --soft-fail flag (already set by action)');
userFlags.splice(softFailIndex, 1);
}
if (userFlags.length > 0) {
core.info(`Using checkov flags: ${userFlags.join(' ')}`);
}
}
// Add --directory . if not already specified
const hasDirectory = userFlags.some(f => f.startsWith('--directory') || f === '-d');
const hasFile = userFlags.some(f => f.startsWith('--file') || f === '-f');
const args = [
'--directory', directory,
'--output', 'json',
'--soft-fail' // Always use soft-fail to capture results; we'll handle failure in the action
'--soft-fail', // Always use soft-fail to capture results; we'll handle failure in the action
];
if (framework !== 'all') {
args.push('--framework', framework);
// Default to current directory if neither --directory nor --file specified
if (!hasDirectory && !hasFile) {
args.push('--directory', '.');
}
if (configFile) {
args.push('--config-file', configFile);
}
args.push(...userFlags);
let exitCode = 0;
let outputData = '';

View file

@ -59,7 +59,7 @@ async function addAnnotations(results, context) {
}
}
// Check if this file was changed in the PR
// Only annotate files that were changed in the PR
if (matchedPath) {
const properties = {
title: `${check.checkId}: ${check.checkName}`,
@ -79,8 +79,6 @@ async function addAnnotations(results, context) {
// Create error annotations for all failed checks
core.error(message, properties);
annotationCount++;
} else {
core.warning(`No match for file: ${check.file} (tried variations but none matched changed files)`);
}
}

View file

@ -10,31 +10,17 @@ const { addAnnotations } = require('./annotations');
async function run() {
try {
// Get inputs
const directory = core.getInput('directory') || '.';
const framework = core.getInput('framework') || 'all';
const failOnError = core.getInput('fail-on-error') !== 'false';
const checkovVersion = core.getInput('checkov-version') || 'latest';
let configFile = core.getInput('config-file') || '';
// Check for default config file if not specified
if (!configFile) {
const defaultConfigs = ['.checkov.yaml', '.checkov.yml'];
for (const defaultConfig of defaultConfigs) {
if (fs.existsSync(defaultConfig)) {
configFile = defaultConfig;
core.info(`Using config file: ${configFile}`);
break;
}
}
}
const checkovFlags = core.getInput('checkov-flags') || '';
core.info('Installing Checkov...');
await installCheckov(checkovVersion);
core.info(`Running Checkov scan on directory: ${directory}`);
core.info('Running Checkov scan...');
const outputFile = path.join(process.env.RUNNER_TEMP || '/tmp', 'checkov-results.json');
const exitCode = await runCheckov(directory, framework, outputFile, configFile);
const exitCode = await runCheckov(outputFile, checkovFlags);
// Read and parse results
let results = null;
@ -56,15 +42,22 @@ async function run() {
if (github.context.eventName === 'pull_request') {
await addAnnotations(results, github.context);
}
}
// Handle failure
if (exitCode !== 0 && failOnError) {
core.setFailed(`Checkov found security issues (exit code: ${exitCode})`);
// Handle failure based on results (not exit code, since we use --soft-fail)
if (results.summary.failed > 0 && failOnError) {
core.setFailed(`Checkov found ${results.summary.failed} security issue${results.summary.failed > 1 ? 's' : ''}`);
} else if (results.summary.failed > 0) {
core.warning(`Checkov found ${results.summary.failed} security issue${results.summary.failed > 1 ? 's' : ''} but fail-on-error is disabled`);
} else {
core.info('Checkov scan completed successfully with no issues');
}
} else if (exitCode !== 0) {
core.warning(`Checkov found security issues but fail-on-error is disabled`);
} else {
core.info('Checkov scan completed successfully with no issues');
// Fallback if we couldn't parse results
if (failOnError) {
core.setFailed(`Checkov exited with code ${exitCode}`);
} else {
core.warning(`Checkov exited with code ${exitCode} but fail-on-error is disabled`);
}
}
} catch (error) {
@ -80,20 +73,47 @@ async function installCheckov(version) {
await exec.exec(pipCommand[0], pipCommand.slice(1));
}
async function runCheckov(directory, framework, outputFile, configFile) {
async function runCheckov(outputFile, checkovFlags) {
let userFlags = [];
// Parse user flags if provided
if (checkovFlags) {
userFlags = checkovFlags.trim().split(/\s+/).filter(f => f);
// Check if user specified --output and warn/remove it
const outputIndex = userFlags.findIndex(f => f === '--output' || f === '-o');
if (outputIndex !== -1) {
core.warning('Overriding --output flag (must be JSON for parsing)');
userFlags.splice(outputIndex, 2); // Remove --output and its value
}
// Check if user specified --soft-fail and remove it (we manage this)
const softFailIndex = userFlags.findIndex(f => f === '--soft-fail');
if (softFailIndex !== -1) {
core.info('Removing redundant --soft-fail flag (already set by action)');
userFlags.splice(softFailIndex, 1);
}
if (userFlags.length > 0) {
core.info(`Using checkov flags: ${userFlags.join(' ')}`);
}
}
// Add --directory . if not already specified
const hasDirectory = userFlags.some(f => f.startsWith('--directory') || f === '-d');
const hasFile = userFlags.some(f => f.startsWith('--file') || f === '-f');
const args = [
'--directory', directory,
'--output', 'json',
'--soft-fail' // Always use soft-fail to capture results; we'll handle failure in the action
'--soft-fail', // Always use soft-fail to capture results; we'll handle failure in the action
];
if (framework !== 'all') {
args.push('--framework', framework);
// Default to current directory if neither --directory nor --file specified
if (!hasDirectory && !hasFile) {
args.push('--directory', '.');
}
if (configFile) {
args.push('--config-file', configFile);
}
args.push(...userFlags);
let exitCode = 0;
let outputData = '';