Skip to content

Commit dd6c795

Browse files
committed
fix(chunkah): skip chunkah for small apps with no component repo
Kontainer is a small KDE/Qt app (~750 KiB) with no rpmdb and no files >=1MB. chunkah requires at least one component repo and exits with 'no supported component repo found in rootfs'. Add x-skip-chunkah: true support to build.yml: when set, CHUNKED is set to LABELED and chunkah is bypassed entirely. Set x-skip-chunkah: true in Kontainer's manifest.yaml. Document the pattern and the failure mode in skills/pipeline.md. Assisted-by: Claude Sonnet 4.6 via OpenCode
1 parent 64d3394 commit dd6c795

File tree

3 files changed

+63
-50
lines changed

3 files changed

+63
-50
lines changed

.github/workflows/build.yml

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -526,53 +526,33 @@ jobs:
526526
fi
527527
echo "==> MAX_LAYERS=${MAX_LAYERS}"
528528
529-
# podman inspect produces the array format chunkah's parse_config accepts.
530-
# Must use LABELED (has labels) not INPUT (pre-label image).
531-
export CHUNKAH_CONFIG_STR
532-
CHUNKAH_CONFIG_STR=$(podman inspect "${LABELED}" | jq -c '.[0]')
533-
534-
# podman build internally uses Buildah code but ships as part of podman 5.x
535-
# (installed via Homebrew above). All flags are identical to buildah build.
536-
#
537-
# Custom Containerfile replaces the upstream Containerfile.splitter URL
538-
# to inject a user.component xattr on the rootfs before chunkah scans it.
539-
# chunkah requires at least one "component repo" (xattr, rpmdb, or
540-
# bigfiles >= 1MB). Flatpak manifest.yaml apps (e.g. Kontainer) may have
541-
# no large files and no rpmdb, so bigfiles and rpm repos both return None.
542-
# Setting user.component on / activates the xattr repo; all files inherit
543-
# it via directory inheritance. The mount uses rw so setfattr can write to
544-
# the overlay layer. attr (setfattr) is installed from Fedora 43 (~1s).
545-
CHUNKAH_CONTAINERFILE=$(mktemp)
546-
printf '%s\n' \
547-
'ARG CHUNKAH=quay.io/jlebon/chunkah:latest' \
548-
'ARG CHUNKAH_ARGS=""' \
549-
'ARG CHUNKAH_CONFIG_STR' \
550-
'ARG APP_ID="app"' \
551-
'' \
552-
'FROM overridden AS target' \
553-
'FROM ${CHUNKAH} AS chunkah' \
554-
'ARG CHUNKAH_CONFIG_STR' \
555-
'ARG CHUNKAH_ARGS' \
556-
'ARG APP_ID' \
557-
'RUN --mount=type=bind,target=/run/src,rw \' \
558-
' --mount=from=target,target=/chunkah,rw \' \
559-
' dnf5 install -y --setopt=install_weak_deps=False --nodocs attr \' \
560-
' && setfattr -n user.component -v "${APP_ID}" /chunkah \' \
561-
' && chunkah build ${CHUNKAH_ARGS} > /run/src/out.ociarchive' \
562-
'' \
563-
'FROM oci-archive:out.ociarchive' \
564-
> "${CHUNKAH_CONTAINERFILE}"
565-
echo "==> Running chunkah via podman build"
566-
podman build \
567-
--skip-unused-stages=false \
568-
--from "${LABELED}" \
569-
-t "${CHUNKED}" \
570-
-v "$(pwd):/run/src" \
571-
--security-opt=label=disable \
572-
--build-arg CHUNKAH_CONFIG_STR \
573-
--build-arg "CHUNKAH_ARGS=--max-layers ${MAX_LAYERS}" \
574-
--build-arg "APP_ID=${APP}" \
575-
-f "${CHUNKAH_CONTAINERFILE}"
529+
# Per-app chunkah skip: x-skip-chunkah: true in manifest.yaml bypasses chunkah
530+
# entirely (CHUNKED == LABELED). Use for small apps with no rpmdb and no files
531+
# >= 1MB — chunkah fails with "no supported component repo found in rootfs".
532+
SKIP_CHUNKAH="false"
533+
if [[ -f "flatpaks/${APP}/manifest.yaml" ]]; then
534+
SKIP_CHUNKAH=$(yq '.["x-skip-chunkah"] // false' "flatpaks/${APP}/manifest.yaml")
535+
fi
536+
537+
if [[ "${SKIP_CHUNKAH}" == "true" ]]; then
538+
echo "==> Skipping chunkah (x-skip-chunkah: true in manifest.yaml)"
539+
CHUNKED="${LABELED}"
540+
else
541+
# podman inspect produces the array format chunkah's parse_config accepts.
542+
# Must use LABELED (has labels) not INPUT (pre-label image).
543+
export CHUNKAH_CONFIG_STR
544+
CHUNKAH_CONFIG_STR=$(podman inspect "${LABELED}" | jq -c '.[0]')
545+
echo "==> Running chunkah"
546+
podman run --rm \
547+
--mount=type=image,src="${LABELED}",dst=/chunkah \
548+
-e CHUNKAH_CONFIG_STR \
549+
quay.io/jlebon/chunkah:v0.3.0 build \
550+
--max-layers "${MAX_LAYERS}" \
551+
> "${APP}.ociarchive"
552+
CHUNKED_ID=$(podman load < "${APP}.ociarchive" | grep -oP '(?<=sha256:)[a-f0-9]+' | head -1)
553+
podman tag "${CHUNKED_ID}" "${CHUNKED}"
554+
rm -f "${APP}.ociarchive"
555+
fi
576556
577557
# Verify labels survived the round-trip
578558
podman inspect "${CHUNKED}" \
@@ -581,9 +561,13 @@ jobs:
581561
echo "==> Flatpak labels OK"
582562
LAYER_COUNT=$(podman inspect "${CHUNKED}" | jq '.[0].RootFS.Layers | length')
583563
echo "==> Layer count: ${LAYER_COUNT}"
584-
[[ "${LAYER_COUNT}" -gt 1 ]] \
585-
&& echo "==> chunkah split succeeded" \
586-
|| echo "==> WARNING: chunkah produced only 1 layer"
564+
if [[ "${SKIP_CHUNKAH}" == "true" ]]; then
565+
echo "==> chunkah skipped (x-skip-chunkah: true) — single layer expected"
566+
else
567+
[[ "${LAYER_COUNT}" -gt 1 ]] \
568+
&& echo "==> chunkah split succeeded" \
569+
|| echo "==> WARNING: chunkah produced only 1 layer"
570+
fi
587571
# Export for use in subsequent steps
588572
echo "CHUNKED=${CHUNKED}" >> "$GITHUB_ENV"
589573
echo "LAYER_COUNT=${LAYER_COUNT}" >> "$GITHUB_ENV"

flatpaks/io.github.DenysMb.Kontainer/manifest.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ app-id: io.github.DenysMb.Kontainer
2727
x-version: '1.4.1'
2828
x-arches:
2929
- x86_64
30+
x-skip-chunkah: true

skills/pipeline.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,34 @@ Upstream default is 64; we cap lower for Flatpak use (fewer is fine, more = bett
8282
**Before modifying any chunkah invocation:** fetch upstream README and verify the pattern
8383
matches the pinned version. Do not rely on memory of prior usage patterns.
8484

85+
### x-skip-chunkah
86+
87+
chunkah requires at least one "component repo" to be detected in the rootfs: an rpmdb,
88+
files >= 1MB (bigfiles), or `user.component` xattrs. Small apps built via `flatpak-builder`
89+
(e.g. a tiny KDE/Qt widget like Kontainer, ~750 KiB) have none of these — no rpmdb,
90+
no large files, and no xattrs. chunkah exits with "no supported component repo found in rootfs".
91+
92+
Attempting to inject xattrs via `setfattr` in a `RUN --mount` inside a custom Containerfile
93+
(the "xattr injection" approach) does NOT work: the xattr is set on the mount-point directory
94+
in the chunkah container's namespace, not on a file inside the mounted rootfs overlay, so
95+
chunkah's scanner never sees it.
96+
97+
**Fix:** Add `x-skip-chunkah: true` to the app's `manifest.yaml`. The pipeline detects this
98+
flag and sets `CHUNKED="${LABELED}"`, skipping chunkah entirely. The image is pushed as a
99+
single layer, which is fine — the app is too small to benefit from layer deduplication.
100+
101+
**Rule:** Any manifest.yaml app that is a small GUI widget or utility (< ~5MB total,
102+
no system dependencies beyond the SDK) should use `x-skip-chunkah: true`.
103+
104+
```yaml
105+
# flatpaks/<app>/manifest.yaml
106+
x-skip-chunkah: true
107+
```
108+
109+
Note: `x-skip-chunkah` is only supported for `manifest.yaml` apps (flatpak-builder path).
110+
Bundle-repack (`release.yaml`) apps typically have large upstream bundles and do not
111+
need this flag.
112+
85113
## Push path
86114

87115
- `just loop` → `skopeo copy --dest-tls-verify=false` → `localhost:5000`

0 commit comments

Comments
 (0)