Automate Gitea init, NocoDB auto sign-in, and fix prod compose
- Add scripts/gitea-init.sh: runs migrations + creates admin user on first boot, replacing the manual installation wizard - Set GITEA__security__INSTALL_LOCK=true in both compose files - Add NocoDB auth bridge (nginx) + /api/services/nocodb-auth proxy endpoint so the admin iframe auto-authenticates - Update NocoDBPage.tsx to fetch token and use auth bridge flow - Fix docker-compose.prod.yml missing Gitea env vars for API container (GITEA_URL, GITEA_API_TOKEN, GITEA_ADMIN_PASSWORD, etc.) - Pass NC_ADMIN_EMAIL/PASSWORD to API for NocoDB auth proxy - Increase Gitea auto-setup retries from 3 to 6 with admin auth check - Update config.sh non-interactive mode to set GITEA_ADMIN_USER - Include gitea-init.sh in release tarball (build-release.sh) Bunker Admin
This commit is contained in:
@@ -96,6 +96,8 @@ const envSchema = z.object({
|
||||
|
||||
// Platform Services (NocoDB, n8n, Gitea)
|
||||
NOCODB_URL: z.string().default('http://changemaker-v2-nocodb:8080'),
|
||||
NC_ADMIN_EMAIL: z.string().default(''),
|
||||
NC_ADMIN_PASSWORD: z.string().default(''),
|
||||
NOCODB_PORT: z.coerce.number().default(8091),
|
||||
NOCODB_EMBED_PORT: z.coerce.number().default(8881),
|
||||
N8N_URL: z.string().default('http://n8n-changemaker:5678'),
|
||||
|
||||
@@ -393,17 +393,26 @@ async function autoSetupIfNeeded(): Promise<{ alreadyComplete: boolean; success:
|
||||
// DB might not be ready yet
|
||||
}
|
||||
|
||||
// Wait for Gitea to be available (up to 3 retries, 15s apart)
|
||||
// Wait for Gitea to be available and admin user to exist (up to 6 retries, 10s apart).
|
||||
// The gitea-init.sh script creates the admin user after migrations,
|
||||
// so we need to wait for both Gitea web AND admin auth to be ready.
|
||||
let giteaReady = false;
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let i = 0; i < 6; i++) {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||
try {
|
||||
// Check if Gitea is online
|
||||
const res = await fetch(`${env.GITEA_URL}/api/v1/version`, { signal: controller.signal });
|
||||
if (res.ok) {
|
||||
giteaReady = true;
|
||||
break;
|
||||
// Also verify admin auth works (user may not exist yet if init script is still running)
|
||||
try {
|
||||
await giteaBasicRequest<{ login: string }>('GET', '/user', 'admin', password);
|
||||
giteaReady = true;
|
||||
break;
|
||||
} catch {
|
||||
// Admin user not ready yet — gitea-init.sh may still be running
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
@@ -411,14 +420,14 @@ async function autoSetupIfNeeded(): Promise<{ alreadyComplete: boolean; success:
|
||||
} catch {
|
||||
// Not ready yet
|
||||
}
|
||||
if (i < 2) {
|
||||
logger.info(`Gitea auto-setup: waiting for Gitea to be ready (attempt ${i + 1}/3)...`);
|
||||
await new Promise(r => setTimeout(r, 15000));
|
||||
if (i < 5) {
|
||||
logger.info(`Gitea auto-setup: waiting for Gitea + admin user (attempt ${i + 1}/6)...`);
|
||||
await new Promise(r => setTimeout(r, 10000));
|
||||
}
|
||||
}
|
||||
|
||||
if (!giteaReady) {
|
||||
return { alreadyComplete: false, success: false, error: 'Gitea not reachable after 3 attempts' };
|
||||
return { alreadyComplete: false, success: false, error: 'Gitea not reachable or admin user not ready after 6 attempts' };
|
||||
}
|
||||
|
||||
// Run setup
|
||||
|
||||
@@ -64,6 +64,48 @@ router.get(
|
||||
},
|
||||
);
|
||||
|
||||
// GET /api/services/nocodb-auth — proxy NocoDB signin to get an auth token for iframe auto-login
|
||||
router.get(
|
||||
'/nocodb-auth',
|
||||
async (_req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
if (!env.NC_ADMIN_EMAIL || !env.NC_ADMIN_PASSWORD) {
|
||||
res.status(503).json({ error: 'NocoDB admin credentials not configured' });
|
||||
return;
|
||||
}
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||
try {
|
||||
const response = await fetch(`${env.NOCODB_URL}/api/v1/auth/user/signin`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email: env.NC_ADMIN_EMAIL, password: env.NC_ADMIN_PASSWORD }),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
res.status(502).json({ error: 'NocoDB authentication failed' });
|
||||
return;
|
||||
}
|
||||
|
||||
const data = (await response.json()) as { token?: string };
|
||||
if (!data.token) {
|
||||
res.status(502).json({ error: 'No token in NocoDB response' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ token: data.token });
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('NocoDB auth proxy failed', err);
|
||||
next(err);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// GET /api/services/config — return public-facing port numbers + subdomain info for iframe URLs
|
||||
router.get(
|
||||
'/config',
|
||||
|
||||
Reference in New Issue
Block a user