mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-13 14:37:26 +00:00
ci: remove the vu1nz security scan (#127)
vu1nz reviews a diff by calling Claude, which needs ANTHROPIC_API_KEY supplied through the ENV_FILE secret. That key is not present on this repository, so the scanner has never reviewed a pull request. On pack 1.0.0 and 1.0.1 that failure was silent: the job reported "0 finding(s), no high/critical issues" on a diff nothing had read, which is worse than no scanner at all. threatcrush-scan covers the same ground deterministically - credentials, injection, SSRF, unsafe deserialisation, XXE, dependency tampering - with no API key and no per-pull-request cost. Reinstallable from the sh1pt Actions Store if the key is ever provisioned. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3440a2e4da
commit
bfb536c894
1 changed files with 0 additions and 214 deletions
214
.github/workflows/vu1nz-scan.yml
vendored
214
.github/workflows/vu1nz-scan.yml
vendored
|
|
@ -1,214 +0,0 @@
|
||||||
# Managed by sh1pt Actions Fleet
|
|
||||||
# pack: vu1nz-scan@1.0.0
|
|
||||||
# install: sh1pt-actions-store
|
|
||||||
# hash: sha256:a5f27998f1a6ddd9e2ff263724a5d4eb5887a306210d9c00591d9a918a7136ad
|
|
||||||
name: vu1nz security scan
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
review:
|
|
||||||
name: Review PR for security vulnerabilities
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 15
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: "3.12"
|
|
||||||
|
|
||||||
- name: Install vu1nz
|
|
||||||
run: pip install --quiet git+https://github.com/profullstack/vu1nz-gh-actions.git
|
|
||||||
|
|
||||||
- name: Load env file
|
|
||||||
env:
|
|
||||||
ENV_FILE: ${{ secrets.ENV_FILE }}
|
|
||||||
run: |
|
|
||||||
echo "$ENV_FILE" > "$RUNNER_TEMP/.env"
|
|
||||||
echo "Keys in ENV_FILE:"
|
|
||||||
grep -oP '^[A-Z_]+(?==)' "$RUNNER_TEMP/.env" || echo "(no keys found or different format)"
|
|
||||||
ANTHROPIC_API_KEY=$(grep -E '^ANTHROPIC_API_KEY=' "$RUNNER_TEMP/.env" | head -1 | sed 's/^ANTHROPIC_API_KEY=//')
|
|
||||||
if [ -n "$ANTHROPIC_API_KEY" ]; then
|
|
||||||
echo "::add-mask::$ANTHROPIC_API_KEY"
|
|
||||||
echo "ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY" >> "$GITHUB_ENV"
|
|
||||||
echo "ANTHROPIC_API_KEY found and exported"
|
|
||||||
else
|
|
||||||
echo "::warning::ANTHROPIC_API_KEY not found in ENV_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Review PR
|
|
||||||
id: review
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
NO_COLOR: "1"
|
|
||||||
TERM: dumb
|
|
||||||
run: |
|
|
||||||
vu1nz review-pr main \
|
|
||||||
${{ github.repository }} \
|
|
||||||
${{ github.event.pull_request.number }} \
|
|
||||||
--token "$GITHUB_TOKEN" \
|
|
||||||
--json \
|
|
||||||
| tee "$RUNNER_TEMP/vu1nz-review-raw.txt" || true
|
|
||||||
|
|
||||||
python3 -c "
|
|
||||||
import json, re, sys
|
|
||||||
raw = open('$RUNNER_TEMP/vu1nz-review-raw.txt').read()
|
|
||||||
raw = re.sub(r'\x1b\[[0-9;]*m', '', raw)
|
|
||||||
start = raw.find('{')
|
|
||||||
if start >= 0:
|
|
||||||
obj, _ = json.JSONDecoder(strict=False).raw_decode(raw, start)
|
|
||||||
json.dump(obj, sys.stdout)
|
|
||||||
else:
|
|
||||||
print('{}')
|
|
||||||
" > "$RUNNER_TEMP/vu1nz-review.json"
|
|
||||||
|
|
||||||
- name: Build PR comment
|
|
||||||
id: comment
|
|
||||||
run: |
|
|
||||||
python3 << 'PYEOF'
|
|
||||||
import json, os, sys
|
|
||||||
|
|
||||||
review_file = os.environ.get("RUNNER_TEMP", "") + "/vu1nz-review.json"
|
|
||||||
comment_file = os.environ.get("RUNNER_TEMP", "") + "/vu1nz-comment.md"
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(review_file) as f:
|
|
||||||
data = json.loads(f.read(), strict=False)
|
|
||||||
except Exception as e:
|
|
||||||
print(f"::warning::Could not parse review results: {e}")
|
|
||||||
with open(comment_file, "w") as f:
|
|
||||||
f.write("## vu1nz Security Review\n\nCould not parse review results.\n")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
findings = data.get("findings", [])
|
|
||||||
analysis = data.get("analysis", "")
|
|
||||||
pr = data.get("pr_number", "?")
|
|
||||||
total = len(findings)
|
|
||||||
|
|
||||||
counts = {"critical": 0, "high": 0, "medium": 0, "low": 0}
|
|
||||||
for finding in findings:
|
|
||||||
sev = finding.get("severity", "").lower()
|
|
||||||
if sev in counts:
|
|
||||||
counts[sev] += 1
|
|
||||||
|
|
||||||
has_hc = counts["critical"] > 0 or counts["high"] > 0
|
|
||||||
|
|
||||||
lines = ["## vu1nz Security Review", ""]
|
|
||||||
lines.append(f"**{total}** finding(s) in PR #{pr}")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
badge_parts = []
|
|
||||||
for sev in ("critical", "high", "medium", "low"):
|
|
||||||
if counts[sev] > 0:
|
|
||||||
badge_parts.append(f"**{sev.upper()}**: {counts[sev]}")
|
|
||||||
if badge_parts:
|
|
||||||
lines.append(" | ".join(badge_parts))
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
if has_hc:
|
|
||||||
lines.append("> **High or critical findings - review before merging.**")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
if findings:
|
|
||||||
lines.append("### Findings")
|
|
||||||
lines.append("")
|
|
||||||
lines.append("| Severity | File | Issue | Suggestion |")
|
|
||||||
lines.append("|----------|------|-------|------------|")
|
|
||||||
for f in findings:
|
|
||||||
sev = f.get("severity", "?").upper()
|
|
||||||
file = f.get("file", "N/A")
|
|
||||||
issue = f.get("issue", "").replace("\n", " ")[:150]
|
|
||||||
suggestion = f.get("suggestion", "").replace("\n", " ")[:150]
|
|
||||||
lines.append(f"| {sev} | `{file}` | {issue} | {suggestion} |")
|
|
||||||
lines.append("")
|
|
||||||
else:
|
|
||||||
lines.append("No security issues found.")
|
|
||||||
lines.append("")
|
|
||||||
|
|
||||||
if analysis:
|
|
||||||
lines.append("<details><summary>Full AI Analysis</summary>")
|
|
||||||
lines.append("")
|
|
||||||
lines.append(analysis)
|
|
||||||
lines.append("")
|
|
||||||
lines.append("</details>")
|
|
||||||
|
|
||||||
body = "\n".join(lines)
|
|
||||||
with open(comment_file, "w") as f:
|
|
||||||
f.write(body)
|
|
||||||
|
|
||||||
with open(os.environ.get("GITHUB_OUTPUT", ""), "a") as out:
|
|
||||||
out.write(f"total={total}\n")
|
|
||||||
out.write(f"has_high_critical={'true' if has_hc else 'false'}\n")
|
|
||||||
|
|
||||||
if has_hc:
|
|
||||||
print(f"::error::vu1nz found high/critical vulnerabilities in PR code")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print(f"::notice::vu1nz review: {total} finding(s), no high/critical issues")
|
|
||||||
PYEOF
|
|
||||||
|
|
||||||
- name: Write report to job summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
if [ -f "$RUNNER_TEMP/vu1nz-comment.md" ]; then
|
|
||||||
cat "$RUNNER_TEMP/vu1nz-comment.md" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
else
|
|
||||||
echo "## vu1nz Security Review" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
echo "Scan completed but could not read results." >> "$GITHUB_STEP_SUMMARY"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Comment on PR
|
|
||||||
if: always() && github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const fs = require('fs');
|
|
||||||
const commentFile = `${process.env.RUNNER_TEMP}/vu1nz-comment.md`;
|
|
||||||
let body;
|
|
||||||
try {
|
|
||||||
body = fs.readFileSync(commentFile, 'utf8');
|
|
||||||
} catch {
|
|
||||||
body = '## vu1nz Security Review\n\nScan completed but could not read results.';
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data: comments } = await github.rest.issues.listComments({
|
|
||||||
issue_number: context.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
});
|
|
||||||
|
|
||||||
const existing = comments.find(c =>
|
|
||||||
c.user.type === 'Bot' && c.body.includes('vu1nz Security Review')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existing) {
|
|
||||||
await github.rest.issues.updateComment({
|
|
||||||
comment_id: existing.id,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: body,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
issue_number: context.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
body: body,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
if (err.status === 403) {
|
|
||||||
core.warning(`Cannot post PR comment (read-only token): ${err.message}. Findings are in the job summary.`);
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue