From 89dad5137e992b232197ce29ed5ad0560168dc9a Mon Sep 17 00:00:00 2001 From: Cameron Johnson Date: Wed, 8 Apr 2026 20:01:08 -0500 Subject: [PATCH 1/2] Fix PR comment workflow parsing on main --- .github/workflows/costguard-pr-comment.yml | 42 ++++++++++++++-------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/.github/workflows/costguard-pr-comment.yml b/.github/workflows/costguard-pr-comment.yml index 6b1c5a6..19151a6 100644 --- a/.github/workflows/costguard-pr-comment.yml +++ b/.github/workflows/costguard-pr-comment.yml @@ -21,20 +21,34 @@ jobs: const fs = require('fs'); const data = JSON.parse(fs.readFileSync('result.json', 'utf8')); - const body = ` -❌ CostGuardAI Analysis - -Safety Score: ${data.safety_score}/100 - -Top risks: -${data.top_risks?.map(r => `- ${r}`).join('\n') || '- None'} - -Prevent this automatically in CI: - -\`\`\`yaml -- uses: Camj78/costguardai-action@v1 -\`\`\` -`; + const files = Array.isArray(data.files) ? data.files : []; + + const highestRiskFile = files.reduce((max, f) => { + return (f.risk_score ?? 0) > (max.risk_score ?? 0) ? f : max; + }, files[0] || {}); + + const riskScore = highestRiskFile.risk_score ?? 0; + const safetyScore = 100 - riskScore; + const fileName = highestRiskFile.file || 'unknown'; + const riskDrivers = Array.isArray(highestRiskFile.risk_drivers) + ? highestRiskFile.risk_drivers + : []; + + const driversText = riskDrivers.length > 0 + ? riskDrivers.map(r => "- " + r).join("\n") + : "- None identified"; + + const body = + "## CostGuardAI Safety Report\n\n" + + "**File:** `" + fileName + "`\n" + + "**Safety Score:** " + safetyScore + "/100 (100 - risk score of " + riskScore + ")\n\n" + + "**Risk Drivers:**\n" + + driversText + "\n\n" + + "---\n" + + "Add CostGuardAI to your CI pipeline:\n\n" + + "```yaml\n" + + "- uses: Camj78/costguardai-action@v1\n" + + "```"; await github.rest.issues.createComment({ issue_number: context.issue.number, From a03f57cd297af65932d76ce3342e267f19dba289 Mon Sep 17 00:00:00 2001 From: Cameron Johnson Date: Wed, 8 Apr 2026 20:54:49 -0500 Subject: [PATCH 2/2] Retrigger PR comment workflow on clean PR --- .github/workflows/costguard-pr-comment.yml | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/costguard-pr-comment.yml b/.github/workflows/costguard-pr-comment.yml index 19151a6..bdbb181 100644 --- a/.github/workflows/costguard-pr-comment.yml +++ b/.github/workflows/costguard-pr-comment.yml @@ -9,20 +9,57 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Detect analyzable files + id: detect + run: | + FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD 2>/dev/null | grep -E '\.(prompt|txt|md)$' || true) + if [ -z "$FILES" ]; then + echo "skip=true" >> $GITHUB_OUTPUT + echo "No analyzable prompt files changed — skipping analysis." + else + echo "skip=false" >> $GITHUB_OUTPUT + echo "Analyzable files found:" + echo "$FILES" + fi + - name: Run CostGuardAI id: costguard + if: steps.detect.outputs.skip == 'false' run: npx @camj78/costguardai@latest ci --fail-on-risk 70 --format json > result.json continue-on-error: true - name: Post PR comment + if: steps.detect.outputs.skip == 'false' uses: actions/github-script@v7 with: script: | const fs = require('fs'); - const data = JSON.parse(fs.readFileSync('result.json', 'utf8')); + + if (!fs.existsSync('result.json')) { + console.log('result.json not found — skipping comment.'); + return; + } + + let data; + try { + const raw = fs.readFileSync('result.json', 'utf8').trim(); + if (!raw) { + console.log('result.json is empty — skipping comment.'); + return; + } + data = JSON.parse(raw); + } catch (e) { + console.log('result.json could not be parsed — skipping comment: ' + e.message); + return; + } const files = Array.isArray(data.files) ? data.files : []; + if (files.length === 0) { + console.log('No files in analysis output — skipping comment.'); + return; + } + const highestRiskFile = files.reduce((max, f) => { return (f.risk_score ?? 0) > (max.risk_score ?? 0) ? f : max; }, files[0] || {});