deploy read-only Formulation viewer

This commit is contained in:
2026-08-13 17:45:01 -05:00
parent 04e15aca22
commit 9591742d1d
6 changed files with 41 additions and 20 deletions
+9
View File
@@ -0,0 +1,9 @@
.git
.astro
dist
generated
node_modules
var
.env*
*.png
*.html
+3 -8
View File
@@ -1,4 +1,4 @@
name: Build & Push Astro Site Image name: Build & Deploy Formulation
on: on:
push: push:
@@ -12,7 +12,7 @@ jobs:
env: env:
REGISTRY_USERNAME: nicholas REGISTRY_USERNAME: nicholas
IMAGE_REGISTRY: git.uuard.com IMAGE_REGISTRY: git.uuard.com
IMAGE_NAME: nicholas/recipe-book IMAGE_NAME: nicholas/formulation
IMAGE_TAG: ${{ github.sha }} IMAGE_TAG: ${{ github.sha }}
runs-on: shared-ci runs-on: shared-ci
steps: steps:
@@ -30,11 +30,6 @@ jobs:
python3 -m pip install --user -r requirements-dev.txt python3 -m pip install --user -r requirements-dev.txt
scripts/validate-content scripts/validate-content
- name: 🏗️ Build Astro site
run: |
npm ci
npm run build
- name: 🔐 Gitea Registry Login - name: 🔐 Gitea Registry Login
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
@@ -83,7 +78,7 @@ jobs:
chmod 600 ~/.kube/config chmod 600 ~/.kube/config
kubectl auth can-i update deployments --namespace nicholas kubectl auth can-i update deployments --namespace nicholas
- name: Deploy recipe-book - name: Deploy Formulation read-only viewer
run: | run: |
set -euo pipefail set -euo pipefail
sed -E -i "s#newTag: [0-9a-f]+#newTag: ${IMAGE_TAG}#" k8s/kustomization.yaml sed -E -i "s#newTag: [0-9a-f]+#newTag: ${IMAGE_TAG}#" k8s/kustomization.yaml
+20 -4
View File
@@ -1,7 +1,23 @@
FROM nginx:alpine FROM node:24-alpine AS build
RUN rm -rf /usr/share/nginx/html/* WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run db:reset && npm run build
COPY dist /usr/share/nginx/html/ FROM node:24-alpine AS runtime
EXPOSE 80 ENV NODE_ENV=production \
FORMULATION_READ_ONLY=true \
HOST=0.0.0.0 \
PORT=8080
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build --chown=node:node /app/dist/app ./dist/app
COPY --from=build --chown=node:node /app/var/recipe-book.sqlite ./var/recipe-book.sqlite
COPY --from=build --chown=node:node /app/public ./public
USER node
EXPOSE 8080
CMD ["node", "dist/app/server/entry.mjs"]
+6 -6
View File
@@ -25,15 +25,15 @@ spec:
- name: gitea-registry - name: gitea-registry
containers: containers:
- name: recipe-book - name: recipe-book
image: git.uuard.com/nicholas/recipe-book image: git.uuard.com/nicholas/formulation
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http
containerPort: 80 containerPort: 8080
protocol: TCP protocol: TCP
readinessProbe: readinessProbe:
httpGet: httpGet:
path: / path: /app/
port: http port: http
initialDelaySeconds: 2 initialDelaySeconds: 2
periodSeconds: 5 periodSeconds: 5
@@ -41,7 +41,7 @@ spec:
failureThreshold: 6 failureThreshold: 6
livenessProbe: livenessProbe:
httpGet: httpGet:
path: / path: /app/
port: http port: http
initialDelaySeconds: 10 initialDelaySeconds: 10
periodSeconds: 10 periodSeconds: 10
@@ -50,10 +50,10 @@ spec:
resources: resources:
requests: requests:
cpu: 10m cpu: 10m
memory: 32Mi memory: 64Mi
limits: limits:
cpu: 100m cpu: 100m
memory: 128Mi memory: 256Mi
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
seccompProfile: seccompProfile:
+2 -2
View File
@@ -6,5 +6,5 @@ resources:
- service.yaml - service.yaml
- ingress.yaml - ingress.yaml
images: images:
- name: git.uuard.com/nicholas/recipe-book - name: git.uuard.com/nicholas/formulation
newTag: 7c17e3047560967dd58f8f7b8f0dd7387ba46aa5 newTag: latest
+1
View File
@@ -4,6 +4,7 @@ import { readOnlyMode } from "../lib/runtime";
const safeMethods = new Set(["GET", "HEAD", "OPTIONS"]); const safeMethods = new Set(["GET", "HEAD", "OPTIONS"]);
export const onRequest = defineMiddleware(async ({ request, url, redirect }, next) => { export const onRequest = defineMiddleware(async ({ request, url, redirect }, next) => {
if (url.pathname === "/") return redirect("/app/", 302);
if (!readOnlyMode) return next(); if (!readOnlyMode) return next();
if (!safeMethods.has(request.method)) { if (!safeMethods.has(request.method)) {
return new Response("This Formulation instance is read-only.", { status: 405, headers: { Allow: "GET, HEAD, OPTIONS" } }); return new Response("This Formulation instance is read-only.", { status: 405, headers: { Allow: "GET, HEAD, OPTIONS" } });