# Inspect operating-system package sources in a Yeeted build

One image, three base operating systems, one question: **did the distro
package manager fetch from the Artifact Keeper, or from the public internet?**

Every other example here proves a language stack builds. This one proves the
layer underneath it. A synthesized Ruby image runs

```
apt-get update && apt-get install -y build-essential libpq-dev ...
```

before bundler installs a single gem, and until the keeper had OS archives
every byte of that (about 107 MB on the Rails path) came straight off
`deb.debian.org`.

## What it does

Four stages:

| stage  | base                 | package manager | records            |
|--------|----------------------|-----------------|--------------------|
| `deb`  | `debian:bookworm-slim` | apt           | `/out/debian.json` |
| `ubu`  | `ubuntu:24.04`         | apt           | `/out/ubuntu.json` |
| `arch` | `archlinux:base`       | pacman        | `/out/arch.json`   |
| app    | `python:3.12-slim`     | -             | serves all three   |

Each of the first three installs the same package (`jq`) with its own package
manager and records the **host that package manager resolved** for it, read
back out of `apt-get install --print-uris` and `pacman -Sp`. The app serves
those three records at `/os`, plus one derived field:

```json
"mirrored": true
```

which is true when all three resolved to a single endpoint and that endpoint is
not a public archive.

There is nothing platform-specific in the Dockerfile on purpose. build-service
injects the mirror configuration itself
(`services/build-service/osmirror.go`), so:

- `docker build .` on a laptop reports `deb.debian.org`, `archive.ubuntu.com`
  and a pkgbuild mirror, and `"mirrored": false`.
- The same file deployed to Yeeted reports the keeper three times, and
  `"mirrored": true`.

That difference is the test.

## Where it fits

`infra/keeper-proxy-gate.sh` runs at deploy time and proves the keeper
**answers** for each archive: Debian, debian-security, Ubuntu,
ubuntu-security, Alpine and Arch. It cannot prove a build **used** them.
This example is the other half, and it runs after the deployment:

```
sh smoke.sh https://<your-deployment>
```

`qa/test_examples.py` deploys it and asserts the same thing.

## Endpoints

- `GET /healthz` - `ok`
- `GET /os` - the three build records, the derived `mirrored` flag, and the
  distinct source hosts

## Caveats

- Arch is not an Artifact Keeper repository. The keeper's format enum has no
  pacman entry and its `generic` format routes nothing, so pacman is served by
  the nginx sidecar beside the keeper under `/arch/`
  (`infra/keeper-gems-proxy.conf.template`). That is why the Arch source host
  is the same name on a different port.
- No database, no state. The interesting work all happened at build time.

## Run locally

Use Docker and allow access to the base-image registries and package archives.
From `os/os-matrix`:

```sh
docker build -t yeeted-os-matrix .
docker run --rm -p 8080:8080 yeeted-os-matrix
```

Open `http://localhost:8080/os`. A local build usually reports public package
sources and `"mirrored": false`. That is an expected local result, not a
failed application build. This example is an infrastructure diagnostic rather
than an end-user application template.

## Deploy and verify

Follow the [deployment walkthrough](getting-started.md). Deploy the
whole folder with its multi-stage Dockerfile and `yeeted.yaml`, with no
database. The runtime listens on port 8080.

```sh
sh smoke.sh "$PREVIEW_URL"
curl -fsS "$PREVIEW_URL/os"
```

The smoke script expects a Yeeted deployment to report three package-source
records and `"mirrored": true`. Check that every build record has a source
and no error. The flag compares source hostnames to a short list of public
archives; it is a diagnostic heuristic, not cryptographic evidence of package
provenance or a measurement of build speed.

## Sharing results

The response includes package-source hostnames. Inspect those before sharing
build reports publicly. Base images and package archives change over time;
record the source revision and actual build output when comparing two runs.
No standalone unit test suite is included in this example.

[All examples](index.md) · [Deploy an example](getting-started.md)
