Add workflow that creates/updates GitHub issue on CI failure
What changed, and why it matters
This commit adds a GitHub Actions workflow that automatically opens or closes a repository issue when two specific scheduled CI workflows (Fuzz and Kani CI) fail or succeed on the master branch. It is purely an automation/notification change and does not modify any library code, cryptography, network handling, or user-facing behavior of the rust-bitcoin crate.
No security action required. Treat as routine repository automation. If desired, reviewers can confirm the issues:write permission is limited to this single workflow and that the workflow_run trigger only responds to the expected internal workflows.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The new .github/workflows/ci-failure-issues.yml runs on workflow_run completion for ‘Fuzz’ and ‘Kani CI’ on master. It uses actions/github-script with issues:write permission to list open issues, find one tagged with a workflow-specific HTML comment marker, create an issue if the run failed and none exists, or comment and close the issue if the run succeeded. The workflow pins the github-script action to a specific commit hash and includes a zizmor ignore comment for the workflow_run trigger. No source code, tests, or build logic are changed.
Changed components
.github/workflows/ci-failure-issues.ymlInspect captured patch +94 / −0
diff --git a/.github/workflows/ci-failure-issues.yml b/.github/workflows/ci-failure-issues.yml
new file mode 100644
index 00000000..0b8fd72b
--- /dev/null
+++ b/.github/workflows/ci-failure-issues.yml
@@ -0,0 +1,94 @@
+name: CI Failure Issues
+
+on:
+ workflow_run: # zizmor: ignore[dangerous-triggers]
+ workflows:
+ - Fuzz
+ - Kani CI
+ types:
+ - completed
+ branches:
+ - master
+
+permissions:
+ issues: write
+
+concurrency:
+ group: ci-failure-issues-${{ github.event.workflow_run.name }}
+ cancel-in-progress: false
+
+jobs:
+ sync-issue:
+ if: ${{ contains(fromJson('["failure","success"]'), github.event.workflow_run.conclusion) }}
+ runs-on: ubuntu-24.04
+
+ steps:
+ - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
+ with:
+ script: |
+ const run = context.payload.workflow_run;
+ const workflow = run.name;
+ const marker = `<!-- ci-failure-key:${workflow} -->`;
+ const workflowFiles = {
+ "Fuzz": "cron-daily-fuzz.yml",
+ "Kani CI": "cron-daily-kani.yml",
+ };
+
+ const formatTs = iso => {
+ const d = new Date(iso);
+ const pad = n => String(n).padStart(2, "0");
+ return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} at ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())} UTC`;
+ };
+ const shortSha = sha => (sha || "unknown").slice(0, 7);
+ const commitUrl = sha => `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/commit/${sha}`;
+ const workflowUrl = workflowFiles[workflow]
+ ? `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/workflows/${workflowFiles[workflow]}`
+ : `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions?query=${encodeURIComponent(`workflow:"${workflow}"`)}`;
+
+ function titleFor() {
+ return `The ${workflow} workflow is failing`;
+ }
+
+ function bodyForFailure() {
+ return [
+ marker,
+ "",
+ `The [${workflow} workflow](${workflowUrl}) started failing on ${formatTs(run.created_at)}: [${workflow} #${run.run_number}](${run.html_url}) - [\`${shortSha(run.head_sha)}\`](${commitUrl(run.head_sha)})`,
+ ].join("\n");
+ }
+
+ const issues = await github.paginate(github.rest.issues.listForRepo, {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: "open",
+ per_page: 100,
+ });
+
+ const existing = issues.find(issue =>
+ !issue.pull_request && issue.body && issue.body.includes(marker)
+ );
+
+ if (run.conclusion === "failure" && !existing) {
+ await github.rest.issues.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ title: titleFor(),
+ body: bodyForFailure(),
+ });
+ }
+
+ if (run.conclusion === "success" && existing) {
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: existing.number,
+ body: `The [${workflow} workflow](${workflowUrl}) successfully ran again on ${formatTs(run.created_at)}: [${workflow} #${run.run_number}](${run.html_url}).`,
+ });
+
+ await github.rest.issues.update({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: existing.number,
+ state: "closed",
+ });
+ }
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.