@bongos/core 1.19.261 → 1.19.262
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 +19 -14
- package/config/branding.neutral.json +52 -12
- package/modules/provisioning/provisioning.js +23 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/provision.js +2 -2
- package/src/branding.js +6 -0
- package/src/module-api.js +3 -1
- package/tests/provisioning_settings_env.mjs +121 -0
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.
|
|
6
|
-
"core_contract": "1.19.
|
|
7
|
-
"source_commit": "
|
|
5
|
+
"core_version": "1.19.262",
|
|
6
|
+
"core_contract": "1.19.262",
|
|
7
|
+
"source_commit": "5c66bd4246a027582b292909499f6d31009157c6",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-
|
|
9
|
+
"built_at": "2026-08-19T20:21:59.469Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 318,
|
|
13
13
|
"agent_docs_stubbed": 22,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 1362,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 1702,
|
|
20
|
+
"tree_sha256": "6c446d9f84793d24dace5316025f4a09517fd85c5260884cb2885e445dcfb2d1",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -382,7 +382,7 @@
|
|
|
382
382
|
{
|
|
383
383
|
"path": "config/branding.neutral.json",
|
|
384
384
|
"mode": "0000644",
|
|
385
|
-
"sha256": "
|
|
385
|
+
"sha256": "d1d2622e002edaed8a98deb8b69ff5a77c6eeab7993e3b0e7f1513f32ff027c6"
|
|
386
386
|
},
|
|
387
387
|
{
|
|
388
388
|
"path": "config/design-tokens.neutral.json",
|
|
@@ -4152,7 +4152,7 @@
|
|
|
4152
4152
|
{
|
|
4153
4153
|
"path": "modules/provisioning/provisioning.js",
|
|
4154
4154
|
"mode": "0000644",
|
|
4155
|
-
"sha256": "
|
|
4155
|
+
"sha256": "862fa78c7272a28cdc644debfd8ec364b80b635e8b9a6f41afb76b93312f27dd"
|
|
4156
4156
|
},
|
|
4157
4157
|
{
|
|
4158
4158
|
"path": "modules/provisioning/rate-limit.js",
|
|
@@ -4462,12 +4462,12 @@
|
|
|
4462
4462
|
{
|
|
4463
4463
|
"path": "package-lock.json",
|
|
4464
4464
|
"mode": "0000644",
|
|
4465
|
-
"sha256": "
|
|
4465
|
+
"sha256": "687fe7e65dc80ea4688cbb7e530324b70b97e512f3b786d0264c810e47629388"
|
|
4466
4466
|
},
|
|
4467
4467
|
{
|
|
4468
4468
|
"path": "package.json",
|
|
4469
4469
|
"mode": "0000644",
|
|
4470
|
-
"sha256": "
|
|
4470
|
+
"sha256": "bdb5fabfd35c8e1402b7a68bfd9033ab7bb8072e83f3cd181a835aed180eab8a"
|
|
4471
4471
|
},
|
|
4472
4472
|
{
|
|
4473
4473
|
"path": "public-docs/index.html",
|
|
@@ -5402,7 +5402,7 @@
|
|
|
5402
5402
|
{
|
|
5403
5403
|
"path": "scripts/gds/provision.js",
|
|
5404
5404
|
"mode": "0000644",
|
|
5405
|
-
"sha256": "
|
|
5405
|
+
"sha256": "1b1e4ca721a9052206265736712ea17e96b2b724c2926faba49839def36a1818"
|
|
5406
5406
|
},
|
|
5407
5407
|
{
|
|
5408
5408
|
"path": "scripts/gds/publish-credential-check.js",
|
|
@@ -6092,7 +6092,7 @@
|
|
|
6092
6092
|
{
|
|
6093
6093
|
"path": "src/branding.js",
|
|
6094
6094
|
"mode": "0000644",
|
|
6095
|
-
"sha256": "
|
|
6095
|
+
"sha256": "04c7bd3146abc16cb51d81fa6550520cdd169cd527fbe2de13dffd2c6fcc8ef5"
|
|
6096
6096
|
},
|
|
6097
6097
|
{
|
|
6098
6098
|
"path": "src/build-info.js",
|
|
@@ -6112,7 +6112,7 @@
|
|
|
6112
6112
|
{
|
|
6113
6113
|
"path": "src/module-api.js",
|
|
6114
6114
|
"mode": "0000644",
|
|
6115
|
-
"sha256": "
|
|
6115
|
+
"sha256": "1c68d692ed6e52924b04af09f9d816514b8b1ccd795984960f1c9cddefb6eba5"
|
|
6116
6116
|
},
|
|
6117
6117
|
{
|
|
6118
6118
|
"path": "src/module-loader/catalog.js",
|
|
@@ -7889,6 +7889,11 @@
|
|
|
7889
7889
|
"mode": "0000644",
|
|
7890
7890
|
"sha256": "a525fdcfa2fde8edd2be3198ca7213b9b6bc43a12f748a718a570b7f993972b6"
|
|
7891
7891
|
},
|
|
7892
|
+
{
|
|
7893
|
+
"path": "tests/provisioning_settings_env.mjs",
|
|
7894
|
+
"mode": "0000644",
|
|
7895
|
+
"sha256": "ee73d6af28f68bc6c197aae847663e9db2afb45e5073e2886a28c2a15925ad53"
|
|
7896
|
+
},
|
|
7892
7897
|
{
|
|
7893
7898
|
"path": "tests/provisioning_slug_available.mjs",
|
|
7894
7899
|
"mode": "0000644",
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
"identity": {
|
|
4
4
|
"productName": "Cloud Bongos",
|
|
5
5
|
"worldName": "Cloud Bongos",
|
|
6
|
-
"company": {
|
|
6
|
+
"company": {
|
|
7
|
+
"name": "",
|
|
8
|
+
"site": ""
|
|
9
|
+
}
|
|
7
10
|
},
|
|
8
11
|
"llmProjectName": "this project",
|
|
9
12
|
"domains": {
|
|
@@ -23,33 +26,70 @@
|
|
|
23
26
|
"_note": "Cross-site identity (ADR 0141). idp=false → this instance owns its auth outright (its own GitHub app; the default + the self-hosted path). A HOSTED instance sets idp=true and gets its hub origin + client credentials from env (<PREFIX>_HUB_ORIGIN / _HUB_CLIENT_ID / _HUB_CLIENT_SECRET, written by provisioning) so web + CLI sign-in federate through the Cloud Bongos hub with no GitHub app of its own. Identity is federated; authority stays local.",
|
|
24
27
|
"idp": false
|
|
25
28
|
},
|
|
26
|
-
"
|
|
27
|
-
|
|
29
|
+
"project": {
|
|
30
|
+
"_note": "Per-project policy the PLATFORM decides and this instance OBEYS (task 1003139, goal 1000058). Stored on the platform's provisioning_instances.settings; written here as <PREFIX>_PLATFORM_VISIBILITY / <PREFIX>_JOINABILITY by the provisioning runner, which re-writes web.env and restarts the service when the owner changes one. The defaults are TODAY's behavior, so an instance that never receives a push — a self-hosted one, or one provisioned before this channel — keeps behaving exactly as it does now. platformVisibility: public | gated. joinability: open | apply | invite_only.",
|
|
31
|
+
"platformVisibility": "public",
|
|
32
|
+
"joinability": "apply"
|
|
33
|
+
},
|
|
34
|
+
"repo": {
|
|
35
|
+
"owner": "",
|
|
36
|
+
"name": ""
|
|
37
|
+
},
|
|
38
|
+
"db": {
|
|
39
|
+
"database": null
|
|
40
|
+
},
|
|
28
41
|
"configDir": "cloudbongos",
|
|
29
42
|
"firstAdmin": "",
|
|
30
|
-
"currency": {
|
|
31
|
-
|
|
32
|
-
|
|
43
|
+
"currency": {
|
|
44
|
+
"label": "credits",
|
|
45
|
+
"symbol": ""
|
|
46
|
+
},
|
|
47
|
+
"reward": {
|
|
48
|
+
"marginPct": 20,
|
|
49
|
+
"usdPeg": 1,
|
|
50
|
+
"mode": "cost-plus-and-estimate"
|
|
51
|
+
},
|
|
52
|
+
"models": {
|
|
53
|
+
"main": "opus",
|
|
54
|
+
"subagentDefault": "opus",
|
|
55
|
+
"subagentRoutine": "haiku"
|
|
56
|
+
},
|
|
33
57
|
"theme": {
|
|
34
58
|
"palette": "",
|
|
35
59
|
"mode": "cloud-bongos",
|
|
36
60
|
"ui": {
|
|
37
61
|
"colors": {
|
|
38
|
-
"bg": "#f9d9a8",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
62
|
+
"bg": "#f9d9a8",
|
|
63
|
+
"bgCard": "#fffaf2",
|
|
64
|
+
"bgDeep": "#f6d8ae",
|
|
65
|
+
"bgFrame": "#f0c489",
|
|
66
|
+
"ink": "#2b170e",
|
|
67
|
+
"inkSoft": "#6d4a33",
|
|
68
|
+
"inkFaint": "#785a41",
|
|
69
|
+
"rule": "#e8a463",
|
|
70
|
+
"ruleSoft": "#f6d8ae",
|
|
71
|
+
"accent": "#ce4806",
|
|
72
|
+
"accentDeep": "#9e3406",
|
|
73
|
+
"sea": "#0f7a96",
|
|
74
|
+
"terracotta": "#855b3d"
|
|
42
75
|
},
|
|
43
76
|
"fonts": {
|
|
44
77
|
"display": "\"Baloo 2\", \"Quicksand\", system-ui, sans-serif",
|
|
45
78
|
"body": "\"Quicksand\", system-ui, -apple-system, \"Segoe UI\", sans-serif",
|
|
46
|
-
"links": [
|
|
79
|
+
"links": [
|
|
80
|
+
"https://fonts.googleapis.com/css2?family=Baloo+2:wght@500;600;700&family=Quicksand:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap"
|
|
81
|
+
]
|
|
47
82
|
},
|
|
48
83
|
"favicon": "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><circle cx='12' cy='17' r='8' fill='%23ce4806'/><circle cx='22' cy='17' r='6' fill='%23855b3d'/><circle cx='12' cy='17' r='3.5' fill='%23fffaf2'/><circle cx='22' cy='17' r='2.5' fill='%23fffaf2'/></svg>",
|
|
49
84
|
"backdrop": "#f9d9a8"
|
|
50
85
|
}
|
|
51
86
|
},
|
|
52
|
-
"rankLabels": {
|
|
87
|
+
"rankLabels": {
|
|
88
|
+
"xenos": "Newcomer",
|
|
89
|
+
"thetes": "Contributor",
|
|
90
|
+
"metic": "Trusted",
|
|
91
|
+
"archon": "Owner"
|
|
92
|
+
},
|
|
53
93
|
"copy": {
|
|
54
94
|
"tagline": "Building Digitally, as simple as Bongos.",
|
|
55
95
|
"hallName": "Builders' Hall",
|
|
@@ -235,6 +235,28 @@ function publicInstance(row) {
|
|
|
235
235
|
// The instance's EFFECTIVE settings: the defaults overlaid with the stored,
|
|
236
236
|
// on-vocabulary keys. An off-vocabulary or unknown stored value falls back to
|
|
237
237
|
// its default rather than leaking into the read surface. PURE.
|
|
238
|
+
// The web.env lines that carry this instance's settings, as the runner writes them
|
|
239
|
+
// at standup (task 1003139). PURE (row + prefix in, string out) and owned HERE, next
|
|
240
|
+
// to SETTINGS_VOCAB, rather than in provision.js — the vocabulary and the thing that
|
|
241
|
+
// transmits it must not be able to drift. Values come from effectiveSettings, so a
|
|
242
|
+
// row with no stored settings emits today's behavior EXPLICITLY rather than nothing:
|
|
243
|
+
// an instance must never have to infer a policy from an absent variable.
|
|
244
|
+
//
|
|
245
|
+
// This is the standup leg only. Changing a setting on an ALREADY-RUNNING instance
|
|
246
|
+
// needs a push (re-write web.env + restart, since the branding pack is memoized for
|
|
247
|
+
// the process lifetime) — that is the 'settings-apply' intent, still to be built.
|
|
248
|
+
function settingsEnvLines(row, prefix) {
|
|
249
|
+
const s = effectiveSettings(row);
|
|
250
|
+
return `# Per-project policy the platform decides and this instance obeys (task
|
|
251
|
+
# 1003139). Written at standup from the platform's provisioning_instances.settings;
|
|
252
|
+
# src/branding.js ENV_OVERRIDES maps these onto project.*. Changing one on a RUNNING
|
|
253
|
+
# instance still needs a push (re-write + restart) — not built yet, so today a change
|
|
254
|
+
# takes effect on the next provision run.
|
|
255
|
+
${prefix}_PLATFORM_VISIBILITY=${s.platform_visibility}
|
|
256
|
+
${prefix}_JOINABILITY=${s.joinability}
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
259
|
+
|
|
238
260
|
function effectiveSettings(row) {
|
|
239
261
|
const stored = row && row.settings && typeof row.settings === 'object' && !Array.isArray(row.settings)
|
|
240
262
|
? row.settings : {};
|
|
@@ -783,6 +805,7 @@ async function costLedger(db, { limit = 500 } = {}) {
|
|
|
783
805
|
module.exports = {
|
|
784
806
|
// constants
|
|
785
807
|
INSTANCE_STATES, HOSTING_SHAPES, ONBOARD_MODES, PROJECT_TYPES, INTENT_ACTIONS, TEARDOWN_FROM,
|
|
808
|
+
settingsEnvLines,
|
|
786
809
|
PROVISION_ENQUEUE_FROM, DOMAIN_ATTACH_FROM, TIER_MONTHLY_USD, CERT_ELIGIBLE_STATES,
|
|
787
810
|
SETTINGS_VOCAB, DEFAULT_SETTINGS,
|
|
788
811
|
// pure
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.262",
|
|
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.262",
|
|
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.262",
|
|
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
|
@@ -1157,7 +1157,7 @@ function provisionedEnvPrefix() {
|
|
|
1157
1157
|
// stays at neutral localhost and the hall never loads (task 1972). No domain yet
|
|
1158
1158
|
// (bring-your-own deferred, ADR 0111 §4) ⇒ origins stay neutral until one is set.
|
|
1159
1159
|
function webEnvBody(inst, { clientId = '', clientSecret = '', appId = null, appPem = null, federation = null } = {}) {
|
|
1160
|
-
const prefix = provisionedEnvPrefix();
|
|
1160
|
+
const prefix = provisionedEnvPrefix(), { settingsEnvLines } = require(path.join(REPO_ROOT, 'modules/provisioning/provisioning')); // eslint-disable-line global-require
|
|
1161
1161
|
const origin = inst.domain ? `https://${inst.domain}` : '';
|
|
1162
1162
|
const originLines = origin
|
|
1163
1163
|
? `# Single-host origins (task 1972): the hall serves on THIS host + OAuth/redirects
|
|
@@ -1234,7 +1234,7 @@ ${prefix}_GITHUB_CLIENT_SECRET=${clientSecret || ''}
|
|
|
1234
1234
|
${firstAdminLine}GDS_BRANDING_FILE=${PROVISIONED_BRANDING_FILE}
|
|
1235
1235
|
${originLines}${appLines}PORT=${inst.port}
|
|
1236
1236
|
PGDATABASE=${dbName(inst)}
|
|
1237
|
-
${fedLines}`;
|
|
1237
|
+
${fedLines}${settingsEnvLines(inst, prefix)}`;
|
|
1238
1238
|
}
|
|
1239
1239
|
function webEnvPath(inst, { etcBase = CONFIG.etcBase } = {}) {
|
|
1240
1240
|
return path.posix.join(etcBase, inst.slug, 'web.env');
|
package/src/branding.js
CHANGED
|
@@ -54,6 +54,12 @@ const ENV_OVERRIDES = [
|
|
|
54
54
|
// front door with one env var and no instance branding.json — cloudbongos.com
|
|
55
55
|
// sets <PREFIX>_POST_LOGIN_LANDING=/gate/ (the orbs). Task 1002240.
|
|
56
56
|
['POST_LOGIN_LANDING', ['landing', 'postLogin']],
|
|
57
|
+
// Per-project policy pushed by the provisioning runner (task 1003139). The pack
|
|
58
|
+
// ships today's behavior, so an instance that never receives a push is unchanged.
|
|
59
|
+
// Read through branding, which is memoized + deep-frozen for the process lifetime
|
|
60
|
+
// — which is exactly why applying a change RESTARTS the instance.
|
|
61
|
+
['PLATFORM_VISIBILITY', ['project', 'platformVisibility']],
|
|
62
|
+
['JOINABILITY', ['project', 'joinability']],
|
|
57
63
|
];
|
|
58
64
|
|
|
59
65
|
const isObj = (v) => v && typeof v === 'object' && !Array.isArray(v);
|
package/src/module-api.js
CHANGED
|
@@ -949,8 +949,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
949
949
|
// landed since 1.19.259 with no explicit bump. run 32289043893. (task 1002620)
|
|
950
950
|
// 1.19.261 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
951
951
|
// landed since 1.19.260 with no explicit bump. run 32295699354. (task 1002620)
|
|
952
|
+
// 1.19.262 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
953
|
+
// landed since 1.19.261 with no explicit bump. run 32298063660. (task 1002620)
|
|
952
954
|
// ---------------------------------------------------------------------------
|
|
953
|
-
const CORE_VERSION = '1.19.
|
|
955
|
+
const CORE_VERSION = '1.19.262'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
954
956
|
|
|
955
957
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
956
958
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// tests/provisioning_settings_env.mjs
|
|
2
|
+
//
|
|
3
|
+
// The standup leg of the platform->instance settings channel (task 1003139, goal
|
|
4
|
+
// 1000058): a per-project setting the PLATFORM stores must reach the INSTANCE that
|
|
5
|
+
// has to obey it.
|
|
6
|
+
//
|
|
7
|
+
// The gap this closes: PATCH /provisioning/instances/:id/settings wrote
|
|
8
|
+
// platform_visibility / joinability to the platform's jsonb and pushed nothing, and a
|
|
9
|
+
// standalone instance never federates — it holds no hub credential and has no
|
|
10
|
+
// authenticated path back to the platform to pull one. The settings were write-only
|
|
11
|
+
// state. The transport that DOES exist is /etc/<slug>/web.env, read through the
|
|
12
|
+
// branding pack, so the runner now writes them there at standup and src/branding.js
|
|
13
|
+
// resolves them onto project.*.
|
|
14
|
+
//
|
|
15
|
+
// NOT covered here because it is NOT built: pushing a CHANGED setting to an
|
|
16
|
+
// already-running instance (the branding pack is memoized + deep-frozen for the
|
|
17
|
+
// process lifetime, so that needs a re-write + restart — the deferred
|
|
18
|
+
// 'settings-apply' intent). These tests assert the standup leg only, and one of them
|
|
19
|
+
// pins that the generated file does not CLAIM the push exists.
|
|
20
|
+
//
|
|
21
|
+
// DB-free and hermetic: pure builders + a child process with env set. No network.
|
|
22
|
+
//
|
|
23
|
+
// Run: node tests/provisioning_settings_env.mjs
|
|
24
|
+
|
|
25
|
+
import { strict as assert } from 'node:assert';
|
|
26
|
+
import { createRequire } from 'node:module';
|
|
27
|
+
import { execFileSync } from 'node:child_process';
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
import { fileURLToPath } from 'node:url';
|
|
30
|
+
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
33
|
+
const provisioning = require('../modules/provisioning/provisioning.js');
|
|
34
|
+
|
|
35
|
+
let passed = 0, failed = 0;
|
|
36
|
+
function t(name, fn) {
|
|
37
|
+
try { fn(); passed++; console.log(` PASS ${name}`); }
|
|
38
|
+
catch (e) { failed++; console.log(` FAIL ${name}\n ${e.message}`); }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const linesOf = (s) => s.split('\n').filter((l) => l && !l.startsWith('#'));
|
|
42
|
+
const varsOf = (s) => Object.fromEntries(linesOf(s).map((l) => l.split('=')));
|
|
43
|
+
|
|
44
|
+
console.log('settingsEnvLines — the platform\'s stored settings, as the instance reads them:');
|
|
45
|
+
|
|
46
|
+
t('a stored setting is carried verbatim under the pack\'s env prefix', () => {
|
|
47
|
+
const v = varsOf(provisioning.settingsEnvLines(
|
|
48
|
+
{ settings: { platform_visibility: 'gated', joinability: 'invite_only' } }, 'CLOUDBONGOS'));
|
|
49
|
+
assert.equal(v.CLOUDBONGOS_PLATFORM_VISIBILITY, 'gated');
|
|
50
|
+
assert.equal(v.CLOUDBONGOS_JOINABILITY, 'invite_only');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
t('a row with NO stored settings emits today\'s behavior EXPLICITLY, never nothing', () => {
|
|
54
|
+
const v = varsOf(provisioning.settingsEnvLines({}, 'CLOUDBONGOS'));
|
|
55
|
+
// an instance must never have to infer a policy from an absent variable
|
|
56
|
+
assert.equal(v.CLOUDBONGOS_PLATFORM_VISIBILITY, 'public');
|
|
57
|
+
assert.equal(v.CLOUDBONGOS_JOINABILITY, 'apply');
|
|
58
|
+
assert.equal(linesOf(provisioning.settingsEnvLines({}, 'X')).length, 2, 'both keys always present');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
t('an off-vocabulary stored value falls back to the default, never reaches the instance', () => {
|
|
62
|
+
const v = varsOf(provisioning.settingsEnvLines(
|
|
63
|
+
{ settings: { platform_visibility: 'sort-of-public', joinability: 'whenever' } }, 'CLOUDBONGOS'));
|
|
64
|
+
assert.equal(v.CLOUDBONGOS_PLATFORM_VISIBILITY, 'public');
|
|
65
|
+
assert.equal(v.CLOUDBONGOS_JOINABILITY, 'apply');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
t('the prefix is the pack\'s, not a guess — a wrong prefix silently never fires', () => {
|
|
69
|
+
const v = varsOf(provisioning.settingsEnvLines({}, 'MERCURY'));
|
|
70
|
+
assert.ok('MERCURY_PLATFORM_VISIBILITY' in v);
|
|
71
|
+
assert.ok(!('CLOUDBONGOS_PLATFORM_VISIBILITY' in v));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
t('every emitted key is in SETTINGS_VOCAB — the two lists cannot drift', () => {
|
|
75
|
+
const keys = linesOf(provisioning.settingsEnvLines({}, 'X')).map((l) => l.split('=')[0].replace(/^X_/, '').toLowerCase());
|
|
76
|
+
assert.deepEqual(keys.sort(), Object.keys(provisioning.SETTINGS_VOCAB).sort(),
|
|
77
|
+
'a key added to the vocabulary must be carried, or the instance never learns it');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
console.log('\nThe generated file tells the truth about what it is:');
|
|
81
|
+
|
|
82
|
+
t('it does NOT claim a live push exists — that intent is not built', () => {
|
|
83
|
+
const s = provisioning.settingsEnvLines({}, 'X');
|
|
84
|
+
assert.doesNotMatch(s, /settings-apply/,
|
|
85
|
+
'no comment may name an intent action the runner cannot dispatch');
|
|
86
|
+
assert.match(s, /next provision run/i, 'it says when a change actually takes effect');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log('\nwebEnvBody — the settings ride the real per-instance env file:');
|
|
90
|
+
|
|
91
|
+
t('the runner writes them into web.env alongside PORT and PGDATABASE', () => {
|
|
92
|
+
const provision = require('../scripts/gds/provision.js');
|
|
93
|
+
const body = provision.webEnvBody(
|
|
94
|
+
{ slug: 'spike-harbor', port: 3010, db_name: 'spike-harbor', target_ref: 'jaxri/spike-harbor',
|
|
95
|
+
hosting_shape: 'standalone', settings: { platform_visibility: 'gated' } }, {});
|
|
96
|
+
assert.match(body, /_PLATFORM_VISIBILITY=gated/);
|
|
97
|
+
assert.match(body, /_JOINABILITY=apply/);
|
|
98
|
+
assert.match(body, /PORT=3010/, 'the rest of the file is untouched');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log('\nsrc/branding.js — the value actually reaches code:');
|
|
102
|
+
|
|
103
|
+
t('the neutral pack ships today\'s behavior, so an un-pushed instance is unchanged', () => {
|
|
104
|
+
const pack = require('../config/branding.neutral.json');
|
|
105
|
+
assert.equal(pack.project.platformVisibility, 'public');
|
|
106
|
+
assert.equal(pack.project.joinability, 'apply');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
t('the env override resolves onto project.* in a real process', () => {
|
|
110
|
+
const read = (env) => JSON.parse(execFileSync(process.execPath, ['-e',
|
|
111
|
+
"const b=require('./src/branding.js');const r=(b.branding||b)();console.log(JSON.stringify({v:r.project.platformVisibility,j:r.project.joinability}))"],
|
|
112
|
+
{ cwd: ROOT, encoding: 'utf8', env: { ...process.env, ...env } }));
|
|
113
|
+
assert.deepEqual(read({}), { v: 'public', j: 'apply' }, 'no env → the pack default');
|
|
114
|
+
assert.deepEqual(
|
|
115
|
+
read({ CLOUDBONGOS_PLATFORM_VISIBILITY: 'gated', CLOUDBONGOS_JOINABILITY: 'invite_only' }),
|
|
116
|
+
{ v: 'gated', j: 'invite_only' },
|
|
117
|
+
'the web.env the runner writes is what the instance reads');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log(`\nprovisioning_settings_env: ${passed} passed, ${failed} failed`);
|
|
121
|
+
if (failed) process.exit(1);
|