214 lines
8.4 KiB
Markdown
214 lines
8.4 KiB
Markdown
---
|
|
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>
|