AgeCommit message (Collapse)AuthorLines
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.
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.
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 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.
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-16/+26
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 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-16/+18
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 that the outermost avatar brackets come offBryce Kwon-0/+4
With one pair of brackets, matching the innermost pair would have passed the old check as well.
Say why the Lua search paths reach the testsBryce Kwon-1/+4
Give the harness cgit's print and its other sinksBryce Kwon-2/+35
Lua's own print wrote outside the collected output, so a stray print in a filter passed every check while under cgit it lands on the page. html_url_arg and html_include were missing, which only a filter using them would have found.
Compare link-trailers output wholeBryce Kwon-1/+5
A short object name was checked only for a missing anchor, and the value that passes through untouched never held the entities cgit escapes it with, so escaping it again would have passed.
Compare link-commits output wholeBryce Kwon-8/+13
Four checks only looked for a missing anchor, which output with the text dropped also passes, and no message held the entities cgit escapes it with.
Time the other filters at two lengths as wellBryce Kwon-26/+59
The avatar checks held a 40000 byte address to half a second, twenty times tighter than the readme budget that already failed on a slow host, and in stub mode nearly all of that time went on the fake digest. Link-commits and link-trailers had no check on a long input at all. The readme checks' method moves into the harness so all four share it. A single timing of each length let a busy host that took the CPU away during the longer one make a linear pass look quadratic. The lengths now take turns and the fastest timing of each counts, since a busy host can slow one timing but rarely all five. A ratio under six ends the turns at once, so only one near the bound of ten waits for all five.
Hold the avatar stub checks to an absolute hashBryce Kwon-7/+28
The stub mode checks only compared hashes with each other, and the stand-in digest took any algorithm name, so md5, a misspelt sha256 or hex in capitals passed everywhere luaossl is missing, which is every machine here. The comparisons also passed with no hash found on either side.
Cover how link-trailers applies its rulesBryce Kwon-0/+26
Skipping a malformed rule, a rule without a key, the switch for bare urls and the shipped CVE example were untested, and the only url kept from linking was one holding a quote, so a broader scheme check would have let javascript:// through.
Cover how link-commits applies its rulesBryce Kwon-0/+41
Skipping a malformed rule, the tie between two rules, the scan past an empty match, a rule with no capture and the switch for object names were all untested, and none of the shipped examples beyond the issue rule had ever been loaded.
Cover the rest of syntax-highlight's outputBryce Kwon-4/+22
No token ever took hl-type or hl-comment, so a typo in either row, or a rule gone from the stylesheet, passed. Nothing fed the filter a NUL byte or a blob of exactly the size cap either.
Check the lexer modules the filter cannot useBryce Kwon-3/+54
A module called lexer that is not Scintillua, a Scintillua older than 6.0 without detect(), lexers that cannot load lpeg and a lexer that returns no token list were all documented and none was tried.
Drop the section labels from the readme checksBryce Kwon-4/+0
Cover the rest of the man macrosBryce Kwon-0/+25
Cover the rest of the markdown grammarBryce Kwon-0/+53
The changelog for 2.12.0 says a list split by a code block keeps counting, and only the split by a blank line was checked.
Pair each readme absence check with what rendersBryce Kwon-2/+6
Four checks only looked for something missing, which a dropped or plain text rendering also satisfies, and the spacing macro check missed a 0 drawn at the start of a line.
Never give two headings the same anchorBryce Kwon-0/+10
A repeat's count was keyed on the bare text, so a heading whose text already ended in that count took the same anchor, as "Twice 1" did after two of "Twice", and "About 1" after "About". A link to either then landed on the first. The count now goes on up past any anchor already handed out, the way GitHub's slugger does.
Check what the nesting rules actually renderBryce Kwon-3/+6
The emphasis bomb checked only that the output was not empty, which it never is, and its input never nests. No input reaches the ceiling on inline nesting either, since an emphasis cannot hold its own kind, so the check now proves the nesting that does happen. Past the quote ceiling only the innermost text was looked for, and any x passed.
Check the two fallbacks around rendering a readmeBryce Kwon-0/+13
Check the log line for lexers that are not foundBryce Kwon-5/+43
Every check set CGIT_SCINTILLUA_PATH, which the filter takes as given, so the line for a server with no Scintillua at all never ran and deleting it passed. The harness can now clear a variable and hide the directories the filter probes. A lexer.lua anywhere on LUA_PATH also loaded in place of the missing one, so the fallback runs now keep every Lua module out of reach.
Prove the avatar fallback on any machineBryce Kwon-1/+2
The page without icons was checked only where cgit's Lua lacked luaossl, so a machine that has it never ran the fallback. It now runs with every Lua search path pointed at an empty directory, and the log line is compared whole. Writing the config needs no Lua, so that step runs everywhere too.
Prove the about page fallback on any machineBryce Kwon-1/+24
The fallback through cgit ran only where cgit's own Lua lacked lpeg, and every machine the suite runs on has it, so the test never ran. With every Lua search path pointed at an empty directory it runs anywhere. It now also checks that the readme's markup is escaped, as its title said, and compares the whole log line.
Fail a unit check run that made no checkBryce Kwon-0/+5
Decide every unit check skip in the shellBryce Kwon-25/+52
Where a standalone Lua had no lpeg, the harness skipped the markdown and man checks itself, behind a note the test library hides, and the test passed on the six checks left. The real luaossl checks were left out the same way. Each now shows as a skip under a prerequisite named for the interpreter, and a misspelt mode fails rather than running the default.
Show unit checks as skipped when no Lua is foundBryce Kwon-2/+5
With no standalone interpreter on the path the unit checks were never registered, so they counted as neither run nor skipped, and a fault in the version probe dropped them all behind one line of output. The test bodies now expand their paths as they run, so a quote in a path no longer breaks them.
Run each standalone Lua version onceBryce Kwon-5/+27
A plain lua is usually one of the versioned names again, as lua and lua5.5 are here, so every 5.5 check ran twice, while names such as lua54 and lua-5.4 were never looked for. A test now names the version that ran, since "under lua" did not say which one it was.
Stop the run when the Lua probe failsBryce Kwon-2/+14
The probe piped cgit into grep, so a crash or a sanitizer abort while probing read as a missing module, and t0501, t0504 and t0505 then expected the fallback on a machine that has the module.
Check that link-trailers encodes a rule captureBryce Kwon-0/+7
As in link-commits, every capture was hex or digits. A string replacement there would also raise outside the pcall that guards the pattern and take the whole page down.