#!/bin/sh # Checks the post-receive hooks under custom/hooks. The cache hook runs from a # copy pointed at a cache and a scan path in the trash directory, since the # shipped one names the system's own, and the hooks run inside bare # repositories the way git runs them after a push. test_description='Check the shipped post-receive hooks' CGIT_TEST_NO_CREATE_REPOS=YesPlease . ./setup.sh HOOK_DIRECTORY="$TEST_OUTPUT_DIRECTORY/../custom/hooks" # The request each page slot in a directory answers, read off its head the # way the hook reads it, leaving out the locks and the cached repository # scan. cached_requests() { test -d "$1" || return 1 for slot in "$1"/* do case $slot in *.lock | */rc-*) continue ;; esac dd if="$slot" bs=4096 count=1 2>/dev/null >slot-head && tr "\0" "\n" cachedrc && for page in / /a.git/ /a.git/log/ /b.git/ /b.git/log/ do CGIT_CONFIG="$PWD/cachedrc" PATH_INFO="$page" QUERY_STRING= cgit >/dev/null || return 1 done && cgit_rc cachedrc "url=a.git/refs/" >/dev/null && cgit_rc cachedrc "url=b.git/refs/" >/dev/null && echo writer >slots/0123abcd.lock && cp -R slots pristine && sort >expect-keys <<-\EOF && 7|http://0|1|/0| 7|http://0|7|/a.git/0| 7|http://0|11|/a.git/log/0| 7|http://0|7|/b.git/0| 7|http://0|11|/b.git/log/0| 7|http://0|0|15|url=a.git/refs/ 7|http://0|0|15|url=b.git/refs/ EOF cached_requests pristine >keys && sort keys >sorted-keys && test_cmp expect-keys sorted-keys && ls pristine >pristine-slots && grep "^rc-" pristine-slots && sed -e "s|^cache_root=.*|cache_root='\''$PWD/slots'\''|" \ -e "s|^scan_path=.*|scan_path='\''$PWD/scan'\''|" \ "$HOOK_DIRECTORY/post-receive.cgit-cache" >cache-hook && grep -Fx "cache_root='\''$PWD/slots'\''" cache-hook && grep -Fx "scan_path='\''$PWD/scan'\''" cache-hook ' # The hooks are POSIX sh, so every case runs under each such shell that is # here. Whatever a hook prints reaches the pusher, so each has to stay # silent. shells= for shell in sh dash ksh bash do command -v $shell >/dev/null && shells="$shells $shell" done for shell in $shells do test_expect_success "a push drops its own pages and the index under $shell" ' fresh_slots && (cd scan/a.git && $shell ../../cache-hook 2>../../err) && test_must_be_empty err && cached_requests slots >left && test_grep "|/b.git/log/" left && test_grep "url=b.git/refs/" left && test_grep ! "a.git" left && test_grep ! "1|/0|" left && test_path_is_file slots/0123abcd.lock && ls slots >left-slots && test_grep ! "^rc-" left-slots ' test_expect_success "a repository named in cgitrc gives the hook its url under $shell" ' fresh_slots && git -C scan/b.git config hooks.cgiturl b.git && sed "s|^scan_path=.*|scan_path=/nonexistent|" cache-hook >named-hook && grep -Fx "scan_path=/nonexistent" named-hook && (cd scan/b.git && $shell ../../named-hook 2>../../err) && test_must_be_empty err && cached_requests slots >left && test_grep "|/a.git/log/" left && test_grep ! "b.git" left ' test_expect_success "with no url to go on the whole cache goes under $shell" ' fresh_slots && (cd scan/a.git && $shell ../../named-hook 2>../../err) && test_must_be_empty err && test "$(ls slots)" = 0123abcd.lock ' test_expect_success SANITY "the cache hook shows a pusher no error under $shell" ' fresh_slots && test_when_finished "chmod 755 slots" && chmod 555 slots && (cd scan/a.git && $shell ../../cache-hook 2>../../err) && test_must_be_empty err && ls slots >left && test_cmp pristine-slots left ' done # The newest branch tip by committer date is main. The other branch has the # newer author date, a tag outside refs/heads points at a newer commit # still, and an annotated tag was made later than all of them. test_expect_success 'set up a repository whose dates disagree' ' test_create_repo work && ( cd work && echo one >file && git add file && GIT_AUTHOR_DATE="2001-01-01 00:00:00 +0000" \ GIT_COMMITTER_DATE="2021-02-03 04:05:06 +0000" git commit -q -m newest && git branch -M main && git checkout -q -b old && echo two >file && GIT_AUTHOR_DATE="2029-01-01 00:00:00 +0000" \ GIT_COMMITTER_DATE="2019-01-01 00:00:00 +0000" git commit -q -a -m older && echo three >file && GIT_COMMITTER_DATE="2025-01-01 00:00:00 +0000" git commit -q -a -m loose && git tag loose && git reset -q --hard HEAD^ && GIT_COMMITTER_DATE="2027-01-01 00:00:00 +0000" git tag -a -m release release main ) && git init -q --bare plain.git && git -C work push -q ../plain.git main old loose release && echo "2021-02-03 04:05:06 +0000" >expect && echo last-modified >expect-entries && echo kept >kept ' for shell in $shells do test_expect_success "the age hook writes the newest branch commit date under $shell" ' rm -f plain.git/info/web/last-modified && (cd plain.git && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && test_cmp expect plain.git/info/web/last-modified && ls plain.git/info/web >entries && test_cmp expect-entries entries ' test_expect_success SANITY "the age hook shows a pusher no error under $shell" ' cp kept plain.git/info/web/last-modified && test_when_finished "chmod 755 plain.git/info/web" && chmod 555 plain.git/info/web && (cd plain.git && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && test_cmp kept plain.git/info/web/last-modified && ls plain.git/info/web >entries && test_cmp expect-entries entries ' test_expect_success "the age hook leaves a repository with no branches as it was under $shell" ' git init -q --bare tags-$shell.git && git -C work push -q ../tags-$shell.git release && mkdir -p tags-$shell.git/info/web && echo kept >tags-$shell.git/info/web/last-modified && (cd tags-$shell.git && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && test_cmp kept tags-$shell.git/info/web/last-modified ' test_expect_success SANITY "the age hook shows no error when it cannot make its directory under $shell" ' git init -q --bare closed-$shell.git && git -C work push -q ../closed-$shell.git main && test_when_finished "chmod 755 closed-$shell.git/info" && chmod 555 closed-$shell.git/info && (cd closed-$shell.git && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && test_path_is_missing closed-$shell.git/info/web ' # git keeps a shared repository group writable whatever the pusher's # umask, and the next member to push has to be able to replace the file. test_expect_success SANITY "the age hook keeps a shared directory group writable under $shell" ' git init -q --bare --shared=group shared-$shell.git && git -C work push -q ../shared-$shell.git main && (cd shared-$shell.git && umask 022 && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && ls -ld shared-$shell.git/info/web >mode && test_grep "^drwxrw[xs]" mode ' # The web server reads what the hooks write, so the pusher's own umask # must not keep it out. test_expect_success "the age hook writes a file anyone can read under a tight umask under $shell" ' git init -q --bare private-$shell.git && git -C work push -q ../private-$shell.git main && (cd private-$shell.git && umask 077 && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && ls -ld private-$shell.git/info/web private-$shell.git/info/web/last-modified >mode && test_grep "^drwxr-xr-x" mode && test_grep "^-rw-r--r--" mode ' test_expect_success "the age hook reads core.sharedRepository as git does under $shell" ' git -C private-$shell.git config core.sharedRepository FALSE && rm private-$shell.git/info/web/last-modified && (cd private-$shell.git && umask 077 && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && ls -l private-$shell.git/info/web/last-modified >mode && test_grep "^-rw-r--r--" mode && git -C private-$shell.git config core.sharedRepository 0660 && rm private-$shell.git/info/web/last-modified && (cd private-$shell.git && umask 077 && $shell "$HOOK_DIRECTORY/post-receive.cgit-age" 2>../err) && test_must_be_empty err && ls -l private-$shell.git/info/web/last-modified >mode && test_grep "^-rw-rw-r--" mode ' test_expect_success "the commit-graph hook writes a graph with path filters under $shell" ' git init -q --bare graph-$shell.git && git -C work push -q ../graph-$shell.git main && (cd graph-$shell.git && $shell "$HOOK_DIRECTORY/post-receive.commit-graph" 2>../err) && test_must_be_empty err && test_path_is_file graph-$shell.git/objects/info/commit-graphs/commit-graph-chain && grep -q BDAT graph-$shell.git/objects/info/commit-graphs/*.graph && git -C graph-$shell.git commit-graph verify ' test_expect_success "the commit-graph hook writes a graph anyone can read under a tight umask under $shell" ' git init -q --bare private-graph-$shell.git && git -C work push -q ../private-graph-$shell.git main && (cd private-graph-$shell.git && umask 077 && $shell "$HOOK_DIRECTORY/post-receive.commit-graph" 2>../err) && test_must_be_empty err && ls -l private-graph-$shell.git/objects/info/commit-graphs >modes && test_grep "commit-graph-chain" modes && test_grep "\.graph" modes && test_grep ! "^-r-------" modes ' test_expect_success "a later push moves the graph on under $shell" ' cat graph-$shell.git/objects/info/commit-graphs/commit-graph-chain >chain-$shell && test_commit -C work graph-$shell && git -C work push -q ../graph-$shell.git HEAD:main && (cd graph-$shell.git && $shell "$HOOK_DIRECTORY/post-receive.commit-graph" 2>../err) && test_must_be_empty err && ! test_cmp chain-$shell graph-$shell.git/objects/info/commit-graphs/commit-graph-chain && git -C graph-$shell.git commit-graph verify ' done test_done