@bongos/core 1.19.734 → 1.19.735
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 +17 -12
- package/docs/module-api-changelog.md +2 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/package-core.js +31 -10
- package/src/module-api.js +1 -1
- package/tests/leak_scan_fail_closed.mjs +108 -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.735",
|
|
6
|
+
"core_contract": "1.19.735",
|
|
7
|
+
"source_commit": "6688485db7975049f67d21b58eac72ab6a93875e",
|
|
8
8
|
"source_ref": "HEAD",
|
|
9
|
-
"built_at": "2026-09-
|
|
9
|
+
"built_at": "2026-09-13T16:18:04.615Z",
|
|
10
10
|
"redaction": {
|
|
11
11
|
"model": "docs-redacted+functional-verbatim",
|
|
12
12
|
"docs_redacted": 478,
|
|
13
13
|
"agent_docs_stubbed": 24,
|
|
14
|
-
"functional_verbatim":
|
|
14
|
+
"functional_verbatim": 2108,
|
|
15
15
|
"rules": 3,
|
|
16
16
|
"gate_literals": 3,
|
|
17
17
|
"gate": "passed"
|
|
18
18
|
},
|
|
19
|
-
"file_count":
|
|
20
|
-
"tree_sha256": "
|
|
19
|
+
"file_count": 2610,
|
|
20
|
+
"tree_sha256": "4b125203b2c2f21ff8db51bae409a2e72e3e7099c38bc1e17a85f48573b17831",
|
|
21
21
|
"files": [
|
|
22
22
|
{
|
|
23
23
|
"path": ".claude/skills/ask-for-help/SKILL.md",
|
|
@@ -2487,7 +2487,7 @@
|
|
|
2487
2487
|
{
|
|
2488
2488
|
"path": "docs/module-api-changelog.md",
|
|
2489
2489
|
"mode": "0000644",
|
|
2490
|
-
"sha256": "
|
|
2490
|
+
"sha256": "3d409c55101525a3f86cf54a60169bc3d82c6926118b9234d98487c44128d7b7"
|
|
2491
2491
|
},
|
|
2492
2492
|
{
|
|
2493
2493
|
"path": "docs/modules-contract.md",
|
|
@@ -7532,12 +7532,12 @@
|
|
|
7532
7532
|
{
|
|
7533
7533
|
"path": "package-lock.json",
|
|
7534
7534
|
"mode": "0000644",
|
|
7535
|
-
"sha256": "
|
|
7535
|
+
"sha256": "210fb895f45fb7015cd76403ab23dabddbbc53d4fe45c6f2fd3ae4c313daeb18"
|
|
7536
7536
|
},
|
|
7537
7537
|
{
|
|
7538
7538
|
"path": "package.json",
|
|
7539
7539
|
"mode": "0000644",
|
|
7540
|
-
"sha256": "
|
|
7540
|
+
"sha256": "6fe0a516197ae1a54ee1d809bc4faa941ae9ff9e3b681adc4184953dd756d518"
|
|
7541
7541
|
},
|
|
7542
7542
|
{
|
|
7543
7543
|
"path": "public-docs/index.html",
|
|
@@ -8327,7 +8327,7 @@
|
|
|
8327
8327
|
{
|
|
8328
8328
|
"path": "scripts/gds/package-core.js",
|
|
8329
8329
|
"mode": "0000644",
|
|
8330
|
-
"sha256": "
|
|
8330
|
+
"sha256": "225bf45e1e0b297e25b140263a6bd2b616d63a9ab2ee0517edfcf71630cef5aa"
|
|
8331
8331
|
},
|
|
8332
8332
|
{
|
|
8333
8333
|
"path": "scripts/gds/paste-token.js",
|
|
@@ -9337,7 +9337,7 @@
|
|
|
9337
9337
|
{
|
|
9338
9338
|
"path": "src/module-api.js",
|
|
9339
9339
|
"mode": "0000644",
|
|
9340
|
-
"sha256": "
|
|
9340
|
+
"sha256": "1bb00c54f48017dd7f83cf8c8d51e8c0acc0f80cb939a5e304a9e70c3fe2a836"
|
|
9341
9341
|
},
|
|
9342
9342
|
{
|
|
9343
9343
|
"path": "src/module-loader/catalog.js",
|
|
@@ -11374,6 +11374,11 @@
|
|
|
11374
11374
|
"mode": "0000644",
|
|
11375
11375
|
"sha256": "f6097301300cdb559d3620a5c602b763b70f1acc14816a7e70e1cdb61bb42d95"
|
|
11376
11376
|
},
|
|
11377
|
+
{
|
|
11378
|
+
"path": "tests/leak_scan_fail_closed.mjs",
|
|
11379
|
+
"mode": "0000644",
|
|
11380
|
+
"sha256": "e5968a1df544680db05c66eeec803ebdbbbe98932bfec31a5287617c6dc01466"
|
|
11381
|
+
},
|
|
11377
11382
|
{
|
|
11378
11383
|
"path": "tests/lib_sh_resolution.mjs",
|
|
11379
11384
|
"mode": "0000644",
|
|
@@ -1942,5 +1942,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
1942
1942
|
landed since 1.19.732 with no explicit bump. run 34766569496. (task 1002620)
|
|
1943
1943
|
1.19.734 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1944
1944
|
landed since 1.19.733 with no explicit bump. run 34767120578. (task 1002620)
|
|
1945
|
+
1.19.735 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
1946
|
+
landed since 1.19.734 with no explicit bump. run 34768136326. (task 1002620)
|
|
1945
1947
|
---------------------------------------------------------------------------
|
|
1946
1948
|
```
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.735",
|
|
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.735",
|
|
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.735",
|
|
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",
|
|
@@ -59,8 +59,11 @@
|
|
|
59
59
|
// (task 1002218 / audit H3) — deterministic + network-free.
|
|
60
60
|
// --self-verify-boot ALSO `npm install <tgz>` into a throwaway consumer + boot /healthz
|
|
61
61
|
// (reuses tests/consumer_layout_boot.mjs; needs npm/registry access).
|
|
62
|
-
// --leak-scan
|
|
63
|
-
//
|
|
62
|
+
// --no-leak-scan THE ONLY ESCAPE from the post-build leak scan: skips it entirely.
|
|
63
|
+
// The scan is FAIL-CLOSED by default — an un-allowlisted prior-instance
|
|
64
|
+
// literal in the built artifact aborts the build (task 1003870 / H6).
|
|
65
|
+
// --leak-scan-strict accepted as an explicit no-op; fatal IS the default since task
|
|
66
|
+
// 1003870. Kept so CI can state the intent it relies on out loud.
|
|
64
67
|
// Outputs (nothing is committed — dist/ is gitignored):
|
|
65
68
|
// dist/bongos-core-<version>/ the redacted core tree (inspectable)
|
|
66
69
|
// dist/bongos-core-<version>.tgz the installable unit
|
|
@@ -629,6 +632,18 @@ function scanKindOf(pathRel) {
|
|
|
629
632
|
return 'functional';
|
|
630
633
|
}
|
|
631
634
|
|
|
635
|
+
// The post-build leak scan's POLICY, split out of main() so a test can plant a literal and prove
|
|
636
|
+
// the build refuses without running a full 2-minute package (task 1003870). Pure: argv in, verdict
|
|
637
|
+
// out. Fail-closed — any un-allowlisted prior-instance literal is fatal unless the operator has
|
|
638
|
+
// explicitly said --no-leak-scan, which skips the scan altogether rather than downgrading it.
|
|
639
|
+
// `--leak-scan-strict` is honoured as a no-op: it named this behaviour before it became default.
|
|
640
|
+
function leakScanVerdict(remainingLiteralHits, argv = process.argv) {
|
|
641
|
+
if (argv.includes('--no-leak-scan')) return { run: false, fatal: false, reason: 'skipped' };
|
|
642
|
+
const n = (remainingLiteralHits || []).length;
|
|
643
|
+
if (n === 0) return { run: true, fatal: false, reason: 'clean' };
|
|
644
|
+
return { run: true, fatal: true, reason: 'prior-instance-literals' };
|
|
645
|
+
}
|
|
646
|
+
|
|
632
647
|
// Independent post-build leak scan over the built core file set (task 1002220 / audit H6). Two layers:
|
|
633
648
|
// • INSTANCE LITERALS — findLeaks() over PRIOR_INSTANCE_LITERALS (+ the public-IP floor) across
|
|
634
649
|
// EVERY shipped file: brand/owner/history that must not ship in a portable core. This is the
|
|
@@ -942,14 +957,14 @@ function main() {
|
|
|
942
957
|
|
|
943
958
|
// Post-build leak scan (task 1002220 / audit H6): independent verification that the BUILT
|
|
944
959
|
// artifact carries no prior-instance identity, + a warn-level secret-shape scan over functional
|
|
945
|
-
// files. Runs on every build
|
|
946
|
-
//
|
|
947
|
-
//
|
|
948
|
-
// secret-shape hit
|
|
960
|
+
// files. Runs on every build and is FAIL-CLOSED: an un-allowlisted prior-instance literal aborts
|
|
961
|
+
// the build. The trunk sweep (task 1003869) cleared the residue those literals used to represent,
|
|
962
|
+
// so warning instead of failing would only let it creep back (task 1003870). --no-leak-scan is
|
|
963
|
+
// the sole escape. A secret-shape hit stays a non-fatal warning — those 14 files were each
|
|
964
|
+
// confirmed a test fixture (task 1003871) and the R88 functional-verbatim fix is preserved.
|
|
949
965
|
if (!process.argv.includes('--no-leak-scan')) {
|
|
950
966
|
const scanFiles = staged.map((s) => ({ path: s.name.startsWith(TAR_ROOT) ? s.name.slice(TAR_ROOT.length) : s.name, content: s.buf }));
|
|
951
967
|
const scan = scanArtifactForLeaks(scanFiles);
|
|
952
|
-
const strict = process.argv.includes('--leak-scan-strict');
|
|
953
968
|
// Named, reasoned exceptions (task 1003869). A detector must carry the pattern it
|
|
954
969
|
// detects and a "public IPs are flagged" test must be handed a public IP, so those
|
|
955
970
|
// hits are real but not leaks. Each is listed per (file, literal) with its reason in
|
|
@@ -966,17 +981,21 @@ function main() {
|
|
|
966
981
|
for (const e of stale) console.error(` ${e.path} [${e.literal}]`);
|
|
967
982
|
}
|
|
968
983
|
scan.literalHits = remaining;
|
|
984
|
+
const verdict = leakScanVerdict(scan.literalHits);
|
|
969
985
|
if (scan.literalHits.length) {
|
|
970
986
|
const byLit = {};
|
|
971
987
|
for (const h of scan.literalHits) byLit[h.sample] = (byLit[h.sample] || 0) + 1;
|
|
972
988
|
const summary = Object.entries(byLit).sort((a, b) => b[1] - a[1]).map(([k, n]) => `${k}×${n}`).join(', ');
|
|
973
989
|
const files = [...new Set(scan.literalHits.map((h) => h.path))];
|
|
974
990
|
console.error('');
|
|
975
|
-
console.error(`[leak-scan]
|
|
991
|
+
console.error(`[leak-scan] FAILED — ${scan.literalHits.length} prior-instance literal hit(s) across ${files.length} shipped file(s): ${summary}`);
|
|
976
992
|
for (const p of files.slice(0, 30)) console.error(` ${p}`);
|
|
977
993
|
if (files.length > 30) console.error(` … +${files.length - 30} more file(s)`);
|
|
978
|
-
|
|
979
|
-
console.error('[leak-scan]
|
|
994
|
+
console.error('[leak-scan] refusing to certify a leaky artifact. Either remove the literal at SOURCE (check what');
|
|
995
|
+
console.error('[leak-scan] REGENERATES the file — a generator re-leaks on every run, task 1003911), or, if the hit is');
|
|
996
|
+
console.error('[leak-scan] a detector carrying its own pattern, add a named (path, class) reason to');
|
|
997
|
+
console.error('[leak-scan] scripts/gds/leak-scan-allowlist.js. --no-leak-scan skips this gate entirely.');
|
|
998
|
+
if (verdict.fatal) process.exit(1);
|
|
980
999
|
} else {
|
|
981
1000
|
console.error('[leak-scan] ✓ no prior-instance literals in the built artifact.');
|
|
982
1001
|
}
|
|
@@ -1021,6 +1040,8 @@ module.exports = {
|
|
|
1021
1040
|
selfVerify, reproducePinFromTree,
|
|
1022
1041
|
// task 1002220 (audit H6) — post-build leak scan (prior-instance literals + functional secret shapes)
|
|
1023
1042
|
scanArtifactForLeaks, PRIOR_INSTANCE_LITERALS,
|
|
1043
|
+
// task 1003870 — the fail-closed verdict the build acts on (pure, so a test can plant a literal)
|
|
1044
|
+
leakScanVerdict,
|
|
1024
1045
|
// task 1002217 (audit H4) — the fixed neutral floor injected into the doc-redaction + fail-closed gate
|
|
1025
1046
|
PRIOR_INSTANCE_FLOOR,
|
|
1026
1047
|
};
|
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.735'; // 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');
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// tests/leak_scan_fail_closed.mjs
|
|
2
|
+
//
|
|
3
|
+
// Task 1003870 — the post-build leak scan must FAIL CLOSED. The detector (task 1002220) and
|
|
4
|
+
// the neutral floor (task 1002217) both landed, but strictness was opt-in and the publish lane
|
|
5
|
+
// never opted in, so a leaky artifact could have gone to npm while the workflow's own header
|
|
6
|
+
// comment claimed a fail-closed gate. This locks both halves:
|
|
7
|
+
// 1. the POLICY — planting a prior-instance literal makes the build refuse, with no flag,
|
|
8
|
+
// 2. the WIRING — the publish lane still arms the gate and never disarms it.
|
|
9
|
+
// (2) is the half that was actually broken, and a policy test alone would not have caught it.
|
|
10
|
+
//
|
|
11
|
+
// Run: node tests/leak_scan_fail_closed.mjs
|
|
12
|
+
|
|
13
|
+
import { strict as assert } from 'node:assert';
|
|
14
|
+
import { createRequire } from 'node:module';
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { dirname, join } from 'node:path';
|
|
18
|
+
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
20
|
+
const { scanArtifactForLeaks, leakScanVerdict, PRIOR_INSTANCE_FLOOR } = require('../scripts/gds/package-core.js');
|
|
21
|
+
|
|
22
|
+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
23
|
+
|
|
24
|
+
// This file is itself published, so it DERIVES the literal it plants instead of spelling it
|
|
25
|
+
// out — the self-leak invariant the allowlist and mirror-redact both hold about themselves.
|
|
26
|
+
// It also means a future rename of the prior instance cannot quietly gut this test: the plant
|
|
27
|
+
// follows the floor, rather than pinning a string that would stop matching.
|
|
28
|
+
const TOKEN = PRIOR_INSTANCE_FLOOR.tokens[0];
|
|
29
|
+
const OWNER = PRIOR_INSTANCE_FLOOR.owners[0];
|
|
30
|
+
|
|
31
|
+
let passed = 0, failed = 0;
|
|
32
|
+
function t(name, fn) {
|
|
33
|
+
try { fn(); passed++; console.log(` PASS ${name}`); }
|
|
34
|
+
catch (e) { failed++; console.log(` FAIL ${name}\n ${e.message}`); }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('\nthe planted literal makes the build refuse (no flag required):');
|
|
38
|
+
|
|
39
|
+
t('a planted prior-instance token in a functional file is FATAL by default', () => {
|
|
40
|
+
const files = [{ path: 'src/some-module.js', content: `const host = "${TOKEN}";\n` }];
|
|
41
|
+
const scan = scanArtifactForLeaks(files);
|
|
42
|
+
assert.ok(scan.literalHits.length > 0, 'the scan must see the planted token');
|
|
43
|
+
const v = leakScanVerdict(scan.literalHits, ['node', 'package-core.js']);
|
|
44
|
+
assert.equal(v.run, true, 'the scan runs when no escape flag is passed');
|
|
45
|
+
assert.equal(v.fatal, true, 'THE LOAD-BEARING ASSERTION: a leak aborts the build with no flag');
|
|
46
|
+
assert.equal(v.reason, 'prior-instance-literals');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
t('a planted prior-instance OWNER is fatal too, not just the token', () => {
|
|
50
|
+
const files = [{ path: 'scripts/thing.js', content: `// maintained by ${OWNER}\n` }];
|
|
51
|
+
const scan = scanArtifactForLeaks(files);
|
|
52
|
+
assert.ok(scan.literalHits.length > 0, 'the scan must see the planted owner');
|
|
53
|
+
assert.equal(leakScanVerdict(scan.literalHits, ['node', 'x']).fatal, true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
t('a clean artifact is NOT fatal (the gate does not fire on everything)', () => {
|
|
57
|
+
const files = [{ path: 'src/clean.js', content: 'const x = 1;\n' }];
|
|
58
|
+
const scan = scanArtifactForLeaks(files);
|
|
59
|
+
assert.equal(scan.literalHits.length, 0);
|
|
60
|
+
const v = leakScanVerdict(scan.literalHits, ['node', 'x']);
|
|
61
|
+
assert.equal(v.fatal, false);
|
|
62
|
+
assert.equal(v.reason, 'clean');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
t('--leak-scan-strict is a no-op: it cannot be the thing that makes it fatal', () => {
|
|
66
|
+
const files = [{ path: 'src/some-module.js', content: `x = "${TOKEN}"\n` }];
|
|
67
|
+
const hits = scanArtifactForLeaks(files).literalHits;
|
|
68
|
+
const withFlag = leakScanVerdict(hits, ['node', 'x', '--leak-scan-strict']);
|
|
69
|
+
const without = leakScanVerdict(hits, ['node', 'x']);
|
|
70
|
+
assert.deepEqual(withFlag, without, 'strict must add nothing — fatal is the default now');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
t('--no-leak-scan is the only escape, and it skips rather than downgrades', () => {
|
|
74
|
+
const files = [{ path: 'src/some-module.js', content: `x = "${TOKEN}"\n` }];
|
|
75
|
+
const hits = scanArtifactForLeaks(files).literalHits;
|
|
76
|
+
const v = leakScanVerdict(hits, ['node', 'x', '--no-leak-scan']);
|
|
77
|
+
assert.equal(v.run, false, 'the scan does not run at all');
|
|
78
|
+
assert.equal(v.fatal, false);
|
|
79
|
+
assert.equal(v.reason, 'skipped');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
console.log('\nthe publish lane arms the gate (the half that was actually broken):');
|
|
83
|
+
|
|
84
|
+
const publishYml = readFileSync(join(ROOT, '.github/workflows/publish.yml'), 'utf8');
|
|
85
|
+
const packLine = publishYml.split('\n').find((l) => l.includes('package-core.js') && l.includes('--ref HEAD'));
|
|
86
|
+
|
|
87
|
+
t('publish.yml still invokes package-core to build the release artifact', () => {
|
|
88
|
+
assert.ok(packLine, 'no package-core invocation found — the lane was rewired, re-check this test');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
t('the publish invocation arms the leak gate explicitly', () => {
|
|
92
|
+
assert.ok(packLine.includes('--leak-scan-strict'),
|
|
93
|
+
'the publish lane must state the gate it depends on, even though fatal is the default');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
t('nothing the publish lane RUNS disarms the leak scan', () => {
|
|
97
|
+
// Executable lines only: a YAML/shell comment may legitimately name the escape flag while
|
|
98
|
+
// explaining why the lane never uses it, and matching prose would fail on its own docs.
|
|
99
|
+
const executable = publishYml
|
|
100
|
+
.split('\n')
|
|
101
|
+
.filter((l) => !/^\s*#/.test(l))
|
|
102
|
+
.join('\n');
|
|
103
|
+
assert.ok(!executable.includes('--no-leak-scan'),
|
|
104
|
+
'the one lane that makes an artifact permanent and public must never skip the scan');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
console.log(`\n${passed} passed, ${failed} failed\n`);
|
|
108
|
+
if (failed) process.exit(1);
|