@bongos/core 1.19.434 → 1.19.435

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 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.434",
6
- "core_contract": "1.19.434",
7
- "source_commit": "9e1f14e0da2a9564da668d0df84120d18c260818",
5
+ "core_version": "1.19.435",
6
+ "core_contract": "1.19.435",
7
+ "source_commit": "93f1acd4ec60f7f6d7c3241e716a7a2c25315f02",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-29T23:50:03.324Z",
9
+ "built_at": "2026-08-30T01:56:28.344Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 367,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 2130,
20
- "tree_sha256": "6e699f497253f649f37311bc797f8db6bcbb949f7016560ab79c0348fd6f7357",
20
+ "tree_sha256": "f47b962f793eb603e2233c230c31e64d83e1c9d0059a8e68f40c27badabb6f72",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -1987,7 +1987,7 @@
1987
1987
  {
1988
1988
  "path": "docs/module-api-changelog.md",
1989
1989
  "mode": "0000644",
1990
- "sha256": "eb1a0de13cc95a1dae894bd98ed5cc20f67ac4099c7103244672cd8662dbf5db"
1990
+ "sha256": "a143667876a68f55e726b5342461ebb87ef424c43b73de5d234f13df0ab9e333"
1991
1991
  },
1992
1992
  {
1993
1993
  "path": "docs/modules-contract.md",
@@ -2092,7 +2092,7 @@
2092
2092
  {
2093
2093
  "path": "docs/recipes/core-release-pipeline.md",
2094
2094
  "mode": "0000644",
2095
- "sha256": "5f272d8caf53bf1ceb49604996ea44375b1f9a9308fd3a7cac5a6f9a5982e142"
2095
+ "sha256": "06b938c2ad38915d3ed92b20a94c57621ae835f617b01ab02fc01129cd154e2c"
2096
2096
  },
2097
2097
  {
2098
2098
  "path": "docs/recipes/devbox-app-release.md",
@@ -5597,12 +5597,12 @@
5597
5597
  {
5598
5598
  "path": "package-lock.json",
5599
5599
  "mode": "0000644",
5600
- "sha256": "7ef67287e6a676ec28f617429cf5a6a3fa8e9a84770fb2b6e9e59f212b466b70"
5600
+ "sha256": "bbd8414f9a02067c7742dfbfdf0c5ec5a386330994822a47867d2d04b6b2b29e"
5601
5601
  },
5602
5602
  {
5603
5603
  "path": "package.json",
5604
5604
  "mode": "0000644",
5605
- "sha256": "e23bd916855233dde8d2edf4c37e987d5fb9662c7f00074e7fb9286cf711e189"
5605
+ "sha256": "5cbdd7b7313ace6d7481d61088e1c29805ccd2df5ba21368f28bdfe4fcf7fd8e"
5606
5606
  },
5607
5607
  {
5608
5608
  "path": "public-docs/index.html",
@@ -7732,7 +7732,7 @@
7732
7732
  {
7733
7733
  "path": "src/module-api.js",
7734
7734
  "mode": "0000644",
7735
- "sha256": "71759a388a48589b56848030003dd62dbe1ab658ae3dc0370daae3694e57bf2e"
7735
+ "sha256": "1ff4e0ce398b437fc6cfadfaede99b6b977e108e8cf820ef3b954d49163be38f"
7736
7736
  },
7737
7737
  {
7738
7738
  "path": "src/module-loader/catalog.js",
@@ -1305,5 +1305,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
1305
1305
  landed since 1.19.432 with no explicit bump. run 33279772171. (task 1002620)
1306
1306
  1.19.434 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1307
1307
  landed since 1.19.433 with no explicit bump. run 33281881764. (task 1002620)
1308
+ 1.19.435 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
1309
+ landed since 1.19.434 with no explicit bump. run 33286790214. (task 1002620)
1308
1310
  ---------------------------------------------------------------------------
1309
1311
  ```
@@ -179,24 +179,24 @@ git tag --list 'core-v*' --contains <your-merge-sha> | sort -V | head -1
179
179
 
180
180
  ### Step 2 — the bump (the owner runs this line, via `!` in the session)
181
181
 
182
- The permission classifier blocks the agent from running a mutating `sudo -u lars` over ssh, so this paste is the **owner's**. The `!` prefix also keeps ssh honest: a bare `ssh host` is non-interactive here — it connects, prints the MOTD, and exits — so the command must ride as an argument.
182
+ This paste is the **owner’s**: the permission classifier’s treatment of a mutating `sudo` over ssh **varies by session** — some sessions permit it, others block every ssh including read-only probes and `backup.js --trigger`. Don’t retry into a block; hand the owner the line. The `!` prefix also keeps ssh honest: a bare `ssh host` is non-interactive here — it connects, prints the MOTD, and exits — so the command must ride as an argument.
183
183
 
184
184
  ```
185
- ! ssh -i ~/.ssh/otb_builder jaxri@REDACTED_IP "sudo -n -u lars bash -c 'cd /home/lars/cloudbongos-instance && export NPM_TOKEN=\$(grep -oP \"(?<=_authToken=).*\" /home/lars/.npmrc | head -1) && [ -n \"\$NPM_TOKEN\" ] || { echo EMPTY NPM_TOKEN — aborting; exit 12; }; ./node_modules/.bin/bongos upgrade --registry --to <VER> --service cloudbongos.service --health-url http://127.0.0.1:3002/healthz --commit-pin'"
185
+ ! ssh -i ~/.ssh/otb_builder jaxri@REDACTED_IP "sudo -n bash -c 'set -a; . /etc/cloudbongos/npm.env; set +a; cd /home/lars/cloudbongos-instance && sudo -n -u lars --preserve-env=NPM_TOKEN env PGDATABASE=cloudbongos CLOUDBONGOS_INSTANCE_ROOT=/home/lars/cloudbongos-instance ./node_modules/.bin/bongos upgrade --to <VER> --registry --commit-pin --restart-cmd \"sudo systemctl restart cloudbongos.service\" --health-url http://127.0.0.1:3002/healthz'"
186
186
  ```
187
187
 
188
188
  What each piece is for — each guards a failure that actually happened:
189
189
 
190
- - **Token extraction runs as lars** (the whole command is inside `sudo -u lars bash -c`). Reading `/home/lars/.npmrc` as `jaxri` is `Permission denied`, which yields an **empty** `NPM_TOKEN`, which sends npm to the **public** registry, which 404s on the private `@bongos/core` — and the upgrade rolls back cleanly, having taught you nothing. The `[ -n "$NPM_TOKEN" ] || exit` guard aborts instead of half-running.
190
+ - **The token lives in root-only `/etc/cloudbongos/npm.env`, and is handed DOWN to `lars`.** This is the step that used to be documented wrongly, so read it before improvising. `NPM_TOKEN` is **not** in lars’s environment, **not** in the interactive profile, and **not** in `/home/lars/.npmrc` — all three probed empty (2026-08-17). An earlier version of this runbook grepped `~/.npmrc` and therefore aborted on its own `[ -n "$NPM_TOKEN" ]` guard every time. Worse, it could not have worked even if that file were populated: the project `.npmrc` says `_authToken=<redacted>, which **overrides** lars’s user `~/.npmrc`, so the variable is the only channel. Hence the shape above: `set -a; . /etc/cloudbongos/npm.env; set +a` reads it as **root** (mode 600), and `--preserve-env=NPM_TOKEN` hands it to the unprivileged `lars` — exactly what systemd does for the sweep unit (`User=lars` + `EnvironmentFile=`). Without it npm falls back to the **public** registry, 404s on the private `@bongos/core`, and rolls back cleanly having taught you nothing.
191
191
  - **Never put the token in the command line — `sudo` logs the full argv (task 1003218).** The shape above is safe *because* the token is read INSIDE the quoted script, so only the `grep` reaches argv. The tempting variant is not:
192
192
  ```
193
193
  sudo -u lars -H env NPM_TOKEN="<redacted>" … bongos upgrade … # ← LEAKS
194
194
  ```
195
- The shell expands `$NPM_TOKEN` before `sudo` ever runs, so the real token lands in the system journal — which is persistent on this box. That variant put the live token into 26 journal lines between 2026-08-17 and 2026-08-23. If you need to hand a secret to a privileged child, use `sudo --preserve-env=NPM_TOKEN …`, which passes it through the environment where nothing logs it. Passing "by reference" in the script text is NOT enough; what matters is what argv looks like after expansion.
195
+ Passing "by reference" in the script text is NOT enough; what matters is what argv looks like after expansion. **The command above is the compliant form of exactly this advice** — it uses `--preserve-env=NPM_TOKEN`, so the token travels in the environment and never reaches any argv.
196
196
  - **`--to <VER>` is required** — `bongos upgrade` refuses to guess a target.
197
- - **`--service` + `--health-url` buy the automatic rollback.** Point the health URL at `http://127.0.0.1:3002/healthz`, **not the public URL** — a pre-launch `basic_auth` on the apex makes a healthy boot look failed and triggers a needless rollback.
197
+ - **Use `--restart-cmd`, NOT `--service` — and `--health-url` is what buys the automatic rollback.** The two restart flags are not interchangeable here. `restartService()` ([`scripts/gds/upgrade.js`](../../scripts/gds/upgrade.js)) runs a **bare** `systemctl restart <svc>` for `--service`, with no `sudo`; the upgrade runs as unprivileged `lars`, who has NOPASSWD sudo for the restart but cannot restart a unit directly — so `--service` fails at the last step, after the core is already swapped in. `--restart-cmd` lets you spell the `sudo` (it overrides `--service` when both are passed). Point the health URL at `http://127.0.0.1:3002/healthz` — **not** `:3000` (that is the port named in CLAUDE.md, not this instance's; read the truth from `systemctl cat cloudbongos.service`) and **not** the public URL, where a pre-launch `basic_auth` on the apex makes a healthy boot look failed and triggers a needless rollback that then misreports "health STILL failing after rollback". The service is fine; the probe was wrong. Health polls ~30s, so an immediate `fetch failed` is not a failure.
198
198
  - **`--commit-pin` commits AND pushes the pin.** The instance is a pull-deploy repo: the next sync runs `git reset --hard origin/main`, which reverts an uncommitted pin, and `npm ci` then reinstalls the old core. Nothing errors. This is exactly how live sat 13 releases behind (task 1002712). The same applies to any tracked instance-config edit (`config/branding.json`): commit + push or the next deploy tick undoes it. A commit that fails to *push* saves nothing — deploy.sh resets to the remote.
199
- - **The `core_upgrades` ledger row needs `PGDATABASE`.** The migrate step resolves the instance DB itself, but the ledger write reads only the env — under `sudo -u lars bash -c` there is none, so the run logs `ledger skipped (no DATABASE_URL or PGDATABASE)`. The bump still succeeds. If you want the row: read the DB name once (`! ssh -i ~/.ssh/otb_builder jaxri@REDACTED_IP "sudo -n -u lars grep -A1 '\"db\"' /home/lars/cloudbongos-instance/config/branding.json"`) and splice `export PGDATABASE=<name> &&` into the paste before the `bongos upgrade` call.
199
+ - **`PGDATABASE=cloudbongos` is inline above, and that is what records the `core_upgrades` ledger row.** The migrate step resolves the instance DB itself, but the ledger write reads only the env; a form that omits it still upgrades successfully and just logs `ledger skipped (no DATABASE_URL or PGDATABASE)`. It is also **load-bearing beyond the ledger** — `migrate.sh` defaults to a *different* production DB (`example`), so name it explicitly rather than letting it default.
200
200
 
201
201
  ### Step 3 — verify on the box, not from your browser
202
202
 
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.434",
3
+ "version": "1.19.435",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.434",
9
+ "version": "1.19.435",
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.434",
3
+ "version": "1.19.435",
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
@@ -33,7 +33,7 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
33
33
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
34
34
  // the entry to that file. Look for a version's history there, not here.
35
35
  // ---------------------------------------------------------------------------
36
- const CORE_VERSION = '1.19.434'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
36
+ const CORE_VERSION = '1.19.435'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
37
37
 
38
38
  // A namespaced logger so a module's log lines are attributable + consistent.
39
39
  // Usage: const log = api.logger('dev-box'); log.info('mounted');