diff --git a/.mise/tasks/deobfuscate b/.mise/tasks/deobfuscate index 63e5d75..84baa14 100755 --- a/.mise/tasks/deobfuscate +++ b/.mise/tasks/deobfuscate @@ -28,7 +28,13 @@ if [ -n "${usage_files:-}" ]; then arg="${arg#"${notes_dir}/"}" # Skip empty variadic defaults after xargs unquotes "''". [ -z "$arg" ] && continue - arg=$(basename "$arg") + # Match basename's handling of trailing slashes without spawning it. + while [ "${arg%/}" != "$arg" ]; do + trimmed="${arg%/}" + [ -n "$trimmed" ] || break + arg="$trimmed" + done + [ "$arg" = "/" ] || arg="${arg##*/}" ARGS+=("$arg") done < <(printf '%s' "${usage_files}" | xargs printf '%s\n') fi diff --git a/README.md b/README.md index 8fb26a2..d6f42ee 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ **Collective memory, encrypted.** -[![tests: 420](https://img.shields.io/badge/tests-420-brightgreen?style=flat)](test/) +[![tests: 424](https://img.shields.io/badge/tests-424-brightgreen?style=flat)](test/) ![lints: 8](https://img.shields.io/badge/lints-8-blue?style=flat) [![license: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat)](LICENSE) diff --git a/lib/obfuscate.sh b/lib/obfuscate.sh index 1bc3eb5..548262c 100644 --- a/lib/obfuscate.sh +++ b/lib/obfuscate.sh @@ -433,7 +433,8 @@ _rename_one_to_readable() { fi local target_dir - target_dir=$(dirname "$notes_dir/$relpath") + target_dir="$notes_dir/$relpath" + target_dir="${target_dir%/*}" [ ! -d "$target_dir" ] && mkdir -p "$target_dir" if [ -e "$notes_dir/$relpath" ] && ! cmp -s "$notes_dir/$id" "$notes_dir/$relpath"; then diff --git a/test/deobfuscate.bats b/test/deobfuscate.bats index ade4016..a144ca3 100644 --- a/test/deobfuscate.bats +++ b/test/deobfuscate.bats @@ -208,6 +208,69 @@ SH } +@test "scoped deobfuscate derives an ID without calling basename" { + notes obfuscate + + local alpha_id mock_bin real_basename blocked_log + alpha_id=$(grep 'alpha.md' "$NOTES_CALLER_PWD/notes/.manifest" | cut -f1) + mock_bin="$BATS_TEST_TMPDIR/basename-guard-bin" + blocked_log="$BATS_TEST_TMPDIR/basename-blocked" + real_basename=$(command -v basename) + mkdir -p "$mock_bin" + cat > "$mock_bin/basename" <<'BASH' +#!/usr/bin/env bash +if [ "$#" -eq 1 ] && [ "$1" = "$BLOCKED_BASENAME_ARG" ]; then + printf '%s\n' "$1" > "$BLOCKED_COMMAND_LOG" + exit 97 +fi +exec "$REAL_BASENAME" "$@" +BASH + chmod +x "$mock_bin/basename" + + PATH="$mock_bin:$PATH" \ + BLOCKED_BASENAME_ARG="$alpha_id" \ + BLOCKED_COMMAND_LOG="$blocked_log" \ + REAL_BASENAME="$real_basename" \ + run notes deobfuscate "notes/$alpha_id" + + [ "$status" -eq 0 ] + [ -f "$NOTES_CALLER_PWD/notes/alpha.md" ] + [ ! -e "$blocked_log" ] +} + + +@test "scoped deobfuscate keeps a trailing-slash path scoped" { + notes obfuscate + + local alpha_id beta_id + alpha_id=$(grep 'alpha.md' "$NOTES_CALLER_PWD/notes/.manifest" | cut -f1) + beta_id=$(grep 'beta.md' "$NOTES_CALLER_PWD/notes/.manifest" | cut -f1) + + notes deobfuscate "notes/$alpha_id/" + + [ -f "$NOTES_CALLER_PWD/notes/alpha.md" ] + [ -f "$NOTES_CALLER_PWD/notes/$beta_id" ] + [ ! -f "$NOTES_CALLER_PWD/notes/beta.md" ] +} + + +@test "scoped deobfuscate keeps a slash-only path scoped" { + notes obfuscate + + local alpha_id beta_id + alpha_id=$(grep 'alpha.md' "$NOTES_CALLER_PWD/notes/.manifest" | cut -f1) + beta_id=$(grep 'beta.md' "$NOTES_CALLER_PWD/notes/.manifest" | cut -f1) + + run notes deobfuscate "////" + + [ "$status" -eq 0 ] + [ -f "$NOTES_CALLER_PWD/notes/$alpha_id" ] + [ -f "$NOTES_CALLER_PWD/notes/$beta_id" ] + [ ! -f "$NOTES_CALLER_PWD/notes/alpha.md" ] + [ ! -f "$NOTES_CALLER_PWD/notes/beta.md" ] +} + + @test "deobfuscate with args warns on unknown ID" { notes obfuscate diff --git a/test/rename.bats b/test/rename.bats index 6f91606..afba51d 100644 --- a/test/rename.bats +++ b/test/rename.bats @@ -226,6 +226,30 @@ setup() { [ -f "$NOTES_CALLER_PWD/notes/sub/deep.md" ] } +@test "rename_to_readable derives nested target directories without dirname" { + mkdir -p "$NOTES_CALLER_PWD/notes/sub" + echo "# Deep" > "$NOTES_CALLER_PWD/notes/sub/deep.md" + rename_to_obfuscated "$NOTES_CALLER_PWD/notes" > /dev/null + + local mock_bin blocked_log + mock_bin="$BATS_TEST_TMPDIR/dirname-guard-bin" + blocked_log="$BATS_TEST_TMPDIR/dirname-blocked" + mkdir -p "$mock_bin" + cat > "$mock_bin/dirname" <<'BASH' +#!/usr/bin/env bash +printf '%s\n' "$*" > "$BLOCKED_COMMAND_LOG" +exit 97 +BASH + chmod +x "$mock_bin/dirname" + + PATH="$mock_bin:$PATH" BLOCKED_COMMAND_LOG="$blocked_log" \ + run rename_to_readable "$NOTES_CALLER_PWD/notes" + + [ "$status" -eq 0 ] + [ -f "$NOTES_CALLER_PWD/notes/sub/deep.md" ] + [ ! -e "$blocked_log" ] +} + @test "rename_to_readable preserves manifest" { rename_to_obfuscated "$NOTES_CALLER_PWD/notes" > /dev/null local manifest_before