@bongos/core 1.19.543 → 1.19.544

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 CHANGED
@@ -2,22 +2,22 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.543",
6
- "core_contract": "1.19.543",
7
- "source_commit": "8d5b1f68e885902bb0851591d2b35d43eecff581",
5
+ "core_version": "1.19.544",
6
+ "core_contract": "1.19.544",
7
+ "source_commit": "39e93444ac36149c8bb957f5ae126d8aa7cd62f2",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-04T17:09:32.032Z",
9
+ "built_at": "2026-09-04T17:18:05.591Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 441,
13
13
  "agent_docs_stubbed": 24,
14
- "functional_verbatim": 2002,
14
+ "functional_verbatim": 2003,
15
15
  "rules": 3,
16
16
  "gate_literals": 3,
17
17
  "gate": "passed"
18
18
  },
19
- "file_count": 2467,
20
- "tree_sha256": "f3f5f90431fba132c561bccac86ccf363ecf2e5be726ac20df1e515ff5a17b96",
19
+ "file_count": 2468,
20
+ "tree_sha256": "b0c7ab244b91e9f7d26b62e0eab1f44718911676a3fa72e820c1a0df26ca25a2",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -2647,7 +2647,7 @@
2647
2647
  {
2648
2648
  "path": "docs/module-api-changelog.md",
2649
2649
  "mode": "0000644",
2650
- "sha256": "363cca06f1b0153833ca8c99e1049e07be4720893824f9a850b92115ae933f8d"
2650
+ "sha256": "12a76f02ae81dc2a3674d6de15040ab2131cdf4dc912b4e48291d4790be9cde1"
2651
2651
  },
2652
2652
  {
2653
2653
  "path": "docs/modules-contract.md",
@@ -7412,12 +7412,12 @@
7412
7412
  {
7413
7413
  "path": "package-lock.json",
7414
7414
  "mode": "0000644",
7415
- "sha256": "001aec2b3056c4a091ac11df84b601915620bfd12c47d301c911ae73010e435f"
7415
+ "sha256": "5a9a55d27d4d93812cd6e549519231de3458d772987ad429cb2ae4f746af820f"
7416
7416
  },
7417
7417
  {
7418
7418
  "path": "package.json",
7419
7419
  "mode": "0000644",
7420
- "sha256": "83110f9406eab37d64b6ddfe263ec2ed5897875f071ef1d11a16bb9b582297a7"
7420
+ "sha256": "bf0b5224da645322f40ca158a7e795b728cd9a5b05a746c46937b31702b3aed6"
7421
7421
  },
7422
7422
  {
7423
7423
  "path": "public-docs/index.html",
@@ -7602,7 +7602,7 @@
7602
7602
  {
7603
7603
  "path": "scripts/gds/box.js",
7604
7604
  "mode": "0000644",
7605
- "sha256": "d6533af0ebd1e75cda7816694871b4bac812b972b9e67b6f9cbbdaeaaf3f75a8"
7605
+ "sha256": "afcebfb8e8e8f7041ee9cbfce1e9b8a46a299feb5e6e89ce4e00273135b268db"
7606
7606
  },
7607
7607
  {
7608
7608
  "path": "scripts/gds/build-bongos.js",
@@ -9102,7 +9102,7 @@
9102
9102
  {
9103
9103
  "path": "src/module-api.js",
9104
9104
  "mode": "0000644",
9105
- "sha256": "f5656136402e72498a9e8508fe683ee9f54bd6b58aaa78b5516f1313a681566b"
9105
+ "sha256": "de4fc6ed04c9b3425132b6671c6741bcbc18c8e8b5545c5ee12fe2f2f723f725"
9106
9106
  },
9107
9107
  {
9108
9108
  "path": "src/module-loader/catalog.js",
@@ -9484,6 +9484,11 @@
9484
9484
  "mode": "0000644",
9485
9485
  "sha256": "f0718abdcaaf538bff5b7724bf848ec8a81082192fee4f492409a13faf18c578"
9486
9486
  },
9487
+ {
9488
+ "path": "tests/box_env.mjs",
9489
+ "mode": "0000644",
9490
+ "sha256": "38fa2cd23a84c4e5d7c9b665e906b14965783bc0c570f444764c68a539bc0073"
9491
+ },
9487
9492
  {
9488
9493
  "path": "tests/box_host_keys.mjs",
9489
9494
  "mode": "0000644",
@@ -1535,5 +1535,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
1535
1535
  landed since 1.19.541 with no explicit bump. run 33898437821. (task 1002620)
1536
1536
  1.19.543 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1537
1537
  landed since 1.19.542 with no explicit bump. run 33898997776. (task 1002620)
1538
+ 1.19.544 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1539
+ landed since 1.19.543 with no explicit bump. run 33899781074. (task 1002620)
1538
1540
  ---------------------------------------------------------------------------
1539
1541
  ```
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.543",
3
+ "version": "1.19.544",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.543",
9
+ "version": "1.19.544",
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.543",
3
+ "version": "1.19.544",
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",
@@ -177,6 +177,25 @@ async function resolveBuilder(pool, ref) {
177
177
  // A short, DNS-safe-ish suffix from the current time (CLI context — Date is fine).
178
178
  // ---- provision -------------------------------------------------------------
179
179
 
180
+ // Pure: renders the /etc/otb/box.env content cloud-init bakes onto a box (task
181
+ // 1002466). Split out of cmdProvision so GDS_BASE — and the named-tunnel block
182
+ // baked in beside it — can be unit-tested without DB/DO/Cloudflare.
183
+ //
184
+ // GDS_BASE is the FULL api base (origin + /api/gds), matching what
185
+ // infra/box-report-*.sh already derive from the session file when the env var is
186
+ // absent (`"$GDS_BASE/box/host-keys"` with no further path inserted) — every box
187
+ // used to get this only as a fallback derived on-box; baking it explicitly closes
188
+ // the one on-box script (box-source-fetch.sh, out-of-repo) that skips that
189
+ // derivation entirely and hardcodes a different instance's origin instead.
190
+ function buildBoxEnv({ apiOrigin, namedTunnel }) {
191
+ let env = `# /etc/otb/box.env — baked by box.js provision\nGDS_BASE=${String(apiOrigin).replace(/\/+$/, '')}/api/gds\n`;
192
+ if (namedTunnel) {
193
+ const { token, hostname, credential, previewHostname } = namedTunnel;
194
+ env += `# named tunnel (#771/#774, ADR 0038)\nBOX_TUNNEL_TOKEN=${token}\nBOX_TERMINAL_HOSTNAME=${hostname}\nBOX_TERMINAL_CREDENTIAL=${credential}\nBOX_PREVIEW_HOSTNAME=${previewHostname}\n`;
195
+ }
196
+ return env;
197
+ }
198
+
180
199
  async function cmdProvision(pool, boxes, boxOnboard, ref, { apply }) {
181
200
  const builder = await resolveBuilder(pool, ref);
182
201
  if (!builder) return fail(`no builder matches "${ref}"`);
@@ -272,7 +291,13 @@ async function cmdProvision(pool, boxes, boxOnboard, ref, { apply }) {
272
291
  // (setTerminalAccess): the builder reads them from the hall, with no token placed
273
292
  // on the box and no box-side reporter (the quick-tunnel fallback that caused the
274
293
  // #771/#774 chicken-and-egg). ADR 0016 holds — no credential funneled into a box.
275
- let boxEnv = '';
294
+ // GDS_BASE (task 1002466 — see buildBoxEnv above for the shape/why): a box was
295
+ // never actually bare here EXCEPT the one on-box script that skips the
296
+ // session-file fallback (box-source-fetch.sh, out-of-repo on the control-plane
297
+ // — see the cross-repo blocker filed alongside this fix). Baking it explicitly
298
+ // closes that gap for every future box regardless of which script forgets it.
299
+ const apiOrigin = process.env.GDS_PUBLIC_ORIGIN || instanceConfig.defaultApiBase();
300
+ let boxEnv = buildBoxEnv({ apiOrigin });
276
301
  let terminalHostname = null;
277
302
  let terminalCredential = null;
278
303
  if (namedTunnelEnabled()) {
@@ -286,7 +311,10 @@ async function cmdProvision(pool, boxes, boxOnboard, ref, { apply }) {
286
311
  // + DNS for the live game preview. Bake its hostname so the box's
287
312
  // box-preview command can show the builder their URL (no DB row needed — the
288
313
  // host is deterministic; box-game-preview.service serves :3000 behind it).
289
- boxEnv = `# /etc/otb/box.env — baked by box.js provision (#771/#774, ADR 0038 named tunnel)\nBOX_TUNNEL_TOKEN=${token}\nBOX_TERMINAL_HOSTNAME=${th}\nBOX_TERMINAL_CREDENTIAL=${terminalCredential}\nBOX_PREVIEW_HOSTNAME=${ph}\n`;
314
+ boxEnv = buildBoxEnv({
315
+ apiOrigin,
316
+ namedTunnel: { token, hostname: th, credential: terminalCredential, previewHostname: ph },
317
+ });
290
318
  console.log(` ✓ named tunnel ready — ${th}`);
291
319
  console.log(` ✓ live game preview — https://${ph} (ADR 0044)`);
292
320
  // The rule PUT is the ONLY thing that proves edit scope. Report its real
@@ -330,6 +358,12 @@ async function cmdProvision(pool, boxes, boxOnboard, ref, { apply }) {
330
358
  builder: { id: builder.id, github_login: builder.github_login, rank: builder.rank },
331
359
  // The instance's OWN public origin (task 1002428) — a hardcoded founder host
332
360
  // here would point every newly provisioned box at the wrong instance.
361
+ //
362
+ // defaultApiBase(), deliberately NOT resolveApiBase() (task 1002466): a box
363
+ // belongs to the SERVER it was provisioned on, not to whichever instance this
364
+ // operator's own CLI session happens to be signed into right now — the two can
365
+ // differ (an operator provisioning boxes across instances) and the box must
366
+ // still call home to itself, not to the operator's other login.
333
367
  api_base: process.env.GDS_PUBLIC_ORIGIN || instanceConfig.defaultApiBase(),
334
368
  }, null, 2);
335
369
 
@@ -1265,4 +1299,4 @@ async function main() {
1265
1299
 
1266
1300
  if (require.main === module) main();
1267
1301
 
1268
- module.exports = { cmdProvision, deprovisionOne, parkOne, cmdSweepIdle, cmdSweepDormant, deleteWithRetry, cmdReconcileDrift, runDnsHook, runDnsHookBlackhole, markErrorUnlessDestroyed, resolveBoxInfraDir, boxInfraCandidates, readCloudInit, BOX_INFRA_TEMPLATE };
1302
+ module.exports = { cmdProvision, deprovisionOne, parkOne, cmdSweepIdle, cmdSweepDormant, deleteWithRetry, cmdReconcileDrift, runDnsHook, runDnsHookBlackhole, markErrorUnlessDestroyed, resolveBoxInfraDir, boxInfraCandidates, readCloudInit, buildBoxEnv, BOX_INFRA_TEMPLATE };
package/src/module-api.js CHANGED
@@ -49,7 +49,7 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
49
49
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
50
50
  // the entry to that file. Look for a version's history there, not here.
51
51
  // ---------------------------------------------------------------------------
52
- const CORE_VERSION = '1.19.543'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
52
+ const CORE_VERSION = '1.19.544'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
53
53
 
54
54
  // A namespaced logger so a module's log lines are attributable + consistent.
55
55
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -0,0 +1,64 @@
1
+ // tests/box_env.mjs
2
+ //
3
+ // task 1002466 — a provisioned box's cloud-init baked NO GDS_BASE, so any on-box
4
+ // script that (unlike infra/box-report-*.sh) doesn't fall back to deriving it from
5
+ // the session file's api_base had nothing telling it which instance to talk to.
6
+ // box.js now bakes GDS_BASE explicitly via the pure buildBoxEnv() helper, split
7
+ // out of cmdProvision so this can be pinned without DB/DO/Cloudflare.
8
+ //
9
+ // Pure + hermetic: buildBoxEnv takes plain inputs and returns a string. No DB, no
10
+ // network, no droplet.
11
+ //
12
+ // Run: node tests/box_env.mjs
13
+
14
+ import { strict as assert } from 'node:assert';
15
+ import { createRequire } from 'node:module';
16
+ import { makeRunner } from './helpers.mjs';
17
+
18
+ const require = createRequire(import.meta.url);
19
+ const box = require('../scripts/gds/box.js');
20
+
21
+ const { test, summary } = makeRunner();
22
+
23
+ await test('bakes GDS_BASE as the FULL api base (origin + /api/gds) — matches box-report-*.sh, not box-heartbeat.sh\'s bare-origin BASE', () => {
24
+ const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com' });
25
+ assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/gds$/m);
26
+ });
27
+
28
+ await test('strips a trailing slash off the origin before appending /api/gds', () => {
29
+ const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com/' });
30
+ assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/gds$/m);
31
+ assert.ok(!env.includes('//api/gds'), 'must not double the slash');
32
+ });
33
+
34
+ await test('no named tunnel: box.env carries GDS_BASE and nothing else', () => {
35
+ const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com' });
36
+ assert.ok(!/BOX_TUNNEL_TOKEN|BOX_TERMINAL_HOSTNAME|BOX_TERMINAL_CREDENTIAL|BOX_PREVIEW_HOSTNAME/.test(env));
37
+ });
38
+
39
+ await test('named tunnel: box.env carries GDS_BASE AND all four tunnel vars', () => {
40
+ const env = box.buildBoxEnv({
41
+ apiOrigin: 'https://cloudbongos.com',
42
+ namedTunnel: {
43
+ token: 'tok123', hostname: 'term-alice.example.com',
44
+ credential: 'cred456', previewHostname: 'sandbox-alice.example.com',
45
+ },
46
+ });
47
+ assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/gds$/m);
48
+ assert.match(env, /^BOX_TUNNEL_TOKEN=tok123$/m);
49
+ assert.match(env, /^BOX_TERMINAL_HOSTNAME=term-alice\.example\.com$/m);
50
+ assert.match(env, /^BOX_TERMINAL_CREDENTIAL=cred456$/m);
51
+ assert.match(env, /^BOX_PREVIEW_HOSTNAME=sandbox-alice\.example\.com$/m);
52
+ });
53
+
54
+ await test('every line is a clean KEY=VALUE (or a comment) — no leftover template gaps', () => {
55
+ const env = box.buildBoxEnv({
56
+ apiOrigin: 'https://cloudbongos.com',
57
+ namedTunnel: { token: 't', hostname: 'h', credential: 'c', previewHostname: 'p' },
58
+ });
59
+ for (const line of env.split('\n').filter(Boolean)) {
60
+ assert.ok(/^#/.test(line) || /^[A-Z_]+=\S+$/.test(line), `unexpected line shape: ${line}`);
61
+ }
62
+ });
63
+
64
+ summary();