@bongos/core 1.19.926 → 1.19.927
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 +12 -12
- package/docs/module-api-changelog.md +2 -0
- package/modules/provisioning/control-plane-guard.js +9 -1
- package/modules/provisioning/core-upgrade.js +11 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +1 -1
- package/tests/core_upgrade_door.mjs +55 -4
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.927",
|
|
6
|
+
"core_contract": "1.19.927",
|
|
7
|
+
"source_commit": "8a6b09d4e2f48071fe35cfa4147ffdb779753896",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-20T23:
|
|
9
|
+
"built_at": "2026-09-20T23:34:18.483Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 511,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2851,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "2c2b24754d790a0405bb73c8c5381d97a364f5c4a544b31d471df58b3458cf49",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2677,7 +2677,7 @@
|
|
|
2677
2677
|
{
|
|
2678
2678
|
"path": "docs/module-api-changelog.md",
|
|
2679
2679
|
"mode": "0000644",
|
|
2680
|
-
"sha256": "
|
|
2680
|
+
"sha256": "3bc7467a01b53a0d28388f5df4f6028fc71a764e8155280e754ff2b17edd5e4e"
|
|
2681
2681
|
},
|
|
2682
2682
|
{
|
|
2683
2683
|
"path": "docs/modules-contract.md",
|
|
@@ -6412,12 +6412,12 @@
|
|
|
6412
6412
|
{
|
|
6413
6413
|
"path": "modules/provisioning/control-plane-guard.js",
|
|
6414
6414
|
"mode": "0000644",
|
|
6415
|
-
"sha256": "
|
|
6415
|
+
"sha256": "e1d060477287884f878748da4c2b7cfe164c782538728ffc7efc473c8b6a4997"
|
|
6416
6416
|
},
|
|
6417
6417
|
{
|
|
6418
6418
|
"path": "modules/provisioning/core-upgrade.js",
|
|
6419
6419
|
"mode": "0000644",
|
|
6420
|
-
"sha256": "
|
|
6420
|
+
"sha256": "291a3765197f9429c70dd240fe5cdfa72a245ad3698c822032e71bb88999d533"
|
|
6421
6421
|
},
|
|
6422
6422
|
{
|
|
6423
6423
|
"path": "modules/provisioning/credential-preflight.js",
|
|
@@ -7922,12 +7922,12 @@
|
|
|
7922
7922
|
{
|
|
7923
7923
|
"path": "package-lock.json",
|
|
7924
7924
|
"mode": "0000644",
|
|
7925
|
-
"sha256": "
|
|
7925
|
+
"sha256": "52b5b2136a302b5f6f0d855f3b6b9b55db2412a60766c05f857a313e52cd451e"
|
|
7926
7926
|
},
|
|
7927
7927
|
{
|
|
7928
7928
|
"path": "package.json",
|
|
7929
7929
|
"mode": "0000644",
|
|
7930
|
-
"sha256": "
|
|
7930
|
+
"sha256": "33d35abf35aa8693f2b36cf95227a052986b760bd7de71eaee002c7d450f4eaa"
|
|
7931
7931
|
},
|
|
7932
7932
|
{
|
|
7933
7933
|
"path": "public-docs/index.html",
|
|
@@ -9927,7 +9927,7 @@
|
|
|
9927
9927
|
{
|
|
9928
9928
|
"path": "src/module-api.js",
|
|
9929
9929
|
"mode": "0000644",
|
|
9930
|
-
"sha256": "
|
|
9930
|
+
"sha256": "e0b786da5becfbcb6f79530193b0424db2c1164e26173f9218ff330d9aba079d"
|
|
9931
9931
|
},
|
|
9932
9932
|
{
|
|
9933
9933
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10837,7 +10837,7 @@
|
|
|
10837
10837
|
{
|
|
10838
10838
|
"path": "tests/core_upgrade_door.mjs",
|
|
10839
10839
|
"mode": "0000644",
|
|
10840
|
-
"sha256": "
|
|
10840
|
+
"sha256": "bb2a39d645141a15b7391580069bf05b6f812e40f20d10fd55dbc564eb8f00ec"
|
|
10841
10841
|
},
|
|
10842
10842
|
{
|
|
10843
10843
|
"path": "tests/core_upgrade_runner.mjs",
|
|
@@ -2326,5 +2326,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2326
2326
|
landed since 1.19.924 with no explicit bump. run 35542154729. (task 1002620)
|
|
2327
2327
|
1.19.926 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2328
2328
|
landed since 1.19.925 with no explicit bump. run 35543911646. (task 1002620)
|
|
2329
|
+
1.19.927 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2330
|
+
landed since 1.19.926 with no explicit bump. run 35545006099. (task 1002620)
|
|
2329
2331
|
---------------------------------------------------------------------------
|
|
2330
2332
|
```
|
|
@@ -30,10 +30,18 @@
|
|
|
30
30
|
// the door task 1003159 builds.
|
|
31
31
|
// restart — the liveness remedy (task 1003238). Restarting the platform is
|
|
32
32
|
// recoverable and already owner-initiated elsewhere.
|
|
33
|
+
// core-upgrade-preflight
|
|
34
|
+
// — `upgrade.js --dry-run`. It RUNS NOTHING: it returns at pre-flight
|
|
35
|
+
// before the pin moves, before npm, before any restart. Refusing it
|
|
36
|
+
// here protected the box from nothing and removed the feature from
|
|
37
|
+
// everyone, because the control plane is the ONLY instance that runs
|
|
38
|
+
// the provisioning module — so its hall is the only one with an
|
|
39
|
+
// Upgrade page at all. A preview that cannot run where the button
|
|
40
|
+
// lives is not a preview (task 1004125).
|
|
33
41
|
//
|
|
34
42
|
// Adding to this list is a deliberate edit someone has to argue for. It is pinned
|
|
35
43
|
// by name in tests/core_upgrade_door.mjs so it cannot grow as a side effect.
|
|
36
|
-
const CONTROL_PLANE_ACTIONS = Object.freeze(['core-upgrade', 'restart']);
|
|
44
|
+
const CONTROL_PLANE_ACTIONS = Object.freeze(['core-upgrade', 'core-upgrade-preflight', 'restart']);
|
|
37
45
|
|
|
38
46
|
/**
|
|
39
47
|
* May this intent action be aimed at an instance of this hosting shape? PURE.
|
|
@@ -209,6 +209,17 @@ function makeCoreUpgradeHandler({ provisioning, pool, parseId, validateOrRespond
|
|
|
209
209
|
});
|
|
210
210
|
} catch (err) {
|
|
211
211
|
log.error('[provisioning] POST /provisioning/instances/:id/core-upgrade', err);
|
|
212
|
+
// A REFUSAL IS NOT AN OUTAGE. The control-plane guard throws an error carrying
|
|
213
|
+
// `code`, `status` and a `publicMessage` it wrote for exactly this moment — and
|
|
214
|
+
// this catch used to discard all three, so every guard refusal reached the owner
|
|
215
|
+
// as a 500 "internal error" while the real sentence sat in the journal. Nothing
|
|
216
|
+
// in the repo honoured `publicMessage`; it was assigned once and read never
|
|
217
|
+
// (task 1004125). Only an error that has already declared itself public is
|
|
218
|
+
// forwarded — anything else still gets the opaque 500, because an unexpected
|
|
219
|
+
// throw may carry anything.
|
|
220
|
+
if (err && err.publicMessage && err.code && err.status) {
|
|
221
|
+
return res.fail(err.code, { status: err.status, message: err.publicMessage });
|
|
222
|
+
}
|
|
212
223
|
return res.fail('core_upgrade_failed', { status: 500, message: 'internal error' });
|
|
213
224
|
}
|
|
214
225
|
};
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.927",
|
|
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.927",
|
|
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.927",
|
|
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",
|
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.927'; // 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');
|
|
@@ -93,10 +93,29 @@ await t('every action not explicitly allowed is refused on the self row', () =>
|
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
await t('the allow-list is exactly the
|
|
96
|
+
await t('the allow-list is exactly the acts that cannot destroy the box', () => {
|
|
97
97
|
// Pinned by NAME so widening it is a deliberate edit someone has to argue for,
|
|
98
|
-
// not a side effect of adding an action to INTENT_ACTIONS.
|
|
99
|
-
|
|
98
|
+
// not a side effect of adding an action to INTENT_ACTIONS. It did its job: adding
|
|
99
|
+
// 'core-upgrade-preflight' to INTENT_ACTIONS in task 1004121 did NOT reach here, and
|
|
100
|
+
// this line is what forced the argument to be made (task 1004125). The argument: a
|
|
101
|
+
// dry run returns at pre-flight having moved no pin, run no npm and restarted
|
|
102
|
+
// nothing, and the control plane is the only instance whose hall HAS an Upgrade
|
|
103
|
+
// page — so refusing the preview there protected nothing and removed everything.
|
|
104
|
+
assert.deepEqual([...G.CONTROL_PLANE_ACTIONS].sort(),
|
|
105
|
+
['core-upgrade', 'core-upgrade-preflight', 'restart']);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await t('the preview is permitted on the control plane — the one row that can use it', () => {
|
|
109
|
+
assert.equal(G.intentAllowedForShape('core-upgrade-preflight', 'control-plane'), true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await t('and widening it did NOT let the destructive acts through', () => {
|
|
113
|
+
// The whole risk of arguing one action onto an allow-list is arguing four.
|
|
114
|
+
for (const a of P.INTENT_ACTIONS) {
|
|
115
|
+
if (['core-upgrade', 'core-upgrade-preflight', 'restart'].includes(a)) continue;
|
|
116
|
+
assert.equal(G.intentAllowedForShape(a, 'control-plane'), false,
|
|
117
|
+
`'${a}' must still be refused against the box the platform runs on`);
|
|
118
|
+
}
|
|
100
119
|
});
|
|
101
120
|
|
|
102
121
|
await t('an ordinary instance is untouched by the guard', () => {
|
|
@@ -489,7 +508,7 @@ const validatorHarness = () => {
|
|
|
489
508
|
fail: (code, o) => { body = { code, ...(typeof o === 'object' ? o : { status: o }) }; status = (o && o.status) || o || 400; return res; },
|
|
490
509
|
status: (c) => { status = c; return res; },
|
|
491
510
|
};
|
|
492
|
-
return { calls, handler, res, read: () => ({ body, status }) };
|
|
511
|
+
return { calls, handler, res, provisioning, read: () => ({ body, status }) };
|
|
493
512
|
};
|
|
494
513
|
|
|
495
514
|
await t('the preview payload the page posts is ACCEPTED, not refused as an unknown field', async () => {
|
|
@@ -503,6 +522,38 @@ await t('the preview payload the page posts is ACCEPTED, not refused as an unkno
|
|
|
503
522
|
assert.ok(queued, 'and it reaches the queue as a PREVIEW, not as a move');
|
|
504
523
|
});
|
|
505
524
|
|
|
525
|
+
await t('a guard refusal reaches the owner as ITS OWN sentence, not "internal error"', async () => {
|
|
526
|
+
// The guard writes `code`, `status: 409` and a publicMessage for exactly this moment.
|
|
527
|
+
// The catch discarded all three, so every control-plane refusal this route ever made
|
|
528
|
+
// was shown as a 500 "internal error" while the real sentence sat in the journal —
|
|
529
|
+
// which is how the preview refusal stayed invisible until it was pressed live.
|
|
530
|
+
// Elsewhere in this file we already assert that sentence is well-formed; nothing
|
|
531
|
+
// asserted it ARRIVED.
|
|
532
|
+
const h = validatorHarness();
|
|
533
|
+
const refusal = Object.assign(new Error('blocked'), {
|
|
534
|
+
code: 'control_plane_protected', status: 409,
|
|
535
|
+
publicMessage: 'That action cannot be aimed at the machine the platform itself runs on.',
|
|
536
|
+
});
|
|
537
|
+
h.provisioning.enqueueIntent = async () => { throw refusal; };
|
|
538
|
+
await h.handler({ builder: { id: 42 }, params: { id: '7' }, body: { to: '1.19.926' } }, h.res);
|
|
539
|
+
const { body } = h.read();
|
|
540
|
+
assert.equal(body && body.code, 'control_plane_protected', 'the guard\'s own code, not core_upgrade_failed');
|
|
541
|
+
assert.equal(body && body.status, 409, 'a refusal is not a 500');
|
|
542
|
+
assert.match((body && body.message) || '', /cannot be aimed at the machine/);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
await t('an UNEXPECTED throw is still opaque — this is not a blanket error passthrough', async () => {
|
|
546
|
+
// Forwarding every error would leak internals. Only an error that declared itself
|
|
547
|
+
// public (code + status + publicMessage) is forwarded.
|
|
548
|
+
const h = validatorHarness();
|
|
549
|
+
h.provisioning.enqueueIntent = async () => { throw new Error('connection terminated: relation "secrets" does not exist'); };
|
|
550
|
+
await h.handler({ builder: { id: 42 }, params: { id: '7' }, body: { to: '1.19.926' } }, h.res);
|
|
551
|
+
const { body } = h.read();
|
|
552
|
+
assert.equal(body && body.code, 'core_upgrade_failed');
|
|
553
|
+
assert.equal(body && body.message, 'internal error');
|
|
554
|
+
assert.ok(!/secrets|relation/.test(JSON.stringify(body)), 'no internals reach the client');
|
|
555
|
+
});
|
|
556
|
+
|
|
506
557
|
await t('the move payload still validates, and still queues a move', async () => {
|
|
507
558
|
const h = validatorHarness();
|
|
508
559
|
await h.handler({ builder: { id: 42 }, params: { id: '7' }, body: { to: '1.19.925' } }, h.res);
|