Commit 76bf7bf
fix(docker): add coreutils so MAX_LIFETIME_SECONDS works on Wolfi base (#586)
## Summary
`MAX_LIFETIME_SECONDS` is broken on the published `unstructured-api`
image and has been since the base image moved from RockyLinux to
Chainguard Wolfi (#423).
`scripts/app-start.sh` runs GNU `timeout` with `--preserve-status` and
`--foreground` when `MAX_LIFETIME_SECONDS` is set. The Wolfi base only
provides BusyBox `timeout`, which does not support those flags, so
BusyBox rejects the first one and exits non-zero. uvicorn never
launches, the script falls through to its shutdown echoes, and a
container with a restart policy loops.
GNU coreutils shipped for free as part of the old RockyLinux userland
and was lost in the distro swap; it has never been an explicit package
in the Dockerfile. This PR adds it back.
Reported in Pylon 2657. Fixes ENG-1428.
## Reproduction
Runs the real `scripts/app-start.sh` with a stub standing in for
uvicorn.
Current base (BusyBox `timeout`), server never starts:
```
$ docker run --rm -e MAX_LIFETIME_SECONDS=3 -v "$PWD:/work" \
--entrypoint sh cgr.dev/chainguard/wolfi-base:latest \
-c 'apk add --no-cache bash >/dev/null 2>&1; export PATH=/work/bin:$PATH; cd /work; bash app-start.sh'
Server's lifetime set to 3 seconds.
timeout: unrecognized option '--preserve-status'
BusyBox v1.38.0 multi-call binary.
Usage: timeout [-s SIG] [-k KILL_SECS] SECS PROG ARGS
Server was shutdown
Reached timeout of 3 seconds
```
The stub "server started" line never prints.
With this fix (base + coreutils), server launches and runs for the full
lifetime:
```
$ docker run --rm -e MAX_LIFETIME_SECONDS=3 -v "$PWD:/work" \
--entrypoint sh cgr.dev/chainguard/wolfi-base:latest \
-c 'apk add --no-cache bash coreutils >/dev/null 2>&1; export PATH=/work/bin:$PATH; cd /work; bash app-start.sh'
Server's lifetime set to 3 seconds.
[stub-uvicorn] server started, args: prepline_general.api.app:app --log-config logger_config.yaml --host 0.0.0.0 --port 8000 --workers 1
Server was shutdown
Reached timeout of 3 seconds
```
## CVE impact
`apk add coreutils` was scanned with grype (DB 27 August 2026) on
`cgr.dev/chainguard/wolfi-base:latest`:
| Image | apk packages | CVEs |
| --- | --- | --- |
| base as-is | 15 | 0 |
| base + coreutils | 21 | 0 |
It pulls in 6 Chainguard-maintained packages (coreutils, libacl1,
libattr1, libpcre2-8-0, libselinux, libsepol), all with no known
vulnerabilities. Image size grows about 10 MB. Adding coreutils does not
reintroduce the RockyLinux CVE surface that #423 was shedding.
## Notes
- The guard in `app-start.sh` (`command -v timeout`) is also broken
independent of the base image: BusyBox `timeout` satisfies the check, so
the intended `gtimeout` fallback never runs. This PR fixes the reported
bug by making GNU `timeout` present; hardening the script to detect
BusyBox vs GNU would make it robust regardless of base and can be a
follow-up.
- The `core-product` mirror of this Dockerfile (base
`cgr.dev/unstructured.io/python-fips:3.12-dev`) is also Wolfi-based and
lacks coreutils, so it needs the same change.
## Test plan
- [x] Reproduced the failure with the real `app-start.sh` on the current
base
- [x] Verified the server starts and runs for the full lifetime with
coreutils
- [x] Confirmed 0 new CVEs via grype
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent b887028 commit 76bf7bf
3 files changed
Lines changed: 8 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
1 | 7 | | |
2 | 8 | | |
3 | 9 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
0 commit comments