@bongos/core 1.19.978 → 1.19.980
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 +20 -20
- package/docs/adr/0176-private-repo-deploy-keys.md +3 -1
- package/docs/copy-inventory.md +4 -4
- package/docs/copy-registry.json +6 -6
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/blockers.js +4 -4
- package/modules/hall-ui/public/goal-inbox.js +3 -3
- package/modules/provisioning/repo-private.js +5 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/provision-repo-private.js +10 -0
- package/scripts/gds/provision-repo.js +4 -4
- package/src/module-api.js +1 -1
- package/tests/blockers_page_ui.mjs +6 -0
- package/tests/provision_repo_private.mjs +54 -0
- package/tests/rot_inbox.mjs +10 -0
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.980",
|
|
6
|
+
"core_contract": "1.19.980",
|
|
7
|
+
"source_commit": "7e92e28e22b7fc66cf188d2f089c9824fc3c2c4f",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-23T16:31:15.535Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 517,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2929,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "c520e6934b708166a12bcdce8eb65bec32d14c3141823739f4e11ca7a4ccf0e0",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -1362,7 +1362,7 @@
|
|
|
1362
1362
|
{
|
|
1363
1363
|
"path": "docs/adr/0176-private-repo-deploy-keys.md",
|
|
1364
1364
|
"mode": "0000644",
|
|
1365
|
-
"sha256": "
|
|
1365
|
+
"sha256": "a397741f6fcbf88fe3a05fabe74c5fa0e6464d810e812ae7981700b13a0f1806"
|
|
1366
1366
|
},
|
|
1367
1367
|
{
|
|
1368
1368
|
"path": "docs/adr/0177-goal-membership-kind.md",
|
|
@@ -2172,12 +2172,12 @@
|
|
|
2172
2172
|
{
|
|
2173
2173
|
"path": "docs/copy-inventory.md",
|
|
2174
2174
|
"mode": "0000644",
|
|
2175
|
-
"sha256": "
|
|
2175
|
+
"sha256": "ba0cec7ca155cae33a729aeed1bc960396f62f24119b4189070ae0ed1720e7f6"
|
|
2176
2176
|
},
|
|
2177
2177
|
{
|
|
2178
2178
|
"path": "docs/copy-registry.json",
|
|
2179
2179
|
"mode": "0000644",
|
|
2180
|
-
"sha256": "
|
|
2180
|
+
"sha256": "fa6b7f4460cd63dcd37fe69928707e6281a32a36a6a2ce1f18d430961ec51039"
|
|
2181
2181
|
},
|
|
2182
2182
|
{
|
|
2183
2183
|
"path": "docs/design/apex-pass-2-direction.md",
|
|
@@ -2707,7 +2707,7 @@
|
|
|
2707
2707
|
{
|
|
2708
2708
|
"path": "docs/module-api-changelog.md",
|
|
2709
2709
|
"mode": "0000644",
|
|
2710
|
-
"sha256": "
|
|
2710
|
+
"sha256": "b0b20c2d38f39b2de54cdc173285f2e37b582a6e94bc4b46244eed8ec5eca1cc"
|
|
2711
2711
|
},
|
|
2712
2712
|
{
|
|
2713
2713
|
"path": "docs/modules-contract.md",
|
|
@@ -4722,7 +4722,7 @@
|
|
|
4722
4722
|
{
|
|
4723
4723
|
"path": "modules/hall-ui/public/blockers.js",
|
|
4724
4724
|
"mode": "0000644",
|
|
4725
|
-
"sha256": "
|
|
4725
|
+
"sha256": "756983ad538385f5992d088d781bffadf495cc866ed3fca6df56ef734c53f50f"
|
|
4726
4726
|
},
|
|
4727
4727
|
{
|
|
4728
4728
|
"path": "modules/hall-ui/public/board-lib.js",
|
|
@@ -4927,7 +4927,7 @@
|
|
|
4927
4927
|
{
|
|
4928
4928
|
"path": "modules/hall-ui/public/goal-inbox.js",
|
|
4929
4929
|
"mode": "0000644",
|
|
4930
|
-
"sha256": "
|
|
4930
|
+
"sha256": "b64ea71dc70993e2d3f8e728a0c3ff6450ffb14d8bc84ea7fb6825f9758aa089"
|
|
4931
4931
|
},
|
|
4932
4932
|
{
|
|
4933
4933
|
"path": "modules/hall-ui/public/goal-map-lib.js",
|
|
@@ -6792,7 +6792,7 @@
|
|
|
6792
6792
|
{
|
|
6793
6793
|
"path": "modules/provisioning/repo-private.js",
|
|
6794
6794
|
"mode": "0000644",
|
|
6795
|
-
"sha256": "
|
|
6795
|
+
"sha256": "aa3e794ed904157f8549d6ab8ce28ae4a9fa3c2235758b59fc4bd3a66a3b7049"
|
|
6796
6796
|
},
|
|
6797
6797
|
{
|
|
6798
6798
|
"path": "modules/provisioning/routes/body-validators.js",
|
|
@@ -8147,12 +8147,12 @@
|
|
|
8147
8147
|
{
|
|
8148
8148
|
"path": "package-lock.json",
|
|
8149
8149
|
"mode": "0000644",
|
|
8150
|
-
"sha256": "
|
|
8150
|
+
"sha256": "d0620eae73bba11cd42473b163ad3eb1fc066cb17e4c9bbe8445517a57b20beb"
|
|
8151
8151
|
},
|
|
8152
8152
|
{
|
|
8153
8153
|
"path": "package.json",
|
|
8154
8154
|
"mode": "0000644",
|
|
8155
|
-
"sha256": "
|
|
8155
|
+
"sha256": "fe13c610a08748c99ae43a611bddad1709f43163c8c107b85fb6d8690fddbb97"
|
|
8156
8156
|
},
|
|
8157
8157
|
{
|
|
8158
8158
|
"path": "public-docs/index.html",
|
|
@@ -9132,12 +9132,12 @@
|
|
|
9132
9132
|
{
|
|
9133
9133
|
"path": "scripts/gds/provision-repo-private.js",
|
|
9134
9134
|
"mode": "0000644",
|
|
9135
|
-
"sha256": "
|
|
9135
|
+
"sha256": "1209c7ae79f6ba568d8ae5b0da28a4a52d27447d24b0faf7d8496196e0110138"
|
|
9136
9136
|
},
|
|
9137
9137
|
{
|
|
9138
9138
|
"path": "scripts/gds/provision-repo.js",
|
|
9139
9139
|
"mode": "0000644",
|
|
9140
|
-
"sha256": "
|
|
9140
|
+
"sha256": "8ed211e290daa9621ec8c5b9ee107b6eea670adf46a32655fc4aa394dba001de"
|
|
9141
9141
|
},
|
|
9142
9142
|
{
|
|
9143
9143
|
"path": "scripts/gds/provision-teardown.js",
|
|
@@ -10177,7 +10177,7 @@
|
|
|
10177
10177
|
{
|
|
10178
10178
|
"path": "src/module-api.js",
|
|
10179
10179
|
"mode": "0000644",
|
|
10180
|
-
"sha256": "
|
|
10180
|
+
"sha256": "6c31da122ca01487eb9d0e70dc06fd77f36d60d2333d0b1f8f24c2660c86c7df"
|
|
10181
10181
|
},
|
|
10182
10182
|
{
|
|
10183
10183
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10712,7 +10712,7 @@
|
|
|
10712
10712
|
{
|
|
10713
10713
|
"path": "tests/blockers_page_ui.mjs",
|
|
10714
10714
|
"mode": "0000644",
|
|
10715
|
-
"sha256": "
|
|
10715
|
+
"sha256": "83f7c78790430927c2666741036c4311e3efab3b2c28d093555e8a4c0b170a6e"
|
|
10716
10716
|
},
|
|
10717
10717
|
{
|
|
10718
10718
|
"path": "tests/bongos_cli.mjs",
|
|
@@ -13317,7 +13317,7 @@
|
|
|
13317
13317
|
{
|
|
13318
13318
|
"path": "tests/provision_repo_private.mjs",
|
|
13319
13319
|
"mode": "0000644",
|
|
13320
|
-
"sha256": "
|
|
13320
|
+
"sha256": "cd97e188c5b842b60d99b250d164a2b2da39e25fb56081064c9ec44107518356"
|
|
13321
13321
|
},
|
|
13322
13322
|
{
|
|
13323
13323
|
"path": "tests/provision_restart.mjs",
|
|
@@ -13652,7 +13652,7 @@
|
|
|
13652
13652
|
{
|
|
13653
13653
|
"path": "tests/rot_inbox.mjs",
|
|
13654
13654
|
"mode": "0000644",
|
|
13655
|
-
"sha256": "
|
|
13655
|
+
"sha256": "7611e8595f5ea2b314d92d756c15ba8dfc6843daf32c0130e00ed13a24fe38b8"
|
|
13656
13656
|
},
|
|
13657
13657
|
{
|
|
13658
13658
|
"path": "tests/route_permission_check.mjs",
|
|
@@ -54,7 +54,9 @@ best-effort revokes the key by title. Pushes keep preferring the owner-token HTT
|
|
|
54
54
|
**Progress (2026-09-23):** the runner half has landed — task 1004167 let the wiring run
|
|
55
55
|
before a flip (`intendedPrivate`), and task 1004193 added the `repo-private` intent whose
|
|
56
56
|
runner leg wires the key and only then flips. The refusal stays until task 1003078 adds the
|
|
57
|
-
route and the manage-page control that enqueue it.
|
|
57
|
+
route and the manage-page control that enqueue it. **That route is owner-only** (owner
|
|
58
|
+
decision, task 1004194): the runner acts with the owner's stored GitHub token whoever
|
|
59
|
+
queued the intent, so an archon override would act on another person's GitHub account.
|
|
58
60
|
- Builder **dev boxes** of a private-repo project were parked here as out of scope.
|
|
59
61
|
**Answered on hardware 2026-08-25 (task 1003247): a box CAN read the private repo, and the
|
|
60
62
|
auth design needed no change.** The GDS-backed credential helper (`otb-git-credential`,
|
package/docs/copy-inventory.md
CHANGED
|
@@ -590,7 +590,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
590
590
|
| `f192ff6563f9` | certain | Leave your GitHub username and an Archon will let you in. No coding needed to start — once you're approved, si | `modules/hall-ui/public/hall-render.js:294` |
|
|
591
591
|
| `d6a78b9e5368` | certain | Let it be for now | `modules/hall-ui/public/studio.js:204` |
|
|
592
592
|
| `d6a78b9e5368` | certain | Let it be for now | `modules/hall-ui/public/studio.js:219` |
|
|
593
|
-
| `b8ba1fa4457c` | certain | Link a task | `modules/hall-ui/public/blockers.js:
|
|
593
|
+
| `b8ba1fa4457c` | certain | Link a task | `modules/hall-ui/public/blockers.js:146` |
|
|
594
594
|
| `43660902bf79` | certain | Link copied. | `modules/hall-ui/public/drachmae.js:332` |
|
|
595
595
|
| `a53e0cde7ff7` | certain | Link first — your rank role is set the moment you join. | `modules/hall-ui/public/settings.js:840` |
|
|
596
596
|
| `64e85f1691f9` | certain | Link your Discord account and you're added to the {{worldName}} server with your rank role already set — no in | `modules/hall-ui/public/settings.html:61` |
|
|
@@ -862,7 +862,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
862
862
|
| `a030881168b5` | certain | Reset to default | `modules/hall-ui/public/government.js:267` |
|
|
863
863
|
| `fd89b5be9d3b` | certain | Reset zoom to fit | `modules/hall-ui/public/diagram-viewer.js:97` |
|
|
864
864
|
| `9d9567d1dead` | certain | Reset {…} to its default permissions?\n\nEvery change you've made to this rank is discarded, and it takes effe | `modules/hall-ui/public/government.js:293` |
|
|
865
|
-
| `10d8f8c501b0` | certain | Resolution note (optional) | `modules/hall-ui/public/blockers.js:
|
|
865
|
+
| `10d8f8c501b0` | certain | Resolution note (optional) | `modules/hall-ui/public/blockers.js:129` |
|
|
866
866
|
| `10d8f8c501b0` | certain | Resolution note (optional) | `modules/hall-ui/public/task-detail.js:207` |
|
|
867
867
|
| `3ef9382d4726` | certain | Resolved — the copy was changed | `modules/hall-ui/public/copy-desk.html:122` |
|
|
868
868
|
| `0887725744f2` | certain | Restricted. | `modules/hall-ui/public/board-room.js:521` |
|
|
@@ -972,7 +972,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
972
972
|
| `1e40f33483eb` | certain | Switch theme | `modules/hall-ui/public/shell.js:486` |
|
|
973
973
|
| `93fa2e97dd35` | certain | System default for this skill | `modules/hall-ui/public/settings.js:72` |
|
|
974
974
|
| `4894b1d9b0de` | certain | System oversight: people, operations and security. | `modules/hall-ui/public/watch.js:1335` |
|
|
975
|
-
| `e604fc3ace79` | certain | Task # | `modules/hall-ui/public/blockers.js:
|
|
975
|
+
| `e604fc3ace79` | certain | Task # | `modules/hall-ui/public/blockers.js:137` |
|
|
976
976
|
| `a0f384b022fd` | certain | Task dependencies | `modules/hall-ui/public/goals.html:140` |
|
|
977
977
|
| `91576eb7c880` | certain | Task dependency forest — scrolls sideways inside this box | `modules/hall-ui/public/goal-forest-render.js:120` |
|
|
978
978
|
| `dfc967a63d57` | certain | Task lifecycle from backlog to shipped, showing states and transitions and the edge where credits are awarded. | `modules/hall-ui/public/diagrams.html:51` |
|
|
@@ -1406,7 +1406,7 @@ Identical copy within one surface. Sometimes right (a repeated button), sometime
|
|
|
1406
1406
|
| `1711516b4411` | certain | waiting for a nod | `modules/hall-ui/public/thinking.js:130` |
|
|
1407
1407
|
| `35be9e0923da` | certain | walks the whole path in plain language. | `modules/hall-ui/public/hall-render.js:890` |
|
|
1408
1408
|
| `17705daf7b85` | certain | what counts as passing | `modules/hall-ui/public/government.html:55` |
|
|
1409
|
-
| `96a8971a5c44` | certain | what got un-stuck | `modules/hall-ui/public/blockers.js:
|
|
1409
|
+
| `96a8971a5c44` | certain | what got un-stuck | `modules/hall-ui/public/blockers.js:130` |
|
|
1410
1410
|
| `96a8971a5c44` | certain | what got un-stuck | `modules/hall-ui/public/task-detail.js:208` |
|
|
1411
1411
|
| `3126bb540c89` | certain | what needs the owner’s decision | `modules/hall-ui/public/blockers.js:305` |
|
|
1412
1412
|
| `b1c5eaa20a9d` | certain | what the idea is, in one line | `modules/hall-ui/public/ideas.html:150` |
|
package/docs/copy-registry.json
CHANGED
|
@@ -1326,7 +1326,7 @@
|
|
|
1326
1326
|
"text": "Resolution note (optional)",
|
|
1327
1327
|
"occurrences": 2,
|
|
1328
1328
|
"at": [
|
|
1329
|
-
"modules/hall-ui/public/blockers.js:
|
|
1329
|
+
"modules/hall-ui/public/blockers.js:129",
|
|
1330
1330
|
"modules/hall-ui/public/task-detail.js:207"
|
|
1331
1331
|
]
|
|
1332
1332
|
},
|
|
@@ -1776,7 +1776,7 @@
|
|
|
1776
1776
|
"text": "what got un-stuck",
|
|
1777
1777
|
"occurrences": 2,
|
|
1778
1778
|
"at": [
|
|
1779
|
-
"modules/hall-ui/public/blockers.js:
|
|
1779
|
+
"modules/hall-ui/public/blockers.js:130",
|
|
1780
1780
|
"modules/hall-ui/public/task-detail.js:208"
|
|
1781
1781
|
]
|
|
1782
1782
|
},
|
|
@@ -6479,7 +6479,7 @@
|
|
|
6479
6479
|
"surface": "builders-hall",
|
|
6480
6480
|
"text": "Link a task",
|
|
6481
6481
|
"file": "modules/hall-ui/public/blockers.js",
|
|
6482
|
-
"line":
|
|
6482
|
+
"line": 146,
|
|
6483
6483
|
"origin": "js-markup",
|
|
6484
6484
|
"confidence": "certain"
|
|
6485
6485
|
},
|
|
@@ -8927,7 +8927,7 @@
|
|
|
8927
8927
|
"surface": "builders-hall",
|
|
8928
8928
|
"text": "Resolution note (optional)",
|
|
8929
8929
|
"file": "modules/hall-ui/public/blockers.js",
|
|
8930
|
-
"line":
|
|
8930
|
+
"line": 129,
|
|
8931
8931
|
"origin": "js-markup",
|
|
8932
8932
|
"confidence": "certain"
|
|
8933
8933
|
},
|
|
@@ -9917,7 +9917,7 @@
|
|
|
9917
9917
|
"surface": "builders-hall",
|
|
9918
9918
|
"text": "Task #",
|
|
9919
9919
|
"file": "modules/hall-ui/public/blockers.js",
|
|
9920
|
-
"line":
|
|
9920
|
+
"line": 137,
|
|
9921
9921
|
"origin": "js-markup",
|
|
9922
9922
|
"confidence": "certain"
|
|
9923
9923
|
},
|
|
@@ -13823,7 +13823,7 @@
|
|
|
13823
13823
|
"surface": "builders-hall",
|
|
13824
13824
|
"text": "what got un-stuck",
|
|
13825
13825
|
"file": "modules/hall-ui/public/blockers.js",
|
|
13826
|
-
"line":
|
|
13826
|
+
"line": 130,
|
|
13827
13827
|
"origin": "js-markup",
|
|
13828
13828
|
"confidence": "certain"
|
|
13829
13829
|
},
|
|
@@ -2430,5 +2430,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2430
2430
|
landed since 1.19.976 with no explicit bump. run 35880930697. (task 1002620)
|
|
2431
2431
|
1.19.978 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2432
2432
|
landed since 1.19.977 with no explicit bump. run 35882259144. (task 1002620)
|
|
2433
|
+
1.19.979 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2434
|
+
landed since 1.19.978 with no explicit bump. run 35887876013. (task 1002620)
|
|
2435
|
+
1.19.980 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2436
|
+
landed since 1.19.979 with no explicit bump. run 35889261972. (task 1002620)
|
|
2433
2437
|
---------------------------------------------------------------------------
|
|
2434
2438
|
```
|
|
@@ -53,6 +53,9 @@
|
|
|
53
53
|
var body = document.getElementById('blockers-body');
|
|
54
54
|
var countPill = document.getElementById('blockers-count');
|
|
55
55
|
var sub = document.getElementById('blockers-sub');
|
|
56
|
+
// The reason-for-blockers prose lives ONLY in blockers.html; JS restores what
|
|
57
|
+
// the markup shipped instead of carrying a second copy that can drift.
|
|
58
|
+
var baseSub = sub ? sub.textContent : '';
|
|
56
59
|
var fileArea = document.getElementById('blockers-file-area');
|
|
57
60
|
|
|
58
61
|
// The generated typed client (task-detail.js's own pattern), result-mode so
|
|
@@ -203,10 +206,7 @@
|
|
|
203
206
|
function paintHeadline() {
|
|
204
207
|
if (countPill) { countPill.textContent = String(state.total); countPill.hidden = state.total === 0; }
|
|
205
208
|
if (sub) {
|
|
206
|
-
sub.textContent = state.total
|
|
207
|
-
? (state.total === 1 ? 'One thing' : state.total + ' things') + ' stuck on the owner — a credential, a '
|
|
208
|
-
+ 'purchase, a product call only they can make. Resolving one un-sticks every task waiting on it automatically.'
|
|
209
|
-
: 'Nothing is stuck on the owner right now.';
|
|
209
|
+
sub.textContent = state.total ? baseSub : 'Nothing is stuck on the owner right now.';
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -278,7 +278,7 @@
|
|
|
278
278
|
const more = count > 5 ? `<p class="ginbox__pending">…${count - 5} more awaiting a nod.</p>` : '';
|
|
279
279
|
box.innerHTML = '<h3 class="ginbox__sec-h">Reported work awaiting a nod '
|
|
280
280
|
+ `<span class="count-pill">${count}</span></h3>`
|
|
281
|
-
+ `<ul class="
|
|
281
|
+
+ `<ul class="ginbox">${rows.slice(0, 5).map(nodRowHtml).join('')}</ul>${more}`;
|
|
282
282
|
}
|
|
283
283
|
window.OTBAttention?.refresh();
|
|
284
284
|
}
|
|
@@ -358,7 +358,7 @@
|
|
|
358
358
|
const more = count > 5 ? `<p class="ginbox__pending">…${count - 5} more awaiting an answer.</p>` : '';
|
|
359
359
|
box.innerHTML = '<h3 class="ginbox__sec-h">Was this removed? '
|
|
360
360
|
+ `<span class="count-pill">${count}</span></h3>`
|
|
361
|
-
+ `<ul class="
|
|
361
|
+
+ `<ul class="ginbox">${rows.slice(0, 5).map(removalRowHtml).join('')}</ul>${more}`;
|
|
362
362
|
}
|
|
363
363
|
window.OTBAttention?.refresh();
|
|
364
364
|
}
|
|
@@ -457,7 +457,7 @@
|
|
|
457
457
|
: `<span class="ginbox__sub"> — untouched ${escapeHtml(String(t.rot_days ?? '?'))}+ days</span>`;
|
|
458
458
|
box.innerHTML = '<h3 class="ginbox__sec-h">Going quiet '
|
|
459
459
|
+ `<span class="count-pill">${rows.length}</span>${timerNote}</h3>`
|
|
460
|
-
+ `<ul class="
|
|
460
|
+
+ `<ul class="ginbox">${shown.map(rotRowHtml).join('')}</ul>${more}`;
|
|
461
461
|
window.OTBAttention?.refresh();
|
|
462
462
|
}
|
|
463
463
|
|
|
@@ -19,6 +19,11 @@ const provisioning = require('./provisioning');
|
|
|
19
19
|
// { conflict: 'open_intent' } rather than racing a standup, teardown or settings push over
|
|
20
20
|
// the same checkout. The partial unique index ux_provisioning_intents_open stays the
|
|
21
21
|
// arbiter if two requests interleave.
|
|
22
|
+
//
|
|
23
|
+
// The caller is the ONLY authorization: the runner flips with the owner's stored GitHub
|
|
24
|
+
// token whatever `requestedBy` says. So a route calling this is OWNER-ONLY, with no archon
|
|
25
|
+
// override — unlike restart, this acts on the owner's own GitHub account (owner decision
|
|
26
|
+
// 2026-09-23, task 1004194).
|
|
22
27
|
async function enqueueRepoPrivate(db, instanceId, requestedBy) {
|
|
23
28
|
const { intent, created } = await provisioning.enqueueIntent(db, instanceId, 'repo-private', requestedBy);
|
|
24
29
|
if (created) return { intent, created: true };
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.980",
|
|
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.980",
|
|
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.980",
|
|
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",
|
|
@@ -28,6 +28,12 @@ const { REPO_ROOT } = require('./provision-config.js');
|
|
|
28
28
|
const { parseTargetRef, resolveOwnerGithubToken } = require('./provision-repo-auth.js');
|
|
29
29
|
const { ensurePrivateRepoAccess } = require('./provision-repo.js');
|
|
30
30
|
|
|
31
|
+
// A failed shell step (execSync: stderr/output) or file read (a Node system error: syscall)
|
|
32
|
+
// carries the command line, box paths and stderr in its message. It never reaches the
|
|
33
|
+
// owner's card; a GithubApiError, or a fetch error whose syscall sits on its own cause,
|
|
34
|
+
// matches neither.
|
|
35
|
+
const isBoxFailure = (e) => !!e && (e.stderr !== undefined || Array.isArray(e.output) || typeof e.syscall === 'string');
|
|
36
|
+
|
|
31
37
|
async function repoPrivateInstance(inst, deps) {
|
|
32
38
|
const { db, provisioning, log, apply } = deps;
|
|
33
39
|
log(`repo-private ${inst.slug} (shape=${inst.hosting_shape}, status=${inst.status})`);
|
|
@@ -47,6 +53,10 @@ async function repoPrivateInstance(inst, deps) {
|
|
|
47
53
|
try {
|
|
48
54
|
wired = await ensurePrivateRepoAccess(inst, { ...deps, intendedPrivate: true });
|
|
49
55
|
} catch (e) {
|
|
56
|
+
if (isBoxFailure(e) || isBoxFailure(e && e.cause)) {
|
|
57
|
+
log(` [repo-private] deploy-key setup failed on the box: ${(e && e.message) || e}`);
|
|
58
|
+
return { ok: false, error: `${repo.owner}/${repo.name} is still public: its deploy key could not be set up on the server. Nothing on your side caused this, and trying again is safe.` };
|
|
59
|
+
}
|
|
50
60
|
return { ok: false, error: (e && e.message) || String(e) };
|
|
51
61
|
}
|
|
52
62
|
if (!apply) {
|
|
@@ -877,9 +877,9 @@ function deployKeyPath(inst) { return path.posix.join(standaloneRoot(inst), '.gi
|
|
|
877
877
|
// widens only WHEN we wire: the key stays read-only and repository ADMIN is still
|
|
878
878
|
// required. It also HARDENS the two soft skips — no credential, GitHub unreachable —
|
|
879
879
|
// into refusals, because a caller that has committed to flipping cannot be handed an
|
|
880
|
-
// unwired checkout.
|
|
881
|
-
//
|
|
882
|
-
//
|
|
880
|
+
// unwired checkout. Its one caller is the `repo-private` runner leg
|
|
881
|
+
// (provision-repo-private.js, task 1004193); the owner-facing route that enqueues that
|
|
882
|
+
// intent is what remains (split (c) of task 1003078).
|
|
883
883
|
async function ensurePrivateRepoAccess(inst, deps) {
|
|
884
884
|
const { log, apply } = deps;
|
|
885
885
|
const exec = deps.controlExec || deps.exec;
|
|
@@ -1011,7 +1011,7 @@ async function ensurePrivateRepoAccess(inst, deps) {
|
|
|
1011
1011
|
throw new Error(`repository access is not admin: your granted credential can read ${repo.owner}/${repo.name}, but registering its deploy key needs repository ADMIN. Ask a repository admin to raise your access (or make the repository public), then try again.`);
|
|
1012
1012
|
}
|
|
1013
1013
|
// Plain sentence for the owner card — a transient GitHub hiccup must not read as jargon.
|
|
1014
|
-
throw new Error(`deploy-key setup failed for ${repo.owner}/${repo.name}: ${e && e.message}. Nothing is wrong on your side — try again, and if it keeps failing make the repository public and retry
|
|
1014
|
+
throw new Error(`deploy-key setup failed for ${repo.owner}/${repo.name}: ${e && e.message}. Nothing is wrong on your side — try again, and if it keeps failing make the repository public and retry.`, { cause: e });
|
|
1015
1015
|
}
|
|
1016
1016
|
exec(`git -C ${root} remote set-url origin git@github.com:${repo.owner}/${repo.name}.git`);
|
|
1017
1017
|
exec(`git -C ${root} config core.sshCommand "ssh -F /dev/null -i ${keyPath} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"`);
|
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.980'; // 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');
|
|
@@ -323,4 +323,10 @@ await test('resolving through the shared #/blocker/N overlay (otb:blocker-resolv
|
|
|
323
323
|
assert.equal(after, before + 1, 'the queue re-fetched exactly once in response to the event');
|
|
324
324
|
});
|
|
325
325
|
|
|
326
|
+
await test('the sub-line reason prose has ONE source (blockers.html); JS never carries a copy (task 1003985)', () => {
|
|
327
|
+
const html = fs.readFileSync(path.join(HALL, 'blockers.html'), 'utf8');
|
|
328
|
+
assert.match(html, /Resolving one un-sticks every task waiting on it/, 'the static sub-line keeps the prose');
|
|
329
|
+
assert.doesNotMatch(BLOCKERS_JS_SRC, /un-sticks|only they can make/, 'blockers.js must not duplicate the prose');
|
|
330
|
+
});
|
|
331
|
+
|
|
326
332
|
summary();
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
|
|
23
23
|
import { strict as assert } from 'node:assert';
|
|
24
24
|
import { createRequire } from 'node:module';
|
|
25
|
+
import { execSync } from 'node:child_process';
|
|
26
|
+
import { readFileSync } from 'node:fs';
|
|
25
27
|
|
|
26
28
|
const require = createRequire(import.meta.url);
|
|
27
29
|
const P = require('../scripts/gds/provision.js');
|
|
@@ -128,6 +130,58 @@ await ta('GitHub unreachable during the wiring: ok:false (a retry), never a thro
|
|
|
128
130
|
assert.equal(r.at(isFlip), -1);
|
|
129
131
|
});
|
|
130
132
|
|
|
133
|
+
console.log('\nrunner leg — a failure on the box never reaches the owner\'s card verbatim:');
|
|
134
|
+
|
|
135
|
+
// Real Node error objects, not hand-built lookalikes: the leg recognises a box failure by
|
|
136
|
+
// its shape, so the test must throw the shape execSync and fs actually produce.
|
|
137
|
+
function realExecError() {
|
|
138
|
+
try { execSync(`"${process.execPath}" -e "process.stderr.write('Saving key /home/runner/.ssh/deploy-demo failed');process.exit(3)"`, { stdio: 'pipe' }); }
|
|
139
|
+
catch (e) { return e; }
|
|
140
|
+
throw new Error('expected the child to fail');
|
|
141
|
+
}
|
|
142
|
+
function realFsError() {
|
|
143
|
+
try { readFileSync('/srv/instances/demo/.ssh/no-such-key.pub'); } catch (e) { return e; }
|
|
144
|
+
throw new Error('expected the read to fail');
|
|
145
|
+
}
|
|
146
|
+
const BOX_DETAIL = /Command failed|process\.exit|[\\/]home[\\/]runner|[\\/]srv[\\/]instances|ENOENT|ssh-keygen|stderr/;
|
|
147
|
+
|
|
148
|
+
for (const [label, patch] of [
|
|
149
|
+
['ssh-keygen fails while minting the key', (d) => { d.exec = (cmd) => { if (/ssh-keygen/.test(cmd)) throw realExecError(); return { ok: true, stdout: '' }; }; }],
|
|
150
|
+
['git config fails while wiring the checkout', (d) => { d.exec = (cmd) => { if (/core\.sshCommand/.test(cmd)) throw realExecError(); return { ok: true, stdout: '' }; }; }],
|
|
151
|
+
['the new key file cannot be read', (d) => { d.fsImpl = { ...d.fsImpl, readFileSync: () => { throw realFsError(); } }; }],
|
|
152
|
+
['ssh-keygen fails on the key-in-use retry (wrapped as a deploy-key setup failure)', (d) => {
|
|
153
|
+
d.githubRepos = { ...d.githubRepos, addDeployKey: async () => { throw Object.assign(new Error('GitHub refused the key — it is already registered somewhere'), { code: 'key_in_use', status: 422 }); } };
|
|
154
|
+
let keygens = 0;
|
|
155
|
+
d.exec = (cmd) => { if (/ssh-keygen/.test(cmd) && ++keygens === 2) throw realExecError(); return { ok: true, stdout: '' }; };
|
|
156
|
+
}],
|
|
157
|
+
]) {
|
|
158
|
+
await ta(`${label}: a fixed sentence — no command line, box path or stderr — and NO flip`, async () => {
|
|
159
|
+
// Arrange
|
|
160
|
+
const r = recorder();
|
|
161
|
+
patch(r.deps);
|
|
162
|
+
// Act
|
|
163
|
+
const out = await repoPrivateInstance(liveStandalone, r.deps);
|
|
164
|
+
// Assert
|
|
165
|
+
assert.equal(out.ok, false);
|
|
166
|
+
assert.doesNotMatch(out.error, BOX_DETAIL, out.error);
|
|
167
|
+
assert.match(out.error, /example-owner\/demo is still public/);
|
|
168
|
+
assert.match(out.error, /trying again is safe/);
|
|
169
|
+
assert.equal(r.at(isFlip), -1, 'nothing was flipped');
|
|
170
|
+
assert.ok(r.logs.some((l) => /\[repo-private\]/.test(l) && BOX_DETAIL.test(l)), 'the raw detail goes to the runner log for the operator');
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
await ta('a GitHub network failure during key registration keeps its GitHub sentence — not mistaken for a box failure', async () => {
|
|
175
|
+
// fetch's own error hangs the socket detail (syscall) one level down, on its cause.
|
|
176
|
+
const fetchFailed = Object.assign(new TypeError('fetch failed'), { cause: Object.assign(new Error('connect ECONNREFUSED'), { code: 'ECONNREFUSED', syscall: 'connect' }) });
|
|
177
|
+
const r = recorder();
|
|
178
|
+
r.deps.githubRepos = { ...r.deps.githubRepos, listDeployKeys: async () => { throw fetchFailed; } };
|
|
179
|
+
const out = await repoPrivateInstance(liveStandalone, r.deps);
|
|
180
|
+
assert.equal(out.ok, false);
|
|
181
|
+
assert.match(out.error, /deploy-key setup failed for example-owner\/demo: fetch failed/);
|
|
182
|
+
assert.equal(r.at(isFlip), -1);
|
|
183
|
+
});
|
|
184
|
+
|
|
131
185
|
await ta('the flip itself refused (403): ok:false, says the repository is STILL public and a retry is safe', async () => {
|
|
132
186
|
const e = Object.assign(new Error('GitHub refused the change for this account'), { code: 'not_repo_admin', status: 403 });
|
|
133
187
|
const r = recorder({ flipFails: e });
|
package/tests/rot_inbox.mjs
CHANGED
|
@@ -616,6 +616,16 @@ test('row builders emit the CSS classes style.css actually defines, not ginbox__
|
|
|
616
616
|
'rotRowHtml must emit the defined ginbox__body/ginbox__actions classes');
|
|
617
617
|
});
|
|
618
618
|
|
|
619
|
+
test('the nod, removal and rot lists use the defined .ginbox list class, not ginbox__list (task 1003982)', () => {
|
|
620
|
+
assert.match(STYLE_SRC, /^\.ginbox\s*\{[^}]*list-style:\s*none/m, 'style.css must define .ginbox with list-style: none');
|
|
621
|
+
assert.doesNotMatch(GOAL_INBOX_SRC, /ginbox__list/,
|
|
622
|
+
'.ginbox__list is undefined in style.css — with it the browser default bullets and 40px indent leak through');
|
|
623
|
+
for (const fn of ['nodRowHtml', 'removalRowHtml', 'rotRowHtml']) {
|
|
624
|
+
assert.match(GOAL_INBOX_SRC, new RegExp(`<ul class="ginbox">\\$\\{[^\\n]*?map\\(${fn}\\)`),
|
|
625
|
+
`the list built from ${fn} must be <ul class="ginbox">`);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
|
|
619
629
|
test('acting on a rot line refreshes the ROT slice, not the goals list', () => {
|
|
620
630
|
assert.match(GOAL_INBOX_SRC, /ROT_TOASTS\[verb\] \|\| 'Done\.', loadRot\)/,
|
|
621
631
|
'refreshing the wrong slice leaves the acted-on row sitting there — the task-1003066 lesson');
|