AgeCommit message (Collapse)AuthorLines
Check the cache hook in a non-bare repositoryBryce Kwon-0/+29
scan-path finds such a repository by its .git and serves it at the work tree's path, so the hook has to strip the /.git it runs in. Only bare repositories were tried, and a hook that kept it passed.
Check the cache hook with remove_suffix setBryce Kwon-0/+37
Nothing ran the hook against a cache filled with remove-suffix=1, so a hook that kept the .git on the url, and so dropped none of the pages cgit had cached under the shorter one, passed.
Check that cgit reads what the age hook writesBryce Kwon-0/+6
The hook exists to feed the idle column, but nothing had cgit read an age file, so a hook writing a date cgit cannot parse, or one at a path cgit no longer reads, passed.
Say what the age hook does with a read-only fileBryce Kwon-3/+13
The header said a file the pusher cannot write stays as it was, but the hook replaces it through mv, which needs only the directory, and with stdin not a terminal mv does so without asking. That is the useful behaviour, so the header now says so, and a test holds the hook to it. Only a directory the pusher cannot write keeps the old file, which was the one case tested.
Check what the age hook leaves behindBryce Kwon-4/+19
A repository with no branches is meant to keep the date cgit already had, and the hook writes through a temporary file that must not be left beside the real one. Neither was checked.
Check the modes the hooks write underBryce Kwon-0/+38
No hook ran under a restrictive umask, so dropping the forced umask 022 passed, and the age file and the graph would then be unreadable to the web server. Git alone writes the graph as -r-------- under umask 077. core.sharedRepository was only tried as group, so the case folding and the numeric modes went unchecked.
Run every hook case under every shellBryce Kwon-84/+87
The cache hook's named url, no url and no access cases, the age hook's missing directory and shared group, and the first commit-graph write ran under sh alone, though the comment said every shell. The runs that did loop over the shells ignored what the hook printed, which reaches the pusher, so a hook that wrote to stderr or broke on a bashism under dash alone could pass.
Check the cache the hook tests start fromBryce Kwon-17/+51
The checks that pages went had nothing proving they were there to begin with, so they would pass with nothing removed if the scan list stopped being written or two keys shared a slot. Nor did anything check that the copy of the hook was pointed at the trash directory, and a renamed line would have left it wiping the system's cache wherever the test user can write it. cached_requests read the lock and the scan list as if they were pages and hid a failing dd. The test without access could not fail, since nothing can be removed there and the scan list alone names a.git, so it now compares the slots with the pristine copy.
Give the outsider account a hash of its ownBryce Kwon-5/+10
Every account shared one hash, so the binding of a session to its account's hash could not tell accounts apart, and an account_hash that handed back the wrong account's hash passed.
Check a failure flag that follows a question markBryce Kwon-0/+5
A failed login on a page with no query of its own comes back as ?login=failed, the common case, but only the &login=failed form was tried. A drop_failure_flag that handled the ampersand alone would have lost the message and piled flags onto the way back, and passed.
Check every failed login answers and logs alikeBryce Kwon-3/+27
Every post carried both fields, so the guards for a missing name or password never ran. An unknown name was checked for the cookie and the Location alone, so an extra header or body for it passed, and only the wrong password case had its log line checked for the name and against the password.
Check which library cgit logs as missingBryce Kwon-2/+6
The cgit-level check accepted any line starting "[cgit] ", the prefix of cgit's own messages too, as proof that the filter logged a missing module. The guarded copy also kept the system secret path, so on a host with luaossl and a readable secret but no luaposix the form would be signed and the test would fail.
Check each auth library missing on its ownBryce Kwon-5/+44
Only all four libraries missing at once was tried, and the script was not reloaded after they went, so a require at load would not have failed there. The protected visit passed on any error, a typo's nil call included. A login never ran without a library, so a fallback that skipped the mask, or one that let any password through when crypt was missing, passed.
Make the cookie timing check hold on fast coresBryce Kwon-5/+9
The quadratic trim takes 0.58 seconds for the 20,000 spaces the check used under LuaJIT on an M-series Mac, against a threshold of half a second over two calls, so a regression could pass on a slightly faster core. At 100,000 spaces it takes about fifteen seconds and the linear one under a millisecond, and each call is now timed on its own.
Sign the malformed cookies the checks refuseBryce Kwon-3/+3
The exponent and leading separator cases carried a made-up signature, which fails the check whatever the parsing does, so loosening the expiry pattern or dropping its start anchor passed. Both are now built from properly signed tokens.
Check how auth groups resolve to membersBryce Kwon-8/+16
auth-file.lua says group names match whatever their case, but both fixture files spelt devs alike, so dropping either lowercasing passed. No repository named two groups and no user sat in two, so reading only the first group of a list, or only the last line that matched, passed as well. A repository with no groups at all is a file variant matter, and for the inline one the check only repeated the empty one.
Check the age hook picks the right dateBryce Kwon-7/+24
The age fixture had one branch whose author and committer dates were the same, and its only tag was lightweight on that commit. Sorting oldest first, writing the author date or reading every ref rather than the branches all passed, and the expected date came from the same for-each-ref the hook runs. The dates now disagree on every one of those points and the hook's answer is held to a literal date, under every shell.
Accept only a local path as the way back inBryce Kwon-8/+22
is_safe_redirect looked at the first two characters alone, so it accepted https://evil.example/ and javascript:x. Neither could be signed today only because cgit always signs a url that starts with virtual-root, and nothing tested that. A target now has to start with a single slash, which needs virtual-root to be a path for logins to work, as it is by default.
Run the auth checks against the real librariesBryce Kwon-21/+115
The unit checks always took the harness stand-ins and the cgit-level checks needed a module to be missing, so the real luaossl and luaposix were never exercised anywhere. A misuse of their interfaces, or a login through cgit that never worked, passed every run. Where an interpreter has both libraries and its crypt(3) checks a SHA-512 hash from openssl passwd, the unit checks run again against them, adding the secret's mode. Where cgit's own Lua does, a login is posted through cgit and the cookie it grants opens the repository. Both skip where crypt checks no SHA-512 hash or the libraries are missing.
Check the login form's field namesBryce Kwon-0/+4
login() in the checks posts username and password under names of its own, so renaming either field in the form broke every real login while the suite passed.
Check that an auth filter is handed the urlBryce Kwon-0/+35
Both shipped filters key their access lists by a repository's url, and MANUAL says cgit hands that over, but nothing read the argument. Every auth test served a repository whose url and name were the same, so a cgit that passed repo.name, under which a url-keyed list matches nothing and every protected repository goes public, passed.
Check the auth files that are missing or brokenBryce Kwon-0/+21
Only a missing users file and a missing repos file were tried. A missing groups file denies today, but a change returning nil there would have made every protected repository public unnoticed. The repos file's log line and a users file with no line that parses, which has to turn a login down without spending crypt, went unchecked too.
Check the comparisons that must not leak timingBryce Kwon-0/+25
constant_equals was only checked for its answers, on strings that differ in one byte. Summing the plain differences instead of their squares passed, which accepts any signature with the same byte sum, and so did a plain == at the signature or the password check.
Check when a session expiresBryce Kwon-0/+26
Nothing read the expiry signed into a granted session. validate_value treats 0 as never expiring, so a login that signed its session with 0 passed, since the Max-Age the browser is told comes from set_cookie alone. The expiry second itself is now held to be too late, with the clock held still, as a comparison of < instead of <= passed too.
Check that a signature covers every cookie fieldBryce Kwon-0/+20
The only tampering tried was a flipped signature, a field swapped for another and the binding, so a payload that left out the expiry, the salt or the value still passed, and a captured session could have been extended for ever.
Check that the secret keys every signatureBryce Kwon-0/+12
Every check signed and verified under one pinned secret, so a sign() that left the secret out of the HMAC key, which makes every cookie forgeable, passed.
Check that the auth secret is made safelyBryce Kwon-11/+112
The checks replaced get_secret with a constant, so its success path never ran, and the luaposix stand-in had no link or unlink and a umask that ignored its argument. Dropping the tightened mask, which leaves the secret readable by everyone under the usual 022, or accepting a short secret, passed. The real get_secret now makes the secret in the run's directory through stand-ins that behave like the calls they replace, and the checks cover the mask and its restoration, the link race, the temporary file, reuse and a secret written by hand.
Give each auth unit run a directory of its ownBryce Kwon-19/+23
test-auth.lua wrote its fixtures into whatever directory it was started from, so a run by hand from the checkout left auth-users and its siblings behind, and the checks assumed no auth-users-missing or no-such-directory already sat there. It now refuses to run without a directory, and t0505 hands each interpreter and variant a fresh one. The interpreter and paths are expanded inside the test body rather than pasted into it in single quotes, so a path holding a quote no longer breaks the eval.
Check the rest of what the diff page printsBryce Kwon-14/+74
Nothing checked a deleted file, a change of mode, a binary file, a submodule, a path, a range between two commits or the root commit on the HTML page, nor the 404 a revision that is no commit gets. The first checks were steps titled as actions that read one page in turn, so each now fetches its own.
Check the mailmap on every page it reachesBryce Kwon-31/+83
The MANUAL promises the blame and stats pages and says mailmap.file and mailmap.blob are ignored, and none of it was tested. The summary, where v2.11.1 fixed a mailmap crash, was never loaded, and neither was a committer, a mailmap on another branch or the repository flag turning the map on. The empty search checked only that nothing matched, and one test appended to the shared config.
Check the trailer values each path takesBryce Kwon-28/+62
The ident said to follow the mailmap had no entry in it, and the commit filter that takes a value when no trailer filter is set had no test, nor did brackets without an address, a message of nothing but a block and the repository flag turning the table on. One test appended to the shared config, and seven read a page an earlier test fetched.
Check submodule links by revision, path and urlBryce Kwon-32/+118
Every request viewed HEAD and every gitlink sat at the top level, so a link read from the wrong revision's .gitmodules, or looked up by the shown name rather than the full path, passed. The other url schemes, the whole-component rule, the other forges, the templates that take precedence and the submodule page had no test, and the gitlinks pointed at the parent's own commit rather than one of subtarget's.
Check the stats columns, periods and pathBryce Kwon-30/+138
Each period check needed a single heading of the right shape, so a wrong window or column count passed, and the weekly default had no check. A request that straddles midnight is made again rather than failing, since cgit reads the clock for itself and a new day can open a new period. The absence checks gain a presence check on the same page.
Check the dates each format and timezone showsBryce Kwon-25/+61
The index and log checks were absence-only, so a page with no dates passed, and date-format=local ran under UTC on a commit made at +0000, where local time and the commit's own read the same. local-time, the -local formats and the rule keeping a listed date on one line had no test.
Check every age bucket and a date past nowBryce Kwon-6/+43
Only the class prefix was checked, and the fixture held nothing between the two week cutoff and now, so a bucket bound that slipped or a date past now shown as a negative age passed. Each tag sits in the upper half of its bucket, which the bucket below takes if its bound slips.
Keep a followed diff to the path it namesBryce Kwon-2/+40
A followed diff kept every path that started with the requested one, so following small.c took small.cpp in as well. A path now has to be the requested one or lie below it, as the pathspec of an unfollowed diff matches.
Check the feed's elements, limits and pathBryce Kwon-32/+102
No entry content was checked, so a wrong link, id or date passed, and the path control looked at the status alone. A max-atom-items of 0 or below, all=1 and the epoch an empty feed takes had no test. The xmllint checks read a feed an earlier test left behind, which was another feed whenever that test failed early.
Test serving a snapshot signatureBryce Kwon-23/+61
No test fetched a signature within the size limit, so the status, the headers that keep a browser from sniffing it and the body went unchecked, as did the answer for a ref with none and the plain tar signature a compressed tar falls back to.
Request every snapshot name back to its refBryce Kwon-69/+197
The names on the links were checked but never requested back, and the tests shared one repository whose refs each test added to, so a run of a subset broke them. On a case-insensitive filesystem a loose V1.0 also answered lookups for v1.0, so the case tests checked different tags from one filesystem to another. The slash ref sat at master's tip, where the commit compare could not tell it from the default branch.
Compare each snapshot format with git archiveBryce Kwon-58/+47
Only the entry count and one file were checked, never the archive itself. git's own writer at the same commit gives the same bytes, so each format is held to it, which also proves the commit served. That leaves unzip -t unused, which busybox may not have.
Compare more of the patch page with gitBryce Kwon-33/+82
The root patch was checked for its signature alone, so one that lost its diff passed. The headers, the note a path adds to the stat and a merge in a range had no test, and a renamed file's patch was grepped rather than compared. The version is read in the test that needs it, so a missing build/VERSION fails there instead of surfacing later as a mismatch.
Check which commits max-patch-count keepsBryce Kwon-9/+21
Only the number of patches was counted, so keeping the oldest two of a range would have passed. The default of 50 and the 0 that lifts the bound had no test.
Check the rawdiff is served as plain textBryce Kwon-24/+17
strip_headers dropped the headers before every compare, so a rawdiff served under another type passed. Each test now makes its own request, and the ids it needs, rather than reading what an earlier one left.
Test the diff options a request or config setsBryce Kwon-0/+94
None of dt=2, ignorews, context and its cap, side-by-side-diffs or rename-limit had a test anywhere in the suite, nor the 0 that the MANUAL says lifts the rename limit.
Check what each side-by-side cell holdsBryce Kwon-18/+106
The span checks compared page totals, so a span on the wrong side or over the wrong characters passed while the totals agreed. A fill that read cells a longer pair left behind passed as well, since only a literal pair after a longer one shows it. Nothing checked the cell classes the forced-colours border keys on, or the rows for unpaired, overlong, tabbed, binary and cut short lines.
Test enable-plain-email=0 where it changes outputBryce Kwon-0/+28
No test set it, though it switches the patch to a format of cgit's own and drops the address from the feed and the trailer idents.
Check the stats page counts and orders authorsBryce Kwon-10/+60
No test asserted a count, and the fixture had a single author, so a page that stopped counting or sorting passed. The commit graph came in for a language breakdown that is gone. It stays because the walk still releases each commit as it goes, which a commit read from the graph has to survive.
Check the feed escapes what XML cannot carryBryce Kwon-0/+45
Every fixture subject was plain ASCII, so xmllint never met a byte the escaping exists for. git commit rewrites stray bytes as Latin-1 and the commit parser replaces any that are left, so the commit is written by hand and the description carries a stray byte to the feed's own check.
Name the followed path in the diffstat headerBryce Kwon-4/+30
With follow set the diff runs over the whole commit and show_filepair applies the path, so the header read (limited to '') whether or not a path was given.
Check a renamed file's diff leaves the rest outBryce Kwon-8/+15
A new path is diffed across the whole commit so the rename can be found, and a filter then keeps that path alone. The rename commit touched one file, so a diff that dropped the filter passed.