@openparachute/hub 0.5.10-rc.4 → 0.5.10-rc.5
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/package.json +1 -1
- package/src/__tests__/hub-server.test.ts +32 -7
- package/src/__tests__/setup-gate.test.ts +18 -8
- package/src/__tests__/setup-wizard.test.ts +815 -0
- package/src/api-modules-ops.ts +32 -3
- package/src/help.ts +2 -1
- package/src/hub-server.ts +55 -74
- package/src/setup-wizard.ts +1080 -0
package/package.json
CHANGED
|
@@ -979,10 +979,12 @@ describe("hubFetch routing", () => {
|
|
|
979
979
|
}
|
|
980
980
|
});
|
|
981
981
|
|
|
982
|
-
// First-boot setup
|
|
983
|
-
//
|
|
984
|
-
//
|
|
985
|
-
|
|
982
|
+
// First-boot setup wizard (hub#259, expanding hub#258's static
|
|
983
|
+
// placeholder). When no admin exists, GET /admin/setup renders the
|
|
984
|
+
// wizard's account-step form. Once admin + vault both exist, it 301s
|
|
985
|
+
// to /login so a stale bookmark still lands somewhere useful. With
|
|
986
|
+
// admin but no vault, the wizard resumes at the vault step.
|
|
987
|
+
test("/admin/setup renders the wizard's account form when no admin exists", async () => {
|
|
986
988
|
const h = makeHarness();
|
|
987
989
|
try {
|
|
988
990
|
const db = openHubDb(hubDbPath(h.dir));
|
|
@@ -991,7 +993,8 @@ describe("hubFetch routing", () => {
|
|
|
991
993
|
expect(res.status).toBe(200);
|
|
992
994
|
expect(res.headers.get("content-type")).toContain("text/html");
|
|
993
995
|
const body = await res.text();
|
|
994
|
-
expect(body).toContain("
|
|
996
|
+
expect(body).toContain('action="/admin/setup/account"');
|
|
997
|
+
// Env-var seed path is still surfaced as the alt-path disclosure.
|
|
995
998
|
expect(body).toContain("PARACHUTE_INITIAL_ADMIN_USERNAME");
|
|
996
999
|
} finally {
|
|
997
1000
|
db.close();
|
|
@@ -1001,13 +1004,35 @@ describe("hubFetch routing", () => {
|
|
|
1001
1004
|
}
|
|
1002
1005
|
});
|
|
1003
1006
|
|
|
1004
|
-
test("/admin/setup 301s to /login
|
|
1007
|
+
test("/admin/setup 301s to /login once admin + vault both exist (hub#259)", async () => {
|
|
1005
1008
|
const h = makeHarness();
|
|
1006
1009
|
try {
|
|
1007
1010
|
const db = openHubDb(hubDbPath(h.dir));
|
|
1008
1011
|
try {
|
|
1009
1012
|
await createUser(db, "owner", "pw");
|
|
1010
|
-
|
|
1013
|
+
// Seed the vault entry so the wizard's state derives as "done"
|
|
1014
|
+
// and the GET 301s. Without this the wizard would still resume
|
|
1015
|
+
// at the vault step.
|
|
1016
|
+
const { writeManifest } = await import("../services-manifest.ts");
|
|
1017
|
+
const { join } = await import("node:path");
|
|
1018
|
+
writeManifest(
|
|
1019
|
+
{
|
|
1020
|
+
services: [
|
|
1021
|
+
{
|
|
1022
|
+
name: "parachute-vault",
|
|
1023
|
+
version: "0.1.0",
|
|
1024
|
+
port: 1940,
|
|
1025
|
+
paths: ["/vault/default"],
|
|
1026
|
+
health: "/health",
|
|
1027
|
+
},
|
|
1028
|
+
],
|
|
1029
|
+
},
|
|
1030
|
+
join(h.dir, "services.json"),
|
|
1031
|
+
);
|
|
1032
|
+
const res = await hubFetch(h.dir, {
|
|
1033
|
+
getDb: () => db,
|
|
1034
|
+
manifestPath: join(h.dir, "services.json"),
|
|
1035
|
+
})(req("/admin/setup"));
|
|
1011
1036
|
expect(res.status).toBe(301);
|
|
1012
1037
|
expect(res.headers.get("location")).toBe("/login");
|
|
1013
1038
|
} finally {
|
|
@@ -141,16 +141,17 @@ describe("setup gate (no admin yet)", () => {
|
|
|
141
141
|
}
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
-
test("/admin/setup renders the
|
|
144
|
+
test("/admin/setup renders the wizard (account step) when no admin exists", async () => {
|
|
145
145
|
const db = openHubDb(hubDbPath(h.dir));
|
|
146
146
|
try {
|
|
147
147
|
const res = await hubFetch(h.dir, { getDb: () => db })(req("/admin/setup"));
|
|
148
148
|
expect(res.status).toBe(200);
|
|
149
149
|
expect(res.headers.get("content-type")).toContain("text/html");
|
|
150
150
|
const html = await res.text();
|
|
151
|
-
// Spot-check the
|
|
152
|
-
//
|
|
153
|
-
//
|
|
151
|
+
// Spot-check the wizard is rendering its account-step form (hub#259
|
|
152
|
+
// replaced the env-var-only placeholder with a real wizard, but the
|
|
153
|
+
// env-var path is still surfaced as the "alt-path" disclosure).
|
|
154
|
+
expect(html).toContain('action="/admin/setup/account"');
|
|
154
155
|
expect(html).toContain("PARACHUTE_INITIAL_ADMIN_USERNAME");
|
|
155
156
|
expect(html).toContain("PARACHUTE_INITIAL_ADMIN_PASSWORD");
|
|
156
157
|
} finally {
|
|
@@ -182,13 +183,22 @@ describe("setup gate (admin exists)", () => {
|
|
|
182
183
|
}
|
|
183
184
|
});
|
|
184
185
|
|
|
185
|
-
test("/admin/setup
|
|
186
|
+
test("/admin/setup resumes at the vault step when admin exists but vault doesn't (hub#259)", async () => {
|
|
186
187
|
const db = openHubDb(hubDbPath(h.dir));
|
|
187
188
|
try {
|
|
188
189
|
await createUser(db, "owner", "pw");
|
|
189
|
-
const res = await hubFetch(h.dir, {
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
const res = await hubFetch(h.dir, {
|
|
191
|
+
getDb: () => db,
|
|
192
|
+
manifestPath: join(h.dir, "services.json"),
|
|
193
|
+
})(req("/admin/setup"));
|
|
194
|
+
// With admin in place but no vault entry in services.json, the
|
|
195
|
+
// wizard's GET resumes at step 3 — the vault-name form — rather
|
|
196
|
+
// than 301-ing to /login. The 301-to-/login fires only once BOTH
|
|
197
|
+
// admin and vault are in place; that case is exercised in the
|
|
198
|
+
// setup-wizard suite where the manifest is seeded.
|
|
199
|
+
expect(res.status).toBe(200);
|
|
200
|
+
const html = await res.text();
|
|
201
|
+
expect(html).toContain('action="/admin/setup/vault"');
|
|
192
202
|
} finally {
|
|
193
203
|
db.close();
|
|
194
204
|
}
|