@bongos/core 1.19.779 → 1.19.781
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/adr/0200-re-point-a-bring-your-own-domain.md +2 -0
- package/docs/module-api-changelog.md +4 -0
- package/modules/provisioning/routes/provisioning.js +6 -7
- package/modules/public-landing/public/projects.html +3 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/provision.js +2 -2
- package/src/module-api.js +1 -1
- package/tests/projects_hub_pre_uat.mjs +3 -0
- package/tests/provision.mjs +4 -0
- package/tests/provisioning_domain_attach.mjs +11 -2
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.781",
|
|
6
|
+
"core_contract": "1.19.781",
|
|
7
|
+
"source_commit": "d45eac660796500d874b2c6381eb9c07be462935",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-16T21:03:10.547Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 482,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2660,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "76c1ea968399be1d516e7abf97ecbd1b1fe812033d8ff2ddf81901b15c0aff15",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -1492,7 +1492,7 @@
|
|
|
1492
1492
|
{
|
|
1493
1493
|
"path": "docs/adr/0200-re-point-a-bring-your-own-domain.md",
|
|
1494
1494
|
"mode": "0000644",
|
|
1495
|
-
"sha256": "
|
|
1495
|
+
"sha256": "b2b9495e54389f959c30def7986121d386151371e6204f676dced1a2e25f0312"
|
|
1496
1496
|
},
|
|
1497
1497
|
{
|
|
1498
1498
|
"path": "docs/adr/0201-cross-project-application-vouched-row-live-record.md",
|
|
@@ -2507,7 +2507,7 @@
|
|
|
2507
2507
|
{
|
|
2508
2508
|
"path": "docs/module-api-changelog.md",
|
|
2509
2509
|
"mode": "0000644",
|
|
2510
|
-
"sha256": "
|
|
2510
|
+
"sha256": "cf5cab9a32c28dae4029b2d175cd06e6a45f33114c0203392f478e8ee5d7e34f"
|
|
2511
2511
|
},
|
|
2512
2512
|
{
|
|
2513
2513
|
"path": "docs/modules-contract.md",
|
|
@@ -6352,7 +6352,7 @@
|
|
|
6352
6352
|
{
|
|
6353
6353
|
"path": "modules/provisioning/routes/provisioning.js",
|
|
6354
6354
|
"mode": "0000644",
|
|
6355
|
-
"sha256": "
|
|
6355
|
+
"sha256": "616fa85cebc85241a1283b3493caaa2bb93a20b18ea6ea8e9b9fd0969f2ccc49"
|
|
6356
6356
|
},
|
|
6357
6357
|
{
|
|
6358
6358
|
"path": "modules/provisioning/starter-bundles.js",
|
|
@@ -6867,7 +6867,7 @@
|
|
|
6867
6867
|
{
|
|
6868
6868
|
"path": "modules/public-landing/public/projects.html",
|
|
6869
6869
|
"mode": "0000644",
|
|
6870
|
-
"sha256": "
|
|
6870
|
+
"sha256": "e187b9ed50a30d49ff5f40a91ddf8ff9879adfe6b62ee809115903e029c4bf18"
|
|
6871
6871
|
},
|
|
6872
6872
|
{
|
|
6873
6873
|
"path": "modules/public-landing/public/projects.probes.json",
|
|
@@ -7612,12 +7612,12 @@
|
|
|
7612
7612
|
{
|
|
7613
7613
|
"path": "package-lock.json",
|
|
7614
7614
|
"mode": "0000644",
|
|
7615
|
-
"sha256": "
|
|
7615
|
+
"sha256": "649f45c7edc727a1e32796caefe1848113a53872e435be1befbd23167e4a71a4"
|
|
7616
7616
|
},
|
|
7617
7617
|
{
|
|
7618
7618
|
"path": "package.json",
|
|
7619
7619
|
"mode": "0000644",
|
|
7620
|
-
"sha256": "
|
|
7620
|
+
"sha256": "71490018201c33eea331cb3aaa42d97bc024754b83b4b8d6622ec8aa736bdc30"
|
|
7621
7621
|
},
|
|
7622
7622
|
{
|
|
7623
7623
|
"path": "public-docs/index.html",
|
|
@@ -8502,7 +8502,7 @@
|
|
|
8502
8502
|
{
|
|
8503
8503
|
"path": "scripts/gds/provision.js",
|
|
8504
8504
|
"mode": "0000644",
|
|
8505
|
-
"sha256": "
|
|
8505
|
+
"sha256": "9744a8493b15537c1789f7270cf5d9679b5ecf40d685f5857e27b21f34ae8690"
|
|
8506
8506
|
},
|
|
8507
8507
|
{
|
|
8508
8508
|
"path": "scripts/gds/publish-credential-check.js",
|
|
@@ -9477,7 +9477,7 @@
|
|
|
9477
9477
|
{
|
|
9478
9478
|
"path": "src/module-api.js",
|
|
9479
9479
|
"mode": "0000644",
|
|
9480
|
-
"sha256": "
|
|
9480
|
+
"sha256": "ae9fcf83cce465b20cd9d5fc34f88c58decace92ebfaf3fd0f2d477d8b46bc16"
|
|
9481
9481
|
},
|
|
9482
9482
|
{
|
|
9483
9483
|
"path": "src/module-loader/catalog.js",
|
|
@@ -12137,7 +12137,7 @@
|
|
|
12137
12137
|
{
|
|
12138
12138
|
"path": "tests/projects_hub_pre_uat.mjs",
|
|
12139
12139
|
"mode": "0000644",
|
|
12140
|
-
"sha256": "
|
|
12140
|
+
"sha256": "5095bb2c890d89337c819fc3fc07fe26507f0bd78607b2b49239bccf23419aa3"
|
|
12141
12141
|
},
|
|
12142
12142
|
{
|
|
12143
12143
|
"path": "tests/promote_goal_id.mjs",
|
|
@@ -12157,7 +12157,7 @@
|
|
|
12157
12157
|
{
|
|
12158
12158
|
"path": "tests/provision.mjs",
|
|
12159
12159
|
"mode": "0000644",
|
|
12160
|
-
"sha256": "
|
|
12160
|
+
"sha256": "151d6a8b22f3d12b766a4ab1a0402c70e9b91c6a1d9f75f658b9d60937d652df"
|
|
12161
12161
|
},
|
|
12162
12162
|
{
|
|
12163
12163
|
"path": "tests/provision_disconnect.mjs",
|
|
@@ -12212,7 +12212,7 @@
|
|
|
12212
12212
|
{
|
|
12213
12213
|
"path": "tests/provisioning_domain_attach.mjs",
|
|
12214
12214
|
"mode": "0000644",
|
|
12215
|
-
"sha256": "
|
|
12215
|
+
"sha256": "8a5bc0b4b1ab854cb1c5dc2d8c4a1330f38c445455651e2de15b258938acc6ef"
|
|
12216
12216
|
},
|
|
12217
12217
|
{
|
|
12218
12218
|
"path": "tests/provisioning_domain_lookup_index.mjs",
|
|
@@ -48,6 +48,8 @@ Only a **BYO** address is ever queued, and only from a state that actually stood
|
|
|
48
48
|
|
|
49
49
|
The web tier decides both, because it is the tier that knows the apex and the lifecycle state.
|
|
50
50
|
|
|
51
|
+
> **Amendment (owner, 2026-09-16, task 1002902): the first exclusion is withdrawn.** An upgrade off the platform-assigned `<slug>.<apex>` now queues that name for release like any other address a project moves off; only the `requested` exclusion remains. The revive argument did not hold for this path. A revive re-uses the row's *current* address, which after an upgrade is the BYO name, not the assigned one. Teardown already parks whatever address the row holds (task 1002897). A project that moves back onto its assigned name re-UPSERTs it in the same attach, and `releasableDomains` never releases the address a row is on. Keeping the name meant leaving a record aimed at platform infra with no vhost behind it, which is the leak §2 exists to close. The route releases the row's own `current` value and never derives one, so a mis-derived name cannot park another project's record, and the squat rule keeps `<slug>.<apex>` usable only by that slug's own project. The manage card's "lets `<host>` go" line now shows on the upgrade too.
|
|
52
|
+
|
|
51
53
|
**The queue is capped (`MAX_RELEASED_DOMAINS`), and the route that fills it is throttled.** The runner drains this list **synchronously, one <redacted> call per entry**, and every re-point is a write an authenticated owner can repeat — `normalizeHostname` checks a hostname's *shape*, never that it exists. So an uncapped array is a resource-exhaustion vector against a **platform-wide** resource (the control plane's DNS token and rate limit, and the drain loop itself), not merely against the owner's own project. Two bounds, at different layers:
|
|
52
54
|
|
|
53
55
|
- **The cap is enforced in `updateInstanceDomain`'s own SQL**, not trusted from the caller: past the bound the append is dropped, keeping the entries most likely to name a hostname the platform really wired. Dropping is the deliberate failure mode; growing without bound is not.
|
|
@@ -2032,5 +2032,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2032
2032
|
landed since 1.19.777 with no explicit bump. run 35139523999. (task 1002620)
|
|
2033
2033
|
1.19.779 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2034
2034
|
landed since 1.19.778 with no explicit bump. run 35144678111. (task 1002620)
|
|
2035
|
+
1.19.780 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2036
|
+
landed since 1.19.779 with no explicit bump. run 35147229585. (task 1002620)
|
|
2037
|
+
1.19.781 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2038
|
+
landed since 1.19.780 with no explicit bump. run 35150109281. (task 1002620)
|
|
2035
2039
|
---------------------------------------------------------------------------
|
|
2036
2040
|
```
|
|
@@ -1162,13 +1162,12 @@ module.exports = function provisioningRoutes() {
|
|
|
1162
1162
|
// weaker rule and gets no stronger one. The address it moves OFF is queued
|
|
1163
1163
|
// for release (`releasing`): leaving a hostname UPSERTed at platform infra
|
|
1164
1164
|
// for a project that no longer answers there is the leak ADR 0181 §2 named.
|
|
1165
|
-
//
|
|
1166
|
-
//
|
|
1167
|
-
//
|
|
1168
|
-
// instance never had an A record written for the address it is
|
|
1169
|
-
// parking that name would CREATE a junk record rather than release one.
|
|
1170
|
-
const releasing = current && current
|
|
1171
|
-
&& provisioning.DOMAIN_RELEASE_FROM.has(inst.status) ? current : null;
|
|
1165
|
+
// That includes the platform-ASSIGNED <slug>.<apex> an upgrade leaves (task
|
|
1166
|
+
// 1002902, amending ADR 0200): moving back onto it re-UPSERTs it, and a revive
|
|
1167
|
+
// re-uses the row's CURRENT name. Only from a state that actually STOOD UP: a
|
|
1168
|
+
// 'requested' instance never had an A record written for the address it is
|
|
1169
|
+
// leaving — parking that name would CREATE a junk record rather than release one.
|
|
1170
|
+
const releasing = current && provisioning.DOMAIN_RELEASE_FROM.has(inst.status) ? current : null;
|
|
1172
1171
|
const holder = await provisioning.getInstanceByDomain(pool, domain);
|
|
1173
1172
|
if (holder && String(holder.id) !== String(inst.id)) return res.fail('domain_taken', { status: 409, message: 'That address is already in use by another instance.' });
|
|
1174
1173
|
if (!provisioning.DOMAIN_ATTACH_FROM.has(inst.status)) {
|
|
@@ -5721,7 +5721,9 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5721
5721
|
/* true in every state this renders in: a REQUESTED project never answered
|
|
5722
5722
|
anywhere yet, so "stops answering" would be a claim about a thing that
|
|
5723
5723
|
never happened (the F16 rule) */
|
|
5724
|
-
|
|
5724
|
+
/* the assigned <slug>.<apex> is let go too (task 1002902), so the upgrade says so */
|
|
5725
|
+
(!rekick && inst.domain ? '<p class="attachNote">' + (repoint ? 'Changing it' : 'Using a domain you own') +
|
|
5726
|
+
' lets <code>' + esc(inst.domain) + '</code> go — this project won’t use that address any more.</p>' : '') +
|
|
5725
5727
|
'<div class="projMsg' + (mDomNote && mDomNote.cls ? ' ' + mDomNote.cls : '') + '" id="mDomMsg" role="status" aria-live="polite">' +
|
|
5726
5728
|
(mDomNote ? mDomNote.html : '') + '</div>';
|
|
5727
5729
|
var field = $('mDomName');
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.781",
|
|
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.781",
|
|
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.781",
|
|
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/scripts/gds/provision.js
CHANGED
|
@@ -625,8 +625,8 @@ ${roleLines} - [ bash, -lc, "install -d -o ${APP_USER} -g ${APP_USER} -m 0750 $
|
|
|
625
625
|
// (task 1003237). The one guard this tier can make on its own, and the one that
|
|
626
626
|
// matters: the address the instance is CURRENTLY on is never released, so a row
|
|
627
627
|
// that somehow queued its own domain can never blackhole a live project.
|
|
628
|
-
//
|
|
629
|
-
//
|
|
628
|
+
// WHICH addresses reach the queue is the ENQUEUE site's job (the route's
|
|
629
|
+
// `releasing`, ADR 0200 as amended by task 1002902). PURE.
|
|
630
630
|
function releasableDomains(inst) {
|
|
631
631
|
const here = String((inst && inst.domain) || '').toLowerCase();
|
|
632
632
|
return (Array.isArray(inst && inst.released_domains) ? inst.released_domains : [])
|
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.781'; // 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');
|
|
@@ -393,6 +393,9 @@ test('the correction door: a bring-your-own address can be changed, and the sect
|
|
|
393
393
|
assert.match(fold, /repoint \? 'It answers on an address you brought\./, 'the lead names the correction');
|
|
394
394
|
assert.match(fold, /attachNote/, 'and the consequence is stated where the button is');
|
|
395
395
|
assert.match(fold, /won’t use that address any more/, 'letting the old address go is SAID, not discovered');
|
|
396
|
+
// task 1002902: the upgrade off the platform-assigned address lets that name go too
|
|
397
|
+
assert.match(fold, /\(!rekick && inst\.domain \? '<p class="attachNote">' \+ \(repoint \? 'Changing it' : 'Using a domain you own'\)/,
|
|
398
|
+
'the note shows for the assigned-address upgrade as well as a correction, and never on the F19 re-kick');
|
|
396
399
|
// the door itself: an addressed, live project is no longer excluded
|
|
397
400
|
const gate = fn('canAttachDomain');
|
|
398
401
|
assert.doesNotMatch(gate, /!inst\.domain \|\| inst\.domain === assignedDefaultFor\(inst\)/,
|
package/tests/provision.mjs
CHANGED
|
@@ -1963,6 +1963,10 @@ await ta('releasableDomains: the queue, minus the address the instance is CURREN
|
|
|
1963
1963
|
assert.deepEqual(P.releasableDomains({ domain: 'x.example.com' }), [], 'no queue is not a crash');
|
|
1964
1964
|
assert.deepEqual(P.releasableDomains({ domain: 'x.example.com', released_domains: ['a.example.com', '', 'b.example.com'] }),
|
|
1965
1965
|
['a.example.com', 'b.example.com'], 'every abandoned address is released, not just the last');
|
|
1966
|
+
// task 1002902: the route now queues the platform-assigned <slug>.<apex> an upgrade
|
|
1967
|
+
// leaves, so the runner must not second-guess an in-apex name the web tier queued.
|
|
1968
|
+
assert.deepEqual(P.releasableDomains({ domain: 'mine.example.com', released_domains: ['spike.cloudbongos.com'] }),
|
|
1969
|
+
['spike.cloudbongos.com'], 'an assigned address the project moved off is released like any other');
|
|
1966
1970
|
});
|
|
1967
1971
|
|
|
1968
1972
|
await ta('domainAttachInstance(--apply): a re-point parks the old address at the blackhole, AFTER wiring the new one', async () => {
|
|
@@ -323,11 +323,20 @@ await ta('a re-point onto an address ANOTHER project holds is a truthful 409 dom
|
|
|
323
323
|
assert.equal(updateCalls.length, 0);
|
|
324
324
|
});
|
|
325
325
|
|
|
326
|
-
await ta('moving OFF the platform-assigned <slug>.<apex>
|
|
326
|
+
await ta('moving OFF the platform-assigned <slug>.<apex> releases it too — nothing is left answering there (task 1002902)', async () => {
|
|
327
327
|
reset({ inst: { owner_builder_id: 7, slug: 'spike', status: 'active', domain: 'spike.cb.test' } });
|
|
328
328
|
const res = await post('/provisioning/instances/18/domain', { domain: 'mine.example.com' });
|
|
329
329
|
assert.equal(res.status, 200, res.raw);
|
|
330
|
-
assert.equal(res.body.replaced,
|
|
330
|
+
assert.equal(res.body.replaced, 'spike.cb.test', 'the upgrade names the assigned address it lets go');
|
|
331
|
+
assert.deepEqual(updateCalls, [{ id: 18, domain: 'mine.example.com', releasing: 'spike.cb.test' }]);
|
|
332
|
+
assert.match(res.body.message, /spike\.cb\.test is being let go/, 'and says so in the response');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
await ta('an upgrade off the assigned address on a REQUESTED instance still releases nothing — no record was ever written', async () => {
|
|
336
|
+
reset({ inst: { owner_builder_id: 7, slug: 'spike', status: 'requested', domain: 'spike.cb.test' } });
|
|
337
|
+
const res = await post('/provisioning/instances/18/domain', { domain: 'mine.example.com' });
|
|
338
|
+
assert.equal(res.status, 200, res.raw);
|
|
339
|
+
assert.equal(res.body.replaced, null);
|
|
331
340
|
assert.deepEqual(updateCalls, [{ id: 18, domain: 'mine.example.com', releasing: null }]);
|
|
332
341
|
});
|
|
333
342
|
|