Merge remote-tracking branch 'origin/main' into feat/oidc-sso-phase1
# Conflicts: # backend/src/middleware/maintenance.js
This commit is contained in:
+17
-7
@@ -29,14 +29,24 @@ COPY . .
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage (Alpine 3.23 with OpenSSL 3.5.5, patched libexpat)
|
||||
FROM nginx:1.28-alpine
|
||||
# Production stage (nginx stable 1.30 on Alpine 3.24). The 1.28 base is a
|
||||
# dead end for the nginx HTTP/2 + rewrite/charset CVEs (CVE-2026-42055 /
|
||||
# -49975 / -9256 / -48142): nginx.org's nginx-module-* packages pin the exact
|
||||
# nginx version, so `apk upgrade` can never pull Alpine's patched 1.28.3-r4 —
|
||||
# nginx fixes have to come via the base image tag, not apk.
|
||||
FROM nginx:1.30-alpine
|
||||
|
||||
# Upgrade all Alpine packages for security fixes. The explicit nginx upgrade
|
||||
# closes the HTTP/2 + rewrite/charset CVEs (CVE-2026-42055 / -49975 / -9256 /
|
||||
# -48142, fixed in nginx 1.28.3-r4) and busts any cached layer still carrying
|
||||
# the vulnerable r1 build.
|
||||
RUN apk upgrade --no-cache && apk add --no-cache --upgrade nginx
|
||||
# Redeclare CACHEBUST — ARGs don't cross stage boundaries, so the builder
|
||||
# stage's declaration never reached this stage. Consuming it in the RUN below
|
||||
# busts that layer's cache every CI run (CACHEBUST=github.run_number), so the
|
||||
# image always picks up current Alpine security updates. Without this, the
|
||||
# upgrade layer was cached indefinitely and builds kept shipping curl 8.19.0 /
|
||||
# c-ares 1.34.6 for weeks after fixed packages landed in the Alpine repo.
|
||||
ARG CACHEBUST=1
|
||||
|
||||
# Upgrade all Alpine packages for security fixes (nginx itself is version-
|
||||
# pinned by its module packages — see the FROM comment above).
|
||||
RUN echo "cachebust=${CACHEBUST}" && apk upgrade --no-cache
|
||||
|
||||
# Install runtime dependencies. `gettext` provides envsubst, used by
|
||||
# docker-entrypoint.sh for the BRAND_TITLE / BRAND_DESCRIPTION runtime
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "picpeak-frontend",
|
||||
"private": true,
|
||||
"version": "3.88.0-beta.0",
|
||||
"version": "3.89.0-beta.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -16,6 +16,7 @@ interface RestoreResult {
|
||||
tables: number;
|
||||
filesRestored: number;
|
||||
usesExternalMedia: boolean;
|
||||
sessionInvalidated?: boolean;
|
||||
}
|
||||
|
||||
// ── Download half (Dashboard) ────────────────────────────────────────────────
|
||||
@@ -114,6 +115,13 @@ export const PicpeakRestoreCard: React.FC = () => {
|
||||
setResult(res.data);
|
||||
setPendingFile(null);
|
||||
toast.success(t('backup.picpeak.restoreDone', 'Backup restored.'));
|
||||
// The restore rewrote admin_users and the backend revoked our session
|
||||
// (ids may have shifted). Send the operator to a fresh login rather than
|
||||
// letting the now-stale token resolve to a different restored account.
|
||||
if (res.data?.sessionInvalidated) {
|
||||
toast.success(t('backup.picpeak.reloginRequired', 'Restore complete — please sign in again.'));
|
||||
setTimeout(() => { window.location.href = '/admin/login'; }, 1500);
|
||||
}
|
||||
} catch (e: any) {
|
||||
const msg = e.response?.data?.error || t('backup.picpeak.restoreFailed', 'Restore failed.');
|
||||
toast.error(msg);
|
||||
|
||||
Reference in New Issue
Block a user