@bongos/core 1.19.47 → 1.19.49
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 +32 -22
- package/docs/adr/0165-instances-hookless-by-default.md +40 -0
- package/docs/adr/README.md +1 -0
- package/docs/canonical-permissions.md +6 -4
- package/modules/economy/achievements.js +1 -1
- package/modules/lifecycle/publish-reconciler.js +2 -2
- package/modules/lifecycle/routes/gate-approvals.js +1 -1
- package/modules/status-ui/public/status.js +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/audit-authorship.sh +71 -3
- package/scripts/gds/provision.js +1 -1
- package/scripts/setup-builder.sh +3 -3
- package/src/bongos/auth.js +1 -1
- package/src/bongos/routes/modules.js +1 -1
- package/src/module-api.js +5 -1
- package/tests/authorship_audit.mjs +44 -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.49",
|
|
6
|
+
"core_contract": "1.19.49",
|
|
7
|
+
"source_commit": "fd920fff3c9a5107c7e7d198f6e09d04c5f66f5b",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-08-11T18:
|
|
9
|
+
"built_at": "2026-08-11T18:36:50.229Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
|
-
"docs_redacted":
|
|
12
|
+
"docs_redacted": 291,
|
|
13
13
|
"agent_docs_stubbed": 21,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 1217,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 1529,
|
|
20
|
+
"tree_sha256": "94afa19b71a022c6b15c9ce95d71b3c76fe6ed87758e5b38dbfa259e7215ca5b",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/blocker-review/SKILL.md",
|
|
@@ -1294,10 +1294,15 @@
|
|
|
1294
1294
|
"mode": "0000644",
|
|
1295
1295
|
"sha256": "64fb6e129cf5484266e1b6a9cddd8ba88ff7438b9646c3f4d9ffd0cda3cce642"
|
|
1296
1296
|
},
|
|
1297
|
+
{
|
|
1298
|
+
"path": "docs/adr/0165-instances-hookless-by-default.md",
|
|
1299
|
+
"mode": "0000644",
|
|
1300
|
+
"sha256": "d422e10adc391127a7f39b9eb8b5927c149ee455402bc5e4641f55e8b31b2d15"
|
|
1301
|
+
},
|
|
1297
1302
|
{
|
|
1298
1303
|
"path": "docs/adr/README.md",
|
|
1299
1304
|
"mode": "0000644",
|
|
1300
|
-
"sha256": "
|
|
1305
|
+
"sha256": "09a7ba734571fbb304c60a488fe9ccdb6ca06d01127cfb87f07b1cbb54d69408"
|
|
1301
1306
|
},
|
|
1302
1307
|
{
|
|
1303
1308
|
"path": "docs/api-reference.md",
|
|
@@ -1327,7 +1332,7 @@
|
|
|
1327
1332
|
{
|
|
1328
1333
|
"path": "docs/canonical-permissions.md",
|
|
1329
1334
|
"mode": "0000644",
|
|
1330
|
-
"sha256": "
|
|
1335
|
+
"sha256": "b7f66c6f1fbed274e5ba3295c06db8fc8edb84edd44f6ce92f6734e18267e3d9"
|
|
1331
1336
|
},
|
|
1332
1337
|
{
|
|
1333
1338
|
"path": "docs/design-contract.md",
|
|
@@ -2687,7 +2692,7 @@
|
|
|
2687
2692
|
{
|
|
2688
2693
|
"path": "modules/economy/achievements.js",
|
|
2689
2694
|
"mode": "0000644",
|
|
2690
|
-
"sha256": "
|
|
2695
|
+
"sha256": "387c37df8b65bab755e8f006722e6665d9e5aafea29eabf868d1e2dfc4720e99"
|
|
2691
2696
|
},
|
|
2692
2697
|
{
|
|
2693
2698
|
"path": "modules/economy/cost-classify.js",
|
|
@@ -3447,7 +3452,7 @@
|
|
|
3447
3452
|
{
|
|
3448
3453
|
"path": "modules/lifecycle/publish-reconciler.js",
|
|
3449
3454
|
"mode": "0000644",
|
|
3450
|
-
"sha256": "
|
|
3455
|
+
"sha256": "3f7f65007955c419ccce1c89cb1f6da6eeca6daa8a76a738540db2858ebff4e6"
|
|
3451
3456
|
},
|
|
3452
3457
|
{
|
|
3453
3458
|
"path": "modules/lifecycle/routes/analytics.js",
|
|
@@ -3472,7 +3477,7 @@
|
|
|
3472
3477
|
{
|
|
3473
3478
|
"path": "modules/lifecycle/routes/gate-approvals.js",
|
|
3474
3479
|
"mode": "0000644",
|
|
3475
|
-
"sha256": "
|
|
3480
|
+
"sha256": "e65687656da193f9d23b398a94061f927cfbf8a63b5263c7e6ee48c5ef50f6e5"
|
|
3476
3481
|
},
|
|
3477
3482
|
{
|
|
3478
3483
|
"path": "modules/lifecycle/routes/goals.js",
|
|
@@ -4022,7 +4027,7 @@
|
|
|
4022
4027
|
{
|
|
4023
4028
|
"path": "modules/status-ui/public/status.js",
|
|
4024
4029
|
"mode": "0000644",
|
|
4025
|
-
"sha256": "
|
|
4030
|
+
"sha256": "bd0fcd32548c7b2cc7c6d36b0f31cba3e0575c95ff3dc85fdb15b11decbdfe42"
|
|
4026
4031
|
},
|
|
4027
4032
|
{
|
|
4028
4033
|
"path": "modules/status-ui/public/style.css",
|
|
@@ -4032,12 +4037,12 @@
|
|
|
4032
4037
|
{
|
|
4033
4038
|
"path": "package-lock.json",
|
|
4034
4039
|
"mode": "0000644",
|
|
4035
|
-
"sha256": "
|
|
4040
|
+
"sha256": "7124698435e257f65256f4d3ab34277211b216cece5849b932368eccde73330f"
|
|
4036
4041
|
},
|
|
4037
4042
|
{
|
|
4038
4043
|
"path": "package.json",
|
|
4039
4044
|
"mode": "0000644",
|
|
4040
|
-
"sha256": "
|
|
4045
|
+
"sha256": "16fecf0cf1d4f688f452ad27d37ba05776dd028444cd6cc9a2ab68deba3bb693"
|
|
4041
4046
|
},
|
|
4042
4047
|
{
|
|
4043
4048
|
"path": "public-docs/index.html",
|
|
@@ -4457,7 +4462,7 @@
|
|
|
4457
4462
|
{
|
|
4458
4463
|
"path": "scripts/gds/audit-authorship.sh",
|
|
4459
4464
|
"mode": "0000644",
|
|
4460
|
-
"sha256": "
|
|
4465
|
+
"sha256": "6922f6008c72db47855172fce7e40df0953575b7bead0504758648e2cf2859e9"
|
|
4461
4466
|
},
|
|
4462
4467
|
{
|
|
4463
4468
|
"path": "scripts/gds/audit-deps.js",
|
|
@@ -5007,7 +5012,7 @@
|
|
|
5007
5012
|
{
|
|
5008
5013
|
"path": "scripts/gds/provision.js",
|
|
5009
5014
|
"mode": "0000644",
|
|
5010
|
-
"sha256": "
|
|
5015
|
+
"sha256": "93a5c4a6d6f76cf1fa8ca4c902b19d6ef94f9147488f1c01d3413f692a196942"
|
|
5011
5016
|
},
|
|
5012
5017
|
{
|
|
5013
5018
|
"path": "scripts/gds/publish-manifest.js",
|
|
@@ -5352,7 +5357,7 @@
|
|
|
5352
5357
|
{
|
|
5353
5358
|
"path": "scripts/setup-builder.sh",
|
|
5354
5359
|
"mode": "0000644",
|
|
5355
|
-
"sha256": "
|
|
5360
|
+
"sha256": "5860bf9daef3dd83a5ff4d3ee5e017e3cbd465ebda0c00df4ca622d629468ec4"
|
|
5356
5361
|
},
|
|
5357
5362
|
{
|
|
5358
5363
|
"path": "scripts/snapshots/backfill-history.mjs",
|
|
@@ -5422,7 +5427,7 @@
|
|
|
5422
5427
|
{
|
|
5423
5428
|
"path": "src/bongos/auth.js",
|
|
5424
5429
|
"mode": "0000644",
|
|
5425
|
-
"sha256": "
|
|
5430
|
+
"sha256": "a8215fa2659638d5850acb787eb3b193b18b545bc7e86f801764cab328b0c837"
|
|
5426
5431
|
},
|
|
5427
5432
|
{
|
|
5428
5433
|
"path": "src/bongos/cascade-dispatch.js",
|
|
@@ -5597,7 +5602,7 @@
|
|
|
5597
5602
|
{
|
|
5598
5603
|
"path": "src/bongos/routes/modules.js",
|
|
5599
5604
|
"mode": "0000644",
|
|
5600
|
-
"sha256": "
|
|
5605
|
+
"sha256": "30be4d5a235cc704d4e1db264fb4e976ef6c614bc680fe90e05f3a199b62fd3d"
|
|
5601
5606
|
},
|
|
5602
5607
|
{
|
|
5603
5608
|
"path": "src/bongos/routes/optimizer.js",
|
|
@@ -5657,7 +5662,7 @@
|
|
|
5657
5662
|
{
|
|
5658
5663
|
"path": "src/module-api.js",
|
|
5659
5664
|
"mode": "0000644",
|
|
5660
|
-
"sha256": "
|
|
5665
|
+
"sha256": "902071a6283cfb63ca5cc90c8ca201cd97e14490a380b4e4a51c231a89b02e3f"
|
|
5661
5666
|
},
|
|
5662
5667
|
{
|
|
5663
5668
|
"path": "src/module-loader/loader.js",
|
|
@@ -5854,6 +5859,11 @@
|
|
|
5854
5859
|
"mode": "0000644",
|
|
5855
5860
|
"sha256": "92b7033ab16d9d4472fcca4695d9df47938a45bdc62feda87b8771f5a2d59ff2"
|
|
5856
5861
|
},
|
|
5862
|
+
{
|
|
5863
|
+
"path": "tests/authorship_audit.mjs",
|
|
5864
|
+
"mode": "0000644",
|
|
5865
|
+
"sha256": "4697e7e264023c148d1f18cac9695157de56b5dd3db4b60f2ab94d73a8d7af65"
|
|
5866
|
+
},
|
|
5857
5867
|
{
|
|
5858
5868
|
"path": "tests/autonomous_fit_protected_paths.mjs",
|
|
5859
5869
|
"mode": "0000644",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 0165 — Instances are hookless by default: no scaffolded `.husky/`; local hooks stay an instance-owned opt-in
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-08-11
|
|
5
|
+
- **Deciders:** Claude (jaxri session), under the bug-wave mandate — flagged owner-adjacent; the ADR is the revisit point
|
|
6
|
+
|
|
7
|
+
**Track:** `internal` (provisioning / trust boundary). Task [1002641](https://cloudbongos.com/builders#/task/1002641), from idea 1000655. Relates to [ADR 0043](<redacted>.md) (Layer 1), [ADR 0055](<redacted>.md) (server-mediated publish), [ADR 0162](<redacted>.md) (CI-only gates).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
Task 1002608 delivered `.husky/pre-push` — the ADR 0043 **Layer 1** local permission gate — for **this core repo**, and `scripts/gds/install-git-hooks.js` (run by `/builder-setup`) activates whatever hooks a clone's `.husky/` tracks by setting `core.hooksPath`.
|
|
14
|
+
|
|
15
|
+
But nothing delivers Layer 1 to a **scaffolded standalone instance**: `init.js` / `provision.js` / `onboard.js` materialize no `.husky/`, and `publish-manifest.js` excludes `.husky/` from the published core artifact **by design** (`PROTECTED_TOPOLOGY_EXCLUDE` — a core update must never silently rewrite an instance's local gate topology). So instances run with no pre-push permission gate and no pre-commit secrets hook. Task 1002641 asks: is that a gap to fill, or the accepted posture?
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
18
|
+
|
|
19
|
+
**Hookless-by-default is the accepted posture for instances. Provisioning scaffolds no `.husky/`. Local hooks are an instance-owned opt-in: an instance that wants them commits its own `.husky/`, and the core's existing `install-git-hooks.js` activates them on every builder's machine.**
|
|
20
|
+
|
|
21
|
+
Four structural reasons:
|
|
22
|
+
|
|
23
|
+
1. **The population Layer 1 constrains holds no push credential on an instance.** Sub-Metic builders work dev boxes where the git origin is credential-less and landing goes through **server-mediated publish** (ADR 0053/0055): the box uploads a bundle, the *server* pushes and opens the PR. A client-side pre-push hook on the box guards a push that cannot happen. Metic+ builders with real push access are inside the trust boundary, and their pushes meet the server-side gates that actually enforce: branch protection, the required `unit` check (fitness, gate-review tests, the authorship gate — task 1002640), and the every-push `main-audit`.
|
|
24
|
+
2. **A client hook is not a security boundary** (ADR 0016: the DB and server enforce; local edits grant nothing). On the core repo, `.husky/pre-push` is defense-in-depth for contributors with direct push access — a materially different population than instance builders. Scaffolding it onto instances would *look* like a control while a hostile clone deletes it in one command.
|
|
25
|
+
3. **The core cannot maintain what it deliberately does not ship.** `.husky/` is `PROTECTED_TOPOLOGY_EXCLUDE`d from the artifact, so scaffolded hooks would be born orphans — no upgrade path, rotting silently until they misfire. A written control that no longer runs teaches builders to ignore controls (the audit-authorship lesson, task 1002640).
|
|
26
|
+
4. **ADR 0162 (owner directive): gates live in CI, rank-consistent and hands-free.** Instance-side client gates re-introduce the blocked-builder friction class that ADR retired — a broken hook strands a legitimate land until a human intervenes.
|
|
27
|
+
|
|
28
|
+
**Secrets hooks follow the same rule.** A pre-commit secrets guard needs per-machine tooling and gives false local confidence; the PR-time CI secret scan is the enforcing control on every land.
|
|
29
|
+
|
|
30
|
+
**The opt-in stays real, and stays instance-owned.** `install-git-hooks.js` ships in the core and already runs at `/builder-setup` on every instance; it activates whatever `.husky/` the *instance's own repo* tracks. Policy (which hooks, if any) is the instance's; the activation mechanism is the core's. That split mirrors the branding contract (ADR 0062 §7).
|
|
31
|
+
|
|
32
|
+
## Rejected
|
|
33
|
+
|
|
34
|
+
- **Scaffold `.husky/` wrappers at `init`/provision** — orphaned gate topology the core can't update (reason 3), guarding a push path instance builders don't have (reason 1).
|
|
35
|
+
- **An `init --with-hooks` flag** — speculative surface; no instance has asked. If one does, it composes trivially on the opt-in path above.
|
|
36
|
+
- **Treating hooklessness as a security regression to hotfix** — the enforcing controls on instances are server-side and already in place; Layer 1 was always the advisory outermost layer, not the wall.
|
|
37
|
+
|
|
38
|
+
## When to revisit
|
|
39
|
+
|
|
40
|
+
An instance model where builders routinely push directly with their own credentials (no server-mediated publish, no branch protection) would remove reasons 1–2; revisit then.
|
package/docs/adr/README.md
CHANGED
|
@@ -237,5 +237,6 @@ This keeps the decision history honest and traceable.
|
|
|
237
237
|
|
|
238
238
|
| 0163 | [**Pre-197 display names: a transitional 'legacy' source, resolved at first sign-in** ([task 1002643](https://cloudbongos.com/builders#/task/1002643); idea 1000659). Amends [ADR 0156](<redacted>.md), whose migration defaulted every pre-existing row to `'github'` — false for builders who renamed after their last sign-in but before 197 landed, so their names kept reverting. No audit trail exists to backfill precisely, so `core_214` marks every pre-197 `'github'` row `'legacy'` (scoped by 197's `applied_at` on the instance — portable) and the upsert resolves each at its first sign-in: stored = incoming GitHub name → provably GitHub-derived → `'github'`; differs → treated as builder-set → kept, stamped `'user'`. Accepted misclassification: a GitHub-side rename in the window freezes a stale label (visible, self-fixable in Settings) — preferred over silently destroying deliberate renames. Rejected: `display_name <> github_login` heuristic (freezes nearly everyone), comparing forever on all `'github'` rows (turns every future GitHub rename into a frozen name).](<redacted>.md) | GDS / builder experience |
|
|
239
239
|
| 0164 | [**The implausible-pass guard reads substance + evidence; the Metic+ honor-system residual is explicit** ([task 1002658](https://cloudbongos.com/builders#/task/1002658); grader-hardening goal 1000056). The guard fired only on `issues.length===0` — one fabricated `{}` defeated it, its magnitude inputs are client-supplied, and every in-sample firing (eval 2-for-2, tasks 1002643 ×2, 1002663) was a false positive on an honest unanimous zero-issue panel PASS. Redesign: count only SUBSTANTIVE issues (known severity + non-empty summary — padding trips the guard regardless), and waive the zero-issue pass when `signals.workers` carries the full ≥3-worker panel shape, stamped `implausible_pass_waived` for /grade-audit. The residual is named, not hidden: every grade-time input is client-authored, so plausibility at grade time is honest-mistake hygiene; the binding authorities on the real diff are land-time (CI unit, gate-review, main audit) — Metic+ grade-time honesty is accepted honor-system per this ADR. The ADR-0042 CI grade-gate (land it vs record permanent deferral) goes to the owner as a blocker, not decided here. No approval step added or removed (ADR 0162).](<redacted>.md) | GDS / grading |
|
|
240
|
+
| 0165 | [**Instances are hookless by default: no scaffolded `.husky/`; local hooks stay an instance-owned opt-in** ([task 1002641](https://cloudbongos.com/builders#/task/1002641); idea 1000655). Task 1002608 delivered the ADR 0043 Layer 1 pre-push gate for the CORE repo, but nothing materializes `.husky/` on a scaffolded standalone instance (`publish-manifest.js` excludes it by design). Decision: that is the accepted posture, not a gap. Sub-Metic instance builders hold no push credential at all (server-mediated publish, ADR 0053/0055) — a client pre-push hook guards a push that cannot happen; a client hook is not a security boundary (ADR 0016); the core cannot maintain hooks it deliberately does not ship (scaffolded hooks would be born orphans — the audit-authorship rot lesson, task 1002640); and ADR 0162 puts gates in CI, rank-consistent and hands-free. Secrets hooks follow the same rule (the PR-time CI secret scan enforces). The opt-in stays real and instance-owned: an instance commits its own `.husky/` and the core's `install-git-hooks.js` (already run by `/builder-setup`) activates it. Rejected: scaffolding wrappers at init, an `--with-hooks` flag (speculative), treating hooklessness as a regression. Revisit if an instance model has builders pushing directly with their own credentials.](<redacted>.md) | provisioning / trust boundary |
|
|
240
241
|
|
|
241
242
|
> ⚠️ **Numbering collision (known):** two ADRs share `0008`. The numbers were assigned in parallel sessions before the lock could be enforced. The files are kept under their existing filenames to preserve git history, but the table disambiguates them as `0008-a` / `0008-b`. New ADRs should resume at `0040` to avoid further collisions. (`0024` is also a real on-disk duplicate: the cloneable-repo/local-first-memory ADR and the multi-agent-system-architecture ADR were both numbered `0024` in parallel; both keep their filenames, disambiguated as `0024-a` / `0024-b` like `0008`. Likewise `0025` ended up with two on-disk files — the offsite-backup ADR and the structured-criterion↔task-link ADR — both kept under their existing filenames and disambiguated as `0025-a` / `0025-b`; separately, the BFG ADR had also claimed `0025` on 2026-05-30 and yielded to `0026`. A third happened 2026-06-06: `0036` was claimed in parallel by the builders-subdomain ADR ([#726](https://example.com/builders#/task/726)) and this Discord-channels ADR ([#727](https://example.com/builders#/task/727)); the Discord-channels ADR yielded to `0037`. A fourth landed 2026-06-10: `0044` was claimed in parallel by the palette-replacement ADR and the per-box game-preview ADR ([#897](https://example.com/builders#/task/897)); both keep their filenames, disambiguated as `0044-a` / `0044-b` like `0008`. A fifth was caught pre-land 2026-06-13: `0050` was claimed in parallel by the device-flow-admission ADR ([#1000](https://example.com/builders#/task/1000)) and the sandbox-for-everyone ADR ([#1001](https://example.com/builders#/task/1001)); the latter yielded to `0052` before merging, so there is no `0050` duplicate. A sixth was caught pre-land 2026-06-21: the tool-agnostic-design-layer ADR ([#1375](https://example.com/builders#/task/1375)) first collided at `0079` with the value-gated-autonomous-engagement ADR, then at `0080` with the llm-cache-api-transport ADR (both part of the 0075–0080 LLM-cost-reduction series, landed on `main` in parallel); it yielded to `0081` before merging, so there is no `0079`/`0080` design-layer duplicate. A seventh landed 2026-06-23: `0084` was claimed in parallel by the auto-derived-per-task-rank-floor ADR and the remove-default-spend-cap ADR (task 1499); the rank-floor ADR landed on `main` first, so the spend-cap ADR yielded to `0085`, leaving no `0084` duplicate. An eighth landed 2026-06-27: `0095` was claimed in parallel by the borrowed-memory-and-retrieval-concepts ADR (PR #459, landed first) and the cross-agent-context-management ADR ([#1651](https://example.com/builders#/task/1651), PR #460); both keep their filenames, disambiguated as `0095-a` / `0095-b` like `0008`. These two are companions — `0095-a` adopts the memory/retrieval concepts and explicitly defers the grep-vs-semantic question to `0095-b`.)
|
|
@@ -265,7 +265,9 @@ pre-merge gate misses, independent of the builder's cooperation:
|
|
|
265
265
|
[`src/bongos/permission-path-check.js`](../src/bongos/permission-path-check.js) (source of truth).
|
|
266
266
|
- **Nobody pushes `main` directly.** The pre-push hook (`.husky/pre-push`, tracked in this repo and
|
|
267
267
|
activated per-clone by `/builder-setup` via `install-git-hooks.js` — inert on a clone that never
|
|
268
|
-
activated it; ADR 0043 §"G-2/G-17 resolution") blocks it
|
|
268
|
+
activated it; ADR 0043 §"G-2/G-17 resolution") blocks it. This hook is a CORE-repo control:
|
|
269
|
+
scaffolded standalone instances are hookless by default — deliberate, not a gap
|
|
270
|
+
([ADR 0165](adr/<redacted>.md)); the graded
|
|
269
271
|
pipeline pushes only via `scripts/gds/push-main.js` (which carries the `OTB_ALLOW_MAIN_PUSH`
|
|
270
272
|
override). A raw push is caught and reverted by the **post-push main audit**
|
|
271
273
|
(`scripts/gds/main-audit.js`) — nightly and as the `~/deploy.sh` deploy gate — which is the
|
|
@@ -299,6 +301,6 @@ identity. Use `req.builder.*` server-side, the active session client-side, `$HOM
|
|
|
299
301
|
- **Infra config, not impersonation:** the droplet's operational identity (`User=lars`,
|
|
300
302
|
`lars@REDACTED_IP`, `/home/lars/example`, `lars@example.com`).
|
|
301
303
|
- **Enforcement:** [`scripts/gds/audit-authorship.sh`](../scripts/gds/audit-authorship.sh) — exits 0
|
|
302
|
-
clean, exits 1 with a hit list + remediation hints if a new hardcode shows up.
|
|
303
|
-
|
|
304
|
-
|
|
304
|
+
clean, exits 1 with a hit list + remediation hints if a new hardcode shows up. Runs on every PR
|
|
305
|
+
inside the required `unit` check via `tests/authorship_audit.mjs` (task 1002640 — it previously had
|
|
306
|
+
no caller and its exclusions had rotted to 342 stale hits). State clean (0 hits) as of that rewire.
|
|
@@ -239,7 +239,7 @@ async function evaluateAfterCreditAward(client, builderId, totalBefore, totalAft
|
|
|
239
239
|
// with grader_bypass on only ever unlocked first-claim (the claim path works).
|
|
240
240
|
// And breaking-the-100c-bar was boundary-only (totalBefore<100 && totalAfter>=100)
|
|
241
241
|
// on a credit branch the per-session cost-plus reward (ADR 0054) never hits, so
|
|
242
|
-
// it fired for NOBODY — even
|
|
242
|
+
// it fired for NOBODY — even the founding Archon at 22k credits. The whole board looked dead.
|
|
243
243
|
//
|
|
244
244
|
// reconcileBuilderAchievements evaluates every achievement against CURRENT DB
|
|
245
245
|
// state and unlocks any the builder is eligible for but hasn't. It is:
|
|
@@ -122,8 +122,8 @@ function couldBeStaleGenerated(m) {
|
|
|
122
122
|
|
|
123
123
|
// task 1002461 — render the reconciler's operating target: which repo it resolved
|
|
124
124
|
// and whether it holds a credential. This is the line that makes a WRONG repo bind
|
|
125
|
-
// visible without owner access (the live failure: the hub bound
|
|
126
|
-
//
|
|
125
|
+
// visible without owner access (the live failure: the hub bound the instance
|
|
126
|
+
// repo while the PRs were in the core repo).
|
|
127
127
|
// Pure — takes the resolved facts, returns the string — so the wording is
|
|
128
128
|
// unit-tested without a boot.
|
|
129
129
|
function describeTarget({ configured, repo } = {}) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// WHY. The gate-review CI check (ADR 0058) clears an ESCALATE (hard floor) ONLY on
|
|
5
5
|
// an owner approval, and a NEEDS_TRUST without a Metic+ author likewise blocks until
|
|
6
6
|
// the owner approves. Historically that owner approval was a GitHub APPROVED review
|
|
7
|
-
// by
|
|
7
|
+
// by the repo owner on the head sha — i.e. the owner had to leave a GitHub/terminal review.
|
|
8
8
|
// This router gives Archons a browser-only equivalent (feedback: auth flows must be
|
|
9
9
|
// UI-first), trust-consistent with the existing server-set `gate-author-trust`
|
|
10
10
|
// status: the server re-checks the caller's Archon rank server-side (ADR 0016) and
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// API base for the public read endpoints (#737). Empty = same-origin, the case
|
|
5
5
|
// when this file is served by the droplet itself (status.amazonprimea.com
|
|
6
6
|
// proxies /api/* to the same Node process). The OFF-BOX GitHub Pages mirror
|
|
7
|
-
// (
|
|
7
|
+
// (the owner's status-mirror repo, ADR 0029) injects window.STATUS_API_BASE =
|
|
8
8
|
// 'https://amazonprimea.com' in its <head> so the same byte-identical file
|
|
9
9
|
// fetches cross-origin from the droplet there (CORS is open). Keeping this file
|
|
10
10
|
// identical on both hosts is what lets the mirror sync be a pure copy.
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.49",
|
|
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.49",
|
|
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.49",
|
|
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",
|
|
@@ -34,14 +34,24 @@
|
|
|
34
34
|
# * GitHub remote `lars589/amazonprimea` — actual repo owner; cloning
|
|
35
35
|
# anything else would clone a different project.
|
|
36
36
|
# * Comments that document who decided something or who originally ran a
|
|
37
|
-
# one-time backfill — historical decision-attribution.
|
|
37
|
+
# one-time backfill — historical decision-attribution. Allowlisted
|
|
38
|
+
# PER FILE below (a content-level "looks like a comment" filter would
|
|
39
|
+
# also match live code — a JS private class field, a //host literal —
|
|
40
|
+
# so it could be gamed; file entries with justifications can't).
|
|
41
|
+
# * Test data that pins a real contract, allowlisted PER FILE below: owner
|
|
42
|
+
# approval RECORDS the Archon's login, the terminal-URL guard validates
|
|
43
|
+
# term-<login> hostnames — identity in an assertion is the contract.
|
|
44
|
+
# New test files are still scanned (no blanket tests/ exclusion).
|
|
45
|
+
# * Sample API payloads (fixtures/) and gitignored build output (dist/).
|
|
38
46
|
#
|
|
39
47
|
# Usage:
|
|
40
48
|
# bash scripts/gds/audit-authorship.sh # check, exit 1 on new hits
|
|
41
49
|
# bash scripts/gds/audit-authorship.sh --verbose # print every hit (incl.
|
|
42
50
|
# # allowlisted) for review
|
|
43
51
|
#
|
|
44
|
-
#
|
|
52
|
+
# CI lane: tests/authorship_audit.mjs runs this inside the required `unit`
|
|
53
|
+
# check (task 1002640 — it previously had no caller and 342 stale hits).
|
|
54
|
+
# No writes, no network.
|
|
45
55
|
|
|
46
56
|
set -uo pipefail
|
|
47
57
|
|
|
@@ -72,6 +82,10 @@ done
|
|
|
72
82
|
EXCLUDE_DIRS=(
|
|
73
83
|
--exclude-dir=node_modules
|
|
74
84
|
--exclude-dir=.git
|
|
85
|
+
--exclude-dir=dist # gitignored build/package output (a stale
|
|
86
|
+
# core tarball tree re-reports every hit in
|
|
87
|
+
# it — task 1002640); grep -R walks the
|
|
88
|
+
# filesystem, not the git index.
|
|
75
89
|
--exclude-dir=iterations # under art/, historical cost ledger
|
|
76
90
|
--exclude-dir=generated # under art/, generated PNGs / metadata
|
|
77
91
|
--exclude-dir=docs # human prose: ADRs, recipes, plans,
|
|
@@ -79,6 +93,9 @@ EXCLUDE_DIRS=(
|
|
|
79
93
|
# naming the founder by intent
|
|
80
94
|
--exclude-dir=blockers # blockers ARE the things stuck on Lars
|
|
81
95
|
--exclude-dir=limitations # archives + scope-truth docs
|
|
96
|
+
--exclude-dir=fixtures # sample API payloads (hall-preview) mirror
|
|
97
|
+
# real prod rows, which name real builders —
|
|
98
|
+
# frozen sample data, not runtime code.
|
|
82
99
|
--exclude-dir=worktrees # .claude/worktrees/ holds N full repo
|
|
83
100
|
# copies (one per builder worktree); from
|
|
84
101
|
# the main checkout, recursing them is slow
|
|
@@ -151,6 +168,53 @@ ALLOWLIST=(
|
|
|
151
168
|
# leaks in setup.js — the string appearing in the comment IS the
|
|
152
169
|
# specification of what's forbidden in implementation code.
|
|
153
170
|
'tests/setup_smoke.mjs'
|
|
171
|
+
|
|
172
|
+
# Test DATA that pins a real contract (task 1002640) — identity in an
|
|
173
|
+
# assertion IS the contract, not a mis-attribution: owner approval RECORDS
|
|
174
|
+
# the Archon's login (gate_approvals), the terminal-URL SSRF guard validates
|
|
175
|
+
# term-<login> hostnames (box_terminal_ssrf), packaging/provisioning tests
|
|
176
|
+
# exercise the real repo owner + the mirror-redaction floor. Listed per file
|
|
177
|
+
# (never a blanket tests/ exclusion) so a NEW test file is still scanned.
|
|
178
|
+
'tests/provision.mjs'
|
|
179
|
+
'tests/package_core.mjs'
|
|
180
|
+
'tests/init.mjs'
|
|
181
|
+
'tests/box_terminal_ssrf.mjs'
|
|
182
|
+
'tests/gate_approvals.mjs'
|
|
183
|
+
'tests/publish_reconciler.mjs'
|
|
184
|
+
'tests/dev_lib.mjs'
|
|
185
|
+
'tests/ship_card.mjs'
|
|
186
|
+
'tests/scrubber_corpus.mjs'
|
|
187
|
+
'tests/module_submissions.mjs'
|
|
188
|
+
'tests/boxes.mjs'
|
|
189
|
+
'tests/provisioning_onboard_mode.mjs'
|
|
190
|
+
'tests/instance_manifest.mjs'
|
|
191
|
+
'tests/bongos_downloads.mjs'
|
|
192
|
+
'tests/status_mirror_sync.mjs'
|
|
193
|
+
'tests/search_isolation.mjs'
|
|
194
|
+
'tests/grade_aggregates_unavailable.mjs'
|
|
195
|
+
'tests/first_admin_bootstrap.mjs'
|
|
196
|
+
'tests/discord_approvals.mjs'
|
|
197
|
+
'tests/currency_label.mjs'
|
|
198
|
+
'tests/cloud_bongos_pack.mjs'
|
|
199
|
+
'tests/bump_version.mjs'
|
|
200
|
+
'tests/box_scope_session.mjs'
|
|
201
|
+
'tests/auth_inactive_builder.mjs'
|
|
202
|
+
'tests/auth_anthropic_identity.mjs'
|
|
203
|
+
'modules/dev-box/app/test/unit.mjs'
|
|
204
|
+
|
|
205
|
+
# The public landing page links the open-source repo by URL — repo-hosting
|
|
206
|
+
# identity (the provision-staging.sh class), not a builder identity.
|
|
207
|
+
'public-landing/create.html'
|
|
208
|
+
|
|
209
|
+
# The mirror-redaction floor: PRIOR_INSTANCE_FLOOR carries the prior
|
|
210
|
+
# instance's owner literal precisely so packaging can SCRUB it from every
|
|
211
|
+
# published core — the anti-leak spec, not a runtime hardcode (task 1002640).
|
|
212
|
+
'scripts/gds/package-core.js'
|
|
213
|
+
|
|
214
|
+
# Frozen seed script — a task DESCRIPTION quotes migration 023's founding-
|
|
215
|
+
# Archon literal as the thing that task exists to remove (the
|
|
216
|
+
# seed-v3-tasks.js class: stripping it would lose the task history).
|
|
217
|
+
'scripts/gds/seed-medusa-tasks.js'
|
|
154
218
|
)
|
|
155
219
|
|
|
156
220
|
# ----------------------------------------------------------------------------
|
|
@@ -212,7 +276,11 @@ else
|
|
|
212
276
|
fi
|
|
213
277
|
|
|
214
278
|
# Apply operational-identity + spec-string pattern allowlists (both match on
|
|
215
|
-
# line content, not file path).
|
|
279
|
+
# line content, not file path). NB deliberately NO comment-line filter: a
|
|
280
|
+
# content pattern like `^\s*(//|#)` also matches live code (a JS private class
|
|
281
|
+
# field `#name = ...`, a protocol-relative `//host` continuation line), so a
|
|
282
|
+
# real hardcode could dress as a comment to slip through. Historical-
|
|
283
|
+
# attribution comments get per-file ALLOWLIST entries instead (task 1002640).
|
|
216
284
|
grep -vE "$OPS_ALLOWLIST_PATTERN" "$TMP_HITS" \
|
|
217
285
|
| grep -vE "$SPEC_ALLOWLIST_PATTERN" > "$TMP_FILTERED" || true
|
|
218
286
|
|
package/scripts/gds/provision.js
CHANGED
|
@@ -851,7 +851,7 @@ ${prefix}_OAUTH_ORIGIN=${origin}
|
|
|
851
851
|
// <prefix>_FIRST_ADMIN before branding.firstAdmin). WITHOUT it a provisioned instance
|
|
852
852
|
// has NO owner — first sign-in is refused / lands rankless and the owner can never
|
|
853
853
|
// claim their own instance (goal 35 / criterion 165 regression, caught live 2026-07-07:
|
|
854
|
-
// demo had every origin override but no FIRST_ADMIN, so
|
|
854
|
+
// demo had every origin override but no FIRST_ADMIN, so the owner could not be seated).
|
|
855
855
|
// Derived from the instance repo owner (target_ref = "<owner>/<repo>"), the SAME source
|
|
856
856
|
// instanceInitSpec uses for the scaffold's branding.firstAdmin — so this env override and
|
|
857
857
|
// the scaffolded config/branding.json agree. (Org-owned repo: the org login is not a
|
package/scripts/setup-builder.sh
CHANGED
|
@@ -14,15 +14,15 @@
|
|
|
14
14
|
# ./scripts/setup-builder.sh [--skip-keys] [--no-auth] [--help]
|
|
15
15
|
#
|
|
16
16
|
# Run this from INSIDE a clone of the repo. If you don't have the code yet,
|
|
17
|
-
# do "Step 0 — get the project onto your machine" first (see README.md)
|
|
18
|
-
#
|
|
17
|
+
# do "Step 0 — get the project onto your machine" first (see README.md) —
|
|
18
|
+
# clone YOUR instance's repo, then cd into it.
|
|
19
19
|
set -uo pipefail
|
|
20
20
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
21
|
# Guard: this shim must run from inside the repo (where setup-builder.js lives).
|
|
22
22
|
if [ ! -f "$SCRIPT_DIR/setup-builder.js" ]; then
|
|
23
23
|
echo "setup-builder: can't find setup-builder.js next to this script." >&2
|
|
24
24
|
echo "Did you clone the repo and cd into it? See README.md 'Step 0 — get the project onto your machine'." >&2
|
|
25
|
-
echo "
|
|
25
|
+
echo " (clone YOUR instance's repo, then cd into it and re-run this script)" >&2
|
|
26
26
|
exit 1
|
|
27
27
|
fi
|
|
28
28
|
exec node "$SCRIPT_DIR/setup-builder.js" "$@"
|
package/src/bongos/auth.js
CHANGED
|
@@ -63,7 +63,7 @@ const SCOPE = 'read:user';
|
|
|
63
63
|
// support is needed". It is needed. `public_repo` grants write to PUBLIC repos
|
|
64
64
|
// only, so ADOPTING an existing PRIVATE repo dies at the provisioner's scaffold
|
|
65
65
|
// push with GitHub 403 "Write access to repository not granted" — observed live on
|
|
66
|
-
//
|
|
66
|
+
// a private repo of the owner's. ADR 0155 takes the reversal at the owner's
|
|
67
67
|
// explicit call, accepting the cost it names: a token we persist can now write to
|
|
68
68
|
// EVERY repo the user owns, not just their public ones.
|
|
69
69
|
const REPO_SCOPE = 'repo';
|
|
@@ -65,7 +65,7 @@ function ownProjectName() {
|
|
|
65
65
|
try { return require('../../branding').branding().identity.productName; } catch { return null; }
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// "owner/name", e.g. "
|
|
68
|
+
// "owner/name", e.g. "some-owner/their-repo" — the provenance a submission
|
|
69
69
|
// carries (ADR 0107 §2: attribution/provenance travels WITH the module as a
|
|
70
70
|
// portable record, not a cross-GDS link). null if the branding pack has none.
|
|
71
71
|
function sourceRepoLabel() {
|
package/src/module-api.js
CHANGED
|
@@ -521,8 +521,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
|
|
|
521
521
|
// landed since 1.19.45 with no explicit bump. run 31520432748. (task 1002620)
|
|
522
522
|
// 1.19.47 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
523
523
|
// landed since 1.19.46 with no explicit bump. run 31521404176. (task 1002620)
|
|
524
|
+
// 1.19.48 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
525
|
+
// landed since 1.19.47 with no explicit bump. run 31522865111. (task 1002620)
|
|
526
|
+
// 1.19.49 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
527
|
+
// landed since 1.19.48 with no explicit bump. run 31523559509. (task 1002620)
|
|
524
528
|
// ---------------------------------------------------------------------------
|
|
525
|
-
const CORE_VERSION = '1.19.
|
|
529
|
+
const CORE_VERSION = '1.19.49'; // CI auto-patch carrier (ADR 0161); see changelog above
|
|
526
530
|
|
|
527
531
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
528
532
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// tests/authorship_audit.mjs — the no-hardcoded-Archon-identity gate (task 1002640).
|
|
2
|
+
//
|
|
3
|
+
// scripts/gds/audit-authorship.sh (named as THE enforcement in
|
|
4
|
+
// docs/canonical-permissions.md) had no caller — no CI lane, no test, no skill
|
|
5
|
+
// — and 342 stale hits on a clean tree. This test makes it a real gate: it runs
|
|
6
|
+
// inside the required `unit` check, so a new hardcoded founder-identity
|
|
7
|
+
// reference in implementation code fails the PR. The script is local-only (grep
|
|
8
|
+
// over the tree — no DB, no network). Fail-open only where the RUNTIME is
|
|
9
|
+
// missing: a builder machine without bash on PATH (the gen-diagrams render-step
|
|
10
|
+
// precedent) skips with a warning; Linux CI always has bash, so the gate is
|
|
11
|
+
// always live where it matters.
|
|
12
|
+
|
|
13
|
+
import { strict as assert } from 'node:assert';
|
|
14
|
+
import { spawnSync } from 'node:child_process';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const REPO = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
19
|
+
const SCRIPT = path.join(REPO, 'scripts', 'gds', 'audit-authorship.sh');
|
|
20
|
+
const SPAWN_TIMEOUT_MS = 75_000; // under run-unit-tests' 90s cap
|
|
21
|
+
|
|
22
|
+
const r = spawnSync('bash', [SCRIPT], {
|
|
23
|
+
cwd: REPO,
|
|
24
|
+
encoding: 'utf8',
|
|
25
|
+
timeout: SPAWN_TIMEOUT_MS,
|
|
26
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (r.error && r.error.code === 'ENOENT') {
|
|
30
|
+
console.warn('authorship_audit: bash not on PATH — skipping (the gate runs on Linux CI; a bash-less builder box cannot run a .sh).');
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// NO timeout fail-open: the audit is local-only (grep over the tree — no DB,
|
|
35
|
+
// no network), so unlike an infra-dependent check there is no innocent reason
|
|
36
|
+
// for it to hang; a diff engineered to make the scan slow must FAIL the gate,
|
|
37
|
+
// not slip through it. spawnSync's ETIMEDOUT falls through to the assertions.
|
|
38
|
+
assert.equal(r.error, undefined, `audit-authorship.sh failed to run: ${r.error && r.error.message}`);
|
|
39
|
+
assert.equal(
|
|
40
|
+
r.status,
|
|
41
|
+
0,
|
|
42
|
+
`audit-authorship.sh found hardcoded founder-identity references in implementation code:\n${r.stdout}\n${r.stderr}`
|
|
43
|
+
);
|
|
44
|
+
console.log('authorship_audit: clean — no hardcoded Archon-identity references in implementation code.');
|