@bongos/core 1.20.21 → 1.20.23

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 (47) hide show
  1. package/.bongos-core.json +78 -48
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +4 -2
  4. package/clients/bongos-client/index.cjs +4 -2
  5. package/clients/bongos-client/index.d.ts +8 -4
  6. package/clients/bongos-client/index.mjs +4 -2
  7. package/docs/adr/0335-an-invite-is-a-pre-approved-row-on-the-projects-own-instance.md +1 -0
  8. package/docs/adr/0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md +70 -0
  9. package/docs/adr/README.md +1 -0
  10. package/docs/api/openapi.json +137 -72
  11. package/docs/api-reference.md +6 -5
  12. package/docs/architecture.md +14 -0
  13. package/docs/copy-inventory.md +196 -196
  14. package/docs/copy-registry.json +250 -250
  15. package/docs/module-api-changelog.md +4 -0
  16. package/docs/page-inventory.json +2 -1
  17. package/docs/page-readings.json +310 -306
  18. package/migrations/core_265_module_assessments.sql +97 -0
  19. package/modules/hall-ui/public/watch.js +23 -0
  20. package/modules/onboarding/routes/access-requests.js +36 -6
  21. package/modules/platform-identity/invite-notices.js +61 -0
  22. package/modules/platform-identity/module.json +1 -1
  23. package/modules/platform-identity/platform-identity.js +12 -18
  24. package/modules/platform-identity/routes/my-projects.js +6 -15
  25. package/modules/platform-identity/routes/projects.js +22 -15
  26. package/modules/platform-identity/routes/sso-invites.js +82 -0
  27. package/modules/platform-identity/tests/platform-identity.mjs +14 -11
  28. package/modules/public-landing/public/assets/cosmos.css +5 -0
  29. package/modules/public-landing/public/projects.html +35 -29
  30. package/modules/public-landing/public/projects.states.json +1 -0
  31. package/modules/ui-design/kit/serve.js +9 -0
  32. package/package-lock.json +2 -2
  33. package/package.json +1 -1
  34. package/release-notes.json +12 -0
  35. package/src/bongos/auth-admission.js +40 -0
  36. package/src/bongos/auth.js +2 -1
  37. package/src/module-api.js +8 -1
  38. package/tests/access_requests_invite.mjs +39 -1
  39. package/tests/application_lifecycle.mjs +41 -1
  40. package/tests/catalog_only_client.mjs +5 -3
  41. package/tests/hub_invite_notices.mjs +261 -0
  42. package/tests/module_api.mjs +1 -0
  43. package/tests/module_assessments_migration.mjs +96 -0
  44. package/tests/my_projects_surface.mjs +11 -1
  45. package/tests/project_invite_ownership.mjs +12 -7
  46. package/tests/project_invite_ui.mjs +42 -45
  47. package/tests/watch_applications_queue.mjs +33 -2
@@ -94,6 +94,7 @@ async function boot(opts = {}) {
94
94
  rank = 'archon',
95
95
  queueStatus = null, // non-200 for the queue read (403 seals it)
96
96
  patchResult = null, // a scripted answer for PATCH /access-requests/:id
97
+ search = '', // the page's query string (?invite=<login>, task 1002818)
97
98
  } = opts;
98
99
 
99
100
  const requests = [];
@@ -136,7 +137,7 @@ async function boot(opts = {}) {
136
137
  // the ones shipped rather than ones this test invented.
137
138
  parseInto(documentObj.body, PAGE);
138
139
 
139
- const locationObj = { hostname: 'builders.example.test', pathname: '/builders/watch', search: '', hash: '', assign() {} };
140
+ const locationObj = { hostname: 'builders.example.test', pathname: '/builders/watch', search, hash: '', assign() {} };
140
141
 
141
142
  const kit = {
142
143
  makeTabs: () => ({}),
@@ -187,7 +188,7 @@ async function boot(opts = {}) {
187
188
  console: { log() {}, warn() {}, error() {} },
188
189
  setTimeout, clearTimeout, Promise, Date, Math, JSON, Error, isNaN,
189
190
  Number, String, Object, Array, Boolean, Set, Map, RegExp,
190
- encodeURIComponent, decodeURIComponent, parseInt, parseFloat,
191
+ encodeURIComponent, decodeURIComponent, parseInt, parseFloat, URLSearchParams,
191
192
  };
192
193
  sandbox.globalThis = sandbox;
193
194
  vm.createContext(sandbox);
@@ -491,4 +492,34 @@ await test('the profile changes what the row SAYS, never what it offers (ADR 001
491
492
  'a rich record is not a reason to admit and an empty one is not a reason to refuse — the decisions must be identical');
492
493
  });
493
494
 
495
+ // ── ?invite=<login>: the platform hub hands an owner here (task 1002818, ADR 0353) ──
496
+ // The hub's invite widget cannot admit anyone, so it links an owner to THIS box with the
497
+ // name filled in. Filling is all a link may do: the send stays the owner's own click.
498
+
499
+ await test('?invite= fills the invite box — and sends nothing on its own', async () => {
500
+ const h = await boot({ search: '?invite=octo-builder' });
501
+ const box = h.documentObj.getElementById('gate-invite-login');
502
+ assert.ok(box, 'the invite box rendered');
503
+ assert.equal(box.value, 'octo-builder');
504
+ assert.equal(h.requests.filter((r) => r.method === 'POST').length, 0,
505
+ 'a link anyone can craft must never be the act that admits');
506
+ });
507
+
508
+ await test('?invite= is spent on first use — a re-render does not put the name back', async () => {
509
+ const h = await boot({ search: '?invite=octo-builder' });
510
+ const box = h.documentObj.getElementById('gate-invite-login');
511
+ box.value = '';
512
+ await h.switchView('invited'); // the gate re-renders, invite box and all
513
+ assert.equal(h.documentObj.getElementById('gate-invite-login').value, '');
514
+ });
515
+
516
+ await test('?invite= that is not a GitHub username fills nothing', async () => {
517
+ for (const bad of ['?invite=%3Cscript%3E', '?invite=a%20b', '?invite=-lead', '?invite=' + 'x'.repeat(40)]) {
518
+ const h = await boot({ search: bad });
519
+ assert.equal(h.documentObj.getElementById('gate-invite-login').value || '', '', bad);
520
+ }
521
+ const at = await boot({ search: '?invite=%40octo' });
522
+ assert.equal(at.documentObj.getElementById('gate-invite-login').value, 'octo', 'a pasted @ is dropped, as the form itself does');
523
+ });
524
+
494
525
  summary();