@bongos/core 1.20.27 → 1.20.28
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/.bongos-core.json +59 -34
- package/docs/adr/0335-an-invite-is-a-pre-approved-row-on-the-projects-own-instance.md +1 -1
- package/docs/adr/0353-a-hub-invite-is-a-notice-of-the-projects-own-invite.md +1 -1
- package/docs/adr/0356-a-recruit-invite-expires-30-days-after-it-is-sent-read-time.md +46 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +2 -2
- package/docs/copy-inventory.md +20 -19
- package/docs/copy-registry.json +34 -25
- package/docs/module-api-changelog.md +3 -1
- package/docs/page-readings.json +9 -9
- package/migrations/core_266_access_requests_invited_login_idx.sql +31 -0
- package/modules/hall-ui/public/watch.js +9 -3
- package/modules/onboarding/routes/access-requests.js +43 -20
- package/modules/platform-identity/platform-identity.js +12 -8
- package/modules/platform-identity/tests/platform-identity.mjs +4 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +10 -0
- package/scripts/gds/fitness.js +4 -0
- package/scripts/gds/login.js +6 -0
- package/scripts/gds/run-unit-tests.js +4 -0
- package/src/bongos/db-kernel.js +6 -3
- package/src/bongos/invite-expiry.js +47 -0
- package/src/module-api.js +10 -1
- package/tests/access_requests_invite.mjs +2 -1
- package/tests/application_lifecycle.mjs +164 -5
- package/tests/bongos_login.mjs +2 -0
- package/tests/hub_invite_notices.mjs +5 -2
- package/tests/invite_expiry.mjs +37 -0
- package/tests/invite_expiry_db.mjs +196 -0
- package/tests/module_api.mjs +1 -0
- package/tests/project_admin_console_model.mjs +12 -5
package/tests/module_api.mjs
CHANGED
|
@@ -49,6 +49,7 @@ const PUBLISHED_SURFACE = [
|
|
|
49
49
|
'artistGate', // added by task 1003575 (ADR 0241): the artist gate — off | advisory | strict, plus the pure verdict helpers over it. Two modules ask it two different questions ("file this review?" and "does an open one hold the deploy?") and both must resolve the knob through this one reader, never branding().project
|
|
50
50
|
'readApplicantProfileFromHub', // added by task 1002972 (privacy spec D7): the reviewer queue's LIVE per-render read of one applicant's hub profile view. NARROW by design — the underlying call is authenticated with this instance's hub client secret, and loadIdpConfig stays OFF the doorway so no module ever holds the credential that speaks for the whole project
|
|
51
51
|
'notifyHubOfInvite', // added by task 1002818 (ADR 0353): tell the hub about one of THIS project's invites (or its rescind) so the invitee sees it in My Projects. The same NARROW-port reason as readApplicantProfileFromHub: the call carries this instance's hub client secret, so a module passes one login and one direction and can neither widen nor re-address it
|
|
52
|
+
'inviteExpiry', // added by task 1002969 (ADR 0356): the ONE read-time definition of when a recruit invite's door closes. The sign-in gate reads it in core; the onboarding queues and the hub's notice list are modules, so without the doorway each would restate the 30 days and the predicate, and two copies can close a door on different days
|
|
52
53
|
'readApplicationVouch', // added by task 1002285 (ADR 0201 D2): the public access-request write's check of the hub's application vouch. NARROW for the same reason — core supplies the hub key and this instance's client_id, so a module passes a token and a login and can neither swap the key nor re-address the audience
|
|
53
54
|
'enabledDisciplines', // BV1.R81: instance offered-disciplines (1.9.0; onboarding restock backstop)
|
|
54
55
|
'isModuleEnabled', // task 1003881: is ANOTHER module present? onboarding's Discord approve/decline control is only actionable when the `discord` module's reaction handler is loaded, so the posting half has to be able to ask
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
// drift quietly is worse than none, so the load-bearing ones are pinned here:
|
|
7
7
|
//
|
|
8
8
|
// D1 the hub relays and notifies; it never writes a project's admission row
|
|
9
|
-
// D2 an invite is a row the existing gate already reads — `
|
|
10
|
-
// `
|
|
9
|
+
// D2 an invite is a row the existing gate already reads — `created_by` never
|
|
10
|
+
// enters the admission read, and `kind` enters it only through the invite
|
|
11
|
+
// expiry, which can close a door and never open one (ADR 0356 amends D2.5)
|
|
11
12
|
// D3 the admission verdict stays `access_request.review` at the archon floor,
|
|
12
13
|
// and `project.recruit`, once minted, takes exactly the shape the ADR fixes
|
|
13
14
|
//
|
|
@@ -66,16 +67,22 @@ test('the ADR exists, is indexed, and ADR 0141 names it as superseding its §5 i
|
|
|
66
67
|
|
|
67
68
|
// Both admission reads: the gate's own (hasInvitedAccessRequest) and the state the
|
|
68
69
|
// "confirming access" waiting page polls (accessStateByLogin), which must agree with it.
|
|
69
|
-
|
|
70
|
+
// Since ADR 0356 (task 1002969) `kind` reaches them through ONE door: the ANDed
|
|
71
|
+
// invite-expiry unit, which only ever narrows `status = 'invited'`.
|
|
72
|
+
test('D2: both admission reads look at status, narrowed only by the invite expiry — never widened by kind', () => {
|
|
70
73
|
const src = read('src', 'bongos', 'db-kernel.js');
|
|
71
74
|
for (const fn of ['hasInvitedAccessRequest', 'accessStateByLogin']) {
|
|
72
75
|
const m = new RegExp(`async function ${fn}\\([^)]*\\)\\s*\\{([\\s\\S]*?)\\n\\}`).exec(src);
|
|
73
76
|
assert.ok(m, `${fn} is still an admission read in db-kernel.js`);
|
|
74
77
|
const body = m[1];
|
|
75
|
-
assert.match(body, /status\s*=\s*'invited'/, `${fn}: admission is status = invited`);
|
|
76
|
-
assert.doesNotMatch(body, /\bkind\b/, `${fn}: kind is
|
|
78
|
+
assert.match(body, /status\s*=\s*'invited'\s+AND\s+\$\{inviteLiveSql\(\)\}/, `${fn}: admission is status = invited AND the invite has not expired`);
|
|
79
|
+
assert.doesNotMatch(body, /\bkind\b/, `${fn}: kind is never read directly; only through inviteLiveSql`);
|
|
77
80
|
assert.doesNotMatch(body, /\bcreated_by\b/, `${fn}: created_by is audit data; it must never decide admission`);
|
|
78
81
|
}
|
|
82
|
+
// And that unit can only close a door: NOT (an invite AND past its window).
|
|
83
|
+
const { inviteLiveSql } = require('../src/bongos/invite-expiry.js');
|
|
84
|
+
assert.match(inviteLiveSql(), /^NOT \(kind = 'invite' AND created_at <= now\(\) - interval '\d+ days'\)$/,
|
|
85
|
+
'the expiry is a pure narrowing: a row that is not an invite is untouched by it');
|
|
79
86
|
});
|
|
80
87
|
|
|
81
88
|
test('D1: no hub (platform-identity) source writes access_requests — the hub relays, it never admits', () => {
|