Summary
The educates binary in the educates-cli container image embeds the Hugo renderer themes at files/educates/... and files/educates-classic/..., but the renderer expects them under files/themes/.... With that binary, educates workshop render and educates cluster workshop serve cannot find the educates Hugo theme. CLI binaries built with the Makefile, including the ones attached to GitHub releases, embed the themes at the correct path and are not affected.
Where
client-programs/Dockerfile, lines 25-30:
RUN rm -rf pkg/renderer/files && \
mkdir -p pkg/renderer/files && \
mkdir -p bin
COPY --from=themes-source /opt/eduk8s/etc/themes pkg/renderer/files/
When the source of a COPY is a directory, Docker copies the contents of the directory and not the directory itself, so this produces pkg/renderer/files/educates and pkg/renderer/files/educates-classic.
The other places which stage the themes, the stage-renderer-files target in the Makefile (line 230) and .github/workflows/build-and-publish-images.yaml (lines 435, 482, 529 and 577), use cp -rp workshop-images/base-environment/opt/eduk8s/etc/themes client-programs/pkg/renderer/files/, which produces pkg/renderer/files/themes/educates.
client-programs/pkg/renderer/hugo.go embeds files/* (line 35), copies the embedded files into a temporary directory (line 415), and runs Hugo with --themesDir <tempdir>/themes (lines 371 and 648). Only the files/themes/... layout matches.
Reproduction
The embedded paths can be read from the binary in the image:
$ docker create --name cli localhost:5001/educates-cli:latest /educates
$ docker cp cli:/educates ./educates-linux
$ docker rm cli
$ strings educates-linux | grep -o -E "files/(themes/)?educates(-classic)?/layouts/_default/baseof.html"
files/educates-classic/layouts/_default/baseof.html
files/educates/layouts/_default/baseof.html
The same check against a CLI built with make build-cli gives files/themes/educates-classic/... and files/themes/educates/....
This was checked with an educates-cli image built locally from the current client-programs/Dockerfile. Running educates workshop render with the binary from the image was not tried. The failure follows from the --themesDir path above.
Impact
- Anyone using the binary from the
educates-cli image, for example by copying it into their own image as the quick start guide describes (project-docs/getting-started/quick-start-guide.md, line 101), and running educates workshop render or educates cluster workshop serve where Hugo is installed.
- Commands which do not use the Hugo renderer are not affected. Inside the
educates-cli image itself Hugo is not installed.
History
The COPY was added together with the Dockerfile in b46ea44 ("Modifications on the build process so that multiplatform images are built with buildkit and there's a new cli image.", 2025-10-10). It is not changed by #1202.
Suggested fix
Copy the themes into the themes subdirectory:
COPY --from=themes-source /opt/eduk8s/etc/themes pkg/renderer/files/themes/
A RUN test -f pkg/renderer/files/themes/educates/hugo.toml after the copy would stop a regression from producing an image again.
#1203 proposes committing the themes under client-programs/ and embedding them directly, which would remove this copy altogether. Until then, the published educates-cli image carries the wrong layout.
Summary
The
educatesbinary in theeducates-clicontainer image embeds the Hugo renderer themes atfiles/educates/...andfiles/educates-classic/..., but the renderer expects them underfiles/themes/.... With that binary,educates workshop renderandeducates cluster workshop servecannot find theeducatesHugo theme. CLI binaries built with the Makefile, including the ones attached to GitHub releases, embed the themes at the correct path and are not affected.Where
client-programs/Dockerfile, lines 25-30:When the source of a
COPYis a directory, Docker copies the contents of the directory and not the directory itself, so this producespkg/renderer/files/educatesandpkg/renderer/files/educates-classic.The other places which stage the themes, the
stage-renderer-filestarget in theMakefile(line 230) and.github/workflows/build-and-publish-images.yaml(lines 435, 482, 529 and 577), usecp -rp workshop-images/base-environment/opt/eduk8s/etc/themes client-programs/pkg/renderer/files/, which producespkg/renderer/files/themes/educates.client-programs/pkg/renderer/hugo.goembedsfiles/*(line 35), copies the embedded files into a temporary directory (line 415), and runs Hugo with--themesDir <tempdir>/themes(lines 371 and 648). Only thefiles/themes/...layout matches.Reproduction
The embedded paths can be read from the binary in the image:
The same check against a CLI built with
make build-cligivesfiles/themes/educates-classic/...andfiles/themes/educates/....This was checked with an
educates-cliimage built locally from the currentclient-programs/Dockerfile. Runningeducates workshop renderwith the binary from the image was not tried. The failure follows from the--themesDirpath above.Impact
educates-cliimage, for example by copying it into their own image as the quick start guide describes (project-docs/getting-started/quick-start-guide.md, line 101), and runningeducates workshop renderoreducates cluster workshop servewhere Hugo is installed.educates-cliimage itself Hugo is not installed.History
The
COPYwas added together with the Dockerfile in b46ea44 ("Modifications on the build process so that multiplatform images are built with buildkit and there's a new cli image.", 2025-10-10). It is not changed by #1202.Suggested fix
Copy the themes into the
themessubdirectory:COPY --from=themes-source /opt/eduk8s/etc/themes pkg/renderer/files/themes/A
RUN test -f pkg/renderer/files/themes/educates/hugo.tomlafter the copy would stop a regression from producing an image again.#1203 proposes committing the themes under
client-programs/and embedding them directly, which would remove this copy altogether. Until then, the publishededucates-cliimage carries the wrong layout.