@skillsmith/core 0.11.3 → 0.11.5
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 +34 -9
- package/README.md +10 -7
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.js +15 -5
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/client.private-registry.d.ts +80 -0
- package/dist/src/api/client.private-registry.d.ts.map +1 -0
- package/dist/src/api/client.private-registry.js +97 -0
- package/dist/src/api/client.private-registry.js.map +1 -0
- package/dist/src/api/client.private-registry.test.d.ts +9 -0
- package/dist/src/api/client.private-registry.test.d.ts.map +1 -0
- package/dist/src/api/client.private-registry.test.js +127 -0
- package/dist/src/api/client.private-registry.test.js.map +1 -0
- package/dist/src/api/client.toSkill.test.d.ts +25 -0
- package/dist/src/api/client.toSkill.test.d.ts.map +1 -0
- package/dist/src/api/client.toSkill.test.js +97 -0
- package/dist/src/api/client.toSkill.test.js.map +1 -0
- package/dist/src/api/client.token-refresh.d.ts +8 -0
- package/dist/src/api/client.token-refresh.d.ts.map +1 -1
- package/dist/src/api/client.token-refresh.js +26 -0
- package/dist/src/api/client.token-refresh.js.map +1 -1
- package/dist/src/api/client.token-refresh.test.js +82 -0
- package/dist/src/api/client.token-refresh.test.js.map +1 -1
- package/dist/src/api/index.d.ts +2 -0
- package/dist/src/api/index.d.ts.map +1 -1
- package/dist/src/api/index.js +9 -0
- package/dist/src/api/index.js.map +1 -1
- package/dist/src/api/security-summary.d.ts +73 -0
- package/dist/src/api/security-summary.d.ts.map +1 -0
- package/dist/src/api/security-summary.js +88 -0
- package/dist/src/api/security-summary.js.map +1 -0
- package/dist/src/api/security-summary.test.d.ts +9 -0
- package/dist/src/api/security-summary.test.d.ts.map +1 -0
- package/dist/src/api/security-summary.test.js +94 -0
- package/dist/src/api/security-summary.test.js.map +1 -0
- package/dist/src/config/config-atomic-write.d.ts +30 -10
- package/dist/src/config/config-atomic-write.d.ts.map +1 -1
- package/dist/src/config/config-atomic-write.js +33 -80
- package/dist/src/config/config-atomic-write.js.map +1 -1
- package/dist/src/config/config-atomic-write.test.d.ts +8 -0
- package/dist/src/config/config-atomic-write.test.d.ts.map +1 -1
- package/dist/src/config/config-atomic-write.test.js +64 -12
- package/dist/src/config/config-atomic-write.test.js.map +1 -1
- package/dist/src/config/owned-lock.acquire.d.ts +53 -0
- package/dist/src/config/owned-lock.acquire.d.ts.map +1 -0
- package/dist/src/config/owned-lock.acquire.js +140 -0
- package/dist/src/config/owned-lock.acquire.js.map +1 -0
- package/dist/src/config/owned-lock.claim.d.ts +84 -0
- package/dist/src/config/owned-lock.claim.d.ts.map +1 -0
- package/dist/src/config/owned-lock.claim.js +310 -0
- package/dist/src/config/owned-lock.claim.js.map +1 -0
- package/dist/src/config/owned-lock.d.ts +113 -0
- package/dist/src/config/owned-lock.d.ts.map +1 -0
- package/dist/src/config/owned-lock.js +121 -0
- package/dist/src/config/owned-lock.js.map +1 -0
- package/dist/src/config/owned-lock.test.d.ts +12 -0
- package/dist/src/config/owned-lock.test.d.ts.map +1 -0
- package/dist/src/config/owned-lock.test.js +412 -0
- package/dist/src/config/owned-lock.test.js.map +1 -0
- package/dist/src/config/owned-lock.types.d.ts +78 -0
- package/dist/src/config/owned-lock.types.d.ts.map +1 -0
- package/dist/src/config/owned-lock.types.js +30 -0
- package/dist/src/config/owned-lock.types.js.map +1 -0
- package/dist/src/db/createDatabase.d.ts.map +1 -1
- package/dist/src/db/createDatabase.js +19 -7
- package/dist/src/db/createDatabase.js.map +1 -1
- package/dist/src/embeddings/hnsw-store.exports.d.ts +11 -0
- package/dist/src/embeddings/hnsw-store.exports.d.ts.map +1 -0
- package/dist/src/embeddings/hnsw-store.exports.js +10 -0
- package/dist/src/embeddings/hnsw-store.exports.js.map +1 -0
- package/dist/src/embeddings/index.d.ts +1 -2
- package/dist/src/embeddings/index.d.ts.map +1 -1
- package/dist/src/embeddings/index.js +17 -3
- package/dist/src/embeddings/index.js.map +1 -1
- package/dist/src/embeddings/probe.d.ts.map +1 -1
- package/dist/src/embeddings/probe.js +4 -8
- package/dist/src/embeddings/probe.js.map +1 -1
- package/dist/src/exports/services.d.ts +4 -1
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +22 -0
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +5 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +17 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/index.d.ts +1 -1
- package/dist/src/install/index.d.ts.map +1 -1
- package/dist/src/install/index.js +1 -1
- package/dist/src/install/index.js.map +1 -1
- package/dist/src/install/paths.d.ts +10 -0
- package/dist/src/install/paths.d.ts.map +1 -1
- package/dist/src/install/paths.js +19 -0
- package/dist/src/install/paths.js.map +1 -1
- package/dist/src/logging/logger.test.js +57 -0
- package/dist/src/logging/logger.test.js.map +1 -1
- package/dist/src/logging/rotation.d.ts +27 -2
- package/dist/src/logging/rotation.d.ts.map +1 -1
- package/dist/src/logging/rotation.js +44 -3
- package/dist/src/logging/rotation.js.map +1 -1
- package/dist/src/logging/rotation.test.js +69 -0
- package/dist/src/logging/rotation.test.js.map +1 -1
- package/dist/src/logging/types.d.ts +8 -2
- package/dist/src/logging/types.d.ts.map +1 -1
- package/dist/src/security/index.d.ts +2 -1
- package/dist/src/security/index.d.ts.map +1 -1
- package/dist/src/security/index.js +3 -0
- package/dist/src/security/index.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.d.ts +2 -2
- package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.evidence.d.ts +76 -0
- package/dist/src/security/scanner/SecurityScanner.evidence.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.evidence.js +176 -0
- package/dist/src/security/scanner/SecurityScanner.evidence.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.exec.d.ts +8 -1
- package/dist/src/security/scanner/SecurityScanner.exec.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.exec.js +58 -2
- package/dist/src/security/scanner/SecurityScanner.exec.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +35 -10
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.js +106 -59
- package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.js +41 -13
- package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.pii.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.pii.js +23 -1
- package/dist/src/security/scanner/SecurityScanner.pii.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.scanners.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.scanners.js +15 -3
- package/dist/src/security/scanner/SecurityScanner.scanners.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.ssrf.d.ts +11 -1
- package/dist/src/security/scanner/SecurityScanner.ssrf.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.ssrf.js +18 -7
- package/dist/src/security/scanner/SecurityScanner.ssrf.js.map +1 -1
- package/dist/src/security/scanner/index.d.ts +3 -3
- package/dist/src/security/scanner/index.d.ts.map +1 -1
- package/dist/src/security/scanner/index.js +5 -2
- package/dist/src/security/scanner/index.js.map +1 -1
- package/dist/src/security/scanner/multiline-category-closure.test.d.ts +80 -0
- package/dist/src/security/scanner/multiline-category-closure.test.d.ts.map +1 -0
- package/dist/src/security/scanner/multiline-category-closure.test.js +287 -0
- package/dist/src/security/scanner/multiline-category-closure.test.js.map +1 -0
- package/dist/src/security/scanner/patterns.d.ts +41 -14
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.jailbreak.d.ts +41 -0
- package/dist/src/security/scanner/patterns.jailbreak.d.ts.map +1 -0
- package/dist/src/security/scanner/patterns.jailbreak.evidence.d.ts +35 -0
- package/dist/src/security/scanner/patterns.jailbreak.evidence.d.ts.map +1 -0
- package/dist/src/security/scanner/patterns.jailbreak.evidence.js +119 -0
- package/dist/src/security/scanner/patterns.jailbreak.evidence.js.map +1 -0
- package/dist/src/security/scanner/patterns.jailbreak.js +370 -0
- package/dist/src/security/scanner/patterns.jailbreak.js.map +1 -0
- package/dist/src/security/scanner/patterns.js +101 -82
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/src/security/scanner/patterns.scope.d.ts +62 -0
- package/dist/src/security/scanner/patterns.scope.d.ts.map +1 -0
- package/dist/src/security/scanner/patterns.scope.js +207 -0
- package/dist/src/security/scanner/patterns.scope.js.map +1 -0
- package/dist/src/security/scanner/regex-utils.d.ts +20 -0
- package/dist/src/security/scanner/regex-utils.d.ts.map +1 -1
- package/dist/src/security/scanner/regex-utils.js +20 -0
- package/dist/src/security/scanner/regex-utils.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +35 -0
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/services/recommend-guard.d.ts +28 -0
- package/dist/src/services/recommend-guard.d.ts.map +1 -0
- package/dist/src/services/recommend-guard.js +34 -0
- package/dist/src/services/recommend-guard.js.map +1 -0
- package/dist/src/services/recommend-guard.test.d.ts +2 -0
- package/dist/src/services/recommend-guard.test.d.ts.map +1 -0
- package/dist/src/services/recommend-guard.test.js +28 -0
- package/dist/src/services/recommend-guard.test.js.map +1 -0
- package/dist/src/services/skill-installation.content.d.ts +88 -0
- package/dist/src/services/skill-installation.content.d.ts.map +1 -0
- package/dist/src/services/skill-installation.content.js +319 -0
- package/dist/src/services/skill-installation.content.js.map +1 -0
- package/dist/src/services/skill-installation.helpers.d.ts +32 -1
- package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
- package/dist/src/services/skill-installation.helpers.js +39 -6
- package/dist/src/services/skill-installation.helpers.js.map +1 -1
- package/dist/src/services/skill-installation.helpers.test.js +34 -2
- package/dist/src/services/skill-installation.helpers.test.js.map +1 -1
- package/dist/src/services/skill-installation.io.d.ts.map +1 -1
- package/dist/src/services/skill-installation.io.js +86 -2
- package/dist/src/services/skill-installation.io.js.map +1 -1
- package/dist/src/services/skill-installation.service.d.ts +20 -1
- package/dist/src/services/skill-installation.service.d.ts.map +1 -1
- package/dist/src/services/skill-installation.service.js +26 -4
- package/dist/src/services/skill-installation.service.js.map +1 -1
- package/dist/src/services/skill-installation.types.d.ts +42 -1
- package/dist/src/services/skill-installation.types.d.ts.map +1 -1
- package/dist/src/services/skill-installation.types.js.map +1 -1
- package/dist/src/services/skill-resolution.d.ts +67 -0
- package/dist/src/services/skill-resolution.d.ts.map +1 -0
- package/dist/src/services/skill-resolution.js +67 -0
- package/dist/src/services/skill-resolution.js.map +1 -0
- package/dist/src/services/skill-resolution.test.d.ts +2 -0
- package/dist/src/services/skill-resolution.test.d.ts.map +1 -0
- package/dist/src/services/skill-resolution.test.js +143 -0
- package/dist/src/services/skill-resolution.test.js.map +1 -0
- package/dist/src/sync/inventory-collector.d.ts.map +1 -1
- package/dist/src/sync/inventory-collector.js +2 -2
- package/dist/src/sync/inventory-collector.js.map +1 -1
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +4 -0
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/quiet-mode.d.ts +21 -0
- package/dist/src/utils/quiet-mode.d.ts.map +1 -0
- package/dist/src/utils/quiet-mode.js +26 -0
- package/dist/src/utils/quiet-mode.js.map +1 -0
- package/dist/tests/EmbeddingService.test.js +58 -1
- package/dist/tests/EmbeddingService.test.js.map +1 -1
- package/dist/tests/SecurityScanner.ai-defence.test.js +32 -7
- package/dist/tests/SecurityScanner.ai-defence.test.js.map +1 -1
- package/dist/tests/SecurityScanner.exec.test.js +79 -0
- package/dist/tests/SecurityScanner.exec.test.js.map +1 -1
- package/dist/tests/SecurityScanner.performance.test.js +5 -2
- package/dist/tests/SecurityScanner.performance.test.js.map +1 -1
- package/dist/tests/db/database-abstraction.test.js +45 -1
- package/dist/tests/db/database-abstraction.test.js.map +1 -1
- package/dist/tests/helpers/deterministic-dead-pid.d.ts +13 -0
- package/dist/tests/helpers/deterministic-dead-pid.d.ts.map +1 -0
- package/dist/tests/helpers/deterministic-dead-pid.js +31 -0
- package/dist/tests/helpers/deterministic-dead-pid.js.map +1 -0
- package/dist/tests/integration/owned-lock-lost-update.test.d.ts +12 -0
- package/dist/tests/integration/owned-lock-lost-update.test.d.ts.map +1 -0
- package/dist/tests/integration/owned-lock-lost-update.test.js +52 -0
- package/dist/tests/integration/owned-lock-lost-update.test.js.map +1 -0
- package/dist/tests/integration/owned-lock-reclaim-race.test.d.ts +19 -0
- package/dist/tests/integration/owned-lock-reclaim-race.test.d.ts.map +1 -0
- package/dist/tests/integration/owned-lock-reclaim-race.test.js +177 -0
- package/dist/tests/integration/owned-lock-reclaim-race.test.js.map +1 -0
- package/dist/tests/security/ContinuousSecurity.performance.test.js +6 -0
- package/dist/tests/security/ContinuousSecurity.performance.test.js.map +1 -1
- package/dist/tests/security/ContinuousSecurity.test.js +15 -0
- package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
- package/dist/tests/security/ad-crlf-injection.test.d.ts +18 -0
- package/dist/tests/security/ad-crlf-injection.test.d.ts.map +1 -0
- package/dist/tests/security/ad-crlf-injection.test.js +150 -0
- package/dist/tests/security/ad-crlf-injection.test.js.map +1 -0
- package/dist/tests/security/ai-defence-multiline-promotion.test.d.ts +25 -0
- package/dist/tests/security/ai-defence-multiline-promotion.test.d.ts.map +1 -0
- package/dist/tests/security/ai-defence-multiline-promotion.test.js +138 -0
- package/dist/tests/security/ai-defence-multiline-promotion.test.js.map +1 -0
- package/dist/tests/security/nested-instruction-long-attribute.test.d.ts +15 -0
- package/dist/tests/security/nested-instruction-long-attribute.test.d.ts.map +1 -0
- package/dist/tests/security/nested-instruction-long-attribute.test.js +60 -0
- package/dist/tests/security/nested-instruction-long-attribute.test.js.map +1 -0
- package/dist/tests/security/pattern-scope.test.d.ts +17 -0
- package/dist/tests/security/pattern-scope.test.d.ts.map +1 -0
- package/dist/tests/security/pattern-scope.test.js +128 -0
- package/dist/tests/security/pattern-scope.test.js.map +1 -0
- package/dist/tests/security/pii-detection.test.js +39 -0
- package/dist/tests/security/pii-detection.test.js.map +1 -1
- package/dist/tests/security/scanner-evidence-tiers.test.d.ts +30 -0
- package/dist/tests/security/scanner-evidence-tiers.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-evidence-tiers.test.js +258 -0
- package/dist/tests/security/scanner-evidence-tiers.test.js.map +1 -0
- package/dist/tests/security/scanner-privesc-severity.test.d.ts +23 -0
- package/dist/tests/security/scanner-privesc-severity.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-privesc-severity.test.js +43 -0
- package/dist/tests/security/scanner-privesc-severity.test.js.map +1 -0
- package/dist/tests/security/scanner-regression-guard.exec-locality.test.d.ts +20 -0
- package/dist/tests/security/scanner-regression-guard.exec-locality.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-regression-guard.exec-locality.test.js +71 -0
- package/dist/tests/security/scanner-regression-guard.exec-locality.test.js.map +1 -0
- package/dist/tests/security/scanner-regression-guard.test.d.ts +24 -0
- package/dist/tests/security/scanner-regression-guard.test.d.ts.map +1 -1
- package/dist/tests/security/scanner-regression-guard.test.js +59 -3
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/dist/tests/security/scanner-ssrf-word-boundary.test.d.ts +19 -0
- package/dist/tests/security/scanner-ssrf-word-boundary.test.d.ts.map +1 -0
- package/dist/tests/security/scanner-ssrf-word-boundary.test.js +65 -0
- package/dist/tests/security/scanner-ssrf-word-boundary.test.js.map +1 -0
- package/dist/tests/security.test.js +11 -2
- package/dist/tests/security.test.js.map +1 -1
- package/dist/tests/skill-scanner/allowlist.test.js +15 -7
- package/dist/tests/skill-scanner/allowlist.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.content.test.d.ts +10 -0
- package/dist/tests/unit/services/skill-installation.content.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.content.test.js +290 -0
- package/dist/tests/unit/services/skill-installation.content.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.symlink.test.d.ts +8 -0
- package/dist/tests/unit/services/skill-installation.io.symlink.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.symlink.test.js +72 -0
- package/dist/tests/unit/services/skill-installation.io.symlink.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.test.js +54 -1
- package/dist/tests/unit/services/skill-installation.io.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.service.error-codes.test.d.ts +15 -0
- package/dist/tests/unit/services/skill-installation.service.error-codes.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.error-codes.test.js +190 -0
- package/dist/tests/unit/services/skill-installation.service.error-codes.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.multi-client.test.d.ts +17 -0
- package/dist/tests/unit/services/skill-installation.service.multi-client.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.multi-client.test.js +126 -0
- package/dist/tests/unit/services/skill-installation.service.multi-client.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.service.test.js +7 -112
- package/dist/tests/unit/services/skill-installation.service.test.js.map +1 -1
- package/dist/tests/utils/quiet-mode.test.d.ts +12 -0
- package/dist/tests/utils/quiet-mode.test.d.ts.map +1 -0
- package/dist/tests/utils/quiet-mode.test.js +42 -0
- package/dist/tests/utils/quiet-mode.test.js.map +1 -0
- package/package.json +17 -5
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5879 Wave 3 item 2 — structural closure test for cohort E's exclusion
|
|
3
|
+
* proof (design doc `smi-5879-edge-twin-parity-design.md` §8.3.1.2.2).
|
|
4
|
+
* @module @skillsmith/core/security/scanner/multiline-category-closure.test
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS TEST EXISTS
|
|
7
|
+
*
|
|
8
|
+
* The SMI-5879 census (comparing pre-port vs post-port `skills.security_score`
|
|
9
|
+
* across ~344k rows) needs to fully re-simulate every row scoring `>= 8`
|
|
10
|
+
* (cohort C1) but can structurally EXCLUDE every row scoring `0-7` (cohort E)
|
|
11
|
+
* from that expensive re-simulation — *if and only if* three properties about
|
|
12
|
+
* how the multiline pass routes patterns hold. The design doc's §8.3.1.2.1
|
|
13
|
+
* proves those properties in prose ("P1/P2/P3"); this file promotes that proof
|
|
14
|
+
* to a machine-checked gate (design doc gate G-5) so a future source change
|
|
15
|
+
* that silently invalidates the premise fails CI instead of silently
|
|
16
|
+
* corrupting the census's soundness.
|
|
17
|
+
*
|
|
18
|
+
* THE +32 ARITHMETIC THIS TEST PROTECTS (not itself re-derived here — that is
|
|
19
|
+
* `weights.ts` + the design doc's §8.3.1.2 arithmetic; this file only proves
|
|
20
|
+
* the ROUTING facts the arithmetic depends on):
|
|
21
|
+
* max joint contribution = 100 * CATEGORY_WEIGHTS.jailbreak.coefficient (0.20)
|
|
22
|
+
* + 100 * CATEGORY_WEIGHTS.ai_defence.coefficient (0.12)
|
|
23
|
+
* = 32.0
|
|
24
|
+
* S <= 7 => S' <= S + 32 <= 39 < 40 (QUARANTINE_THRESHOLD) => verdict
|
|
25
|
+
* cannot flip to quarantined for any row starting at or below 7.
|
|
26
|
+
* That bound is sound ONLY IF the multiline pass can never inflate any
|
|
27
|
+
* category's subtotal OTHER than jailbreak / ai_defence. The three assertions
|
|
28
|
+
* below are exactly what closes that "only if".
|
|
29
|
+
*
|
|
30
|
+
* THE DOCUMENTED TRAP (design doc §8.3.1.2.3) — DELIBERATELY NOT REPEATED HERE
|
|
31
|
+
*
|
|
32
|
+
* The design doc warns against writing assertion 3 as "every pattern for
|
|
33
|
+
* which `isMultilinePattern()` returns true belongs to an AI-category array"
|
|
34
|
+
* — that predicate is syntactic (it fires on a NEGATED class `[^\n]`, the
|
|
35
|
+
* literal opposite of "spans lines") and is false today for 9 patterns across
|
|
36
|
+
* two non-AI arrays. This file does not use that predicate at all: assertions
|
|
37
|
+
* 1 and 3 are asserted over the multiline pass's CALL SITES (which pattern
|
|
38
|
+
* array is physically wired to `scanPatternsWithMultilineSupport`'s `patterns:`
|
|
39
|
+
* config field), not over any per-pattern syntactic test. That is the
|
|
40
|
+
* "routing, not predicate" distinction the trap section requires.
|
|
41
|
+
*
|
|
42
|
+
* SMI-5881 ADAPTATION (judgment call — flagged, not silently resolved)
|
|
43
|
+
*
|
|
44
|
+
* The design doc's assertion 2 is written directly against `isMultilinePattern()`
|
|
45
|
+
* as the definition of "PASS-1 pattern". SMI-5881 (merged before this file was
|
|
46
|
+
* written) DELETED `isMultilinePattern()` entirely — no compatibility shim —
|
|
47
|
+
* and replaced the syntactic heuristic with `PATTERN_SCOPE` /
|
|
48
|
+
* `resolvePatternScope()` (`./patterns.scope.ts`), an explicit per-pattern
|
|
49
|
+
* `'line' | 'content' | 'both'` declaration. `isMultilinePattern` cannot be
|
|
50
|
+
* imported here; it no longer exists anywhere under `packages/core/src`
|
|
51
|
+
* (guarded by `packages/core/tests/security/pattern-scope.test.ts`).
|
|
52
|
+
*
|
|
53
|
+
* `scanPatternsWithMultilineSupport`'s pass 1 (SecurityScanner.helpers.ts) now
|
|
54
|
+
* reads: `if (resolvePatternScope(pattern) === 'line') continue` — i.e. pass 1
|
|
55
|
+
* tests every pattern whose resolved scope is NOT `'line'` (`'content'` or
|
|
56
|
+
* `'both'`). That predicate is the faithful, current-source equivalent of the
|
|
57
|
+
* design doc's `routed.filter(isMultilinePattern)` — same set membership
|
|
58
|
+
* question ("which patterns does pass 1 actually read"), expressed against
|
|
59
|
+
* the model that replaced the deleted one. Assertion 2 below uses
|
|
60
|
+
* `resolvePatternScope(p) !== 'line'` for exactly this reason.
|
|
61
|
+
*
|
|
62
|
+
* CODE-REVIEW REMEDIATION (Finding 1 — NO-GO, fixed)
|
|
63
|
+
*
|
|
64
|
+
* A first version of this file enumerated call sites with a bounded
|
|
65
|
+
* text-window regex scan (`CALL_TOKEN = 'scanPatternsWithMultilineSupport('`
|
|
66
|
+
* + an `EXTRACTION_WINDOW`-char lookahead for `type:`/`patterns:`). Codex
|
|
67
|
+
* (gpt-5.6-sol) review flagged that as a silent-false-negative hazard: a new
|
|
68
|
+
* call site using extra whitespace before `(`, a locally-aliased identifier,
|
|
69
|
+
* or a renamed import would be invisible to that regex while the existing two
|
|
70
|
+
* call sites kept the count green — defeating the point of a closure proof
|
|
71
|
+
* meant to catch exactly this class of drift. `extractMultilineCallSites`
|
|
72
|
+
* below instead walks the real TypeScript AST (`ts.createSourceFile` +
|
|
73
|
+
* `CallExpression` traversal resolved through `collectAliases`), which is
|
|
74
|
+
* exhaustive by construction against all three variants. Verified via mutation
|
|
75
|
+
* testing: a temporarily-added call through a whitespace-before-paren AND a
|
|
76
|
+
* locally-aliased form was both correctly detected (count became 3, assertion
|
|
77
|
+
* 1 failed) before being reverted.
|
|
78
|
+
*/
|
|
79
|
+
import { readFileSync } from 'node:fs';
|
|
80
|
+
import { join } from 'node:path';
|
|
81
|
+
import { fileURLToPath } from 'node:url';
|
|
82
|
+
import { describe, it, expect } from 'vitest';
|
|
83
|
+
import * as ts from 'typescript';
|
|
84
|
+
import { JAILBREAK_PATTERNS, AI_DEFENCE_PATTERNS } from './patterns.jailbreak.js';
|
|
85
|
+
import { EVIDENCE_TYPE_BY_PATTERN } from './patterns.jailbreak.evidence.js';
|
|
86
|
+
import { resolvePatternScope } from './patterns.scope.js';
|
|
87
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
88
|
+
const SCANNER_PATH = join(__dirname, 'SecurityScanner.ts');
|
|
89
|
+
const SCANNER_SRC = readFileSync(SCANNER_PATH, 'utf-8');
|
|
90
|
+
/** The only two pattern arrays a `scanPatternsWithMultilineSupport` call site may name. */
|
|
91
|
+
const AI_CATEGORY_ARRAY_NAMES = ['JAILBREAK_PATTERNS', 'AI_DEFENCE_PATTERNS'];
|
|
92
|
+
/**
|
|
93
|
+
* Every OTHER pattern array in the scanner (design doc §8.3.1.2.2 assertion 3's
|
|
94
|
+
* explicit exclusion list). `BLOCKED_PATTERNS` is not a real exported const
|
|
95
|
+
* (blocked patterns are an instance-level `ScannerOptions.blockedPatterns`,
|
|
96
|
+
* `SecurityScanner.ts:73`) — kept in the list anyway because the design doc
|
|
97
|
+
* names it explicitly and the check is "this identifier never appears as a
|
|
98
|
+
* `patterns:` value", which is true (and meaningfully checked) regardless of
|
|
99
|
+
* whether the identifier is otherwise reachable.
|
|
100
|
+
*/
|
|
101
|
+
const NON_AI_ARRAY_NAMES = [
|
|
102
|
+
'SUSPICIOUS_PATTERNS',
|
|
103
|
+
'DATA_EXFILTRATION_PATTERNS',
|
|
104
|
+
'PRIVILEGE_ESCALATION_PATTERNS',
|
|
105
|
+
'CODE_EXECUTION_PATTERNS',
|
|
106
|
+
'BLOCKED_PATTERNS',
|
|
107
|
+
];
|
|
108
|
+
const TARGET_FUNCTION_NAME = 'scanPatternsWithMultilineSupport';
|
|
109
|
+
/** The textual callee name of a call expression: `foo(` -> "foo"; `x.bar(` -> "bar". */
|
|
110
|
+
function calleeName(expr) {
|
|
111
|
+
if (ts.isIdentifier(expr))
|
|
112
|
+
return expr.text;
|
|
113
|
+
if (ts.isPropertyAccessExpression(expr))
|
|
114
|
+
return expr.name.text;
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Every local identifier in `sourceFile` that resolves to `targetName` — the
|
|
119
|
+
* name itself, any `import { targetName as Local }` rename, and any simple
|
|
120
|
+
* `const Local = <alias>` variable alias (resolved transitively, to a fixed
|
|
121
|
+
* point, so a chain like `const a = target; const b = a` also resolves).
|
|
122
|
+
* This is what makes the call-site walk below exhaustive against the "an
|
|
123
|
+
* alias" failure mode the code review named: a call reached through a
|
|
124
|
+
* renamed import or a locally-aliased identifier still resolves back to
|
|
125
|
+
* `targetName` and is detected, where a literal-token text scan would miss it.
|
|
126
|
+
*/
|
|
127
|
+
function collectAliases(sourceFile, targetName) {
|
|
128
|
+
const aliases = new Set([targetName]);
|
|
129
|
+
for (const stmt of sourceFile.statements) {
|
|
130
|
+
if (!ts.isImportDeclaration(stmt) || !stmt.importClause?.namedBindings)
|
|
131
|
+
continue;
|
|
132
|
+
const bindings = stmt.importClause.namedBindings;
|
|
133
|
+
if (!ts.isNamedImports(bindings))
|
|
134
|
+
continue;
|
|
135
|
+
for (const el of bindings.elements) {
|
|
136
|
+
const imported = el.propertyName?.text ?? el.name.text;
|
|
137
|
+
if (imported === targetName)
|
|
138
|
+
aliases.add(el.name.text);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
let changed = true;
|
|
142
|
+
while (changed) {
|
|
143
|
+
changed = false;
|
|
144
|
+
const visit = (node) => {
|
|
145
|
+
if (ts.isVariableDeclaration(node) &&
|
|
146
|
+
ts.isIdentifier(node.name) &&
|
|
147
|
+
node.initializer &&
|
|
148
|
+
ts.isIdentifier(node.initializer) &&
|
|
149
|
+
aliases.has(node.initializer.text) &&
|
|
150
|
+
!aliases.has(node.name.text)) {
|
|
151
|
+
aliases.add(node.name.text);
|
|
152
|
+
changed = true;
|
|
153
|
+
}
|
|
154
|
+
ts.forEachChild(node, visit);
|
|
155
|
+
};
|
|
156
|
+
ts.forEachChild(sourceFile, visit);
|
|
157
|
+
}
|
|
158
|
+
return aliases;
|
|
159
|
+
}
|
|
160
|
+
/** The textual name of an object-literal member (identifier or string-literal key). */
|
|
161
|
+
function memberName(prop) {
|
|
162
|
+
if (!prop.name)
|
|
163
|
+
return undefined;
|
|
164
|
+
if (ts.isIdentifier(prop.name))
|
|
165
|
+
return prop.name.text;
|
|
166
|
+
if (ts.isStringLiteral(prop.name))
|
|
167
|
+
return prop.name.text;
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Extract every `scanPatternsWithMultilineSupport(...)` call site in `source`
|
|
172
|
+
* (at path `filePath`, used only for error messages), together with its
|
|
173
|
+
* config object's `type:` and `patterns:` values — via full TypeScript AST
|
|
174
|
+
* traversal (`ts.createSourceFile` + a `CallExpression` walk resolved through
|
|
175
|
+
* `collectAliases`), NOT text/regex matching over a bounded window. This is
|
|
176
|
+
* exhaustive by construction: extra whitespace before `(`, a call reached
|
|
177
|
+
* through a renamed import or a locally-aliased identifier, and a config
|
|
178
|
+
* object appearing in any argument position are all still found — closing
|
|
179
|
+
* the class of silent false-negative a bounded text-window regex scan cannot
|
|
180
|
+
* rule out (the defect the code review's Finding 1 identified).
|
|
181
|
+
*
|
|
182
|
+
* Throws (rather than silently skipping) when a matched call's arguments
|
|
183
|
+
* don't have the expected `{ type: '<string literal>', patterns: <bare
|
|
184
|
+
* identifier> }` shape — an unparseable/unexpected call site must fail
|
|
185
|
+
* loudly, not be dropped from the count assertion 1 depends on, exactly as
|
|
186
|
+
* the prior text-based version did for its own class of unparseable input.
|
|
187
|
+
*/
|
|
188
|
+
function extractMultilineCallSites(filePath, source) {
|
|
189
|
+
const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
190
|
+
const aliases = collectAliases(sourceFile, TARGET_FUNCTION_NAME);
|
|
191
|
+
const sites = [];
|
|
192
|
+
const visit = (node) => {
|
|
193
|
+
if (ts.isCallExpression(node)) {
|
|
194
|
+
const name = calleeName(node.expression);
|
|
195
|
+
if (name && aliases.has(name)) {
|
|
196
|
+
sites.push(extractCallSiteConfig(node, sourceFile, filePath));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
ts.forEachChild(node, visit);
|
|
200
|
+
};
|
|
201
|
+
visit(sourceFile);
|
|
202
|
+
return sites;
|
|
203
|
+
}
|
|
204
|
+
/** Extract and validate the `{ type, patterns }` config object of a matched call. */
|
|
205
|
+
function extractCallSiteConfig(call, sourceFile, filePath) {
|
|
206
|
+
const offset = call.getStart(sourceFile);
|
|
207
|
+
const configArg = call.arguments.find((arg) => ts.isObjectLiteralExpression(arg) &&
|
|
208
|
+
arg.properties.some((p) => memberName(p) === 'type') &&
|
|
209
|
+
arg.properties.some((p) => memberName(p) === 'patterns'));
|
|
210
|
+
if (!configArg) {
|
|
211
|
+
throw new Error(`[multiline-category-closure] ${TARGET_FUNCTION_NAME} call at ${filePath}:${offset} has no ` +
|
|
212
|
+
`object-literal argument with both 'type' and 'patterns' properties. Either the call shape ` +
|
|
213
|
+
`changed (update this extraction) or this is a genuine new/malformed call site — both ` +
|
|
214
|
+
`invalidate the closure proof and must be resolved before this test can pass.`);
|
|
215
|
+
}
|
|
216
|
+
const typeProp = configArg.properties.find((p) => memberName(p) === 'type');
|
|
217
|
+
const patternsProp = configArg.properties.find((p) => memberName(p) === 'patterns');
|
|
218
|
+
if (!typeProp ||
|
|
219
|
+
!ts.isPropertyAssignment(typeProp) ||
|
|
220
|
+
!ts.isStringLiteral(typeProp.initializer)) {
|
|
221
|
+
throw new Error(`[multiline-category-closure] ${TARGET_FUNCTION_NAME} call at ${filePath}:${offset} has a ` +
|
|
222
|
+
`'type' property that is not a plain string literal — this is exactly the "expression ` +
|
|
223
|
+
`argument" shape this AST census exists to catch. Resolve explicitly before this test can pass.`);
|
|
224
|
+
}
|
|
225
|
+
if (!patternsProp ||
|
|
226
|
+
!ts.isPropertyAssignment(patternsProp) ||
|
|
227
|
+
!ts.isIdentifier(patternsProp.initializer)) {
|
|
228
|
+
throw new Error(`[multiline-category-closure] ${TARGET_FUNCTION_NAME} call at ${filePath}:${offset} has a ` +
|
|
229
|
+
`'patterns' property that is not a bare identifier — either a property-access / expression ` +
|
|
230
|
+
`argument was introduced (the exact "silent miss" class this test exists to catch) or the ` +
|
|
231
|
+
`call shape genuinely changed. Resolve explicitly before this test can pass.`);
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
offset,
|
|
235
|
+
type: typeProp.initializer.text,
|
|
236
|
+
patternsIdent: patternsProp.initializer.text,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
describe('SMI-5879 Wave 3 item 2 — multiline-pass category closure (design doc §8.3.1.2.2)', () => {
|
|
240
|
+
const callSites = extractMultilineCallSites(SCANNER_PATH, SCANNER_SRC);
|
|
241
|
+
// --------------------------------------------------------------------
|
|
242
|
+
// Assertion 1 — the multiline pass has exactly two call sites, both AI-category
|
|
243
|
+
// --------------------------------------------------------------------
|
|
244
|
+
describe('assertion 1 — exactly two call sites, both AI-category (design doc P1/P2)', () => {
|
|
245
|
+
it('scanPatternsWithMultilineSupport is called exactly twice in SecurityScanner.ts', () => {
|
|
246
|
+
expect(callSites).toHaveLength(2);
|
|
247
|
+
});
|
|
248
|
+
it('the extracted type: multiset equals exactly [ai_defence, jailbreak] — no more, no fewer, no substitution', () => {
|
|
249
|
+
const types = callSites.map((s) => s.type).sort();
|
|
250
|
+
expect(types).toEqual(['ai_defence', 'jailbreak']);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
// --------------------------------------------------------------------
|
|
254
|
+
// Assertion 2 — every PASS-1 pattern is explicitly classified
|
|
255
|
+
// --------------------------------------------------------------------
|
|
256
|
+
describe('assertion 2 — every pass-1 pattern is explicitly classified (SMI-5881-adapted)', () => {
|
|
257
|
+
// "Pass 1" = every pattern scanPatternsWithMultilineSupport's first pass
|
|
258
|
+
// actually reads: resolvePatternScope(pattern) !== 'line' (see the
|
|
259
|
+
// SMI-5881 ADAPTATION module-doc comment above for why this replaces the
|
|
260
|
+
// design doc's isMultilinePattern-filter wording).
|
|
261
|
+
const routed = [...JAILBREAK_PATTERNS, ...AI_DEFENCE_PATTERNS];
|
|
262
|
+
const pass1 = routed.filter((p) => resolvePatternScope(p) !== 'line');
|
|
263
|
+
it('the pass-1 subset is non-empty — the pass is not vacuous', () => {
|
|
264
|
+
expect(pass1.length).toBeGreaterThan(0);
|
|
265
|
+
});
|
|
266
|
+
it('every pass-1 pattern has an explicit EVIDENCE_TYPE_BY_PATTERN entry (object identity, not fail-closed default)', () => {
|
|
267
|
+
for (const p of pass1) {
|
|
268
|
+
expect(EVIDENCE_TYPE_BY_PATTERN.has(p), `pattern /${p.source}/${p.flags} has no explicit evidence-tier entry`).toBe(true);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
// --------------------------------------------------------------------
|
|
273
|
+
// Assertion 3 — no non-AI pattern array is routed through the multiline pass
|
|
274
|
+
// --------------------------------------------------------------------
|
|
275
|
+
describe('assertion 3 — no non-AI pattern array is routed through the multiline pass (design doc P3, NOT the isMultilinePattern predicate)', () => {
|
|
276
|
+
it('every call site patterns: identifier is one of the two AI-category arrays', () => {
|
|
277
|
+
for (const site of callSites) {
|
|
278
|
+
expect(AI_CATEGORY_ARRAY_NAMES, `call site at offset ${site.offset} routes ${site.patternsIdent}, not an AI-category array`).toContain(site.patternsIdent);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
it.each(NON_AI_ARRAY_NAMES)('%s never appears as a patterns: identifier at any call site', (arrayName) => {
|
|
282
|
+
const idents = callSites.map((s) => s.patternsIdent);
|
|
283
|
+
expect(idents).not.toContain(arrayName);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
//# sourceMappingURL=multiline-category-closure.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiline-category-closure.test.js","sourceRoot":"","sources":["../../../../src/security/scanner/multiline-category-closure.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,34 @@ export declare const DEFAULT_ALLOWED_DOMAINS: string[];
|
|
|
7
7
|
export declare const ENV_PATH_PATTERN: RegExp;
|
|
8
8
|
export declare const SENSITIVE_PATH_PATTERNS: RegExp[];
|
|
9
9
|
export declare const VALUE_GATED_KEYWORD_PATTERNS: ReadonlySet<RegExp>;
|
|
10
|
-
export
|
|
10
|
+
export { JAILBREAK_PATTERNS, AI_DEFENCE_PATTERNS } from './patterns.jailbreak.js';
|
|
11
|
+
export { EVIDENCE_TYPE_BY_PATTERN } from './patterns.jailbreak.evidence.js';
|
|
12
|
+
/**
|
|
13
|
+
* SMI-5876 §0.1/§0.2: bump on ANY pattern-array or evidence-table change in
|
|
14
|
+
* this module or patterns.jailbreak.ts. The security-audit baseline
|
|
15
|
+
* (packages/mcp-server/src/audit/security-baseline.ts /
|
|
16
|
+
* security-audit.ts) stamps every stored entry with the version that
|
|
17
|
+
* produced it and treats a mismatch as "not comparable" — forcing a re-scan
|
|
18
|
+
* instead of silently reusing a stale verdict from a scanner that no longer
|
|
19
|
+
* exists. Without this, the pattern/evidence-tier fix could not clear an
|
|
20
|
+
* already-flagged skill's stale `malicious` baseline on any machine that had
|
|
21
|
+
* scanned it before (see the security-audit.ts `comparable` gate).
|
|
22
|
+
*
|
|
23
|
+
* Bumped to `.2`: SMI-5876 design-pass follow-up added the `state_assertion`
|
|
24
|
+
* evidence tier + 5 new JAILBREAK_PATTERNS entries (J-S1/S2/S3a/S3b/S4) and
|
|
25
|
+
* widened #6 (bypass) + J-N1 in place — this is precisely the
|
|
26
|
+
* previously-clean-content-now-fires scenario the ruleset-version gate
|
|
27
|
+
* exists for.
|
|
28
|
+
*
|
|
29
|
+
* Bumped to `2026-07-29.1`: SMI-5881 P0 — AD_CRLF_INJECTION's source changed
|
|
30
|
+
* (ReDoS fix, same match language, see patterns.jailbreak.ts) and 4
|
|
31
|
+
* AI_DEFENCE_PATTERNS entries were promoted from 'line' to 'both' scope
|
|
32
|
+
* (AD_HTML_COMMENT_VERB/NOUN, AD_NESTED_INSTRUCTION_BLOCK, AD_ZERO_WIDTH — new
|
|
33
|
+
* cross-line matches now possible where none fired before), plus SSRF_
|
|
34
|
+
* INSTRUCTION_PATTERNS word-boundary narrowing (some previously-firing
|
|
35
|
+
* substring FPs, e.g. "budget to localhost", no longer match).
|
|
36
|
+
*/
|
|
37
|
+
export declare const SCANNER_RULESET_VERSION: "2026-07-29.1";
|
|
11
38
|
export declare const SUSPICIOUS_PATTERNS: RegExp[];
|
|
12
39
|
/**
|
|
13
40
|
* SMI-5359 Wave 4.2: Remote-fetch-to-interpreter ("code_execution") patterns.
|
|
@@ -33,30 +60,30 @@ export declare const CODE_EXECUTION_PATTERNS: RegExp[];
|
|
|
33
60
|
export declare const SOCIAL_ENGINEERING_PATTERNS: RegExp[];
|
|
34
61
|
export declare const PROMPT_LEAKING_PATTERNS: RegExp[];
|
|
35
62
|
export declare const DATA_EXFILTRATION_PATTERNS: RegExp[];
|
|
63
|
+
export declare const CREDENTIAL_SUBSTITUTION_PATTERNS: RegExp[];
|
|
36
64
|
export declare const PRIVILEGE_ESCALATION_PATTERNS: RegExp[];
|
|
37
65
|
/**
|
|
38
66
|
* SMI-3509: SSRF instruction patterns
|
|
39
67
|
* Detects content instructing fetches to internal/dangerous endpoints.
|
|
40
68
|
* These are text-oriented patterns for skill content scanning (not URL validators).
|
|
41
|
-
*/
|
|
42
|
-
export declare const SSRF_INSTRUCTION_PATTERNS: RegExp[];
|
|
43
|
-
/**
|
|
44
|
-
* SMI-1532: AIDefence CVE-hardened injection patterns
|
|
45
|
-
* Optimized for sub-10ms scan time with compiled regex and no backtracking
|
|
46
69
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
70
|
+
* SMI-5881: leading `\b` added to every verb alternation below — the verbs
|
|
71
|
+
* (fetch/request/curl/wget/get/open/load/read/connect/send) previously had no
|
|
72
|
+
* boundary, so they matched as a SUBSTRING of an unrelated word ("get" inside
|
|
73
|
+
* "budget"/"target"/"forget"/"widget", "connect" inside "disconnect", "load"
|
|
74
|
+
* inside "download"/"reload", "open" inside "reopen", "read" inside
|
|
75
|
+
* "bread"/"spread"/"thread"). A trailing `\b` was also added after the bare
|
|
76
|
+
* `localhost` literal (both the single-line and multiline forms) so
|
|
77
|
+
* "localhosting" no longer matches via a "localhost" prefix. Every existing
|
|
78
|
+
* `\s` quantifier is unchanged — replacing them with newline-exclusive classes
|
|
79
|
+
* was tried and reverted (breaks a verb+target split across a real line
|
|
80
|
+
* break, a real evasion). See scanner-ssrf-word-boundary.test.ts.
|
|
54
81
|
*/
|
|
82
|
+
export declare const SSRF_INSTRUCTION_PATTERNS: RegExp[];
|
|
55
83
|
/**
|
|
56
84
|
* SMI-3864: PII detection patterns
|
|
57
85
|
* Detects personally identifiable information and credentials in skill content.
|
|
58
86
|
* Complements AIDefence's aidefence_has_pii() for offline/local scanning.
|
|
59
87
|
*/
|
|
60
88
|
export declare const PII_PATTERNS: RegExp[];
|
|
61
|
-
export declare const AI_DEFENCE_PATTERNS: RegExp[];
|
|
62
89
|
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/patterns.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,uBAAuB,UAanC,CAAA;AA4BD,eAAO,MAAM,gBAAgB,QAAoE,CAAA;AAMjG,eAAO,MAAM,uBAAuB,UAsBnC,CAAA;AAID,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,MAAM,CAG3D,CAAA;
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/patterns.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,eAAO,MAAM,uBAAuB,UAanC,CAAA;AA4BD,eAAO,MAAM,gBAAgB,QAAoE,CAAA;AAMjG,eAAO,MAAM,uBAAuB,UAsBnC,CAAA;AAID,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,MAAM,CAG3D,CAAA;AAUF,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAIjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAA;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,uBAAuB,EAAG,cAAuB,CAAA;AAG9D,eAAO,MAAM,mBAAmB,UAY/B,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,uBAAuB,UAmBnC,CAAA;AAGD,eAAO,MAAM,2BAA2B,UAavC,CAAA;AAGD,eAAO,MAAM,uBAAuB,UAenC,CAAA;AAGD,eAAO,MAAM,0BAA0B,UA2DtC,CAAA;AAMD,eAAO,MAAM,gCAAgC,UAG5C,CAAA;AAGD,eAAO,MAAM,6BAA6B,UA8EzC,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,UAuBrC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,UAwBxB,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5876 Wave 1: Jailbreak / AI-Defence pattern arrays + evidence-tier map.
|
|
3
|
+
* @module @skillsmith/core/security/scanner/patterns.jailbreak
|
|
4
|
+
*
|
|
5
|
+
* Split out of patterns.ts (which was approaching the 500-line audit:standards
|
|
6
|
+
* gate) to hold `JAILBREAK_PATTERNS` and `AI_DEFENCE_PATTERNS`; the
|
|
7
|
+
* evidence-tier classification that governs their severity now lives
|
|
8
|
+
* alongside them in `patterns.jailbreak.evidence.ts` (SMI-5881, split out for
|
|
9
|
+
* the same 500-line reason).
|
|
10
|
+
*
|
|
11
|
+
* Background: both arrays previously matched bare vocabulary with no context
|
|
12
|
+
* requirement (`/jailbreak/i`, `/\bDAN\b/`, a bare role marker, a bare `[[...]]`
|
|
13
|
+
* bracket, ...) — a security-checklist skill's prose tripped the same
|
|
14
|
+
* CRITICAL/HIGH severity as a real attack. `EVIDENCE_TYPE_BY_PATTERN`
|
|
15
|
+
* classifies every pattern in both arrays into one of FIVE evidence tiers
|
|
16
|
+
* (`types.ts`'s `EvidenceType` — `mention`, `role_turn_with_body`,
|
|
17
|
+
* `imperative_instruction`, `instruction_override`, and `state_assertion`, the
|
|
18
|
+
* last added in a design-pass follow-up for declarative state assertions like
|
|
19
|
+
* "Jailbreak activated" that no frame-based directive pattern can catch);
|
|
20
|
+
* `SecurityScanner.evidence.ts` turns that tier (+ documentation context) into
|
|
21
|
+
* a severity/confidence pair, and `SecurityScanner.helpers.ts`'s merge-loop
|
|
22
|
+
* picks the STRONGEST tier per line across both the multi-line and
|
|
23
|
+
* single-line scan passes.
|
|
24
|
+
*
|
|
25
|
+
* Discriminator (see the SMI-5876 design doc for the full worked argument): a
|
|
26
|
+
* pattern is `mention`-tier iff its matched text, read in isolation, instructs
|
|
27
|
+
* nothing — pure nouns/names/labels/structural markers/payload-free
|
|
28
|
+
* obfuscation artifacts. Anything with a verb+object pairing or a
|
|
29
|
+
* second-person predicate is directive-tier (`imperative_instruction` /
|
|
30
|
+
* `instruction_override`). A descriptive-frame negative guard (demote when
|
|
31
|
+
* preceded by "guards against" / "for example" / ...) was deliberately
|
|
32
|
+
* REJECTED — for prompt injection the text IS the attack, so any framing-based
|
|
33
|
+
* exemption is itself a bypass vector ("for example, ignore all previous
|
|
34
|
+
* instructions" would be suppressed). This is why JAILBREAK's `bypass ...
|
|
35
|
+
* restrictions/filters/safety` entry stays directive-tier: it's a genuine
|
|
36
|
+
* attack on its own, and the only tool that would separate it from the
|
|
37
|
+
* "guards against bypass" documentation case is the rejected frame guard.
|
|
38
|
+
*/
|
|
39
|
+
export declare const JAILBREAK_PATTERNS: RegExp[];
|
|
40
|
+
export declare const AI_DEFENCE_PATTERNS: RegExp[];
|
|
41
|
+
//# sourceMappingURL=patterns.jailbreak.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.jailbreak.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/patterns.jailbreak.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAoLH,eAAO,MAAM,kBAAkB,UA4B9B,CAAA;AAuLD,eAAO,MAAM,mBAAmB,UAuB/B,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5876 Wave 1 / SMI-5881: evidence-tier classification for
|
|
3
|
+
* JAILBREAK_PATTERNS + AI_DEFENCE_PATTERNS.
|
|
4
|
+
* @module @skillsmith/core/security/scanner/patterns.jailbreak.evidence
|
|
5
|
+
*
|
|
6
|
+
* Split out of patterns.jailbreak.ts (SMI-5881 — that file was approaching
|
|
7
|
+
* the 500-line audit:standards gate again, same reason it was split out of
|
|
8
|
+
* patterns.ts in SMI-5876) so EVIDENCE_TYPE_BY_PATTERN's declaration doesn't
|
|
9
|
+
* grow patterns.jailbreak.ts every time a new pattern is added.
|
|
10
|
+
*
|
|
11
|
+
* Keyed by OBJECT IDENTITY, exhaustive over both arrays (asserted by test in
|
|
12
|
+
* scanner-evidence-tiers.test.ts), but classifyEvidence() (SecurityScanner.
|
|
13
|
+
* evidence.ts) still defaults UNMAPPED patterns to `imperative_instruction` —
|
|
14
|
+
* fail-closed: forgetting to classify a newly added pattern makes it
|
|
15
|
+
* strongest, never weakest.
|
|
16
|
+
*
|
|
17
|
+
* Built from parallel index-aligned arrays (not per-named-const references)
|
|
18
|
+
* because the individual pattern consts (JB_IGNORE_PREVIOUS, AD_ROLE_MARKER_
|
|
19
|
+
* BARE, ...) are private to patterns.jailbreak.ts and intentionally not
|
|
20
|
+
* exported — this file only ever sees the same JAILBREAK_PATTERNS /
|
|
21
|
+
* AI_DEFENCE_PATTERNS arrays every other consumer sees, so a length mismatch
|
|
22
|
+
* (pattern added to one array, tier forgotten here) is impossible to
|
|
23
|
+
* misalign silently: the two arrays below MUST stay index-aligned with the
|
|
24
|
+
* exported pattern arrays, or scanner-evidence-tiers.test.ts's exhaustiveness
|
|
25
|
+
* assertion catches it immediately.
|
|
26
|
+
*
|
|
27
|
+
* Consumed ONLY by SecurityScanner's severity resolution. Every other
|
|
28
|
+
* consumer of JAILBREAK_PATTERNS / AI_DEFENCE_PATTERNS (memory-injection-
|
|
29
|
+
* scanner.ts's quarantine gate, SecurityScanner.quickCheck()) ignores it by
|
|
30
|
+
* design — both those call sites test bare pattern presence, not evidence
|
|
31
|
+
* tier, and that is intentional (see their own inline comments).
|
|
32
|
+
*/
|
|
33
|
+
import type { EvidenceType } from './types.js';
|
|
34
|
+
export declare const EVIDENCE_TYPE_BY_PATTERN: ReadonlyMap<RegExp, EvidenceType>;
|
|
35
|
+
//# sourceMappingURL=patterns.jailbreak.evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.jailbreak.evidence.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/patterns.jailbreak.evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAuD9C,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAMrE,CAAA"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-5876 Wave 1 / SMI-5881: evidence-tier classification for
|
|
3
|
+
* JAILBREAK_PATTERNS + AI_DEFENCE_PATTERNS.
|
|
4
|
+
* @module @skillsmith/core/security/scanner/patterns.jailbreak.evidence
|
|
5
|
+
*
|
|
6
|
+
* Split out of patterns.jailbreak.ts (SMI-5881 — that file was approaching
|
|
7
|
+
* the 500-line audit:standards gate again, same reason it was split out of
|
|
8
|
+
* patterns.ts in SMI-5876) so EVIDENCE_TYPE_BY_PATTERN's declaration doesn't
|
|
9
|
+
* grow patterns.jailbreak.ts every time a new pattern is added.
|
|
10
|
+
*
|
|
11
|
+
* Keyed by OBJECT IDENTITY, exhaustive over both arrays (asserted by test in
|
|
12
|
+
* scanner-evidence-tiers.test.ts), but classifyEvidence() (SecurityScanner.
|
|
13
|
+
* evidence.ts) still defaults UNMAPPED patterns to `imperative_instruction` —
|
|
14
|
+
* fail-closed: forgetting to classify a newly added pattern makes it
|
|
15
|
+
* strongest, never weakest.
|
|
16
|
+
*
|
|
17
|
+
* Built from parallel index-aligned arrays (not per-named-const references)
|
|
18
|
+
* because the individual pattern consts (JB_IGNORE_PREVIOUS, AD_ROLE_MARKER_
|
|
19
|
+
* BARE, ...) are private to patterns.jailbreak.ts and intentionally not
|
|
20
|
+
* exported — this file only ever sees the same JAILBREAK_PATTERNS /
|
|
21
|
+
* AI_DEFENCE_PATTERNS arrays every other consumer sees, so a length mismatch
|
|
22
|
+
* (pattern added to one array, tier forgotten here) is impossible to
|
|
23
|
+
* misalign silently: the two arrays below MUST stay index-aligned with the
|
|
24
|
+
* exported pattern arrays, or scanner-evidence-tiers.test.ts's exhaustiveness
|
|
25
|
+
* assertion catches it immediately.
|
|
26
|
+
*
|
|
27
|
+
* Consumed ONLY by SecurityScanner's severity resolution. Every other
|
|
28
|
+
* consumer of JAILBREAK_PATTERNS / AI_DEFENCE_PATTERNS (memory-injection-
|
|
29
|
+
* scanner.ts's quarantine gate, SecurityScanner.quickCheck()) ignores it by
|
|
30
|
+
* design — both those call sites test bare pattern presence, not evidence
|
|
31
|
+
* tier, and that is intentional (see their own inline comments).
|
|
32
|
+
*/
|
|
33
|
+
import { JAILBREAK_PATTERNS, AI_DEFENCE_PATTERNS } from './patterns.jailbreak.js';
|
|
34
|
+
// Index-aligned with JAILBREAK_PATTERNS (patterns.jailbreak.ts) — keep in sync.
|
|
35
|
+
const JAILBREAK_EVIDENCE = [
|
|
36
|
+
'instruction_override', // JB_IGNORE_PREVIOUS
|
|
37
|
+
'instruction_override', // JB_DISREGARD_PREVIOUS
|
|
38
|
+
'mention', // JB_DEVELOPER_MODE
|
|
39
|
+
'mention', // JB_DAN_BARE
|
|
40
|
+
'mention', // JB_DO_ANYTHING_NOW
|
|
41
|
+
'mention', // JB_JAILBREAK_BARE
|
|
42
|
+
'imperative_instruction', // JB_BYPASS_RESTRICTIONS
|
|
43
|
+
'imperative_instruction', // JB_PRETEND_NO_RESTRICTIONS
|
|
44
|
+
'imperative_instruction', // JB_ACT_NO_ETHICS
|
|
45
|
+
'imperative_instruction', // JB_YOU_ARE_NOW_FREE
|
|
46
|
+
'instruction_override', // JB_IGNORE_SAFETY_GUIDELINES
|
|
47
|
+
'imperative_instruction', // JB_HYPOTHETICAL_SCENARIO
|
|
48
|
+
'imperative_instruction', // JB_JN1_MODE_FRAME
|
|
49
|
+
'imperative_instruction', // JB_JN2_DEVELOPER_MODE_FRAME
|
|
50
|
+
'imperative_instruction', // JB_JN3_PERSONA_FRAME
|
|
51
|
+
'state_assertion', // JB_JS1_STATE_BARE
|
|
52
|
+
'state_assertion', // JB_JS2_NOUN_MODE_STATE
|
|
53
|
+
'state_assertion', // JB_JS3A_DEV_MODE_THEN_CAPABILITY
|
|
54
|
+
'state_assertion', // JB_JS3B_CAPABILITY_THEN_DEV_MODE
|
|
55
|
+
'imperative_instruction', // JB_JS4_OBEDIENCE_COMPULSION
|
|
56
|
+
'instruction_override', // JB_SPLIT_IGNORE
|
|
57
|
+
'instruction_override', // JB_SPLIT_DISREGARD
|
|
58
|
+
'imperative_instruction', // JB_SPLIT_BYPASS
|
|
59
|
+
];
|
|
60
|
+
// Index-aligned with AI_DEFENCE_PATTERNS (patterns.jailbreak.ts) — keep in sync.
|
|
61
|
+
const AI_DEFENCE_EVIDENCE = [
|
|
62
|
+
'mention', // AD_ROLE_MARKER_BARE
|
|
63
|
+
'mention', // AD_BRACKET_HIDDEN
|
|
64
|
+
'instruction_override', // AD_HTML_COMMENT_VERB
|
|
65
|
+
'mention', // AD_HTML_COMMENT_NOUN
|
|
66
|
+
'imperative_instruction', // AD_HOMOGRAPH_RUN_PLUS_KEYWORD
|
|
67
|
+
'mention', // AD_MIXED_SCRIPT_WORD
|
|
68
|
+
'mention', // AD_XML_TAG_BARE
|
|
69
|
+
'imperative_instruction', // AD_BASE64_INSTRUCTIONS
|
|
70
|
+
'mention', // AD_DELIMITER_BARE
|
|
71
|
+
'mention', // AD_JSON_ROLE_FIELD
|
|
72
|
+
'role_turn_with_body', // AD_NESTED_INSTRUCTION_BLOCK
|
|
73
|
+
'instruction_override', // AD_CRLF_INJECTION
|
|
74
|
+
'mention', // AD_TEMPLATE_LITERAL
|
|
75
|
+
'mention', // AD_ZERO_WIDTH
|
|
76
|
+
'imperative_instruction', // AD_MARKDOWN_LINK_PAYLOAD
|
|
77
|
+
'imperative_instruction', // AD_ESCAPE_SEQUENCE_ABUSE
|
|
78
|
+
'mention', // AD_ZALGO_COMBINING
|
|
79
|
+
'role_turn_with_body', // AD_AN1_ROLE_BODY_SAME_LINE
|
|
80
|
+
'role_turn_with_body', // AD_AN2_ROLE_BODY_NEXT_LINE
|
|
81
|
+
'role_turn_with_body', // AD_AN3A_CHAT_TOKEN_BODY_SAME_LINE
|
|
82
|
+
'role_turn_with_body', // AD_AN3B_CHAT_TOKEN_BODY_NEXT_LINE
|
|
83
|
+
];
|
|
84
|
+
export const EVIDENCE_TYPE_BY_PATTERN = new Map([
|
|
85
|
+
...JAILBREAK_PATTERNS.map((p, i) => [p, JAILBREAK_EVIDENCE[i]]),
|
|
86
|
+
...AI_DEFENCE_PATTERNS.map((p, i) => [p, AI_DEFENCE_EVIDENCE[i]]),
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* Module-load gate: unlike patterns.scope.ts's PATTERN_SCOPE, an unmapped
|
|
90
|
+
* entry here degrades safely (classifyEvidence() fail-closes to the
|
|
91
|
+
* strongest tier), so this isn't a silent-coverage-gap risk the way scope is.
|
|
92
|
+
* Still asserted directly rather than relying solely on `Map.has()` via
|
|
93
|
+
* scanner-evidence-tiers.test.ts's exhaustiveness check: `new Map([[p,
|
|
94
|
+
* undefined]])` reports `.has(p) === true`, so an out-of-range EVIDENCE[i]
|
|
95
|
+
* read during construction (a length mismatch between a PATTERNS array and
|
|
96
|
+
* its index-aligned EVIDENCE array) would pass a has()-only check silently.
|
|
97
|
+
*/
|
|
98
|
+
function assertEvidenceCoverage() {
|
|
99
|
+
const pairs = [
|
|
100
|
+
{ name: 'JAILBREAK_PATTERNS', patterns: JAILBREAK_PATTERNS, evidence: JAILBREAK_EVIDENCE },
|
|
101
|
+
{ name: 'AI_DEFENCE_PATTERNS', patterns: AI_DEFENCE_PATTERNS, evidence: AI_DEFENCE_EVIDENCE },
|
|
102
|
+
];
|
|
103
|
+
for (const { name, patterns, evidence } of pairs) {
|
|
104
|
+
if (patterns.length !== evidence.length) {
|
|
105
|
+
throw new Error(`[SecurityScanner] ${name} has ${patterns.length} pattern(s) but its evidence array has ` +
|
|
106
|
+
`${evidence.length} entries — they must be index-aligned and equal length. ` +
|
|
107
|
+
`Add or remove an evidence entry in patterns.jailbreak.evidence.ts to match.`);
|
|
108
|
+
}
|
|
109
|
+
patterns.forEach((pattern, index) => {
|
|
110
|
+
const evidenceType = EVIDENCE_TYPE_BY_PATTERN.get(pattern);
|
|
111
|
+
if (!EVIDENCE_TYPE_BY_PATTERN.has(pattern) || evidenceType === undefined) {
|
|
112
|
+
throw new Error(`[SecurityScanner] ${name}[${index}] (/${pattern.source}/${pattern.flags}) has no ` +
|
|
113
|
+
`EVIDENCE_TYPE_BY_PATTERN entry.`);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
assertEvidenceCoverage();
|
|
119
|
+
//# sourceMappingURL=patterns.jailbreak.evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.jailbreak.evidence.js","sourceRoot":"","sources":["../../../../src/security/scanner/patterns.jailbreak.evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAEjF,gFAAgF;AAChF,MAAM,kBAAkB,GAA4B;IAClD,sBAAsB,EAAE,qBAAqB;IAC7C,sBAAsB,EAAE,wBAAwB;IAChD,SAAS,EAAE,oBAAoB;IAC/B,SAAS,EAAE,cAAc;IACzB,SAAS,EAAE,qBAAqB;IAChC,SAAS,EAAE,oBAAoB;IAC/B,wBAAwB,EAAE,yBAAyB;IACnD,wBAAwB,EAAE,6BAA6B;IACvD,wBAAwB,EAAE,mBAAmB;IAC7C,wBAAwB,EAAE,sBAAsB;IAChD,sBAAsB,EAAE,8BAA8B;IACtD,wBAAwB,EAAE,2BAA2B;IACrD,wBAAwB,EAAE,oBAAoB;IAC9C,wBAAwB,EAAE,8BAA8B;IACxD,wBAAwB,EAAE,uBAAuB;IACjD,iBAAiB,EAAE,oBAAoB;IACvC,iBAAiB,EAAE,yBAAyB;IAC5C,iBAAiB,EAAE,mCAAmC;IACtD,iBAAiB,EAAE,mCAAmC;IACtD,wBAAwB,EAAE,8BAA8B;IACxD,sBAAsB,EAAE,kBAAkB;IAC1C,sBAAsB,EAAE,qBAAqB;IAC7C,wBAAwB,EAAE,kBAAkB;CAC7C,CAAA;AAED,iFAAiF;AACjF,MAAM,mBAAmB,GAA4B;IACnD,SAAS,EAAE,sBAAsB;IACjC,SAAS,EAAE,oBAAoB;IAC/B,sBAAsB,EAAE,uBAAuB;IAC/C,SAAS,EAAE,uBAAuB;IAClC,wBAAwB,EAAE,gCAAgC;IAC1D,SAAS,EAAE,uBAAuB;IAClC,SAAS,EAAE,kBAAkB;IAC7B,wBAAwB,EAAE,yBAAyB;IACnD,SAAS,EAAE,oBAAoB;IAC/B,SAAS,EAAE,qBAAqB;IAChC,qBAAqB,EAAE,8BAA8B;IACrD,sBAAsB,EAAE,oBAAoB;IAC5C,SAAS,EAAE,sBAAsB;IACjC,SAAS,EAAE,gBAAgB;IAC3B,wBAAwB,EAAE,2BAA2B;IACrD,wBAAwB,EAAE,2BAA2B;IACrD,SAAS,EAAE,qBAAqB;IAChC,qBAAqB,EAAE,6BAA6B;IACpD,qBAAqB,EAAE,6BAA6B;IACpD,qBAAqB,EAAE,oCAAoC;IAC3D,qBAAqB,EAAE,oCAAoC;CAC5D,CAAA;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAsC,IAAI,GAAG,CAGhF;IACA,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAU,CAAC;IACxE,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAU,CAAC;CAC3E,CAAC,CAAA;AAEF;;;;;;;;;GASG;AACH,SAAS,sBAAsB;IAC7B,MAAM,KAAK,GAIN;QACH,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,kBAAkB,EAAE,QAAQ,EAAE,kBAAkB,EAAE;QAC1F,EAAE,IAAI,EAAE,qBAAqB,EAAE,QAAQ,EAAE,mBAAmB,EAAE,QAAQ,EAAE,mBAAmB,EAAE;KAC9F,CAAA;IACD,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,KAAK,EAAE,CAAC;QACjD,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,QAAQ,QAAQ,CAAC,MAAM,yCAAyC;gBACvF,GAAG,QAAQ,CAAC,MAAM,0DAA0D;gBAC5E,6EAA6E,CAChF,CAAA;QACH,CAAC;QACD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YAClC,MAAM,YAAY,GAAG,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC1D,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBACzE,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,IAAI,KAAK,OAAO,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,WAAW;oBACjF,iCAAiC,CACpC,CAAA;YACH,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AAED,sBAAsB,EAAE,CAAA"}
|