@bongos/core 1.19.1022 → 1.19.1024
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 +16 -16
- package/docs/copy-inventory.md +1 -1
- package/docs/copy-registry.json +2 -2
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/people.html +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/bongos/auth-github.js +4 -2
- package/src/bongos/db-kernel.js +1 -1
- package/src/module-api.js +1 -1
- package/tests/auth_inactive_builder.mjs +84 -0
- package/tests/people_name_only.mjs +2 -1
package/.bongos-core.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"artifact": "bongos-core",
|
|
3
3
|
"manifest_schema": 1,
|
|
4
4
|
"generator": "scripts/gds/package-core.js",
|
|
5
|
-
"core_version": "1.19.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.1024",
|
|
6
|
+
"core_contract": "1.19.1024",
|
|
7
|
+
"source_commit": "1f872aa1aae41740fd237a96d918a44b10a7eb37",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-25T19:58:25.153Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 529,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2998,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "10c61e80a11ff4a40f7719f719f309183eaa139cfef10e0d768b48cb5b5aba2d",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2222,12 +2222,12 @@
|
|
|
2222
2222
|
{
|
|
2223
2223
|
"path": "docs/copy-inventory.md",
|
|
2224
2224
|
"mode": "0000644",
|
|
2225
|
-
"sha256": "
|
|
2225
|
+
"sha256": "c43c114a44d0b4f5956e619e5248fcc67473f094c1aa9f58af0b877666a6821a"
|
|
2226
2226
|
},
|
|
2227
2227
|
{
|
|
2228
2228
|
"path": "docs/copy-registry.json",
|
|
2229
2229
|
"mode": "0000644",
|
|
2230
|
-
"sha256": "
|
|
2230
|
+
"sha256": "5a0786f9cba9d26c3dc3ef41197a0ea1a00e95a068407305b86a1d880d8fd31e"
|
|
2231
2231
|
},
|
|
2232
2232
|
{
|
|
2233
2233
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2757,7 +2757,7 @@
|
|
|
2757
2757
|
{
|
|
2758
2758
|
"path": "docs/module-api-changelog.md",
|
|
2759
2759
|
"mode": "0000644",
|
|
2760
|
-
"sha256": "
|
|
2760
|
+
"sha256": "fef4b48a53826405914b6b5f88bd39087b2c89791d0c22c4b807ad21a0000d7a"
|
|
2761
2761
|
},
|
|
2762
2762
|
{
|
|
2763
2763
|
"path": "docs/modules-contract.md",
|
|
@@ -5207,7 +5207,7 @@
|
|
|
5207
5207
|
{
|
|
5208
5208
|
"path": "modules/hall-ui/public/people.html",
|
|
5209
5209
|
"mode": "0000644",
|
|
5210
|
-
"sha256": "
|
|
5210
|
+
"sha256": "531b5b44da9f8310cdac68f7028651b9faba93537f46a7d62d2d91b534cb60ee"
|
|
5211
5211
|
},
|
|
5212
5212
|
{
|
|
5213
5213
|
"path": "modules/hall-ui/public/people.js",
|
|
@@ -8312,12 +8312,12 @@
|
|
|
8312
8312
|
{
|
|
8313
8313
|
"path": "package-lock.json",
|
|
8314
8314
|
"mode": "0000644",
|
|
8315
|
-
"sha256": "
|
|
8315
|
+
"sha256": "36328e51d05e9c402d841cb01fb8c71ebc3fb1ac9ab4980d92157019d0390f74"
|
|
8316
8316
|
},
|
|
8317
8317
|
{
|
|
8318
8318
|
"path": "package.json",
|
|
8319
8319
|
"mode": "0000644",
|
|
8320
|
-
"sha256": "
|
|
8320
|
+
"sha256": "7f5cea69d8281535703f3803703b34c4df2196e19284415e59152007b257208e"
|
|
8321
8321
|
},
|
|
8322
8322
|
{
|
|
8323
8323
|
"path": "public-docs/index.html",
|
|
@@ -10067,7 +10067,7 @@
|
|
|
10067
10067
|
{
|
|
10068
10068
|
"path": "src/bongos/auth-github.js",
|
|
10069
10069
|
"mode": "0000644",
|
|
10070
|
-
"sha256": "
|
|
10070
|
+
"sha256": "9d556b0c6b4891be1aee578daf7bd62347f1dc77fe20af7ffcaeb9f61845c141"
|
|
10071
10071
|
},
|
|
10072
10072
|
{
|
|
10073
10073
|
"path": "src/bongos/auth-idp.js",
|
|
@@ -10097,7 +10097,7 @@
|
|
|
10097
10097
|
{
|
|
10098
10098
|
"path": "src/bongos/db-kernel.js",
|
|
10099
10099
|
"mode": "0000644",
|
|
10100
|
-
"sha256": "
|
|
10100
|
+
"sha256": "0e346143160d09d1c9bb5e1977551222bf8d33dce9a1880537b17b1d714f719e"
|
|
10101
10101
|
},
|
|
10102
10102
|
{
|
|
10103
10103
|
"path": "src/bongos/db.js",
|
|
@@ -10362,7 +10362,7 @@
|
|
|
10362
10362
|
{
|
|
10363
10363
|
"path": "src/module-api.js",
|
|
10364
10364
|
"mode": "0000644",
|
|
10365
|
-
"sha256": "
|
|
10365
|
+
"sha256": "e9218e1f21e4706d02bdd26c6c348c571996a23515d3b57295a71b97be5ff193"
|
|
10366
10366
|
},
|
|
10367
10367
|
{
|
|
10368
10368
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10742,7 +10742,7 @@
|
|
|
10742
10742
|
{
|
|
10743
10743
|
"path": "tests/auth_inactive_builder.mjs",
|
|
10744
10744
|
"mode": "0000644",
|
|
10745
|
-
"sha256": "
|
|
10745
|
+
"sha256": "521e4175ec619d578fe18dc23395e384f9f35be747918ed04e7d479cb0166da8"
|
|
10746
10746
|
},
|
|
10747
10747
|
{
|
|
10748
10748
|
"path": "tests/auth_page_gate.mjs",
|
|
@@ -13327,7 +13327,7 @@
|
|
|
13327
13327
|
{
|
|
13328
13328
|
"path": "tests/people_name_only.mjs",
|
|
13329
13329
|
"mode": "0000644",
|
|
13330
|
-
"sha256": "
|
|
13330
|
+
"sha256": "52885d21c83ba02f0eece097529df861ac2e01c8def1a77d7e55a07638cc076d"
|
|
13331
13331
|
},
|
|
13332
13332
|
{
|
|
13333
13333
|
"path": "tests/permission_path.mjs",
|
package/docs/copy-inventory.md
CHANGED
|
@@ -1116,7 +1116,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1116
1116
|
| `bcdbded93d4e` | certain | The work board failed to load. Reload to try again. | `modules/hall-ui/public/work.js:1492` |
|
|
1117
1117
|
| `25794c439321` | certain | Then copy the project onto your machine and run the one-shot bootstrap (it checks your setup, installs depende | `modules/hall-ui/public/hall-render.js:890` |
|
|
1118
1118
|
| `df316c3484de` | certain | Then drive it however you like: | `modules/hall-ui/public/hall-render.js:825` |
|
|
1119
|
-
| `
|
|
1119
|
+
| `bc3e5d620247` | certain | These builders are open to recruiting but keep their cross-project record hidden, so only who they are is show | `modules/hall-ui/public/people.html:54` |
|
|
1120
1120
|
| `a0140098c0e0` | certain | They already have an invitation or a join-request pending on this goal. | `modules/hall-ui/public/goals-render.js:1303` |
|
|
1121
1121
|
| `5151cf635644` | certain | They have asked to connect. | `modules/hall-ui/public/profile-connections.js:236` |
|
|
1122
1122
|
| `10219b02433e` | certain | They join as a member once they accept — you can change that afterwards. Nobody is added until they do. | `modules/hall-ui/public/goals-render.js:1235` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -11554,9 +11554,9 @@
|
|
|
11554
11554
|
"confidence": "certain"
|
|
11555
11555
|
},
|
|
11556
11556
|
{
|
|
11557
|
-
"id": "
|
|
11557
|
+
"id": "bc3e5d620247",
|
|
11558
11558
|
"surface": "builders-hall",
|
|
11559
|
-
"text": "These builders are open to recruiting but keep their cross-project record
|
|
11559
|
+
"text": "These builders are open to recruiting but keep their cross-project record hidden, so only who they are is shown. They are never ranked, and a role filter never finds them.",
|
|
11560
11560
|
"file": "modules/hall-ui/public/people.html",
|
|
11561
11561
|
"line": 54,
|
|
11562
11562
|
"origin": "html-text",
|
|
@@ -2523,5 +2523,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2523
2523
|
landed since 1.19.1020 with no explicit bump. run 36086047874. (task 1002620)
|
|
2524
2524
|
1.19.1022 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2525
2525
|
landed since 1.19.1021 with no explicit bump. run 36176262855. (task 1002620)
|
|
2526
|
+
1.19.1023 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2527
|
+
landed since 1.19.1022 with no explicit bump. run 36178875275. (task 1002620)
|
|
2528
|
+
1.19.1024 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2529
|
+
landed since 1.19.1023 with no explicit bump. run 36182843374. (task 1002620)
|
|
2526
2530
|
---------------------------------------------------------------------------
|
|
2527
2531
|
```
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
response carries a row, and people.js writes it. -->
|
|
52
52
|
<section class="scroll" id="people-named-scroll" aria-labelledby="people-named-h" hidden>
|
|
53
53
|
<h2 id="people-named-h" class="scroll__h">Listed by name only<span class="count-pill" id="people-named-count" hidden></span></h2>
|
|
54
|
-
<p class="scroll__lede" id="people-named-lede">These builders are open to recruiting but keep their cross-project record
|
|
54
|
+
<p class="scroll__lede" id="people-named-lede">These builders are open to recruiting but keep their cross-project record hidden, so only who they are is shown. They are never ranked, and a role filter never finds them.</p>
|
|
55
55
|
<div id="people-named-body"></div>
|
|
56
56
|
<p class="ledger__note" id="people-named-foot" hidden></p>
|
|
57
57
|
</section>
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1024",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.1024",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1024",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
|
@@ -312,8 +312,10 @@ async function completeWebFlow({ code, redirectUri, userAgent, captureRepoToken
|
|
|
312
312
|
// callback can persist it (encrypted, short-TTL) for the repo picker/creator.
|
|
313
313
|
// auth.js stays kernel-clean — it never writes the token to the DB itself; the
|
|
314
314
|
// token is surfaced ONLY on this opt-in path, so an ordinary hall sign-in never
|
|
315
|
-
// even returns it.
|
|
316
|
-
|
|
315
|
+
// even returns it. Never for an offboarded builder: the gate admits every existing
|
|
316
|
+
// row, and this would re-seed the token deactivateBuilder deleted (ADR 0332, task 1004245).
|
|
317
|
+
const captured = captureRepoToken && builder.status !== 'inactive'
|
|
318
|
+
? { githubToken: accessToken, githubScope: grantedScope } : {};
|
|
317
319
|
return { token, builder, expiresAt, ...captured };
|
|
318
320
|
}
|
|
319
321
|
|
package/src/bongos/db-kernel.js
CHANGED
|
@@ -192,7 +192,7 @@ async function upsertBuilder({ githubId, githubLogin, displayName, avatarUrl })
|
|
|
192
192
|
THEN 'user'
|
|
193
193
|
ELSE 'github' END,
|
|
194
194
|
avatar_url = EXCLUDED.avatar_url
|
|
195
|
-
RETURNING id, github_id, github_login, display_name, avatar_url, total_credits, created_at, rank, preferred_disciplines`,
|
|
195
|
+
RETURNING id, github_id, github_login, display_name, avatar_url, total_credits, created_at, rank, preferred_disciplines, status`,
|
|
196
196
|
[String(githubId), githubLogin, displayName, avatarUrl ?? null]
|
|
197
197
|
);
|
|
198
198
|
return rows[0];
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.1024'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
// so a Cookie header stuffed with dozens of gds_session=<junk> values can't
|
|
15
15
|
// amplify into dozens of per-request DB lookups (DoS).
|
|
16
16
|
//
|
|
17
|
+
// 3. An offboarded builder's GitHub web sign-in must not re-seed the
|
|
18
|
+
// github_oauth_tokens row deactivateBuilder deleted (task 1004245, ADR 0332).
|
|
19
|
+
//
|
|
17
20
|
// lookupSession is stubbed on the db module BEFORE auth.js is required, because
|
|
18
21
|
// auth.js destructures it at load time. No server/DB/network.
|
|
19
22
|
//
|
|
@@ -90,5 +93,86 @@ await t('extractTokens caps the candidates it returns (DoS amplification guard)'
|
|
|
90
93
|
assert.equal(tokens[0], 'realone', 'the Bearer token is tried first');
|
|
91
94
|
});
|
|
92
95
|
|
|
96
|
+
// ---- web sign-in cannot re-seed an offboarded builder's GitHub token --------
|
|
97
|
+
// The admission gate admits every EXISTING builder, so an inactive one still
|
|
98
|
+
// completes the web flow. The fake DB runs the REAL upsertBuilder SQL and answers
|
|
99
|
+
// only the columns its RETURNING list names, so this fails if `status` ever drops
|
|
100
|
+
// out of that list. GitHub is a stubbed fetch; the callback is the real handler.
|
|
101
|
+
const { pool } = require('../src/bongos/pool.js');
|
|
102
|
+
const { envPrefix } = require('../src/instance-config.js');
|
|
103
|
+
const coreDb = require('../src/bongos/db.js');
|
|
104
|
+
const buildAuthRouter = require('../src/bongos/routes/auth.js');
|
|
105
|
+
|
|
106
|
+
process.env[`${envPrefix()}_GITHUB_CLIENT_ID`] = 'test-client';
|
|
107
|
+
process.env[`${envPrefix()}_GITHUB_CLIENT_SECRET`] = 'test-secret';
|
|
108
|
+
|
|
109
|
+
const GH_TOKEN = 'gho_repo_scoped_token';
|
|
110
|
+
const ROW = {
|
|
111
|
+
id: 77, github_id: '4242', github_login: 'offboarded-ghost', display_name: 'Ghost', avatar_url: null,
|
|
112
|
+
total_credits: 12, created_at: new Date(0), rank: 'xenos', preferred_disciplines: null,
|
|
113
|
+
};
|
|
114
|
+
let builderRow = null;
|
|
115
|
+
const pick = (list) => Object.fromEntries(list.split(',').map((c) => c.trim()).map((c) => [c, builderRow[c]]));
|
|
116
|
+
pool.query = async (sql) => {
|
|
117
|
+
if (/INSERT INTO builders\b/.test(sql)) return { rows: [pick(sql.split('RETURNING')[1])] };
|
|
118
|
+
if (/FROM builders WHERE github_id/.test(sql)) return { rows: [pick(sql.match(/SELECT([\s\S]*?)FROM/)[1])] };
|
|
119
|
+
return { rows: [], rowCount: 0 };
|
|
120
|
+
};
|
|
121
|
+
globalThis.fetch = async (url) => {
|
|
122
|
+
if (String(url) === 'https://github.com/login/oauth/access_token') {
|
|
123
|
+
return { ok: true, json: async () => ({ access_token: GH_TOKEN, scope: 'read:user,repo' }) };
|
|
124
|
+
}
|
|
125
|
+
if (String(url) === 'https://api.github.com/user') {
|
|
126
|
+
return { ok: true, json: async () => ({ id: 4242, login: ROW.github_login, name: 'Ghost', avatar_url: null }) };
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`unexpected fetch in test: ${url}`);
|
|
129
|
+
};
|
|
130
|
+
const tokenWrites = [];
|
|
131
|
+
coreDb.upsertGithubToken = async (args) => { tokenWrites.push(args); return { stored: true }; };
|
|
132
|
+
|
|
133
|
+
const callback = buildAuthRouter().stack
|
|
134
|
+
.find((l) => l.route?.path === '/auth/web/callback' && l.route.methods.get).route.stack[0].handle;
|
|
135
|
+
async function signInWithRepoOptIn() {
|
|
136
|
+
const req = {
|
|
137
|
+
query: { state: 'st8', code: 'c0de' }, secure: false,
|
|
138
|
+
headers: { cookie: 'gds_oauth_state=st8; gds_oauth_repos=1', host: 'localhost', 'user-agent': 'test' },
|
|
139
|
+
};
|
|
140
|
+
const res = {
|
|
141
|
+
redirectedTo: null, statusCode: 200, cookies: {},
|
|
142
|
+
cookie(name, value) { this.cookies[name] = value; return this; },
|
|
143
|
+
clearCookie() { return this; },
|
|
144
|
+
redirect(to) { this.redirectedTo = to; },
|
|
145
|
+
status(code) { this.statusCode = code; return this; },
|
|
146
|
+
type() { return this; },
|
|
147
|
+
send() { return this; },
|
|
148
|
+
};
|
|
149
|
+
await callback(req, res);
|
|
150
|
+
return res;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
await t('offboarded builder: an opted-in web sign-in never reaches upsertGithubToken', async () => {
|
|
154
|
+
builderRow = { ...ROW, status: 'inactive' };
|
|
155
|
+
tokenWrites.length = 0;
|
|
156
|
+
const res = await signInWithRepoOptIn();
|
|
157
|
+
assert.equal(tokenWrites.length, 0, 'the token deactivateBuilder deleted must not be written back');
|
|
158
|
+
assert.ok(res.redirectedTo, 'sign-in itself is not refused: requireBuilder denies the session per request');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await t('offboarded builder: completeWebFlow never hands the repo token back', async () => {
|
|
162
|
+
builderRow = { ...ROW, status: 'inactive' };
|
|
163
|
+
const out = await auth.completeWebFlow({ code: 'c0de', redirectUri: 'http://localhost/cb', captureRepoToken: true });
|
|
164
|
+
assert.equal(out.githubToken, undefined);
|
|
165
|
+
assert.equal(out.githubScope, undefined);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await t('active builder: an opted-in web sign-in still captures the repo token (control)', async () => {
|
|
169
|
+
builderRow = { ...ROW, status: 'active' };
|
|
170
|
+
tokenWrites.length = 0;
|
|
171
|
+
await signInWithRepoOptIn();
|
|
172
|
+
assert.equal(tokenWrites.length, 1, 'the wizard repo-token capture keeps working');
|
|
173
|
+
assert.equal(tokenWrites[0].builderId, ROW.id);
|
|
174
|
+
assert.equal(tokenWrites[0].token, GH_TOKEN);
|
|
175
|
+
});
|
|
176
|
+
|
|
93
177
|
console.log(`\n${pass} passed, ${fail} failed`);
|
|
94
178
|
process.exit(fail === 0 ? 0 : 1);
|
|
@@ -149,7 +149,8 @@ await test('the page carries the name-only panel, hidden until the server sends
|
|
|
149
149
|
assert.match(PEOPLE_HTML, /id="people-named-h"[^>]*>[^<]+<span class="count-pill" id="people-named-count" hidden>/,
|
|
150
150
|
'a heading with its own count');
|
|
151
151
|
const lede = (PEOPLE_HTML.match(/<p class="scroll__lede" id="people-named-lede">([^<]+)<\/p>/) || [])[1] || '';
|
|
152
|
-
assert.match(lede, /
|
|
152
|
+
assert.match(lede, /hidden/i, 'the lede says why these builders show no record, in the same word Settings uses (hide_stats)');
|
|
153
|
+
assert.doesNotMatch(lede, /private/i, '"private" is account_visibility\'s word, not hide_stats\'');
|
|
153
154
|
assert.match(lede, /ranked/i, 'and that they are never ranked');
|
|
154
155
|
assert.match(lede, /filter/i, 'and that a role filter never finds them');
|
|
155
156
|
assert.match(PEOPLE_HTML, /id="people-named-body"/, 'and a mount for the ledger');
|