@openparachute/hub 0.5.14-rc.2 → 0.5.14-rc.21

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.
Files changed (106) hide show
  1. package/README.md +109 -15
  2. package/package.json +7 -3
  3. package/src/__tests__/account-home-ui.test.ts +251 -15
  4. package/src/__tests__/account-vault-token.test.ts +355 -0
  5. package/src/__tests__/admin-vaults.test.ts +70 -4
  6. package/src/__tests__/api-mint-token.test.ts +693 -5
  7. package/src/__tests__/api-modules-config.test.ts +16 -10
  8. package/src/__tests__/api-modules-ops.test.ts +45 -0
  9. package/src/__tests__/api-modules.test.ts +92 -75
  10. package/src/__tests__/api-ready.test.ts +135 -0
  11. package/src/__tests__/api-revoke-token.test.ts +384 -0
  12. package/src/__tests__/api-users.test.ts +7 -2
  13. package/src/__tests__/auth.test.ts +157 -30
  14. package/src/__tests__/cli.test.ts +44 -5
  15. package/src/__tests__/cloudflare-detect.test.ts +60 -5
  16. package/src/__tests__/expose-2fa-warning.test.ts +31 -17
  17. package/src/__tests__/expose-auth-preflight.test.ts +71 -72
  18. package/src/__tests__/expose-cloudflare.test.ts +582 -11
  19. package/src/__tests__/expose-interactive.test.ts +10 -4
  20. package/src/__tests__/expose-public-auto.test.ts +5 -1
  21. package/src/__tests__/expose.test.ts +52 -2
  22. package/src/__tests__/hub-server.test.ts +396 -10
  23. package/src/__tests__/hub.test.ts +85 -6
  24. package/src/__tests__/init.test.ts +928 -0
  25. package/src/__tests__/lifecycle.test.ts +464 -2
  26. package/src/__tests__/migrate.test.ts +433 -51
  27. package/src/__tests__/oauth-handlers.test.ts +1252 -83
  28. package/src/__tests__/oauth-ui.test.ts +12 -1
  29. package/src/__tests__/operator-token-issuer-self-heal.test.ts +412 -0
  30. package/src/__tests__/proxy-error-ui.test.ts +212 -0
  31. package/src/__tests__/proxy-state.test.ts +192 -0
  32. package/src/__tests__/resource-binding.test.ts +97 -0
  33. package/src/__tests__/scope-explanations.test.ts +77 -12
  34. package/src/__tests__/services-manifest.test.ts +122 -4
  35. package/src/__tests__/setup-wizard.test.ts +633 -53
  36. package/src/__tests__/status.test.ts +36 -0
  37. package/src/__tests__/two-factor-flow.test.ts +602 -0
  38. package/src/__tests__/two-factor.test.ts +183 -0
  39. package/src/__tests__/upgrade.test.ts +78 -1
  40. package/src/__tests__/users.test.ts +68 -0
  41. package/src/__tests__/vault-auth-status.test.ts +312 -11
  42. package/src/__tests__/vault-hub-origin-env.test.ts +263 -0
  43. package/src/__tests__/wizard.test.ts +372 -0
  44. package/src/account-home-ui.ts +488 -38
  45. package/src/account-vault-token.ts +282 -0
  46. package/src/admin-handlers.ts +159 -4
  47. package/src/admin-login-ui.ts +49 -5
  48. package/src/admin-vaults.ts +48 -15
  49. package/src/api-account.ts +14 -0
  50. package/src/api-mint-token.ts +132 -24
  51. package/src/api-modules-ops.ts +49 -11
  52. package/src/api-modules.ts +29 -12
  53. package/src/api-ready.ts +102 -0
  54. package/src/api-revoke-token.ts +107 -21
  55. package/src/api-users.ts +29 -3
  56. package/src/cli.ts +112 -25
  57. package/src/clients.ts +18 -6
  58. package/src/cloudflare/config.ts +10 -4
  59. package/src/cloudflare/detect.ts +82 -20
  60. package/src/commands/auth.ts +165 -24
  61. package/src/commands/expose-2fa-warning.ts +34 -32
  62. package/src/commands/expose-auth-preflight.ts +89 -78
  63. package/src/commands/expose-cloudflare.ts +471 -16
  64. package/src/commands/expose-interactive.ts +10 -11
  65. package/src/commands/expose-public-auto.ts +6 -4
  66. package/src/commands/expose.ts +8 -0
  67. package/src/commands/init.ts +594 -0
  68. package/src/commands/install.ts +33 -2
  69. package/src/commands/lifecycle.ts +386 -17
  70. package/src/commands/migrate.ts +293 -41
  71. package/src/commands/status.ts +22 -0
  72. package/src/commands/upgrade.ts +55 -11
  73. package/src/commands/wizard.ts +847 -0
  74. package/src/env-file.ts +10 -0
  75. package/src/help.ts +157 -15
  76. package/src/hub-db.ts +39 -1
  77. package/src/hub-server.ts +119 -13
  78. package/src/hub-settings.ts +11 -0
  79. package/src/hub.ts +82 -14
  80. package/src/oauth-handlers.ts +298 -21
  81. package/src/oauth-ui.ts +10 -0
  82. package/src/operator-token.ts +151 -0
  83. package/src/pending-login.ts +116 -0
  84. package/src/proxy-error-ui.ts +506 -0
  85. package/src/proxy-state.ts +131 -0
  86. package/src/rate-limit.ts +51 -0
  87. package/src/resource-binding.ts +134 -0
  88. package/src/scope-attenuation.ts +85 -0
  89. package/src/scope-explanations.ts +131 -14
  90. package/src/services-manifest.ts +112 -0
  91. package/src/setup-wizard.ts +738 -125
  92. package/src/tailscale/run.ts +28 -11
  93. package/src/totp.ts +201 -0
  94. package/src/two-factor-handlers.ts +287 -0
  95. package/src/two-factor-store.ts +181 -0
  96. package/src/two-factor-ui.ts +462 -0
  97. package/src/users.ts +58 -0
  98. package/src/vault/auth-status.ts +200 -25
  99. package/src/vault-hub-origin-env.ts +163 -0
  100. package/web/ui/dist/assets/index-BiBlvEaj.css +1 -0
  101. package/web/ui/dist/assets/index-CIN3mnmf.js +61 -0
  102. package/web/ui/dist/index.html +2 -2
  103. package/src/__tests__/vault-tokens-create-interactive.test.ts +0 -183
  104. package/src/commands/vault-tokens-create-interactive.ts +0 -143
  105. package/web/ui/dist/assets/index-7DtAXz7y.css +0 -1
  106. package/web/ui/dist/assets/index-tRmPbbC7.js +0 -61
@@ -5,7 +5,15 @@ import { join } from "node:path";
5
5
  import { renderHub, writeHubFile } from "../hub.ts";
6
6
 
7
7
  describe("renderHub", () => {
8
- const html = renderHub();
8
+ // The verbose discovery body (Get started / Services / Admin) + its
9
+ // data-loading script render only for a signed-in visitor (the signed-out
10
+ // landing is slimmed — see the "signed-out slimming" describe block below).
11
+ // Assertions about that verbose body therefore run against a signed-in
12
+ // render; assertions about the page shell (doctype, styles, brand) hold for
13
+ // both and use whichever render is convenient.
14
+ const html = renderHub({
15
+ session: { displayName: "operator", csrfToken: "csrf-shell" },
16
+ });
9
17
 
10
18
  test("is a self-contained HTML document with inline styles and script", () => {
11
19
  expect(html).toStartWith("<!doctype html>");
@@ -162,12 +170,72 @@ describe("renderHub", () => {
162
170
  });
163
171
 
164
172
  test("default render (no session) emits the 'Sign in' affordance", () => {
165
- expect(html).toContain('class="auth-indicator"');
166
- expect(html).toContain("Sign in");
167
- expect(html).toContain('href="/login?next=/"');
173
+ const out = renderHub();
174
+ expect(out).toContain('class="auth-indicator"');
175
+ expect(out).toContain("Sign in");
176
+ expect(out).toContain('href="/login?next=/"');
168
177
  // No POST form, no CSRF input — those only appear when signed in.
169
- expect(html).not.toContain('action="/logout"');
170
- expect(html).not.toContain("__csrf");
178
+ expect(out).not.toContain('action="/logout"');
179
+ expect(out).not.toContain("__csrf");
180
+ });
181
+ });
182
+
183
+ describe("renderHub — signed-out slimming (operator feedback)", () => {
184
+ // A signed-out visitor should see a clean, minimal landing: brand +
185
+ // tagline (in the header) + a single clear "Sign in" call. The hub's
186
+ // internal detail — the service catalog, vault listings, admin surfaces,
187
+ // and the well-known-driven loading script — must NOT render until the
188
+ // visitor authenticates. The signed-in render is unchanged.
189
+ const signedOut = renderHub();
190
+ const signedIn = renderHub({
191
+ session: { displayName: "operator", csrfToken: "csrf-xyz" },
192
+ });
193
+
194
+ test("signed-out: brand wordmark + tagline still render (the slim landing keeps the brand)", () => {
195
+ expect(signedOut).toContain("<h1>Parachute</h1>");
196
+ expect(signedOut).toContain("Truly personal computing. Your knowledge belongs with you.");
197
+ });
198
+
199
+ test("signed-out: a clear 'Sign in' call is the primary affordance", () => {
200
+ expect(signedOut).toContain('data-testid="signed-out-signin"');
201
+ expect(signedOut).toContain('href="/login?next=/"');
202
+ expect(signedOut).toContain("Sign in");
203
+ });
204
+
205
+ test("signed-out: the verbose Services / Admin / Get started sections are absent", () => {
206
+ expect(signedOut).not.toContain('id="services-section"');
207
+ expect(signedOut).not.toContain('id="admin-section"');
208
+ expect(signedOut).not.toContain('id="get-started-section"');
209
+ expect(signedOut).not.toContain("<h2>Services</h2>");
210
+ expect(signedOut).not.toContain("<h2>Admin</h2>");
211
+ // Admin links / token surface must not be exposed pre-auth.
212
+ expect(signedOut).not.toContain("/admin/vaults");
213
+ expect(signedOut).not.toContain("/admin/tokens");
214
+ });
215
+
216
+ test("signed-out: the well-known service-catalog loading script is not emitted", () => {
217
+ // No data-driven discovery body to populate when signed out → no script.
218
+ // (The brand mark is an inline SVG, not a <script>; assert on the IIFE's
219
+ // load function rather than a blanket "no <script>".) The footer's
220
+ // public "discovery" anchor → /.well-known/parachute.json stays — it's a
221
+ // plain link, not the catalog-fetching script — so assert on the fetch
222
+ // call + the loader function, not the URL string.
223
+ expect(signedOut).not.toContain("loadServices");
224
+ expect(signedOut).not.toContain("renderServices");
225
+ expect(signedOut).not.toContain("fetch('/.well-known/parachute.json'");
226
+ expect(signedOut).not.toContain("<script>");
227
+ });
228
+
229
+ test("signed-in: the verbose sections + loading script DO render (signed-in view unchanged)", () => {
230
+ expect(signedIn).toContain('id="services-section"');
231
+ expect(signedIn).toContain('id="admin-section"');
232
+ expect(signedIn).toContain('id="get-started-section"');
233
+ expect(signedIn).toContain("/admin/vaults");
234
+ expect(signedIn).toContain("/.well-known/parachute.json");
235
+ expect(signedIn).toContain("loadServices");
236
+ // And the signed-out lede / standalone Sign-in CTA is gone (the
237
+ // auth-indicator carries sign-out instead).
238
+ expect(signedIn).not.toContain('data-testid="signed-out-signin"');
171
239
  });
172
240
  });
173
241
 
@@ -189,6 +257,17 @@ describe("renderHub — signed-in indicator (rc.13)", () => {
189
257
  expect(html).not.toContain('href="/login?next=/"');
190
258
  });
191
259
 
260
+ test("signed-in indicator carries an Account breadcrumb to /account/", () => {
261
+ // Onboarding discoverability: a signed-in friend needs a single link
262
+ // to the self-service /account/ home (change password, their vault).
263
+ // Applies to admins too — harmless for them.
264
+ const html = renderHub({
265
+ session: { displayName: "aaron", csrfToken: "csrf-token-xyz" },
266
+ });
267
+ expect(html).toContain('href="/account/"');
268
+ expect(html).toContain("Account");
269
+ });
270
+
192
271
  test("displayName with HTML special chars is escaped", () => {
193
272
  // Username field allows alphanumerics historically, but the
194
273
  // displayName field on the wire is forward-compatible with profile