Hacker Newsnew | past | comments | ask | show | jobs | submit | notyoutube's commentslogin

Mind ELI5ing this? it seems neat


The Fourier transforms map plane waves to points. Blocks of regularly-spaced text have a periodic character, with the period length of their line spacing; their Fourier transform (I think??) would, in 2d frequency space, have amplitude peaks on vectors that have the same angle as the rotation of the lines.


thanks!


Isn't the "flat markup" for inline elements in prosemirror kind of unnatural to work on html?


(And then gitea was forked into forgejo, which is used by codeberg, iiuc)


I'm using Gitea locally. I haven't come across forgejo before. It seems to be forked on the basis of providing a fully open source solution (it states that some Gitea enterprise features are not present).

Do you know what the main differences are and whether it is worth switching?


There are two main differences:

1. Gitea, Inc replaced the prior community leadership structure with one controlled by Gitea, Inc and have pivoted into being primarily about a hosted code SaaS they launched this year that didn't exist for the first 7 years of the project. They could do it because they had 2 of the 3 seats on the community stewardship organisation at the time to vote for it, but that wasn't always true. For a lot of people, Gitea's primary motivation was for the self-hosted and fully open use case, but now it's not clear that that will remain any more of a priority for Gitea Inc as it is for e.g. Gitlab

2. There were also some contributors who were interested for the sake of decentralising code forges (and not just git), and so were big into the forgefed project which was an activitypub based federation protocol. Gitea Inc were officially on board with that, but the contributors felt they weren't helpful enough to actually implementing that with missteps like letting grant funding from NLNet expire.

The contributors from groups 1 and 2, and Codeberg banded together to make Forgejo after the Gitea change.

Until the latest release (just last month) Forgejo was one way pulling all changes from Gitea, but they've diverged enough that they're now hard forks. Both have active development, but Forgejo's main unique focus is the federation stuff, while Gitea's was enhancing their CI offering. But while Gitea may have more development effort, being funded by a commercial organisation rather than volunteers and a non-profit, I think they have a long way to catch up to Gitlab in that front, so it feels like they've dropped their unique factor to try chase Gitlab.


Thanks.

At the moment forgejo does not have features I'm interested in as I'm not making my internal gitea instance public. However, I'd be interested in it if it provides support for things like hierarchical project grouping and organiation/group-wide project and issue tracking. So I'm going to keep an eye on the project to see how it evolves.

One thing that concerns me is Forgejo's statement that they will diverge further from Gitea without migration commitments. This would make it harder for me -- and others -- to switch after upgrading to Gitea 1.22 and later. A similar concern is the other way around: if I switch to Forgejo and want to move back to Gitea, I won't be able to if the projects have sufficiently changed (e.g. if they implement project grouping differently).


I'm skeptical:

* Where do you buy a ≤20 euro bike?

* Most people on the street have bikes that look to be at least 200 euros new, from what I can tell.


I've never done it, but you buy it from the thief (junkie) directly. So it could be that you find them by word of mouth, like you would use to buy drugs when they were illegal. But you can also buy a second hand bike very cheaply, some are even free (just an example: https://www.marktplaats.nl/v/fietsen-en-brommers/fietsen-her...). New bikes are usually more than 200 euros, dutch brands are 500 euros and up


Presumably from the bike thieves. There's a glut in the stolen bike market so the price competition is fierce.


It seems like that that point the bike thieves are just a bike rental company.

You get the bike for < 20 Euro and then, presumably, at some point in the future it gets stolen again, but you already got 20 Euros worth of use out of it.


"Discount Variable Duration" rental program.


Efficient market hypothesis proven.


Last time I bought a bike for £20 even second-hand, the Euro had not yet been introduced.

Even in 2011, when I made the mistake of spending £90 for a new bike… well, the pedals came off while riding it due to metal fatigue.

Adjusting for inflation*, I'd expect similar build quality from a bike that "only" cost €200 today.

* hard to do when there is also a currency switch, especially when the exchange rate has changed so much


This was 2010-ish and I found one on Marktplaats. Might be going for 40 or 50 now with inflation. People selling them on the street also had for cheap, but these were most definitely stolen.


They didn't mention the year of the story, it could've happened a couple of decades ago.


Police unclaimed bike auctions maybe.


It's interesting how there is now

* Maddy: https://github.com/foxcpp/maddy

* Mox: https://github.com/mjl-/mox

* and Stalwart

which all see to aim for more or less the same niche. I wonder if we'll see two of those merge eventually.


Maddy and Mox are written in Goo, but Stalwart in Rust. So perhaps the first two, but unlikely the last.


They're written in Go, but I think I like the concept of a language called Goo. Maybe they should've named it that instead.


Goo is a nice name for object-oriented Go.


Only Stalwart supports JMAP, which imo is the future of mail/calendar/contacts client-server communication.

https://jmap.io/


It seems JMAP isn't universally loved, see for instance the spirited discussion in [0], although I've no direct experience.

My Maildirs "justed worked" though, and have been moved across dozens of servers - not to mention worked in so many different filesystems - over the years.

[0] https://news.ycombinator.com/item?id=19876710


Is the solution against such attacks in the future only to scrutinize more, or are there other reasonable options in terms of hardening?


The lesson here seems to not depend on tools written in languages that have complex, obscure build systems and no one is either able or interested to read. Using tools rewritten in Rust, Go or any other languege which resolves dependencies within project seems the only way to do hardening here.


I agree there's safer languages than C, but nobody reads the 50,000 lines changed when you update the vendoring in a random golang project. It would be easy to introduce something there that nobody notices too.


It is generally harder to introduce vulnerabilities in readable language even more when it is memory safe. Sure life is not perfect and bad actors would have found a ways to inject vulnerabilities also in Rust, Go codebase. The benefit of modern languages is that there is one way to build things and the source code is the only thing that needs to be auditted.


this backdoor had nothing at all to do with memory safety.


You don't need a complex obscure build system for most C code. There's a lot of historical baggage here, but many projects (including xz, I suspect) can get away with a fairly straight-forward Makefile. Double so when using some GNU make extensions.


Thanks for that post, I wish people stopped pushing ever so more complicated build systems, opaque, non-backward compatible between their own versions when a 2 pages Makefile would work just fine, and still work in 20 years time.


Rust is the worst in terms of build system transparency. Ever heard of build.rs? You can hide backdoors in any crate, or in any crate's build.rs, or the same recursively.


Most build systems are turing-complete. Rust, at least, drastically reduces the need for custom build scripts (most of my projects have empty build.rs files or lack one entirely), and build.rs being in the same language as the rest of the codebase aids transparency immensely.


That doesn't make build.rs any less of a juicy target for a supply chain attack.

Arbitrary code downloaded from the internet and run at build time? That's a nightmare scenario for auditing, much worse than anything Autotools or CMake can offer.


You're not wrong about arbitrary code execution. It's just that your statement applies to most of the packages on any linux distribution, Autotools and Cmake included, regardless of language. Many moreso than Rust due to the aforementioned features of Cargo and build.rs not requiring me to be an expert in a second language just to audit it.


Packages in a Linux distro are not built on my machine, they are built by the distro in a sandbox. Every time I type "cargo build" I am potentially running arbitrary code downloaded from the internet. Every time I type "make" in an Autotools program only my code runs.

> not requiring me to be an expert in another language just to audit it.

Do you do that every time your Cargo.lock changes?


> Every time I type "make" in an Autotools program only my code runs.

Says who? Make is just as good at calling arbitrary code as Cargo. Including code that reaches out over the network. Have you audited every single makefile to ensure that isn't the case?


I am talking about my makefiles. They don't automatically build dependencies that I have no control on.

Whereas building my crate can run code locally that no one has ever audited.


So... you're complaining about what could happen in a Rust build if you include a library without examining that library first? How do you think that is different from doing the same in any other language?


The difference is that in another language the build step is delegated to someone else who has packaged the code, and every version has presumably gone through some kind of audit. With Rust I have no idea what new transitive dependencies could be included any time I update one of my dependencies, and what code could be triggered just by building my program without even running it.

Again, we're not talking about the dependencies that I choose, but the whole transitive closure of dependencies, including the most low-level. Did you examine serde the first time you used a dependency that used it? serde did have in the past a slightly sketchy case of using a pre-built binary. Or the whole dependency tree of Bevy?

I mean, Rust has many advantages but the cargo supply chain story is an absolute disaster---not that it's alone, pypi or nodejs or Ruby gems are the same.


> The difference is that in another language the build step is delegated to someone else who has packaged the code

Fedora packages a large number of Rust libraries, just as you describe. Nothing prevents you from using the packaged libraries if you prefer them.

You may find helpful information here: https://docs.fedoraproject.org/en-US/packaging-guidelines/Ru...


> Nothing prevents you from using the packaged libraries if you prefer them

Nothing except, in no particular order: 1) only having one version of crates 2) mismatched features 3) new transitive dependencies that can be introduced at any time without any warning 4) only supporting one version of rust 5) packages being noarch and basically glorified distro-wide vendoring—so their build.rs code is still run on your machine at cargo build time


> 1) only having one version of crates

Same as any other library provided by the distribution in any other language.

> 2) mismatched features

Same as any other library provided by the distribution in any other language.

> 3) new transitive dependencies that can be introduced at any time without any warning

Not in packaged Rust libraries in Fedora, at least. Please read the aforementioned link.

> 4) only supporting one version of rust

Same as any other library provided by the distribution in any other language.

> 5) packages being noarch and basically glorified distro-wide vendoring

Packages containing only source is a consequence of the Rust ABI still stabilizing, see: https://github.com/rust-lang/rust/pull/105586 After ABI stabilization, Rust libraries will be first class like any other language.


seems trivial for a configure script to call curl/wget somewhere in the depths of it, no?


Exactly. And at least Cargo will refuse to download a crate which has been yanked. So any crate which has been discovered to be compromised can be yanked, preventing further damage even when someone has already downloaded something which depends on it.

Building packages with up-to-date dependencies is also vastly preferable to building against ancient copies of libraries vendored into a codebase at some point in the past, a situation I see far too often in C/C++ codebases.


Debian’s rules files often deliberately sinkhole the entire network during the build. It’s not the worst idea.


I wonder if you could do it inside the config script without the network.


Wouldn't a supply chain attack like this be much worse with Rust and Cargo because of the fact it's not just a single dynamic library that needs to be reinstalled system-wise, but, instead, every binary would require a new release?


It would mean rebuilding more packages. I don't think that's meaningfully "much worse", package mangers are perfectly capable of rebuilding the world and the end-user fix is the same "pacman -Syu"/"apt-get update && apt-get upgrade"/...

On the flip side the elegant/readable build system means that the place this exploit was hidden wouldn't exist. Though I wouldn't confidently say that 'no hiding places exist' (especially with the parts of the ecosystem that wrap dependencies in other languages).


It's much worse because it requires repackaging every affected system package instead of a single library. Knowing which packages are affected is difficult because that information isn't exposed to the larger system package manager. After all, it's all managed by the build system.


In the era of modern CI and build infrastructure, I don't really think that's materially an issue.


Those CI and build infrastructures rely on the Debian and RedHat being able to build system packages.

How would an automated CI or build infrastructure stop this attack? It was stopped because the competent package maintainer noticed a performance regression.

In this case, this imagined build system would have to track every rust library used in every package to know which packages to perform an emergency release for.


I... don't see your point. Tracking the dependencies a static binary is built with is already a feature for build systems, just maybe not the ones Debian and RH are using now, but I imagine they would if they were shipping static binaries.

Rust isn't really the point here, it's the age old static vs dynamic linking argument. Rust (or rather, Cargo) already tracks which version of a dependency a library depends on (or a pattern to resolve one), but it's besides the point.


Rust is the issue here because it doesn't give you much of an option. And that option is the wrong one if you need to do an emergency upgrade of a particular library system-wide.


It's really not, it's not hard to do a reverse search of [broken lib] <= depends on <= [rust application] and then rebuild everything that matches. You might have to rebuild more, but that's not really hard with modern build infrastructure.

Not to mention if you have a Rust application that depends on C libraries, it already dynamically links on most platforms. You only need to rebuild if a Rust crate needs to be updated.


> imagined

Cargo already has this information for every project it builds. That other systems do not is their issue, but it’s not a theoretical design.


So, I know that librustxz has been compromised. I'm Debian. I must dive into each rust binary I distribute as part of my system and inspect their Cargo.toml files. Then what? Do I fork each one, bump the version, hope it doesn't break everything, and then push an emergency release!??!


> I must dive into each rust binary I distribute as part of my system and inspect their Cargo.toml

A few things:

1. It'd be Cargo.lock

2. Debian, in particular, processes Cargo's output here and makes individual debs. So they've taken advantage of this to already know via their regular package manager tooling.

3. You wouldn't dive into and look through these by hand, you'd have it as a first-class concept. "Which packages use this package" should be table stakes for a package manager.

> Then what? Do I fork each one, bump the version, hope it doesn't break everything, and then push an emergency release!??!

The exact same thing you do in this current situation? It depends on what the issue is. Cargo isn't magic.

The point is just that "which libraries does the binary depend on" isn't a problem with actual tooling.

People already run tools like cargo-vet in CI to catch versions of packages that may have issues they care about.


> The exact same thing you do in this current situation? It depends on what the issue is. Cargo isn't magic.

False. In the current situation, you just release a new shared library that is used system-wide.


Okay, so the analogous situation here is that you release a new version of the library, and rebuild. Done.


Except that's not the case at all with Rust.


Except it is. The system package maintainers release a new build of the package in question and then you install it. There's not really anything else to do here. There's nothing special about Rust in this context, it would be exactly the same scenario on, for example, Musl libc based distros with any C application.


Fundamentally there is no difference. In practice Rust makes things a lot worse. It encourages the use of dependencies from random (i.e. published with cargo) sources without much quality control. It is really a supply chain disaster to happen. A problem like this would propagate much faster. Here the threat actor had to work hard to get his library updated in distributions and at each step there was a chance that this is detected. Now think about a Rust package automatically pulling in transitively 100s of crates. Sure, a distribution can later figure out what was affected and push upgrades to all the packages. But fundamentally, we should minimize dependencies and we should have quality control at each level (and ideally we should not run code at build time). Cargo goes into the full opposite direction. Rust got this wrong.


Whether a hypothetical alternate world in which Rust didn't have a package manager or didn't make sharing code easy would be better or worse than the world we live in isn't an interesting question, because in that world nobody would use Rust to begin with. Developers have expected to be able to share code with package managers ever since Perl 5 and CPAN took off. Like it or not, supply chain attacks are things we have to confront and take steps to solve. Telling developers to avoid dependencies just isn't realistic.


> It encourages the use of dependencies from random (i.e. published with cargo) sources without much quality control. It is really a supply chain disaster to happen.

Oh I 100% agree with this, but that's not what was being talked about. That being said, I don't think the distribution model is perfect either: it just has a different set of tradeoffs. Not all software has the same risk profile, not all software is a security boundary between a system and the internet. I 100% agree that the sheer number of crates that the average Rust program pulls in is... not good, but it's also not the only language/platform that does this (npm, pypi, pick-your-favorite-text-editor, etc.), so soloing out Rust in that context doesn't make sense either, it only makes sense when comparing it to the C/C++ "ecosystem".

I'm also somewhat surprised that the conclusion people come to here is that dynamic linking is a solution to the problem at hand or even a strong source of mitigation: it's really, really not. The ability to, at almost any time, swap out what version of a dependency something is running is what allowed this exploit to happen in the first place. The fact that there was dynamic linking at all dramatically increased the blast radius of what was effected by this, not decreased it. It only provides a benefit once discovered, and that benefit is mostly in terms of less packages need to be rebuilt and updated by distro maintainers and users. Ultimately, supply-chain security is an incredibly tough problem that is far more nuanced than valueless "dynamic linking is better than static linking" statements can even come close to communicating.

> A problem like this would propagate much faster. Here the threat actor had to work hard to get his library updated in distributions and at each step there was a chance that this is detected.

It wouldn't though, because programs would have had to have been rebuilt with the backdoored versions. The book keeping would be harder, but the blast radius would have probably been smaller with static linking except in the case where the package is meticulously maintained by someone who bumps their dependencies constantly or if the exploit goes unnoticed for a long period of time. That's trouble no matter what.

> Now think about a Rust package automatically pulling in transitively 100s of crates.

Yup, but it only happens at build time. The blast radius has different time-domain properties than with shared libraries. See above. 100s of crates is ridiculous, and IMO the community could (and should) do a lot more to establish which crates are maintained appropriately and are actually being monitored.

> Sure, a distribution can later figure out what was affected and push upgrades to all the packages.

This is trivial to do with build system automation and a small modicum of effort. It's also what already happens, no?

> But fundamentally, we should minimize dependencies and we should have quality control at each level

Agreed, the Rust ecosystem has it's own tooling for quality control. Just because it's not maintained by the distro maintainers doesn't mean it's not there. There is a lot of room for improvement though.

> (and ideally we should not run code at build time). Cargo goes into the full opposite direction. Rust got this wrong.

Hard, hard, hard disagree. Nearly every language requires executing arbitrary code at compile time, yes, even a good chunk of C/C++. A strong and consistent build system is a positive in this regard: it would be much harder to obfuscate an attack like this in a Rust build.rs because there's not multiple stages of abstraction with an arbitrary number of ways to do it. As it stands, part of the reason the xz exploit was even possible was because of the disaster that is autotools. I would argue the Rust build story is significantly better than the average C/C++ build story. Look at all the comments here describing the "autotools gunk" that is used to obfuscate what is actually going on. Sure, you could do something similar for Rust, but it would look weird, not "huh, I don't understand this, but that's autotools for ya, eh?"

To be clear, I agree with you that the state of Rust and it's packaging is not ideal, but I don't think it necessarily made wrong decisions, it's just immature as a platform, which is something that can and will be addressed.


And Alpine Linux is largely a mistake.


That's not an argument, nor is it productive. Nobody even mentioned Alpine. Go away.


Ok well have a nice day I guess.


I am not completely sure about this exploit, but seems like a binary needed to be modified for the exploit to work[1] which was later picked up by build system.

https://github.com/tukaani-project/xz/commit/6e636819e8f0703...


The binary was an xz test file that contained a script that patched the c-code.


This seems to be an orthogonal issue. Rust could build the same dynamic library with cargo which could then be distributed. The diference is that there would be a single way to build things.


Most Rust libraries are not dynamically linked; instead, versions are pinned and included statically during the build process. This is touted as a feature.

Only a few projects are built as system-wide libraries that expose a C-compatible abi interface; rsvg comes to mind.


It's not touted as a feature by any Rust developers I know of. The Rust ABI is merely still stabilizing. See: https://github.com/rust-lang/rust/pull/105586


People are going to be upset with this perspective but I completely agree. The whole autoconf set of tools is a complete disaster.


Once somebody actually does this people are gonna complain the same as always: "The sole purpose of your project is to rewrite perfectly fine stuff in Rust for the sake of it" or something along these lines.


Is this really the lesson here? We are talking about a maintainer here, who had access to signing keys and a full access to the repository. Deb packages which were distributed are also different than the source code. Do you honestly believe that the (arguably awful) autotools syntax is the single root cause of this mess, Rust will save us from everything, and this is what we should take away from this situation?


I call bullshit.

The fundamental problem here was a violation of chain of trust. Open source is only about the source being open. But if users are just downloading blobs with prebuilt binaries or even _pre-generated scripts_ that aren't in the original source, there is nothing a less-obscure build system will save you from as you are putting your entire security on the chain of trust being maintained.


Am I crazy thinking libraries shouldn't be able to provide _other libraries'_ symbols without the other libraries' "permission"? What am I missing?


Mmh, is that a similarity with postmarketos? I have a fuzzy memory that pmbootstrap or some other tool was kind of important to start porting to new devices?


What government is that?


I dunno, all of them? Which governments mandate open source software when calling for bids?


(I wasn't trying to make a point.) As far as I know, that's what the initiatives like PMPC¹ are for. I think in Switzerland, a law recently passed that seems to go in that direction² (Open Source should by default but some leniency as far as I can interpret the text). According to this³ OSOR report, something similar happened in Italy in 2019. So, I think we're slowly going in that direction in Europe.

¹: https://download.fsfe.org/campaigns/pmpc/PMPC-Modernising-wi...

²: https://www.admin.ch/gov/fr/accueil/documentation/communique...

³: https://joinup.ec.europa.eu/sites/default/files/inline-files...



I do not think it should be mandated. But it should be promoted


I'm not sure the distinction is that clean, but isn't ubuntu still based off debian. As in, not a fork that went its own way, but a (big) collection of modifications on top of current debian?


Sounds like a fork with extra steps.


Derivative, it's less distinct than "fork" would have one believe


I've skimmed at the docs, and it's not clear to me how it would deal with:

* Something like row-level access control, so that people can only access the data in tables that belong to them (say clients can only view their own purchases, and also not modify them after they checked them out).

* Integration with the rest of the world, e.g. sending email, acting on triggers, etc.

* Something like CSV export/import.

* Internationalization.

Would that all be possible? Straightforward? Do those all require extending (with go or js)?

Looks like a nice tool.


I've been developing for PocketBase for 2 months.

As someone else mentioned, API rules can control access to rows.

It can send emails. Set timers. And send its own requests to other webservers. (I haven't used any of these features.) https://pocketbase.io/docs/js-sending-emails/

I had to write my own CSV importer. (I'm hoping to open-source it.)

As for internationalization, what specific features did you want? That seems more like a front-end feature.


Re internationalization, I think you're right. I don't have experience building app/websites, a fortiori with internationalization, so I threw this question in with the lot!


Check out

API Rules https://pocketbase.io/docs/api-rules-and-filters/#api-rules

Hooks https://pocketbase.io/docs/js-overview/

Admin panel has backups for data, and import/export of collections schema


The first point (authn) is inherent to the unextended framework via filter rules.

Most of the remainder requires extension other than authz emails, but extension at its simplest just means adding a plain old JavaScript function to run on a record lifecycle event of some kind - typically [before/after] [insert/update/delete] of <record>. Various GO APIs are exposed to the JavaScript runtime for doing filesystem, cryptography, http, email, etc work.

For i18n you have templates and a database.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: