#!/bin/sh # The snapshot page hands a branch back as an archive. One function below # registers the same checks for every compressed tar format, and each format # needs the same compressor cgit pipes through on the server, so one missing # tool skips that format on both grounds at once. Plain tar and zip get checks # of their own, since cgit runs no compressor for either and unzip shares no # flags with the rest. test_description='Verify snapshot' . ./setup.sh check_snapshot_headers() { head -n 1 tmp | grep "Status: 200 OK" && head -n 2 tmp | grep "^Content-Type: $2$" && head -n 3 tmp | grep "Content-Disposition: inline; filename=.master.$1." } check_snapshot_content() { ls master/ >output && test_line_count = 5 output && grep "^5$" master/file-5 && test_line_count = 1 master/file-5 } # Registers the checks for one compressed tar format. test_tar_snapshot() { ext=$1 type=$2 tool=$3 prereq=$4 test_lazy_prereq $prereq "command -v $tool" test_expect_success $prereq "get foo/snapshot/master.$ext" " cgit_url 'foo/snapshot/master.$ext' >tmp " test_expect_success $prereq "check $ext response headers" " check_snapshot_headers $ext $type " test_expect_success $prereq "verify $ext format" " strip_headers master.$ext && '$tool' -t 'master.$ext' " test_expect_success $prereq "untar $ext and verify the content" " rm -rf master && '$tool' -dc 'master.$ext' | tar -xf - && check_snapshot_content " } # The uncompressed tar comes straight out of git's archive writer, so tar # itself both proves the format and unpacks it. test_expect_success 'get foo/snapshot/master.tar' ' cgit_url "foo/snapshot/master.tar" >tmp ' test_expect_success 'check tar response headers' ' check_snapshot_headers tar application/x-tar ' test_expect_success 'untar and verify the content' ' strip_headers master.tar && rm -rf master && tar -xf master.tar && check_snapshot_content ' test_tar_snapshot tar.gz application/gzip gzip GZIP test_tar_snapshot tar.bz2 application/x-bzip2 bzip2 BZIP2 test_tar_snapshot tar.lz application/x-lzip lzip LZIP test_tar_snapshot tar.xz application/x-xz xz XZ test_tar_snapshot tar.zst application/zstd zstd ZSTD test_expect_success 'get foo/snapshot/master.zip' ' cgit_url "foo/snapshot/master.zip" >tmp ' test_expect_success 'check zip response headers' ' check_snapshot_headers zip application/zip ' test_expect_success 'strip off the header lines' ' strip_headers master.zip ' test_expect_success UNZIP 'verify zip format' ' "$GIT_UNZIP" -t master.zip ' test_expect_success UNZIP 'unzip and verify the content' ' rm -rf master && "$GIT_UNZIP" master.zip && check_snapshot_content ' # A tag named v1.0 sheds its v in the snapshot name unless dropping it would # merge two tags. The first tag below stays a loose ref on purpose, because on # a case-insensitive filesystem a ref lookup for V1.0 finds the loose v1.0 # file, and deciding by lookups called every fresh tag ambiguous and kept its # v until git happened to pack the refs. test_expect_success 'set up a repo with a versioned tag' ' mkrepo repos/vtags 2 && git -C repos/vtags update-ref refs/tags/v1.0 HEAD && cgitrc_repo vtagsrc vtags snapshots=tar.gz ' test_expect_success 'a loose v tag still sheds its v in the snapshot name' ' cgit_rc vtagsrc "url=vtags/refs/" >tmp && grep "vtags-1.0.tar.gz" tmp && ! grep "vtags-v1.0.tar.gz" tmp ' # The second tag goes in only after the first is packed, since two loose files # differing in case alone cannot coexist on a case-insensitive filesystem. test_expect_success 'a real case collision keeps the v on both tags' ' git -C repos/vtags pack-refs --all && git -C repos/vtags update-ref refs/tags/V1.0 HEAD~1 && cgit_rc vtagsrc "url=vtags/refs/" >tmp && grep "vtags-v1.0.tar.gz" tmp && grep "vtags-V1.0.tar.gz" tmp && ! grep "vtags-1.0.tar.gz" tmp ' # A name that is all suffix names no revision, and an empty snapshot-prefix # gives the members no leading directory rather than a leading slash. test_expect_success 'a snapshot name with nothing before its suffix is refused' ' git -C repos/vtags branch v HEAD && sed "s/^snapshots=tar.gz$/snapshots=tar/" vtagsrc >vtagstarrc && cgit_rc vtagstarrc "url=vtags/snapshot/.tar" >tmp && grep "^Status: 404" tmp ' test_expect_success 'an empty snapshot-prefix puts no slash ahead of the members' ' { cat vtagstarrc && echo "repo.snapshot-prefix=" } >noprefixrc && cgit_rc noprefixrc "url=vtags/snapshot/vtags.tar&id=master" >tmp && strip_headers noprefix.tar && tar -tf noprefix.tar >members && grep "^file-1$" members && ! grep "^/" members ' # A snapshot is named after the last component of the url once its .git # suffix is gone, so a url of .git alone leaves the ref as the whole name. test_expect_success 'set up repositories whose urls end in .git' ' mkrepo repos/dotgit 1 && git -C repos/dotgit tag v1.0 && { echo "virtual-root=/" && echo "cache-size=0" && echo "snapshots=tar" && echo "repo.url=.git" && echo "repo.path=$PWD/repos/dotgit/.git" && echo "repo.url=sub/.git" && echo "repo.path=$PWD/repos/dotgit/.git" } >dotgitrc ' test_expect_success 'a url of .git names a snapshot after the ref alone' ' cgit_rc dotgitrc "url=.git/refs/" >tmp && grep ">v1.0.tar<" tmp && cgit_rc dotgitrc "url=.git/snapshot/v1.0.tar" >tmp && strip_headers dotgit.tar && tar -tf dotgit.tar >members && grep "^v1.0/file-1$" members ' test_expect_success 'a url ending in /.git names a snapshot after its directory' ' cgit_rc dotgitrc "url=sub/.git/refs/" >tmp && grep ">sub-1.0.tar<" tmp ' # A server may run cgit with no PATH at all, and the compressor is then looked # for on the default path execvp searches. test_expect_success GZIP 'a compressed snapshot is made without a PATH' ' cgitrc_copy nopathrc && cgit_bin=$(command -v cgit) && ( unset PATH && CGIT_CONFIG="$PWD/nopathrc" QUERY_STRING="url=foo/snapshot/master.tar.gz" "$cgit_bin" >tmp ) && grep "^Status: 200" tmp && strip_headers nopath.tar.gz && gzip -t nopath.tar.gz ' # A link offers the snapshot of a tag, and the name on it has to lead back to # that tag even when a branch is spelled like the tag's stem. test_expect_success GZIP 'a snapshot name leads to the tag ahead of a branch' ' git -C repos/vtags update-ref refs/heads/1.0 $(git -C repos/vtags commit-tree -m shadow HEAD^{tree}) && cgit_rc vtagsrc "url=vtags/snapshot/vtags-1.0.tar.gz" >tmp && strip_headers tag.tar.gz && test "$(gzip -dc tag.tar.gz | git -C repos/vtags get-tar-commit-id)" = "$(git -C repos/vtags rev-parse refs/tags/v1.0^{commit})" ' # A signature is a note a pusher stored, held to max-blob-size like any blob. test_expect_success 'a signature past max-blob-size is refused' ' big=$(test_seq 1 2000 | git -C repos/vtags hash-object -w --stdin) && git -C repos/vtags notes --ref signatures/tar.gz add -C $big v1.0 && { echo "max-blob-size=1" && cat vtagsrc } >sigrc && cgit_rc sigrc "url=vtags/snapshot/vtags-1.0.tar.gz.asc" >tmp && grep "^Status: 413" tmp ' test_expect_success 'a snapshot and its signature are linked as one unit' ' test_create_repo repos/signed && ( cd repos/signed && echo one >file && git add file && git commit -m one && git tag one && sig=$(echo signature | git hash-object -w --stdin) && git notes --ref signatures/tar.gz add -C $sig one ) && cgitrc_repo signedrc signed snapshots=tar.gz && cgit_rc signedrc "url=signed/refs/" >tmp && grep "signed-one.tar.gz (sig)" tmp ' test_done