@bongos/core 1.19.1034 → 1.19.1036
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 +88 -68
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +6 -0
- package/clients/bongos-client/index.cjs +6 -0
- package/clients/bongos-client/index.d.ts +9 -1
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/adr/0339-a-projects-owner-upgrades-it-and-a-hosted-project-hands-off-to-the-hub-door.md +84 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +126 -8
- package/docs/api-reference.md +9 -2
- package/docs/copy-inventory.md +10 -10
- package/docs/copy-registry.json +13 -13
- package/docs/module-api-changelog.md +4 -0
- package/modules/autonomy/db.js +19 -0
- package/modules/autonomy/routes/autonomy.js +28 -0
- package/modules/government/catalog.js +2 -2
- package/modules/hall-ui/public/atlas.html +1 -1
- package/modules/hall-ui/public/blockers.html +1 -1
- package/modules/hall-ui/public/board-room.html +1 -1
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/copy-desk.html +1 -1
- package/modules/hall-ui/public/deploy.html +1 -1
- package/modules/hall-ui/public/diagrams.html +1 -1
- package/modules/hall-ui/public/drachmae.html +1 -1
- package/modules/hall-ui/public/fleet.html +1 -1
- package/modules/hall-ui/public/gate.html +1 -1
- package/modules/hall-ui/public/goals.html +1 -1
- package/modules/hall-ui/public/government.html +1 -1
- package/modules/hall-ui/public/idea.html +1 -1
- package/modules/hall-ui/public/ideas.html +1 -1
- package/modules/hall-ui/public/index.html +1 -1
- package/modules/hall-ui/public/modules.html +1 -1
- package/modules/hall-ui/public/people.html +1 -1
- package/modules/hall-ui/public/primer.html +1 -1
- package/modules/hall-ui/public/profile.html +1 -1
- package/modules/hall-ui/public/project-settings.html +1 -1
- package/modules/hall-ui/public/ranks.html +1 -1
- package/modules/hall-ui/public/roadmap.html +1 -1
- package/modules/hall-ui/public/roster.html +1 -1
- package/modules/hall-ui/public/sessions.html +1 -1
- package/modules/hall-ui/public/settings.html +1 -1
- package/modules/hall-ui/public/shell.js +36 -5
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/task.html +1 -1
- package/modules/hall-ui/public/watch.html +1 -1
- package/modules/hall-ui/public/work.html +1 -1
- package/modules/lifecycle/ship-assurance.js +17 -1
- package/modules/provisioning/core-upgrade-authz.js +85 -0
- package/modules/provisioning/core-upgrade.js +2 -1
- package/modules/provisioning/provisioning.js +4 -4
- package/modules/provisioning/routes/core-upgrade.js +12 -6
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +20 -0
- package/scripts/gds/provision-core-upgrade.js +12 -4
- package/src/bongos/auth.js +8 -2
- package/src/bongos/core-update.js +23 -1
- package/src/bongos/routes/core-update.js +51 -4
- package/src/module-api.js +1 -1
- package/tests/core_upgrade_owner_door.mjs +444 -0
- package/tests/nav_permission_atoms.mjs +1 -1
- package/tests/provisioning_teardown_intent.mjs +28 -2
- package/tests/routine_observability_api.mjs +195 -0
- package/tests/scouting_page_gate.mjs +11 -3
- package/tests/ship_assurance.mjs +86 -3
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1036",
|
|
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.1036",
|
|
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.1036",
|
|
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/release-notes.json
CHANGED
|
@@ -7477,5 +7477,25 @@
|
|
|
7477
7477
|
"id": "1004288",
|
|
7478
7478
|
"text": "The setup instructions an AI assistant follows on a fresh copy of a project no longer claim the core package is private, so a real download failure is no longer mistaken for normal."
|
|
7479
7479
|
}
|
|
7480
|
+
],
|
|
7481
|
+
"1.19.1035": [
|
|
7482
|
+
{
|
|
7483
|
+
"id": "1004275",
|
|
7484
|
+
"text": "Marking a task shipped by hand now recognises work that already reached the project through its own merged request, instead of refusing it and making the builder wait for the automatic check minutes later."
|
|
7485
|
+
},
|
|
7486
|
+
{
|
|
7487
|
+
"id": "1002669",
|
|
7488
|
+
"text": "The owner can now check from their own laptop what the automatic background jobs decided and when the project's core software was last upgraded, instead of logging into the server to find out."
|
|
7489
|
+
}
|
|
7490
|
+
],
|
|
7491
|
+
"1.19.1036": [
|
|
7492
|
+
{
|
|
7493
|
+
"id": "1004286",
|
|
7494
|
+
"text": "Pressing delete on the platform's own server is still refused, and now it no longer quietly cancels a restart you had already asked for."
|
|
7495
|
+
},
|
|
7496
|
+
{
|
|
7497
|
+
"id": "1004174",
|
|
7498
|
+
"text": "The owner of a hosted project can now upgrade it themselves: the \"you're behind\" banner on their project links to the Deploy page on the hub, which lets a project's owner move their own project, and only their own."
|
|
7499
|
+
}
|
|
7480
7500
|
]
|
|
7481
7501
|
}
|
|
@@ -140,6 +140,16 @@ function targetFault(to, available, installed, channel, channelAllows) {
|
|
|
140
140
|
return null;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
// The builder id a queued move is attributed to, from the actor the web tier recorded.
|
|
144
|
+
// PURE. Two doors reach the move (ADR 0339): an Archon (`api:archon:<id>`) and, since
|
|
145
|
+
// task 1004174, the project's own owner (`api:owner:<id>`). Both carry the id, because
|
|
146
|
+
// it becomes `--requested-by` on the core_upgrades ledger (ADR 0293 D5). Anything else
|
|
147
|
+
// yields '' — the id is interpolated into a shell command, so only digits ever pass.
|
|
148
|
+
function requestedByOf(intent) {
|
|
149
|
+
const m = intent && typeof intent.requested_by === 'string' && /^api:(?:archon|owner):(\d+)$/.exec(intent.requested_by);
|
|
150
|
+
return m ? m[1] : '';
|
|
151
|
+
}
|
|
152
|
+
|
|
143
153
|
/**
|
|
144
154
|
* Perform a queued core-pin move. Returns { ok } — NEVER throws for an expected refusal.
|
|
145
155
|
*
|
|
@@ -224,9 +234,7 @@ async function coreUpgradeInstance(inst, deps, intent) {
|
|
|
224
234
|
// it the pin lives only in the working tree, and the next pull-deploy resets it away —
|
|
225
235
|
// the silent thirteen-release revert upgrade.js's own header records.
|
|
226
236
|
const versionUrl = `http://127.0.0.1:${inst.port}/version`;
|
|
227
|
-
const requestedBy =
|
|
228
|
-
? intent.requested_by.replace(/^api:archon:/, '')
|
|
229
|
-
: '';
|
|
237
|
+
const requestedBy = requestedByOf(intent);
|
|
230
238
|
// Built by the SAME function the preview uses, so "what you were shown" and "what runs"
|
|
231
239
|
// cannot drift apart into two hand-maintained flag lists (task 1004121).
|
|
232
240
|
// The preview probes; the move must probe identically or the two commands diverge on
|
|
@@ -982,4 +990,4 @@ async function snapshotAllCoreVersions(deps) {
|
|
|
982
990
|
return { seen };
|
|
983
991
|
}
|
|
984
992
|
|
|
985
|
-
module.exports = { UPGRADE_SHAPES, CHANGE_CAP, REPO_NOTES, repoNote, parseChangeRecords, readInstalledNotes, readPackagedNotes, changesBetween, coreCheckoutCandidates, findCoreCheckout, gitFault, resolveRunAs, versionCmd, parseServedVersion, parseSchemaPending, targetFault, parsePreflight, upgradeInvocation, preflightUpgrade, preflightCoreUpgrade, coreUpgradeInstance, snapshotCoreVersions, snapshotAllCoreVersions };
|
|
993
|
+
module.exports = { UPGRADE_SHAPES, CHANGE_CAP, REPO_NOTES, repoNote, requestedByOf, parseChangeRecords, readInstalledNotes, readPackagedNotes, changesBetween, coreCheckoutCandidates, findCoreCheckout, gitFault, resolveRunAs, versionCmd, parseServedVersion, parseSchemaPending, targetFault, parsePreflight, upgradeInvocation, preflightUpgrade, preflightCoreUpgrade, coreUpgradeInstance, snapshotCoreVersions, snapshotAllCoreVersions };
|
package/src/bongos/auth.js
CHANGED
|
@@ -461,7 +461,13 @@ const PAGE_GATES = Object.freeze({
|
|
|
461
461
|
// preview discloses the exact core version the box serves and how far behind it is
|
|
462
462
|
// — a vulnerability window, and exactly the kind of topology ADR 0043 keeps off
|
|
463
463
|
// unauthenticated surfaces.
|
|
464
|
-
|
|
464
|
+
//
|
|
465
|
+
// SINCE ADR 0339 (task 1004174) its routes admit a SECOND audience — a hosted
|
|
466
|
+
// project's own owner, for that project only — so the shell follows through the same
|
|
467
|
+
// `alsoAdmits` door /people uses (ADR 0210). It admits the SHELL for an owner of any
|
|
468
|
+
// live project; which project they may read or move is still the routes' question,
|
|
469
|
+
// asked per request against that project's row.
|
|
470
|
+
requireCorePinPage: Object.freeze({ permission: 'core.pin.move', deniedTo: '/builders', alsoAdmits: 'isProjectOwner' }),
|
|
465
471
|
// The /fleet cost page (task 1001949) — on `provisioning.fleet.manage`, the SAME atom
|
|
466
472
|
// its one read (GET /provisioning/fleet/cost-ledger) checks: every owner's projects
|
|
467
473
|
// and what they cost, so the page reaches exactly as far as the data does.
|
|
@@ -469,7 +475,7 @@ const PAGE_GATES = Object.freeze({
|
|
|
469
475
|
});
|
|
470
476
|
|
|
471
477
|
// The `alsoAdmits` door — "is this visitor the page's OTHER audience?", asked of
|
|
472
|
-
// the module that owns the answer, only for
|
|
478
|
+
// the module that owns the answer, only for a gate that declares one.
|
|
473
479
|
//
|
|
474
480
|
// FAIL-CLOSED, EVERY WAY IT CAN FAIL: a gate with no `alsoAdmits`, a hub module
|
|
475
481
|
// that is off (every non-hub instance), a port that never grew the function, or a
|
|
@@ -144,4 +144,26 @@ async function readCoreUpdate({ running, channel, get, ...deps } = {}) {
|
|
|
144
144
|
return coreUpdateVerdict({ running, available: r.ok ? r.versions : [], channel });
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
// readCoreUpgrades — the instance's own core-upgrade ledger, newest first: when the
|
|
148
|
+
// core pin last moved, from which version to which, and who or what moved it (task
|
|
149
|
+
// 1002669). `core_upgrades` is written by `bongos upgrade` on every successful move and
|
|
150
|
+
// rollback (scripts/gds/upgrade.js), including the unattended patch sweep's, and no
|
|
151
|
+
// route read it — so "when did the pin last move" needed an SSH session. The pool is
|
|
152
|
+
// injectable so the test runs with no database; the default is the instance's own.
|
|
153
|
+
async function readCoreUpgrades({ limit = 20, pool = null } = {}) {
|
|
154
|
+
const db = pool || require('./pool').pool;
|
|
155
|
+
const { rows } = await db.query(
|
|
156
|
+
`SELECT id, from_version, to_version, source_commit, note, applied_at, source, requested_by_builder_id
|
|
157
|
+
FROM core_upgrades
|
|
158
|
+
ORDER BY applied_at DESC, id DESC
|
|
159
|
+
LIMIT $1`,
|
|
160
|
+
[limit]
|
|
161
|
+
);
|
|
162
|
+
return rows.map((r) => ({
|
|
163
|
+
...r,
|
|
164
|
+
id: String(r.id),
|
|
165
|
+
requested_by_builder_id: r.requested_by_builder_id == null ? null : String(r.requested_by_builder_id),
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = { readCoreUpdate, readCoreUpgrades };
|
|
@@ -21,9 +21,35 @@
|
|
|
21
21
|
const express = require('express');
|
|
22
22
|
const { asyncHandler } = require('./_helpers');
|
|
23
23
|
const auth = require('../auth');
|
|
24
|
-
const { readCoreUpdate } = require('../core-update');
|
|
24
|
+
const { readCoreUpdate, readCoreUpgrades } = require('../core-update');
|
|
25
|
+
const { loadIdpConfig } = require('../auth-config');
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
// WHERE A HOSTED PROJECT'S OWNER TAKES THE UPGRADE (task 1004174, ADR 0339): the hub's
|
|
28
|
+
// own deploy door, scoped to this project — `<hub>/deploy?project=<slug>`. The act stays
|
|
29
|
+
// on the control plane (ADR 0293 D1); this instance only names the address, so it gains
|
|
30
|
+
// no capability. Both halves are already here on a federated project: provisioning
|
|
31
|
+
// writes the hub origin and this project's hub client id, which IS its slug (ADR 0246),
|
|
32
|
+
// into web.env. null when this instance is not federated with a hub — a self-hosted
|
|
33
|
+
// instance, or the hub itself — so the hall offers no link rather than a wrong one.
|
|
34
|
+
// Only the origin and the client id are read; the client secret never leaves auth-config.
|
|
35
|
+
function hubDeployUrl(config) {
|
|
36
|
+
if (!config || typeof config.origin !== 'string' || !config.clientId) return null;
|
|
37
|
+
if (!/^https?:\/\/[^\s"'<>]+$/i.test(config.origin)) return null;
|
|
38
|
+
return `${config.origin.replace(/\/+$/, '')}/deploy?project=${encodeURIComponent(String(config.clientId))}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function safeIdpConfig() {
|
|
42
|
+
try { return loadIdpConfig(); } catch { return null; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ?limit for GET /core-upgrades: an integer 1..100, else 20.
|
|
46
|
+
function upgradesLimit(raw) {
|
|
47
|
+
const n = Number.parseInt(String(raw ?? ''), 10);
|
|
48
|
+
if (!Number.isFinite(n)) return 20;
|
|
49
|
+
return Math.min(100, Math.max(1, n));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function buildCoreUpdateRouter({ upgrades = readCoreUpgrades } = {}) {
|
|
27
53
|
const router = express.Router();
|
|
28
54
|
|
|
29
55
|
router.get(
|
|
@@ -41,9 +67,30 @@ module.exports = function buildCoreUpdateRouter() {
|
|
|
41
67
|
// that cannot name its own core reports `no_answer` and renders no banner.
|
|
42
68
|
let running = null;
|
|
43
69
|
try { running = require('../../module-api').CORE_VERSION; } catch { /* version unknown */ }
|
|
44
|
-
res.json({ ok: true, update: await readCoreUpdate({ running }) });
|
|
70
|
+
res.json({ ok: true, update: await readCoreUpdate({ running }), deploy_url: hubDeployUrl(safeIdpConfig()) });
|
|
45
71
|
}, { errorCode: 'core_update_failed', message: false }),
|
|
46
72
|
);
|
|
47
73
|
|
|
74
|
+
// GET /core-upgrades — the instance's own core-upgrade ledger, newest first: when
|
|
75
|
+
// the pin last moved, from and to which version, and whether a person or the
|
|
76
|
+
// unattended sweep moved it (task 1002669). READ-ONLY. Gated on the SAME atom as
|
|
77
|
+
// /core-update above and the deploy door, for the same first reason: it names the
|
|
78
|
+
// exact core this box has run and when, which is a vulnerability-window disclosure
|
|
79
|
+
// (ADR 0043). No new atom, so no migration. ?limit=1..100 (default 20).
|
|
80
|
+
router.get(
|
|
81
|
+
'/core-upgrades',
|
|
82
|
+
auth.requireBuilder,
|
|
83
|
+
auth.requirePermission('core.pin.move'),
|
|
84
|
+
asyncHandler('GET /core-upgrades', async (req, res) => {
|
|
85
|
+
let running = null;
|
|
86
|
+
try { running = require('../../module-api').CORE_VERSION; } catch { /* version unknown */ }
|
|
87
|
+
const limit = upgradesLimit(req.query.limit);
|
|
88
|
+
res.json({ ok: true, running, limit, upgrades: await upgrades({ limit }) });
|
|
89
|
+
}, { errorCode: 'core_upgrades_unreadable', message: false }),
|
|
90
|
+
);
|
|
91
|
+
|
|
48
92
|
return router;
|
|
49
|
-
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = buildCoreUpdateRouter;
|
|
96
|
+
module.exports.hubDeployUrl = hubDeployUrl;
|
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.1036'; // 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');
|