Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 57s
Forgejo Docker Build / Root app tests (push) Successful in 53s
Forgejo Android APK / Build signed APK (push) Successful in 1m59s
Forgejo Docker Build / Build Docker image (push) Has been cancelled
Forgejo Docker Build / Deploy to the host (push) Has been cancelled
pptxgenjs is gone, and with it 269 lines of hand-rolled markdown parsing. It stretched every image. Reading the slide XML it emitted shows why: it writes the target box verbatim with <a:stretch/> and a no-op srcRect, so a 200x800 image handed an 11.8x3.9 box came out 1:4 squashed to 3:1. It could not do better — it never measures an image, and its own getSizeFromImage is commented out and marked "currently unused", reaching for a package called sizeof that does not exist. pandoc measures them: a 300x175 source renders at aspect 1.714 and a 160x360 at 0.445, verified by rendering the deck to PDF and looking at it. Tables, ordered and unordered lists, bold, italic and subscripts all come out natively, and the fonts, palette and slide layouts come from assets/learning/slides-reference.pptx. Design now lives in that file: restyling the decks means editing it in PowerPoint, not editing this route. Only images the requester owns can reach a deck. pandoc resolves an image link against the filesystem, so a markdown link naming any local path would read that file into the presentation. Images are fetched by id through the ownership check, written into a per-request temporary directory under names we choose, and every image link that did not resolve is removed rather than passed through. The directory is removed in a finally block, and the conversion has a 60s timeout so it cannot hang a request. pandoc is in the image rather than a sidecar, because an export must not fail for reasons outside this container. It costs 197MB (307 -> 504). Removing pptxgenjs also removed image-size, and with it both high-severity advisories — GHSA-w3rx-r6r6-pgpr and GHSA-5p2g-fcmc-qvqq, ICNS/JXL/HEIF parser denial of service, ranged <=2.0.2 with no fixed release to upgrade to. npm audit goes from 2 high and 2 moderate to 2 moderate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
57 lines
2.9 KiB
Docker
57 lines
2.9 KiB
Docker
# ─── OpenBao CLI, copied from upstream image (multi-arch automatic) ───
|
|
# Update the tag here to adopt a newer OpenBao. Binary is statically linked,
|
|
# safe to drop into the Node alpine image as-is.
|
|
# Pinned by digest, not by tag: a tag is a moving pointer, so two builds of the
|
|
# same commit could otherwise produce different images. These are manifest-list
|
|
# digests, so buildx still selects the right per-architecture variant.
|
|
FROM openbao/openbao:2.5.3@sha256:fdc6da21ca6963560c32336fd7feb9cf2d5e52668f1a1647205a4b41171f0806 AS bao-src
|
|
|
|
FROM node:24-alpine@sha256:e67514e5d0f6c46656005e1b693b2ec9d52e80b641307de684d4a015ba7a4eaf
|
|
|
|
WORKDIR /app
|
|
|
|
# ffmpeg: audio conversion for AWS Transcribe (WebM → PCM)
|
|
# curl: HTTP helper used by the OpenBao entrypoint and health/debug tooling
|
|
# jq: JSON parsing for the entrypoint's OpenBao secret-fetch step
|
|
# pandoc: Markdown → PPTX for Learning resources. It is large (~230MB), and it
|
|
# is here rather than in a sidecar because a sidecar would add a
|
|
# cross-stack network dependency to an export that must not fail for
|
|
# reasons outside this container. It also measures images, which
|
|
# pptxgenjs cannot: that library emits the target box verbatim with
|
|
# <a:stretch/>, so every image in every generated deck was distorted.
|
|
RUN apk add --no-cache ffmpeg curl jq pandoc-cli
|
|
|
|
# Pull the bao CLI out of the upstream image — matches host arch because
|
|
# buildx pulls the right manifest-list variant per build.
|
|
COPY --from=bao-src /bin/bao /usr/local/bin/bao
|
|
RUN /usr/local/bin/bao version
|
|
|
|
COPY package.json package-lock.json ./
|
|
# argon2 compiles native code via node-gyp — needs python3/make/g++ at build time
|
|
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
|
|
&& npm ci --omit=dev \
|
|
&& apk del .build-deps
|
|
|
|
COPY . .
|
|
|
|
# One validated source revision for both runtime cache busting and OCI provenance.
|
|
# Direct development builds without an explicit revision remain visibly unversioned.
|
|
ARG GIT_REVISION=unknown
|
|
RUN node -e 'const r=process.argv[1]; if (r !== "unknown" && !require("./src/utils/buildId").isGitRevision(r)) throw new Error("GIT_REVISION must be a full lowercase Git SHA"); require("node:fs").writeFileSync("BUILD_ID", r + "\n");' -- "$GIT_REVISION"
|
|
LABEL org.opencontainers.image.revision=$GIT_REVISION
|
|
|
|
# Ensure the entrypoint is executable regardless of host file permissions
|
|
RUN chmod +x /app/docker-entrypoint.sh
|
|
|
|
RUN mkdir -p /app/data/logs
|
|
|
|
EXPOSE 3000
|
|
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s \
|
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
|
|
|
# Entrypoint wrapper handles optional OpenBao secret fetch before exec'ing CMD.
|
|
# See docker-entrypoint.sh for the logic — it is a no-op if OPENBAO_ADDR is
|
|
# unset, so legacy .env-only deployments continue to work unchanged.
|
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
|
CMD ["node", "server.js"]
|