Russ Allbery: Review: Too Like the Lightning
| Series: | Terra Ignota #1 |
| Publisher: | Tor |
| Copyright: | May 2016 |
| ISBN: | 1-4668-5874-5 |
| Format: | Kindle |
| Pages: | 432 |
| Series: | Terra Ignota #1 |
| Publisher: | Tor |
| Copyright: | May 2016 |
| ISBN: | 1-4668-5874-5 |
| Format: | Kindle |
| Pages: | 432 |
Another new release of the gaussfacts package
arrived on CRAN. This follows a
recent one a good week ago, which had been the first in pretty much
exactly a decade!
gaussfacts
provides a fortunes-inspired
function to display randomly-chosen facts about Carl Friedrich
Gauss, based on the collection curated by Mike Cavers via the gaussfacts web site (with an archive.org link
it case it vanishes again). Each call of gaussfact()
displays another (randomly chosen, or indexed) fact.
This release corrects an old typo, thanks to an issue filed right
after the last release. It also adds a small (but useful) feature that
(most if not all of) the other fortunes-alike packages
already have: the ability to look up by (matching) character string.
So to take an example, asking for dice gets us these two cracker
quotes that still make me smile:
> gaussfacts::gaussfact("dice") # match string
God does not play dice, unless Gauss promises to let him win once in a while.
God does not play dice with the universe, but Gauss does.
> Otherwise, and always worth noting, this update had a particularly speedy passage at CRAN taking a whole six minutes:Changes in version 0.0.4 (2026-09-01)
- Support character argument to support lookup via regular expression
- Correct one old typo in README.md
Thanks to my CRANberries, there
is a diff to the previous
release. Questions, comments etc should go to the GitHub issue
tracker off the GitHub repo.
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.
I ve been a Debian user since 1999, and a Debian developer since 2000. Given recent events it s worth thinking about why that that is, and why I haven t switched to something else in the past quarter century.
My first Linux distro was Slackware, off a CD in a book, some time in the mid 90s. After starting university I ran SUSE for a while, then moved to RedHat (both back before they had commercial variants significantly different to what was available freely). The main motivation for switching was package management; I was running a machine at home, and a machine at university. Keeping track of what was installed on each, and what versions, was getting annoying with Slackware. Most of the folk I knew were running RedHat, and I mostly played with SUSE because I m contrary before realising it was different enough that I couldn t easily make use of 3rd party RPMs.
I came to Debian via friends in Cambridge, who spoke highly of it. The first Debian machine I installed was fourier, the initial host for Black Cat Networks, and I never looked back.
(For additional context I should also point out I have contributed, in the distant past, to, and run, OpenWRT, OpenEmbedded, and FreeBSD.)
I d like to try and work out what is it I get from Debian that I d need in anything else. Originally I tried to order the requirements in some sort of priority, but it s sometimes hard to work out what I d drop if I had to compromise somewhere, so it s a somewhat loose ordering.
It is widely accepted that there is an AI bubble in the financial markets at the moment. The moderate opinion is however that LLMs are constantly improving and will eventually take over more and more tasks from humans and increase productivity. But are LLMs actually getting smarter, or just better at fooling us?
There is a growing faction of technical experts that argue that LLMs are actually so bad for real progress, that they are banning their use and requiring human-only work to ensure quality and efficient use of humans time. A recent review of AI policies of 120 open source projects by Rakshit Yadav shows that 37 chose to have a total AI ban. In the Linux kernel AI-assisted contributions are allowed, but the LLM used needs to be attributed for transparency, while projects like GCC, QEMU, SDL, Gentoo, Zig and Ghostty have adopted policies to reject all AI-assisted contributions. There are also development platforms such as Codeberg and Sourcehut and app stores like Flathub that have banned AI use to generate software, documentation, bug reports, review comments and basically anything that is intended for humans to read. The projects that allow AI use typically still require that there must be a human-in-the-loop and the submitter must have read and filtered everything the LLM spits out before another human is exposed to it, in an effort to contain the spread of AI slop.
Right now, the Linux distribution Debian is having a vote among its developers on whether AI should be allowed or banned for use to contribute to Debian. One of the proposals on the ballot is a total ban of AI for code, documentation, translations, bug reports and more. The initial reaction from most people is astonishment why don t these techies want to use the latest and greatest technology mankind has produced so far? Is it that they don t want Debian to improve faster with the help of AI? Or is it actually so that LLMs are a scam and incapable of being truly useful for Debian? These people are distinguished experts in their own field, and certainly not stupid, so it is worth pausing to understand why they are proposing AI banning policies.
Also, keep in mind that the AI datacenters themselves run on Debian or other Linux-based systems. All the open source software in the world has been fed to LLMs and software development is one of the main use cases for AI currently. So why is it that the maintainers of many open source projects don t want to receive LLM-assisted contributions, despite the LLMs basically all running on top of those same software stacks and having been trained on how to do software development using the very same open source software codebases?
| A | G | C | H | F | D | B | E | |
|---|---|---|---|---|---|---|---|---|
| LLM harms | Robustly discussed | Discussed | Robustly summarised | Robustly discussed; especially re climate | Summarised | Accepted as inevitable | Disregarded [1] | Ignored |
| Direct contributions of LLM-generated code | Forbidden | Forbidden | Strongly discouraged | Strongly discouraged | Discouraged | Permitted | Permitted | Permitted |
| Direct use of LLM output in communications (bugs, mailing lists, etc.) | Forbidden | Forbidden | Forbidden (with possible exceptions) | Strongly discouraged | Discouraged | Permitted | Permitted | Permitted |
| LLM use where LLM output does not end up in the code/message | Forbidden | No position, so permitted | Strongly discouraged | Strongly discouraged | Discouraged | Permitted | Permitted | Permitted |
| Disclosure of LLM use | LLM use forbidden | LLM use largely forbidden, no further disclosure requirement | Disclosure required | Disclosure encouraged | Disclosure encouraged | Disclosure required | Disclosure required | Undisclosed LLM use is OK |
| Use of LLMs by upstreams | Condemned | Not recommended | ||||||
| Positive statements about LLMs | Here to stay | Moderate | Strong |
Also in this series:After ranting and railing about LLMs or "AI" as the optimists (or accelerationists?) call it, I figured it might be important to be a little more honest about my use of LLMs and how I think about it more practically in the world.
llm: a CLI utility and Python library for interacting with
Large Language Models, with OpenAI as its default API backendllm-anthropic: a plugin for llm which allows me to talk to
Anthropic's API instead of OpenAIanthropic-sdk-python: the SDK llm-anthropic requires to do
its workllm to the contrib section of Debian, where we keep
software that depends on other non-free software, but I was told that,
since yt-dlp was in main, llm belonged there as well.
So I moved it to main, alongside similarly controversial tools
like llama.cpp or the python-openai library.
gptel, a "simple, extensible LLM client for
Emacs" but I found it kind of terrifying. Giving a LLM control over an
Emacs buffer seems like a security nightmare, so I stopped doing
that.
So I use the llm command-line tool to talk to Anthropic's API. I
started that in the summer of 2025, when I bought 20$USD of API
credits. Before that, I paid for a ChatGPT subscription and then
OpenAI credits, which expired and sent me over to Anthropic, which
seemed then to have better ethics.
As it turns out, Anthropic is also happy to work for the US military
(which is a big red line for me). Anthropic also won't let you talk
about the genocide in Gaza, it is destroying physical books,
and is blackmailing us to use their product for security
coverage.
Needless to say, Anthropic and "Claude" are not my friends, but they
seem like the lesser evil in current "frontier models". So I have
renewed, a couple of weeks ago, another 20$USD of API credits with
Anthropic.
llm is that everything is logged in a sqlite
database, so there are some answers that are easy to get:
> llm logs status
Logging is ON for all prompts
Found log database at /home/anarcat/.config/io.datasette.llm/logs.db
Number of threads logged: 7
Number of turns logged: 12
Number of legacy conversations: 543
Number of legacy responses: 970
Database file size: 9.61MB
That is 10MB of logs, with about a thousand prompts.
My logs go back to 2024-03-07, a little over two years ago, and
include a mix of Anthropic and OpenAI responses. I used it more in
2024 than 2025, and if the trend continues, I will have used it less
in 2026 again:
> llm logs list -n 0 --json jq -r .[].datetime_utc sed 's/-.*//' sort uniq -c
527 2024
357 2025
98 2026
It looks like about 10 prompts per month right now, down from a peak
of about 60 per month in 2024. It's pretty difficult to analyze those
actual logs to get more patterns and I won't run the prompts through a
model again to process them.
llm stack I've
been using. The following two are an attempt at seeing what the model
is capable of and I was "not impressed", to which Claude answered that
I have a "high bar", which, fair enough.
The chat is me failing to use a command line, which shows that
perhaps I need to readjust that "high bar", again.
The next five are a rather embarrassing debacle in a large Postfix
mailing that went sideways, and where I couldn't find an actual
Postfix expert of my level to help. The fabled Claude Fable 5 answered
rather correctly, but dangerously, that I could empty the queue by
disabling the non_smtpd_milters. What Fable (and myself) did not
realize is that the milter was also adding DKIM signatures, so while the
mailing was expedited, it was done without those precious signatures,
which got us promptly blocked at Gmail. We have recovered since, and,
thanks to the model and reading the Postfix manual for the
hundredth time, that pickup(8) is single-threaded and that we
needed to review the architecture of that mailing (and our spam
filters) a bit. Many tickets ensued.
The last one is a test I did to make sure my last uploads of
llm-anthropic and its dependency worked correctly.
Note that the above excludes 5 questions I asked Anthropic while writing this article, where I asked for synonyms and "what nanometer scale are arduino processors built from? how is an arduino CPU printed?", a question which Wikipedia furiously evades providing a good answer.Those prompts are pretty typical of my LLM use: I'm testing the models to see if they work at all, but also, out of desperation, I fire off a prompt after I fire off questions to colleagues or search engines (in that order). It's often weird edge cases like the Prometheus query language, Python's matplotlib, LaTeX, Elisp, optimizations, and so on. I use models for translation a lot. Being fully bilingual, it is common for me to think of a word in French or English and fail to find exactly the right word for that in the other language. Models help with that, and are also useful to find synonyms. Those are low-token uses that seem pretty innocuous to me, but I realize the irony of this after writing about the tower of Babel.
asncounter into Claude to try to fix a
performance regression I had introduced. It found micro-optimizations
that taught me a thing or two about Python's internal implementations,
but overall, it was mostly a waste of time. This was in June 2025, so
perhaps now models would fare better. I have not tried again.
I am not using LLMs to do Debian packaging. When I can, I manually
review the diffs of packages I upload into Debian, still, by hand.
I do this for the reasons outlined in The Four Horsemen of the LLM
Apocalypse, because I refuse to be
complicit in the:
llm toolset, which is more and more
vibe-coded, but I still review the diffs. And I have to say: I
trust Simon here. The code is verbose as hell, feels overengineered,
and llm feels slow, but it generally works, and Simon is still at
the gate.
The Anthropic SDK is another thing entirely. The 0.91.0 to 0.120
upload, for example, was nuts:
806 files changed, 72281 insertions(+), 1478 deletions(-)
I explicitly did not review that entire diff. It feels like there's a
lot of garbage there to just have a shim between a proprietary API and
Python. But this is the hand I've been dealt.
rsync, Rust, and
other places. I don't feel good about this, particularly in Rust, but
they at least made a decent policy. I am glad GCC made a policy
against LLM contributions and I support the human Emacs
project.
We need to have a set of foundational tools that are "clean" in the
sense that they are built upon a community of people that understand
how they are built.
Maybe that's naive or even impossible. The Linux kernel and GCC, in
particular, are massive projects that have long grown past the scale
of a single person's understanding. But the theory was that a
community of humans can understand collectively.
Now we seem to be throwing up our hands and giving up on
that community. That LLMs will just fix the problem, whatever it
is. But we're all just one rug pull away from being completely
incapable of managing those projects. The argument there is that we'll
just switch to local models, but no one is actually doing that.
All I see is people use local models as a corner case
(for privacy) or as in theory, but in reality, everyone uses the
centralized frontier models right now. We just can't fallback.
We're in the same situation we were, a decade or two ago, when
Microsoft decided it would kill free office alternatives by making
Office free for non-profits. It worked: thousands, if not millions of
schools, community groups and individuals stopped looking for
alternatives (including free software but also "piracy") for Office
and embraced what seemed like a generous offer.
Now Microsoft pulled the plug and Over 170,000 Nonprofits Lost All
Their Data.
I'm afraid the rug pull on LLMs will be much worse: never mind that
Linus won't be able to use his tireless helper to fix obscure kernel
bugs; we're looking at a collapse of the economy so large that we are
already talking about bailing out the companies responsible.
In a sense, the most striking thing about the Debian vote is it has
actually no option to completely refuse upstream LLM contributions. It
seems the community has taken it for granted that it's now impossible
to build Debian entirely without LLMs. We lost the battle even without
a fight, it seems.
A new release of gaussfacts package
arrived on CRAN the first in
pretty much exactly a decade! gaussfacts
provides a fortunes-inspired
function to display randomly-chosen facts about Carl Friedrich
Gauss, based on the collection curated by Mike Cavers via the gaussfacts web site (with an archive.org link
it case it vanishes again). Each call of gaussfact()
displays another (randomly chosen, or indexed) fact.
An example:
This releases, as detailed below, accumulates a number of smaller
maintenance changes including switching to Authors@R. Functionality has
not changed. Oddly enough, it appears that I did not blog about the
package when I created it in August 2016. So to (partially) make up for
that, the NEWS for all three releases follow.
Thanks to my CRANberries, there is a diff to the previous release. Questions, comments etc should go to the GitHub issue tracker off the GitHub repo.Changes in version 0.0.3 (2026-08-23)
- Several rounds of continuous integration maintenance and enhancements
- Additional README.md badges
- Updates to DESCRIPTION as CRAN requirements change
- A duplicate data entry has been removed (Tim Pokart in #4)
- Documentation prefers https URLs
- Updated continunous integration multiple times
- Correct man page removing an erroneous duplicate word
Changes in version 0.0.2 (2016-08-03)
- Support 'ind' argument to reference by position
- Clean-up encoding and support extended character set (#2 closes #1)
- Updated continunous integration (#3)
Changes in version 0.0.1 (2016-06-19)
- Initial version and CRAN upload
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.
Warning This post contains interactive examples. To visualize and interact with them, you need to leave your RSS reader.
:demo
A1 @0,0 prio=4096
A2 @0,1
A3 @0,2
A4 @0,3
B1 @1,0 prio=8192
B2 @1,1
B3 @1,2
B4 @1,3
C1 @2,0 prio=8192
C2 @2,1
C3 @2,2
C4 @2,3
A1 -- A2 hazard=0
A2 -- A3 hazard=0
A3 -- A4 hazard=0
B1 -- B2
B2 -- B3
B3 -- B4
C1 -- C2 hazard=0
C2 -- C3 hazard=0
C3 -- C4 hazard=0
A1 -- B1 cost=10
B1 -- C1 cost=10
A4 -- B4 cost=20
B4 -- C4 cost=20
Leo @-0.3,0.7 proto=none icon=
Mia @-0.3,1.3 proto=none icon=
Joy @0.3,0.7 proto=none icon=
Roy @0.3,1.3 proto=none icon=
A2 -- Leo hazard=0 A2:edge
A2 -- Mia hazard=0 A2:edge
A2 -- Joy hazard=0 A2:edge
A2 -- Roy hazard=0 A2:edge
Max @-0.3,1.7 proto=none icon=
Zoe @-0.3,2.3 proto=none icon=
Ada @0.3,1.7 proto=none icon=
Amy @0.3,2.3 proto=none icon=
A3 -- Max hazard=0 A3:edge
A3 -- Zoe hazard=0 A3:edge
A3 -- Ada hazard=0 A3:edge
A3 -- Amy hazard=0 A3:edge
Eli @0.7,0.7 proto=none icon=
Jay @0.7,1.3 proto=none icon=
Kai @1.3,0.7 proto=none icon=
Ben @1.3,1.3 proto=none icon=
B2 -- Eli hazard=0.2 B2:edge
B2 -- Jay hazard=0.2 B2:edge
B2 -- Kai hazard=0.2 B2:edge
B2 -- Ben hazard=0.2 B2:edge
Ava @0.7,1.7 proto=none icon=
Lea @0.7,2.3 proto=none icon=
Ivy @1.3,1.7 proto=none icon=
Rex @1.3,2.3 proto=none icon=
B3 -- Ava hazard=0.2 B3:edge
B3 -- Lea hazard=0.2 B3:edge
B3 -- Ivy hazard=0.2 B3:edge
B3 -- Rex hazard=0.2 B3:edge
Ana @1.7,0.7 proto=none icon=
Eve @1.7,1.3 proto=none icon=
Abe @2.3,0.7 proto=none icon=
Ian @2.3,1.3 proto=none icon=
C2 -- Ana hazard=0 C2:edge
C2 -- Eve hazard=0 C2:edge
C2 -- Abe hazard=0 C2:edge
C2 -- Ian hazard=0 C2:edge
Ned @1.7,1.7 proto=none icon=
Lou @1.7,2.3 proto=none icon=
Fay @2.3,1.7 proto=none icon=
Sue @2.3,2.3 proto=none icon=
C3 -- Ned hazard=0 C3:edge
C3 -- Lou hazard=0 C3:edge
C3 -- Fay hazard=0 C3:edge
C3 -- Sue hazard=0 C3:edge
Note This article is also available as a video, but I advise you to keep reading here to try the interactive demonstrations.
:protocol rstp
:tx-hold 10
A1 @0,1
C11 @1,0 prio=4096 icon=
C12 @1,2 prio=4096 icon=
C21 @2,0 prio=4096 icon=
C22 @2,2 prio=4096 icon=
A2 @3,1
H1 @0,0.2 proto=none icon=
H2 @0,1.8 proto=none icon=
H3 @3,0.2 proto=none icon=
H4 @3,1.8 proto=none icon=
A1 -- C11
A1 -- C12
A2 -- C21
A2 -- C22
C11 -- C12
C11 -- C21
C11 -- C21
C11 -- C22
C12 -- C21
C12 -- C22
C21 -- C22
A1 -- H1 A1:edge
A1 -- H2 A1:edge
A2 -- H3 A2:edge
A2 -- H4 A2:edge
Note While you scroll, the current simulation stays in view so you can look at it while reading. Uncheck this box to disable this behavior: .
I think that I shall never see
A graph more lovely than a tree.
A tree whose crucial property
Is loop-free connectivity.
A tree which must be sure to span
So packets can reach every LAN.
First, the root must be selected.
By ID, it is elected.
Least cost paths from root are traced.
In the tree, these paths are placed.
A mesh is made by folks like me,
Then bridges find a spanning tree. Radia Perlman, Algorhyme.
8192.6e:2b:10:a0:5f:29.
In the example below, S1 and S2 have priorities of 4,096 and 8,192: S1 becomes
root. S4 has a priority of 12,288, while S3 keeps the default priority of
32,768:6 S4 becomes root. S5 and S6 don t have a specific priority, so
the lowest MAC address wins and S5 becomes root.
:protocol rstp
S1 @0,0 prio=4096
S2 @0,1 prio=8192
S1 -- S2
S3 @1,0
S4 @1,1 prio=12288
S3 -- S4
S5 @2,0
S6 @2,1
S5 -- S6
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
Root Identifier: 8192.02:00:00:01:00:01
Bridge Identifier: 8192.02:00:00:01:00:01
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
Root Identifier: 4096.02:00:00:00:00:00
Bridge Identifier: 8192.02:00:00:00:00:01
:protocol rstp
S1 @1,0 prio=4096 icon=
S2 @0,1
S3 @2,1
S1 -- S2
S1 -- S3
S1 -- S3
S2 -- S3
0x8000 vs 0x8001. The other
candidate is an alternate port because the remote port on the link sends a
better BPDU, with an accumulated cost of 0. On the segment between S2 and S3,
S2 s port wins: while both bridges have the same accumulated cost to the root
(20,000), S2 s bridge identifier is smaller 32768.02:00:00:00:00:01 vs
32768.02:00:00:00:00:02.
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
Root Identifier: 4096.02:00:00:00:00:00
Root Path Cost: 20000
Bridge Identifier: 32768.02:00:00:00:00:01
Port identifier: 0x8002
:protocol rstp
S1 @1,0 prio=4096 icon=
S2 @1,1
S3 @0,2
S4 @2,2
S5 @0,3 prio=8192 icon=
S6 @2,3
H1 @0,1.2 proto=none icon=
H2 @2,1.2 proto=none icon=
H3 @2.5,1.3 proto=none icon=
H4 @2.5,2.3 proto=none icon=
S1 -- S2
S2 -- S3
S2 -- S4
S3 -- S5
S4 -- S6
S4 -- S3
S5 -- S6
S3 -- H1 S3:edge
S4 -- H2 S4:edge
S4 -- H3 S4:edge
S6 -- H4 S6:edge
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
BPDU flags: 0x4e, Agreement, Port Role: Designated, Proposal
0... .... = Topology Change Acknowledgment: No
.1.. .... = Agreement: Yes
..0. .... = Forwarding: No
...0 .... = Learning: No
.... 11.. = Port Role: Designated (3)
.... ..1. = Proposal: Yes
.... ...0 = Topology Change: No
Root Identifier: 32768.02:00:00:00:00:01
Root Path Cost: 0
Bridge Identifier: 32768.02:00:00:00:00:01
Port identifier: 0x8001
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
BPDU flags: 0x79, Agreement, Forwarding, Learning, Port Role: Root, Topology Change
0... .... = Topology Change Acknowledgment: No
.1.. .... = Agreement: Yes
..1. .... = Forwarding: Yes
...1 .... = Learning: Yes
.... 10.. = Port Role: Root (2)
.... ..0. = Proposal: No
.... ...1 = Topology Change: Yes
Root Identifier: 4096.02:00:00:00:00:00
Root Path Cost: 20000
Bridge Identifier: 32768.02:00:00:00:00:01
Port identifier: 0x8001
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
BPDU flags: 0x4f, Agreement, Port Role: Designated, Proposal, Topology Change
0... .... = Topology Change Acknowledgment: No
.1.. .... = Agreement: Yes
..0. .... = Forwarding: No
...0 .... = Learning: No
.... 11.. = Port Role: Designated (3)
.... ..1. = Proposal: Yes
.... ...1 = Topology Change: Yes
Root Identifier: 4096.02:00:00:00:00:00
Root Path Cost: 40000
Bridge Identifier: 32768.02:00:00:00:00:02
Port identifier: 0x8002

:protocol rstp
S1 @1,0 prio=4096 icon=
S2 @0,1
S3 @1,1
S4 @2,1
S5 @1,2
LPT @0.1,2 proto=none icon=
S1 -- S2
S1 -- S3
S1 -- S4
S2 -- S3
S2 -- S5
S4 -- S5
S5 -- LPT S5:edge
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
BPDU flags: 0x79, Agreement, Forwarding, Learning, Port Role: Root, Topology Change
0... .... = Topology Change Acknowledgment: No
.1.. .... = Agreement: Yes
..1. .... = Forwarding: Yes
...1 .... = Learning: Yes
.... 10.. = Port Role: Root (2)
.... ..0. = Proposal: No
.... ...1 = Topology Change: Yes
Root Identifier: 4096.02:00:00:00:00:00
Root Path Cost: 40000
Bridge Identifier: 32768.02:00:00:00:00:04
Port identifier: 0x8002
R0 @1.5,1.5 prio=8192
# AutoEdge=true, AdminEdge=false, bridge
S1 @3,1.58
R0 -- S1
# AutoEdge=true, AdminEdge=false, end device
H1 @2.84,2.18 icon= proto=none
R0 -- H1
# AutoEdge=true, AdminEdge=true, bridge
S2 @2.18,2.84
R0 -- S2 R0:edge
# AutoEdge=true, AdminEdge=true, end device
H2 @1.58,3 icon= proto=none
R0 -- H2 R0:edge
# AutoEdge=false, AdminEdge=true, bridge
S3 @0.68,2.76
R0 -- S3 R0:edge R0:no-auto-edge
# AutoEdge=false, AdminEdge=true, end device
H3 @0.24,2.32 icon= proto=none
R0 -- H3 R0:edge R0:no-auto-edge
# AutoEdge=false, AdminEdge=false, bridge
S4 @0,1.42
R0 -- S4 R0:no-auto-edge
# AutoEdge=false, AdminEdge=false, end device
H4 @0.16,0.82 icon= proto=none
R0 -- H4 R0:no-auto-edge
# Network port, bridge
S5 @0.82,0.16
R0 -- S5 R0:network S5:network
# Network port, end device
H5 @1.42,0 icon= proto=none
R0 -- H5 R0:network
# AdminEdge=true, bpdu-guard=true, bridge
S6 @2.32,0.24
R0 -- S6 R0:bpdu-guard R0:edge
# AdminEdge=true, bpdu-guard=true, end device
H6 @2.76,0.68 icon= proto=none
R0 -- H6 R0:bpdu-guard R0:edge
:protocol rstp
:tx-hold 10
# Root bridges
R1 @0,1 prio=0
R2 @0,2 prio=4096
R1 -- R2 cost=200 R1:network R2:network
R1 -- R2 cost=200 R1:network R2:network
# First loop
C1 @1,0 icon=
C4 @2,0 icon=
C7 @3,0 icon=
C10 @4,0 icon=
C12 @5,0 icon=
C13 @5,3 icon=
C15 @4,3 icon=
C18 @3,3 icon=
C21 @2,3 icon=
C24 @1,3 icon=
R1 -- C1 R1:network C1:network
C1 -- C4 C1:network C4:network
C4 -- C7 C4:network C7:network
C7 -- C10 C7:network C10:network
C10 -- C12 C10:network C12:network
C12 -- C13 C12:network C13:network
C13 -- C15 C13:network C15:network
C15 -- C18 C15:network C18:network
C18 -- C21 C18:network C21:network
C21 -- C24 C21:network C24:network
C24 -- R2 C24:network R2:network
# Second loop
C2 @1,0.5 icon=
C5 @2,0.5 icon=
C8 @3,0.5 icon=
C11 @4,0.5 icon=
C14 @4,2.5 icon=
C17 @3,2.5 icon=
C20 @2,2.5 icon=
C23 @1,2.5 icon=
R1 -- C2 R1:network C2:network
C2 -- C5 C2:network C5:network
C5 -- C8 C5:network C8:network
C8 -- C11 C8:network C11:network
C11 -- C14 C11:network C14:network
C14 -- C17 C14:network C17:network
C17 -- C20 C17:network C20:network
C20 -- C23 C20:network C23:network
C23 -- R2 C23:network R2:network
# Third loop
C3 @1,1 icon=
C6 @2,1 icon=
C9 @3,1 icon=
C16 @3,2 icon=
C19 @2,2 icon=
C22 @1,2 icon=
R1 -- C3 R1:network C3:network
C3 -- C6 C3:network C6:network
C6 -- C9 C6:network C9:network
C9 -- C16 C9:network C16:network
C16 -- C19 C16:network C19:network
C19 -- C22 C19:network C22:network
C22 -- R2 C22:network R2:network
:protocol rstp
:tx-hold 10
:max-age 20
R1 @0,0 prio=4096 icon=
R2 @0,5 prio=4096 icon=
S1 @1,0
S2 @2,0
S3 @3,0
S4 @4,0
S5 @5,0
S6 @6,0
S7 @6,1
S8 @5,1
S9 @4,1
S10 @3,1
S11 @2,1
S12 @1,1
S13 @1,2
S14 @2,2
S15 @3,2
S16 @4,2
S17 @5,2
S18 @6,2
S19 @6,3
S20 @5,3
S21 @4,3
S22 @3,3
S23 @2,3
S24 @1,3
S25 @1,4
S26 @2,4
S27 @3,4
S28 @4,4
S29 @5,4
S30 @6,4
S31 @6,5
S32 @5,5
S33 @4,5
S34 @3,5
S35 @2,5
S36 @1,5
R1 -- S1
S1 -- S2
S2 -- S3
S3 -- S4
S4 -- S5
S5 -- S6
S6 -- S7
S7 -- S8
S8 -- S9
S9 -- S10
S10 -- S11
S11 -- S12
S12 -- S13
S13 -- S14
S14 -- S15
S15 -- S16
S16 -- S17
S17 -- S18
S18 -- S19
S19 -- S20
S20 -- S21
S21 -- S22
S22 -- S23
S23 -- S24
S24 -- S25
S25 -- S26
S26 -- S27
S27 -- S28
S28 -- S29
S29 -- S30
S30 -- S31
S31 -- S32
S32 -- S33
S33 -- S34
S34 -- S35
S35 -- S36
S36 -- R2
R1 -- R2 cost=200 down
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
BPDU flags: 0x4e, Agreement, Port Role: Designated, Proposal
Root Identifier: 4096.02:00:00:00:00:00
Root Path Cost: 400000
Bridge Identifier: 32768.02:00:00:00:00:15
Port identifier: 0x8002
Message Age: 20
Max Age: 20
Spanning Tree Protocol
Protocol Identifier: Spanning Tree Protocol (0x0000)
Protocol Version Identifier: Rapid Spanning Tree (2)
BPDU Type: Rapid/Multiple Spanning Tree (0x02)
BPDU flags: 0x7c, Agreement, Forwarding, Learning, Port Role: Designated
Root Identifier: 4096.02:00:00:00:00:01
Root Path Cost: 320000
Bridge Identifier: 32768.02:00:00:00:00:16
Port identifier: 0x8001
Message Age: 16
Max Age: 20
4096.02:00:00:00:00:00 vs 4096.02:00:00:00:00:01.
Fixing the link between R1 and R2 resolves the issue. The
maximum message age any packet carries is now 18, below the configured maximum
age. But it only works until another link breaks. A plausible fix is to increase
the maximum age to 40.17
:protocol rstp
R0 @1,0 prio=0
S1 @1,1 prio=4096
S2 @0,2 prio=8192
S3 @2,2
R0 -- S1
S1 -- S2
S2 -- S3
S3 -- S1
import loadMSTPD from "./dist/mstpd.mjs";
const mstp = await loadMSTPD();
// Create 3 bridges
const a = mstp.createBridge("A", priority: 4096 );
const b = mstp.createBridge("B", priority: 8192 );
const c = mstp.createBridge("C");
// Each bridge has two ports
const a1 = a.addPort("a-b", portno: 1 );
const a2 = a.addPort("a-c", portno: 2 );
const b1 = b.addPort("b-a", portno: 1 );
const b2 = b.addPort("b-c", portno: 2 );
const c1 = c.addPort("c-a", portno: 1 );
const c2 = c.addPort("c-b", portno: 2 );
// Build a triangle topology
mstp.link(a1, b1);
mstp.link(a2, c1);
mstp.link(b2, c2);
// Enable all bridges and ports
for (const br of [a, b, c]) br.enable();
for (const p of [a1, a2, b1, b2, c1, c2]) p.enable();
// Execute 40 seconds' worth of wall clock and display the topology
mstp.step(40);
console.log("Topology:", mstp.topology());
$ node --test *.test.mjs
two bridges: lower priority becomes root (41.657342ms)
triangle loop: exactly one port blocks and all agree on the root (5.832ms)
breaking the active link reconverges and restoring recovers (18.730753ms)
[ ]
tests 40
pass 40
fail 0
[ ]
duration_ms 396.190897
<pre> blocks containing a
topology definition and turns them into interactive widgets. You can inspect
and modify the definition by hitting the edit button.
There is also a cool trick to tell whether the topology has converged. After
each step, we save a snapshot of the simulation memory, play 50 seconds worth
of simulation to check if the topology is stable, and travel back in time by
restoring that snapshot.
The complete code lives on GitHub. I am happy with the result. It can be
difficult to follow everything happening during a single step, but stepping
forward and backward helps. I plan to use the same approach in future blog posts
about networking features.
Note Michael Lynch reviewed a first draft of this article. He authored Refactoring English, a book to sharpen your writing for blog posts, documentation, commit messages, and tutorials. Any errors are still mine!
ff:ff:ff:ff:ff:ff). This behavior bootstraps
the learning process.
:forward-delay 21), as the standard
enforces this condition: 2 (Forward Delay 1) Max Age. For this
specific topology, you could also increase the maximum age to 37 and
forward-delay to 20.
In Jo o Pessoa, we had a two-day event. The first day was dedicated
entirely to workshops, and I ran a packaging workshop for newcomers.
It was the first time I had been responsible for a workshop, and it
was a great experience. We didn't have a lot of time, so I decided to
start with a 30-minute talk explaining a few things about Debian. For
example, I made this image to explain the packaging workflow:
This image was based on The
Debian Administrator's Handbook, and I think the participants really
enjoyed learning about this workflow. When I showed the slide with this
image, it was the moment when I received the most questions.
After the talk, I explained my way of working and what they were
going to do. The hardest part was setting up the environment, since my
approach uses sbuild + gbp. They were running different Debian releases
and, because of my inexperience with workshops, I had some of them
configure sbuild with unshare, even though it is only available in
stable through backports.
Some of them even managed to learn how to use backports, while others
decided to start again using the "old" way.
One thing that helped a lot was the Debian Brasil
Wiki. It has all the instructions for configuring sbuild in
Portuguese, along with great examples. The Brazilian wiki is an
opinionated version of the Debian Wiki. We generally prefer to use it
for the convenience of having the exact workflow we follow, as well as
an up-to-date Portuguese version of our process.
If you want to learn more about the Brazilian community, you can find
more details in the schedules from previous DebConfs. We almost always
had a talk about the community and its activities.
In the end, everyone successfully set up their development
environment, and all six participants made their first contribution to
Debian. If you take a look at my upload
tracking page, you will see that every upload made on August 15,
2026 was a sponsored upload from this event. One of them appear twice in
the list because I sponsored the upload and also made some other
changes.
I also asked all of them to put this in their changelog:
* My first contribution!
The idea was to make it clear to other people that they were only
working on small Lintian issues as a way of learning and understanding
the process. By the way, I made a UDD
query to find packages with the following Lintian tag:
redundant-rules-requires-root-no-field. To fix this issue,
they only had to remove one line from the debian/control
file.
It is obvious that these uploads are not particularly useful. I call
them "motivational uploads" because my goal is to help newcomers
understand the process and immediately give them the reward of having
made a contribution to Debian.
I'll try to keep in touch with them. My plan is to hold another
session, this time remotetly, to help them continue contributing to
Debian. In fact, I already have another package prepared by one of them
waiting for my review.
The second day was a full-day event featuring a bunch of talks from
the local community. I gave a talk explaining the new members
process.
I was the only Debian Developer at the event, and I think having a DD
there made a real difference. Being there to answer questions, and
simply being present, makes Debian feel more tangible and accessible to
people.
A big shout-out to Rafael Rocha, who put in a lot of work to make
this event happen, with the help of many volunteers who contributed
along the way.
One thing I really like about Debian Days is that each place has its
own way of doing things. In Jo o Pessoa, we had a MiniDebConf-like
event, while in Bras lia, we had something smaller but still very
valuable. We decided to keep things simple: talk to a few students at
the University of Bras lia (UnB) and then go somewhere to eat and have a
few drinks.
As I am writing this, there is a vote ongoing in the Debian
project on how to deal with AI in general and AI-assisted contributions to Debian specifically. Massive discussions
have happened in debian-vote and other locations. I have also asked
questions there and offered my perspective. IMHO now is the time to summarize that, after all the discussions
that I've had with people on multiple sides of this debate both online and offline, and explain how I will be
voting and why. Hopefully that will be helpful to someone else as well. None of this has been compiled with AI
assistance, but only because I think that forming opinions is not something where AI can really be helpful.
Spellcheck was used though.
So, first I will describe how I see each of the 8 proposals, then what my vote will be, and then a bit more
detail on the reasoning and thinking behind this. WARNING - this went long.
Also in this series:In a post to oss-security, my (Debian) co-developer Russ Allbery stated that "open source software [OSS] is coming face to face with a motivation crisis that has been building for a long time". His point is essentially that large language models (LLMs1) are making the existing OSS community crisis worse. For him, it's the flood of code reviews, but he argues that varies according to people's desires, for others it's security issues and so on. I think Russ is right, but I would argue there's something much bigger than our open communities going on here, and it's about the entire field of computing. This pressure is on all of us, regardless of whether we work on open source software or not.
Once it s done, I ll useThink about what that means for a minute. This is automation built to fire up dozens of agents crunching at a problem for minutes if not hours of GPU compute time, in parallel. This is essentially a couple of shelves in a datacenter rack, totally maxed out on power and cooling, abstracted behind a cute little/code-reviewand let Claude spawn sub-agents to do a full review of the new code. This usually finds some problems, even problems that the main Claude instance didn t find during its validation. I usually keep running/code-reviewagain and again after finding and fixing issues, until there aren t any left.
/code-review command.
The author, here, is rightly concerned that "Anthropic could pull the
rug out and require API pricing", which is perhaps a code word for
"charging something closer to actual costs". Brian also pays lip
service to environmental and societal costs but those are largely
abstracted away, so let's keep that conversation aside here as well,
as we have discussed it before anyways.
But clearly, this way of working has an (externalized) cost, to
say the least.
For human developers, using coding LLMs magnifies their difference in skill levels.I am one that rarely thinks things are always black and white. Back in March, I wrote Artifial Intelligence: Shades of Gray. Since then, I ve had more of a chance to experiment with LLMs myself. I also happen to work for an employer that is taking a very pragmatic approach to LLMs: teams and individuals use it as they see fit, but if they are causing considerable expense, they have to justify it. In various settings, I have seen the egregious examples of AI slop we all know about. As I wrote in March, I have seen it both waste more time than it saves, and save a ton of time. I have come to see that, as a tool, it is most valuable when it is running under the supervision of an experienced engineer. It is at its worst when it has no such supervision; the vibe coding and other low-quality slop we see. A coding agent is like a junior developer or research assistant. When properly supervised, they help projects move along more quickly by letting a senior developer focus on the more difficult, less mundane aspects of the project. But one couldn t expect a junior developer to consistently deliver high-quality code and architecture on their own. Let s put a pin in this idea and look at the story in Debian. LLM use in Debian There is a vote happening in Debian around the use of LLMs. In typical Debian fashion, there are 8 options to choose from, many of them similar. Most of these proposals acknowledge there are different types of tasks done in Debian, but the proposals don t differentiate between them well. Let me do so here. These are some of the LLM-relevant tasks people in Debian perform:
It has now been thirty-three years since the Debian project was announced to
the world by Ian Murdock, on August 16, 1993. This anniversary is an
opportunity to reaffirm the goals, characteristics, and qualities of the
Debian project: it s an association of individuals who have made common cause
to create a free operating system. Our distribution is characterized by a
commitment to software freedom, as enshrined in the Debian Social Contract
and the Debian Free Software Guidelines. It focuses on security and
stability. This stability is crucial to Debian position in the free software
ecosystem.
With our users as our priority, Debian makes special efforts regarding
accessibility with Debian-Accessibility and diversity with our Outreach
Programs.
Debian Day is a great opportunity to get together, whether for a local meetup,
or simply to grab a coffee with other members of the Debian community. Check
out the Debian Day wiki to see if there is a celebration near you. And if
there isn't, maybe you can organize it next year!
Today is also an opportunity for you to start or resume your contributions
to Debian. For example, you can install the how-can-i-help package and
see if there is a bug in any of the software that you use that you can help
to fix, contribute small tips on how to install Debian on your machines to our
wiki pages, or put a Debian live image in an USB memory
and give it to some person near you, who still didn't discover Debian.
Thanks to everybody who has contributed to develop our beloved operating
system in these 33 years, and
Happy birthday Debian!
Welcome to the July 2026 report from the Reproducible Builds project!
In our reports, we try to outline the most important things that we have been up to over the past month. As a quick recap about what problem our project intends to solve, whilst anyone may inspect the source code of free software for malicious flaws, almost all software is distributed to end users as pre-compiled binaries. The motivation behind the reproducible builds effort is to ensure no flaws have been introduced during this compilation process by promising identical results are always generated from a given source, thus allowing multiple third-parties to come to a consensus on whether a build was compromised or not.
If you are interested in contributing to the project, please visit the Contribute page on our website.
In this month s report, we cover:
diffoscope is our in-depth and content-aware diff utility that can locate and diagnose reproducibility issues. This month, Chris Lamb made the following changes, including preparing and uploading versions 324, 325 and 326 to Debian:
zipdetails 4.0008. (#1141359)pedump binary to use the mono package under GNU Guix. [ ]
ctime as returned by the lstat(2) syscall. [ ], which Chris Lamb uploaded whilst bumping the Standards-Version to version 4.7.4 [ ]. Bernhard Wiedemann also updated disorderfs to version 0.7.0 in openSUSE.
Yet again, there were a number of improvements made to our website this month as well. For example, Chris Lamb, by request of Digital Ocean, changed the target of a referral link so that they can manage incoming referrers [ ] and pushed a number of changes to the Tools page [ ].
In Debian this month, 32 reviews of Debian packages were added, 26 were updated and a total of 21 were removed this month, adding to our extensive knowledge about identified issues.
A number of issue types were added by Chris Lamb, including:
python_towncrier_build_date [ ][ ]log_files_installed_in_package [ ]fontforge_varies_by_timezone [ ][ ]build_date_in_manpage_generated_by_spf13_cobra issue. [ ]
In addition, there is a new page showing verification rebuilds of OpenWrt APK packages and firmware images, powered by rebuilderd:
Yan Li, Nan Jiang, Qihang Zhou, Shaowen Xu, Yamin Xie and Xiaoqi Jia of the Chinese Academy of Sciences published a paper titled VCAligner: Aligning Source Distribution Versions with Upstream Git Commits to Secure Supply Chain:
We present VCAligner, a content-based alignment methodology that constructs inverted indexes over VCS histories to precisely map released artifacts to their originating commits, independent of fragile version tags. We evaluated VCAligner on a dataset of 2,984 verifiable PyPI packages derived from the 4,000 most-downloaded projects linked to public GitHub upstreams. Our results reveal a critical weakness in conventional tag-based heuristics: while they appear effective on 85% of the dataset, the residual 15% failure rate generates a catastrophic downstream audit workload of over 10.3 million commits. In contrast, VCAligner reduces this burden by two orders of magnitude ( 158 ), bounding the total workload to under 65,000 commits. Furthermore, we provide the large-scale characterization of Packaging Noise, classifying artifact divergence into structural additions (Path Phantoms) and content mutations (Blob Phantoms), thereby isolating the distinct attack surfaces of malicious injection and code tampering.
Jens Dietrich and Spencer Sun from the Victoria University of Wellington together with Tim W. White and Behnaz Hassanshahi from Oracle Inc pre-published their paper No Snake Oil: Verifying Python Package Builds (PDF):
Python has become the default language for interacting with AI, with packages being distributed through registries like the Python Package Index (PyPI). This creates a need to analyse supply chains comprising such packages. One such analysis is to rebuild packages in order to identify compromised builds injecting malware. Independent rebuilds in hardened environments have the added advantage that they can generate and record provenance in order to increase the trustworthiness of packages. Two tools that are designed to automate such rebuilds and run them at scale are macaron and oss-rebuild. We study 12,180 popular releases from PyPI and find that the byte-for-byte equivalence rate is generally low. We analyse the reasons why they produce different wheels, and find that equivalence between the original and rebuilt wheels can often still be established, preserving most of the guarantees users expect from rebuildable releases. We present and evaluate daleq4py, a tool to establish the equivalence of Python wheels through the kernel of a normalisation function that is based on provenance-preserving datalog rules. Experimental results show that daleq4py substantially expands the set of rebuilds that can be accepted as equivalent. Although only 15.4% of macaron rebuilds and 19.1% of oss-rebuild rebuilds are byte-for-byte identical to the published PyPI wheels, daleq4py establishes wheel equivalence for 60.2% and 78.9% of source-equivalent rebuilds, respectively.
Denise Nanni, Julien Malka, Stefano Zacchiroli and Th o Zimmermann from T l com Paris together with Gabriele D Angelo from the University of Bologna pre-published their paper Understanding Build Reproducibility in the F-Droid Ecosystem (PDF), which was accepted at the 2026 ACM Conference on Reproducibility and Replicability:
The security of open source applications benefits considerably from the possibility of rebuilding their source and verifying the output. F-Droid, a prominent distribution for open source Android applications, systematically rebuilds them from source and tests their bitwise reproducibility at app publishing time. However, F-Droid offers no guarantee that app reproducibility will continue to hold in the future. As software ecosystems evolve, reproducibility may degrade, with potential negative consequences for software preservation and security. We present the first empirical study of build reproducibility in the F-Droid app ecosystem. Analyzing historical reproducibility logs, we find that the overall bitwise reproducibility rate has been steadily increasing over time (as new versions of apps are published). We then evaluate how reproducibility holds in time for fixed app versions, by attempting to rebuild 18 904 app versions that F-Droid had previously confirmed bitwise reproducible, published between September 2018 and February 2026, achieving an 83% rebuild success rate, and identify missing dependencies as the dominant cause of failure, accounting for 76% of non-rebuildable cases. Among successfully rebuilt apps, 94% are also bitwise reproducible-i.e., they still yield bitwise identical artifacts upon rebuild. Together, these results show that while bitwise reproducibility largely holds for apps that can be rebuilt, rebuildability itself is highly sensitive to temporal decay.
golang-github-tidwall-wal.lightproof.libslow5lib.siso.grout.libpsl.node-grunt-contrib-internal.fontforge.spopt.go-dlib.towncrier.python-sphinx-chango.gasnet.yubihsm-connector.dh-fortran.watcher.rakudo.kf6-breeze-icons.oxygen-icons.gnu-apl.barvinok.ecbuild.Reproducible builds remove trust in the builder: anyone re-derives the same artifact from the same source, byte for byte. The same shape applies one layer over, to a retained record. Most record-keeping regimes (the EU AI Act s Article 12 logging is the current example) require that events be recorded and logs retained, but not that a retained log be verifiable, by a party who was not present, as unaltered and existing when claimed. That leaves an integrity obligation resting on trusting the party being audited.(Full thread)
#reproducible-builds on irc.oftc.net.
rb-general@lists.reproducible-builds.org
Today I stumbled over some behavior that I found quite surprising:
$ ipython3 -c 'import httpx;print(httpx.URL("https://example.com/foo/bar/../../baz"))'
https://example.com/baz
Even more surprising that behavior is actually standards-compliant,
even mandated by RFC 3986.
The underlying motivation is relative reverences.
If some resource reachable by "https://example.com/foo/bar"
references another resource relatively as "../../baz" then
this is of course the intended result.
Getting from this problem to what RFC 3986 suggests
might be surprising in the result, but somewhat understandable if you
look at the consequences of that problem:
Giving the path components ".." (and ".")
special meaning at the start of the relative reference means that if you allowed
them in absolute URLs those would be impossible (or at least very convoluted)
to address as relative URLs.
So RFC 3986 describes a way to handle them everywhere:
Just join the path of the base URL and the path of the relative reference
and normalize the result. Or normalize the absolute on either side if only
that is to be taken.
This makes things very convenient:
Multiple reference URLs can just be joined without special handling for
relative references starting with dots, making writing applications handling
them easier.
Programmers don't have to care how to handle relative references and can
just join everything in whatever way they want.
For maximum elegance there is still some corner case left:
What happens if an absolute URL has a path starting with double-dot components?
Or an relative path starting with more of them then the base URL's path has components.
You just ignore them:
$ ipython3 -c 'import httpx;print(httpx.URL("https://example.com/../../baz"))'
https://example.com/baz
With that last point every URL is valid and has well-defined meaning.
Handling relative references and relative paths is very easy and convenient.
So this shows a high regard for simplicity, elegance and convenience.
And a total and uncompromising disregard of security.
After all the most convenient it is for an attacker;
If they are allowed to supply a path component for a request a system
does in their behalf, then they can easily escape anything they were supposed
to be limited to.
The ignoring of dots at the start means they don't even have to know
exactly how deep their request is:
$ python3 -c 'import httpx;print(httpx.URL("https://example.com/public/api/public/resources/harmless/../../../../../../../../../internal/data"))'
https://example.com/internal/data
So even if the resource server securely handles request
(unless you consider not having any way to lower your permissions for one request to a specific subset),
your fully RFC conforming client library will already request the permission they should not have permission for.
Even worse dots are usually not characters you can easily forbid so once slashes are to be allowed things get complicated.
There also would have been a simple, elegant and secure way:
Consider every path element ".." or "."
in an (absolute) URL an error.
Define a reference resolution that allows the relative reference to only start
with "./" or one or multiple "../" and
consider every appearance of a dot or two dots as path components after than an error.
Everything joining two paths has to either use an implementation of that path joining
algorithm, but only if they want to joins paths in the potentially dangerous
way allowing leading "../". Otherwise they can just use the normal
join and even if an attacker gets those dots that will just cause the generated URL
to be rejected as invalid.
Of course using a secure implementation is now even more inconvenient thanks to RFC 3986 being around:
If you have no control over the generator of relative references, it is always possible
that they generate relative references with ".." components after non-dot
components.
And if you check all code to properly filter out "/../",
keep in mind that convienence does not stop there.
After all it is not unheared of for server implementations to helpfully normalize
unicode characters, too, or translate them to their nearest ASCII equivalents.
Or translate percent escaped characters back before doing path splitting.
Or you might think there was some unicode codepoints between those two dots,
but they that those were some meaningless control characters that can be omitted.
So you need some really restrictive allow lists...
While many Western democracies seem to be in a state of decay and are no longer the safe, civilized and prosperous countries they once were, there are still some European countries that are governed well. One of those that stand out is Estonia.
Estonia is probably most well known for multiple software companies that originated from there, such as Wise, Bolt, Pipedrive and Skype. The government itself is also famous for being early in issuing government IDs with an embedded smart chip for online authentication already in the 1990s. Via the national portal at eesti.ee all residents can access extensive eServices ranging from viewing their health benefits to filing taxes.
Estonia has also been running an e-Residency program since 2014, where they issue digital ID cards to foreigners, making it easy for them to remotely log into the government portals and for example, establish businesses, file annual reports and so forth. Note that the e-Residency is not a path to physical residency. Estonia does, however, have a separate Digital Nomad visa program that makes it easy for non-EU citizens to also physically establish themselves in Estonia, assuming, of course, you meet the criteria, which includes, among others, a minimum monthly income of 3960 from outside Estonia. EU citizens naturally have free mobility inside the EU and can simply get an apartment and register as a resident in Estonia if they so choose. And there are plenty of reasons to do so.
Estonians also seem to value the school system highly. The government has been actively raising teacher pay and has a stated goal of reaching 120% of the national average by 2027. The students are also expected to value the education and respect their teachers. According to the TALIS 2024 survey (OECD s international teacher survey), Estonian teachers spend significantly more time on actual teaching and learning and waste less time on interruptions or keeping classroom order compared to the OECD average. This is among the highest rates internationally, meaning they spend relatively little time on maintaining order or dealing with disruptions. While the international education benchmark PISA scores have been dropping globally, Estonia has consistently been climbing the ranks in past decades. In the latest PISA study (from 2022), Estonia ranked number one in Europe for reading, mathematics and science. In the overall results, Estonia ranked seventh globally, only behind countries such as Japan, Korea and Singapore.
Valuing entrepreneurship is evident in how the taxation system is set up in Estonia. Famously, in Estonia, companies can defer taxes on annual earnings and reinvest all of their profit in growing the company. Taxes are due only later, when paid out from the company, for example as dividends. For individuals, receiving dividends from any Estonian or foreign company is tax-free as long as the company paying dividends already paid corporate tax on the same income.
The tax system is also very simple. For all individuals, all types of income, including salary and capital gains, are always taxed at a flat rate of 22%. This removes the incentive for anyone to try to convert income into different types, setting up holding company structures and other optimizations as there is no gain. All entrepreneurs can simply focus on growing their business and forget extra bureaucracy. There is also no marginal tax rate cliff to stop working at everyone is encouraged to always try to produce as much value as they can. A simple tax system is also reflected in the fact that anyone can easily read all tax rules that apply to individuals in plain English on the Estonian tax authority website, and one does not need to hire any accountants simply to file taxes.
Estonia also has a very straightforward investment account system: any person can freely open a self-directed investment account at any brokerage at no extra cost and report it as such to the tax authority, and then use it to save for an apartment, retirement, or other purposes, and defer all income taxes until withdrawal. There are no caps or time limits, and all residents are encouraged to save and invest as much as they can and thus take responsibility for their own wealth accumulation.
It seems that culturally Estonians respect people who are active and progress in their careers and businesses more than in other countries. Unlike in Finland, successful people are admired and living on government welfare is not romanticized. At the same time, the government benefits are less generous so people can t live comfortably on them and, for example, many of the asylum seekers Estonia accepted have since left on their own initiative to other European countries in search of better benefits.
This is not just my personal experience. According to the Numbeo crime index, Estonia has one of the lowest crime rates in the world. Also, comparing drug and property crime stats, for example, Finland has twice as much crime per capita, and places like Vancouver in Canada almost five times more.
I don t have any clear explanation for why crime is so much lower in Estonia, but some suggest that higher social cohesion and lower levels of welfare contribute to people standing to lose more if they behave antisocially. Compared to Finland, Estonia also more readily jails repeat offenders, and those who are put on trial will experience a swifter court process thanks to simplified legal processes and more efficient governance.
The next step is to buy a local prepaid SIM card at e.g., an R-Kiosk or a convenience store as signing up for other matters later on will require an Estonian phone number. Once you have an apartment and e.g., signed a rental agreement, you can register in the population registry online.
After that, you have proof you are a local resident with an address and telephone number in Estonia. With local resident status, you can go to the police station to get a local ID card. Don t bother scheduling an appointment, just go to the Tammesaare police station in Tallinn, take a queue number and wait. Once it is your turn, they will guide you on how to use the photo booth, fingerprint registration device, and file your application. A few days later you will receive an email confirming whether your application was accepted, and after a few more days, you will get another email notifying you that your ID card has been printed and is available for pick-up at the same location. This will also be your first practical experience of how fast and efficient the government in Estonia is.
Once you have the local ID card, you can use the smart card feature to log into all the government eServices and sort out the rest of the relocation process, such as registering tax residency and getting a family doctor.
I enjoyed reading this post by Marginalia
"Your harddrive is probably full"
You can construct an entropic argument that there are simply more ways for a harddrive to be full than ways in which it can be empty.Of course it made me check how full my laptop drive is, and indeed it was more than 75% full, as predicted. But, I almost never feel that my hard drive is full. I can very easily free up almost any amount of disk space at any time, without any thought. While writing this blog post, I ran a single command and now my harddrive is 50% empty.
The other part of the equation is that a full disk isn t a problem until it s so full you can t put more stuff on it, and at the point it s so irredeemably cluttered that when you do clean it up, you only have the patience to clean up enough to bide your time, judging the fate of every file on the harddrive is simply too much work.Why doesn't this apply to me? Because I have put in the up-front thought to organize things, so that I never have to do that anymore. I have 3 categories of files that I can remove at any time I need more space, without any thought:
git-annex drop any file and stop it using disk
space, but the file is still there (as a broken symlink) so you don't
risk losing or forgetting about it.~/tmp/, which is reserved for any files I only want to have a
passing acquaintance with. If I'm not comfortable with something being
deleted at any time, I don't put it there./tmp/ as an example that I long ago used as the basis for the rules for my
~/tmp/. I hope that git-annex might also serve as an example
that moving files between drives is not the best way to manage disk space
use.
Welcome to post 57 in the R4 series.
R packages with compiled codes can use the file
src/Makevars to set compilation flags. We often rely on
this to set libraries, include directories or compilation options. When
using external libraries, be it header-only or via headers and linking,
we are often experiencing compilation noise when these libraries
tickle warnings under generally-recommended flags such as
-Wall -pedantic. Two packages I maintain are clearly repeat
offenders here: Eigen, and BH. Both cam generate pages and pages of
compiler output. This is generally not great as it may hide genuine
warnings from our own code.
What makes matters worse is that some of the available and specific
options for the compilers are treated by R CMD check as
non-portable leading to a nag on package checking. Examples are
-Wno-parentheses, -Wno-maybe-uninitialize or
-Wno-nunnull.
I have long resorted to adding these to my per-user
~/.R/Makevars. When added there, compilation is quieter,
but R CMD check still nags here where the option
is set but not at CRAN or
r-universe. A situation that is not ideal but what somewhat
stable .
More recently, I realized there was an available check we can use to
conditionally add extra compilation flags but leave them off by
default. That makes local development quiet allowing us to focus on the
quality of our additions here without noise from third-party libraries
we may use. At the same time we do not need to do anything else to let
CRAN do its work.
The check we now use is whether there is a .git/
directory present. If so, we are indeed building from local sources and
can add extra flags. If not, we are likely building from a tar.gz source
archive which is the case for CRAN and hence do not set these.
An example use is this recent additional to package qlcal where this bit of R
code is invoked from a minimal shell script configure and
replaces the stub @XTRAFLAGS@ in
src/Makevars.in (or src/Makevars.win.in)
if (dir.exists(".git"))
## development from a .git directory can use these flags
xtraflags <- "-Wno-nonnull -Wno-deprecated-declarations"
else
## else build from tarball so stick with existing flags
xtraflags <- ""
win <- if (Sys.info()[["sysname"]] == "Windows") ".win" else ""
infile <- file.path("src", paste0("Makevars", win, ".in"))
outfile <- file.path("src", paste0("Makevars", win))
lines <- readLines(infile)
lines <- gsub("@XTRAFLAGS@", xtraflags, lines)
writeLines(lines, outfile)configure
file written in autoconf. Here is a similar example from RcppEigen
(showing some relevants parts of the whole file)
# PKG_CXXFLAGS initialized earlier ...
## Check if building locally
AC_MSG_CHECKING([whether .git/ exists])
if test -d "$srcdir/.git"; then
AC_MSG_RESULT([yes, adding extra flags])
AC_SUBST([PKG_CXXFLAGS],["$ PKG_CXXFLAGS -Wno-ignored-attributes -Wno-maybe-uninitialized"])
else
AC_MSG_RESULT([no, consider adding '-Wno-ignored-attributes -Wno-maybe-uninitialized' to ~/.R/Makevars])
fi
AC_SUBST([PKG_CXXFLAGS], ["$ PKG_CXXFLAGS "])
AC_CONFIG_FILES([src/Makevars])
AC_OUTPUTThis post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can now sponsor me at GitHub.
Next.