Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
395 commits
Select commit Hold shift + click to select a range
2a0cfcc
Progress: owner questions answered; LXMF removal started
afit21 Oct 19, 2026
8b3b06d
Move rnfs: URIs, the link-map field and the inbox import out of the L…
afit21 Oct 19, 2026
d51ad83
Roadmap: pace path requests and cut idle link and lookup traffic
afit21 Oct 19, 2026
d8b9f38
Remove LXMF messaging from rnfs; retire the lxmf_* settings
afit21 Oct 19, 2026
bbd30bb
Remove the feature deprecation mechanism, unused since LXMF left
afit21 Oct 19, 2026
14daaac
Drop the LXMF dependency from every package and lock
afit21 Oct 19, 2026
4b45e30
Document LXMF's removal from rnfs in the spec, design.md, README and …
afit21 Oct 19, 2026
543fd7d
Merge the removal of LXMF from rnfs core into dev
afit21 Oct 19, 2026
f761584
Roadmap and progress: LXMF removed from core
afit21 Oct 19, 2026
ab45593
Progress: final verification after the LXMF removal passes
afit21 Oct 19, 2026
6819c88
Roadmap: say what 0.2.0 implemented
afit21 Oct 19, 2026
2c559e7
Lint the APIs Windows lacks, and name each use's guard
afit21 Oct 19, 2026
265e5ea
Fix four tests that fail on macOS or Windows
afit21 Oct 19, 2026
31b3c53
Make bare wait_for calls fail on a timeout, and check none is left
afit21 Oct 19, 2026
8ff1ffb
Make five timing-dependent tests independent of the runner's speed
afit21 Oct 19, 2026
b85f192
Run a test that failed in CI once more before failing the run
afit21 Oct 19, 2026
3fc7a9f
Roadmap: make 0.2.0 the last foreseeable feature release
afit21 Oct 19, 2026
2a5ffbd
Progress: rewrap a paragraph
afit21 Oct 19, 2026
ff0bd09
Roadmap: move what can't ship in 0.2.0 into a Future part
afit21 Oct 19, 2026
25e44ae
Roadmap: the 0.2.0 review's fixes and improvements still to do
afit21 Oct 20, 2026
c26320e
Add the handoff for finishing 0.2.0
afit21 Oct 20, 2026
7b4dd03
Progress: start Part 3, finishing 0.2.0
afit21 Oct 20, 2026
1e78d97
Progress: item 2 started alongside item 1
afit21 Oct 20, 2026
ac38138
Bound a NomadNet page answer to 16 MiB at its first segment (REV5)
afit21 Oct 20, 2026
19a4f4c
Index the REV5 regression test (REV5)
afit21 Oct 20, 2026
aad8643
Progress: Part 3 baseline test run
afit21 Oct 20, 2026
a876cbf
Split build_tar's member placement from building a file
afit21 Oct 20, 2026
284268e
Prove a missing app's name like an existing one's (REV9)
afit21 Oct 20, 2026
a4da9f3
Say plainly that an app's token can do what the CLI's can (REV12)
afit21 Oct 20, 2026
abf8ab0
Don't render files as pages on gateway sites unless their DAG names t…
afit21 Oct 20, 2026
265e5f3
Merge branch 'worktree-agent-ada574c32ef0bc9c8' into integ
afit21 Oct 20, 2026
3929033
Merge branch 'worktree-agent-ae60a8530b302a5fe' into integ
afit21 Oct 20, 2026
7cd77d1
Merge branch 'worktree-agent-a243c39cf2068c973' into integ
afit21 Oct 20, 2026
c99d1d2
Progress: the integration branch for Part 3
afit21 Oct 20, 2026
76b5af4
Count allocation units and collect leftovers when unpacking sealed fo…
afit21 Oct 20, 2026
09801a9
Document that sealed files depend on the recipient's node key (REV12)
afit21 Oct 20, 2026
9225a16
Index REV10's regression test in the security README
afit21 Oct 20, 2026
53ed603
Partition mode can't be forced from outside (REV4)
afit21 Oct 20, 2026
5228aa9
Merge branch 'worktree-agent-a683668febd5c4249' into integ
afit21 Oct 20, 2026
b29f13f
Progress: REV5, REV6, REV9, REV10 reviewed and on integ
afit21 Oct 20, 2026
5195153
Refuse the rnfs dir in add, and skip it in every walk (REV1)
afit21 Oct 20, 2026
38b4c74
Say what provide_entries publishes (REV12)
afit21 Oct 20, 2026
37157ed
Merge branch 'worktree-agent-aacdc17587353dc98' into integ
afit21 Oct 20, 2026
4ccf9b3
Progress: REV1 reviewed and on integ
afit21 Oct 20, 2026
1109f77
The announce first-seen log keeps its senior servers (REV7)
afit21 Oct 20, 2026
abc2681
Hold name announces while the clock is behind their last, and estimat…
afit21 Oct 20, 2026
63201f5
Give provider records a write budget (REV2)
afit21 Oct 20, 2026
18897a5
Let Earned records give way at a full key (REV3)
afit21 Oct 20, 2026
f5dd6e8
Cap the provider standings kept without records (REV11)
afit21 Oct 20, 2026
07511e2
Name the REV2, REV3 and REV11 fix commits in the security test index
afit21 Oct 20, 2026
b827ee8
Model RNS's path-request ingress limit in the topology simulation
afit21 Oct 20, 2026
f934066
Record the path-request limit study in the topology results
afit21 Oct 20, 2026
4642277
Roadmap: pacing path requests with the topology study's numbers
afit21 Oct 20, 2026
d07487b
Progress: the topology study's findings and the LoRa fetcher's review
afit21 Oct 20, 2026
340f504
Progress: provider store fixes reviewed, owner questions for Part 3
afit21 Oct 20, 2026
55f9fcd
Merge branch 'worktree-agent-a482aa74884e7e6b2' into integ
afit21 Oct 20, 2026
b3e2e1a
Merge branch 'worktree-agent-ae086e788184ef5b0' into integ
afit21 Oct 20, 2026
0749a88
Merge branch 'worktree-agent-a64e86ddb90b76b99' into integ
afit21 Oct 20, 2026
199b3d6
Security test index: REV rows in order
afit21 Oct 20, 2026
d018e7e
Progress: first integ run green, more merged
afit21 Oct 20, 2026
f9a28ca
Retry a lost /blocks request on a new link instead of failing its pro…
afit21 Oct 20, 2026
f1d3824
Judge slow links per provider, not per node, when fetching
afit21 Oct 20, 2026
ba1f6aa
Size a range read's window by the providers' links
afit21 Oct 20, 2026
e6d55ce
Keep a link open while its provider's upload pacing is waited out
afit21 Oct 20, 2026
97fdeab
Wrap the lines the LoRa fetching changes left over 120 columns
afit21 Oct 20, 2026
c6746e2
Made-up IDs can't inflate the network size estimate (REV8)
afit21 Oct 20, 2026
da60ac0
Keep a failed pinned fetch's progress as a cached fetch
afit21 Oct 20, 2026
52968c5
Retry remote pins and jobs whose content isn't found yet
afit21 Oct 20, 2026
d1db2e7
Progress: REV4, REV7, REV8 reviewed
afit21 Oct 20, 2026
c1c6428
Let a job be submitted not to wait for content not found
afit21 Oct 20, 2026
d99e7b5
Merge integ: security fixes REV1-3, 5, 6, 9-11, clock problems, the p…
afit21 Oct 20, 2026
d8e73f5
Merge branch 'worktree-agent-a6f6daca6659e2c2b' into integ
afit21 Oct 20, 2026
79aad91
Merge branch 'worktree-agent-a5098fbae75ae7e26' into integ
afit21 Oct 20, 2026
31731b7
Merge branch 'worktree-agent-a91f87bfefe6e2284' into integ
afit21 Oct 20, 2026
b39bff6
Progress: where Part 3 stands after the first merge
afit21 Oct 20, 2026
b7163e5
Run test_sweep's placement test with its region lookups one at a time
afit21 Oct 20, 2026
92e2944
Close idle links before RNS keeps them alive
afit21 Oct 20, 2026
3c47c1d
Merge integ: LoRa fetching (lost packets, slow links per provider, ra…
afit21 Oct 20, 2026
11b95c6
Progress: second integ merge, interop green
afit21 Oct 20, 2026
f2946eb
Roadmap: the 0.2.0 review's security fixes, as implemented
afit21 Oct 20, 2026
af1b4e0
Security test index: say where the REV IDs come from
afit21 Oct 20, 2026
0542804
Don't ask a probe that brought the first block for it again
afit21 Oct 20, 2026
29f91e0
Spec: RNS's path-request limits, and what announces carry
afit21 Oct 20, 2026
49f44b3
Count each block's disk allocation against max_storage
afit21 Oct 20, 2026
c251cb2
Progress: max_storage counts allocation, reviewed
afit21 Oct 20, 2026
03e2513
Pace path requests node-wide
afit21 Oct 20, 2026
fd71ae7
Measure sweep providing on LoRa islands and at a first start with the…
afit21 Oct 20, 2026
6f093ba
Don't count a query that failed for want of a path towards partition …
afit21 Oct 20, 2026
2893ee7
Remember providers between fetches
afit21 Oct 20, 2026
56ec319
Progress: remembered providers and idle links, reviewed
afit21 Oct 20, 2026
3d62bdb
Merge branch 'worktree-agent-a476880a2bae2c1db' into integ
afit21 Oct 20, 2026
7e8ccb6
Merge branch 'worktree-agent-a4213ea5f13c1ed6d' into integ
afit21 Oct 20, 2026
c9eff02
Ask for a named node's path only where the node can be
afit21 Oct 20, 2026
280dbf9
Tell island operators how path requests travel on a LoRa island
afit21 Oct 20, 2026
08e51e2
Size sweep regions by the network size estimate too
afit21 Oct 20, 2026
6218b23
Progress: sweep region sizing, reviewed
afit21 Oct 20, 2026
e140a36
Progress: pacing path requests reviewed; how path requests travel on …
afit21 Oct 20, 2026
7c2a6e4
Scope a named node's path request only over a fast interface
afit21 Oct 20, 2026
6a537e4
Merge branch 'worktree-agent-abaa6185d13659059' into integ
afit21 Oct 20, 2026
d99812c
Merge integ: max_storage counts allocation, remembered providers, idl…
afit21 Oct 20, 2026
1f72548
Merge branch 'worktree-agent-a12718d7dce6473d3' into integ
afit21 Oct 20, 2026
0a6600b
Progress: third merge, pacing and sweep on integ, Reticulum started
afit21 Oct 20, 2026
757b83d
Merge integ: pacing path requests, path requests scoped to fast inter…
afit21 Oct 20, 2026
526a90e
Progress: fourth merge, interop green
afit21 Oct 20, 2026
de9d66c
Roadmap: LoRa fetching, pacing path requests and less link traffic, a…
afit21 Oct 20, 2026
ec7b49f
Progress: Scale reviewed, the last item started
afit21 Oct 20, 2026
0eba98d
Pace a slow node by its radio's measured load
afit21 Oct 20, 2026
963205e
Honour RNS's identity blackhole
afit21 Oct 20, 2026
a67bef6
Count a link the server closed as a refusal, not a failure
afit21 Oct 20, 2026
d987bd8
Shorter path waits for lookup candidates on fast nodes
afit21 Oct 20, 2026
ff4211b
Merge branch 'worktree-agent-a533a89328941ce99' into integ
afit21 Oct 20, 2026
2c7adce
Security test index: the blackhole test's fix commit
afit21 Oct 20, 2026
a174d12
Progress: Using more of Reticulum reviewed and on integ
afit21 Oct 20, 2026
deca800
Keep the publisher's state on disk, read per round
afit21 Oct 20, 2026
561387b
Provide entries of the user's own pins only, up to provide_entries_max
afit21 Oct 20, 2026
839ae47
Size the publisher benchmark's regions as a node does
afit21 Oct 20, 2026
e397688
Progress: fifth merge
afit21 Oct 20, 2026
553333f
Merge integ: using more of Reticulum (radio load, blackhole, server-c…
afit21 Oct 20, 2026
6c26064
Roadmap: using more of Reticulum, as implemented
afit21 Oct 20, 2026
87de8aa
Answer /blocks through RequestServer._serve
afit21 Oct 20, 2026
2f8c4f5
Progress: resumable and compressed block transfers reviewed
afit21 Oct 20, 2026
02724ae
Resumable and compressed block transfers: the optional /range request
afit21 Oct 20, 2026
0c56e10
Take a node for one that doesn't answer /range only after two silence…
afit21 Oct 20, 2026
5ba2b2f
Merge branch 'worktree-agent-a67b88a23bc92cc7f' into integ
afit21 Oct 20, 2026
4acac18
Security test index: the /range tests' fix commits
afit21 Oct 20, 2026
38c7ae5
Roadmap: resumable and compressed block transfers, as implemented
afit21 Oct 20, 2026
d87ba54
Merge integ: resumable and compressed block transfers (the optional /…
afit21 Oct 20, 2026
cd01f48
Progress: /range merged
afit21 Oct 20, 2026
5da0f4b
Merge branch 'worktree-agent-a1475517f028f54f6' into integ
afit21 Oct 20, 2026
81ff2fd
Progress: every item built; the sweep scaling problem and the interop…
afit21 Oct 20, 2026
a084fd5
Compare per server in test_lookups_at_once_send_what_one_at_a_time_sends
afit21 Oct 20, 2026
92f7e0c
Cover a region's keys by what it can store to, not by the size estimate
afit21 Oct 20, 2026
6bcddbc
Keep an answer that arrives before RNS registers its request
afit21 Oct 20, 2026
d3a935e
Progress: sweep coverage fixed
afit21 Oct 20, 2026
0198643
Merge integ: the publisher's state on disk, provide_entries of the us…
afit21 Oct 20, 2026
4e95883
Progress: seventh merge
afit21 Oct 20, 2026
769e87d
Merge branch 'worktree-agent-a12718d7dce6473d3' into integ
afit21 Oct 20, 2026
c332fd3
Roadmap: Scale, as implemented
afit21 Oct 20, 2026
3afbc2d
Progress: the interop delays were an RNS race, fixed in rnfs
afit21 Oct 20, 2026
4ed7a81
Merge branch 'worktree-agent-a4a34acb2ea946aa8' into integ
afit21 Oct 20, 2026
12fa188
Progress: the Done table for Part 3
afit21 Oct 20, 2026
8447c86
Progress: what Part 3 leaves for real hardware
afit21 Oct 20, 2026
853b1e3
Merge integ: sweep coverage by what a region can store to, the RNS re…
afit21 Oct 20, 2026
f416218
Progress: Part 3 finished, final runs on dev green
afit21 Oct 20, 2026
e82fd96
Spec: quotas count bytes, and what that means on disk
afit21 Oct 20, 2026
b13ee61
Roadmap: decide 0.2.0's open items
afit21 Oct 20, 2026
76b6c54
Roadmap: rewrap the Future part's introduction
afit21 Oct 20, 2026
83d5952
Progress: the owner's decisions and the clean-up
afit21 Oct 20, 2026
68d49fb
Refactor code structure for improved readability and maintainability
afit21 Oct 20, 2026
c20675d
Tests: keep the sweeper thread out of LinkPoolTest's sweep tests
afit21 Oct 20, 2026
0125546
Interop: accept 0.1.3's wording of a keeper query in its log
afit21 Oct 20, 2026
7cc037a
Keep NomadNet answers that beat RNS's registration of their request
afit21 Oct 20, 2026
09c41ab
Jobs: retrying content not found is opt-in, as 0.1.6 failed at once
afit21 Oct 20, 2026
13e0fad
Roadmap: jobs retry content not found only when asked to
afit21 Oct 20, 2026
2d85bf2
Merge branch 'worktree-agent-ab7f00aa545d379e5' into dev
afit21 Oct 20, 2026
7841466
Merge branch 'worktree-agent-af59e5b17c6a76cc0' into dev
afit21 Oct 20, 2026
41c60df
Keep a score within the limit when a node stops being a bootstrap node
afit21 Oct 20, 2026
6ed1751
Fuzz the parsers of remote input 0.2.0 added
afit21 Oct 20, 2026
18e8d46
Merge branch 'worktree-agent-a8e79b96dd5f070e9' into dev
afit21 Oct 20, 2026
7142df2
Security test index: the 0.2.0 fuzz tests' commit
afit21 Oct 20, 2026
7780ca0
Report the clock only when it looks behind, not ahead
afit21 Oct 20, 2026
cd95d78
Report the record store's capacity from the room left in its budget
afit21 Oct 20, 2026
9b1c653
Changelog: rewrap a line
afit21 Oct 20, 2026
ce3e25d
Say what a long first start after the upgrade is doing
afit21 Oct 20, 2026
92cd81d
Ask the first node of a fetch with /range where a provider would be
afit21 Oct 20, 2026
1248979
Write the daemon's log a line at a time
afit21 Oct 20, 2026
10763e3
Don't log a one-byte answer's size as -1 B
afit21 Oct 20, 2026
1a4701d
Say what the rest of a long start is doing, and fix the move's reports
afit21 Oct 20, 2026
a92fb5e
Try a local server once more when no link to it could be opened
afit21 Oct 20, 2026
0af1e51
Close a link the other end lost after one unanswered request
afit21 Oct 20, 2026
be69c5f
Start a fetch's search with the provider records held here
afit21 Oct 20, 2026
6b269aa
Accept links only once the node can answer requests on them
afit21 Oct 20, 2026
cb89212
Mark for the heal republish what a node publishes after starting cut off
afit21 Oct 20, 2026
a61fbbd
Hardware test results: LoRa between two RNodes, and cloud upgrades
afit21 Oct 20, 2026
053f2e0
Refuse links and requests from the start of a stop
afit21 Oct 20, 2026
0dafaa6
Fix what a review found in this round's LoRa fixes
afit21 Oct 20, 2026
90850fc
Hardware test results: the 30 MB cloud transfer and an idle hour at 9…
afit21 Oct 20, 2026
70bf23f
Fix the rest of a review of the 0.2.0 status and upgrade reports
afit21 Oct 20, 2026
d95a2d8
Don't publish a slow node's downloads unless its user asks
afit21 Oct 20, 2026
17bc360
Look for more providers during a long fetch
afit21 Oct 20, 2026
8509b9d
README: set local_hops to 1 on a node one radio hop from its gateway
afit21 Oct 20, 2026
3f7a229
Security tests: H2's roots check reads the node's strategy, now that …
afit21 Oct 20, 2026
7bd50b7
Ask a provider with no path again a minute later before failing it
afit21 Oct 20, 2026
2d496e2
Fix what a review found in searching again and the unreachable retry
afit21 Oct 20, 2026
7958129
Deny the raw CID a file-hash entry names
afit21 Oct 20, 2026
00660d7
Don't read a DAG already memoised complete when warming a collection
afit21 Oct 20, 2026
5da2c3c
Walk each pin once at a start, and decode DAG nodes without re-encoding
afit21 Oct 20, 2026
31bbeba
Tests: a one-block file denied by its hash is now refused before it i…
afit21 Oct 20, 2026
2b3318c
Count apart the blocks nothing used that a cache rm collects
afit21 Oct 20, 2026
52e40c1
Send Server: rnfs, without the trailing space an empty sys_version left
afit21 Oct 20, 2026
2f422ec
Take an exited daemon not yet reaped as stopped
afit21 Oct 20, 2026
6760409
Installer: refuse a missing local RNFS_SOURCE cleanly; Python on Ubun…
afit21 Oct 20, 2026
e67395d
Say "removed from rnfs.toml" for config unset
afit21 Oct 20, 2026
ef6f696
Hardware test results: the second round
afit21 Oct 20, 2026
9aa3d7d
Say why a heal republish starts: at the first off-island contact afte…
afit21 Oct 21, 2026
6ca2a04
Count a block's ranges in a job's progress as they arrive
afit21 Oct 21, 2026
d5779bf
Log a shared instance's refused RPC (rnsd restarting) as verbose, not…
afit21 Oct 21, 2026
2458391
Give a get job its total from the root, before the sealed check reads…
afit21 Oct 21, 2026
51e07a2
Use providers from lookup answers that arrive after the run ended; co…
afit21 Oct 21, 2026
3d81e9d
Tests: a sealed get's total is told twice, the same; name the late-an…
afit21 Oct 21, 2026
f85a9b8
Hardware test results: the third round
afit21 Oct 21, 2026
1a34a69
REL-1: a missing path doesn't reset a provider's lost count, so alter…
afit21 Oct 21, 2026
4288e10
REL-2: answer a request for nothing served without a response slot, s…
afit21 Oct 21, 2026
744e8cb
REL-3: drop a request that isn't [time, path hash, data] before RNS i…
afit21 Oct 21, 2026
192c4c7
Spec: a one-block file's hash entry denies its block wherever it is, …
afit21 Oct 21, 2026
3849a43
REL-4: refuse a tar member of negative size on every interpreter
afit21 Oct 21, 2026
d90cd7d
REL-5, REL-7: a link closed before an answer shows no /range handler;…
afit21 Oct 21, 2026
4ef96b8
REL-6: a partial block the disk can't keep or give back is asked whol…
afit21 Oct 21, 2026
61b67c3
REL-8: refuse adding a file inside the rnfs dir reached by another na…
afit21 Oct 21, 2026
3c84f4a
REL-9: gateway documents are revalidated rather than cached as immuta…
afit21 Oct 21, 2026
9f6ac19
REL-10: name a get job's write-out after the job, so a resumed run re…
afit21 Oct 21, 2026
b2d9cd9
REL-11: only time spent waiting counts towards giving up a retry, not…
afit21 Oct 21, 2026
ac5f9b8
Keep a long fetch's first search and its latest 8, not every one
afit21 Oct 21, 2026
b47d8c9
Say the daemon is starting, not that it has no token, while a process…
afit21 Oct 21, 2026
5404214
REL-12: under the default cap, the next response may start twice the …
afit21 Oct 21, 2026
e216954
REL-13: give back the write-budget row of a withdrawal undone before …
afit21 Oct 21, 2026
52d3936
REL-5: keep a node known to answer /range known through lost ranges; …
afit21 Oct 21, 2026
29b95b4
REL-14: the keeper store and its queries count the name floor, so a l…
afit21 Oct 21, 2026
6d01750
REL-15: the clock-offset estimate is the senior servers' once there a…
afit21 Oct 21, 2026
da478f1
REL-16: drop the folder sync of a name whose key was deleted by hand,…
afit21 Oct 21, 2026
b3f099b
Security index: the 0.2.0 release audit; the request guard marks what…
afit21 Oct 21, 2026
5026998
REL-17: what fuzzing the gateway, API, settings and tar streams found
afit21 Oct 21, 2026
24a758e
Security index: REL-17's commit
afit21 Oct 21, 2026
9805291
REL-19: a provider whose response stopped arriving partway is asked i…
afit21 Oct 21, 2026
c699841
REL-18: JSON or TOML nested too deeply to parse is damage like any th…
afit21 Oct 21, 2026
d2bf474
REL-18: a publisher whose 0.1.x provider times are infinite upgrades …
afit21 Oct 21, 2026
1732760
REL-18: an LXMF inbox or outbox file's next_id below 1 counts as miss…
afit21 Oct 21, 2026
3c1870b
REL-18: provider rows whose key isn't an ID are never read, and a sta…
afit21 Oct 21, 2026
14dbacc
REL-18: a cut-short round's item list that doesn't parse is malformed…
afit21 Oct 21, 2026
ede887e
REL-18: partial blocks are kept in memory when <state dir>/partial is…
afit21 Oct 21, 2026
c37ecb4
REL-18: CHANGELOG: damaged local state no longer stops the node
afit21 Oct 21, 2026
0351584
Hardware test results: the release audit's soak and LoRa rounds
afit21 Oct 21, 2026
cc5ffd8
Drop Raspberry Pi SD-card numbers from the release checklist and the …
afit21 Oct 21, 2026
2938ce1
A search's query unanswered past patience gives up its place, so serv…
afit21 Oct 21, 2026
2546a84
Hardware test results: the island search fix on LoRa
afit21 Oct 21, 2026
4c7575f
Refuse an announce, republish or scan interval so short it would run …
afit21 Oct 21, 2026
50e0768
Read an rnfs.toml that starts with a UTF-8 byte-order mark
afit21 Oct 21, 2026
0c5fa0d
REL-20: a /range provider that disowns a block it was sending is scor…
afit21 Oct 21, 2026
0fce56f
Security index: REL-20's commit
afit21 Oct 21, 2026
df4cdaa
API: no body after HEAD's headers; integers, Content-Length and quiet…
afit21 Oct 21, 2026
9109d4e
Raise an interval under its minimum in rnfs.toml to it with a warning…
afit21 Oct 21, 2026
a6ef02e
feat: Enhance job progress reporting with provider details and search…
afit21 Oct 21, 2026
6b5ab3a
Path requests keep their spacing when a waiting thread oversleeps its…
afit21 Oct 21, 2026
b7194d1
Tests: hold on macOS and Python 3.14 (bsdtar's decomposed names, json…
afit21 Oct 21, 2026
91abfc8
CI: give the unit tests 45 minutes; Windows takes up to 32
afit21 Oct 21, 2026
0bd6eee
An explicit fetch that found no provider searches once more before it…
afit21 Oct 22, 2026
814666c
rnfs 0.2.0
afit21 Oct 22, 2026
e1e5bd4
CI: give the unit tests 60 minutes; a slow Windows runner took 45
afit21 Oct 22, 2026
7f29ca5
Enhance security checks with Bandit configuration and update test ass…
afit21 Oct 22, 2026
5af3d4c
Add Bandit to the Flatpak manifest for enhanced security analysis
afit21 Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ updates:

# Report only: open-pull-requests-limit 0 turns off version-update pull requests for pyproject.toml's
# dependencies, while a vulnerable one is still reported (Dependabot alerts and security updates, once turned on
# in the repository's settings). rnfs relies on RNS and LXMF internals, so a new version is taken deliberately:
# in the repository's settings). rnfs relies on RNS internals, so a new version is taken deliberately:
# packaging/update-lock.py, packaging/flatpak/generate-sources.py and tests/test_rns_compat.py (CONTRIBUTING.md)
- package-ecosystem: pip
directory: /
Expand Down
14 changes: 10 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches: ["**"] # not tags: the release workflow runs these jobs itself before publishing
pull_request:
workflow_call: # from release.yml, which grants no more than contents: read
workflow_dispatch: # by hand, on any branch: Actions > tests > Run workflow, to try macOS and Windows before a PR

# Read-only token: these jobs only check out and test the code
permissions:
Expand Down Expand Up @@ -35,17 +36,22 @@ jobs:
python -m pip install --require-hashes --only-binary=:all: -r packaging/build-backend.lock
python -m pip install --no-deps --no-build-isolation .
python -m pip check
# tests/ci_run.py runs `unittest discover tests`, then once more, alone, any test that failed (up to 5): one
# that passes then is named in a warning on the run's page and summary instead of failing the run
- name: Unit tests
run: python -m unittest discover tests
run: python -m tests.ci_run
# Windows takes 23-45 minutes as its runners vary (Linux and macOS about 9): 30 and then 45 stopped runs whose
# every test passed
timeout-minutes: 60
# On Windows the daemons are started in their own process groups and stopped with CTRL_BREAK_EVENT. Every
# module gated on RNFS_E2E is listed here (test_packaging checks it): the embedded node and the security
# regressions that need real RNS included
- name: End-to-end tests (real daemons over local TCP)
env:
RNFS_E2E: "1"
run: >-
python -m unittest tests.test_e2e tests.test_client tests.test_embedded tests.security.test_h1_real_rns
tests.security.test_m1_real_rns tests.security.test_h2_display_page_pins
python -m tests.ci_run tests.test_e2e tests.test_client tests.test_embedded tests.security.test_h1_real_rns
tests.security.test_m1_real_rns tests.security.test_h2_display_page_pins tests.test_nomadnet_e2e
timeout-minutes: 20
- name: Command works
run: rnfs --version
Expand All @@ -70,7 +76,7 @@ jobs:
- name: Tests under coverage
env:
RNFS_E2E: "1"
run: python -m coverage run --source=rnfs -m unittest discover tests
run: python -m coverage run --source=rnfs -m tests.ci_run
timeout-minutes: 30
- name: Report
run: python -m coverage report --sort=cover
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ build-dir/
.coverage
.coverage.*
htmlcov/
bandit/
980 changes: 979 additions & 1 deletion CHANGELOG.md

Large diffs are not rendered by default.

65 changes: 53 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ Compatibility rules every change keeps:
```sh
git clone https://github.com/afit21/rnfs && cd rnfs
python3 -m venv .venv && . .venv/bin/activate
pip install --require-hashes --only-binary=:all: -r packaging/requirements.lock # rns, lxmf and theirs
pip install --require-hashes --only-binary=:all: -r packaging/requirements.lock # rns and its dependencies
pip install --require-hashes --only-binary=:all: -r packaging/build-tools.lock # ruff, coverage, build, ...
pip install --no-deps --no-build-isolation -e .
```

The library and the CLI use the standard library besides RNS and LXMF; `rnfs.apiclient`, `rnfs.remote`
The library and the CLI use the standard library besides RNS; `rnfs.apiclient`, `rnfs.remote`
(rnfs.Client) and the modules they import never import RNS. Keep it that way.

## Tests
Expand All @@ -42,17 +42,23 @@ variables:

| Variable | What it turns on |
|---|---|
| `RNFS_E2E=1` | Real daemons and real RNS over local TCP, driven through the CLI or the library. Run them with `RNFS_E2E=1 python3 -m unittest tests.test_e2e tests.test_client tests.test_embedded tests.security.test_h1_real_rns tests.security.test_m1_real_rns tests.security.test_h2_display_page_pins` (3 to 4 minutes). CI's end-to-end step lists every module gated on it, and `tests/test_packaging.py` fails if a new one is missing from that list. |
| `RNFS_E2E=1` | Real daemons and real RNS over local TCP, driven through the CLI or the library. Run them with `RNFS_E2E=1 python3 -m unittest tests.test_e2e tests.test_client tests.test_embedded tests.security.test_h1_real_rns tests.security.test_m1_real_rns tests.security.test_h2_display_page_pins tests.test_nomadnet_e2e` (3 to 4 minutes). CI's end-to-end step lists every module gated on it, and `tests/test_packaging.py` fails if a new one is missing from that list. |
| `RNFS_FUZZ_EXAMPLES=N` | A deeper, randomized run of `tests/security/test_fuzz_parsers.py` (e.g. 3000 examples per parser). That module needs hypothesis, which isn't one of rnfs's dependencies: without it every test there is skipped, as in CI. |
| `RNFS_BENCH=1` | Prints the FastCDC chunking rate measured by `tests/test_chunker.py` (the test itself only checks a floor). |
| `RNFS_ECLIPSE=1` | A larger run of `tests/test_eclipse.py` (identities placed next to a key: 2,000 servers, more keys, slow nodes too, about 1.5 minutes) that prints what it measured: findability under attack, false positives, `/find` and stores per search and publish. |

`tests/bench_block_writes.py` is a benchmark, not a test: run it by hand on the disks that matter (its docstring
says how, including on a Raspberry Pi SD card). Performance changes record their before and after numbers in
CHANGELOG.md.
says how, including on a Raspberry Pi SD card). So is `tests/bench_startup.py`, which times opening a large block
store at startup (after a clean stop, after a crash, and the first start on 0.1.6's layout), and
`tests/bench_publisher.py`, which measures what each provided key costs the publisher (memory, disk, writes per
round) and how long a wake takes, and `tests/bench_refresh.py`, which times a start's first walk of every pin for
what the node serves and provides (a store of about 565,000 blocks, a Gutenberg-like folder among its pins).
Performance changes
record their before and after numbers in CHANGELOG.md.

`tests/interop.py` is a manual cross-version check, not a test either: it runs this tree's daemons against daemons
of older releases over local TCP, in both directions, and prints a PASS/FAIL table (providers, get and cat,
transfers with and without `max_upload_rate` checked for refusals, names, keepers, LXMF). Run it before a release
transfers with and without `max_upload_rate` checked for refusals, names, keepers). Run it before a release
with each supported old release extracted by `git archive`:

mkdir -p /tmp/rnfs-0.1.5 && git archive v0.1.5 | tar -x -C /tmp/rnfs-0.1.5
Expand All @@ -72,6 +78,32 @@ Tests that guard compatibility, and must stay green:
Never weaken or delete a test to make a change pass. If a change deliberately alters behaviour a test encodes,
change the test in the same commit and say why in the commit message.

### Tests on every OS

CI runs every test on Linux, macOS and Windows, and nearly every CI failure so far was a test written and run only
on Linux. So:
- **Paths.** Compare a path the code resolved with one the test built through `tests.support.real()`: macOS
reaches the temp directory through `/private/var`, and Windows may name it `RUNNER~1`. Write `/` in an expected
path only where the code does.
- **POSIX-only APIs** (`os.geteuid`, `os.fchmod`, `os.mkfifo`, `resource`, `fcntl`, signals Windows lacks, and the
rest of the list in `pyproject.toml`) fail ruff (TID251) unless the line says what guards it: `# noqa: TID251 -
<the guard>`. Skip a test with `tests/support.py`'s `POSIX_MODES`, `PERMISSION_CHECKS`, `IS_ROOT`, `HAS_FIFO` or
`CAN_SYMLINK`.
- **Files.** Windows keeps no execute bit, can't remove or replace a file another handle has open (close stores,
databases and nodes before the temporary directory is removed), and reads `\` or `C:` in a name as a path; a link
to a directory needs `target_is_directory=True` and is removed with `os.rmdir` there. macOS refuses names that
aren't UTF-8, and paths over 1024 bytes.
- **Time.** Wait for a condition with `support.wait_for(..., what=...)`, never a fixed sleep: without `what=` its
result is all that can fail, so a call that ignores it must name what it waits for (`tests/test_suite_rules.py`
checks). Leave upper bounds a wide margin (CI's macOS runners are several times slower than a desktop) and lower
bounds a tick of slack (Windows' clock ticks every 15.6 ms before Python 3.13).

CI runs each test that failed once more, alone, in a fresh process (`tests/ci_run.py`, up to 5 of them): one that
then passes doesn't fail the run, but is named in a warning on the run's page and summary. Fix it: it will fail
again. To run CI on a branch before a pull request, use Actions > tests > Run workflow. Every push to any branch
runs it too, so push work in progress often: a release that brings weeks of commits to macOS and Windows for the
first time is what has made releases fail.

### Security regression tests

Every security fix comes with a regression test in `tests/security/test_<id>_<what>.py` (for example
Expand All @@ -89,7 +121,8 @@ ruff check .
```

A broad `except Exception` in `rnfs/` carries `# noqa: BLE001 - <why it must catch everything>`, an import that
can't be at the top `# noqa: E402`, and RUF100 flags a `noqa` that suppresses nothing. The companion NomadNet
can't be at the top `# noqa: E402`, a use of an API Windows lacks `# noqa: TID251 - <the guard>` ("Tests on every
OS", above; the same holds in `rnfs/`), and RUF100 flags a `noqa` that suppresses nothing. The companion NomadNet
pages (`companion-nomadnet-sites/*/index.mu`) are linted as Python. CI also fails on merge-conflict markers.

Style: match the surrounding code. Every function has a docstring, comments say why rather than what, and lines
Expand All @@ -102,7 +135,7 @@ versions:

| File | What | Regenerate with |
|---|---|---|
| `packaging/requirements.lock` | rnfs's runtime dependencies (rns, lxmf and theirs), every file PyPI has for each | `python3 -I packaging/update-lock.py [rns==X lxmf==Y ...]` (no arguments: the newest versions `pyproject.toml` allows) |
| `packaging/requirements.lock` | rnfs's runtime dependencies (rns and its dependencies), every file PyPI has for each | `python3 -I packaging/update-lock.py [rns==X ...]` (no arguments: the newest versions `pyproject.toml` allows) |
| `packaging/build-backend.lock`, `packaging/build-tools.lock` | setuptools; and build, twine, PyInstaller, ruff, coverage and their dependencies | `python3 -I packaging/update-lock.py --build pyinstaller==X ...` (run it on Linux with Python 3.12) |
| `packaging/flatpak/python3-deps.json`, `build-sources.json` | the Flatpak's wheels, from the locks | `python3 -I packaging/flatpak/generate-sources.py` |

Expand Down Expand Up @@ -151,7 +184,14 @@ route touches these places:
tested on both by `tests/test_public.py`.
5. The CLI command, if any (`rnfs/cli.py`, or the feature's own commands), through `ApiConnection` rather than
a hand-written path.
6. Tests of the handler (`tests/test_api.py` or the feature's test file), and a CHANGELOG line.
6. The OpenAPI reference, `docs/openapi.json`: the operation (method and path, `operationId`, a feature's
route tagged with and `x-rnfs-feature` naming its feature), its parameters or request body, its answer's
schema and the statuses it answers; `X-Rnfs-Pin-Key` if it pins for the caller; a new error code, event kind or
capability in `ErrorCode`, `EventKind` and `Event`, or `Capabilities`. A new field in `GET /api/status` goes
into the status part that produces it (`StatusCore` for the node's, `Status<Feature>` for a feature's; a new
feature adds a part to `Status`'s `allOf`). `tests/test_openapi.py` fails, naming it, on a route, code, kind
or capability missing, and its live checks on a field the answers carry that isn't documented.
7. Tests of the handler (`tests/test_api.py` or the feature's test file), and a CHANGELOG line.

## Commits

Expand All @@ -174,7 +214,8 @@ Steps:
1. Go through the checklist below.
2. Set `__version__` in `rnfs/__init__.py` to X.Y.Z, change CHANGELOG.md's first heading from
`## X.Y.Z (unreleased)` to `## X.Y.Z`, and update README's release links and file names
(`tests/test_packaging.py` checks the three agree).
(`tests/test_packaging.py` checks the three agree), and `info.version` in `docs/openapi.json`
(`tests/test_openapi.py`).
3. Commit, let CI pass on `main`, then push the tag: `git tag vX.Y.Z && git push origin vX.Y.Z`. The workflow
refuses a tag that isn't `v` + `__version__`, and a CHANGELOG whose section for it is still marked
unreleased.
Expand All @@ -195,8 +236,8 @@ Steps:
- [ ] Every security fix has its `tests/security/test_<id>_*.py` regression test, and `tests/security/README.md`
lists it.
- [ ] CI runs every `RNFS_E2E` module. Lint passes.
- [ ] Before and after numbers for the performance changes (a desktop NVMe disk and a Raspberry Pi SD card),
recorded in CHANGELOG.md.
- [ ] Before and after numbers for the performance changes, on a desktop disk, recorded in CHANGELOG.md
(Raspberry Pi SD-card numbers aren't a release requirement).
- [ ] specification.md updated for every change in behaviour, with its version and compatibility note at the top.
- [ ] design.md updated for every change in how things work.
- [ ] CHANGELOG.md's entry states whether the wire format or CIDs changed ("no wire-format or CID changes"),
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ prune packaging
# ...except the dependency lock, which install.sh uses when installing from an sdist
include packaging/requirements.lock
include packaging/build-backend.lock
# The local API's OpenAPI reference, for app authors
include docs/openapi.json
# The example program for the public API (rnfs.Node, rnfs.Client)
recursive-include examples *.py
Loading
Loading