Skip to content

Change workflow trigger from pull_request to pull_request_target #833

Change workflow trigger from pull_request to pull_request_target

Change workflow trigger from pull_request to pull_request_target #833

name: Entropy Beauty + TruffleHog Scan
on:
push:
release:
pull_request:
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
- name: Cache TruffleHog Docker image
id: cache-trufflehog
uses: actions/cache@v4
with:
path: /tmp/trufflehog-image.tar
key: trufflehog-3.96.0-${{ runner.os }}
- name: Load TruffleHog image from cache
if: steps.cache-trufflehog.outputs.cache-hit == 'true'
run: docker load -i /tmp/trufflehog-image.tar
- name: Pull TruffleHog image (cache miss)
if: steps.cache-trufflehog.outputs.cache-hit != 'true'
run: |
docker pull trufflesecurity/trufflehog:3.96.0
docker save trufflesecurity/trufflehog:3.96.0 -o /tmp/trufflehog-image.tar
- name: Run TruffleHog
run: |
docker run --rm \
-v "$PWD:/pwd" \
trufflesecurity/trufflehog:3.96.0 \
git file:///pwd \
--results=verified,unknown \
--filter-entropy=3.5 \
--json \
--no-update \
> trufflehog.json 2>/dev/null || true
- name: Compute mid-4 beauty entropy
env:
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha || '' }}
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: python .github/workflows/compute-entropy.py
- name: Create sanitized summary (never include Raw secrets)
run: |
python3 << 'EOF'
import json, os
from pathlib import Path
findings = []
if Path("trufflehog.json").exists():
for line in Path("trufflehog.json").read_text().splitlines():
line = line.strip()
if not line:
continue
try:
f = json.loads(line)
findings.append({
"detector": f.get("DetectorName"),
"verified": f.get("Verified"),
"file": f.get("SourceMetadata", {}).get("Data", {}).get("Git", {}).get("file"),
"line": f.get("SourceMetadata", {}).get("Data", {}).get("Git", {}).get("line"),
})
except Exception:
pass
beauty = {}
if Path("/tmp/beauty.json").exists():
beauty = json.loads(Path("/tmp/beauty.json").read_text())
summary = {
"beauty": beauty,
"findings_count": len(findings),
"findings": findings, # safe fields only
}
Path("scan-summary.json").write_text(json.dumps(summary, indent=2))
print(f"Sanitized summary written ({len(findings)} findings)")
EOF
- name: Upload sanitized results only
uses: actions/upload-artifact@v4
with:
name: scan-results
path: scan-summary.json
retention-days: 1
# Separate job that only runs on trusted events and has write permission
create-issue:
needs: scan
if: github.event_name == 'push' || github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- name: Download summary
uses: actions/download-artifact@v4
with:
name: scan-results
- name: Create issue on suspicious entropy
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const summary = JSON.parse(fs.readFileSync('scan-summary.json', 'utf8'));
const beauty = summary.beauty || {};
const findingsCount = summary.findings_count || 0;
if (beauty.average_entropy >= 4.3 && beauty.average_entropy <= 5.1) {
console.log("✅ Mid-4 beauty — no issue created");
return;
}
let body = `**Average entropy:** ${beauty.average_entropy} bits/char\n\n`;
body += `**Verdict:** ${beauty.verdict}\n\n`;
if (beauty.files && beauty.files.length) {
body += `**Changed files:**\n\`\`\`\n${beauty.files.join('\n')}\n\`\`\`\n\n`;
}
if (findingsCount > 0) {
body += `**TruffleHog found ${findingsCount} potential issue(s)**\n`;
} else {
body += `✅ No secrets or suspicious high-entropy strings found.\n`;
}
body += `\n*Triggered by ${context.eventName} to \`${context.sha}\` — mid-4 beauty heuristic*`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🚨 Suspicious entropy detected in recent ${context.eventName} (${beauty.average_entropy})`,
body: body,
labels: ['entropy', 'security', 'review-needed']
});