From b80840307a2f4dd4e6e5ceeeb97aea82662af1a4 Mon Sep 17 00:00:00 2001 From: Will Sarg <12886992+willsarg@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:02:47 -0500 Subject: [PATCH] ci(pr-intake): make template/format checks advisory (#595) * fix(workflows): standardize runner configuration for security jobs * ci(actionlint): add Blacksmith runner label to config Add blacksmith-2vcpu-ubuntu-2404 to actionlint self-hosted-runner labels config to suppress "unknown label" warnings during workflow linting. This label is used across all workflows after the Blacksmith migration. * fix(actionlint): adjust indentation for self-hosted runner labels * feat(security): enhance security workflow with CodeQL analysis steps * fix(security): update CodeQL action to version 4 for improved analysis * fix(security): remove duplicate permissions in security workflow * fix(security): revert CodeQL action to v3 for stability The v4 version was causing workflow file validation failures. Reverting to proven v3 version that is working on main branch. * fix(security): remove duplicate permissions causing workflow validation failure The permissions block had duplicate security-events and actions keys, which caused YAML validation errors and prevented workflow execution. Fixes: workflow file validation failures on main branch * fix(security): remove pull_request trigger to reduce costs * fix(security): restore PR trigger but skip codeql on PRs * fix(security): resolve YAML syntax error in security workflow * refactor(security): split CodeQL into dedicated scheduled workflow * fix(security): update workflow name to Rust Package Security Audit * fix(codeql): remove push trigger, keep schedule and on-demand only * feat(codeql): add CodeQL configuration file to ignore specific paths * Potential fix for code scanning alert no. 39: Hard-coded cryptographic value Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix(ci): resolve auto-response workflow merge markers * fix(build): restore ChannelMessage reply_target usage * ci(workflows): run workflow sanity on workflow pushes for all branches * ci(workflows): rename auto-response workflow to PR Auto Responder * ci(workflows): require owner approval for workflow file changes * ci: add lint-first PR feedback gate * ci(workflows): split label policy checks from workflow sanity * ci(workflows): consolidate policy and rust workflow setup * ci: add safe pull request intake sanity checks * ci(security): switch audit to pinned rustsec audit-check * fix(providers): clarify reliable failure entries for custom providers * ci(pr-intake): make template/format checks advisory Keep PR Intake Sanity non-blocking for template completeness and formatting findings, while still failing on dangerous merge-conflict markers in added lines. --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/pr-intake-sanity.yml | 73 ++++++++++++++++++-------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/.github/workflows/pr-intake-sanity.yml b/.github/workflows/pr-intake-sanity.yml index 10a597e..9f40da3 100644 --- a/.github/workflows/pr-intake-sanity.yml +++ b/.github/workflows/pr-intake-sanity.yml @@ -62,7 +62,8 @@ jobs: per_page: 100, }); - const formatProblems = []; + const formatWarnings = []; + const dangerousProblems = []; for (const file of files) { const patch = file.patch || ""; if (!patch) continue; @@ -73,13 +74,13 @@ jobs: const added = line.slice(1); const lineNo = idx + 1; if (/\t/.test(added)) { - formatProblems.push(`${file.filename}:patch#${lineNo} contains tab characters`); + formatWarnings.push(`${file.filename}:patch#${lineNo} contains tab characters`); } if (/[ \t]+$/.test(added)) { - formatProblems.push(`${file.filename}:patch#${lineNo} contains trailing whitespace`); + formatWarnings.push(`${file.filename}:patch#${lineNo} contains trailing whitespace`); } if (/^(<<<<<<<|=======|>>>>>>>)/.test(added)) { - formatProblems.push(`${file.filename}:patch#${lineNo} contains merge conflict markers`); + dangerousProblems.push(`${file.filename}:patch#${lineNo} contains merge conflict markers`); } } } @@ -88,15 +89,19 @@ jobs: .map((file) => file.filename) .filter((name) => name.startsWith(".github/workflows/")); - const failures = []; + const advisoryFindings = []; + const blockingFindings = []; if (missingSections.length > 0) { - failures.push(`Missing required PR template sections: ${missingSections.join(", ")}`); + advisoryFindings.push(`Missing required PR template sections: ${missingSections.join(", ")}`); } if (missingFields.length > 0) { - failures.push(`Incomplete required PR template fields: ${missingFields.join(", ")}`); + advisoryFindings.push(`Incomplete required PR template fields: ${missingFields.join(", ")}`); } - if (formatProblems.length > 0) { - failures.push(`Formatting/safety issues in added lines (${formatProblems.length})`); + if (formatWarnings.length > 0) { + advisoryFindings.push(`Formatting issues in added lines (${formatWarnings.length})`); + } + if (dangerousProblems.length > 0) { + blockingFindings.push(`Dangerous patch markers found (${dangerousProblems.length})`); } const comments = await github.paginate(github.rest.issues.listComments, { @@ -107,7 +112,7 @@ jobs: }); const existing = comments.find((comment) => (comment.body || "").includes(marker)); - if (failures.length === 0) { + if (advisoryFindings.length === 0 && blockingFindings.length === 0) { if (existing) { await github.rest.issues.deleteComment({ owner, @@ -120,13 +125,22 @@ jobs: } const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`; - const details = []; - if (formatProblems.length > 0) { - details.push(...formatProblems.slice(0, 20).map((entry) => `- ${entry}`)); - if (formatProblems.length > 20) { - details.push(`- ...and ${formatProblems.length - 20} more issue(s)`); + const advisoryDetails = []; + if (formatWarnings.length > 0) { + advisoryDetails.push(...formatWarnings.slice(0, 20).map((entry) => `- ${entry}`)); + if (formatWarnings.length > 20) { + advisoryDetails.push(`- ...and ${formatWarnings.length - 20} more issue(s)`); } } + const blockingDetails = []; + if (dangerousProblems.length > 0) { + blockingDetails.push(...dangerousProblems.slice(0, 20).map((entry) => `- ${entry}`)); + if (dangerousProblems.length > 20) { + blockingDetails.push(`- ...and ${dangerousProblems.length - 20} more issue(s)`); + } + } + + const isBlocking = blockingFindings.length > 0; const ownerApprovalNote = workflowFilesChanged.length > 0 ? [ @@ -140,14 +154,19 @@ jobs: const commentBody = [ marker, - "### PR intake checks failed", + isBlocking + ? "### PR intake checks failed (blocking)" + : "### PR intake checks found warnings (non-blocking)", "", - "Fast safe checks ran before full CI and found issues:", - ...failures.map((entry) => `- ${entry}`), + isBlocking + ? "Fast safe checks found blocking safety issues:" + : "Fast safe checks found advisory issues. CI lint/test/build gates still enforce merge quality.", + ...(blockingFindings.length > 0 ? blockingFindings.map((entry) => `- ${entry}`) : []), + ...(advisoryFindings.length > 0 ? advisoryFindings.map((entry) => `- ${entry}`) : []), "", "Action items:", - "1. Complete the required PR template sections/fields.", - "2. Remove tabs, trailing whitespace, and conflict markers from added lines.", + "1. Complete required PR template sections/fields.", + "2. Remove tabs, trailing whitespace, and merge conflict markers from added lines.", "3. Re-run local checks before pushing:", " - `./scripts/ci/rust_quality_gate.sh`", " - `./scripts/ci/rust_strict_delta_gate.sh`", @@ -155,8 +174,11 @@ jobs: "", `Run logs: ${runUrl}`, "", - "Detected line issues (sample):", - ...(details.length > 0 ? details : ["- none"]), + "Detected blocking line issues (sample):", + ...(blockingDetails.length > 0 ? blockingDetails : ["- none"]), + "", + "Detected advisory line issues (sample):", + ...(advisoryDetails.length > 0 ? advisoryDetails : ["- none"]), ownerApprovalNote, ].join("\n"); @@ -176,4 +198,9 @@ jobs: }); } - core.setFailed("PR intake sanity checks failed. See sticky comment for details."); + if (isBlocking) { + core.setFailed("PR intake sanity checks found blocking issues. See sticky comment for details."); + return; + } + + core.info("PR intake sanity checks found advisory issues only.");