| 1 |
# 7. Installing software |
| 2 |
|
| 3 |
This is the chapter that makes an atomic system make sense. It is also the |
| 4 |
thing Alloy is most opinionated about. |
| 5 |
|
| 6 |
On a normal distro there is one question: install it or not. Here there are |
| 7 |
three places software can live, and picking the right one is most of the skill. |
| 8 |
Alloy replaces "which tool" with one question: **how much of your machine |
| 9 |
should this software be able to reach?** |
| 10 |
|
| 11 |
## The isolation dial |
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
| `host` | Your whole home directory, your devices, the session bus | Development toolchains, anything that must feel installed | |
| 16 |
| `workspace` | Its own private home, plus the directories you name | Running someone else's build, a package manager over untrusted code | |
| 17 |
| `sandboxed` | What a portal hands it: a file picker, permission-gated devices | Graphical apps you did not write | |
| 18 |
|
| 19 |
You pick the level. Alloy picks the implementation behind it: distrobox for |
| 20 |
`host`, podman directly for `workspace`, flatpak for `sandboxed`. The level is |
| 21 |
the stable interface, which is why the backend can change later without your |
| 22 |
boxes changing. |
| 23 |
|
| 24 |
**Be clear about what `workspace` is.** A rootless container with a bind mount |
| 25 |
limits blast radius. It is not a security boundary and Alloy will not call it |
| 26 |
one. `sandboxed` is the only level with a real isolation model behind it. |
| 27 |
|
| 28 |
## Boxes |
| 29 |
|
| 30 |
alloy pkg box |
| 31 |
|
| 32 |
lists every box on the machine, including ones created outside Alloy with a |
| 33 |
bare `podman run` or a direct `flatpak install`. An inventory that hid those |
| 34 |
would be lying. Rows mark which boxes are declared (reproducible) and which are |
| 35 |
ad hoc (gone on a rebuild). |
| 36 |
|
| 37 |
From that tab you can start, stop, enter, remove, and export a box. |
| 38 |
|
| 39 |
**Entering** a box hands the terminal over to it, so the console tears itself |
| 40 |
down and comes back when you exit. |
| 41 |
|
| 42 |
**Exporting** puts a command from inside a box onto your host `PATH`, at |
| 43 |
`~/.local/bin`, which Fedora already searches. Running `rg` then runs it inside |
| 44 |
its box, in the right directory, starting the box first if it was stopped. |
| 45 |
|
| 46 |
An exported wrapper takes the plain name of the binary, so two boxes exporting |
| 47 |
`rg` would land on one file, and exporting something the host already has would |
| 48 |
put the box's copy ahead of the system one. Neither happens quietly: an export |
| 49 |
whose name is already taken is refused, and the message names the file or the |
| 50 |
host path in the way. Drop the name from that box's `export.bin`, or clear |
| 51 |
whatever holds it, and export again. |
| 52 |
|
| 53 |
## Declaring boxes |
| 54 |
|
| 55 |
Boxes can be described in TOML, which makes them reproducible and syncable: |
| 56 |
|
| 57 |
```toml |
| 58 |
[box.dev] |
| 59 |
level = "host" |
| 60 |
image = "registry.fedoraproject.org/fedora-toolbox:43" |
| 61 |
export = { bin = ["rg", "fd", "hx"] } |
| 62 |
|
| 63 |
[box.scratch] |
| 64 |
level = "workspace" |
| 65 |
image = "registry.fedoraproject.org/fedora-toolbox:43" |
| 66 |
mounts = ["~/code/thing"] |
| 67 |
|
| 68 |
[box.somegui] |
| 69 |
level = "sandboxed" |
| 70 |
app = "org.example.SomeApp" |
| 71 |
``` |
| 72 |
|
| 73 |
`host` and `workspace` boxes take an `image`; a `sandboxed` box is one app, so |
| 74 |
it takes an `app`. |
| 75 |
|
| 76 |
## Layering onto the base image |
| 77 |
|
| 78 |
The fourth option is putting a package into the operating system itself: |
| 79 |
|
| 80 |
rpm-ostree install <package> |
| 81 |
|
| 82 |
This does not change the running system. It stages a new deployment that takes |
| 83 |
effect at the next boot. `alloy pkg install` shows what is layered and which |
| 84 |
rows are staged rather than active, which is the single most confusing thing |
| 85 |
about an atomic base and the reason that tab exists. |
| 86 |
|
| 87 |
Layer sparingly. Every layered package slows down every future image update, |
| 88 |
and a package you layer is one that has to keep resolving against a base that |
| 89 |
moves. If it can be a box, make it a box. |
| 90 |
|
| 91 |
Removing one is `rpm-ostree uninstall <package>`, and it stages the removal the |
| 92 |
same way. |
| 93 |
|
| 94 |
Whatever you install, it arrives without its man page. The image is built with |
| 95 |
documentation excluded, which is the largest single thing that keeps it from |
| 96 |
being a quarter of a gigabyte bigger, and rpm gives no way to keep man pages |
| 97 |
while dropping the rest of `%doc`. Most tools answer `--help`; for the rest, |
| 98 |
upstream's own documentation is a search away. If you would rather have the |
| 99 |
pages, build your image with `TRIM=keep` (chapter 2) and they come back along |
| 100 |
with every translation. |
| 101 |
|
| 102 |
## Sandboxed apps |
| 103 |
|
| 104 |
The `flatpak` client is in the image, no Flatpaks are provisioned, and **no |
| 105 |
remote is configured**. That last part is deliberate: a remote is a catalog, |
| 106 |
and a catalog is a decision about who your software comes from. Alloy does not |
| 107 |
make that one for you. |
| 108 |
|
| 109 |
So the first step is yours. Add whichever catalog you want: |
| 110 |
|
| 111 |
flatpak remote-add --user --if-not-exists <name> <url> |
| 112 |
|
| 113 |
Then apps install from it in the ordinary way: |
| 114 |
|
| 115 |
flatpak install <name> org.example.SomeApp |
| 116 |
|
| 117 |
`alloy pkg` uses the same remotes; a box entry can name one, and one that does |
| 118 |
not is resolved across whatever you have added. Alloy ships no graphical file |
| 119 |
manager, so this is where one comes from if you want one. |
| 120 |
|
| 121 |
## What a sandboxed app does not get |
| 122 |
|
| 123 |
Alloy trims flatpak's default permissions before an app ever asks. The image |
| 124 |
ships system-wide overrides that remove three grants: X11 access, raw access to |
| 125 |
every device node, and blanket access to your home directory and the host |
| 126 |
filesystem. GPU access stays, because a video player or a browser without it is |
| 127 |
not usable. |
| 128 |
|
| 129 |
That is a smaller sandbox than most catalogs assume, so some apps will misbehave. Give |
| 130 |
back what one actually needs, per app: |
| 131 |
|
| 132 |
flatpak override --user org.example.SomeApp --filesystem=~/Projects |
| 133 |
|
| 134 |
The list of what an app currently has: |
| 135 |
|
| 136 |
flatpak info --show-permissions org.example.SomeApp |
| 137 |
|
| 138 |
The defaults live in `/var/lib/flatpak/overrides/global`. It is yours to edit, |
| 139 |
and an image update will not overwrite it once it exists. |
| 140 |
|
| 141 |
## X11 applications do not run |
| 142 |
|
| 143 |
There is no X server. Alloy is a Wayland-only session and the sway config ships |
| 144 |
`xwayland disable`, so an application that can only speak X11 exits saying it |
| 145 |
cannot open a display. |
| 146 |
|
| 147 |
This affects Steam, most Electron applications, some screen-sharing paths, and |
| 148 |
older Java toolkits. Anything Wayland-native is unaffected, and most Electron |
| 149 |
apps can be told to use Wayland with `--ozone-platform=wayland`. |
| 150 |
|
| 151 |
The reason is that X11 gives every client the ability to read every other |
| 152 |
client's keystrokes and window contents. A sandboxed app with X11 access is not |
| 153 |
sandboxed in any way that matters. |
| 154 |
|
| 155 |
If you need it back, put this in `~/.config/sway/config.d/` and log in again: |
| 156 |
|
| 157 |
xwayland enable |
| 158 |
|
| 159 |
Your file wins over the shipped one. The Xwayland package stays in the image so |
| 160 |
that this works without rebuilding. Turning it on is a real cost, not a |
| 161 |
formality: it applies to the whole session, not to the one app you wanted. |
| 162 |
|
| 163 |
## Which one, in practice |
| 164 |
|
| 165 |
- **A CLI tool you use daily and Fedora has it.** Layer it, or put it in a |
| 166 |
`host` box and export it. Layering is simpler; the box keeps the base clean. |
| 167 |
- **A language toolchain for one project.** `workspace`, with the project |
| 168 |
directory mounted. |
| 169 |
- **A graphical app from the internet.** `sandboxed`. |
| 170 |
- **Something the desktop itself needs to work** (a compositor piece, a font, a |
| 171 |
daemon). Edit the Containerfile and rebuild. That is what the builder model |
| 172 |
is for. |
| 173 |
|