Iguana: Zig downloader and version manager in 64 lines of code

iguana:


Zig downloader and version manager in 64 lines of code

www.codeberg.org/mslapek/iguana

It allows easy installation of various Zig versions, to use them directly from the shell:

$ iguana install 0.16.0
$ iguana install 0.15.2

$ zig version  # will print 0.16.0, by default takes the newest installed version

$ export ZIG_RELEASE=0.15.2
$ zig version  # will print 0.15.2
$ zig zen

The distinguishing feature - auditable, the self-contained script consists only of 64 lines of POSIX shell script:

$ wc -l iguana
      64 iguana

Recently there’s a lot of discussion about chain supply attacks. This prompted me to make that script and experiment how “lean” we can get our software (and the pain points resulting from that).

Explicitly README.md asks you to audit the script, with the philosophy “don’t trust me”.

Stuff I learned

  • It turns out that the tar shell command isn’t in the POSIX standard, instead there’s a pax tool. However, I’ve decided to go with tar in my script, because it’s more popular (battle tested!). The homepage of GNU paxutils feels abandoned (last update in 2011).

  • Making a documentation of this script was boring, however it displayed to me, what could be improved in it - to remove stuff from README.md (less is more). For instance:

    • original instructions required user to set $ZIG_RELEASE in .bashrc - so I made the newest installed version the default - to remove this requirement,
    • requirements mentioned sort utils with -V/--version-sort, which isn’t present in POSIX. So I’ve managed to sort by version without that extension with POSIX sort.
    • user was requested to manually mkdir ~/.iguana, now script creates the dir before Zig’s installation.

Design decisions

To make the script lean, I’ve made a few compromises:

  • crude error messages, no build-in documentation,
  • user has to modify parameters in the script (at least it encourages to take a look at that),
  • limited argument verification, for instance you can pass an excessive number of parameters, like iguana install 0.16.0 foo bar.

The repo has some smoke tests in pytest - so I can test the script in various environments easily with make test. However, it isn’t TDD - had I accidentally omitted minisign invocation in the script, the current tests wouldn’t catch that.

Supported Zig versions

All published Zig releases (or at least those that have a similar tarball structure as Zig 0.16.0).

It should work on all Unix-like OSes satisfying the requirements from README.md.

8 Likes

Like this! We also have a version of similar thing in TigerBeetle, which should be good enough to copy-paste:

  • Its a local per-project install, rather than global install
  • Checks hashes, rather than signatures
  • Hash-checking is also used to implement download caching (I believe iguana does the same, just wanted to call this out as a positive important-for-ci thing)
  • work on windows as well.
2 Likes

The script from Tigerbeetle looks cool.

The trick with a Powershell comment in ./zig/download.ps1 is something new for me - a script which runs both under Windows and UNIX.

Hashes vs signatures

  • Yeah, your script with sha256sum is indeed better for CI - because we want to confirm that the downloaded tar is the same as on our development machines. Even in the case of private keys leak (or just a bug in the release software), automation will not start autonomously consuming tampered software.

  • However, if a dev wants to experiment with various Zig versions (“browse around”), they would need to add manually the reference to the sha256 sum to the script. In that case, iguana’s approach is more attractive.

Per project vs per UNIX user install

Per project install is less brittle because it only puts stuff in the project’s dir. And removal of that dir cleans up all artifacts, instead of ~/.magic or ~/.cache/magic floating in the home dir.

On the other hand, iguana assumes that Zig 0.16.0 is the same Zig 0.16.0 for all projects used by the user - so it’s only once unpacked in ~/.iguana/ver/0.16.0.

To reduce chances of corrupting Zig’s installation (for instance, in an editor, by browsing stdlib files), iguana removes write permissions on installed Zig:

chmod -R a-w "ver/$ZIG_RELEASE"

Assuming you don’t use :w! in vi. :stuck_out_tongue:

Mirrors

I’ve noticed that Tigerbeetle’s zig/download.sh uses such URLs:

${ZIG_MIRROR}/0.14.1/zig-aarch64-linux-0.14.1.tar.xz

Unfortunately, it doesn’t work with mirrors from https://ziglang.org/download/community-mirrors.txt.

For instance, https://zigmirror.com has tarballs directly under the root, not in the 0.14.1 directory:

${ZIG_MIRROR}/zig-aarch64-linux-0.14.1.tar.xz

I was myself surprised by that.

Iguana out of the box uses mirrors instead of https://ziglang.org/download, because due to human nature - people will forget to set the mirror and strain ziglang.org.

I really like that cool project. Its dead simple, but works (and despite writing shell scripts for years, I learned a new and easy way of argument parsing from it :wink:). I’m about to switch to it and leave anyzig behind.

Maybe an idea for a little enhancement: If you want to install the current dev version, you need to search for the (unintuitive) version number and copy it to your shell. E.g. iguana install 0.17.0-dev.1099+7db2ef610. While this works, it might be more convenient to be able to just type iguana install master.

Edit: In my fork, I added a iguana install repo argument which mimics anyzig’s behaviour of installing the version specified in build.zig.zon. Its just one (longer) additional line of code. Was just for fun, but maybe its an interesting option: additional line

1 Like

Neat! Nice and small. Btw I noticed a missing part of the verification: https://codeberg.org/mslapek/iguana/issues/2
tl;dr:

To prevent downgrade attacks, a “file” field in the trusted comment is provided that must be verified to match the name of the requested tarball. The reference implementation, minisign, will verify the trusted comment but does not look for a “file” field, so this verification step must be implemented manually.

2 Likes

learned a lot from this post, thanks!
I love this sort of practical learnings / tips
Never really thought of lean software as a means to more transparent software, makes total sense

1 Like