Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0235bee17 |
@@ -16,7 +16,6 @@ linters:
|
|||||||
- depguard # Dependency allow/block lists
|
- depguard # Dependency allow/block lists
|
||||||
- godot # Requires comments to end with periods
|
- godot # Requires comments to end with periods
|
||||||
- wsl # Deprecated, replaced by wsl_v5
|
- wsl # Deprecated, replaced by wsl_v5
|
||||||
- gomodguard # Deprecated, replaced by gomodguard_v2
|
|
||||||
- wrapcheck # Too verbose for internal packages
|
- wrapcheck # Too verbose for internal packages
|
||||||
- varnamelen # Short names like db, id are idiomatic Go
|
- varnamelen # Short names like db, id are idiomatic Go
|
||||||
settings:
|
settings:
|
||||||
|
|||||||
+1
-4
@@ -69,10 +69,7 @@ RUN version="${VERSION:-$(git describe --tags --always)}"; \
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
cd cmd/mfer && \
|
cd cmd/mfer && \
|
||||||
CGO_ENABLED=0 go build -tags urfave_cli_no_docs -ldflags "-X main.Gitrev=$version" -o /mfer .
|
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
|
||||||
|
|||||||
+24
-40
@@ -10,7 +10,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -426,51 +425,36 @@ func TestGPGTimeoutKillsGPG(t *testing.T) {
|
|||||||
assert.Contains(t, err.Error(), "gpg sign failed: gpg timed out")
|
assert.Contains(t, err.Error(), "gpg sign failed: gpg timed out")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestGPGCancelWhenChildHoldsOutput uses a fake gpg that runs sleep as a
|
// TestGPGTimeoutWhenChildHoldsOutput uses a fake gpg that runs sleep as a
|
||||||
// child instead of exec-ing it, the way a wrapper script around the real
|
// child instead of exec-ing it, the way a wrapper script around the real
|
||||||
// gpg might. Killing the fake gpg leaves sleep holding its stdout and
|
// gpg might. Killing the fake gpg leaves sleep holding its stdout and
|
||||||
// stderr open; the call must still return once ctx ends instead of waiting
|
// stderr open; the call must still return shortly after the deadline
|
||||||
// for sleep to exit. The fake gpg writes the process ID of sleep to a named
|
// instead of waiting for sleep to exit. The fake gpg writes the process ID
|
||||||
// pipe; the test ends ctx only after reading it, so sleep is running by
|
// of sleep to a file so that the test can kill it before returning.
|
||||||
// then, and kills sleep before returning.
|
func TestGPGTimeoutWhenChildHoldsOutput(t *testing.T) {
|
||||||
func TestGPGCancelWhenChildHoldsOutput(t *testing.T) {
|
pidFile := filepath.Join(t.TempDir(), "sleep.pid")
|
||||||
pidPipe := filepath.Join(t.TempDir(), "sleep.pid")
|
|
||||||
require.NoError(t, syscall.Mkfifo(pidPipe, 0o600))
|
|
||||||
// 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 3 &\necho $! >'"+pidFile+"'\nwait\n"))
|
||||||
|
t.Cleanup(func() {
|
||||||
|
pid, err := os.ReadFile(pidFile) //nolint:gosec // G304: path inside t.TempDir()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
n, err := strconv.Atoi(strings.TrimSpace(string(pid)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
sleep, err := os.FindProcess(n)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, sleep.Kill())
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
signErr := make(chan error, 1)
|
start := time.Now()
|
||||||
|
_, err := gpgSign(ctx, []byte("data"), GPGKeyID("any"))
|
||||||
go func() {
|
require.ErrorIs(t, err, context.DeadlineExceeded)
|
||||||
_, err := gpgSign(ctx, []byte("data"), GPGKeyID("any"))
|
assert.Less(t, time.Since(start), 3*time.Second,
|
||||||
signErr <- err
|
"the call waited for the child holding gpg's output to exit")
|
||||||
}()
|
|
||||||
|
|
||||||
pid, err := os.ReadFile(pidPipe) //nolint:gosec // G304: path inside t.TempDir()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
n, err := strconv.Atoi(strings.TrimSpace(string(pid)))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
sleep, err := os.FindProcess(n)
|
|
||||||
require.NoError(t, err)
|
|
||||||
t.Cleanup(func() { require.NoError(t, sleep.Kill()) })
|
|
||||||
|
|
||||||
cancel()
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
+31
-4
@@ -304,19 +304,46 @@ func TestScannerEnumerateFS(t *testing.T) {
|
|||||||
func TestSendEnumerateStatusNonBlocking(t *testing.T) {
|
func TestSendEnumerateStatusNonBlocking(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Nobody receives, so a blocking send would hang the test into its timeout.
|
// Channel with no buffer - send should not block
|
||||||
ch := make(chan EnumerateStatus)
|
ch := make(chan EnumerateStatus)
|
||||||
|
|
||||||
sendEnumerateStatus(ch, EnumerateStatus{FilesFound: 1})
|
// This should not block
|
||||||
|
done := make(chan bool)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
sendEnumerateStatus(ch, EnumerateStatus{FilesFound: 1})
|
||||||
|
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
// Success - did not block
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
t.Fatal("sendEnumerateStatus blocked on full channel")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendScanStatusNonBlocking(t *testing.T) {
|
func TestSendScanStatusNonBlocking(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Nobody receives, so a blocking send would hang the test into its timeout.
|
// Channel with no buffer - send should not block
|
||||||
ch := make(chan ScanStatus)
|
ch := make(chan ScanStatus)
|
||||||
|
|
||||||
sendScanStatus(ch, ScanStatus{ScannedFiles: 1})
|
done := make(chan bool)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
sendScanStatus(ch, ScanStatus{ScannedFiles: 1})
|
||||||
|
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
// Success - did not block
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
t.Fatal("sendScanStatus blocked on full channel")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendStatusNilChannel(t *testing.T) {
|
func TestSendStatusNilChannel(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user