docs(05-shell-decoder): create phase plan
This commit is contained in:
213
.planning/phases/05-shell-decoder/05-02-PLAN.md
Normal file
213
.planning/phases/05-shell-decoder/05-02-PLAN.md
Normal file
@@ -0,0 +1,213 @@
|
||||
---
|
||||
phase: 05-shell-decoder
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- "05-01"
|
||||
files_modified:
|
||||
- shell/test_decoder.sh
|
||||
autonomous: true
|
||||
requirements:
|
||||
- SHL-01
|
||||
- SHL-02
|
||||
- SHL-03
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Shell decoder extracts single text file byte-identical to original"
|
||||
- "Shell decoder extracts multiple files (text + binary) byte-identical to originals"
|
||||
- "Shell decoder extracts files with Cyrillic UTF-8 filenames correctly"
|
||||
- "Shell decoder handles no-compress mode (raw encrypted, not gzip-compressed)"
|
||||
- "Shell decoder handles empty (0-byte) files"
|
||||
- "Shell decoder handles large files (100 KB+)"
|
||||
artifacts:
|
||||
- path: "shell/test_decoder.sh"
|
||||
provides: "Cross-validation test script: Rust pack -> Shell decode -> SHA-256 verify"
|
||||
min_lines: 150
|
||||
contains: "sha256sum"
|
||||
key_links:
|
||||
- from: "shell/test_decoder.sh"
|
||||
to: "shell/decode.sh"
|
||||
via: "Invokes decode.sh to decode Rust-created archives"
|
||||
pattern: "decode\\.sh"
|
||||
- from: "shell/test_decoder.sh"
|
||||
to: "target/release/encrypted_archive"
|
||||
via: "Uses Rust archiver to create test archives"
|
||||
pattern: "encrypted_archive.*pack"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create cross-validation test script that verifies the shell decoder produces byte-identical output to originals for all edge cases.
|
||||
|
||||
Purpose: Prove the shell decoder correctly implements the archive format by testing against Rust-created archives (same pattern as kotlin/test_decoder.sh).
|
||||
|
||||
Output: `shell/test_decoder.sh` -- a test script that creates archives with the Rust CLI, decodes with decode.sh, and verifies byte-identical output via SHA-256 comparison.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/nick/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/nick/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/05-shell-decoder/05-01-SUMMARY.md
|
||||
@kotlin/test_decoder.sh
|
||||
@shell/decode.sh
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create shell/test_decoder.sh cross-validation test script</name>
|
||||
<files>shell/test_decoder.sh</files>
|
||||
<action>
|
||||
Create `shell/test_decoder.sh` modeled after `kotlin/test_decoder.sh` but adapted for the shell decoder. This script uses bash (it runs on the development machine, not the target device) but invokes `decode.sh` with `sh` to ensure POSIX compatibility.
|
||||
|
||||
**Script structure (follow kotlin/test_decoder.sh pattern):**
|
||||
|
||||
1. **Header:**
|
||||
- `#!/usr/bin/env bash`
|
||||
- `set -euo pipefail`
|
||||
- Comment: Cross-validation test script for Shell decoder
|
||||
|
||||
2. **Variables and helpers (copy pattern from kotlin/test_decoder.sh):**
|
||||
- SCRIPT_DIR, PROJECT_DIR, TMPDIR, PASS_COUNT, FAIL_COUNT, TOTAL_COUNT
|
||||
- Colors (GREEN, RED, YELLOW, BOLD, NC) with terminal detection
|
||||
- `cleanup()` function with trap
|
||||
- `pass()`, `fail()`, `sha256_of()`, `verify_file()` helper functions (identical to kotlin version)
|
||||
|
||||
3. **Prerequisites check:**
|
||||
- Check for `cargo` (to build Rust archiver)
|
||||
- Check for `openssl` (needed by decode.sh)
|
||||
- Check for `sh` (always available, but verify)
|
||||
- Print versions: cargo, openssl, sh
|
||||
|
||||
4. **Build Rust archiver:**
|
||||
```bash
|
||||
(cd "$PROJECT_DIR" && cargo build --release -q)
|
||||
ARCHIVER="$PROJECT_DIR/target/release/encrypted_archive"
|
||||
```
|
||||
|
||||
5. **Decoder path:**
|
||||
```bash
|
||||
DECODER="$SCRIPT_DIR/decode.sh"
|
||||
```
|
||||
Verify it exists and is executable.
|
||||
|
||||
6. **Test cases (6 tests matching kotlin/test_decoder.sh):**
|
||||
|
||||
**Test 1: Single text file**
|
||||
- Create `hello.txt` with content "Hello, World!" (no newline: `echo -n`)
|
||||
- Pack with Rust archiver
|
||||
- Decode with: `sh "$DECODER" "$TMPDIR/test1.archive" "$TMPDIR/output1/"`
|
||||
- verify_file hello.txt
|
||||
|
||||
**Test 2: Multiple files (text + binary)**
|
||||
- Create text.txt with 3 lines
|
||||
- Create binary.bin with 10 KB random data (`dd if=/dev/urandom bs=1024 count=10`)
|
||||
- Pack both files
|
||||
- Decode with sh
|
||||
- verify_file text.txt, binary.bin
|
||||
|
||||
**Test 3: No-compress mode**
|
||||
- Create fake.dat with 2.5 KB random data
|
||||
- Pack with `--no-compress "fake.dat"`
|
||||
- Decode with sh
|
||||
- verify_file fake.dat
|
||||
|
||||
**Test 4: Empty file**
|
||||
- Create empty.txt with `touch`
|
||||
- Pack with Rust archiver
|
||||
- Decode with sh
|
||||
- Verify output file exists and is 0 bytes (same logic as kotlin test)
|
||||
|
||||
**Test 5: Large file (100 KB)**
|
||||
- Create large.bin with 100 KB random data
|
||||
- Pack with Rust archiver
|
||||
- Decode with sh
|
||||
- verify_file large.bin
|
||||
|
||||
**Test 6: Cyrillic UTF-8 filename (SHL-03 validation)**
|
||||
- Create a file with a Cyrillic name: `echo -n "Тестовое содержимое" > "$TMPDIR/файл.txt"`
|
||||
- Pack with Rust archiver
|
||||
- Decode with sh
|
||||
- verify_file that the Cyrillic-named file exists and matches SHA-256
|
||||
- This test specifically validates SHL-03
|
||||
|
||||
7. **Summary:**
|
||||
- Print results: "N passed, M failed out of T tests"
|
||||
- Exit 1 if any failures, exit 0 if all pass
|
||||
|
||||
**Key difference from kotlin test:** Instead of `java -jar "$JAR"`, use `sh "$DECODER"` to invoke the shell decoder. This ensures the decoder is tested under POSIX sh, not bash.
|
||||
|
||||
Make the script executable: `chmod +x shell/test_decoder.sh`
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/nick/Projects/Rust/encrypted_archive && test -f shell/test_decoder.sh && test -x shell/test_decoder.sh && bash -n shell/test_decoder.sh && echo "SYNTAX OK" && grep -q 'decode.sh' shell/test_decoder.sh && grep -q 'verify_file' shell/test_decoder.sh && echo "STRUCTURE OK"</automated>
|
||||
<manual>Run `bash shell/test_decoder.sh` and verify all 6 tests pass</manual>
|
||||
</verify>
|
||||
<done>shell/test_decoder.sh exists, is executable, passes bash -n, and contains all 6 test cases including Cyrillic filename test</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Run cross-validation tests and fix any decode.sh issues</name>
|
||||
<files>shell/decode.sh, shell/test_decoder.sh</files>
|
||||
<action>
|
||||
Run the cross-validation test script and fix any issues discovered:
|
||||
|
||||
```bash
|
||||
cd /home/nick/Projects/Rust/encrypted_archive
|
||||
bash shell/test_decoder.sh
|
||||
```
|
||||
|
||||
**Expected:** All 6 tests pass (PASS for each test case).
|
||||
|
||||
**If tests fail:**
|
||||
- Read the error output carefully
|
||||
- Common issues to look for:
|
||||
1. **Hex case mismatch:** HMAC or SHA-256 comparison fails because of uppercase vs lowercase hex. Fix: normalize with `tr 'A-F' 'a-f'`
|
||||
2. **dd offset errors:** Wrong offset calculation in TOC parsing. Fix: verify field order matches FORMAT.md Section 5 exactly
|
||||
3. **openssl pipe issues:** Decryption produces garbage. Fix: extract ciphertext to temp file first, then decrypt from file (not pipe)
|
||||
4. **Empty file handling:** gunzip fails on empty input. Fix: check original_size=0 before decompression
|
||||
5. **Cyrillic filename:** garbled characters. Fix: ensure LC_ALL=C and no text processing on filename bytes
|
||||
6. **HMAC scope error:** Wrong bytes fed to HMAC. Fix: HMAC = IV (from archive file, 16 bytes) || ciphertext (encrypted_size bytes)
|
||||
|
||||
Fix decode.sh until all tests pass. Do NOT modify the test script to make tests pass -- fix the decoder.
|
||||
|
||||
**After all tests pass**, run one more verification:
|
||||
```bash
|
||||
# Verify Rust round-trip still works
|
||||
cd /home/nick/Projects/Rust/encrypted_archive && cargo test --release 2>&1 | tail -5
|
||||
```
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/nick/Projects/Rust/encrypted_archive && bash shell/test_decoder.sh 2>&1 | tail -20 && echo "---" && cargo test --release 2>&1 | tail -3</automated>
|
||||
<manual>All 6 shell decoder tests pass, including Cyrillic filename. Rust tests still pass.</manual>
|
||||
</verify>
|
||||
<done>All 6 cross-validation tests pass (single file, multiple files, no-compress, empty file, large file, Cyrillic filename). Existing Rust tests still pass.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. `bash shell/test_decoder.sh` runs all 6 tests and reports "ALL TESTS PASSED"
|
||||
2. Test 6 specifically validates Cyrillic filename extraction (SHL-03)
|
||||
3. Test 3 validates no-compress mode with openssl raw decryption (SHL-02)
|
||||
4. All tests use Rust archiver to pack and shell decoder to unpack (SHL-01)
|
||||
5. `cargo test --release` still passes (no regressions)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- shell/test_decoder.sh exists and is executable
|
||||
- All 6 test cases pass: single file, multiple files, no-compress, empty file, large file, Cyrillic filename
|
||||
- Shell decoder produces byte-identical output verified by SHA-256 comparison
|
||||
- Existing Rust test suite still passes
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/05-shell-decoder/05-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user