catalog / ghcr.io/gethomepage/homepage
ghcr.io/gethomepage/homepage
validated pin current tags: v1.13.2
gethomepage/homepage read-only-filesystem minimum (dashboard), derived by drop-test. homepage runs correctly under read_only:true; its config lives on a persistent VOLUME (/app/config) and its one runtime tmpfs need is /app/.next/cache — Next.js image optimization mkdir's it on the first /_next/image request and errors (unhandledRejection) when it isn't writable. A bare dashboard GET serves even without the cache, so the requirement only shows under image optimization; the drop-test correctness check exercises it. /tmp was drop-tested and is NOT required. capabilities: not yet derived. Absence means not tested for this image — not that the Docker default capability set is needed.
Use it
services:
homepage:
image: ghcr.io/gethomepage/homepage:v1.13.2
read_only: true
tmpfs:
- /app/.next/cache
Dimension: filesystem
read_only: true + tmpfs: /app/.next/cache
| tool | container-sec-derive 0.7.0 |
|---|---|
| observer | drop-test |
| validated image | ghcr.io/gethomepage/homepage@sha256:a0b71c8e7572… |
| validated date | 2026-07-03 |
| confidence | high |
| validated via | drop-test, ci-smoke |
| workload | profiles/workloads/homepage.sh |
| workload sha256 | 78802a281970… |
| ig version | v0.51.0 |
Drop-test evidence
Each candidate removed in turn, the container restarted, and the workload re-verified.
| Removed | Verdict | Observed |
|---|---|---|
/app/.next/cache | required | homepage cannot write /app/.next/cache (read-only, no tmpfs) |
/tmp | removable | homepage serving + image-optimization cache writable |
Recorded invocation (run_config)
The minimum is valid for this invocation; a different user:, volume state, or entrypoint can change it.
| env | HOMEPAGE_ALLOWED_HOSTS |
|---|
Workload script (profiles/workloads/homepage.sh)
#!/usr/bin/env bash
# Workload exerciser for the gethomepage/homepage reference image.
#
# Drives the dashboard (GET /) and Next.js image optimization (GET /_next/image,
# which writes /app/.next/cache), via docker exec so no host ports need
# publishing. Returns 0 if the dashboard serves and the image-optimization cache
# is writable (no read-only / ENOENT error), which is the correctness bar the
# filesystem profile is judged against.
#
# Required env: HOMEPAGE_CONTAINER (target container name or id).
set -euo pipefail
: "${HOMEPAGE_CONTAINER:?HOMEPAGE_CONTAINER must be set}"
C="${HOMEPAGE_CONTAINER}"
# Wait until the dashboard responds.
deadline=$((SECONDS + 40))
until docker exec "${C}" wget -qO- http://localhost:3000/ >/dev/null 2>&1; do
if (( SECONDS >= deadline )); then
echo "homepage did not become ready in 40s" >&2
exit 1
fi
sleep 2
done
# Dashboard happy path.
docker exec "${C}" wget -qO- http://localhost:3000/ >/dev/null
# Image optimization — exercises the /app/.next/cache write.
docker exec "${C}" wget -qO- "http://localhost:3000/_next/image?url=%2Ficon.png&w=64&q=75" >/dev/null 2>&1 || true
sleep 2
# Correct only if the cache write did not fail on a read-only filesystem.
# capture-then-match — `docker logs | grep -q` under pipefail SIGPIPEs the
# producer on a match, which here would read the error as ABSENT (false pass).
if grep -qiE "mkdir '/app/.next/cache'|EROFS|read-only file system" <<<"$(docker logs "${C}" 2>&1)"; then
echo "homepage could not write /app/.next/cache" >&2
exit 1
fi
Dimension: capabilities
Not yet derived — this dimension has not been drop-tested for this image. Absence means not tested, not that a minimum here is infeasible.
Evidence & provenance
- Validation criteria — per-image scenarios and pass criteria
- Profile source in the repository
- Version history — every previously published pin, with the full profile as validated against it
Raw profile YAML
# gethomepage/homepage read-only-filesystem minimum (dashboard), derived by
# drop-test. homepage runs correctly under read_only:true; its config lives on a
# persistent VOLUME (/app/config) and its one runtime tmpfs need is
# /app/.next/cache — Next.js image optimization mkdir's it on the first
# /_next/image request and errors (unhandledRejection) when it isn't writable. A
# bare dashboard GET serves even without the cache, so the requirement only shows
# under image optimization; the drop-test correctness check exercises it. /tmp was
# drop-tested and is NOT required.
#
# capabilities: not yet derived. Absence means not tested for this image —
# not that the Docker default capability set is needed.
schema_version: "1.5"
image: ghcr.io/gethomepage/homepage
reference_url: https://tmatens.github.io/container-security-profiles/profiles/ghcr.io/gethomepage/homepage.html
applies_to:
tags: ["v1.13.2"]
status: validated
dimensions:
filesystem:
read_only: true
tmpfs: [/app/.next/cache]
derivation:
tool: container-sec-derive
tool_version: "0.7.0"
sidecar_schema_version: "1.5"
observer: drop-test
validated_image: ghcr.io/gethomepage/homepage@sha256:a0b71c8e757298d02560186bab9fbe3fc2d375c523a62cc1019177b37e48aa28
validated_date: "2026-07-03"
duration_seconds: 30
confidence: high
workload: profiles/workloads/homepage.sh
workload_sha256: "78802a2819707f8857b66cce4c91a399033e71ff4db60531ca736095f2f351c8"
validated_via: [drop-test, ci-smoke]
observation_backend:
ig_version: v0.51.0
gadgets: []
run_config:
user: ""
command: []
entrypoint: ""
network: ""
pid: ""
devices: []
security_opt: []
mounts: []
env: [HOMEPAGE_ALLOWED_HOSTS]
drop_test:
checks:
- {removed: /app/.next/cache, required: true, observed: "homepage cannot write /app/.next/cache (read-only, no tmpfs)"}
- {removed: /tmp, required: false, observed: "homepage serving + image-optimization cache writable"}