@bongos/core 1.19.958 → 1.19.960
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 +14 -14
- package/docs/module-api-changelog.md +4 -0
- package/modules/government/protected-surfaces.json +35 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/claude-materialize.js +27 -4
- package/src/bongos/module-scope-map.js +12 -0
- package/src/module-api.js +1 -1
- package/tests/claude_materialize.mjs +53 -2
- package/tests/government_protected_surfaces.mjs +81 -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.960",
|
|
6
|
+
"core_contract": "1.19.960",
|
|
7
|
+
"source_commit": "07224a002beb8673193550edb973a83f63733ac9",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-22T16:38:38.841Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 514,
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
19
|
"file_count": 2898,
|
|
20
|
-
"tree_sha256": "
|
|
20
|
+
"tree_sha256": "de8dc0908595fb0f613026497e94dc03c3a50bb631a2adc952bdaefedcb96199",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2692,7 +2692,7 @@
|
|
|
2692
2692
|
{
|
|
2693
2693
|
"path": "docs/module-api-changelog.md",
|
|
2694
2694
|
"mode": "0000644",
|
|
2695
|
-
"sha256": "
|
|
2695
|
+
"sha256": "4cc28a5f552998a430d1d1ecb6ec1882607ccd555f5d2e01c7a2197b6414b67a"
|
|
2696
2696
|
},
|
|
2697
2697
|
{
|
|
2698
2698
|
"path": "docs/modules-contract.md",
|
|
@@ -4497,7 +4497,7 @@
|
|
|
4497
4497
|
{
|
|
4498
4498
|
"path": "modules/government/protected-surfaces.json",
|
|
4499
4499
|
"mode": "0000644",
|
|
4500
|
-
"sha256": "
|
|
4500
|
+
"sha256": "ad15115c455dc9eb8b7786ce704beb94b5c40fabe17806e88b5edffb20b164cf"
|
|
4501
4501
|
},
|
|
4502
4502
|
{
|
|
4503
4503
|
"path": "modules/government/ranks.js",
|
|
@@ -8082,12 +8082,12 @@
|
|
|
8082
8082
|
{
|
|
8083
8083
|
"path": "package-lock.json",
|
|
8084
8084
|
"mode": "0000644",
|
|
8085
|
-
"sha256": "
|
|
8085
|
+
"sha256": "f1832d9a38929a6d0cd0a93720088edcba0cc7952bbe2df7d57ec0986c1dea49"
|
|
8086
8086
|
},
|
|
8087
8087
|
{
|
|
8088
8088
|
"path": "package.json",
|
|
8089
8089
|
"mode": "0000644",
|
|
8090
|
-
"sha256": "
|
|
8090
|
+
"sha256": "98d101c939c100960c78ea1887fd429720d643c3931840ac847df15544312e72"
|
|
8091
8091
|
},
|
|
8092
8092
|
{
|
|
8093
8093
|
"path": "public-docs/index.html",
|
|
@@ -8432,7 +8432,7 @@
|
|
|
8432
8432
|
{
|
|
8433
8433
|
"path": "scripts/gds/claude-materialize.js",
|
|
8434
8434
|
"mode": "0000644",
|
|
8435
|
-
"sha256": "
|
|
8435
|
+
"sha256": "717de4da1c2e966aff2cb8dff997a4cedcf5d92eea85a9ceeb75118bef1f6859"
|
|
8436
8436
|
},
|
|
8437
8437
|
{
|
|
8438
8438
|
"path": "scripts/gds/claude-md-template.js",
|
|
@@ -9897,7 +9897,7 @@
|
|
|
9897
9897
|
{
|
|
9898
9898
|
"path": "src/bongos/module-scope-map.js",
|
|
9899
9899
|
"mode": "0000644",
|
|
9900
|
-
"sha256": "
|
|
9900
|
+
"sha256": "70b35812cbf26b9ce8c25663bbc4fcce40272b4877b89baf70cd64a5fe90b3b3"
|
|
9901
9901
|
},
|
|
9902
9902
|
{
|
|
9903
9903
|
"path": "src/bongos/module-submissions.js",
|
|
@@ -10092,7 +10092,7 @@
|
|
|
10092
10092
|
{
|
|
10093
10093
|
"path": "src/module-api.js",
|
|
10094
10094
|
"mode": "0000644",
|
|
10095
|
-
"sha256": "
|
|
10095
|
+
"sha256": "23025d957268d4f44b0a2a8a552f1371a9c50af1220239de8ca3fd9b0bd605f3"
|
|
10096
10096
|
},
|
|
10097
10097
|
{
|
|
10098
10098
|
"path": "src/module-loader/catalog.js",
|
|
@@ -10872,7 +10872,7 @@
|
|
|
10872
10872
|
{
|
|
10873
10873
|
"path": "tests/claude_materialize.mjs",
|
|
10874
10874
|
"mode": "0000644",
|
|
10875
|
-
"sha256": "
|
|
10875
|
+
"sha256": "0f0d53e5c63f9b776aa5ea9c2e0408e350e54230ee0c214af26faf34eaa7bb5f"
|
|
10876
10876
|
},
|
|
10877
10877
|
{
|
|
10878
10878
|
"path": "tests/clawback_confirmed_backlog.mjs",
|
|
@@ -11777,7 +11777,7 @@
|
|
|
11777
11777
|
{
|
|
11778
11778
|
"path": "tests/government_protected_surfaces.mjs",
|
|
11779
11779
|
"mode": "0000644",
|
|
11780
|
-
"sha256": "
|
|
11780
|
+
"sha256": "4299e738542cd8951ec9846c4add158e902cb2ad29deba6c4afbfdb2b94877bf"
|
|
11781
11781
|
},
|
|
11782
11782
|
{
|
|
11783
11783
|
"path": "tests/government_rank_sync.mjs",
|
|
@@ -2390,5 +2390,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
2390
2390
|
landed since 1.19.956 with no explicit bump. run 35692861666. (task 1002620)
|
|
2391
2391
|
1.19.958 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2392
2392
|
landed since 1.19.957 with no explicit bump. run 35735231183. (task 1002620)
|
|
2393
|
+
1.19.959 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2394
|
+
landed since 1.19.958 with no explicit bump. run 35740227000. (task 1002620)
|
|
2395
|
+
1.19.960 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
2396
|
+
landed since 1.19.959 with no explicit bump. run 35755397900. (task 1002620)
|
|
2393
2397
|
---------------------------------------------------------------------------
|
|
2394
2398
|
```
|
|
@@ -26,7 +26,13 @@
|
|
|
26
26
|
"permission": "path.protected.modify",
|
|
27
27
|
"surfaces": [
|
|
28
28
|
{ "glob": "src/bongos/auth.js", "group": "authz", "why": "requireBuilder / requireRank definitions" },
|
|
29
|
+
{ "glob": "src/bongos/auth-admission.js", "group": "authz", "why": "task 1004024. Carved out of auth.js (task 1003206): the OAuth flows, session-token minting, admission and IdP checks auth.js now delegates to. Registering auth.js alone protected the facade and none of them." },
|
|
30
|
+
{ "glob": "src/bongos/auth-config.js", "group": "authz", "why": "task 1004024. Carved out of auth.js (task 1003206): the OAuth flows, session-token minting, admission and IdP checks auth.js now delegates to. Registering auth.js alone protected the facade and none of them." },
|
|
31
|
+
{ "glob": "src/bongos/auth-discord.js", "group": "authz", "why": "task 1004024. Carved out of auth.js (task 1003206): the OAuth flows, session-token minting, admission and IdP checks auth.js now delegates to. Registering auth.js alone protected the facade and none of them." },
|
|
32
|
+
{ "glob": "src/bongos/auth-github.js", "group": "authz", "why": "task 1004024. Carved out of auth.js (task 1003206): the OAuth flows, session-token minting, admission and IdP checks auth.js now delegates to. Registering auth.js alone protected the facade and none of them." },
|
|
33
|
+
{ "glob": "src/bongos/auth-idp.js", "group": "authz", "why": "task 1004024. Carved out of auth.js (task 1003206): the OAuth flows, session-token minting, admission and IdP checks auth.js now delegates to. Registering auth.js alone protected the facade and none of them." },
|
|
29
34
|
{ "glob": "src/bongos/db.js", "group": "authz", "why": "rank tiers, REQUIRES_RANK_TIER — the CASE edited in the SEC #863 incident" },
|
|
35
|
+
{ "glob": "src/bongos/db-kernel.js", "group": "authz", "why": "task 1004024. The kernel db slice carved out of db.js (BV1.R69 / ADR 0091): builder identity and the rank reads the SEC #863 entry above exists for." },
|
|
30
36
|
{ "glob": "src/bongos/route-rank-check.js", "group": "authz", "why": "the route-gate auditor" },
|
|
31
37
|
{ "glob": "src/bongos/permission-path-check.js", "group": "authz", "why": "the matcher that reads this registry (self-protect)" },
|
|
32
38
|
{ "glob": "src/bongos/middleware/", "group": "authz", "why": "audit + any auth middleware" },
|
|
@@ -43,11 +49,40 @@
|
|
|
43
49
|
{ "glob": "scripts/gds/box-infra.js", "group": "box-access", "why": "task 1002891. CREDENTIAL READER: reads process.env.CLOUDFLARE_API_TOKEN and process.env.CLOUDFLARE_ACCOUNT_ID into the CF config the box plane provisions against." },
|
|
44
50
|
{ "glob": "scripts/gds/cf-tunnel.js", "group": "box-access", "why": "task 1002891. CREDENTIAL READER: defaults its token parameter to process.env.CLOUDFLARE_API_TOKEN, so it reads the credential whenever a caller omits one. Not named by the recorded decision — the recomputation found it, which is the whole argument for computing the set instead of transcribing it." },
|
|
45
51
|
{ "glob": "scripts/gds/box.js", "group": "box-access", "why": "task 1002891. CREDENTIAL READER: reads process.env.DO_API_TOKEN — the DigitalOcean control plane for the box fleet. Also not named by the recorded decision. Registering it does NOT widen any module wall: the dev-box module key already lists this file and already derives protected:true from the modules/dev-box/ entries above, so the derived protected-module set is unchanged (verified before and after against src/bongos/module-scope-map.js)." },
|
|
52
|
+
{ "glob": "scripts/gds/box-auth-check.js", "group": "box-access", "why": "task 1004024. Split out of the box.js family and never registered; box-infra.js was already listed by name above." },
|
|
53
|
+
{ "glob": "scripts/gds/box-sync.js", "group": "box-access", "why": "task 1004024. Split out of the box.js family and never registered; box-infra.js was already listed by name above." },
|
|
46
54
|
{ "glob": "scripts/gds/do-api.js", "group": "box-access", "why": "task 1002891. The DigitalOcean API client the token is handed TO. Unlike the five above it reads no process.env value — it takes the token as a parameter and throws when a live call has none — so the drift tripwire does not demand it and its absence from that computed set is expected, not a bug. It is registered because the recorded decision named it and because it is the code that puts the credential on the wire." },
|
|
47
55
|
{ "glob": "modules/grading/grader.js", "group": "pipeline", "why": "BV1.R73: grading carved to modules/grading/ — the glob follows the file" },
|
|
56
|
+
{ "glob": "modules/grading/grader-config.js", "group": "pipeline", "why": "task 1004024. Carved out of grader.js: the deterministic permission-path pre-pass, the server-side score guards a model cannot talk past, the subagent spawn and the prompt. grader.js alone protected the facade and none of the gate." },
|
|
57
|
+
{ "glob": "modules/grading/grader-model.js", "group": "pipeline", "why": "task 1004024. Carved out of grader.js: the deterministic permission-path pre-pass, the server-side score guards a model cannot talk past, the subagent spawn and the prompt. grader.js alone protected the facade and none of the gate." },
|
|
58
|
+
{ "glob": "modules/grading/grader-no-artifact.js", "group": "pipeline", "why": "task 1004024. Carved out of grader.js: the deterministic permission-path pre-pass, the server-side score guards a model cannot talk past, the subagent spawn and the prompt. grader.js alone protected the facade and none of the gate." },
|
|
59
|
+
{ "glob": "modules/grading/grader-prompt.js", "group": "pipeline", "why": "task 1004024. Carved out of grader.js: the deterministic permission-path pre-pass, the server-side score guards a model cannot talk past, the subagent spawn and the prompt. grader.js alone protected the facade and none of the gate." },
|
|
60
|
+
{ "glob": "modules/grading/grader-score.js", "group": "pipeline", "why": "task 1004024. Carved out of grader.js: the deterministic permission-path pre-pass, the server-side score guards a model cannot talk past, the subagent spawn and the prompt. grader.js alone protected the facade and none of the gate." },
|
|
61
|
+
{ "glob": "modules/grading/grader-subagent.js", "group": "pipeline", "why": "task 1004024. Carved out of grader.js: the deterministic permission-path pre-pass, the server-side score guards a model cannot talk past, the subagent spawn and the prompt. grader.js alone protected the facade and none of the gate." },
|
|
48
62
|
{ "glob": "modules/grading/grader-workers/", "group": "pipeline", "why": "the adversarial panel (Narc/Hacker/Quality/Efficiency) — blunting these blunts the gate" },
|
|
49
63
|
{ "glob": "modules/grading/grader-rubric.json", "group": "pipeline", "why": "the grader's scoring rubric (ADR 0058)" },
|
|
50
64
|
{ "glob": "scripts/gds/ship.js", "group": "pipeline", "why": "the ship lifecycle driver" },
|
|
65
|
+
{ "glob": "scripts/gds/ship-check.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
66
|
+
{ "glob": "scripts/gds/ship-deploy-target.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
67
|
+
{ "glob": "scripts/gds/ship-escalation.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
68
|
+
{ "glob": "scripts/gds/ship-finish.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
69
|
+
{ "glob": "scripts/gds/ship-flow.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
70
|
+
{ "glob": "scripts/gds/ship-git.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
71
|
+
{ "glob": "scripts/gds/ship-grade-steps.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
72
|
+
{ "glob": "scripts/gds/ship-grade.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
73
|
+
{ "glob": "scripts/gds/ship-honesty.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
74
|
+
{ "glob": "scripts/gds/ship-io.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
75
|
+
{ "glob": "scripts/gds/ship-land.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
76
|
+
{ "glob": "scripts/gds/ship-memory-sync.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
77
|
+
{ "glob": "scripts/gds/ship-merge-gate.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
78
|
+
{ "glob": "scripts/gds/ship-merge.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
79
|
+
{ "glob": "scripts/gds/ship-preflight-steps.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
80
|
+
{ "glob": "scripts/gds/ship-regen.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
81
|
+
{ "glob": "scripts/gds/ship-resume.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
82
|
+
{ "glob": "scripts/gds/ship-session-upload.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
83
|
+
{ "glob": "scripts/gds/ship-state.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
84
|
+
{ "glob": "scripts/gds/ship-surprise.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
85
|
+
{ "glob": "scripts/gds/ship-visual.js", "group": "pipeline", "why": "task 1004024. The 2026-08-23 carve of ship.js (task 1003205): the land path, the ship state machine, the grade gate steps, the merge and pushVia, about 6,200 lines behind a 373-line protected entry point." },
|
|
51
86
|
{ "glob": "scripts/gds/confirm.js", "group": "pipeline", "why": "the confirm step" },
|
|
52
87
|
{ "glob": "scripts/gds/merge-mode.js", "group": "pipeline", "why": "the manual land fallback" },
|
|
53
88
|
{ "glob": "scripts/gds/ci-grade.js", "group": "pipeline", "why": "CI grade-gate driver — steers the grade check (ADR 0058)" },
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.960",
|
|
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.960",
|
|
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.960",
|
|
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",
|
|
@@ -385,12 +385,35 @@ const STARTER_COMMANDS = [
|
|
|
385
385
|
const STARTER_SHELL_TOOLS = ['Bash', 'PowerShell'];
|
|
386
386
|
const STARTER_ALLOW = STARTER_SHELL_TOOLS.flatMap((tool) => STARTER_COMMANDS.map((command) => `${tool}(${command})`));
|
|
387
387
|
|
|
388
|
+
// The deny half (task 1003966): what the local agent may not READ. Keys are the
|
|
389
|
+
// same exposure on every instance, so those rules ship verbatim.
|
|
390
|
+
const STARTER_DENY_SECRETS = [
|
|
391
|
+
'Read(.env)', 'Read(**/.env)', 'Read(.env.local)', 'Read(**/.env.local)',
|
|
392
|
+
'Read(.env.*.local)', 'Read(**/.env.*.local)',
|
|
393
|
+
'Read(**/*.pem)', 'Read(**/id_rsa*)', 'Read(**/id_ed25519*)',
|
|
394
|
+
];
|
|
395
|
+
|
|
396
|
+
// Credential files are derived from where the CLI actually reads them, not rebranded from the
|
|
397
|
+
// core's literals: the rebrand would also move the host-keyed store, which sits at a fixed anchor
|
|
398
|
+
// whatever the brand (cli-lib sessionStoreDir, task 1003741). The shelf rule is the only layer an
|
|
399
|
+
// instance gets against the repo-global stash stack, since the git-guard hook does not ship.
|
|
400
|
+
function starterDeny(branding = {}) {
|
|
401
|
+
const dirs = [...new Set([effConfigDir(branding), ...ic.LEGACY_DIRS])];
|
|
402
|
+
const credentialFiles = ['env', ...ic.SESSION_FILENAMES];
|
|
403
|
+
return [
|
|
404
|
+
...STARTER_DENY_SECRETS,
|
|
405
|
+
...dirs.flatMap((dir) => credentialFiles.map((file) => `Read(~/.config/${dir}/${file})`)),
|
|
406
|
+
`Read(~/.config/${ic.FALLBACK_DIR}/instances/**)`,
|
|
407
|
+
...STARTER_SHELL_TOOLS.map((tool) => `${tool}(git stash:*)`),
|
|
408
|
+
];
|
|
409
|
+
}
|
|
410
|
+
|
|
388
411
|
// The starter an instance gets when the core root carries no settings.json — a
|
|
389
412
|
// package-only install. Permissions ONLY: no hooks (they are topology), no env.
|
|
390
|
-
function renderStarterSettings() {
|
|
413
|
+
function renderStarterSettings(branding = {}) {
|
|
391
414
|
return `${JSON.stringify({
|
|
392
|
-
_doc: 'Starter written by scripts/gds/claude-materialize.js (
|
|
393
|
-
permissions: { allow: STARTER_ALLOW },
|
|
415
|
+
_doc: 'Starter written by scripts/gds/claude-materialize.js (tasks 1003962, 1003966). Permissions only — the blessed Bongos commands, mirroring the core repo\'s own allow-list (ADR 0104), and the deny rules that keep the local agent from reading keys and session tokens. An allow-rule lets the local agent RUN a command; it grants no authority, which the server decides per request from your live rank (ADR 0016). Yours to edit: a later materialize never clobbers this file.',
|
|
416
|
+
permissions: { allow: STARTER_ALLOW, deny: starterDeny(branding) },
|
|
394
417
|
}, null, 2)}\n`;
|
|
395
418
|
}
|
|
396
419
|
|
|
@@ -685,7 +708,7 @@ function materializeClaude({ coreRoot, instanceDir, dryRun = false, overwrite =
|
|
|
685
708
|
} else {
|
|
686
709
|
if (!dryRun) {
|
|
687
710
|
fs.mkdirSync(destClaude, { recursive: true });
|
|
688
|
-
fs.writeFileSync(settingsDest, renderStarterSettings());
|
|
711
|
+
fs.writeFileSync(settingsDest, renderStarterSettings(toBranding));
|
|
689
712
|
}
|
|
690
713
|
addWritten('.claude/settings.json');
|
|
691
714
|
summary.settings = true;
|
|
@@ -48,6 +48,9 @@ const MODULE_GLOBS = {
|
|
|
48
48
|
'src/bongos/auth.js', 'src/bongos/db.js', 'src/bongos/db-kernel.js', 'src/bongos/pool.js',
|
|
49
49
|
'src/bongos/routes.js', 'src/bongos/route-rank-check.js',
|
|
50
50
|
'src/bongos/permission-path-check.js', 'src/bongos/sensitive-surfaces.js',
|
|
51
|
+
// task 1004024: the auth.js carve (db-kernel.js, above, is db.js's), now protected.
|
|
52
|
+
'src/bongos/auth-admission.js', 'src/bongos/auth-config.js', 'src/bongos/auth-discord.js',
|
|
53
|
+
'src/bongos/auth-github.js', 'src/bongos/auth-idp.js',
|
|
51
54
|
'src/bongos/middleware/', 'src/bongos/live-channel.js', 'src/bongos/secret-box.js',
|
|
52
55
|
'src/bongos/repo-info.js', 'src/bongos/api-path-404.js', 'src/bongos/serve-internal.js',
|
|
53
56
|
'src/bongos/module-scope-map.js', 'src/bongos/hierarchy-config.js',
|
|
@@ -91,6 +94,14 @@ const MODULE_GLOBS = {
|
|
|
91
94
|
lifecycle: [
|
|
92
95
|
'modules/lifecycle/',
|
|
93
96
|
'scripts/gds/ship.js', 'scripts/gds/claim.js', 'scripts/gds/release.js',
|
|
97
|
+
// task 1004024: the 2026-08-23 ship.js carve, now protected (by name: no '*' here).
|
|
98
|
+
'scripts/gds/ship-check.js', 'scripts/gds/ship-deploy-target.js', 'scripts/gds/ship-escalation.js',
|
|
99
|
+
'scripts/gds/ship-finish.js', 'scripts/gds/ship-flow.js', 'scripts/gds/ship-git.js',
|
|
100
|
+
'scripts/gds/ship-grade-steps.js', 'scripts/gds/ship-grade.js', 'scripts/gds/ship-honesty.js',
|
|
101
|
+
'scripts/gds/ship-io.js', 'scripts/gds/ship-land.js', 'scripts/gds/ship-memory-sync.js',
|
|
102
|
+
'scripts/gds/ship-merge-gate.js', 'scripts/gds/ship-merge.js', 'scripts/gds/ship-preflight-steps.js',
|
|
103
|
+
'scripts/gds/ship-regen.js', 'scripts/gds/ship-resume.js', 'scripts/gds/ship-session-upload.js',
|
|
104
|
+
'scripts/gds/ship-state.js', 'scripts/gds/ship-surprise.js', 'scripts/gds/ship-visual.js',
|
|
94
105
|
'scripts/gds/merge-mode.js', 'scripts/gds/confirm.js', 'scripts/gds/main-audit.js',
|
|
95
106
|
'scripts/gds/gate-review.js', 'scripts/gds/push-main.js', 'scripts/gds/ci-grade.js',
|
|
96
107
|
'scripts/gds/merge-lock.js', 'scripts/gds/version-close.js',
|
|
@@ -355,6 +366,7 @@ const MODULE_GLOBS = {
|
|
|
355
366
|
'modules/dev-box/', 'devbox-app/',
|
|
356
367
|
'scripts/gds/box.js', 'scripts/gds/box-auth-check.js', 'scripts/gds/box-connect-lib.js',
|
|
357
368
|
'scripts/gds/smoke-box.sh',
|
|
369
|
+
'scripts/gds/box-sync.js', // task 1004024: split out of box.js, now protected
|
|
358
370
|
|
|
359
371
|
// ADOPTED (task 1004111): the box BRING-UP surface. box.js (already here)
|
|
360
372
|
// orchestrates these five provisioning CLIs, and infra/ is the shell-script
|
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.960'; // 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');
|
|
@@ -18,14 +18,16 @@
|
|
|
18
18
|
import { strict as assert } from 'node:assert';
|
|
19
19
|
import { createRequire } from 'node:module';
|
|
20
20
|
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync, readdirSync, rmSync } from 'node:fs';
|
|
21
|
-
import { tmpdir } from 'node:os';
|
|
22
|
-
import { join, dirname } from 'node:path';
|
|
21
|
+
import { tmpdir, homedir } from 'node:os';
|
|
22
|
+
import { join, dirname, relative, sep } from 'node:path';
|
|
23
23
|
import { fileURLToPath } from 'node:url';
|
|
24
24
|
|
|
25
25
|
const require = createRequire(import.meta.url);
|
|
26
26
|
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
27
27
|
const m = require('../scripts/gds/claude-materialize.js');
|
|
28
28
|
const claim = require('../scripts/gds/claim.js');
|
|
29
|
+
const cliLib = require('../scripts/gds/cli-lib.js');
|
|
30
|
+
const ic = require('../src/instance-config.js');
|
|
29
31
|
// The live verb table, so a starter allow-rule naming a verb that does not exist
|
|
30
32
|
// fails here rather than shipping as an inert permission (task 1003962).
|
|
31
33
|
const { VERBS: cliVerbs } = require('../bin/bongos.js');
|
|
@@ -804,6 +806,55 @@ t('a package-only install (no settings.json at the core root) GETS the starter',
|
|
|
804
806
|
rmSync(inst, { recursive: true, force: true });
|
|
805
807
|
});
|
|
806
808
|
|
|
809
|
+
// task 1003966 — the starter shipped the allow half alone: the convenience with none of the
|
|
810
|
+
// hardening. The deny half is what stops the agent reading a key or a session token.
|
|
811
|
+
const starterDenyFor = (branding) => JSON.parse(m.renderStarterSettings(branding)).permissions.deny;
|
|
812
|
+
const homeRel = (abs) => `~/${relative(homedir(), abs).split(sep).join('/')}`;
|
|
813
|
+
|
|
814
|
+
t("a package-only install gets the deny rules, pointed at THAT instance's config dir", () => {
|
|
815
|
+
const core = mkdtempSync(join(tmpdir(), 'w3-deny-core-'));
|
|
816
|
+
const inst = mkdtempSync(join(tmpdir(), 'w3-deny-inst-'));
|
|
817
|
+
mkdirSync(join(core, '.claude', 'skills'), { recursive: true });
|
|
818
|
+
mkdirSync(join(inst, 'config'), { recursive: true });
|
|
819
|
+
writeFileSync(join(inst, 'config', 'branding.json'), JSON.stringify({ configDir: 'acme', envPrefix: 'ACME' }));
|
|
820
|
+
m.materializeClaude({ coreRoot: core, instanceDir: inst, dryRun: false });
|
|
821
|
+
const deny = JSON.parse(readFileSync(join(inst, '.claude', 'settings.json'), 'utf8')).permissions.deny;
|
|
822
|
+
assert.ok(Array.isArray(deny), 'the starter must carry permissions.deny');
|
|
823
|
+
for (const secret of ['Read(**/.env)', 'Read(**/.env.*.local)', 'Read(**/*.pem)', 'Read(**/id_rsa*)']) {
|
|
824
|
+
assert.ok(deny.includes(secret), `missing ${secret}`);
|
|
825
|
+
}
|
|
826
|
+
assert.ok(deny.includes('Read(~/.config/acme/bongos-session.json)'), "the instance's OWN session file");
|
|
827
|
+
assert.deepEqual(deny.filter((r) => /\.config\/(?!acme\/)/.test(r) && !r.startsWith(`Read(${homeRel(cliLib.sessionStoreDir())}`)
|
|
828
|
+
&& !ic.LEGACY_DIRS.some((d) => r.includes(`.config/${d}/`))), [],
|
|
829
|
+
"a session rule naming another brand's dir guards the wrong path and leaves this one open");
|
|
830
|
+
for (const tool of ['Bash', 'PowerShell']) assert.ok(deny.includes(`${tool}(git stash:*)`), `${tool}(git stash:*)`);
|
|
831
|
+
rmSync(core, { recursive: true, force: true });
|
|
832
|
+
rmSync(inst, { recursive: true, force: true });
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
t('every file the CLI reads a session from is denied, the host-keyed store included', () => {
|
|
836
|
+
// Pinned to cli-lib's own read list, so a new session filename or dir fails HERE.
|
|
837
|
+
let brand = {};
|
|
838
|
+
try { brand = require('../src/branding').branding(); } catch { /* unbranded checkout */ }
|
|
839
|
+
const deny = starterDenyFor(brand);
|
|
840
|
+
for (const p of cliLib.SESSION_READ_PATHS) assert.ok(deny.includes(`Read(${homeRel(p)})`), `Read(${homeRel(p)})`);
|
|
841
|
+
assert.ok(deny.includes(`Read(${homeRel(cliLib.sessionStoreDir())}/**)`),
|
|
842
|
+
'the store sits at a fixed anchor whatever the brand (task 1003741), so it is never rebranded');
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
t("every deny rule in the core's own settings.json reaches the starter", () => {
|
|
846
|
+
// The two lists drift the way the allow halves could: a rule added to the core
|
|
847
|
+
// protects the core and silently no instance. A config-dir file is compared by
|
|
848
|
+
// name, in the instance's dir; everything else must match verbatim.
|
|
849
|
+
const core = JSON.parse(readFileSync(join(ROOT, '.claude', 'settings.json'), 'utf8')).permissions.deny;
|
|
850
|
+
const deny = starterDenyFor({ configDir: 'acme' });
|
|
851
|
+
for (const rule of core) {
|
|
852
|
+
const cfg = rule.match(/^Read\(~\/\.config\/[^/]+\/(.+)\)$/);
|
|
853
|
+
const want = cfg ? `Read(~/.config/acme/${cfg[1]})` : rule;
|
|
854
|
+
assert.ok(deny.includes(want), `core deny ${rule} → starter must carry ${want}`);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
|
|
807
858
|
// task 1004012 — the other source: a CHECKOUT core root does carry a settings.json, and the
|
|
808
859
|
// instance used to receive its allow-list verbatim, naming scripts its skills no longer run.
|
|
809
860
|
t('a checkout-materialized instance gets allow-rules in the bongos form, end to end', () => {
|
|
@@ -116,6 +116,14 @@ const EXPECTED_GLOBS_BEFORE_R101 = [
|
|
|
116
116
|
// If the owner does want the agents module rank-walled, it needs the entry here,
|
|
117
117
|
// a publish-manifest carve-out, and the module-scope-map roster test updated —
|
|
118
118
|
// three deliberate edits, not a side effect of a scope fix.
|
|
119
|
+
// One ADDED_SINCE_R101 entry per file carved out of `parent`, chained so each sits directly
|
|
120
|
+
// below the previous one — the order the registry lists them in.
|
|
121
|
+
function carve(parent, names, why) {
|
|
122
|
+
const dir = path.posix.dirname(parent);
|
|
123
|
+
const globs = names.map((n) => `${dir}/${n}.js`);
|
|
124
|
+
return globs.map((glob, i) => ({ after: i ? globs[i - 1] : parent, glob, why }));
|
|
125
|
+
}
|
|
126
|
+
|
|
119
127
|
const ADDED_SINCE_R101 = [
|
|
120
128
|
// task 1003366, audit ref MIT1 (2026-08-29 security audit, goal 1000084). The EIGHT
|
|
121
129
|
// execution roots the merge resolver runs out of a cloned branch. The audit named four
|
|
@@ -263,6 +271,30 @@ const ADDED_SINCE_R101 = [
|
|
|
263
271
|
+ 'sub-Metic builders out of in spirit, so the real cost of this entry is three '
|
|
264
272
|
+ 'tasks that arguably should not have been open.',
|
|
265
273
|
},
|
|
274
|
+
// task 1004024, owner decision 2026-09-22 (all five families). Each protected FILE below
|
|
275
|
+
// had been carved into `<name>-*.js` siblings and only the facade stayed registered. The
|
|
276
|
+
// carve tripwire further down is what found the four beyond the one the task named.
|
|
277
|
+
// Listed BY NAME, not as `<name>-*.js`: path-match (the goal scope wall) reads no '*'.
|
|
278
|
+
...carve('src/bongos/auth.js', ['auth-admission', 'auth-config', 'auth-discord', 'auth-github', 'auth-idp'],
|
|
279
|
+
'the auth.js carve: session-token minting and the OAuth exchange, admission and '
|
|
280
|
+
+ 'first-admin seating, IdP assertion checks.'),
|
|
281
|
+
...carve('src/bongos/db.js', ['db-kernel'],
|
|
282
|
+
'the kernel slice carved out of db.js: builder identity and the rank reads the '
|
|
283
|
+
+ 'SEC #863 entry exists for.'),
|
|
284
|
+
...carve('scripts/gds/box.js', ['box-auth-check', 'box-sync'],
|
|
285
|
+
'the box.js family: the dev-box session-start auth gate and the box sync; box-infra.js '
|
|
286
|
+
+ 'was already listed by name.'),
|
|
287
|
+
...carve('modules/grading/grader.js', ['grader-config', 'grader-model', 'grader-no-artifact',
|
|
288
|
+
'grader-prompt', 'grader-score', 'grader-subagent'],
|
|
289
|
+
'the grader.js carve: the deterministic permission-path pre-pass and the server-side '
|
|
290
|
+
+ 'score guards a model cannot talk past.'),
|
|
291
|
+
...carve('scripts/gds/ship.js', ['ship-check', 'ship-deploy-target', 'ship-escalation',
|
|
292
|
+
'ship-finish', 'ship-flow', 'ship-git', 'ship-grade-steps', 'ship-grade', 'ship-honesty',
|
|
293
|
+
'ship-io', 'ship-land', 'ship-memory-sync', 'ship-merge-gate', 'ship-merge',
|
|
294
|
+
'ship-preflight-steps', 'ship-regen', 'ship-resume', 'ship-session-upload', 'ship-state',
|
|
295
|
+
'ship-surprise', 'ship-visual'],
|
|
296
|
+
'the 2026-08-23 ship.js carve: the land path, the ship state machine, the grade gate '
|
|
297
|
+
+ 'steps and pushVia, ~6,200 lines behind a 373-line protected entry point.'),
|
|
266
298
|
];
|
|
267
299
|
|
|
268
300
|
// Surfaces RENAMED since R101 — still protected, under a new path. Distinct from
|
|
@@ -392,6 +424,55 @@ test('every execution root in the closure is a protected surface (MIT1 drift tri
|
|
|
392
424
|
}
|
|
393
425
|
});
|
|
394
426
|
|
|
427
|
+
// ---------- the carve tripwire: a protected FILE's `<name>-*.js` siblings are protected ----------
|
|
428
|
+
//
|
|
429
|
+
// task 1004024. Splitting a protected file into `<name>-<phase>.js` siblings is this repo's
|
|
430
|
+
// carve convention, and every carve so far left only the facade registered: ship.js (21
|
|
431
|
+
// files), grader.js (6), auth.js (5), db.js, box.js. A require()-graph rule was measured and
|
|
432
|
+
// rejected — from the protected scripts it reaches 52 unprotected files (upgrade.js, login.js,
|
|
433
|
+
// package-core.js…), floor-gating ordinary work. The name rule is the shape a carve leaves.
|
|
434
|
+
function stemSiblings(entry, tracked) {
|
|
435
|
+
const dir = path.posix.dirname(entry);
|
|
436
|
+
const prefix = `${path.posix.basename(entry, '.js')}-`;
|
|
437
|
+
return tracked.filter((f) => path.posix.dirname(f) === dir
|
|
438
|
+
&& path.posix.basename(f).startsWith(prefix) && f.endsWith('.js'));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
test('no protected glob uses a wildcard — the goal scope wall could not read it', () => {
|
|
442
|
+
// permission-path-check reads '*', but module-scope-map derives ownership and the
|
|
443
|
+
// protected module set through path-match, which knows only an exact path or a '/'
|
|
444
|
+
// prefix. A wildcard here would protect files no module can own (task 1004024).
|
|
445
|
+
assert.deepEqual(ppc.PROTECTED_GLOBS.filter((g) => g.includes('*')), []);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
test('stemSiblings finds a split-out file and nothing that merely resembles one', () => {
|
|
449
|
+
const tree = ['scripts/gds/ship.js', 'scripts/gds/ship-land.js', 'scripts/gds/shipper.js',
|
|
450
|
+
'scripts/gds/ship_x.js', 'scripts/gds/sub/ship-x.js', 'scripts/gds/ship-notes.md', 'src/ship-y.js'];
|
|
451
|
+
assert.deepEqual(stemSiblings('scripts/gds/ship.js', tree), ['scripts/gds/ship-land.js']);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
test('every file split out of a protected file is itself protected (1004024 carve tripwire)', () => {
|
|
455
|
+
const tracked = execFileSync('git', ['ls-files', '*.js'], { cwd: ROOT, encoding: 'utf8' })
|
|
456
|
+
.split('\n').map((s) => s.trim()).filter(Boolean);
|
|
457
|
+
const entries = ppc.PROTECTED_GLOBS.filter((g) => g.endsWith('.js') && !g.includes('*'));
|
|
458
|
+
let checked = 0;
|
|
459
|
+
for (const entry of entries) {
|
|
460
|
+
const floor = ppc.RANK_TIER[ppc.surfaceFor(entry).floor];
|
|
461
|
+
for (const rel of stemSiblings(entry, tracked)) {
|
|
462
|
+
checked += 1;
|
|
463
|
+
const surface = ppc.surfaceFor(rel);
|
|
464
|
+
assert.ok(surface,
|
|
465
|
+
`${rel} sits beside the protected ${entry} under its name — the shape a carve leaves — `
|
|
466
|
+
+ 'but no protected surface covers it. Register it by name in '
|
|
467
|
+
+ 'modules/government/protected-surfaces.json, declare it in ADDED_SINCE_R101, and '
|
|
468
|
+
+ 'give it the parent\'s owning module in src/bongos/module-scope-map.js.');
|
|
469
|
+
assert.ok(ppc.RANK_TIER[surface.floor] >= floor,
|
|
470
|
+
`${rel} is floored at '${surface.floor}', below the ${entry} it was carved from.`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
assert.ok(checked >= 35, `fixture sanity: expected the five known carves (35 files), saw ${checked}`);
|
|
474
|
+
});
|
|
475
|
+
|
|
395
476
|
// ---------- the credential tripwire: every credential READER is a protected surface ----------
|
|
396
477
|
//
|
|
397
478
|
// task 1002891, from idea 1000692 (the grader's hacker worker, on the 1002690 re-grade).
|