AgeCommit message (Collapse)AuthorLines
Check the line links of a side-by-side diffBryce Kwon-9/+17
The links have been written through html_attr since b8adfd6, so with the percent-encoding dropped a quote came out as an entity the absence check could not match, and the presence check was met by the file links above the diff. The test now reads the line links themselves, for a name holding a hash and a question mark as well.
Look for inline handlers on every main pageBryce Kwon-4/+15
Only the commit page was checked, and only for onchange, though a site policy without unsafe-inline blocks every inline handler on any page.
Tie each escaped readme to its own payloadBryce Kwon-8/+7
The escaped script tag alone matched either readme, so the markdown page showing the text readme passed.
Compare the small blob the plain page servesBryce Kwon-2/+6
The test took any page holding the word top, with no status checked. The refusal half lives in t0204, so the fixture now says why its limit is set so low.
Read the --output refusal from its own requestBryce Kwon-10/+10
The refusal was read from a page the previous test had left, which --run could skip, and both requests went through the shared page cache. The marker is also named apart from the one the filter test plants, so a failure in one cannot fail the other.
Test every scanned key that waits on trustBryce Kwon-23/+79
Only head-content and logo-link were tried, so logo, clone-url and both module-link forms could have been taken from a repository's own cgitrc unnoticed. A trusted control shows each value would reach the page, and the refused disk readmes are now checked against a file that would show if read.
Check the policy sent with repository bytesBryce Kwon-0/+28
No test asserted the Content-Security-Policy header, though it is all that keeps script in an SVG from running when the plain page serves it under its own type.
Test the snapshot slash rule on a real refBryce Kwon-4/+20
Every candidate name meets check_refname_format first, which refuses the old payload, so the slash rule never answered it and could go unnoticed. A tag holding a slash reaches it, and a name in revision syntax without a slash now pins the ref name check of its own.
Catch an ignored SIGPIPE under any shellBryce Kwon-9/+15
dash reports a write to a closed pipe as an I/O error and never names a broken pipe, so where sh is dash the test passed with the reset removed. The writer now leaves a marker when it outlives the closed pipe, which it can only do with the signal ignored. That holds under dash, bash and ksh.
Prove the login body is cut at the bufferBryce Kwon-5/+16
The posted body was 22 bytes, so an unclamped read stopped at its end and nothing overflowed, and the test could not fail. The filter now counts what it was handed from a body larger than the buffer.
Ask for the working auth pages through cgit_okBryce Kwon-13/+19
The unedited copy and the login page were requested through cgit_rc, so a page cut short or an error logged on the way passed. The owner and description checks on the login page could not fail either if the config lost them, so the same config with a filter that lets the visitor in now has to show both.
Count the auth unit checks as skipped without LuaBryce Kwon-3/+6
With no standalone Lua on the path the unit checks were never registered, so they counted as neither run nor skipped, and t0505 passed on its cgit checks alone.
Say which earlier tests each hook case needsBryce Kwon-2/+6
Push to each hook installed as post-receiveBryce Kwon-0/+35
No hook ran the way git runs it, so the shebang, the executable bit, GIT_DIR, the refs on stdin and the remote: lines a pusher sees were all untested.
Check the commit-graph hook with a git too oldBryce Kwon-0/+24
The header says a git too old for the options leaves the graph as it was and the hook stays silent, but every run had a git that could write it.
Run the hooks under every POSIX shell presentBryce Kwon-24/+45
Only sh, dash, ksh and bash were tried, so busybox sh ran only where it is /bin/sh, and mksh, yash, posh and zsh's sh mode never ran. Where sh is a link to dash, the same shell ran twice. A shell reached by two names now runs once, and the list is said so a run shows what it covered.
Drop cached pages asked for with an escaped urlBryce Kwon-2/+20
README tells a visitor to write a plus in the query form as %2b, and cgit caches such a page under the raw query, but the hook compared that query with the url as it stands. A push to foo+bar.git left its pages under url=foo%2bbar.git/ and r=foo%2Bbar.git cached and stale until their ttl ran out. Decoding in sh would take more than the hook is worth, so a query with a % or a + now counts as stale, which costs another repository's page at most a refill.
Check more of the keys the cache hook readsBryce Kwon-0/+16
No page asked for with r= was cached, no slot held a head that does not parse as cgit's, and the hook never met a cache root that was missing, so ignoring r=, keeping an unreadable slot, or complaining without a cache all passed.
Write the auth test configs through cgitrc_repoBryce Kwon-25/+4
Drive the auth actions through the harnessBryce Kwon-14/+2
run_action repeated harness.run line for line, and three comments only labelled the sections below them.
Check the two auth filters share their codeBryce Kwon-0/+14
Both say a change to the code they share belongs in both, but nothing held them to it, so a fix made to one alone in a path the unit checks do not reach would have gone unseen.
Hold signatures to the length SHA-256 givesBryce Kwon-1/+7
The fake HMAC returned 16 bytes, so the checks signed with signatures half the real length, and a signature cut short passed. tohex's output was never pinned either, so dropping its zero padding stayed consistent with itself and passed.
Check a session cookie scoped below the rootBryce Kwon-0/+9
A cookie_path other than / has to keep Secure but drop the __Host- name, which a browser takes only for the whole host. Neither was tried.
Check expired and planted sessions on a visitBryce Kwon-0/+7
An expired session was only tried against validate_value, never sent through a visit, and nothing sent a session under the plain cookie name, which a sibling subdomain can set where it cannot set the __Host- one.
Check the form is there where a message is notBryce Kwon-1/+4
The checks that a forged session is not taken for a signed-in visitor, and that https brings no warning, would also have passed on the page saying logins are unavailable.
Check a login when crypt cannot check the hashBryce Kwon-1/+12
crypt(3) answers nil for a kind of hash the system does not check, but the stand-in never did, so a login that raised on it, or let it through, passed.
Check that a later push adds a graph layerBryce Kwon-2/+8
The check was a negated test_cmp, which also passes when either file is missing, and a changed chain does not prove the new layer was written. The chain's last line now has to name a graph file that exists and was not in the chain before the push.
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-0/+9
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-0/+10
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.