Compare commits

2 Commits
Author SHA1 Message Date
clawbot a192f3928b Scanner status tests no longer depend on a 100 ms timer (closes #124)
check / check (push) Failing after 3s
The two status-send tests now call the send directly on a channel nobody
receives from, so a blocking send hangs the test into its timeout instead
of racing a 100 ms timer that a loaded host can miss.

The gpg test for a child holding gpg's output had the same problem: its
100 ms deadline could fire before the fake gpg wrote the PID of sleep,
and the cleanup then failed. The fake gpg now writes that PID to a named
pipe, and the test cancels only after reading it. It then waits up to
10 s for the call, so a call that waits for sleep fails the test and the
cleanup still kills sleep.

Model: opus-5-5
2026-10-04 07:01:17 +00:00
clawbot b91e92b070 Build a static binary so the scratch image runs (closes #126)
check / check (push) Failing after 1s
The final stage is scratch, which has no C library, but the builder
compiled mfer with cgo on (the golang image's default). The binary
imports net (mfer's own HTTP code does, and so does google/uuid), so
with cgo on it came out dynamically linked and the image could not
start. The image's go build now sets CGO_ENABLED=0; nothing in mfer
needs cgo. A new builder step runs ldd on the binary and fails the
build unless it reports a static executable.

Model: opus-5-5
2026-10-04 08:48:52 +02:00
2 changed files with 15 additions and 3 deletions
+4 -1
View File
@@ -67,7 +67,10 @@ RUN version="${VERSION:-$(git describe --tags --always)}"; \
exit 1; \ exit 1; \
fi; \ fi; \
cd cmd/mfer && \ cd cmd/mfer && \
go build -tags urfave_cli_no_docs -ldflags "-X main.Gitrev=$version" -o /mfer . CGO_ENABLED=0 go build -tags urfave_cli_no_docs -ldflags "-X main.Gitrev=$version" -o /mfer .
# Fail unless /mfer is statically linked: scratch has no C library to run it.
RUN ldd /mfer 2>&1 | grep -q 'not a dynamic executable'
FROM scratch FROM scratch
COPY --from=builder /mfer /mfer COPY --from=builder /mfer /mfer
+11 -2
View File
@@ -436,7 +436,7 @@ func TestGPGTimeoutKillsGPG(t *testing.T) {
func TestGPGCancelWhenChildHoldsOutput(t *testing.T) { func TestGPGCancelWhenChildHoldsOutput(t *testing.T) {
pidPipe := filepath.Join(t.TempDir(), "sleep.pid") pidPipe := filepath.Join(t.TempDir(), "sleep.pid")
require.NoError(t, syscall.Mkfifo(pidPipe, 0o600)) require.NoError(t, syscall.Mkfifo(pidPipe, 0o600))
// sleep outlasts the 30 s test timeout, so a call that waits for it fails. // sleep outlasts the 10 s wait below, so a call that waits for it fails.
t.Setenv("PATH", fakeGPGPath(t, t.Setenv("PATH", fakeGPGPath(t,
"#!/bin/sh\nsleep 60 &\necho $! >'"+pidPipe+"'\nwait\n")) "#!/bin/sh\nsleep 60 &\necho $! >'"+pidPipe+"'\nwait\n"))
@@ -461,7 +461,16 @@ func TestGPGCancelWhenChildHoldsOutput(t *testing.T) {
t.Cleanup(func() { require.NoError(t, sleep.Kill()) }) t.Cleanup(func() { require.NoError(t, sleep.Kill()) })
cancel() cancel()
require.ErrorIs(t, <-signErr, context.Canceled)
// The call should return about gpgWaitDelay (one second) after the
// cancel. 10 s is far above that and well under the 30 s test timeout,
// which would abort the whole package before the cleanup kills sleep.
select {
case err := <-signErr:
require.ErrorIs(t, err, context.Canceled)
case <-time.After(10 * time.Second):
t.Fatal("the call waited for the child holding gpg's output to exit")
}
} }
// TestBuildPassesContextToSigning checks that a caller can cancel the gpg // TestBuildPassesContextToSigning checks that a caller can cancel the gpg