From ea618c5e257a6aabded76e63567ec0e7b99ac6c4 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Mon, 24 Aug 2026 16:21:18 -1000 Subject: Renumber the test scripts into themed ranges t000x the ground the suite stands on: git version, html validity, the cache t01xx page content, one script per page t02xx features that cut across pages: filters, submodule links, dates, limits t03xx defence, the security regressions and the $HOME promise t04xx the helper tools under tools/ --- tests/t0204-limits.sh | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100755 tests/t0204-limits.sh (limited to 'tests/t0204-limits.sh') diff --git a/tests/t0204-limits.sh b/tests/t0204-limits.sh new file mode 100755 index 0000000..f09c290 --- /dev/null +++ b/tests/t0204-limits.sh @@ -0,0 +1,182 @@ +#!/bin/sh + +# Checks the ceilings a config can put on a page, that is the caps on refs +# listed, on the lines and the files a diff renders inline, and on the size +# of a blob any view will inflate, along with the clamp on how long an index +# query may be. Crossing one of these has to trim the page or point the +# reader at somewhere better suited, never drop the request, so each case +# watches what survives as closely as what is left out. The last case is the +# same idea applied to a filter, which degrades to escaped text rather than +# failing when its highlighting library is absent. + +test_description='Check the ref listing and diff size limits' +. ./setup.sh + +if [ $CGIT_HAS_LUA -eq 1 ]; then + test_set_prereq LUA +fi + +# The limits only show themselves against content that crosses them, so the +# fixture carries more branches and tags than max-ref-count allows and a +# commit whose oversized file diff sits beside a small one, which is what +# tells a per file limit apart from a whole page one. +test_expect_success 'set up limit fixtures' ' + mkrepo repos/limits 1 && + ( + cd repos/limits && + seq 1 60 >big.c && + printf "int x;\n" >small.c && + git add -A && + git commit -m sources && + seq 301 360 >big.c && + printf "int y;\n" >small.c && + git commit -am change && + for i in 1 2 3; do git branch branch-$i || exit 1; done && + for i in 1 2 3; do git tag tag-$i || exit 1; done + ) && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "max-ref-count=2" && + echo "max-diff-lines=20" && + echo "max-diff-files=0" && + echo "repo.url=limits" && + echo "repo.path=$PWD/repos/limits/.git" + } >limitrc && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "max-diff-files=1" && + echo "repo.url=limits" && + echo "repo.path=$PWD/repos/limits/.git" + } >limitfilesrc +' + +limitq() { CGIT_CONFIG="$PWD/limitrc" QUERY_STRING="$1" cgit; } + +# An index query is compared against every repository the listing holds, so +# an enormous one multiplies out across the whole index. Clamping it rather +# than refusing it keeps the cost bounded without making an ordinary search +# behave any differently. +test_expect_success 'an enormous query is clamped, not rejected' ' + long=$(awk "BEGIN{s=\"\";for(i=0;i<4000;i++)s=s \"a\"; print s}") && + test ${#long} -eq 4000 && + cgit_query "q=$long" >tmp && + grep "" tmp && + longest=$(grep -o "aaaa*" tmp | awk "{print length}" | sort -n | tail -1) && + test "$longest" -eq 512 +' + +test_expect_success 'an ordinary query still filters the index' ' + cgit_query "q=foo" >tmp && + grep "foo" tmp && + ! grep ">bar<" tmp +' + +# The combined refs page caps branches and tags separately, and the pages it +# hands the overflow to page on their own, so a limit that leaked between the +# two sections would show up as the wrong link or the wrong count here. +test_expect_success 'refs page lists max-ref-count branches and tags' ' + limitq "url=limits/refs/" >tmp && + test $(grep -c "log/?h=" tmp) -eq 2 && + test $(grep -c "/tag/?h=tag-" tmp) -eq 2 +' + +test_expect_success 'refs page links each overflow to its own category' ' + grep "refs/heads" tmp && + grep "refs/tags" tmp +' + +test_expect_success 'branch page paginates independently' ' + limitq "url=limits/refs/heads/" >tmp && + test $(grep -c "log/?h=" tmp) -eq 2 && + grep "\[next\]" tmp && + limitq "url=limits/refs/heads/&ofs=2" >tmp && + grep "\[prev\]" tmp && + ! grep "/tag/?h=tag-" tmp +' + +test_expect_success 'tag page paginates independently' ' + limitq "url=limits/refs/tags/&ofs=2" >tmp && + grep "/tag/?h=tag-" tmp && + grep "\[prev\]" tmp && + ! grep "log/?h=" tmp +' + +# A file that busts max-diff-lines is replaced by a link to its own page, +# where the reader asked for that one file and the limit no longer applies. +# The rest of the commit still renders, so one huge file cannot hide the +# small change beside it. +test_expect_success 'oversized file diff is replaced by a link' ' + limitq "url=limits/commit/" >tmp && + grep "too large to be rendered inline" tmp && + grep "View it on its own page" tmp +' + +test_expect_success 'small file in the same commit still renders inline' ' + grep "class=.add.>+int y;" tmp +' + +test_expect_success 'the single-file diff page always renders in full' ' + limitq "url=limits/diff/big.c" >tmp && + grep "class=.hunk." tmp && + ! grep "too large to be rendered inline" tmp +' + +# max-diff-files counts the files in a commit rather than the lines in one, +# so it drops the whole body back to the diffstat while a request naming a +# single file stays unaffected. +test_expect_success 'a commit changing too many files shows stat only' ' + CGIT_CONFIG="$PWD/limitfilesrc" QUERY_STRING="url=limits/commit/" cgit >tmp && + grep "too large to be rendered inline" tmp && + ! grep "class=.hunk." tmp +' + +test_expect_success 'the single-file page is not limited by max-diff-files' ' + CGIT_CONFIG="$PWD/limitfilesrc" QUERY_STRING="url=limits/diff/small.c" cgit >tmp && + grep "class=.hunk." tmp +' + +# The diff views must not inflate a blob past max-blob-size merely to render +# it, which is the same defence the tree and plain views make and is easy to +# miss on this path. Such a file is reported as binary instead. +test_expect_success 'a diff of an oversized blob is not inlined' ' + mkrepo repos/blobdiff 1 && + ( + cd repos/blobdiff && + awk "BEGIN{for(i=0;i<400;i++)print \"aaaaaaaa\"}" >big.txt && + git add -A && + git commit -m add && + awk "BEGIN{for(i=0;i<401;i++)print \"aaaaaaaa\"}" >big.txt && + git commit -am change + ) && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "max-blob-size=1" && + echo "repo.url=blobdiff" && + echo "repo.path=$PWD/repos/blobdiff/.git" + } >blobdiffrc && + sha=$(git -C repos/blobdiff rev-parse HEAD) && + CGIT_CONFIG="$PWD/blobdiffrc" QUERY_STRING="url=blobdiff/commit/&id=$sha" cgit >tmp && + grep "Binary files differ" tmp && + ! grep "aaaaaaaa" tmp +' + +# A missing scintillua leaves the shipped filter with nothing to highlight +# with, and a filter that failed there would take the whole page down with +# it, so it has to hand the source back escaped instead. +test_expect_success LUA 'highlight filter passes text through without scintillua' ' + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "source-filter=lua:$(cd ../../custom/extensions && pwd)/syntax-highlight.lua" && + echo "repo.url=limits" && + echo "repo.path=$PWD/repos/limits/.git" + } >hlrc && + CGIT_SCINTILLUA_PATH=/nonexistent CGIT_CONFIG="$PWD/hlrc" \ + QUERY_STRING="url=limits/tree/small.c" cgit >tmp && + grep "int y;" tmp +' + +test_done -- cgit v2.8.0