@bongos/core 1.19.331 → 1.19.333
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 +163 -43
- package/docs/api/openapi.json +2 -2
- package/docs/api-reference.md +1 -1
- package/docs/copy-inventory.md +202 -202
- package/docs/copy-registry.json +384 -384
- package/modules/grading/grader-config.js +98 -0
- package/modules/grading/grader-model.js +150 -0
- package/modules/grading/grader-prompt.js +139 -0
- package/modules/grading/grader-score.js +706 -0
- package/modules/grading/grader-subagent.js +328 -0
- package/modules/grading/grader.js +5 -1287
- package/modules/hall-ui/public/builders.js +19 -1182
- package/modules/hall-ui/public/goals-page.js +11 -997
- package/modules/hall-ui/public/goals-render.js +1032 -0
- package/modules/hall-ui/public/goals.html +4 -0
- package/modules/hall-ui/public/hall-render.js +1211 -0
- package/modules/hall-ui/public/index.html +6 -0
- package/modules/lifecycle/routes/goal-route-authz.js +400 -0
- package/modules/lifecycle/routes/goals.js +1 -367
- package/modules/lifecycle/routes/task-route-helpers.js +219 -0
- package/modules/lifecycle/routes/task-write-routes.js +542 -0
- package/modules/lifecycle/routes/tasks.js +3 -696
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +4 -0
- package/public-landing/projects.html +103 -23
- package/scripts/gds/box-infra.js +280 -0
- package/scripts/gds/box.js +1 -245
- package/scripts/gds/fitness-checks-identity.js +320 -0
- package/scripts/gds/fitness-checks-vocabulary.js +230 -0
- package/scripts/gds/fitness-checks-write-validation.js +144 -0
- package/scripts/gds/fitness-lib.js +82 -0
- package/scripts/gds/fitness.js +55 -668
- package/scripts/gds/provision-config.js +204 -0
- package/scripts/gds/provision-net.js +221 -0
- package/scripts/gds/provision-repo.js +849 -0
- package/scripts/gds/provision-units.js +262 -0
- package/scripts/gds/provision.js +4 -1395
- package/src/bongos/auth-admission.js +264 -0
- package/src/bongos/auth-config.js +151 -0
- package/src/bongos/auth-discord.js +198 -0
- package/src/bongos/auth-github.js +336 -0
- package/src/bongos/auth-idp.js +330 -0
- package/src/bongos/auth.js +5 -1100
- package/src/module-api.js +5 -1
- package/tests/auth_admission_gate.mjs +3 -1
- package/tests/est_advisory.mjs +3 -1
- package/tests/goal_advisory.mjs +3 -2
- package/tests/goal_criterion_confirm_ui.mjs +6 -0
- package/tests/goal_subtitle.mjs +5 -2
- package/tests/goals_card_view.mjs +10 -3
- package/tests/grader_generated_provenance.mjs +3 -1
- package/tests/hall_palette.mjs +3 -1
- package/tests/helpers.mjs +58 -25
- package/tests/lib_sh_resolution.mjs +3 -1
- package/tests/membership_kind_lockstep.mjs +3 -1
- package/tests/migration_allocation.mjs +5 -2
- package/tests/patch_gate_ordering.mjs +3 -1
- package/tests/projects_hub_pre_uat.mjs +53 -0
- package/tests/rank_tier_single_source.mjs +16 -3
- package/tests/reward_gate.mjs +3 -2
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// scripts/gds/provision-units.js — the systemd + environment templates: the
|
|
2
|
+
// instance service unit, the db-backup service and timer, and the web.env body.
|
|
3
|
+
//
|
|
4
|
+
// Carved out of scripts/gds/provision.js by task 1003206 (goal 1000079, the R03
|
|
5
|
+
// de-monolith plan) to bring the control-plane CLI under the 1,500-line ratchet.
|
|
6
|
+
// A STRUCTURAL move: bodies unchanged, provision.js requires every name back, so
|
|
7
|
+
// the intent runner and its unit templates behave exactly as before.
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('node:fs');
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
const { CONFIG, REPO_ROOT } = require('./provision-config.js');
|
|
14
|
+
const { APP_USER, CORE_PKG_DIR, dbName, parseTargetRef, standaloneRoot } = require('./provision-repo.js');
|
|
15
|
+
|
|
16
|
+
function serviceUnit(inst, { etcBase = CONFIG.etcBase } = {}) {
|
|
17
|
+
const envFile = path.posix.join(etcBase, inst.slug, 'web.env');
|
|
18
|
+
const standalone = inst.hosting_shape === 'standalone';
|
|
19
|
+
const workDir = standalone ? standaloneRoot(inst) : REPO_ROOT;
|
|
20
|
+
const execStart = standalone
|
|
21
|
+
? `/usr/bin/node ${CORE_PKG_DIR}/src/platform-server.js`
|
|
22
|
+
: `/usr/bin/node src/platform-server.js`;
|
|
23
|
+
return `[Unit]
|
|
24
|
+
Description=Cloud Bongos instance — ${inst.slug} (provisioned by provision.js, ADR 0111)
|
|
25
|
+
After=network-online.target postgresql.service
|
|
26
|
+
Wants=network-online.target
|
|
27
|
+
Requires=postgresql.service
|
|
28
|
+
|
|
29
|
+
[Service]
|
|
30
|
+
Type=simple
|
|
31
|
+
User=lars
|
|
32
|
+
Group=lars
|
|
33
|
+
WorkingDirectory=${workDir}
|
|
34
|
+
EnvironmentFile=${envFile}
|
|
35
|
+
Environment=PGDATABASE=${dbName(inst)}
|
|
36
|
+
Environment=PORT=${inst.port}
|
|
37
|
+
ExecStart=${execStart}
|
|
38
|
+
Restart=always
|
|
39
|
+
RestartSec=3
|
|
40
|
+
StandardOutput=journal
|
|
41
|
+
StandardError=journal
|
|
42
|
+
NoNewPrivileges=true
|
|
43
|
+
|
|
44
|
+
[Install]
|
|
45
|
+
WantedBy=multi-user.target
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
function serviceUnitPath(inst) { return `/etc/systemd/system/${inst.slug}.service`; }
|
|
49
|
+
|
|
50
|
+
// ── nightly DB backup: per-instance timer + service (task 2213) ─────────────
|
|
51
|
+
// PRODUCTIZES the manual task-2210 fix: a newly-provisioned instance was born with
|
|
52
|
+
// NO backups (dir absent, GDS_BACKUP_DB unset → the script fell back to the
|
|
53
|
+
// nonexistent `amazonprimea` default, and the repo's global gds-db-backup units
|
|
54
|
+
// hardcode /home/lars/amazonprimea — wrong for the consumer node_modules/@bongos/
|
|
55
|
+
// core layout). These generators emit a PER-INSTANCE unit pair that fixes all three:
|
|
56
|
+
// • name → `<slug>-db-backup.{service,timer}` so co-tenant instances on one box
|
|
57
|
+
// never collide (each dumps its OWN db; the script's retention prune is
|
|
58
|
+
// already `<db>-*.sql.gz`-scoped, so a shared backupDir is safe).
|
|
59
|
+
// • DB → Environment=GDS_BACKUP_DB=<instance db>, set on the unit (not read from
|
|
60
|
+
// the web.env) so the dump targets the right database with no fallback.
|
|
61
|
+
// • path → ExecStart resolves the canonical script INSIDE the instance's pinned
|
|
62
|
+
// @bongos/core (standalone) or this control-plane checkout (co-tenant),
|
|
63
|
+
// the SAME workDir/CORE_PKG_DIR split serviceUnit uses — never the old
|
|
64
|
+
// monorepo path.
|
|
65
|
+
function backupUnitName(inst) { return `${inst.slug}-db-backup`; }
|
|
66
|
+
function backupServicePath(inst) { return `/etc/systemd/system/${backupUnitName(inst)}.service`; }
|
|
67
|
+
function backupTimerPath(inst) { return `/etc/systemd/system/${backupUnitName(inst)}.timer`; }
|
|
68
|
+
// The consumer-layout-correct absolute path to db-backup-nightly.sh. Standalone runs
|
|
69
|
+
// it from the instance's own pinned core; co-tenant/dedicated from this checkout's
|
|
70
|
+
// scripts/gds/ — mirrors serviceUnit's execStart resolution so they can't diverge.
|
|
71
|
+
function backupScriptPath(inst) {
|
|
72
|
+
const rel = 'scripts/gds/db-backup-nightly.sh';
|
|
73
|
+
return inst.hosting_shape === 'standalone'
|
|
74
|
+
? path.posix.join(standaloneRoot(inst), CORE_PKG_DIR, rel)
|
|
75
|
+
: path.posix.join(REPO_ROOT, rel);
|
|
76
|
+
}
|
|
77
|
+
function backupService(inst, { backupDir = CONFIG.backupDir } = {}) {
|
|
78
|
+
return `[Unit]
|
|
79
|
+
Description=Nightly pg_dump of the ${inst.slug} GDS DB (provisioned by provision.js, task 2213)
|
|
80
|
+
After=postgresql.service
|
|
81
|
+
Requires=postgresql.service
|
|
82
|
+
|
|
83
|
+
[Service]
|
|
84
|
+
Type=oneshot
|
|
85
|
+
User=${APP_USER}
|
|
86
|
+
Group=${APP_USER}
|
|
87
|
+
# The DB to dump + where dumps land — set on the unit (not via the instance web.env)
|
|
88
|
+
# so the dump targets the right database with no fallback to a stale default (root
|
|
89
|
+
# cause of the task-2210 breakage). db-backup-nightly.sh reads both as env.
|
|
90
|
+
Environment=GDS_BACKUP_DB=${dbName(inst)}
|
|
91
|
+
Environment=GDS_BACKUP_DIR=${backupDir}
|
|
92
|
+
# Consumer-layout path: the canonical script inside this instance's pinned core.
|
|
93
|
+
ExecStart=/bin/bash ${backupScriptPath(inst)}
|
|
94
|
+
# Modest hardening — the script only needs read on the pg socket + write on the
|
|
95
|
+
# backup dir. Mirrors the repo's gds-db-backup.service.
|
|
96
|
+
NoNewPrivileges=true
|
|
97
|
+
ProtectSystem=strict
|
|
98
|
+
ReadWritePaths=${backupDir}
|
|
99
|
+
ProtectHome=read-only
|
|
100
|
+
PrivateTmp=true
|
|
101
|
+
|
|
102
|
+
[Install]
|
|
103
|
+
# Not socket-activated; the timer drives this. The timer's WantedBy is what enables.
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
function backupTimer(inst) {
|
|
107
|
+
return `[Unit]
|
|
108
|
+
Description=Daily timer for the ${inst.slug} GDS DB pg_dump (provisioned by provision.js, task 2213)
|
|
109
|
+
|
|
110
|
+
[Timer]
|
|
111
|
+
# 04:00 UTC daily, mirroring the repo's gds-db-backup.timer (low-traffic window).
|
|
112
|
+
OnCalendar=*-*-* 04:00:00 UTC
|
|
113
|
+
# Catch up on next boot if the box was off when the timer was due.
|
|
114
|
+
Persistent=true
|
|
115
|
+
# Jitter so simultaneous timers don't dogpile the disk at exactly 04:00.
|
|
116
|
+
RandomizedDelaySec=300
|
|
117
|
+
Unit=${backupUnitName(inst)}.service
|
|
118
|
+
|
|
119
|
+
[Install]
|
|
120
|
+
WantedBy=timers.target
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// The branding pack a provisioned CO-TENANT instance loads: the shared, committed
|
|
125
|
+
// neutral starter (the co-tenant model shares ONE checkout, differentiated only by
|
|
126
|
+
// env — src/branding.js's GDS_BRANDING_FILE knob). Per-instance identity/domains
|
|
127
|
+
// therefore ride ENV OVERRIDES, not a divergent pack. Kept as a constant so the
|
|
128
|
+
// GDS_BRANDING_FILE line below and the env-var PREFIX (which must equal this pack's
|
|
129
|
+
// envPrefix, or src/branding.js's ENV_OVERRIDES never fire) can't drift apart.
|
|
130
|
+
const PROVISIONED_BRANDING_FILE = 'config/branding.neutral.json';
|
|
131
|
+
|
|
132
|
+
// The env-var prefix a provisioned instance actually RESOLVES — i.e. the envPrefix
|
|
133
|
+
// of the pack it loads (PROVISIONED_BRANDING_FILE). src/instance-config.resolveEnv
|
|
134
|
+
// reads <envPrefix>_<SUFFIX>, and src/branding.resolveBranding applies
|
|
135
|
+
// <envPrefix>_{PUBLIC,BUILDERS,…}_ORIGIN overrides — so a web.env var only takes
|
|
136
|
+
// effect under THIS prefix. Read from the pack (fail-soft to the vanilla default)
|
|
137
|
+
// so it stays in lockstep instead of a magic string. (The prior slug-based prefix
|
|
138
|
+
// was a latent bug: it never matched the neutral pack's CLOUDBONGOS envPrefix, so
|
|
139
|
+
// the OAuth creds were silently unreadable — task 1972.)
|
|
140
|
+
function provisionedEnvPrefix() {
|
|
141
|
+
try {
|
|
142
|
+
const pack = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, PROVISIONED_BRANDING_FILE), 'utf8'));
|
|
143
|
+
return pack.envPrefix || 'CLOUDBONGOS';
|
|
144
|
+
} catch { return 'CLOUDBONGOS'; }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// The per-instance secrets file body (the standup runbook's /etc/<inst>/web.env).
|
|
148
|
+
// The OAuth client id/secret are GUIDED/manual inputs (no GitHub create-API) — the
|
|
149
|
+
// runner writes placeholders the owner fills, unless provided via the intent later.
|
|
150
|
+
// A domain (bring-your-own or provisioned) drives the single-host origin overrides:
|
|
151
|
+
// with them set, src/branding.js resolves the instance's REAL buildersOrigin, so the
|
|
152
|
+
// core's single-host router (isBuildersHost === buildersOrigin host, task 1971) serves
|
|
153
|
+
// the hall on this host + OAuth uses the real callback origin — without them the pack
|
|
154
|
+
// stays at neutral localhost and the hall never loads (task 1972). No domain yet
|
|
155
|
+
// (bring-your-own deferred, ADR 0111 §4) ⇒ origins stay neutral until one is set.
|
|
156
|
+
function webEnvBody(inst, { clientId = '', clientSecret = '', appId = null, appPem = null, federation = null } = {}) {
|
|
157
|
+
const prefix = provisionedEnvPrefix(), { settingsEnvLines } = require(path.join(REPO_ROOT, 'modules/provisioning/provisioning')); // eslint-disable-line global-require
|
|
158
|
+
const origin = inst.domain ? `https://${inst.domain}` : '';
|
|
159
|
+
const originLines = origin
|
|
160
|
+
? `# Single-host origins (task 1972): the hall serves on THIS host + OAuth/redirects
|
|
161
|
+
# use the real address. Resolved by src/branding.js ENV_OVERRIDES under the pack's
|
|
162
|
+
# ${prefix} envPrefix. A single-host instance has no dedicated builders./status.
|
|
163
|
+
# subdomain, so all four point at the one host.
|
|
164
|
+
${prefix}_PUBLIC_ORIGIN=${origin}
|
|
165
|
+
${prefix}_BUILDERS_ORIGIN=${origin}
|
|
166
|
+
${prefix}_STATUS_ORIGIN=${origin}
|
|
167
|
+
${prefix}_OAUTH_ORIGIN=${origin}
|
|
168
|
+
`
|
|
169
|
+
: `# No domain yet (bring-your-own-domain pending, ADR 0111 §4) — origins stay
|
|
170
|
+
# neutral (localhost); add ${prefix}_{PUBLIC,BUILDERS,OAUTH}_ORIGIN once a domain
|
|
171
|
+
# is set, or the hall won't load on the instance's host.
|
|
172
|
+
`;
|
|
173
|
+
// The OAuth app creds are filled by ONE of two paths (task 2080): the GitHub App
|
|
174
|
+
// Manifest flow (placeManifestCreds fetches them control-plane-side + re-writes this
|
|
175
|
+
// file with clientId/clientSecret set), or the manual oauth-secret.js placement. On
|
|
176
|
+
// the first provision write they are blank placeholders the flow fills later.
|
|
177
|
+
const credComment = federation
|
|
178
|
+
? `# Provisioned by scripts/gds/provision.js (ADR 0111). This instance FEDERATES sign-in
|
|
179
|
+
# through the Cloud Bongos hub (ADR 0141 §4) — it needs no GitHub app of its own, so the
|
|
180
|
+
# GitHub client id/secret below stay blank; the ${prefix}_HUB_* block drives sign-in.`
|
|
181
|
+
: clientId || clientSecret
|
|
182
|
+
? `# Provisioned by scripts/gds/provision.js (ADR 0111). OAuth app creds placed via the
|
|
183
|
+
# GitHub App Manifest flow (ADR 0133) — the owner clicked one link; no secret was pasted.`
|
|
184
|
+
: `# Provisioned by scripts/gds/provision.js (ADR 0111). Fill the OAuth app creds via the
|
|
185
|
+
# one-click GitHub App Manifest flow (ADR 0133), or manually (oauth-secret.js place):`;
|
|
186
|
+
// The founding owner (firstAdmin): the GitHub login src/bongos/auth.js seats as the
|
|
187
|
+
// instance's first Archon on first sign-in (maybeSeatFirstAdmin checks
|
|
188
|
+
// <prefix>_FIRST_ADMIN before branding.firstAdmin). WITHOUT it a provisioned instance
|
|
189
|
+
// has NO owner — first sign-in is refused / lands rankless and the owner can never
|
|
190
|
+
// claim their own instance (goal 35 / criterion 165 regression, caught live 2026-07-07:
|
|
191
|
+
// demo had every origin override but no FIRST_ADMIN, so the owner could not be seated).
|
|
192
|
+
// Derived from the instance repo owner (target_ref = "<owner>/<repo>"), the SAME source
|
|
193
|
+
// instanceInitSpec uses for the scaffold's branding.firstAdmin — so this env override and
|
|
194
|
+
// the scaffolded config/branding.json agree. (Org-owned repo: the org login is not a
|
|
195
|
+
// sign-in identity, so it is left unset; the owner sets <prefix>_FIRST_ADMIN by hand.)
|
|
196
|
+
const ownerRepo = parseTargetRef(inst.target_ref);
|
|
197
|
+
const firstAdminLine = ownerRepo && ownerRepo.owner
|
|
198
|
+
? `${prefix}_FIRST_ADMIN=${ownerRepo.owner}\n`
|
|
199
|
+
: '';
|
|
200
|
+
// Cross-site identity federation block (ADR 0141 §4, task #1002109). Present only for
|
|
201
|
+
// a HOSTED (federated) instance: flips auth.idp ON via the env override branding.js
|
|
202
|
+
// reads (idpEnabled), and carries the hub origin, this instance's per-client secret
|
|
203
|
+
// (authenticates it TO the hub, server-to-server), and the hub's PUBLIC key (verifies
|
|
204
|
+
// the CLI's hub-signed assertion offline). All written straight to this chmod-600
|
|
205
|
+
// file — never through a browser or chat (the ADR 0133 secret-placement posture).
|
|
206
|
+
const fedLines = federation
|
|
207
|
+
? `${prefix}_AUTH_IDP=true
|
|
208
|
+
${prefix}_HUB_ORIGIN=${federation.hubOrigin}
|
|
209
|
+
${prefix}_HUB_CLIENT_ID=${federation.clientId}
|
|
210
|
+
${prefix}_HUB_CLIENT_SECRET=${federation.clientSecret}
|
|
211
|
+
${prefix}_HUB_PUBLIC_KEY=${federation.hubPublicKey}
|
|
212
|
+
`
|
|
213
|
+
: '';
|
|
214
|
+
// The publish credential (task 1003049, ADR 0055): the manifest-born App's id +
|
|
215
|
+
// private key, read BARE (no prefix) by modules/lifecycle/github-push.js. The
|
|
216
|
+
// pem is env-file-flattened to a single line with literal \n (the ADR 0055
|
|
217
|
+
// rotation convention; normalizePem restores it). The installation id is NOT
|
|
218
|
+
// written — the server discovers it from the repo once the owner installs the
|
|
219
|
+
// App (the onboarding app-install step).
|
|
220
|
+
const appLines = appId && appPem
|
|
221
|
+
? `# Publish credential (ADR 0055): the sign-in GitHub App doubles as it. The server
|
|
222
|
+
# mints short-lived installation tokens once the App is INSTALLED on the repo.
|
|
223
|
+
GITHUB_APP_ID=${appId}
|
|
224
|
+
GITHUB_APP_PRIVATE_KEY=${String(appPem).replace(/\r?\n/g, '\\n')}
|
|
225
|
+
`
|
|
226
|
+
: '';
|
|
227
|
+
return `# /etc/${inst.slug}/web.env — per-instance secrets (chmod 600, OUTSIDE the repo).
|
|
228
|
+
${credComment}
|
|
229
|
+
${prefix}_GITHUB_CLIENT_ID=${clientId || ''}
|
|
230
|
+
${prefix}_GITHUB_CLIENT_SECRET=${clientSecret || ''}
|
|
231
|
+
${firstAdminLine}GDS_BRANDING_FILE=${PROVISIONED_BRANDING_FILE}
|
|
232
|
+
${originLines}${appLines}PORT=${inst.port}
|
|
233
|
+
PGDATABASE=${dbName(inst)}
|
|
234
|
+
${fedLines}${settingsEnvLines(inst, prefix)}`;
|
|
235
|
+
}
|
|
236
|
+
function webEnvPath(inst, { etcBase = CONFIG.etcBase } = {}) {
|
|
237
|
+
return path.posix.join(etcBase, inst.slug, 'web.env');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ── Cross-site identity: federate a hosted instance's sign-in through the hub ───
|
|
241
|
+
// (ADR 0141 §4, task #1002109). The control plane IS the hub (cloudbongos.com), so
|
|
242
|
+
// registration is a direct in-process call against the hub pool — no HTTP hop.
|
|
243
|
+
|
|
244
|
+
// The hub's own public origin, written into each federated instance as
|
|
245
|
+
// <PREFIX>_HUB_ORIGIN (what auth.js loadIdpConfig reads). Explicit PROVISION_HUB_ORIGIN
|
|
246
|
+
// wins; otherwise the control plane's OWN public origin (<PREFIX>_PUBLIC_ORIGIN, the
|
|
247
|
+
// env the hub already runs under). Null → not hub-configured → shouldFederate is false.
|
|
248
|
+
|
|
249
|
+
module.exports = {
|
|
250
|
+
PROVISIONED_BRANDING_FILE,
|
|
251
|
+
backupScriptPath,
|
|
252
|
+
backupService,
|
|
253
|
+
backupServicePath,
|
|
254
|
+
backupTimer,
|
|
255
|
+
backupTimerPath,
|
|
256
|
+
backupUnitName,
|
|
257
|
+
provisionedEnvPrefix,
|
|
258
|
+
serviceUnit,
|
|
259
|
+
serviceUnitPath,
|
|
260
|
+
webEnvBody,
|
|
261
|
+
webEnvPath,
|
|
262
|
+
};
|