@blamejs/exceptd-skills 0.16.8 → 0.16.10
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/CHANGELOG.md +16 -1
- package/data/_indexes/_meta.json +10 -10
- package/data/_indexes/activity-feed.json +18 -18
- package/data/_indexes/catalog-summaries.json +6 -6
- package/data/_indexes/chains.json +1139 -0
- package/data/_indexes/frequency.json +1 -0
- package/data/atlas-ttps.json +8 -3
- package/data/attack-techniques.json +34 -12
- package/data/cve-catalog.json +684 -3
- package/data/cwe-catalog.json +39 -8
- package/data/framework-control-gaps.json +51 -18
- package/data/zeroday-lessons.json +527 -2
- package/lib/cve-curation.js +2 -4
- package/lib/flag-suggest.js +1 -1
- package/lib/lint-skills.js +1 -0
- package/lib/playbook-runner.js +2 -2
- package/lib/scoring.js +3 -3
- package/lib/validate-playbooks.js +0 -2
- package/manifest.json +44 -44
- package/package.json +1 -1
- package/sbom.cdx.json +42 -42
- package/scripts/check-codebase-patterns-currency.js +1 -2
- package/scripts/check-codebase-patterns.js +109 -1
- package/scripts/release.js +2 -2
package/sbom.cdx.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.6",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:8bb2d8cc-10a2-40a8-a3e7-67aba4a5fe06",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "
|
|
7
|
+
"timestamp": "2100-04-09T18:45:32.000Z",
|
|
8
8
|
"tools": [
|
|
9
9
|
{
|
|
10
10
|
"vendor": "blamejs",
|
|
11
11
|
"name": "scripts/refresh-sbom.js",
|
|
12
|
-
"version": "0.16.
|
|
12
|
+
"version": "0.16.10"
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"component": {
|
|
16
|
-
"bom-ref": "pkg:npm/@blamejs/exceptd-skills@0.16.
|
|
16
|
+
"bom-ref": "pkg:npm/@blamejs/exceptd-skills@0.16.10",
|
|
17
17
|
"type": "application",
|
|
18
18
|
"name": "@blamejs/exceptd-skills",
|
|
19
|
-
"version": "0.16.
|
|
19
|
+
"version": "0.16.10",
|
|
20
20
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 42 skills, 11 catalogs (427 CVEs / 173 CWEs / 805 ATT&CK + ICS / 170 ATLAS / 468 D3FEND / 8888 RFCs), 35 jurisdictions, 10-class catalog gap detector + budget gate, real XML parser + canonical-form diff + content-pattern regression detection, Ed25519-signed.",
|
|
21
21
|
"licenses": [
|
|
22
22
|
{
|
|
@@ -25,17 +25,17 @@
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
|
-
"purl": "pkg:npm/%40blamejs/exceptd-skills@0.16.
|
|
28
|
+
"purl": "pkg:npm/%40blamejs/exceptd-skills@0.16.10",
|
|
29
29
|
"hashes": [
|
|
30
30
|
{
|
|
31
31
|
"alg": "SHA-256",
|
|
32
|
-
"content": "
|
|
32
|
+
"content": "6645aae260375bdfd45fef3a154848cb7b71634e0cb8a5063beacce54ed78dc6"
|
|
33
33
|
}
|
|
34
34
|
],
|
|
35
35
|
"externalReferences": [
|
|
36
36
|
{
|
|
37
37
|
"type": "distribution",
|
|
38
|
-
"url": "https://www.npmjs.com/package/@blamejs/exceptd-skills/v/0.16.
|
|
38
|
+
"url": "https://www.npmjs.com/package/@blamejs/exceptd-skills/v/0.16.10"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"type": "vcs",
|
|
@@ -116,11 +116,11 @@
|
|
|
116
116
|
"hashes": [
|
|
117
117
|
{
|
|
118
118
|
"alg": "SHA-256",
|
|
119
|
-
"content": "
|
|
119
|
+
"content": "00756e446fca3d66af2838dee91d30f591e5f8a179c97683eaebe4b3495a27d6"
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
122
|
"alg": "SHA3-512",
|
|
123
|
-
"content": "
|
|
123
|
+
"content": "ebe3f08786809489c762ec4cc294b9f78124013d44ce82e77c2fb501cd49b0c1692c380881829e4e301a2c786fcbf2edf871d480fd006ef3dc72b0f1f3bfe66a"
|
|
124
124
|
}
|
|
125
125
|
]
|
|
126
126
|
},
|
|
@@ -296,11 +296,11 @@
|
|
|
296
296
|
"hashes": [
|
|
297
297
|
{
|
|
298
298
|
"alg": "SHA-256",
|
|
299
|
-
"content": "
|
|
299
|
+
"content": "f66b456cf82a3c20575d8479de41f7b11b7ee5693eb1fcf64a67e162ae1b88a2"
|
|
300
300
|
},
|
|
301
301
|
{
|
|
302
302
|
"alg": "SHA3-512",
|
|
303
|
-
"content": "
|
|
303
|
+
"content": "ac0a2fb2d7ecfd6dee341a59decaba6392c537c828ff03418f8b981dfbd5ed5e1d832ad1080c2b928444e8cb8d611de602064df278ab56a9bee235e4e180256e"
|
|
304
304
|
}
|
|
305
305
|
]
|
|
306
306
|
},
|
|
@@ -311,11 +311,11 @@
|
|
|
311
311
|
"hashes": [
|
|
312
312
|
{
|
|
313
313
|
"alg": "SHA-256",
|
|
314
|
-
"content": "
|
|
314
|
+
"content": "c39f28e3402ef13ad9b7076819f63fda67a22f97e3e375cfe01c4a4e0beff7c9"
|
|
315
315
|
},
|
|
316
316
|
{
|
|
317
317
|
"alg": "SHA3-512",
|
|
318
|
-
"content": "
|
|
318
|
+
"content": "3a28ad5f73ae2db91948756336ba523c2158b3c0000676c12db8309daca3d601103d4231e7e5ad4a3788c06c7d98257bc3b38c797a200ca7f88b5ff059d3a8d2"
|
|
319
319
|
}
|
|
320
320
|
]
|
|
321
321
|
},
|
|
@@ -326,11 +326,11 @@
|
|
|
326
326
|
"hashes": [
|
|
327
327
|
{
|
|
328
328
|
"alg": "SHA-256",
|
|
329
|
-
"content": "
|
|
329
|
+
"content": "8264da4534d39c9493cfcd18acf7e38ed47ce2a81be15afd5a3f4baf1d504929"
|
|
330
330
|
},
|
|
331
331
|
{
|
|
332
332
|
"alg": "SHA3-512",
|
|
333
|
-
"content": "
|
|
333
|
+
"content": "9cc4838794d659360d86b85f03ca8eebd7233c5a4f50ff83bccd6c962efedc3f9ca7c63cb7c35fef3e798cbca6d35d914da560bf02d63739c01007d0f56edb9a"
|
|
334
334
|
}
|
|
335
335
|
]
|
|
336
336
|
},
|
|
@@ -341,11 +341,11 @@
|
|
|
341
341
|
"hashes": [
|
|
342
342
|
{
|
|
343
343
|
"alg": "SHA-256",
|
|
344
|
-
"content": "
|
|
344
|
+
"content": "5def8d82bbe51382ec55fc7186722974077e1289194e4ea002df0e3c52c6a017"
|
|
345
345
|
},
|
|
346
346
|
{
|
|
347
347
|
"alg": "SHA3-512",
|
|
348
|
-
"content": "
|
|
348
|
+
"content": "59c7a63a85811aa46842b2a7888998e61983752bc3975ac65b69cf54ebea5a16d4f553690b4c2bc8afadf995d32435cdcbe5b77dc9825de2f7fccf0bb4c02fe7"
|
|
349
349
|
}
|
|
350
350
|
]
|
|
351
351
|
},
|
|
@@ -401,11 +401,11 @@
|
|
|
401
401
|
"hashes": [
|
|
402
402
|
{
|
|
403
403
|
"alg": "SHA-256",
|
|
404
|
-
"content": "
|
|
404
|
+
"content": "3f9ad83198da40d920e70933e615ac14ade4add037e1c664586c2ee3524edec4"
|
|
405
405
|
},
|
|
406
406
|
{
|
|
407
407
|
"alg": "SHA3-512",
|
|
408
|
-
"content": "
|
|
408
|
+
"content": "f4dd727e8d0b14ffc17e60437cd4904158242938c00d6b1217a528925a2628bae4783bdfa912da4776102d8a42634857e3cdcd600bd7691e1cfeb9efcd24f60e"
|
|
409
409
|
}
|
|
410
410
|
]
|
|
411
411
|
},
|
|
@@ -806,11 +806,11 @@
|
|
|
806
806
|
"hashes": [
|
|
807
807
|
{
|
|
808
808
|
"alg": "SHA-256",
|
|
809
|
-
"content": "
|
|
809
|
+
"content": "b6403d31f06e8f081217c338d2d5c515f8352295fbf58395f3c571cd95a05de0"
|
|
810
810
|
},
|
|
811
811
|
{
|
|
812
812
|
"alg": "SHA3-512",
|
|
813
|
-
"content": "
|
|
813
|
+
"content": "20acd5641af244666e023470670fd6dede0c58a0d750ff013e0fcf9b003a19d85abaf9803a414509642d2f8f6d6eba7e229ac506e112165c9db4471c4d8fcaea"
|
|
814
814
|
}
|
|
815
815
|
]
|
|
816
816
|
},
|
|
@@ -1166,11 +1166,11 @@
|
|
|
1166
1166
|
"hashes": [
|
|
1167
1167
|
{
|
|
1168
1168
|
"alg": "SHA-256",
|
|
1169
|
-
"content": "
|
|
1169
|
+
"content": "069a323205aa0ee280661b9bd1b85bb4d35ea547f7f5dfdd24ea545d14ef492f"
|
|
1170
1170
|
},
|
|
1171
1171
|
{
|
|
1172
1172
|
"alg": "SHA3-512",
|
|
1173
|
-
"content": "
|
|
1173
|
+
"content": "ff9b24c9197e80129933c1f2b89e820ebdbd401ef50b9e255723de04c959f81b0abef396bca24f0e8236b9048ff7fd516219a12f753d8297120d7ebe1af1c9de"
|
|
1174
1174
|
}
|
|
1175
1175
|
]
|
|
1176
1176
|
},
|
|
@@ -1226,11 +1226,11 @@
|
|
|
1226
1226
|
"hashes": [
|
|
1227
1227
|
{
|
|
1228
1228
|
"alg": "SHA-256",
|
|
1229
|
-
"content": "
|
|
1229
|
+
"content": "eb1a3820bba3203967c6057f12cd594e18f3044d966e1c7c1ba17757d902559f"
|
|
1230
1230
|
},
|
|
1231
1231
|
{
|
|
1232
1232
|
"alg": "SHA3-512",
|
|
1233
|
-
"content": "
|
|
1233
|
+
"content": "1a0acc79ebea7cb9d80cde43503c14f14342ccffda834752c2f29215aacfba46a9d120e78c544cd389e6023ccaa519b829dc82eb4f4de6ed1d4ca2ce2ee06e97"
|
|
1234
1234
|
}
|
|
1235
1235
|
]
|
|
1236
1236
|
},
|
|
@@ -1301,11 +1301,11 @@
|
|
|
1301
1301
|
"hashes": [
|
|
1302
1302
|
{
|
|
1303
1303
|
"alg": "SHA-256",
|
|
1304
|
-
"content": "
|
|
1304
|
+
"content": "0ce41dee14acf7998866f5adb63502b614b5501acf8f88c37cd277c96b91a87c"
|
|
1305
1305
|
},
|
|
1306
1306
|
{
|
|
1307
1307
|
"alg": "SHA3-512",
|
|
1308
|
-
"content": "
|
|
1308
|
+
"content": "58f6d75ff97f64633937bef489fdfefd6cf331115109cab30b2064cf3aebfaaddde6c973fa71b31bb44f06ecb485751ee9137e11f528a61b329b4699d53a4041"
|
|
1309
1309
|
}
|
|
1310
1310
|
]
|
|
1311
1311
|
},
|
|
@@ -1316,11 +1316,11 @@
|
|
|
1316
1316
|
"hashes": [
|
|
1317
1317
|
{
|
|
1318
1318
|
"alg": "SHA-256",
|
|
1319
|
-
"content": "
|
|
1319
|
+
"content": "68bc62828f28047b5f09da9e5fa3c2cc3ed98d965c1a43dbf51b9fa7e45ec1a1"
|
|
1320
1320
|
},
|
|
1321
1321
|
{
|
|
1322
1322
|
"alg": "SHA3-512",
|
|
1323
|
-
"content": "
|
|
1323
|
+
"content": "c05800e93846fb755ded51be74047d84d032eeff9f5a0b818b1abc16f76c7032181ded4d5cf054d0387c3d7f2d71095f55a7a42c7f4c2764ec0115300ce75c85"
|
|
1324
1324
|
}
|
|
1325
1325
|
]
|
|
1326
1326
|
},
|
|
@@ -1451,11 +1451,11 @@
|
|
|
1451
1451
|
"hashes": [
|
|
1452
1452
|
{
|
|
1453
1453
|
"alg": "SHA-256",
|
|
1454
|
-
"content": "
|
|
1454
|
+
"content": "70fda3a2033d461f3ef1ac7e4bf259c9fe78090f1a1f5c09eb72dbf927e59955"
|
|
1455
1455
|
},
|
|
1456
1456
|
{
|
|
1457
1457
|
"alg": "SHA3-512",
|
|
1458
|
-
"content": "
|
|
1458
|
+
"content": "8547b087e1881cf58a55fd0aab186441f508ad226be0ab4aa3efd13a0e864af776f29576e25df9b4324ec7a4712bb3476faac5ed63a226a6ff71d225c297c969"
|
|
1459
1459
|
}
|
|
1460
1460
|
]
|
|
1461
1461
|
},
|
|
@@ -1631,11 +1631,11 @@
|
|
|
1631
1631
|
"hashes": [
|
|
1632
1632
|
{
|
|
1633
1633
|
"alg": "SHA-256",
|
|
1634
|
-
"content": "
|
|
1634
|
+
"content": "fe42cfd0758cb2709dc7dad91c4e47b495d6ebf984b00ace2422de34e744d35f"
|
|
1635
1635
|
},
|
|
1636
1636
|
{
|
|
1637
1637
|
"alg": "SHA3-512",
|
|
1638
|
-
"content": "
|
|
1638
|
+
"content": "a06a61b0f278a5973c0e4d6398d1688a574dec3442ca9823d0b4c5f37d1cb1cab47e8575580051b56e34829f8e22195ded1f4f57bdc3925ca32edae3e4c8839f"
|
|
1639
1639
|
}
|
|
1640
1640
|
]
|
|
1641
1641
|
},
|
|
@@ -1751,11 +1751,11 @@
|
|
|
1751
1751
|
"hashes": [
|
|
1752
1752
|
{
|
|
1753
1753
|
"alg": "SHA-256",
|
|
1754
|
-
"content": "
|
|
1754
|
+
"content": "b2f7ad163ce22cedc2a990633761b25d3f436012c20dc162739959f92220161f"
|
|
1755
1755
|
},
|
|
1756
1756
|
{
|
|
1757
1757
|
"alg": "SHA3-512",
|
|
1758
|
-
"content": "
|
|
1758
|
+
"content": "342cee9e227424456314cbbdf150ee9a4077ea00d2ae87d58e5301d80492af5cf7f38f1d0aa7f66751c77e7345ddefb40bb5f2ba58921d665985654dce7cfa0c"
|
|
1759
1759
|
}
|
|
1760
1760
|
]
|
|
1761
1761
|
},
|
|
@@ -2201,11 +2201,11 @@
|
|
|
2201
2201
|
"hashes": [
|
|
2202
2202
|
{
|
|
2203
2203
|
"alg": "SHA-256",
|
|
2204
|
-
"content": "
|
|
2204
|
+
"content": "7ef5ed5d9a6dd68b2d43419d7fa2d0408eb8b57b69588e51db136aa0f29e82a6"
|
|
2205
2205
|
},
|
|
2206
2206
|
{
|
|
2207
2207
|
"alg": "SHA3-512",
|
|
2208
|
-
"content": "
|
|
2208
|
+
"content": "b96dad01e1385bc17bb1fa54d2f0d86558063856c12401fca1d96a01869de984b87cf5c54ded025a5f93762c109385ef6aed5552abff36070e281810ae063db8"
|
|
2209
2209
|
}
|
|
2210
2210
|
]
|
|
2211
2211
|
},
|
|
@@ -2216,11 +2216,11 @@
|
|
|
2216
2216
|
"hashes": [
|
|
2217
2217
|
{
|
|
2218
2218
|
"alg": "SHA-256",
|
|
2219
|
-
"content": "
|
|
2219
|
+
"content": "bd449efbfde0263c17aa1d2cf4ff57f39f8221e78a7f8eb62392b522acc7f3b8"
|
|
2220
2220
|
},
|
|
2221
2221
|
{
|
|
2222
2222
|
"alg": "SHA3-512",
|
|
2223
|
-
"content": "
|
|
2223
|
+
"content": "1a7ecda566d16f89d15d721ca491962344fe9f011c27126f48cde5fb887405d5be5a28dac1892add97fd7316ab2204aa69020ede2bc1c43db4d988b45c1f1dea"
|
|
2224
2224
|
}
|
|
2225
2225
|
]
|
|
2226
2226
|
},
|
|
@@ -2486,11 +2486,11 @@
|
|
|
2486
2486
|
"hashes": [
|
|
2487
2487
|
{
|
|
2488
2488
|
"alg": "SHA-256",
|
|
2489
|
-
"content": "
|
|
2489
|
+
"content": "1e140b2a035043d72cfb1a46e57751bbb2d4b3d39ecc73b48c28625b260e17f3"
|
|
2490
2490
|
},
|
|
2491
2491
|
{
|
|
2492
2492
|
"alg": "SHA3-512",
|
|
2493
|
-
"content": "
|
|
2493
|
+
"content": "f027c768c24cd0c5a4aff871afe82482a7ee655a56a69ab0d95662609a95fb28a31a3b4aa1108f879bdbf59ce097a6536e931c128105a7d93436e6eed59bfd82"
|
|
2494
2494
|
}
|
|
2495
2495
|
]
|
|
2496
2496
|
},
|
|
@@ -30,7 +30,7 @@ const ROOT = path.resolve(__dirname, "..");
|
|
|
30
30
|
// Every key here was classified (adopted / already-owned / helper-dependent /
|
|
31
31
|
// out-of-scope). A class appearing upstream but absent here is NEW and wants
|
|
32
32
|
// triage. Refresh this list (and re-triage the delta) when this check fires.
|
|
33
|
-
const UPSTREAM_TRIAGED = Object.freeze([
|
|
33
|
+
const UPSTREAM_TRIAGED = Object.freeze([ // keep-sorted
|
|
34
34
|
"ai-disclosure-on-request-without-requested-gate",
|
|
35
35
|
"archive-gz-without-safedecompress",
|
|
36
36
|
"archive-wrap-partial-recipient",
|
|
@@ -59,7 +59,6 @@ const UPSTREAM_TRIAGED = Object.freeze([
|
|
|
59
59
|
"math-random-noncrypto",
|
|
60
60
|
"nfinity",
|
|
61
61
|
"no-number-money-arithmetic",
|
|
62
|
-
"numeric-opt-no-bounds-check",
|
|
63
62
|
"primitive-unreachable",
|
|
64
63
|
"process-exit",
|
|
65
64
|
"raw-byte-literal",
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
* VALID_ALLOW_CLASSES, or is missing the `— <reason>` tail. A typo'd
|
|
20
20
|
* marker suppresses nothing, so the underlying violation would ship
|
|
21
21
|
* unflagged — this meta-guard keeps the marker mechanism trustworthy.
|
|
22
|
+
* - unsorted-marked-array : a flat string array tagged `// keep-sorted` that
|
|
23
|
+
* drifted out of alphabetical order. Opt-in — only marked arrays are
|
|
24
|
+
* checked, so a one-time allowlist sort becomes a standing guarantee.
|
|
25
|
+
* - misaligned-marked-run : a `// keep-aligned` const/weight table whose
|
|
26
|
+
* `=`/`:` assignment columns are not all equal. Opt-in, same shape.
|
|
22
27
|
*
|
|
23
28
|
* Exceptions live at the violation site, not in this file:
|
|
24
29
|
* - file-level, in the first 50 lines: // codebase-patterns:allow-file <class> — <reason>
|
|
@@ -42,6 +47,8 @@ const VALID_ALLOW_CLASSES = Object.freeze({
|
|
|
42
47
|
"process-exit-after-stdout-write": true,
|
|
43
48
|
"dynamic-regex": true,
|
|
44
49
|
"bidi-codepoint-literal": true,
|
|
50
|
+
"unsorted-marked-array": true,
|
|
51
|
+
"misaligned-marked-run": true,
|
|
45
52
|
});
|
|
46
53
|
|
|
47
54
|
const EXCLUDE_DIRS = new Set([
|
|
@@ -272,6 +279,91 @@ function detectOrphanAllowClass(files) {
|
|
|
272
279
|
return hits;
|
|
273
280
|
}
|
|
274
281
|
|
|
282
|
+
// ---- opt-in readability detectors (preventative) -------------------------
|
|
283
|
+
// These fire ONLY on sites that explicitly opt in via a marker, so unmarked
|
|
284
|
+
// code is never flagged. They turn a one-time cleanup (sorting an allowlist,
|
|
285
|
+
// aligning a const table) into a standing guarantee: mark the cleaned site and
|
|
286
|
+
// the gate keeps it clean.
|
|
287
|
+
|
|
288
|
+
// `// keep-sorted` marks a flat string-literal array that must stay
|
|
289
|
+
// alphabetically sorted (e.g. an allowlist). Only arrays whose opening line
|
|
290
|
+
// carries the marker are checked; arrays containing object/nested elements are
|
|
291
|
+
// skipped (not a flat string list).
|
|
292
|
+
function scanUnsortedMarkedArray(rel, lines) {
|
|
293
|
+
const hits = [];
|
|
294
|
+
for (let i = 0; i < lines.length; i++) {
|
|
295
|
+
if (!/\/\/\s*keep-sorted\b/.test(lines[i])) continue;
|
|
296
|
+
const openIdx = lines[i].indexOf("[");
|
|
297
|
+
if (openIdx === -1) continue;
|
|
298
|
+
let depth = 0, started = false, body = "";
|
|
299
|
+
for (let j = i; j < lines.length; j++) {
|
|
300
|
+
const seg = (j === i) ? lines[j].slice(openIdx) : lines[j];
|
|
301
|
+
for (const ch of seg) {
|
|
302
|
+
if (ch === "[") { depth++; started = true; }
|
|
303
|
+
else if (ch === "]") { depth--; }
|
|
304
|
+
}
|
|
305
|
+
body += " " + seg;
|
|
306
|
+
if (started && depth <= 0) break;
|
|
307
|
+
}
|
|
308
|
+
if (/[{]/.test(body)) continue; // object/nested elements — not a flat string array
|
|
309
|
+
const strs = [];
|
|
310
|
+
const re = /(['"])((?:\\.|(?!\1).)*)\1/g;
|
|
311
|
+
let m;
|
|
312
|
+
while ((m = re.exec(body)) !== null) strs.push(m[2]);
|
|
313
|
+
if (strs.length < 2) continue;
|
|
314
|
+
const sorted = [...strs].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
315
|
+
if (strs.join("") !== sorted.join("")) {
|
|
316
|
+
const k = strs.findIndex((s, idx) => idx > 0 && strs[idx - 1] > s);
|
|
317
|
+
hits.push({ file: rel, line: i + 1, content: lines[i].trim(), why: `marked // keep-sorted but "${strs[k]}" is out of alphabetical order` });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return hits;
|
|
321
|
+
}
|
|
322
|
+
function detectUnsortedMarkedArray(files) {
|
|
323
|
+
const hits = [];
|
|
324
|
+
for (const rel of (files || filesUnder(["bin/exceptd.js", "lib", "orchestrator", "scripts"]))) {
|
|
325
|
+
if (rel === "scripts/check-codebase-patterns.js") continue; // holds the detector + its own marker prose
|
|
326
|
+
hits.push(...scanUnsortedMarkedArray(rel, readLines(rel)));
|
|
327
|
+
}
|
|
328
|
+
return hits;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// `// keep-aligned` marks a contiguous run of `IDENT = value` / `IDENT: value`
|
|
332
|
+
// lines (a const/weight table) whose assignment columns must all line up. The
|
|
333
|
+
// run is the lines immediately after the marker, until a blank or non-assignment
|
|
334
|
+
// line. Opt-in, so only deliberately-aligned tables are enforced.
|
|
335
|
+
function scanMisalignedMarkedRun(rel, lines) {
|
|
336
|
+
const hits = [];
|
|
337
|
+
for (let i = 0; i < lines.length; i++) {
|
|
338
|
+
if (!/\/\/\s*keep-aligned\b/.test(lines[i])) continue;
|
|
339
|
+
const run = [];
|
|
340
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
341
|
+
if (/^\s*$/.test(lines[j])) break;
|
|
342
|
+
const code = stripLineComment(lines[j]).replace(/\s+$/, "");
|
|
343
|
+
const m = code.match(/^(\s*[A-Za-z_$][\w$.'"-]*\s*)([:=])\s/);
|
|
344
|
+
if (!m) break;
|
|
345
|
+
run.push({ lineNo: j + 1, col: m[1].length, op: m[2], content: lines[j].trim() });
|
|
346
|
+
}
|
|
347
|
+
if (run.length < 2) continue;
|
|
348
|
+
const op = run[0].op;
|
|
349
|
+
const cols = run.filter((r) => r.op === op).map((r) => r.col);
|
|
350
|
+
const target = Math.max(...cols);
|
|
351
|
+
const bad = run.find((r) => r.op === op && r.col !== target);
|
|
352
|
+
if (bad) {
|
|
353
|
+
hits.push({ file: rel, line: bad.lineNo, content: bad.content, why: `marked // keep-aligned but the '${op}' columns are not all equal` });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return hits;
|
|
357
|
+
}
|
|
358
|
+
function detectMisalignedMarkedRun(files) {
|
|
359
|
+
const hits = [];
|
|
360
|
+
for (const rel of (files || filesUnder(["bin/exceptd.js", "lib", "orchestrator", "scripts"]))) {
|
|
361
|
+
if (rel === "scripts/check-codebase-patterns.js") continue;
|
|
362
|
+
hits.push(...scanMisalignedMarkedRun(rel, readLines(rel)));
|
|
363
|
+
}
|
|
364
|
+
return hits;
|
|
365
|
+
}
|
|
366
|
+
|
|
275
367
|
const CLASSES = [
|
|
276
368
|
{
|
|
277
369
|
id: "process-exit-after-stdout-write",
|
|
@@ -282,9 +374,21 @@ const CLASSES = [
|
|
|
282
374
|
{
|
|
283
375
|
id: "dynamic-regex",
|
|
284
376
|
run: detectDynamicRegex,
|
|
285
|
-
warnOnly:
|
|
377
|
+
warnOnly: false,
|
|
286
378
|
hint: "RegExp from operator input is a ReDoS sink — anchor + length-cap, or `// allow:dynamic-regex — <reason>` when the pattern is a trusted bundled schema",
|
|
287
379
|
},
|
|
380
|
+
{
|
|
381
|
+
id: "unsorted-marked-array",
|
|
382
|
+
run: detectUnsortedMarkedArray,
|
|
383
|
+
warnOnly: false,
|
|
384
|
+
hint: "a flat string array tagged `// keep-sorted` drifted out of alphabetical order — re-sort it, or drop the marker if the order is intentional",
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
id: "misaligned-marked-run",
|
|
388
|
+
run: detectMisalignedMarkedRun,
|
|
389
|
+
warnOnly: false,
|
|
390
|
+
hint: "a `// keep-aligned` const/weight table has uneven assignment columns — realign the `=`/`:` columns, or drop the marker",
|
|
391
|
+
},
|
|
288
392
|
{
|
|
289
393
|
id: "bidi-codepoint-literal",
|
|
290
394
|
run: detectBidiCodepointLiteral,
|
|
@@ -331,6 +435,10 @@ module.exports = {
|
|
|
331
435
|
detectDynamicRegex,
|
|
332
436
|
detectBidiCodepointLiteral,
|
|
333
437
|
detectOrphanAllowClass,
|
|
438
|
+
detectUnsortedMarkedArray,
|
|
439
|
+
detectMisalignedMarkedRun,
|
|
440
|
+
scanUnsortedMarkedArray,
|
|
441
|
+
scanMisalignedMarkedRun,
|
|
334
442
|
filesUnder,
|
|
335
443
|
};
|
|
336
444
|
|
package/scripts/release.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Usage:
|
|
13
13
|
* node scripts/release.js prepare [--minor] # bump + sign + indexes + snapshot + sbom + baseline
|
|
14
|
-
* node scripts/release.js gates # npm test +
|
|
14
|
+
* node scripts/release.js gates # npm test + 20-gate predeploy
|
|
15
15
|
* node scripts/release.js commit # release branch + signed commit
|
|
16
16
|
* node scripts/release.js push # push branch + open PR
|
|
17
17
|
* node scripts/release.js watch # CI watch + flag unresolved review threads
|
|
@@ -576,7 +576,7 @@ function cmdHelp() {
|
|
|
576
576
|
console.log("");
|
|
577
577
|
console.log("Usage:");
|
|
578
578
|
console.log(" node scripts/release.js prepare [--minor] # bump + sign + indexes + snapshot + sbom + baseline");
|
|
579
|
-
console.log(" node scripts/release.js gates # npm test +
|
|
579
|
+
console.log(" node scripts/release.js gates # npm test + 20-gate predeploy");
|
|
580
580
|
console.log(" node scripts/release.js commit # release branch + signed commit");
|
|
581
581
|
console.log(" node scripts/release.js push # push branch + open PR");
|
|
582
582
|
console.log(" node scripts/release.js watch # CI watch + flag unresolved review threads");
|