@mkdir -p $(COV_INSTALL)
@export COV_DIR=$(COV_INSTALL); \
for test_script in tests/installer-test*.sh; do \
- kcov --bash-dont-parse-binary-dir \
- --include-pattern=install.sh \
- --exclude-path=$(PWD)/.git,$(PWD)/tests \
- $(COV_INSTALL) \
- "$$test_script" 2>&1 | tee -a .tmp/kcov.log; \
+ if [ "$$test_script" = "tests/installer-test-logic.sh" ]; then \
+ kcov --bash-dont-parse-binary-dir \
+ --include-pattern=install.sh \
+ --exclude-path=$(PWD)/.git,$(PWD)/tests \
+ $(COV_INSTALL) \
+ "$$test_script" 2>&1 | tee -a .tmp/kcov.log; \
+ else \
+ bash "$$test_script" 2>&1 | tee -a .tmp/kcov.log; \
+ fi; \
done; \
if grep -q 'kcov: error:' .tmp/kcov.log; then \
echo "FAIL: kcov errors detected (see above)"; exit 1; \
version Show version information
check [URL] Check if URL is a gcrypt repository
clean [URL|REMOTE] Scan/Clean unencrypted files from remote
- clean -f, --force Actually delete files (default is scan only)
- clean -i, --init Scan even if no manifest found (DANGEROUS with --force)
+ clean --force Actually delete files (default is scan only)
+ clean --init Allow cleaning valid files (requires --force)
+ clean --hard Override safety checks (requires --force)
stat [URL|REMOTE] Show diagnostics (file counts, tracked vs untracked)
Git Protocol Commands (for debugging):
capabilities List remote helper capabilities
# 2. Handle subcommands
case "${COMP_WORDS[1]}" in
- clean)
- local remotes=$( git remote -v 2>/dev/null | grep 'gcrypt::' | awk '{print $1}' | sort -u || : )
- COMPREPLY=( $( compgen -W "-f --force -i --init $remotes" -- "$cur" ) )
- return 0
- ;;
- check|stat)
- local remotes=$( git remote 2>/dev/null || : )
- COMPREPLY=( $( compgen -W "$remotes" -- "$cur" ) )
- return 0
- ;;
- capabilities|fetch|list|push)
- COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
- return 0
- ;;
+ clean)
+ local remotes=$(git remote -v 2>/dev/null | grep 'gcrypt::' | awk '{print $1}' | sort -u || :)
+ COMPREPLY=($(compgen -W "--force Actually --init Allow --hard Override $remotes" -- "$cur"))
+ return 0
+ ;;
+ check | stat)
+ local remotes=$(git remote 2>/dev/null || :)
+ COMPREPLY=($(compgen -W "$remotes" -- "$cur"))
+ return 0
+ ;;
+ capabilities | fetch | list | push)
+ COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
+ return 0
+ ;;
esac
# 3. Fallback (global flags if not in a known subcommand?)
complete -c git-remote-gcrypt -n "__fish_seen_subcommand_from stat" -a "(git remote 2>/dev/null)" -d 'Git Remote'
# Clean flags
-complete -c git-remote-gcrypt -f -n "__fish_seen_subcommand_from clean" -s f -l force -d 'Flag';
-complete -c git-remote-gcrypt -f -n "__fish_seen_subcommand_from clean" -s i -l init -d 'Flag';
+complete -c git-remote-gcrypt -f -n "__fish_seen_subcommand_from clean" -s -force -l Actually -d 'Flag';
+complete -c git-remote-gcrypt -f -n "__fish_seen_subcommand_from clean" -s -init -l Allow -d 'Flag';
+complete -c git-remote-gcrypt -f -n "__fish_seen_subcommand_from clean" -s -hard -l Override -d 'Flag';
# We'll read the template line by line? No, sed is standard.
# We use a temp file for the replacement string to avoid sed escaping hell for large blocks?
# Or just keep it simple.
-sed "s/{commands}/$COMMANDS_LIST/" "$ZSH_TMPL" \
- | sed "s|{clean_flags_zsh}|$CLEAN_FLAGS_ZSH|" >"$ZSH_OUT"
+sed "s/{commands}/$COMMANDS_LIST/" "$ZSH_TMPL" |
+ sed "s|{clean_flags_zsh}|$CLEAN_FLAGS_ZSH|" >"$ZSH_OUT"
# 6. Generate Fish
echo "Generating Fish completions..."
# Fish needs {not_sc_list} which matches {commands} (space separated)
-sed "s/{not_sc_list}/$COMMANDS_LIST/g" "$FISH_TMPL" \
- |
+sed "s/{not_sc_list}/$COMMANDS_LIST/g" "$FISH_TMPL" |
# Multi-line replacement in sed is hard. Use awk?
# Or just injecting the string with escaped newlines.
sed "s|{clean_flags_fish}|$CLEAN_FLAGS_FISH|" >"$FISH_OUT"
# 2. Handle subcommands
case "${COMP_WORDS[1]}" in
- clean)
- local remotes=$( git remote -v 2>/dev/null | grep 'gcrypt::' | awk '{print $1}' | sort -u || : )
- COMPREPLY=( $( compgen -W "{clean_flags_bash} $remotes" -- "$cur" ) )
- return 0
- ;;
- check|stat)
- local remotes=$( git remote 2>/dev/null || : )
- COMPREPLY=( $( compgen -W "$remotes" -- "$cur" ) )
- return 0
- ;;
- capabilities|fetch|list|push)
- COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
- return 0
- ;;
+ clean)
+ local remotes=$(git remote -v 2>/dev/null | grep 'gcrypt::' | awk '{print $1}' | sort -u || :)
+ COMPREPLY=($(compgen -W "{clean_flags_bash} $remotes" -- "$cur"))
+ return 0
+ ;;
+ check | stat)
+ local remotes=$(git remote 2>/dev/null || :)
+ COMPREPLY=($(compgen -W "$remotes" -- "$cur"))
+ return 0
+ ;;
+ capabilities | fetch | list | push)
+ COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
+ return 0
+ ;;
esac
# 3. Fallback (global flags if not in a known subcommand?)
_arguments {clean_flags_zsh} \
'*:gcrypt URL: _alternative "remotes:gcrypt remote:($(git remote -v 2>/dev/null | grep "gcrypt::" | awk "{print \$1}" | sort -u))" "files:file:_files"'
;;
- check|stat)
+ check | stat)
_arguments \
'*:gcrypt URL: _alternative "remotes:git remote:($(git remote 2>/dev/null))" "files:file:_files"'
;;
case $line[1] in
clean)
- _arguments '(-f --force -i --init)'{-f,--force,-i,--init}'[flag]' \
+ _arguments '(--force Actually --init Allow --hard Override)'{--force,Actually,--init,Allow,--hard,Override}'[flag]' \
'*:gcrypt URL: _alternative "remotes:gcrypt remote:($(git remote -v 2>/dev/null | grep "gcrypt::" | awk "{print \$1}" | sort -u))" "files:file:_files"'
;;
- check|stat)
+ check | stat)
_arguments \
'*:gcrypt URL: _alternative "remotes:git remote:($(git remote 2>/dev/null))" "files:file:_files"'
;;
version Show version information
check [URL] Check if URL is a gcrypt repository
clean [URL|REMOTE] Scan/Clean unencrypted files from remote
- clean -f, --force Actually delete files (default is scan only)
- clean -i, --init Scan even if no manifest found (DANGEROUS with --force)
+ clean --force Actually delete files (default is scan only)
+ clean --init Allow cleaning valid files (requires --force)
+ clean --hard Override safety checks (requires --force)
stat [URL|REMOTE] Show diagnostics (file counts, tracked vs untracked)
Git Protocol Commands (for debugging):
capabilities List remote helper capabilities
shift
while [ $# -gt 0 ]; do
case "$1" in
- --force|-f) FORCE_CLEAN=yes ;;
- --init|-i) FORCE_INIT=yes ;;
+ --force) FORCE_CLEAN=yes ;;
+ --hard) HARD_FORCE=yes ;;
+ --init) FORCE_INIT=yes ;;
-*) echo "Unknown option: $1" >&2; exit 1 ;;
*)
if [ -z "$URL" ]; then
esac
shift
done
+ if [ -n "$HARD_FORCE" ] && [ -z "$FORCE_CLEAN" ]; then
+ echo "Error: --hard requires --force" >&2
+ exit 1
+ fi
+ if [ "${FORCE_INIT:-}" = "yes" ] && [ -z "$FORCE_CLEAN" ]; then
+ echo "Error: --init requires --force" >&2
+ echo "(To scan a repository, use 'clean' without arguments)" >&2
+ exit 1
+ fi
break # Stop parsing outer loop
;;
stat)
(
export GIT_INDEX_FILE="$temp_index"
git read-tree "$Gref"
- git rm --cached --ignore-unmatch -q "$2"
+ if [ -n "$HARD_FORCE" ]; then
+ git rm --cached --ignore-unmatch -q -f "$2"
+ else
+ if ! git rm --cached --ignore-unmatch -q "$2"; then
+ echo_info "Error: Failed to remove '$2' because it has local modifications."
+ echo_info "Manual removal command: git rm --cached -f '$2'"
+
+ suggest_args="--force --hard"
+ # If we are in init mode (FORCE_INIT set), the user MUST pass --init again
+ if [ "${FORCE_INIT:-}" = "yes" ]; then
+ suggest_args="--init $suggest_args"
+ fi
+
+ echo_info "To force remove via tool, run:"
+ echo_info " git-remote-gcrypt clean $suggest_args $URL"
+ exit 1
+ fi
+ fi
tree_id=$(git write-tree)
if [ "$tree_id" != "$(git rev-parse "$Gref^{tree}")" ]; then
commit_id=$(anon_commit "$tree_id") &&
fi
print_info "Injected garbage_file into remote $GREF"
+# 2.5 Inject a DOTFILE garbage file
+DOT_GARBAGE_BLOB=$(echo "HIDDEN GARBAGE" | $GIT hash-object -w --stdin)
+export GIT_INDEX_FILE=index.dotgarbage
+$GIT read-tree "$NEW_TREE"
+$GIT update-index --add --cacheinfo 100644 "$DOT_GARBAGE_BLOB" ".garbage_file"
+NEW_TREE_DOT=$($GIT write-tree)
+rm index.dotgarbage
+NEW_COMMIT_DOT=$(echo "Inject dot garbage" | $GIT commit-tree "$NEW_TREE_DOT" -p "$NEW_COMMIT")
+$GIT update-ref "$GREF" "$NEW_COMMIT_DOT"
+
+if ! $GIT ls-tree -r "$GREF" | grep -q "\.garbage_file"; then
+ print_err "Failed to inject .garbage_file into $GREF"
+ exit 1
+fi
+print_info "Injected .garbage_file into remote $GREF"
+
# 3. Scan (expect to find garbage_file)
set -x
output=$("$SCRIPT_DIR/git-remote-gcrypt" clean "gcrypt::$tempdir/valid.git" 2>&1)
set +x
assert_grep "garbage_file" "$output" "clean identified unencrypted file in valid repo"
+assert_grep "\.garbage_file" "$output" "clean identified unencrypted DOTFILE in valid repo"
assert_grep "NOTE: This is a scan" "$output" "clean scan-only mode confirmed"
# 4. Clean Force