lsupg Static Builds With GHC 9 (Part 3)
I made some time to work on lsupg
yesterday. My plan was to first reconfigure the project to use benz0li/ghc-musl
images from Docker Hub, but I unfortunately ran
into issues immediately.
As described in my blog entry on Testing GHC Versions, my goal is to maintain Haskell software to work with five years of GHC, boot libraries, and Cabal versions. In practice, I test against the latest release of each GHC minor version, so I currently try to test (at least) the following GHC versions.
GHC Version | Release Date | Cabal Version |
---|---|---|
8.6.5 | 2019-04-23 | 2.4 |
8.8.4 | 2020-07-15 | 3.0 |
8.10.7 | 2021-08-27 | 3.2 |
9.0.2 | 2021-12-25 | 3.4 |
9.2.8 | 2023-05-26 | 3.6 |
9.4.8 | 2023-11-10 | 3.8 |
9.6.5 | 2024-04-16 | 3.10 |
9.8.2 | 2024-02-23 | 3.10.2.0 |
I have been using utdemir/ghc-musl
to build lsupg
static executables. The oldest supported GHC version is GHC 8.8.4, so
this is also the oldest version that lsupg
supports. The oldest supported GHC version is the same in benz0li/ghc-musl
.
Attempting to build a static executable using Stack and GHC 8.8.4, the build
failed before compilation because groupadd
is not found.
Stack uses this to manage permissions, so that the ownership of files
created within the container match the ownership of the project files in
the host system. This command is provided by the shadow
package. Checking the source, I confirmed which builds include this
package. The images for GHC versions 8.8.4, 8.10.7, and 9.0.2 are
problematic for me.
GHC Version | shadow |
---|---|
8.8.4 | |
8.10.1 | |
8.10.4 | |
8.10.5 | |
8.10.6 | |
8.10.7 | |
9.0.1 | |
9.0.2 | |
9.2.1 | |
9.2.2 | |
9.2.3 | |
9.2.4 | |
9.2.5 | |
9.2.6 | |
9.2.7 | |
9.2.8 | Installed |
9.4.1 | |
9.4.2 | |
9.4.3 | |
9.4.4 | |
9.4.5 | |
9.4.6 | Installed |
9.4.7 | Installed |
9.4.8 | Installed |
9.6.1 | |
9.6.2 | Installed |
9.6.3 | Installed |
9.6.4 | Installed |
9.6.5 | Installed |
9.8.1 | Installed |
To fix this missing shadow
package issue, the package needs to be added so that the image works
with Stack. Adding packages is a common need, as developers need to add
packages that are required to build their applications. For example, an
application that needs to work with PNG files may require the libpng-static
package.
There are a few ways to do this. One option is to build new images
from scratch, using edited versions of benz0li/ghc-musl
Dockerfile
s. As noted in my previous blog entry, however, I
have had issues with building benz0li/ghc-musl
images locally. Even if I can figure out a way to resolve these issues,
building GHC is costly in terms of resources and time. Another option is
to create new images on top of the existing images, so that GHC does not
need to be rebuilt. Note that installing packages when running an
existing image is not an option when using Stack.
This reminded me of a much more significant issue, however. Security is a major concern with static executables because libraries are included in the executables. When using dynamically linked executables, upgrading a library to fix a security vulnerability generally fixes the vulnerability for all of the dynamically linked executables that use the library. Static executables, on the other hand, must be rebuilt using the new libraries. In general, a static build should use the latest (compatible) version of Alpine, with all installed packages updated to the latest versions available.
As documented in SECURITY.md
,
only the image for the latest version of GHC is updated with security
updates. The (other) images on Docker Hub are therefore not
suitable for use when security is a concern. For images that use the
most recent Alpine version, it is possible to create new images that
upgrade the installed packages. For images that use older Alpine
versions, however, new images need to be built from scratch.
Supporting five years of dependencies and worrying about security for
lsupg
may seem a bit silly. One of my goals for the project, however, is to
use it as a public project for developing and testing such things. I
have worked on proprietary projects where these things are taken very
seriously. Some companies have very strict security requirements! lsupg
allows me to work on this in public, which makes it easier to
collaborate with others as well as provides information to anybody else
who may need to do something similar.