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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/actions/checkov/iac-scan/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: "Trivy IaC Security Scan"
description: "Scan IaC (Terraform, Kubernetes, etc.) for misconfigurations using Trivy"

inputs:
ref:
description: 'Git ref to scan'
required: false
type: string
scan-path:
description: 'Path to IaC files (Terraform, YAML, etc.)'
required: false
type: string
default: "."
fail_on_critical:
description: 'Fail workflow if critical misconfigurations are found'
required: false
type: boolean
default: true
iac-type:
description: "Required IaC type (cloudformation, terraform, kubernetes, all)"
required: false
type: string
default: "all"
download_external_modules:
description: "Download external terraform modules from public git repositories and terraform registry"
required: false
type: boolean
default: true
skip-check:
description: "Specific check_ids to skip"
required: false
type: string
default: none
post_pr_comment:
description: 'Post scan results as a PR comment'
required: false
type: boolean
default: true
github-token:
description: "GitHub token for PR comments"
required: true
type: string

runs:
using: "composite"
steps:
- name: Checkout repository
id: repo-checkout
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}

- name: Checkov IaC scan
id: iac-scan
uses: bridgecrewio/checkov-action@v12
with:
directory: ${{ inputs.scan-path }}
framework: ${{ inputs.iac-type }}
download_external_modules: ${{ inputs.download_external_modules }}
soft_fail: true
skip_check: ${{ inputs.skip-check }}
log_level: INFO
output_format: cli,json
output_file_path: console,checkov-iac-report.json

- name: Upload Vulnerability Scan Results
id: upload-results
uses: actions/upload-artifact@v4
with:
name: checkov-results
path: checkov-iac-report.json
retention-days: 7

- name: Fail Build on High/Criticial Vulnerabilities
id: scan-status
if: ${{ inputs.fail_on_critical == true }}
uses: bridgecrewio/checkov-action@v12
with:
directory: ${{ inputs.scan-path }}
framework: ${{ inputs.iac-type }}
download_external_modules: ${{ inputs.download_external_modules }}
skip_check: ${{ inputs.skip-check }}
check: HIGH,CRITICAL
log_level: INFO
soft_fail: false
135 changes: 135 additions & 0 deletions .github/actions/claude/claude-review/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: "Claude Code Review"
description: "Run Claude Code for Code Review"

inputs:
ref:
description: 'Git ref to scan'
required: false
type: string
default: ${{ github.ref }}
fetch-depth:
description: 'Number of commits to fetch. Use 0 for full history'
required: false
type: number
default: 1
system-prompt:
description: "Filepath to system prompt for code review"
required: true
type: string
review-prompt:
description: "Filepath to user prompt for code review"
required: true
type: string
track-progress:
description: "Force tag mode with tracking comments"
required: false
type: boolean
default: false
max-turns:
description: "Max turns the model can take during code review process"
required: true
type: number
default: 5
timeout-minutes:
description: 'Timeout for the Claude Code action'
required: false
type: number
default: 10
allowed-tools:
description: "Tools permitted for use by Claude"
required: true
type: string
default: "Task,Edit,Read,Glob,Grep,SlashCommand,mcp__github_comment__update_claude_comment,mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
disallowed-tools:
description: "Tools not permitted for use by Claude"
required: true
type: string
default: "WebFetch,WebSearch,DeleteFile,Bash(gh pr review --approve:*),Bash(gh pr review -a:*)"
claude-model:
description: "Anthropic Model for code review"
required: true
type: string
default: "claude-sonnet-4-5-20250929"
post_pr_comment:
description: "Post scan results back to the PR"
required: false
type: boolean
default: true
claude-token:
description: "Anthropic API key for accessing Claude model"
required: true
type: string
github-token:
description: "GitHub token for PR comments"
required: true
type: string


runs:
using: "composite"
steps:
- name: Checkout repository
id: repo-checkout
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}
fetch-depth: ${{ inputs.fetch-depth }}

- name: Validate and Load Prompt Files
id: load-prompts
shell: bash
run: |
set -euo pipefail

validate_file() {
local file="$1"
local label="$2"

if [[ -z "$file" ]]; then
echo "::error::$label path is empty"
exit 1
fi

if [[ ! -f "$file" ]]; then
echo "::error::$label file not found: $file"
exit 1
fi

if [[ ! -s "$file" ]]; then
echo "::error::$label file is empty: $file"
exit 1
fi
}

validate_file "${{ inputs.system-prompt-file }}" "System Prompt"
validate_file "${{ inputs.review-prompt-file }}" "Review Prompt"

{
echo "system_prompt<<EOF"
cat "${{ inputs.system-prompt-file }}"
echo "EOF"
} >> "$GITHUB_OUTPUT"

{
echo "review_prompt<<EOF"
cat "${{ inputs.review-prompt-file }}"
echo "EOF"
} >> "$GITHUB_OUTPUT"

- name: PR Review
id: claude-review
uses: anthropics/claude-code-action@v1
timeout-minutes: ${{ inputs.timeout-minutes }}
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
with:
prompt: ${{ steps.load-prompts.outputs.review_prompt }}
anthropic_api_key: ${{ inputs.claude-token }}
track_progress: ${{ inputs.track-progress }}
claude_args: |
--system-prompt ${{ steps.load-prompts.outputs.system_prompt }}
--max-turns ${{ inputs.max-turns }}
--allowedTools ${{ inputs.allowed-tools }}
--disallowedTools ${{ inputs.disallowed-tools }}
--model ${{ inputs.claude-model }}

67 changes: 67 additions & 0 deletions .github/actions/codeql-aggregate/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: "Aggregate CodeQL Results"
description: "Download and combine CodeQL results artifacts, then optionally post as PR comment"

inputs:
post-pr-comment:
description: 'Whether to post combined results as a PR comment'
required: false
type: boolean
default: true
github-token:
description: 'GitHub token for posting comments'
required: true
type: string

runs:
using: "composite"
steps:
- name: Download all CodeQL results
id: download-results
uses: actions/download-artifact@v6
with:
path: ./codeql-aggregate

- name: Combine SARIF results
id: combine-sarif-results
run: |
mkdir -p ./codeql-merged
# Merge all SARIF files into one combined SARIF file
jq -s 'reduce .[] as $item ({}; .runs += $item.runs)' ./codeql-aggregate/**/*.sarif > ./codeql-merged/combined-codeql-results.sarif || true

- name: Post combined results as PR comment
id: post-pr-comment
if: ${{ github.event_name == 'pull_request' && inputs.post_pr_comment == true }}
uses: actions/github-script@v7
with:
github-token: ${{ inputs.github-token }}
script: |
const fs = require('fs');
const maxLength = 50000;
let results = '';

try {
// Read the combined SARIF file
const sarifData = fs.readFileSync('./codeql-merged/combined-codeql-results.sarif', 'utf8');
const sarifJson = JSON.parse(sarifData);
// Extracting just the rule messages (simplified example, you can extract more info)
results = sarifJson.runs.flatMap(run =>
run.results.map(result => `${result.ruleId}: ${result.message.text}`)
).join("\n");
} catch (err) {
results = 'No CodeQL results found.';
}

// Truncate the result if it's too long
if (results.length > maxLength) {
results = results.slice(0, maxLength) + "\n...[truncated]";
}

// Post the comment on the PR
const commentBody = `### CodeQL Scan Results (all languages)\n\`\`\`\n${results}\n\`\`\``;

await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: commentBody
});
51 changes: 51 additions & 0 deletions .github/actions/codeql/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: "CodeQL SAST Scan"
description: "Static Application Security Testing (SAST) using GitHub CodeQL"

inputs:
ref:
description: 'Git ref to scan'
required: false
type: string
default: ${{ github.ref }}
language:
description: 'Language to scan'
required: true
type: string

runs:
using: "composite"
steps:
- name: Checkout repository
id: repo-checkout
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}

- name: Initialize CodeQL
id: codeql-initialize
uses: github/codeql-action/init@v4
with:
languages: ${{ inputs.language }}

- name: Perform CodeQL Analysis
id: codeql-scan
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{ inputs.language }}"

- name: Save CodeQL results artifact
id: save-results
shell: bash
run: |
if [ -f results.sarif ]; then
cp results.sarif codeql-results-${{ inputs.language }}.sarif
fi

- name: Upload CodeQL Scan Results
id: upload-results
uses: actions/upload-artifact@v6
with:
name: codeql-results-${{ inputs.language }}
path: codeql-results-${{ inputs.language }}.sarif
retention-days: 7

Loading