neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
audit: say what was found, for the workflow's badge
be6c752 · gmorell · 2026-11-10 00:12
Message
{commit_body(@commit)}
Files changed
modified
.forgejo/workflows/audit.yml
+7
−1
@@ -49,6 +49,9 @@ jobs:
| 49 | 49 | # GitHub and Forgejo read it as an ordinary output. |
| 50 | 50 | outputs: |
| 51 | 51 | gitgud-conclusion: ${{ steps.scan.outputs.conclusion }} |
| 52 | + # "2 to fix, 1 no fix": what the workflow's badge says, rather | |
| 53 | + # than just "warning" (GitGud.Badges). | |
| 54 | + gitgud-summary: ${{ steps.scan.outputs.summary }} | |
| 52 | 55 | steps: |
| 53 | 56 | - uses: actions/checkout@v4 |
| 54 | 57 | with: |
@@ -108,6 +111,7 @@ jobs:
| 108 | 111 | runs-on: self-hosted |
| 109 | 112 | outputs: |
| 110 | 113 | gitgud-conclusion: ${{ steps.pending.outputs.conclusion }} |
| 114 | + gitgud-summary: ${{ steps.pending.outputs.summary }} | |
| 111 | 115 | steps: |
| 112 | 116 | # The job's own token reads its repository's image, as build.yml's |
| 113 | 117 | # pushes it. |
@@ -127,9 +131,11 @@ jobs:
| 127 | 131 | pending=$(docker run --rm --user root --entrypoint sh "$IMAGE" -c \ |
| 128 | 132 | 'apt-get update -qq >/dev/null && apt list --upgradable 2>/dev/null | grep -- -security' || true) |
| 129 | 133 | if [ -n "$pending" ]; then |
| 134 | + count=$(echo "$pending" | wc -l) | |
| 130 | 135 | echo "$pending" |
| 131 | − echo "::warning::$(echo "$pending" | wc -l) Debian security update(s) not in the published image: bump RUNNER_DEBIAN_VERSION, or rebuild." | |
| 136 | + echo "::warning::$count Debian security update(s) not in the published image: bump RUNNER_DEBIAN_VERSION, or rebuild." | |
| 132 | 137 | echo "conclusion=warning" >> "$GITHUB_OUTPUT" |
| 138 | + echo "summary=$count image updates" >> "$GITHUB_OUTPUT" | |
| 133 | 139 | exit 0 |
| 134 | 140 | fi |
| 135 | 141 | echo "No Debian security updates pending." |
modified
scripts/osv-audit
+19
−3
@@ -25,6 +25,10 @@ failure:
| 25 | 25 | outputs: |
| 26 | 26 | gitgud-conclusion: ${{ steps.scan.outputs.conclusion }} |
| 27 | 27 | |
| 28 | +Alongside it, `summary=` says what was found in a few words ("2 to fix, | |
| 29 | +1 no fix"), for the job's `gitgud-summary` output: the badge for the | |
| 30 | +workflow shows it (GitGud.Badges). Nothing found writes no summary. | |
| 31 | + | |
| 28 | 32 | `conclusion=success` when nothing was found. osv-scanner's own errors |
| 29 | 33 | are passed on: 127 (it failed) as 127, and 128 (no lockfiles found) as |
| 30 | 34 | 128 unless `--allow-no-lockfiles` was given, when it's nothing found. |
@@ -151,11 +155,23 @@ def report(fixable, unfixable):
| 151 | 155 | ) |
| 152 | 156 | |
| 153 | 157 | |
| 154 | −def set_output(conclusion): | |
| 158 | +def set_output(conclusion, summary=None): | |
| 155 | 159 | path = os.environ.get("GITHUB_OUTPUT") |
| 156 | 160 | if path: |
| 157 | 161 | with open(path, "a") as f: |
| 158 | 162 | f.write(f"conclusion={conclusion}\n") |
| 163 | + if summary: | |
| 164 | + f.write(f"summary={summary}\n") | |
| 165 | + | |
| 166 | + | |
| 167 | +def summary(fixable, unfixable): | |
| 168 | + """A badge's worth: `2 to fix, 1 no fix`, `1 no fix`.""" | |
| 169 | + parts = [] | |
| 170 | + if fixable: | |
| 171 | + parts.append(f"{len(fixable)} to fix") | |
| 172 | + if unfixable: | |
| 173 | + parts.append(f"{len(unfixable)} no fix") | |
| 174 | + return ", ".join(parts) or None | |
| 159 | 175 | |
| 160 | 176 | |
| 161 | 177 | def main(argv): |
@@ -199,11 +215,11 @@ def main(argv):
| 199 | 215 | |
| 200 | 216 | if fixable: |
| 201 | 217 | print(f"\n{len(fixable)} package(s) have a fixed version: update them.") |
| 202 | − set_output("failure") | |
| 218 | + set_output("failure", summary(fixable, unfixable)) | |
| 203 | 219 | return 1 |
| 204 | 220 | if unfixable: |
| 205 | 221 | print(f"\nNothing to update yet: {len(unfixable)} package(s) have no fixed version.") |
| 206 | − set_output("warning") | |
| 222 | + set_output("warning", summary(fixable, unfixable)) | |
| 207 | 223 | return 0 |
| 208 | 224 | print("\nNo known vulnerabilities.") |
| 209 | 225 | set_output("success") |
modified
test/scripts/osv_audit_test.exs
+5
−3
@@ -7,7 +7,7 @@ defmodule GitGud.Scripts.OsvAuditTest do
| 7 | 7 | What it covers is the sorting — a fixed version listed for the |
| 8 | 8 | package means "fix now", none means "blocked" — and what each outcome |
| 9 | 9 | exits with and says in `$GITHUB_OUTPUT`, which a job's |
| 10 | − `gitgud-conclusion` output reads. | |
| 10 | + `gitgud-conclusion` and `gitgud-summary` outputs read. | |
| 11 | 11 | """ |
| 12 | 12 | use ExUnit.Case, async: true |
| 13 | 13 |
@@ -91,7 +91,9 @@ defmodule GitGud.Scripts.OsvAuditTest do
| 91 | 91 | ]) |
| 92 | 92 | ]) |
| 93 | 93 | |
| 94 | − assert {out, 1, {:ok, "conclusion=failure\n"}, args} = audit(dir, report, 1) | |
| 94 | + assert {out, 1, {:ok, "conclusion=failure\nsummary=1 to fix, 1 no fix\n"}, args} = | |
| 95 | + audit(dir, report, 1) | |
| 96 | + | |
| 95 | 97 | assert args == ~w(scan source --format json -r .) |
| 96 | 98 | |
| 97 | 99 | [fix_now, blocked] = String.split(out, "No fix available / blocked") |
@@ -108,7 +110,7 @@ defmodule GitGud.Scripts.OsvAuditTest do
| 108 | 110 | ]) |
| 109 | 111 | ]) |
| 110 | 112 | |
| 111 | − assert {out, 0, {:ok, "conclusion=warning\n"}, _} = audit(dir, report, 1) | |
| 113 | + assert {out, 0, {:ok, "conclusion=warning\nsummary=1 no fix\n"}, _} = audit(dir, report, 1) | |
| 112 | 114 | assert out =~ "Fix now: 0" |
| 113 | 115 | assert out =~ "No fix available / blocked: 1" |
| 114 | 116 | end |
Parents: 0d6bdf0