mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-30 20:29:15 +00:00
feat(onboarding): add first-run environment checker (#1290)
* feat(onboarding): add first-run environment checker Add a preflight that checks whether the host can run Docker deploys before a deploy fails for an avoidable reason. It verifies the Docker engine is reachable and permitted, the Compose plugin is present, the compose directory is writable and mounted at a matching host path, the dashboard is behind TLS, and the compose volume has disk headroom. Each result that needs attention carries a specific fix rather than a generic error, and the checks never block: an operator who knows their setup can continue. The checks run as the final step of first-boot setup and can be re-run any time from the Recovery settings tab. A new admin-only endpoint, GET /api/diagnostics/environment, backs both surfaces. * fix(onboarding): distinguish unverified path mapping and support parent binds Treat a container whose self-inspect fails as an unverified path-mapping warning instead of a false "not containerized" pass, so an unverifiable mapping never reads as healthy. Resolve the compose directory through the longest-prefix bind mount and compare the host path it resolves to, so a parent bind such as -v /opt:/opt correctly covers COMPOSE_DIR=/opt/compose instead of warning that the directory is not bind-mounted. * test(e2e): advance the setup wizard past the environment step in loginAs The first-run setup helper clicked "Initialize console" and immediately waited for the dashboard, but setup now shows an environment-preflight step before landing the console. Click "Enter Sencho" to complete onboarding before asserting the dashboard, so the first test on a fresh instance passes.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Router, type Request, type Response } from 'express';
|
||||
import { requireAdmin, requireUserSession } from '../middleware/tierGates';
|
||||
import { collectDiagnostics } from '../services/DiagnosticsService';
|
||||
import { collectEnvironmentReport, buildRealProbes } from '../services/EnvironmentCheckService';
|
||||
import DockerController from '../services/DockerController';
|
||||
import { withTimeout } from '../utils/withTimeout';
|
||||
|
||||
@@ -36,3 +37,22 @@ diagnosticsRouter.get('/', async (req: Request, res: Response): Promise<void> =>
|
||||
res.status(500).json({ error: 'Failed to collect diagnostics.' });
|
||||
}
|
||||
});
|
||||
|
||||
// First-run / preflight environment checks (Docker engine + Compose, the
|
||||
// compose directory and its host path mapping, TLS, disk headroom). Same admin
|
||||
// session gate as the recovery report. proto / host come from the request so
|
||||
// the TLS verdict reflects how this browser reached the dashboard; behind a
|
||||
// reverse proxy that terminates TLS, x-forwarded-proto carries the real scheme.
|
||||
diagnosticsRouter.get('/environment', async (req: Request, res: Response): Promise<void> => {
|
||||
if (!requireUserSession(req, res)) return;
|
||||
if (!requireAdmin(req, res)) return;
|
||||
try {
|
||||
const proto = (req.get('x-forwarded-proto')?.split(',')[0].trim()) || req.protocol;
|
||||
const host = req.get('host') || '';
|
||||
const report = await collectEnvironmentReport(buildRealProbes({ proto, host }));
|
||||
res.json(report);
|
||||
} catch (err) {
|
||||
console.error('[diagnostics] failed to collect environment report:', (err as Error).message);
|
||||
res.status(500).json({ error: 'Failed to collect environment checks.' });
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user