ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.82k stars 2.55k forks source link

support fetch plugins to download dependencies from less common protocols #14294

Open andrewrk opened 1 year ago

andrewrk commented 1 year ago

Extracted from #14265.

Zig will have built-in support for fetching dependencies from some protocols, such as http, https, gzip, tar, and some others. But there will always be new or exotic protocols. One such example would be ipfs. Not really ubiquitous enough to support directly, but could be interesting for some people to use.

For this I propose a "fetch plugin" system.

Fetch plugins would be specified in build.zig.zon like this:

.{
    // ...
    .fetch_plugins = .{
        .ipfs = .{
            .url = "git+ssh://git@example.com/foo.tar.gz#6f987aba83414319c3afba57a9f49a71f6e13c8e",
            .hash = "sha256=c9b30cffc40999d2c078ff350cbcee642970a224fe123c756d0892f876cf1aae",
        },
        .@"git+ssh" = .{
            .url = "http://example.com/bar.tar.gz",
            .hash = "sha256=9ba4f49895b174a3f918d489238acbc146bd393575062b2e3be33488b688e36f",
        },
    },
    // ...
}

The url fields within fetch_plugins must use a built-in URI scheme or a different fetch plugin from the same manifest.

Implementing this proposal will lift out this code from the zig compiler:

https://github.com/ziglang/zig/blob/7cb2f9222da38d687e8708dd5d94d3175cc77995/src/main.zig#L4080-L4126

...and move it to a new file lib/fetch_runner.zig. This is similar to build_runner.zig and test_runner.zig and has the responsibility to fetch the full dependency tree. It will deal with fetch plugins by fetching them, and then rebuilding the fetch runner itself, multiple times if necessary, until everything is fetched.

Once everything is fetched, build_runner.zig proceeds as usual. Note that in the case when everything is already fetched, the fetch_runner will not be executed because the open() syscalls on the first-level dependencies based on their hashes all succeeded.

AdamGoertz commented 1 year ago

How would this fit into the framework proposed in #14286? It sounds like the goal in that issue is to make it safer to run un-audited build.zig files from dependencies by sandboxing them with WASM, but this proposal would also allow arbitrary code execution by downloading and running fetch plugins, similarly to running someone else's build.zig.

ArtemKolichenkov commented 11 months ago

As a user of IPFS once in a blue moon, here's my 2 cents.

If you found a package that for some reason exists only on IPFS, you can

This is applicable to practically any other uncommon protocols and are generally straightforward to implement. It is also guaranteed to work with Zig (it would just see it as normal http/tar). For those who frequently use exotic protocols, they likely already have the expertise to employ standard proxy methods. If a proxy for a specific protocol isn't available, developing a general-purpose proxy could be more beneficial than creating a plugin specifically for the Zig package manager.

Even without considering security implications - this just seems like a feature creep.

Given that the package manager is still in its early development phase, focusing on foundational stability and functionality might be more prudent. I wouldn't expect this kind of feature to be available even in Zig 1.0, let alone 0.13.0

exxjob commented 11 months ago

I'd like to add, this relates to extensible v. composable, and making extensibility features at the right layer. I wouldn't be comfortable with mandated X protocols to ratify counterpart Y protocols declaratively, let alone recursively. Also not sure how indiscriminate you can get with this.

daurnimator commented 11 months ago

This is applicable to practically any other uncommon protocols and are generally straightforward to implement. It is also guaranteed to work with Zig (it would just see it as normal http/tar). For those who frequently use exotic protocols, they likely already have the expertise to employ standard proxy methods. If a proxy for a specific protocol isn't available, developing a general-purpose proxy could be more beneficial than creating a plugin specifically for the Zig package manager.

Even without considering security implications - this just seems like a feature creep.

Agreed, see also my comment at https://github.com/ziglang/zig/issues/14298#issuecomment-1735162557

KilianHanich commented 3 months ago

So, I decided that I try to tackle this over the last few days, so, here is my rather basic proposal. It may have some flaws which I overlooked, but I think it's fine for what one can get without an implementation. It makes it quite easy to e.g. implement Git over SSH (for a few reason which I mentioned in that issue #14295).

As for security considerations. The way I have formulated this one could end up restricting it in a way to make it run inside of a sandbox (e.g only access to the network and the target directory and maybe some directory for temporary files), but since for example Git over SSH users often use their SSH keys to connect to the server, I am not sure how practical that would end up being.

Anyway, here we go:

A fetch plugin is a directory with the following contents:

The plugin is supposed to behave according to the following interface:

Here an quick'n'dirty example:

Directory with the files fetch-plugin.zon, git-plugin.sh and git-plugin.bat.