fix: Gitea CI/CD und Blank-Page-Fehler behoben
- Helmet CSP: upgrade-insecure-requests und HSTS für HTTP-Deployments deaktiviert (war die Ursache der leeren Seite - Browser versuchte JS über HTTPS zu laden) - Backend: statische Dateien werden jetzt in allen NODE_ENV-Modi serviert - Frontend: IS_DEV erkennt auch VITE_TEST_MODE=true (Build-Zeit Variable) - Dockerfile: VITE_TEST_MODE=true beim Vite-Build, NODE_ENV=development - docker-compose.yml: NODE_ENV=development, CORS_ORIGIN=* - Gitea Workflow: Auth-Token für git clone, Build via Portainer API statt lokaler Docker CLI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+23
-6
@@ -28,6 +28,10 @@ app.use(
|
||||
// Staffbase lädt das Plugin in einem iFrame
|
||||
// X-Frame-Options muss daher SAMEORIGIN oder ALLOW-FROM erlauben
|
||||
frameguard: false,
|
||||
// HSTS nur aktivieren wenn wir über HTTPS laufen (z.B. hinter einem Reverse Proxy)
|
||||
hsts: process.env.NODE_ENV === 'production' && process.env.PLUGIN_BASE_URL?.startsWith('https')
|
||||
? { maxAge: 15552000, includeSubDomains: true }
|
||||
: false,
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
@@ -35,6 +39,8 @@ app.use(
|
||||
styleSrc: ["'self'", "'unsafe-inline'"], // für inline styles im Frontend
|
||||
imgSrc: ["'self'", 'data:', 'https://crests.football-data.org'],
|
||||
frameAncestors: ['https://app.staffbase.com', 'https://*.staffbase.com'],
|
||||
// upgrade-insecure-requests nur wenn HTTPS verfügbar ist, sonst werden JS-Assets geblockt
|
||||
upgradeInsecureRequests: process.env.PLUGIN_BASE_URL?.startsWith('https') ? [] : null,
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -48,6 +54,10 @@ const allowedOrigins = (process.env.CORS_ORIGIN ?? 'https://app.staffbase.com')
|
||||
app.use(
|
||||
cors({
|
||||
origin: (origin, callback) => {
|
||||
// Wildcard: alle Origins erlauben
|
||||
if (allowedOrigins.includes('*')) {
|
||||
return callback(null, true);
|
||||
}
|
||||
// Requests ohne Origin (z.B. direkte API-Calls) in Development erlauben
|
||||
if (!origin && process.env.NODE_ENV !== 'production') {
|
||||
return callback(null, true);
|
||||
@@ -137,15 +147,22 @@ if (process.env.NODE_ENV === 'development') {
|
||||
|
||||
// ============================================================
|
||||
// Frontend (React Build) – statisches Serving
|
||||
// In Production liefert das Backend auch das Frontend aus
|
||||
// Wird in allen Modi aktiviert, wenn ein public-Ordner existiert
|
||||
// (Docker-Container liefern Frontend immer über das Backend aus)
|
||||
// ============================================================
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path') as typeof import('path');
|
||||
app.use(express.static(path.join(process.cwd(), 'public')));
|
||||
app.get('*', (_req, res) => {
|
||||
res.sendFile(path.join(process.cwd(), 'public', 'index.html'));
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs') as typeof import('fs');
|
||||
const publicDir = path.join(process.cwd(), 'public');
|
||||
if (fs.existsSync(publicDir)) {
|
||||
logger.info('Serving frontend static files from', { publicDir });
|
||||
app.use(express.static(publicDir));
|
||||
app.get('*', (_req, res) => {
|
||||
res.sendFile(path.join(publicDir, 'index.html'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
||||
Reference in New Issue
Block a user