Repository navigation
0.3.0
·
56 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
Upgrade steps
- Rename
releasetovintageinsources.toml. The old key is now refused, with a
message naming the new one (see Removed below). - A source with
headersneeds an httpsurlnow (see Security below). Switch an
http://URL tohttps://, which most APIs serve. - Run
buildagain for JSON sources: numbers are now written as they appear in the file,
so such an output can change (see Changed below).
Added
--manifest PATHon every command, andmanifest=onmain, read asources.toml
other than the one in the current directory, such as one a project ships inside its
package. The data still goes todata/in the current directory.- A weekly CI job runs the Save Page Now contract test against the live archive, so the
stand-in the other tests use is checked against the real service. Run it locally with
uv run pytest -m live. - Two docs pages: How sourceledger works, on the stages and the
files each one writes, and Use sourceledger safely. The README
shows how to verify a release withgh attestation verifyorpypi-attestations.
Changed
- sourceledger is for Linux and macOS (POSIX), and its package metadata now says so. On
Windows it runs, butfetchtakes no lock against a second run. - Reading a table with thousands of columns, or a
sources.tomlwith thousands of sources,
is faster: the check for repeated names no longer grows with the square of their number. - JSON sources keep numbers as written:
1.10stays1.10and1e5stays1e5, at the
top level and inside nested values. Before, they were read as numbers and written back
as1.1and100000.0. An output built from such a file changes on the nextbuild. buildreads a CSV source and writes its output one row at a time, with the default
parser, so memory use no longer grows with the size of the file. For a 161 MiB source it
peaked at 2.5 GiB before, and it is about a quarter faster. The output and
datapackage.json are the same, byte for byte. JSON, Excel, gzipped CSV and a custom
parseare still read whole.validatereads each output one row at a time, and checks the raw file's hash without
reading it into memory, so memory use no longer grows with the size of the data. For a
161 MiB source it peaked at 2.5 GiB before.buildon the command line counts the rows
it prints the same way.fetchchecks a raw file's hash before a conditional request without reading the whole
file into memory, and reads the fetch log once per run. Before, each source with
archive = truethat came back with the same bytes read the whole log again.
Removed
- Breaking: the old key
releaseis no longer read asvintage. A manifest that
still uses it fails to load and names the new key, rather than being kept as an unknown
key and leaving the vintage "not stated".
Fixed
- Bytes in the fetch log that are not UTF-8 no longer stop fetch, status and revisions
with a bare decoding error. They read as U+FFFD, so a line they break is reported by
its number, as any other damaged line is. archive = truenow waits up to 120 s for Save Page Now, up from 15 s. The archive
answers only once the snapshot is taken, 49 s for a GitHub page in one test, so a fetch
whose snapshot took longer than 15 s recorded an emptyarchive_urlalthough the
archive had the page.- A fetch log whose last line is a whole record without its final newline, as an editor
or a merge can leave it, keeps that record. Before, the next fetch took it for a line
cut off by an interrupted fetch and deleted it from the history. Appending now reads
only the end of the log, not all of it. - A source's last record in the fetch log, or its
.fetch.json, with a missing field or a
field of the wrong type (a SHA-256 that is not 64 hex digits, a size that is not a whole
number), is now reported as not a fetch record. Before,fetch,build,validateandrevisions
could stop with a traceback, andfetchskipped the sources after it.fetchnow
downloads such a source again, andvalidatelists it as a problem. revisionsfails when the current log does not exist, as it already did for the
earlier copy. Run from the wrong directory, it used to report no revisions.fetchandbuildcalled from Python with asha256pin in upper case, bypassing
load_manifest, now treat it the same way: both compare it as written.- A cut-off or damaged gzip, a file that is not an Excel workbook, and JSON nested too
deeply to read now failbuildandvalidatewith one line that names the source,
not a traceback. - An Excel sheet with a value right of its header is refused, as a CSV row with more
fields than its header is. Before, it became a column with an empty name, and two such
values gave a misleading "appear more than once" error. Empty header cells at the end
of the first row are no longer read as columns.
Security
- Breaking:
headerson a source whoseurlis not https is a manifest error, since
the API key would cross the network in clear text. - A redirect that changes the scheme, such as https to http on the same host, now drops
theheaderstoo, as a redirect to another host already did. Before, the key went out
in clear text after the downgrade. - A redirect from a public host is now checked against the address the connection
actually reached, not a separate lookup before it. A name that resolved to a public
address for the check and to an internal one for the connection could get past it.
Through a proxy the check is skipped, since the proxy resolves the name. - The 300 s limit on one source's fetch now holds against a server that sends a few
bytes at a time. Each read used to wait for a full 1 MiB, so a slow trickle kept a
fetch going far past the limit. It now stops within one 30 s socket timeout of it. fetchno longer follows a symlink atdata/raw/.lockordata/fetches.jsonl. A
checkout could plant one, and taking the lock emptied the file it pointed at. The lock
file is never truncated now, and a symlinked log fails the fetch.- An Excel workbook is refused when it unzips past
max_bytes, as a gzipped file
already was. A small workbook could otherwise expand to more memory than the machine
has.