@aion0/forge 0.10.70 → 0.10.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE_NOTES.md +3 -18
- package/bin/forge-server.mjs +19 -0
- package/lib/projects.ts +13 -3
- package/package.json +1 -1
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
# Forge v0.10.
|
|
1
|
+
# Forge v0.10.72
|
|
2
2
|
|
|
3
3
|
Released: 2026-06-11
|
|
4
4
|
|
|
5
|
-
## Changes since v0.10.
|
|
5
|
+
## Changes since v0.10.71
|
|
6
6
|
|
|
7
|
-
### Other
|
|
8
|
-
- revert: remove CLI quick-setup wizard + AUTH_SECRET persist (keep BRIDGE/CHAT port fixes)
|
|
9
|
-
- feat(setup): ask for department in enterprise wizard
|
|
10
|
-
- fix(auth): persist AUTH_SECRET so sessions survive refresh/restart
|
|
11
|
-
- fix(server): per-instance CHAT_PORT (webPort+5) — fixes 2nd-instance settings/sync
|
|
12
|
-
- feat(server): minimal first-run quick setup (public/enterprise)
|
|
13
|
-
- revert: remove first-run wizard + AUTH_SECRET persist + onboarding tweaks
|
|
14
|
-
- fix(setup): skip first-run wizard when instance already configured
|
|
15
|
-
- fix(setup): normalize half-typed email against tenant domain
|
|
16
|
-
- fix(auth): persist AUTH_SECRET so sessions survive refresh/restart
|
|
17
|
-
- fix(onboarding): show banner only, don't auto-open the modal each load
|
|
18
|
-
- fix(server): per-instance BRIDGE_PORT (webPort+4) + wizard sets onboardingCompleted
|
|
19
|
-
- feat(server): first-run public/enterprise quick-setup wizard
|
|
20
|
-
- fix(pipeline): run finalizePipeline on git-preflight abort
|
|
21
7
|
|
|
22
|
-
|
|
23
|
-
**Full Changelog**: https://github.com/aiwatching/forge/compare/v0.10.69...v0.10.70
|
|
8
|
+
**Full Changelog**: https://github.com/aiwatching/forge/compare/v0.10.71...v0.10.72
|
package/bin/forge-server.mjs
CHANGED
|
@@ -262,6 +262,25 @@ process.env.BRIDGE_PORT = String(bridgePort);
|
|
|
262
262
|
process.env.CHAT_PORT = String(chatPort);
|
|
263
263
|
process.env.FORGE_DATA_DIR = DATA_DIR;
|
|
264
264
|
|
|
265
|
+
// Persist AUTH_SECRET so every next-server worker uses the same key.
|
|
266
|
+
// lib/auth.ts generates a random one per process when unset, and Next prod
|
|
267
|
+
// mode spawns multiple workers — without a stable secret, a cookie signed
|
|
268
|
+
// by worker A is rejected by worker B, so the user randomly gets bounced
|
|
269
|
+
// to /login every few requests. Forge-server.mjs is the only common parent
|
|
270
|
+
// of all workers; lib/auth.ts is intentionally untouched.
|
|
271
|
+
if (!process.env.AUTH_SECRET) {
|
|
272
|
+
const SECRET_FILE = join(DATA_DIR, '.auth-secret');
|
|
273
|
+
let secret = '';
|
|
274
|
+
try { if (existsSync(SECRET_FILE)) secret = readFileSync(SECRET_FILE, 'utf-8').trim(); } catch {}
|
|
275
|
+
if (!secret) {
|
|
276
|
+
const { randomBytes } = await import('node:crypto');
|
|
277
|
+
secret = randomBytes(32).toString('hex');
|
|
278
|
+
if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true });
|
|
279
|
+
writeFileSync(SECRET_FILE, secret, { mode: 0o600 });
|
|
280
|
+
}
|
|
281
|
+
process.env.AUTH_SECRET = secret;
|
|
282
|
+
}
|
|
283
|
+
|
|
265
284
|
// ── Password setup (first run or --reset-password) ──
|
|
266
285
|
// Skipped in --add-enterprise-key persist-and-exit mode: registering a
|
|
267
286
|
// key from install.sh must not block on an interactive prompt.
|
package/lib/projects.ts
CHANGED
|
@@ -386,15 +386,25 @@ export function resolveOrCloneProject(name: string | undefined): ResolveResult {
|
|
|
386
386
|
// 2. `name` is empty / unknown — pull the gitlab connector's
|
|
387
387
|
// `default_project_path` (e.g. "fortinet/fortinac-dev") and use
|
|
388
388
|
// it as the fallback repo.
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
//
|
|
389
|
+
// Before cloning, scan local projectRoots for a checkout whose git
|
|
390
|
+
// origin already matches — saves a redundant clone and also covers the
|
|
391
|
+
// "server just booted, registry/settings cache not warm yet" window
|
|
392
|
+
// where the user's real local FortiNAC was missed by the name-based
|
|
393
|
+
// lookups above.
|
|
392
394
|
const gl = readGitlabConnector();
|
|
393
395
|
if (gl) {
|
|
394
396
|
const targetPath = trimmed && trimmed.includes('/')
|
|
395
397
|
? trimmed
|
|
396
398
|
: (gl.default_project_path || '').trim();
|
|
397
399
|
if (targetPath) {
|
|
400
|
+
const projects = scanProjects();
|
|
401
|
+
const want = normalizeRepoPath(targetPath) || targetPath.toLowerCase().replace(/^\/+|\/+$/g, '');
|
|
402
|
+
const wantBase = want.split('/').pop()!;
|
|
403
|
+
const byRepo = projects.filter((p) => p.repo && p.repo === want);
|
|
404
|
+
if (byRepo.length === 1) return { project: byRepo[0], source: 'existing' };
|
|
405
|
+
const byRepoBase = projects.filter((p) => p.repo && p.repo.split('/').pop() === wantBase);
|
|
406
|
+
if (byRepoBase.length === 1) return { project: byRepoBase[0], source: 'existing' };
|
|
407
|
+
|
|
398
408
|
const cloned = tryGitlabClone(targetPath);
|
|
399
409
|
if (cloned) return { project: cloned, source: 'gitlab-cloned', clone_url: `${gl.base_url}/${targetPath.replace(/^\/+|\/+$/g, '')}.git` };
|
|
400
410
|
}
|
package/package.json
CHANGED