Skip to content

Binds permission mounts an empty directory over /app, crash-looping the extension on install #5

Description

@KevinGriffin-new

Summary

The Dockerfile's permissions label includes:

"Binds": ["/usr/blueos/extensions/$IMAGE_NAME:/app"]

This entry breaks the extension when installed through Kraken, for two independent reasons:

  1. $IMAGE_NAME is never substituted. All the labels are single-quoted (LABEL permissions='...'), and Docker does not perform build-arg/env expansion inside single-quoted LABEL values (Dockerfile reference, "Environment replacement"). The published image (esalexander/blueos-quickstart:main) carries the literal string $IMAGE_NAME in the label — as well as literal $AUTHOR, $AUTHOR_EMAIL, $MAINTAINER, $OWNER, and $REPO in the authors, company, readme, and links labels, which are all single-quoted too. This is easy to verify: build with --build-arg IMAGE_NAME=foo and docker inspect still shows the literal $IMAGE_NAME.

  2. Even with correct substitution, binding over /app shadows the application code. On first install the host directory doesn't exist, so Docker creates it empty and mounts it over /app. The image's code at /app (copied by COPY app /app) becomes invisible to the container. The pip install /app step installs a quickstart distribution but no importable application modules, so litestar run depends entirely on discovering the app from the /app directory contents — which the bind has just emptied.

Observed behavior

Installing the extension via Kraken (POST /kraken/v1.0/extension/install) on BlueOS master starts the container, Docker creates the empty host dir /usr/blueos/extensions/$IMAGE_NAME (literal $IMAGE_NAME as the directory name), mounts it over /app, and the entrypoint crash-loops:

Could not find a Litestar app or factory.

Reproduction (no BlueOS needed)

# Works — /app contains the code baked into the image:
docker run --rm -p 8000:8000 esalexander/blueos-quickstart:main

# Crash-loops — same empty-dir bind that Kraken applies from the permissions label:
mkdir -p /tmp/empty
docker run --rm -p 8000:8000 -v /tmp/empty:/app esalexander/blueos-quickstart:main

Confirmed 2026-07-10 on BlueOS core master (Docker Desktop / arm64, and the failure mode is platform-independent).

Impact

Every extension forked from this template inherits the broken bind, and the failure (crash-loop with an app-discovery error) doesn't obviously point back at the permissions label.

Suggested fix

The only thing in /app that benefits from persistence is the log directory (main.py writes to /app/logs). So either:

  • Drop the Binds entry entirely (logs become ephemeral, extension works), or
  • Bind only the logs subdirectory with a literal path, e.g. "Binds": ["/usr/blueos/extensions/quickstart/logs:/app/logs"], so persistence survives without shadowing the code.

Independent of the choice above, it would make the template more robust to add WORKDIR /app (or an explicit --app main:app) so app discovery doesn't depend on the container's default working directory, and to fix the other single-quoted labels so $AUTHOR/$OWNER/$REPO actually substitute (double-quote the label values, or move the JSON to --label build flags).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions