From f5d017ab10a6ebc499e7259c39d2a4631e93a4ea Mon Sep 17 00:00:00 2001 From: wantaek Date: Thu, 9 Apr 2026 18:06:10 +0900 Subject: [PATCH 1/3] Use git common dir for internal state --- commands.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/commands.cpp b/commands.cpp index 6b3c498..6976522 100644 --- a/commands.cpp +++ b/commands.cpp @@ -239,16 +239,16 @@ static void validate_key_name_or_throw (const char* key_name) static std::string get_internal_state_path () { - // git rev-parse --git-dir + // git rev-parse --git-common-dir std::vector command; command.push_back("git"); command.push_back("rev-parse"); - command.push_back("--git-dir"); + command.push_back("--git-common-dir"); std::stringstream output; if (!successful_exit(exec_command(command, output))) { - throw Error("'git rev-parse --git-dir' failed - is this a Git repository?"); + throw Error("'git rev-parse --git-common-dir' failed - is this a Git repository?"); } std::string path; @@ -1705,4 +1705,3 @@ int status (int argc, const char** argv) return exit_status; } - From b1d247a3a32a6cb79f84075b5013091b6be692cb Mon Sep 17 00:00:00 2001 From: wantaek Date: Thu, 9 Apr 2026 18:06:21 +0900 Subject: [PATCH 2/3] Add worktree regression tests --- Makefile | 5 +- tests/worktree.sh | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100755 tests/worktree.sh diff --git a/Makefile b/Makefile index 1d2b1ef..35a9c8d 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,9 @@ build: $(BUILD_TARGETS) build-bin: git-crypt +test: build-bin + tests/worktree.sh ./git-crypt + git-crypt: $(OBJFILES) $(CXX) $(CXXFLAGS) -o $@ $(OBJFILES) $(LDFLAGS) @@ -90,6 +93,6 @@ install-man: build-man install -m 644 man/man1/git-crypt.1 $(DESTDIR)$(MANDIR)/man1/ .PHONY: all \ - build build-bin build-man \ + build build-bin build-man test \ clean clean-bin clean-man \ install install-bin install-man diff --git a/tests/worktree.sh b/tests/worktree.sh new file mode 100755 index 0000000..fdb91cb --- /dev/null +++ b/tests/worktree.sh @@ -0,0 +1,160 @@ +#!/bin/sh + +set -eu + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 GIT_CRYPT_BINARY" >&2 + exit 2 +fi + +GIT_CRYPT=$1 + +case "$GIT_CRYPT" in +/*) ;; +*) + GIT_CRYPT=$(cd "$(dirname "$GIT_CRYPT")" && pwd)/$(basename "$GIT_CRYPT") + ;; +esac + +if [ ! -x "$GIT_CRYPT" ]; then + echo "git-crypt binary is not executable: $GIT_CRYPT" >&2 + exit 1 +fi + +TMP_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/git-crypt-worktree-test.XXXXXX") +trap 'rm -rf "$TMP_ROOT"' EXIT INT TERM HUP + +fail () { + echo "not ok - $1" >&2 + exit 1 +} + +assert_file_equals () { + path=$1 + expected=$2 + + if [ ! -f "$path" ]; then + fail "missing file: $path" + fi + + actual=$(cat "$path") + if [ "$actual" != "$expected" ]; then + fail "unexpected contents in $path" + fi +} + +assert_clean_status () { + repo=$1 + status=$(git -C "$repo" status --short) + if [ -n "$status" ]; then + echo "$status" >&2 + fail "working tree is not clean: $repo" + fi +} + +init_repo () { + repo=$1 + + mkdir -p "$repo" + git -C "$repo" init >/dev/null + git -C "$repo" config user.name "Codex Test" + git -C "$repo" config user.email "codex@example.com" + git -C "$repo" config core.fsmonitor false + + ( + cd "$repo" + key_path=$(cd .. && pwd)/$(basename "$repo").key + "$GIT_CRYPT" init >/dev/null + printf 'secret.txt filter=git-crypt diff=git-crypt\n' > .gitattributes + printf 'topsecret\n' > secret.txt + git add .gitattributes secret.txt + git commit -m "init secret" >/dev/null + "$GIT_CRYPT" export-key "$key_path" >/dev/null + ) +} + +test_non_worktree_unlock () { + repo=$TMP_ROOT/non-worktree + + init_repo "$repo" + + ( + cd "$repo" + "$GIT_CRYPT" lock --force >/dev/null + "$GIT_CRYPT" unlock "$repo.key" >/dev/null + ) + + assert_file_equals "$repo/secret.txt" "topsecret" + assert_clean_status "$repo" +} + +test_worktree_checkout_uses_common_state () { + repo=$TMP_ROOT/worktree-main + wt=$TMP_ROOT/worktree-checkout + + init_repo "$repo" + git -C "$repo" worktree add "$wt" >/dev/null + git -C "$wt" config core.fsmonitor false + + assert_file_equals "$wt/secret.txt" "topsecret" + assert_clean_status "$wt" +} + +test_worktree_unlock_uses_common_state () { + repo=$TMP_ROOT/worktree-unlock-main + wt=$TMP_ROOT/worktree-unlock + + mkdir -p "$repo" + git -C "$repo" init >/dev/null + git -C "$repo" config user.name "Codex Test" + git -C "$repo" config user.email "codex@example.com" + git -C "$repo" config core.fsmonitor false + + ( + cd "$repo" + printf 'base\n' > README + git add README + git commit -m "base" >/dev/null + + key_path=$(cd .. && pwd)/$(basename "$repo").key + "$GIT_CRYPT" init >/dev/null + printf 'secret.txt filter=git-crypt diff=git-crypt\n' > .gitattributes + printf 'topsecret\n' > secret.txt + git add .gitattributes secret.txt + git commit -m "add secret" >/dev/null + encrypted_rev=$(git rev-parse HEAD) + printf '%s\n' "$encrypted_rev" > ../$(basename "$repo").rev + "$GIT_CRYPT" export-key "$key_path" >/dev/null + "$GIT_CRYPT" lock --force >/dev/null + ) + + git -C "$repo" worktree add --detach "$wt" HEAD~1 >/dev/null + git -C "$wt" config core.fsmonitor false + encrypted_rev=$(cat "$TMP_ROOT/$(basename "$repo").rev") + + ( + cd "$wt" + "$GIT_CRYPT" unlock "$repo.key" >/dev/null + git checkout "$encrypted_rev" >/dev/null + ) + + common_dir=$(git -C "$wt" rev-parse --git-common-dir) + git_dir=$(git -C "$wt" rev-parse --git-dir) + + if [ ! -f "$common_dir/git-crypt/keys/default" ]; then + fail "missing common-dir key state" + fi + + if [ -e "$git_dir/git-crypt/keys/default" ]; then + fail "unexpected worktree-local key state" + fi + + assert_file_equals "$wt/secret.txt" "topsecret" + assert_clean_status "$wt" +} + +test_non_worktree_unlock +test_worktree_checkout_uses_common_state +test_worktree_unlock_uses_common_state + +echo "ok - worktree regression tests passed" From 6392b63b90b7dd2f9d145e4c88ddddc09bee834e Mon Sep 17 00:00:00 2001 From: wantaek Date: Thu, 9 Apr 2026 18:06:48 +0900 Subject: [PATCH 3/3] Run test target in GitHub Actions --- .github/workflows/test.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4954ec9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,19 @@ +name: Test + +on: + push: + pull_request: + +jobs: + test: + name: Build And Test + runs-on: ubuntu-22.04 + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install dependencies + run: sudo apt update && sudo apt install -y libssl-dev + - name: Run tests + run: make test