transparency-dev / transparency-dev/tesseract

cmd/fsck: `--ui=false` Exits 0 on Corrupted Logs

Open
#937 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Go
Stars
37
Forks
18
Avg merge
19h 22m
Merged PRs (30d)
15

Description

[discovered w/ the help of Claude]

Problem

fsck --ui=false always exits 0 even on corruption, discarding errors before they reach $?. In 2 of 3 failure modes, no diagnostic is printed, making --ui=false unusable as an automated CI/pipeline gate.

Impact Matrix (Fault Injection on Static-CT Log)
Corruption Type Detected Internally Output Diagnostic Exit Code
Bit flip (tile/0/042) Yes (hash mismatch) None 0
Truncation (tile/data/042) Yes (bundle parse error) None 0
Missing issuer (issuer/<hex>) Yes (fetch failure) WARN only 0

Underlying detection logic in tessera/fsck is sound; only cmd/fsck error reporting fails.

Root Causes

  1. Early Return Bypasses eg.Wait() (main.go:92–101):
    f.Check completion invokes deferred cancel(), closing ctx.Done(). The non-TUI loop executes case <-ctx.Done(): return, exiting main directly and skipping eg.Wait(), os.Exit(1), and slog.Info("OK").
  2. Disconnected Issuer Status:
    Successfully fsck'd log (tessera/fsck/fsck.go:167) reflects tree verification only, omitting concurrent checkIssuersTask status.
  3. LIFO Defer Prematurely Cancels Context (main.go:76–81):
    defer cancel() runs before defer lsc.Close(), canceling ctx while issuer workers may still be draining issuersToCheck, potentially truncating checks on large logs or causing spurious HTTP context canceled errors.
  4. Regression test: No test currently invokes the cmd/fsck binary — all existing fsck coverage calls Check() directly and inspects the returned error, which is why this went unnoticed. Add a test that execs the built binary against a corrupted fixture with --ui=false and asserts a non-zero exit.

Minimal Reproduction

go build -o /tmp/fsck-ct ./cmd/fsck

# Corrupt single byte in a mirrored log tile:
cp -r /path/to/log /tmp/broken
printf '\x01' | dd of=/tmp/broken/tile/0/042 bs=1 seek=100 conv=notrunc

# Run without TUI:
/tmp/fsck-ct --monitoring_url=file:///tmp/broken \
  --origin=<origin> --public_key=<key> --ui=false
echo $?  # Returns 0 with no error diagnostics (BUG)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with cmd/fsck/main.go:76–101 and tessera/fsck/fsck.go:167, then build ./cmd/fsck and reproduce the corrupted-log case with --ui=false. Add a test that executes the fsck binary against a corrupted fixture and verifies diagnostics plus a non-zero exit; done also requires issuer checks to be included without premature cancellation.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.