Skip to the content.

Work Breakdown

Numbered so each item maps 1:1 to a GitHub issue. Three owners, one per filesystem, plus a shared core that must land first.

Depends on refers to item numbers in this doc. Status: (done), (partial), or unmarked for not started.

Phase 0: Shared core

Mostly done. Only item 9 (nemo clear) is outstanding.

1. internal/image: Image interface + raw file backend (done)

Owner: core · Depends on: none Scope: internal/image/image.go (Image interface: ReadAt, WriteAt, Size, Path), internal/image/rawimage.go (os.File-backed Open and OpenReadOnly), internal/image/readonly.go (ReadOnly wrapper that fails every write). Acceptance: unit test opens a temp file, reads and writes at offsets, checks Size().

2. internal/binutil: binary helpers (done)

Owner: core · Depends on: none Scope: internal/binutil/binutil.go (Uint/Int, Bits, String/UTF16String), internal/binutil/reader.go (a sequential cursor with a sticky first-error). Acceptance: unit tests covering each helper against known byte sequences.

3. internal/custody: write recording + hashing (done)

Owner: core · Depends on: 1 Scope: internal/custody/custody.go (Wrap(image.Image) Recorder decorator, SHA-256 plus a recorded event per WriteAt), internal/custody/log.go (Record type, append to the custody log). Acceptance: wrapping a test Image and calling WriteAt produces one event with the correct hash, timestamp, and offset; the underlying Image still receives the write.

4. internal/filesystem: core interfaces (done)

Owner: core · Depends on: none Scope: internal/filesystem/filesystem.go (FileSystem, Entry, Type, and the three optional capability interfaces NamedStreamCapable, SlackSpaceCapable, TimestompCapable) per docs/architecture.md. Acceptance: compiles with no implementations yet; doc comments match the contracts in docs/architecture.md.

5. internal/filesystem/registry.go: detection + factory (done)

Owner: core · Depends on: 1, 4 Scope: Detector struct (Type, Sniff, New, Techniques), Register(Detector), Detectors(), Open(image.Image) (FileSystem, error) that sniffs every registered detector. Acceptance: unit test registers two fake detectors, confirms Open picks the right one by signature and errors on no match.

6. internal/technique: technique interface + Finding/Result (done)

Owner: core · Depends on: 4 Scope: internal/technique/technique.go (Finding, Result, Backup, Request, the Technique interface with namedStreamTechnique/slackSpaceTechnique/timestompTechnique, Get(name string) (Technique, error), ErrUnsupported and the “unsupported on this filesystem” path), slackframe.go (slack frame encode/decode), manifest.go (JSON Lines backup manifest). Acceptance: unit test calls each technique against a fake Entry that does or does not implement the needed capability, checks success and the error case.

7. cmd/hide.go (done)

Owner: core · Depends on: 5, 6 Scope: flags per docs/user-interface.md (--technique, --image, --data, --stream-name, --field, --timestamp, --manifest), mode selection (image mode iff --image given), building the custody-log line from Result plus the hash and timestamp internal/custody recorded. Acceptance: nemo hide --help shows correct flags; running against item 11’s fake filesystem exercises the named-stream path end to end.

8. cmd/detect.go (done)

Owner: core · Depends on: 5, 6 Scope: target-or-whole-image scanning; the no-target case walks Root() and Children() recursively; --technique restricts to one technique, default scans all three; one output line per finding. Acceptance: nemo detect --help correct; against item 11’s fake filesystem, the no-target scan visits every entry.

9. cmd/clear.go

Owner: core · Depends on: 5, 6 Scope: flags per docs/user-interface.md (--technique default all, --stream-name), custody recording as in hide, manifest replay via LoadManifest and LatestBackup. Acceptance: nemo clear --help correct; exercises the clear path against item 11’s fake filesystem.

10. nemo features (done)

Owner: core · Depends on: 5 Scope: Cobra command reading Techniques off every registered Detector, printing the filesystem by technique matrix. Acceptance: with only fake or no detectors registered, prints an empty or fake matrix with no image and no error.

11. In-memory fake FileSystem/Entry for testing (done)

Owner: core · Depends on: 4 Scope: internal/filesystem/fakefs, an implementation of FileSystem/Entry plus all three capability interfaces and an in-memory Image, backed by an in-memory map. Lets items 6 to 10 be tested before any real filesystem parser exists. Acceptance: used as the test double in items 6, 7, 8, 9’s acceptance tests.

Phase 1: Per filesystem (NTFS / APFS / ext4)

Each track is the same five items. Land them in order a to e; b, c, and d can ship independently of each other (add the technique’s name to Detector.Techniques in the same PR it lands in).

NTFS (owner: NTFS dev)

Not started.

12a. NTFS core parser: internal/filesystem/ntfs/ntfs.go, mft.go; satisfies FileSystem/Entry (Open, Children) against a test NTFS image; registers a Detector. Depends on: 5. 13b. NTFS named streams (ADS): namedstream.go, image-mode NamedStreamCapable. Depends on: 12a, 6. 14c. NTFS timestomp: timestomp.go, image-mode TimestompCapable. Depends on: 12a, 6. 15d. NTFS slack space: slack.go, image-mode SlackSpaceCapable. Depends on: 12a, 6. 16e. NTFS live mode: live_windows.go (syscalls for named-stream and timestomp; slack only when opened against a raw device), live_stub.go (non-Windows build tag, clean “unsupported” error). Depends on: 13b, 14c.

Acceptance for each: nemo hide/detect/clear with --technique <x> succeed against a real or synthetic NTFS test image (or, for 16e, against a live path on Windows and a stub error elsewhere).

APFS (owner: APFS dev)

17a done (parser and Detector registered, no techniques wired). Rest not started.

17a. APFS core parser (done): apfs.go, btree.go; registers Detector. Depends on: 5. 18b. APFS named streams (done): namedstream.go (xattr + resource fork), btree_write.go (in-place B-tree leaf rewrite), NamedStreamCapable. Depends on: 17a, 6. 19c. APFS timestomp: timestomp.go. Depends on: 17a, 6. 20d. APFS slack space: slack.go. Depends on: 17a, 6. 21e. APFS live mode: live_darwin.go, live_stub.go. Depends on: 18b, 19c.

Acceptance: same shape as NTFS, against an APFS test image or macOS live path.

ext4 (owner: ext4 dev)

22a, 23b, 24c done. Detector.Techniques is ["named-stream", "timestomp"].

22a. ext4 core parser (done): ext4.go, inode.go; registers Detector. Depends on: 5. 23b. ext4 named streams (xattr) (done): xattr.go. Depends on: 22a, 6. 24c. ext4 timestomp (done): timestomp.go. Depends on: 22a, 6. 25d. ext4 slack space: slack.go. Depends on: 22a, 6. 26e. ext4 live mode: live_linux.go, live_stub.go. Depends on: 23b, 24c.

Acceptance: same shape as NTFS, against an ext4 test image or Linux live path.

Phase 2: Validation and polish

Not started.

27. internal/tskcheck: libtsk cgo adapter

Owner: TBD · Depends on: 1 Scope: tskcheck.go, Validator.CrossCheck(image.Image) ([]Finding, error), build-tagged so the rest of the tree still builds with CGO_ENABLED=0. Acceptance: CGO_ENABLED=0 go build ./... succeeds excluding this package; with cgo enabled, the cross-check runs against a test image.

28. Wire tskcheck into detect

Owner: TBD · Depends on: 8, 27 Scope: optional flag or behavior in cmd/detect.go (image mode only) to run the cross-check and merge its findings. Acceptance: detect still works with tskcheck unavailable; produces cross-check output when available.

29. internal/validate: dataset harness

Owner: TBD · Depends on: 8, at least one of 12 to 26 fully done Scope: harness.go runs detect against fkie-cad/hide-and-seek-dataset images, reports pass/fail per known-hidden item. Acceptance: the harness runs against a downloaded sample of the dataset and reports a score.

30. CI: build, vet, test, cross-compile

Owner: TBD · Depends on: 7, 8, 9, 16e/21e/26e (at least the stub files) Scope: CI config running make vet, make test, and GOOS-matrixed builds (windows, darwin, linux) to catch a missing live_stub.go on any platform. Acceptance: CI green on a clean clone; deliberately breaking one platform’s stub fails the matrix build.

31. README refresh

Owner: TBD · Depends on: most of Phase 1 Scope: update anything stale in README and docs/architecture.md to match the real, built-out tree instead of the planned one. Acceptance: the architecture doc’s file tree matches find . -name '*.go' output.