| Age | Commit message (Collapse) | Author | Lines |
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
The test for a hunk that carries a length ran on foo's diff, whose only
numbered side is +1 with no length, so it repeated the comma-less test.
Every fixture hunk started at line 1, so a parser that always answered
1 passed. A line 0 never gets a link, so the absent 0 link could not
show either way.
|
|
|
|
A robustness test asked for the inner tag's page by id, but nothing
checked that the outer tag's page links there.
|
|
|
|
The tag requests passed on any answer short of a crash, and the title
test read a page the cache kept from an earlier test. The id pattern
also matched an empty id, the date row was checked only for its
opening tag, and the lightweight tag was never shown to lack a date
row. Two tests read a page an earlier test wrote.
|
|
|
|
|
|
|
|
The comment names a message with no encoding header as one case, but
only a header naming an unknown charset was tested. Without a header
the text is taken as UTF-8 and never converted, so only the clean-up
stands between its stray bytes and the page.
|
|
The octopus took its first parent's tree, so its diff would have been
empty whether drawn or not, and only the missing options were checked,
with nothing to show the right page rendered. A merge of two parents,
the other side of the limit, had no test.
|
|
The commit requests passed on any answer short of a crash, and the
root commit checks read a page another test wrote. The tree row was
found by its href alone, never by the tree id it names.
|
|
Only a robustness test touched the blob page, so a request by bare id,
the binary type, the untrusted headers and the refusal of a malformed
id had no check.
|
|
|
|
|
|
The content security policy had no test anywhere, and nosniff was
only checked on a scanned repository.
|
|
|
|
The plain requests passed on any answer short of a crash, and the
listing test never looked at where its links led. The types config was
a copy of the shared one with its page cache still on, which
cgitrc_copy exists to switch off.
|