blob: 69bafdce75d53ff49255ab9e6ef12dd9432493a4 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Both bases are pinned by digest, not by tag. A tag moves; a release image that cannot be
# rebuilt from its own Dockerfile a year later is not much of a release artifact, and the SBOM
# published beside it would describe a build nobody can reproduce. The tag is kept in the comment
# so a human can see what the digest was when it was pinned.
# ---------------------------------------------------------------------------------------------
# Stage 1 — build the Angular application
# ---------------------------------------------------------------------------------------------
FROM node:24-alpine@sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43 AS build
WORKDIR /app
COPY package.json package-lock.json ./
# `npm ci`, not `npm install`. `install` is free to resolve a transitive dependency to a version
# the lockfile does not name, so the image would not be reproducible from the lockfile the SBOM
# and the licence scan both describe. CI has a whole job (Dependency Integrity) enforcing this for
# the build; the image had been exempt from it, which is the one place it matters most.
RUN npm ci
COPY . .
RUN npm run build -- --configuration production
# ---------------------------------------------------------------------------------------------
# Stage 2 — serve it
# ---------------------------------------------------------------------------------------------
FROM nginx:stable-alpine@sha256:97d490c12ba55b4946b01546d1c3ed324e8d41ab1c9fcb2a616aa470620e5b46
# Only the built output crosses the stage boundary: no node_modules, no sources, no git history.
COPY --from=build /app/dist/fineract-backoffice-ui/browser /usr/share/nginx/html
# A template rather than a finished config. The upstream Fineract is not known until the container
# starts, and the whole point of the proxy is that the browser only ever talks to this origin.
COPY deploy/nginx.conf.template /etc/nginx/templates/default.conf.template
COPY deploy/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80
# Answers from nginx itself, so it reports whether *this* container is serving — not whether
# Fineract is up, which is a different question with a different answer and its own healthcheck.
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost/index.html || exit 1
ENTRYPOINT ["/entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]