Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ jobs:
DIGEST_BUN_WEB: ${{ steps.build-bun-web.outputs.digest }}
run: |
set -euo pipefail
# Self-hosted runners keep /tmp across runs: start empty so digests of
# earlier runs are never uploaded (#15184).
rm -rf /tmp/digests
mkdir -p /tmp/digests/base /tmp/digests/web /tmp/digests/bun-base /tmp/digests/bun-web
touch "/tmp/digests/base/${DIGEST_BASE#sha256:}"
touch "/tmp/digests/web/${DIGEST_WEB#sha256:}"
Expand Down Expand Up @@ -472,6 +475,18 @@ jobs:
path: /tmp/digests/bun-web
merge-multiple: true

- name: Guard against stale digests
run: |
set -euo pipefail
# One digest per arch (amd64 + arm64) at most; more means stale digests leaked in (#15184).
for dir in base web bun-base bun-web; do
count=$(find "/tmp/digests/$dir" -type f 2>/dev/null | wc -l)
if [ "$count" -gt 2 ]; then
echo "digests in $dir: found $count, expected at most 2 (stale digests leaked in)" >&2
exit 1
fi
done

- name: Create Docker Hub version manifests
run: |
set -euo pipefail
Expand Down
1 change: 1 addition & 0 deletions changelog.d/fixes/15184-docker-publish-stale-digests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- fix(ci): docker-publish no longer leaks stale digests from self-hosted runners into version manifests (#15184)
36 changes: 36 additions & 0 deletions tests/unit/docker-publish-stale-digests-15184.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Regression for #15184 — docker-publish.yml's amd64 leg may run on the persistent
// self-hosted `omni-build` runner. The digest export wrote into a fixed /tmp/digests/*
// that was never cleaned, so digests from EARLIER runs ended up in the version index.
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";

const workflow = readFileSync(
fileURLToPath(new URL("../../.github/workflows/docker-publish.yml", import.meta.url)),
"utf8"
);

function stepBlock(name: string): string {
const start = workflow.indexOf(`- name: ${name}`);
assert.notEqual(start, -1, `step "${name}" not found`);
const next = workflow.indexOf("\n - name:", start + 1);
return workflow.slice(start, next === -1 ? undefined : next);
}

test("#15184: Export digests starts from an empty directory", () => {
const exportStep = stepBlock("Export digests");
assert.ok(
/rm\s+-rf\s+\/tmp\/digests/.test(exportStep) || exportStep.includes("RUNNER_TEMP"),
"Export digests must rm -rf /tmp/digests or use $RUNNER_TEMP before mkdir/touch"
);
assert.ok(exportStep.indexOf("rm -rf") < exportStep.indexOf("mkdir -p"));
});

test("#15184: merge job guards against stale digests before imagetools create", () => {
const merge = workflow.slice(workflow.indexOf("\n merge:"));
const guardAt = merge.indexOf("Guard against stale digests");
const createAt = merge.indexOf("Create Docker Hub version manifests");
assert.ok(guardAt !== -1 && guardAt < createAt, "guard step must precede manifest creation");
assert.match(stepBlock("Guard against stale digests"), /-gt 2/);
});
Loading