@skillsmith/core 0.9.0 → 0.11.0
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 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts +23 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.d.ts.map +1 -1
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js +137 -0
- package/dist/src/analysis/tree-sitter/pythonIncremental.hardening.test.js.map +1 -1
- package/dist/src/analysis/tree-sitter/pythonIncremental.js +83 -10
- package/dist/src/analysis/tree-sitter/pythonIncremental.js.map +1 -1
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js +6 -1
- package/dist/src/analysis/tree-sitter/queryExtractionMatchesOrExceedsRegex.test.js.map +1 -1
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.js +6 -0
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/client.test.d.ts +9 -0
- package/dist/src/api/client.test.d.ts.map +1 -0
- package/dist/src/api/client.test.js +81 -0
- package/dist/src/api/client.test.js.map +1 -0
- package/dist/src/config/audit-notify-state.d.ts +46 -0
- package/dist/src/config/audit-notify-state.d.ts.map +1 -0
- package/dist/src/config/audit-notify-state.js +55 -0
- package/dist/src/config/audit-notify-state.js.map +1 -0
- package/dist/src/config/audit-notify-state.test.d.ts +9 -0
- package/dist/src/config/audit-notify-state.test.d.ts.map +1 -0
- package/dist/src/config/audit-notify-state.test.js +63 -0
- package/dist/src/config/audit-notify-state.test.js.map +1 -0
- package/dist/src/config/index.d.ts +10 -0
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/exports/services.d.ts +3 -1
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +9 -1
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +6 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/agent-config-merge.json-array.d.ts +29 -0
- package/dist/src/install/agent-config-merge.json-array.d.ts.map +1 -0
- package/dist/src/install/agent-config-merge.json-array.js +100 -0
- package/dist/src/install/agent-config-merge.json-array.js.map +1 -0
- package/dist/src/install/agent-config-merge.json.d.ts +37 -0
- package/dist/src/install/agent-config-merge.json.d.ts.map +1 -0
- package/dist/src/install/agent-config-merge.json.js +134 -0
- package/dist/src/install/agent-config-merge.json.js.map +1 -0
- package/dist/src/install/agent-config-merge.toml-block.d.ts +48 -0
- package/dist/src/install/agent-config-merge.toml-block.d.ts.map +1 -0
- package/dist/src/install/agent-config-merge.toml-block.js +107 -0
- package/dist/src/install/agent-config-merge.toml-block.js.map +1 -0
- package/dist/src/install/agent-config-merge.types.d.ts +87 -0
- package/dist/src/install/agent-config-merge.types.d.ts.map +1 -0
- package/dist/src/install/agent-config-merge.types.js +83 -0
- package/dist/src/install/agent-config-merge.types.js.map +1 -0
- package/dist/src/install/agent-config-merge.yaml.d.ts +46 -0
- package/dist/src/install/agent-config-merge.yaml.d.ts.map +1 -0
- package/dist/src/install/agent-config-merge.yaml.js +133 -0
- package/dist/src/install/agent-config-merge.yaml.js.map +1 -0
- package/dist/src/install/agent-config-merge.yaml.test.d.ts +2 -0
- package/dist/src/install/agent-config-merge.yaml.test.d.ts.map +1 -0
- package/dist/src/install/agent-config-merge.yaml.test.js +210 -0
- package/dist/src/install/agent-config-merge.yaml.test.js.map +1 -0
- package/dist/src/install/agent-harness-targets.d.ts +98 -0
- package/dist/src/install/agent-harness-targets.d.ts.map +1 -0
- package/dist/src/install/agent-harness-targets.js +154 -0
- package/dist/src/install/agent-harness-targets.js.map +1 -0
- package/dist/src/install/agent-home-relocate.d.ts +29 -0
- package/dist/src/install/agent-home-relocate.d.ts.map +1 -0
- package/dist/src/install/agent-home-relocate.js +38 -0
- package/dist/src/install/agent-home-relocate.js.map +1 -0
- package/dist/src/install/agent-manifest-path-guard.d.ts +55 -0
- package/dist/src/install/agent-manifest-path-guard.d.ts.map +1 -0
- package/dist/src/install/agent-manifest-path-guard.js +109 -0
- package/dist/src/install/agent-manifest-path-guard.js.map +1 -0
- package/dist/src/install/agent-manifest-path-guard.test.d.ts +2 -0
- package/dist/src/install/agent-manifest-path-guard.test.d.ts.map +1 -0
- package/dist/src/install/agent-manifest-path-guard.test.js +72 -0
- package/dist/src/install/agent-manifest-path-guard.test.js.map +1 -0
- package/dist/src/install/agent-manifest.d.ts +58 -0
- package/dist/src/install/agent-manifest.d.ts.map +1 -0
- package/dist/src/install/agent-manifest.js +103 -0
- package/dist/src/install/agent-manifest.js.map +1 -0
- package/dist/src/install/agent-pack-installer.d.ts +39 -0
- package/dist/src/install/agent-pack-installer.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.entry.d.ts +55 -0
- package/dist/src/install/agent-pack-installer.entry.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.entry.js +90 -0
- package/dist/src/install/agent-pack-installer.entry.js.map +1 -0
- package/dist/src/install/agent-pack-installer.fs-helpers.d.ts +33 -0
- package/dist/src/install/agent-pack-installer.fs-helpers.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.fs-helpers.js +59 -0
- package/dist/src/install/agent-pack-installer.fs-helpers.js.map +1 -0
- package/dist/src/install/agent-pack-installer.harness.d.ts +66 -0
- package/dist/src/install/agent-pack-installer.harness.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.harness.js +310 -0
- package/dist/src/install/agent-pack-installer.harness.js.map +1 -0
- package/dist/src/install/agent-pack-installer.js +221 -0
- package/dist/src/install/agent-pack-installer.js.map +1 -0
- package/dist/src/install/agent-pack-installer.preserve.test.d.ts +11 -0
- package/dist/src/install/agent-pack-installer.preserve.test.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.preserve.test.js +72 -0
- package/dist/src/install/agent-pack-installer.preserve.test.js.map +1 -0
- package/dist/src/install/agent-pack-installer.test.d.ts +2 -0
- package/dist/src/install/agent-pack-installer.test.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.test.js +350 -0
- package/dist/src/install/agent-pack-installer.test.js.map +1 -0
- package/dist/src/install/agent-pack-installer.types.d.ts +51 -0
- package/dist/src/install/agent-pack-installer.types.d.ts.map +1 -0
- package/dist/src/install/agent-pack-installer.types.js +16 -0
- package/dist/src/install/agent-pack-installer.types.js.map +1 -0
- package/dist/src/install/agent-pack-uninstaller.d.ts +43 -0
- package/dist/src/install/agent-pack-uninstaller.d.ts.map +1 -0
- package/dist/src/install/agent-pack-uninstaller.js +113 -0
- package/dist/src/install/agent-pack-uninstaller.js.map +1 -0
- package/dist/src/install/agent-pack-uninstaller.test.d.ts +2 -0
- package/dist/src/install/agent-pack-uninstaller.test.d.ts.map +1 -0
- package/dist/src/install/agent-pack-uninstaller.test.js +212 -0
- package/dist/src/install/agent-pack-uninstaller.test.js.map +1 -0
- package/dist/src/install/index.d.ts +7 -0
- package/dist/src/install/index.d.ts.map +1 -1
- package/dist/src/install/index.js +7 -0
- package/dist/src/install/index.js.map +1 -1
- package/dist/src/install/paths.d.ts +1 -1
- package/dist/src/install/paths.d.ts.map +1 -1
- package/dist/src/install/paths.js +4 -0
- package/dist/src/install/paths.js.map +1 -1
- package/dist/src/install/paths.test.js +15 -0
- package/dist/src/install/paths.test.js.map +1 -1
- package/dist/src/journal/hash.d.ts +13 -0
- package/dist/src/journal/hash.d.ts.map +1 -0
- package/dist/src/journal/hash.js +16 -0
- package/dist/src/journal/hash.js.map +1 -0
- package/dist/src/journal/index.d.ts +15 -0
- package/dist/src/journal/index.d.ts.map +1 -0
- package/dist/src/journal/index.js +15 -0
- package/dist/src/journal/index.js.map +1 -0
- package/dist/src/journal/journal.test.d.ts +16 -0
- package/dist/src/journal/journal.test.d.ts.map +1 -0
- package/dist/src/journal/journal.test.js +171 -0
- package/dist/src/journal/journal.test.js.map +1 -0
- package/dist/src/journal/path.d.ts +44 -0
- package/dist/src/journal/path.d.ts.map +1 -0
- package/dist/src/journal/path.js +61 -0
- package/dist/src/journal/path.js.map +1 -0
- package/dist/src/journal/reader.d.ts +38 -0
- package/dist/src/journal/reader.d.ts.map +1 -0
- package/dist/src/journal/reader.js +93 -0
- package/dist/src/journal/reader.js.map +1 -0
- package/dist/src/journal/types.d.ts +87 -0
- package/dist/src/journal/types.d.ts.map +1 -0
- package/dist/src/journal/types.js +21 -0
- package/dist/src/journal/types.js.map +1 -0
- package/dist/src/journal/writer.d.ts +52 -0
- package/dist/src/journal/writer.d.ts.map +1 -0
- package/dist/src/journal/writer.js +125 -0
- package/dist/src/journal/writer.js.map +1 -0
- package/dist/src/logging/context.d.ts +58 -0
- package/dist/src/logging/context.d.ts.map +1 -0
- package/dist/src/logging/context.js +62 -0
- package/dist/src/logging/context.js.map +1 -0
- package/dist/src/logging/context.test.d.ts +14 -0
- package/dist/src/logging/context.test.d.ts.map +1 -0
- package/dist/src/logging/context.test.js +88 -0
- package/dist/src/logging/context.test.js.map +1 -0
- package/dist/src/logging/index.d.ts +13 -0
- package/dist/src/logging/index.d.ts.map +1 -0
- package/dist/src/logging/index.js +12 -0
- package/dist/src/logging/index.js.map +1 -0
- package/dist/src/logging/logger.d.ts +71 -0
- package/dist/src/logging/logger.d.ts.map +1 -0
- package/dist/src/logging/logger.js +264 -0
- package/dist/src/logging/logger.js.map +1 -0
- package/dist/src/logging/logger.test.d.ts +9 -0
- package/dist/src/logging/logger.test.d.ts.map +1 -0
- package/dist/src/logging/logger.test.js +320 -0
- package/dist/src/logging/logger.test.js.map +1 -0
- package/dist/src/logging/redact.d.ts +35 -0
- package/dist/src/logging/redact.d.ts.map +1 -0
- package/dist/src/logging/redact.js +152 -0
- package/dist/src/logging/redact.js.map +1 -0
- package/dist/src/logging/redact.test.d.ts +8 -0
- package/dist/src/logging/redact.test.d.ts.map +1 -0
- package/dist/src/logging/redact.test.js +330 -0
- package/dist/src/logging/redact.test.js.map +1 -0
- package/dist/src/logging/rotation.d.ts +75 -0
- package/dist/src/logging/rotation.d.ts.map +1 -0
- package/dist/src/logging/rotation.js +284 -0
- package/dist/src/logging/rotation.js.map +1 -0
- package/dist/src/logging/rotation.test.d.ts +11 -0
- package/dist/src/logging/rotation.test.d.ts.map +1 -0
- package/dist/src/logging/rotation.test.js +132 -0
- package/dist/src/logging/rotation.test.js.map +1 -0
- package/dist/src/logging/types.d.ts +69 -0
- package/dist/src/logging/types.d.ts.map +1 -0
- package/dist/src/logging/types.js +9 -0
- package/dist/src/logging/types.js.map +1 -0
- package/dist/src/paywall-triggers/index.d.ts +13 -0
- package/dist/src/paywall-triggers/index.d.ts.map +1 -0
- package/dist/src/paywall-triggers/index.js +13 -0
- package/dist/src/paywall-triggers/index.js.map +1 -0
- package/dist/src/paywall-triggers/path.d.ts +47 -0
- package/dist/src/paywall-triggers/path.d.ts.map +1 -0
- package/dist/src/paywall-triggers/path.js +73 -0
- package/dist/src/paywall-triggers/path.js.map +1 -0
- package/dist/src/paywall-triggers/store.d.ts +75 -0
- package/dist/src/paywall-triggers/store.d.ts.map +1 -0
- package/dist/src/paywall-triggers/store.js +122 -0
- package/dist/src/paywall-triggers/store.js.map +1 -0
- package/dist/src/paywall-triggers/store.test.d.ts +2 -0
- package/dist/src/paywall-triggers/store.test.d.ts.map +1 -0
- package/dist/src/paywall-triggers/store.test.js +121 -0
- package/dist/src/paywall-triggers/store.test.js.map +1 -0
- package/dist/src/paywall-triggers/types.d.ts +24 -0
- package/dist/src/paywall-triggers/types.d.ts.map +1 -0
- package/dist/src/paywall-triggers/types.js +13 -0
- package/dist/src/paywall-triggers/types.js.map +1 -0
- package/dist/src/security/index.d.ts +2 -0
- package/dist/src/security/index.d.ts.map +1 -1
- package/dist/src/security/index.js +4 -0
- package/dist/src/security/index.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.compound.d.ts +13 -0
- package/dist/src/security/scanner/SecurityScanner.compound.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.compound.js +127 -0
- package/dist/src/security/scanner/SecurityScanner.compound.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts +46 -0
- package/dist/src/security/scanner/SecurityScanner.hostile-update.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.hostile-update.js +209 -0
- package/dist/src/security/scanner/SecurityScanner.hostile-update.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.js +10 -1
- package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.pii.d.ts +23 -0
- package/dist/src/security/scanner/SecurityScanner.pii.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.pii.js +152 -0
- package/dist/src/security/scanner/SecurityScanner.pii.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.scanners.d.ts +5 -12
- package/dist/src/security/scanner/SecurityScanner.scanners.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.scanners.js +63 -137
- package/dist/src/security/scanner/SecurityScanner.scanners.js.map +1 -1
- package/dist/src/security/scanner/index.d.ts +2 -1
- package/dist/src/security/scanner/index.d.ts.map +1 -1
- package/dist/src/security/scanner/index.js +2 -0
- package/dist/src/security/scanner/index.js.map +1 -1
- package/dist/src/security/scanner/patterns.d.ts +2 -0
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.js +79 -11
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +23 -0
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/services/agent-pack/agent-pack.test.d.ts +18 -0
- package/dist/src/services/agent-pack/agent-pack.test.d.ts.map +1 -0
- package/dist/src/services/agent-pack/agent-pack.test.js +344 -0
- package/dist/src/services/agent-pack/agent-pack.test.js.map +1 -0
- package/dist/src/services/agent-pack/hooks.d.ts +29 -0
- package/dist/src/services/agent-pack/hooks.d.ts.map +1 -0
- package/dist/src/services/agent-pack/hooks.js +139 -0
- package/dist/src/services/agent-pack/hooks.js.map +1 -0
- package/dist/src/services/agent-pack/index.d.ts +26 -0
- package/dist/src/services/agent-pack/index.d.ts.map +1 -0
- package/dist/src/services/agent-pack/index.js +109 -0
- package/dist/src/services/agent-pack/index.js.map +1 -0
- package/dist/src/services/agent-pack/prompt-source.d.ts +47 -0
- package/dist/src/services/agent-pack/prompt-source.d.ts.map +1 -0
- package/dist/src/services/agent-pack/prompt-source.js +182 -0
- package/dist/src/services/agent-pack/prompt-source.js.map +1 -0
- package/dist/src/services/agent-pack/shims.d.ts +40 -0
- package/dist/src/services/agent-pack/shims.d.ts.map +1 -0
- package/dist/src/services/agent-pack/shims.js +96 -0
- package/dist/src/services/agent-pack/shims.js.map +1 -0
- package/dist/src/services/agent-pack/skill-md.d.ts +35 -0
- package/dist/src/services/agent-pack/skill-md.d.ts.map +1 -0
- package/dist/src/services/agent-pack/skill-md.js +89 -0
- package/dist/src/services/agent-pack/skill-md.js.map +1 -0
- package/dist/src/services/agent-pack/types.d.ts +118 -0
- package/dist/src/services/agent-pack/types.d.ts.map +1 -0
- package/dist/src/services/agent-pack/types.js +61 -0
- package/dist/src/services/agent-pack/types.js.map +1 -0
- package/dist/src/services/agent-tool-profile.d.ts +59 -0
- package/dist/src/services/agent-tool-profile.d.ts.map +1 -0
- package/dist/src/services/agent-tool-profile.js +76 -0
- package/dist/src/services/agent-tool-profile.js.map +1 -0
- package/dist/src/services/agent-tool-profile.test.d.ts +2 -0
- package/dist/src/services/agent-tool-profile.test.d.ts.map +1 -0
- package/dist/src/services/agent-tool-profile.test.js +28 -0
- package/dist/src/services/agent-tool-profile.test.js.map +1 -0
- package/dist/src/services/bundled-sibling-scan.d.ts +111 -0
- package/dist/src/services/bundled-sibling-scan.d.ts.map +1 -0
- package/dist/src/services/bundled-sibling-scan.js +170 -0
- package/dist/src/services/bundled-sibling-scan.js.map +1 -0
- package/dist/src/services/skill-installation.io.d.ts +16 -5
- package/dist/src/services/skill-installation.io.d.ts.map +1 -1
- package/dist/src/services/skill-installation.io.js +63 -22
- package/dist/src/services/skill-installation.io.js.map +1 -1
- package/dist/src/services/skill-installation.policy.d.ts +96 -0
- package/dist/src/services/skill-installation.policy.d.ts.map +1 -0
- package/dist/src/services/skill-installation.policy.js +144 -0
- package/dist/src/services/skill-installation.policy.js.map +1 -0
- package/dist/src/services/skill-installation.service.d.ts.map +1 -1
- package/dist/src/services/skill-installation.service.js +9 -3
- package/dist/src/services/skill-installation.service.js.map +1 -1
- package/dist/src/sources/index.d.ts +1 -0
- package/dist/src/sources/index.d.ts.map +1 -1
- package/dist/src/sources/index.js +4 -0
- package/dist/src/sources/index.js.map +1 -1
- package/dist/src/sync/access-token.d.ts +27 -0
- package/dist/src/sync/access-token.d.ts.map +1 -0
- package/dist/src/sync/access-token.js +40 -0
- package/dist/src/sync/access-token.js.map +1 -0
- package/dist/src/sync/audit-notify-client.d.ts +83 -0
- package/dist/src/sync/audit-notify-client.d.ts.map +1 -0
- package/dist/src/sync/audit-notify-client.js +126 -0
- package/dist/src/sync/audit-notify-client.js.map +1 -0
- package/dist/src/sync/audit-notify-client.test.d.ts +14 -0
- package/dist/src/sync/audit-notify-client.test.d.ts.map +1 -0
- package/dist/src/sync/audit-notify-client.test.js +133 -0
- package/dist/src/sync/audit-notify-client.test.js.map +1 -0
- package/dist/src/sync/index.d.ts +2 -1
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +3 -1
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/inventory-client.d.ts +16 -0
- package/dist/src/sync/inventory-client.d.ts.map +1 -1
- package/dist/src/sync/inventory-client.js +59 -16
- package/dist/src/sync/inventory-client.js.map +1 -1
- package/dist/src/sync/inventory-client.test.js +67 -1
- package/dist/src/sync/inventory-client.test.js.map +1 -1
- package/dist/src/sync/inventory-collector.d.ts.map +1 -1
- package/dist/src/sync/inventory-collector.js +32 -5
- package/dist/src/sync/inventory-collector.js.map +1 -1
- package/dist/src/sync/inventory-collector.test.js +50 -1
- package/dist/src/sync/inventory-collector.test.js.map +1 -1
- package/dist/src/sync/inventory-types.d.ts +9 -0
- package/dist/src/sync/inventory-types.d.ts.map +1 -1
- package/dist/src/sync/inventory-types.js +3 -0
- package/dist/src/sync/inventory-types.js.map +1 -1
- package/dist/src/telemetry/agent-marker.d.ts +137 -0
- package/dist/src/telemetry/agent-marker.d.ts.map +1 -0
- package/dist/src/telemetry/agent-marker.js +242 -0
- package/dist/src/telemetry/agent-marker.js.map +1 -0
- package/dist/src/telemetry/agent-marker.test.d.ts +13 -0
- package/dist/src/telemetry/agent-marker.test.d.ts.map +1 -0
- package/dist/src/telemetry/agent-marker.test.js +202 -0
- package/dist/src/telemetry/agent-marker.test.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +2 -1
- package/dist/src/telemetry/index.d.ts.map +1 -1
- package/dist/src/telemetry/index.js +6 -1
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/posthog.d.ts +25 -0
- package/dist/src/telemetry/posthog.d.ts.map +1 -1
- package/dist/src/telemetry/posthog.js +10 -1
- package/dist/src/telemetry/posthog.js.map +1 -1
- package/dist/src/telemetry/wrap.bench.js +5 -0
- package/dist/src/telemetry/wrap.bench.js.map +1 -1
- package/dist/src/telemetry/wrap.correlation.test.d.ts +20 -0
- package/dist/src/telemetry/wrap.correlation.test.d.ts.map +1 -0
- package/dist/src/telemetry/wrap.correlation.test.js +174 -0
- package/dist/src/telemetry/wrap.correlation.test.js.map +1 -0
- package/dist/src/telemetry/wrap.d.ts +28 -7
- package/dist/src/telemetry/wrap.d.ts.map +1 -1
- package/dist/src/telemetry/wrap.gate.test.d.ts +22 -0
- package/dist/src/telemetry/wrap.gate.test.d.ts.map +1 -0
- package/dist/src/telemetry/wrap.gate.test.js +202 -0
- package/dist/src/telemetry/wrap.gate.test.js.map +1 -0
- package/dist/src/telemetry/wrap.js +196 -52
- package/dist/src/telemetry/wrap.js.map +1 -1
- package/dist/src/telemetry/wrap.marker.test.d.ts +16 -0
- package/dist/src/telemetry/wrap.marker.test.d.ts.map +1 -0
- package/dist/src/telemetry/wrap.marker.test.js +190 -0
- package/dist/src/telemetry/wrap.marker.test.js.map +1 -0
- package/dist/src/telemetry/wrap.test.js +14 -0
- package/dist/src/telemetry/wrap.test.js.map +1 -1
- package/dist/src/types.d.ts +6 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tests/SecurityScanner.exec.test.js +60 -0
- package/dist/tests/SecurityScanner.exec.test.js.map +1 -1
- package/dist/tests/security/ContinuousSecurity.test.js +10 -4
- package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
- package/dist/tests/security/SecurityScanner.chmod-evasion.test.d.ts +2 -0
- package/dist/tests/security/SecurityScanner.chmod-evasion.test.d.ts.map +1 -0
- package/dist/tests/security/SecurityScanner.chmod-evasion.test.js +126 -0
- package/dist/tests/security/SecurityScanner.chmod-evasion.test.js.map +1 -0
- package/dist/tests/security/chmod-compound.test.d.ts +2 -0
- package/dist/tests/security/chmod-compound.test.d.ts.map +1 -0
- package/dist/tests/security/chmod-compound.test.js +188 -0
- package/dist/tests/security/chmod-compound.test.js.map +1 -0
- package/dist/tests/security/pii-detection.test.js +24 -0
- package/dist/tests/security/pii-detection.test.js.map +1 -1
- package/dist/tests/security/scanner-regression-guard.test.d.ts +23 -7
- package/dist/tests/security/scanner-regression-guard.test.d.ts.map +1 -1
- package/dist/tests/security/scanner-regression-guard.test.js +206 -12
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/dist/tests/security/sensitive-path-fp.test.d.ts +2 -0
- package/dist/tests/security/sensitive-path-fp.test.d.ts.map +1 -0
- package/dist/tests/security/sensitive-path-fp.test.js +142 -0
- package/dist/tests/security/sensitive-path-fp.test.js.map +1 -0
- package/dist/tests/services/bundled-sibling-scan.test.d.ts +2 -0
- package/dist/tests/services/bundled-sibling-scan.test.d.ts.map +1 -0
- package/dist/tests/services/bundled-sibling-scan.test.js +139 -0
- package/dist/tests/services/bundled-sibling-scan.test.js.map +1 -0
- package/dist/tests/unit/services/skill-installation.io.test.js +166 -0
- package/dist/tests/unit/services/skill-installation.io.test.js.map +1 -1
- package/dist/tests/unit/services/skill-installation.policy.test.d.ts +8 -0
- package/dist/tests/unit/services/skill-installation.policy.test.d.ts.map +1 -0
- package/dist/tests/unit/services/skill-installation.policy.test.js +151 -0
- package/dist/tests/unit/services/skill-installation.policy.test.js.map +1 -0
- package/package.json +28 -3
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Bundled-sibling security scan for the local rescan path (SMI-5422 Phase 2).
|
|
3
|
+
* @module @skillsmith/core/services/bundled-sibling-scan
|
|
4
|
+
*
|
|
5
|
+
* Walks an installed skill's bundle directory and scans its sibling bundled
|
|
6
|
+
* files (`.mcp.json`, `.claude/settings*.json`, `package.json` lifecycle hooks,
|
|
7
|
+
* `config.json`, `scripts/*.sh` + top-level `*.sh`) so `skill_rescan` can
|
|
8
|
+
* quarantine a skill whose MALICIOUS sibling — not its `SKILL.md` — carries the
|
|
9
|
+
* threat (CVE-2025-59536 hook execution, `curl|bash` postinstall, a
|
|
10
|
+
* remote-fetch-execute install script).
|
|
11
|
+
*
|
|
12
|
+
* This is the local-FS rescan analogue of the Phase-1 install/validate helpers —
|
|
13
|
+
* NOT a duplicate. The three callers intentionally differ:
|
|
14
|
+
* - install: `skill-installation.io.ts` `fetchAndScanOptionalFiles` (fetch-by-path, no glob)
|
|
15
|
+
* - validate: mcp-server `validate-bundled-scan.ts` `scanBundledSiblings` (returns ValidationError[])
|
|
16
|
+
* - rescan (this): directory walk + symlink-safe reads + structured result.
|
|
17
|
+
*
|
|
18
|
+
* DELIBERATE FP-SAFE DIVERGENCE (Phase 2 review B1, verified empirically):
|
|
19
|
+
* install/validate reject via `isRejectableScan` (= `!report.passed` OR a
|
|
20
|
+
* `code_execution`/`obfuscated_directive` finding). The `!report.passed` clause
|
|
21
|
+
* fires on ANY high/critical finding, and sibling files are non-markdown so they
|
|
22
|
+
* get NO documentation-context downgrade — so routine, benign script idioms fire
|
|
23
|
+
* at full severity and would quarantine a working skill:
|
|
24
|
+
* `chmod 755 ./bin/cli` => privilege_escalation:critical => !passed
|
|
25
|
+
* `cp .env.example .env` => sensitive_path:high => !passed
|
|
26
|
+
* `source .env` / `export X=$1` / `cat ~/.ssh/...` => sensitive_path:high
|
|
27
|
+
* For an ALREADY-INSTALLED skill that false positive hides a working skill from
|
|
28
|
+
* local search. So this module drives the quarantine decision SOLELY from
|
|
29
|
+
* `code_execution`/`obfuscated_directive` presence (still catches `curl|bash`).
|
|
30
|
+
* The root cause — privilege_escalation/sensitive_path over-firing in
|
|
31
|
+
* non-markdown execution contexts (which is the SAME latent FP on the install
|
|
32
|
+
* path) — is tracked in SMI-5424; once those patterns are narrowed at the
|
|
33
|
+
* source, all three callers can safely share the broader criterion.
|
|
34
|
+
*
|
|
35
|
+
* INHERITED DETECTION GAPS (FN, tracked SMI-5424): bare-interpreter hook
|
|
36
|
+
* payloads (`node evil.js`, `python evil.py`, `bun`/`deno`), `&&`/`;`-chained
|
|
37
|
+
* fetch-then-exec, `npx`, and JSON `\uXXXX`-escaped commands inside raw-scanned
|
|
38
|
+
* structured files are NOT detected. `.js`/`.py`/`.mjs`/`.ts` payload files and
|
|
39
|
+
* nested/non-`scripts/` `.sh` are a Phase-3 follow-up (recursive bundle walk).
|
|
40
|
+
* COUNT-CAP DECOY-PADDING (FN): the fixed bundled files are cap-exempt, but the
|
|
41
|
+
* `.sh` glob is capped — an author can name the malicious script to sort last
|
|
42
|
+
* and pad `scripts/` with cap-many benign decoys so it lands in `droppedForCount`
|
|
43
|
+
* and is never scanned. This is surfaced (never a silent drop) but not blocked;
|
|
44
|
+
* a cumulative-resource bound is a Phase-3 follow-up.
|
|
45
|
+
*
|
|
46
|
+
* config.json IS scanned here (only doc-class siblings are skipped), whereas the
|
|
47
|
+
* Phase-1 validate helper (validate-bundled-scan.ts) also skips `config` — rescan
|
|
48
|
+
* is the deliberately stricter superset because it is a quarantine path.
|
|
49
|
+
*/
|
|
50
|
+
import type { SecurityFinding } from '../security/scanner/types.js';
|
|
51
|
+
import type { SecurityScanner } from '../security/index.js';
|
|
52
|
+
/** Max `.sh` glob files scanned per skill (fixed bundled files are exempt). */
|
|
53
|
+
export declare const MAX_SIBLING_SH_FILES = 50;
|
|
54
|
+
/** Per-file byte ceiling; larger siblings are skipped (recorded, never silent). */
|
|
55
|
+
export declare const MAX_SIBLING_FILE_BYTES: number;
|
|
56
|
+
/** Tunable caps for {@link scanLocalBundleSiblings}. */
|
|
57
|
+
export interface BundledSiblingScanOptions {
|
|
58
|
+
/** Override {@link MAX_SIBLING_SH_FILES}. */
|
|
59
|
+
maxShFiles?: number;
|
|
60
|
+
/** Override {@link MAX_SIBLING_FILE_BYTES}. */
|
|
61
|
+
maxBytesPerFile?: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Result of scanning a skill bundle's sibling files. All path fields are
|
|
65
|
+
* relative to the skill directory. `findings` is the full (display) set;
|
|
66
|
+
* `rejectableFindings`/`rejectableFiles` are the quarantine-driving subset.
|
|
67
|
+
*/
|
|
68
|
+
export interface BundledSiblingScanResult {
|
|
69
|
+
/** All non-doc sibling findings, each tagged with `location = relPath`. */
|
|
70
|
+
findings: SecurityFinding[];
|
|
71
|
+
/** True when any sibling carries a `code_execution`/`obfuscated_directive`. */
|
|
72
|
+
rejectable: boolean;
|
|
73
|
+
/** The execution-threat findings that drive quarantine. */
|
|
74
|
+
rejectableFindings: SecurityFinding[];
|
|
75
|
+
/** Relative paths that drove rejection. */
|
|
76
|
+
rejectableFiles: string[];
|
|
77
|
+
/** Relative paths actually scanned. */
|
|
78
|
+
scannedFiles: string[];
|
|
79
|
+
/**
|
|
80
|
+
* Max riskScore across REJECTING sibling reports only (display only; rejection
|
|
81
|
+
* is type-driven so this can be below the threshold). Non-rejecting siblings
|
|
82
|
+
* (e.g. a benign `chmod` that scores high) are excluded so they cannot
|
|
83
|
+
* mis-attribute a quarantine's surfaced score.
|
|
84
|
+
*/
|
|
85
|
+
maxSiblingRiskScore: number;
|
|
86
|
+
/** `.sh` files beyond the count cap — surfaced, never silently dropped. */
|
|
87
|
+
droppedForCount: string[];
|
|
88
|
+
/** Files skipped for exceeding the byte cap. */
|
|
89
|
+
skippedOversize: string[];
|
|
90
|
+
/** Symlink siblings resolving outside the skill dir (SMI-4287 guard). */
|
|
91
|
+
skippedSymlinkEscape: string[];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Scan a skill bundle's sibling files and return the structured result.
|
|
95
|
+
*
|
|
96
|
+
* Fixed {@link BUNDLED_SCAN_FILES} are always scanned (exempt from the count
|
|
97
|
+
* cap, so a decoy-padding attack on `scripts/` cannot push the primary hook /
|
|
98
|
+
* postinstall surface out of the scan window). The `.sh` glob is capped and
|
|
99
|
+
* any overflow is reported in `droppedForCount`.
|
|
100
|
+
*
|
|
101
|
+
* Doc-class siblings (`README.md`, `examples.md`) are intentionally NOT scanned:
|
|
102
|
+
* prose routinely quotes attack strings, so they can never drive a quarantine
|
|
103
|
+
* (Phase-1 H6 control). Every read is symlink-safe via `resolveSafeRealpath`
|
|
104
|
+
* (containment to `skillDir`, SMI-4287) and reads the resolved realpath.
|
|
105
|
+
*
|
|
106
|
+
* @param skillDir absolute path to the installed skill's bundle directory
|
|
107
|
+
* @param scanner a constructed SecurityScanner (injected to keep this module DB-free)
|
|
108
|
+
* @param opts optional caps
|
|
109
|
+
*/
|
|
110
|
+
export declare function scanLocalBundleSiblings(skillDir: string, scanner: SecurityScanner, opts?: BundledSiblingScanOptions): Promise<BundledSiblingScanResult>;
|
|
111
|
+
//# sourceMappingURL=bundled-sibling-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-sibling-scan.d.ts","sourceRoot":"","sources":["../../../src/services/bundled-sibling-scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAc,MAAM,8BAA8B,CAAA;AAI/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAQ3D,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,KAAK,CAAA;AACtC,mFAAmF;AACnF,eAAO,MAAM,sBAAsB,QAAa,CAAA;AAEhD,wDAAwD;AACxD,MAAM,WAAW,yBAAyB;IACxC,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,+CAA+C;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,eAAe,EAAE,CAAA;IAC3B,+EAA+E;IAC/E,UAAU,EAAE,OAAO,CAAA;IACnB,2DAA2D;IAC3D,kBAAkB,EAAE,eAAe,EAAE,CAAA;IACrC,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,uCAAuC;IACvC,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB;;;;;OAKG;IACH,mBAAmB,EAAE,MAAM,CAAA;IAC3B,2EAA2E;IAC3E,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,gDAAgD;IAChD,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,yEAAyE;IACzE,oBAAoB,EAAE,MAAM,EAAE,CAAA;CAC/B;AAgCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,eAAe,EACxB,IAAI,GAAE,yBAA8B,GACnC,OAAO,CAAC,wBAAwB,CAAC,CAuEnC"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Bundled-sibling security scan for the local rescan path (SMI-5422 Phase 2).
|
|
3
|
+
* @module @skillsmith/core/services/bundled-sibling-scan
|
|
4
|
+
*
|
|
5
|
+
* Walks an installed skill's bundle directory and scans its sibling bundled
|
|
6
|
+
* files (`.mcp.json`, `.claude/settings*.json`, `package.json` lifecycle hooks,
|
|
7
|
+
* `config.json`, `scripts/*.sh` + top-level `*.sh`) so `skill_rescan` can
|
|
8
|
+
* quarantine a skill whose MALICIOUS sibling — not its `SKILL.md` — carries the
|
|
9
|
+
* threat (CVE-2025-59536 hook execution, `curl|bash` postinstall, a
|
|
10
|
+
* remote-fetch-execute install script).
|
|
11
|
+
*
|
|
12
|
+
* This is the local-FS rescan analogue of the Phase-1 install/validate helpers —
|
|
13
|
+
* NOT a duplicate. The three callers intentionally differ:
|
|
14
|
+
* - install: `skill-installation.io.ts` `fetchAndScanOptionalFiles` (fetch-by-path, no glob)
|
|
15
|
+
* - validate: mcp-server `validate-bundled-scan.ts` `scanBundledSiblings` (returns ValidationError[])
|
|
16
|
+
* - rescan (this): directory walk + symlink-safe reads + structured result.
|
|
17
|
+
*
|
|
18
|
+
* DELIBERATE FP-SAFE DIVERGENCE (Phase 2 review B1, verified empirically):
|
|
19
|
+
* install/validate reject via `isRejectableScan` (= `!report.passed` OR a
|
|
20
|
+
* `code_execution`/`obfuscated_directive` finding). The `!report.passed` clause
|
|
21
|
+
* fires on ANY high/critical finding, and sibling files are non-markdown so they
|
|
22
|
+
* get NO documentation-context downgrade — so routine, benign script idioms fire
|
|
23
|
+
* at full severity and would quarantine a working skill:
|
|
24
|
+
* `chmod 755 ./bin/cli` => privilege_escalation:critical => !passed
|
|
25
|
+
* `cp .env.example .env` => sensitive_path:high => !passed
|
|
26
|
+
* `source .env` / `export X=$1` / `cat ~/.ssh/...` => sensitive_path:high
|
|
27
|
+
* For an ALREADY-INSTALLED skill that false positive hides a working skill from
|
|
28
|
+
* local search. So this module drives the quarantine decision SOLELY from
|
|
29
|
+
* `code_execution`/`obfuscated_directive` presence (still catches `curl|bash`).
|
|
30
|
+
* The root cause — privilege_escalation/sensitive_path over-firing in
|
|
31
|
+
* non-markdown execution contexts (which is the SAME latent FP on the install
|
|
32
|
+
* path) — is tracked in SMI-5424; once those patterns are narrowed at the
|
|
33
|
+
* source, all three callers can safely share the broader criterion.
|
|
34
|
+
*
|
|
35
|
+
* INHERITED DETECTION GAPS (FN, tracked SMI-5424): bare-interpreter hook
|
|
36
|
+
* payloads (`node evil.js`, `python evil.py`, `bun`/`deno`), `&&`/`;`-chained
|
|
37
|
+
* fetch-then-exec, `npx`, and JSON `\uXXXX`-escaped commands inside raw-scanned
|
|
38
|
+
* structured files are NOT detected. `.js`/`.py`/`.mjs`/`.ts` payload files and
|
|
39
|
+
* nested/non-`scripts/` `.sh` are a Phase-3 follow-up (recursive bundle walk).
|
|
40
|
+
* COUNT-CAP DECOY-PADDING (FN): the fixed bundled files are cap-exempt, but the
|
|
41
|
+
* `.sh` glob is capped — an author can name the malicious script to sort last
|
|
42
|
+
* and pad `scripts/` with cap-many benign decoys so it lands in `droppedForCount`
|
|
43
|
+
* and is never scanned. This is surfaced (never a silent drop) but not blocked;
|
|
44
|
+
* a cumulative-resource bound is a Phase-3 follow-up.
|
|
45
|
+
*
|
|
46
|
+
* config.json IS scanned here (only doc-class siblings are skipped), whereas the
|
|
47
|
+
* Phase-1 validate helper (validate-bundled-scan.ts) also skips `config` — rescan
|
|
48
|
+
* is the deliberately stricter superset because it is a quarantine path.
|
|
49
|
+
*/
|
|
50
|
+
import { join } from 'path';
|
|
51
|
+
import { safeFs, resolveSafeRealpath } from '../sources/LocalFilesystemAdapter.helpers.js';
|
|
52
|
+
import { BUNDLED_SCAN_FILES, classifyBundledFile, extractPackageJsonLifecycleScripts, } from './skill-installation.policy.js';
|
|
53
|
+
/** Max `.sh` glob files scanned per skill (fixed bundled files are exempt). */
|
|
54
|
+
export const MAX_SIBLING_SH_FILES = 50;
|
|
55
|
+
/** Per-file byte ceiling; larger siblings are skipped (recorded, never silent). */
|
|
56
|
+
export const MAX_SIBLING_FILE_BYTES = 512 * 1024;
|
|
57
|
+
/** A finding is a quarantine driver only if it is a direct execution threat. */
|
|
58
|
+
function isExecutionThreat(finding) {
|
|
59
|
+
return finding.type === 'code_execution' || finding.type === 'obfuscated_directive';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Collect `*.sh` candidates: top-level then `scripts/`, regular files only
|
|
63
|
+
* (symlinked scripts are not followed by the glob — Phase 3). Sorted so the cap
|
|
64
|
+
* and `droppedForCount` are reproducible rather than dependent on readdir order.
|
|
65
|
+
* NOTE: sorting does NOT defeat decoy-padding — an author can name the malicious
|
|
66
|
+
* file to sort last; that residual FN is documented in the module header and the
|
|
67
|
+
* dropped names are always surfaced in `droppedForCount` (no silent drop).
|
|
68
|
+
*/
|
|
69
|
+
async function collectShFiles(skillDir) {
|
|
70
|
+
const out = [];
|
|
71
|
+
const top = await safeFs.readdir(skillDir);
|
|
72
|
+
if (top.ok) {
|
|
73
|
+
for (const e of top.value) {
|
|
74
|
+
if (e.isFile() && e.name.endsWith('.sh'))
|
|
75
|
+
out.push(e.name);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const scripts = await safeFs.readdir(join(skillDir, 'scripts'));
|
|
79
|
+
if (scripts.ok) {
|
|
80
|
+
for (const e of scripts.value) {
|
|
81
|
+
if (e.isFile() && e.name.endsWith('.sh'))
|
|
82
|
+
out.push(join('scripts', e.name));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return out.sort();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Scan a skill bundle's sibling files and return the structured result.
|
|
89
|
+
*
|
|
90
|
+
* Fixed {@link BUNDLED_SCAN_FILES} are always scanned (exempt from the count
|
|
91
|
+
* cap, so a decoy-padding attack on `scripts/` cannot push the primary hook /
|
|
92
|
+
* postinstall surface out of the scan window). The `.sh` glob is capped and
|
|
93
|
+
* any overflow is reported in `droppedForCount`.
|
|
94
|
+
*
|
|
95
|
+
* Doc-class siblings (`README.md`, `examples.md`) are intentionally NOT scanned:
|
|
96
|
+
* prose routinely quotes attack strings, so they can never drive a quarantine
|
|
97
|
+
* (Phase-1 H6 control). Every read is symlink-safe via `resolveSafeRealpath`
|
|
98
|
+
* (containment to `skillDir`, SMI-4287) and reads the resolved realpath.
|
|
99
|
+
*
|
|
100
|
+
* @param skillDir absolute path to the installed skill's bundle directory
|
|
101
|
+
* @param scanner a constructed SecurityScanner (injected to keep this module DB-free)
|
|
102
|
+
* @param opts optional caps
|
|
103
|
+
*/
|
|
104
|
+
export async function scanLocalBundleSiblings(skillDir, scanner, opts = {}) {
|
|
105
|
+
const maxShFiles = opts.maxShFiles ?? MAX_SIBLING_SH_FILES;
|
|
106
|
+
const maxBytes = opts.maxBytesPerFile ?? MAX_SIBLING_FILE_BYTES;
|
|
107
|
+
const result = {
|
|
108
|
+
findings: [],
|
|
109
|
+
rejectable: false,
|
|
110
|
+
rejectableFindings: [],
|
|
111
|
+
rejectableFiles: [],
|
|
112
|
+
scannedFiles: [],
|
|
113
|
+
maxSiblingRiskScore: 0,
|
|
114
|
+
droppedForCount: [],
|
|
115
|
+
skippedOversize: [],
|
|
116
|
+
skippedSymlinkEscape: [],
|
|
117
|
+
};
|
|
118
|
+
const shFiles = await collectShFiles(skillDir);
|
|
119
|
+
result.droppedForCount = shFiles.slice(maxShFiles);
|
|
120
|
+
// Fixed files first (cap-exempt), then the capped, sorted .sh glob.
|
|
121
|
+
const candidates = [...BUNDLED_SCAN_FILES, ...shFiles.slice(0, maxShFiles)];
|
|
122
|
+
for (const rel of candidates) {
|
|
123
|
+
const fileClass = classifyBundledFile(rel);
|
|
124
|
+
if (fileClass === 'doc')
|
|
125
|
+
continue; // prose quotes attack strings (H6) — never scanned
|
|
126
|
+
const abs = join(skillDir, rel);
|
|
127
|
+
const resolved = await resolveSafeRealpath(abs, skillDir, {});
|
|
128
|
+
if (!resolved.ok) {
|
|
129
|
+
// not-found = sibling absent (silent skip). symlink-escape = SMI-4287 guard.
|
|
130
|
+
// loop/permission/io = unreadable; skip (the file contributes no signal).
|
|
131
|
+
if (resolved.error.code === 'symlink-escape')
|
|
132
|
+
result.skippedSymlinkEscape.push(rel);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const realPath = resolved.value;
|
|
136
|
+
const st = await safeFs.stat(realPath);
|
|
137
|
+
if (!st.ok)
|
|
138
|
+
continue;
|
|
139
|
+
if (st.value.size > maxBytes) {
|
|
140
|
+
result.skippedOversize.push(rel);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const read = await safeFs.readFile(realPath);
|
|
144
|
+
if (!read.ok)
|
|
145
|
+
continue;
|
|
146
|
+
let textToScan = read.value;
|
|
147
|
+
if (fileClass === 'package-json') {
|
|
148
|
+
const lifecycle = extractPackageJsonLifecycleScripts(read.value);
|
|
149
|
+
if (lifecycle.length === 0)
|
|
150
|
+
continue; // no install-time hooks — nothing risky
|
|
151
|
+
textToScan = lifecycle;
|
|
152
|
+
}
|
|
153
|
+
const report = scanner.scan(`${skillDir}/${rel}`, textToScan);
|
|
154
|
+
result.scannedFiles.push(rel);
|
|
155
|
+
// Fresh objects (no mutation of the report's findings array) tagged with the file.
|
|
156
|
+
const tagged = report.findings.map((f) => ({ ...f, location: rel }));
|
|
157
|
+
result.findings.push(...tagged);
|
|
158
|
+
const drivers = tagged.filter(isExecutionThreat);
|
|
159
|
+
if (drivers.length > 0) {
|
|
160
|
+
result.rejectable = true;
|
|
161
|
+
result.rejectableFindings.push(...drivers);
|
|
162
|
+
result.rejectableFiles.push(rel);
|
|
163
|
+
// Only a REJECTING sibling contributes to the surfaced score, so a benign
|
|
164
|
+
// high-scoring sibling cannot mis-attribute the quarantine's riskScore.
|
|
165
|
+
result.maxSiblingRiskScore = Math.max(result.maxSiblingRiskScore, report.riskScore);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=bundled-sibling-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-sibling-scan.js","sourceRoot":"","sources":["../../../src/services/bundled-sibling-scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,11 +33,22 @@ export interface OptionalInstallFilesResult {
|
|
|
33
33
|
}>;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
|
-
* SMI-5359 Gap-1: fetch + scan the optional install files
|
|
37
|
-
* The caller runs this BEFORE writeInstallFiles, rejects
|
|
38
|
-
* and only then writes `filesToWrite` (so a malicious
|
|
39
|
-
* leave a partially-installed skill on disk).
|
|
40
|
-
*
|
|
36
|
+
* SMI-5359 Gap-1 / SMI-5422 Phase 1: fetch + scan the optional install files
|
|
37
|
+
* WITHOUT writing them. The caller runs this BEFORE writeInstallFiles, rejects
|
|
38
|
+
* on any `failedScans`, and only then writes `filesToWrite` (so a malicious
|
|
39
|
+
* optional file can never leave a partially-installed skill on disk).
|
|
40
|
+
*
|
|
41
|
+
* Per-file policy (see skill-installation.policy.ts for the authoritative spec):
|
|
42
|
+
* doc – scan failure is a silent skip (FP control H6).
|
|
43
|
+
* config – hard-reject on scan failure (pre-existing behaviour).
|
|
44
|
+
* structured – hard-reject on scan failure, all trust tiers.
|
|
45
|
+
* package-json – KEY-LEVEL: only lifecycle-hook script values are scanned.
|
|
46
|
+
* A package.json with no lifecycle hooks is never rejected.
|
|
47
|
+
*
|
|
48
|
+
* A fetch/404 error is always a silent skip (NOT a scan failure).
|
|
49
|
+
*
|
|
50
|
+
* Phase 3 follow-up: directory-glob scanning (e.g. scripts/*.sh) is out of
|
|
51
|
+
* scope here — fetchFromGitHub fetches by exact path only.
|
|
41
52
|
*/
|
|
42
53
|
export declare function fetchAndScanOptionalFiles(owner: string, repo: string, basePath: string, branch: string, skillId: string, scannerOptions: ScannerOptions | null): Promise<OptionalInstallFilesResult>;
|
|
43
54
|
//# sourceMappingURL=skill-installation.io.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-installation.io.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.io.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"skill-installation.io.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.io.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAStE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAQ1E;AAkBD,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAkBlB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,aAAa,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC3D,eAAe,EAAE,MAAM,GAAG,SAAS,GAClC,OAAO,CAAC,kBAAkB,CAAC,CA0E7B;AAED,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB;;;OAGG;IACH,WAAW,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;IACxD,4EAA4E;IAC5E,YAAY,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC3D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,cAAc,GAAG,IAAI,GACpC,OAAO,CAAC,0BAA0B,CAAC,CAgDrC"}
|
|
@@ -9,6 +9,7 @@ import * as os from 'os';
|
|
|
9
9
|
import { safeWriteFile } from '../utils/safe-fs.js';
|
|
10
10
|
import { SecurityScanner } from '../security/index.js';
|
|
11
11
|
import { validateOptionalConfig } from './skill-installation.validate.js';
|
|
12
|
+
import { BUNDLED_SCAN_FILES, classifyBundledFile, extractPackageJsonLifecycleScripts, isRejectableScan, } from './skill-installation.policy.js';
|
|
12
13
|
export function assertNotEncrypted(content, filePath) {
|
|
13
14
|
if (content.startsWith('\x00GITCRYPT')) {
|
|
14
15
|
throw new Error('File "' +
|
|
@@ -16,13 +17,30 @@ export function assertNotEncrypted(content, filePath) {
|
|
|
16
17
|
'" is git-crypt encrypted. The repository uses git-crypt and this file cannot be fetched from GitHub.');
|
|
17
18
|
}
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* SMI-5582: per-request timeout for raw.githubusercontent.com fetches.
|
|
22
|
+
*
|
|
23
|
+
* This is THE critical-path GitHub fetch for a registry install: it is reached
|
|
24
|
+
* from `SkillInstallationService.install()` (SKILL.md) and from
|
|
25
|
+
* `fetchAndScanOptionalFiles` (up to 7 optional files), each with a possible
|
|
26
|
+
* `main`→`master` fallback — i.e. up to ~16 sequential network calls per
|
|
27
|
+
* skill. Before SMI-5582 none of them were bounded, so a single hung GitHub
|
|
28
|
+
* socket could stall the caller indefinitely. Since Tier-1 auto-install now
|
|
29
|
+
* runs this chain at server startup, an unbounded fetch here is what would
|
|
30
|
+
* have hung MCP startup. 10s matches the "generous but finite" budget of the
|
|
31
|
+
* other startup network paths (`version-check.ts` uses 3s for a single npm
|
|
32
|
+
* ping; this is a heavier raw-content fetch, hence the larger bound).
|
|
33
|
+
*/
|
|
34
|
+
const GITHUB_FETCH_TIMEOUT_MS = 10_000;
|
|
19
35
|
export async function fetchFromGitHub(owner, repo, filePath, branch = 'main') {
|
|
20
36
|
const url = 'https://raw.githubusercontent.com/' + owner + '/' + repo + '/' + branch + '/' + filePath;
|
|
21
|
-
const response = await fetch(url);
|
|
37
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(GITHUB_FETCH_TIMEOUT_MS) });
|
|
22
38
|
if (!response.ok) {
|
|
23
39
|
if (branch === 'main') {
|
|
24
40
|
const masterUrl = 'https://raw.githubusercontent.com/' + owner + '/' + repo + '/master/' + filePath;
|
|
25
|
-
const masterResponse = await fetch(masterUrl
|
|
41
|
+
const masterResponse = await fetch(masterUrl, {
|
|
42
|
+
signal: AbortSignal.timeout(GITHUB_FETCH_TIMEOUT_MS),
|
|
43
|
+
});
|
|
26
44
|
if (!masterResponse.ok) {
|
|
27
45
|
throw new Error('Failed to fetch ' + filePath + ': ' + response.status);
|
|
28
46
|
}
|
|
@@ -126,41 +144,64 @@ export async function writeInstallFiles(installPath, skillsDir, skillName, final
|
|
|
126
144
|
return { writtenFiles, subagentPath };
|
|
127
145
|
}
|
|
128
146
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
147
|
+
* SMI-5359 Gap-1 / SMI-5422 Phase 1: fetch + scan the optional install files
|
|
148
|
+
* WITHOUT writing them. The caller runs this BEFORE writeInstallFiles, rejects
|
|
149
|
+
* on any `failedScans`, and only then writes `filesToWrite` (so a malicious
|
|
150
|
+
* optional file can never leave a partially-installed skill on disk).
|
|
151
|
+
*
|
|
152
|
+
* Per-file policy (see skill-installation.policy.ts for the authoritative spec):
|
|
153
|
+
* doc – scan failure is a silent skip (FP control H6).
|
|
154
|
+
* config – hard-reject on scan failure (pre-existing behaviour).
|
|
155
|
+
* structured – hard-reject on scan failure, all trust tiers.
|
|
156
|
+
* package-json – KEY-LEVEL: only lifecycle-hook script values are scanned.
|
|
157
|
+
* A package.json with no lifecycle hooks is never rejected.
|
|
158
|
+
*
|
|
159
|
+
* A fetch/404 error is always a silent skip (NOT a scan failure).
|
|
160
|
+
*
|
|
161
|
+
* Phase 3 follow-up: directory-glob scanning (e.g. scripts/*.sh) is out of
|
|
162
|
+
* scope here — fetchFromGitHub fetches by exact path only.
|
|
140
163
|
*/
|
|
141
164
|
export async function fetchAndScanOptionalFiles(owner, repo, basePath, branch, skillId, scannerOptions) {
|
|
142
165
|
const optionalFileScanner = scannerOptions ? new SecurityScanner(scannerOptions) : null;
|
|
143
|
-
const optionalFiles = ['README.md', 'examples.md', 'config.json'];
|
|
144
166
|
const configWarnings = [];
|
|
145
167
|
const failedScans = [];
|
|
146
168
|
const filesToWrite = [];
|
|
147
|
-
for (const file of
|
|
169
|
+
for (const file of BUNDLED_SCAN_FILES) {
|
|
148
170
|
let content;
|
|
149
171
|
try {
|
|
150
172
|
content = await fetchFromGitHub(owner, repo, basePath + file, branch);
|
|
151
173
|
}
|
|
152
174
|
catch {
|
|
153
|
-
// Optional file absent / fetch failed —
|
|
175
|
+
// Optional file absent / fetch failed — silent skip (NOT a scan failure).
|
|
154
176
|
continue;
|
|
155
177
|
}
|
|
156
178
|
if (optionalFileScanner) {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
const fileClass = classifyBundledFile(file);
|
|
180
|
+
// Determine the text to scan. For package-json, only lifecycle hook values;
|
|
181
|
+
// for everything else, the full file content.
|
|
182
|
+
let textToScan;
|
|
183
|
+
if (fileClass === 'package-json') {
|
|
184
|
+
const lifecycle = extractPackageJsonLifecycleScripts(content);
|
|
185
|
+
// Empty string means no install-time hooks — nothing risky to scan.
|
|
186
|
+
textToScan = lifecycle.length > 0 ? lifecycle : null;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
textToScan = content;
|
|
190
|
+
}
|
|
191
|
+
if (textToScan !== null) {
|
|
192
|
+
const fileScan = optionalFileScanner.scan(skillId + '/' + file, textToScan);
|
|
193
|
+
// Hard-reject classes also reject on a lone code_execution / obfuscated_
|
|
194
|
+
// directive finding (medium severity), which `passed` alone would miss —
|
|
195
|
+
// remote-fetch-execute / concealed directives have no place in a hook
|
|
196
|
+
// or config file (SMI-5422 Phase 1; isRejectableScan is FP-safe).
|
|
197
|
+
if (isRejectableScan(fileScan)) {
|
|
198
|
+
// H6 FP control: prose docs quote attack strings — never hard-reject.
|
|
199
|
+
if (fileClass === 'doc')
|
|
200
|
+
continue;
|
|
201
|
+
// config, structured, and package-json all hard-reject on failure.
|
|
202
|
+
failedScans.push({ file, report: fileScan });
|
|
161
203
|
continue;
|
|
162
|
-
|
|
163
|
-
continue;
|
|
204
|
+
}
|
|
164
205
|
}
|
|
165
206
|
}
|
|
166
207
|
if (file === 'config.json') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-installation.io.js","sourceRoot":"","sources":["../../../src/services/skill-installation.io.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAA;AACjC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAC5B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"skill-installation.io.js","sourceRoot":"","sources":["../../../src/services/skill-installation.io.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Scan policy for bundled optional files in the skill install path.
|
|
3
|
+
* @module @skillsmith/core/services/skill-installation.policy
|
|
4
|
+
* @see SMI-5422 Phase 1: widen the bundled-file scan corpus
|
|
5
|
+
*
|
|
6
|
+
* Kept in its own module so io.ts and mcp-server/validate.ts can share the
|
|
7
|
+
* policy without coupling to the full install service. The three exports —
|
|
8
|
+
* BUNDLED_SCAN_FILES, classifyBundledFile, extractPackageJsonLifecycleScripts —
|
|
9
|
+
* are the contract; everything else is implementation detail.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Per-file scan policy classes for bundled optional install files.
|
|
13
|
+
*
|
|
14
|
+
* doc - Routine prose docs that routinely quote attack strings as
|
|
15
|
+
* examples (FP control H6). A scan failure is a SILENT SKIP —
|
|
16
|
+
* never a hard reject.
|
|
17
|
+
* config - Pre-existing skill config (config.json). Hard-reject on scan
|
|
18
|
+
* failure (pre-existing behaviour, no change in Phase 1).
|
|
19
|
+
* structured - Execution-environment files (.mcp.json, .claude/settings*).
|
|
20
|
+
* Hard-reject on scan failure, uniform across ALL trust tiers.
|
|
21
|
+
* package-json - Only lifecycle-hook script VALUES are scanned, not the whole
|
|
22
|
+
* file. Hard-reject if that extracted text fails. A package.json
|
|
23
|
+
* with only test/lint scripts or dep ranges is never rejected.
|
|
24
|
+
*/
|
|
25
|
+
export type BundledFileClass = 'doc' | 'config' | 'structured' | 'package-json';
|
|
26
|
+
/**
|
|
27
|
+
* Widened fixed-name file list for the install corpus (SMI-5422 Phase 1).
|
|
28
|
+
*
|
|
29
|
+
* The install path fetches each file by exact path via fetchFromGitHub — there
|
|
30
|
+
* is NO directory globbing. Files like scripts/*.sh are OUT of scope for Phase 1
|
|
31
|
+
* and are noted as a Phase 3 follow-up (directory-glob scanning).
|
|
32
|
+
*/
|
|
33
|
+
export declare const BUNDLED_SCAN_FILES: readonly ["README.md", "examples.md", "config.json", ".claude/settings.json", ".claude/settings.local.json", ".mcp.json", "package.json"];
|
|
34
|
+
/** Union type of every file name in the bundled scan corpus. */
|
|
35
|
+
export type BundledScanFile = (typeof BUNDLED_SCAN_FILES)[number];
|
|
36
|
+
/**
|
|
37
|
+
* Return the scan-policy class for a bundled optional file.
|
|
38
|
+
*
|
|
39
|
+
* Unknown names fall back to 'structured' (hard-reject) so that a file added
|
|
40
|
+
* to BUNDLED_SCAN_FILES without a corresponding FILE_CLASS_MAP entry defaults
|
|
41
|
+
* to the conservative posture rather than silently skipped.
|
|
42
|
+
*/
|
|
43
|
+
export declare function classifyBundledFile(filename: string): BundledFileClass;
|
|
44
|
+
/**
|
|
45
|
+
* Extract lifecycle-hook script values from raw package.json content.
|
|
46
|
+
*
|
|
47
|
+
* Returns a newline-joined string of all present lifecycle hook values, or ''
|
|
48
|
+
* when the file is malformed JSON or contains no lifecycle keys at all.
|
|
49
|
+
*
|
|
50
|
+
* An empty return means "no install-time execution risk" — the caller should
|
|
51
|
+
* write the file without scanning it. A package.json with only `scripts.test`,
|
|
52
|
+
* `scripts.lint`, dependency version ranges, or metadata fields will always
|
|
53
|
+
* produce '' here and is NEVER rejected.
|
|
54
|
+
*
|
|
55
|
+
* On JSON parse error: returns '' (silent skip). It is not the scanner's job
|
|
56
|
+
* to reject a malformed package.json — the npm toolchain handles that. A
|
|
57
|
+
* corrupt or non-JSON file simply contributes no risky text to scan.
|
|
58
|
+
*/
|
|
59
|
+
export declare function extractPackageJsonLifecycleScripts(content: string): string;
|
|
60
|
+
/**
|
|
61
|
+
* SMI-5422 Phase 1: should a hard-reject-class file (config/structured/package-
|
|
62
|
+
* json) reject given its scan report?
|
|
63
|
+
*
|
|
64
|
+
* Rejects when the scan fails the standard gate (a high/critical finding OR
|
|
65
|
+
* score ≥ threshold) OR contains ANY `code_execution` / `obfuscated_directive`
|
|
66
|
+
* finding regardless of severity. Those two top-tier categories mean "remote
|
|
67
|
+
* fetch-and-execute" / "concealed directive". A lone such match scores only
|
|
68
|
+
* MEDIUM under the scanner's deliberate SKILL.md prose-FP-avoidance model — but
|
|
69
|
+
* inside a config / hook / lifecycle file there is no documentation-context
|
|
70
|
+
* excuse, so it must reject (this is the CVE-2025-59536 hook-execution threat).
|
|
71
|
+
*
|
|
72
|
+
* FP-safe: legit build commands (tsc, vitest, node-gyp rebuild, `rm -rf` of a
|
|
73
|
+
* cache dir) and the canonical `.mcp.json` shape (`{command:"node",args:[…]}`)
|
|
74
|
+
* do NOT match `code_execution` — it requires curl|wget piped to a shell with a
|
|
75
|
+
* real URL/domain target — so normal lifecycle scripts and server specs pass.
|
|
76
|
+
*
|
|
77
|
+
* KNOWN DETECTION GAPS (inherited from the scanner patterns, tracked in SMI-5424
|
|
78
|
+
* — these are scanner-pattern + edge-twin changes, out of scope for Phase 1's
|
|
79
|
+
* install plumbing): `&&`/`;`-chained or redirect-then-exec download+execute
|
|
80
|
+
* (`curl URL -o /tmp/s && bash /tmp/s`), `npx --yes <pkg>`, `fish`/`bun`/`deno`
|
|
81
|
+
* interpreter sinks, and JSON `\uXXXX`-escaped commands inside raw-scanned
|
|
82
|
+
* STRUCTURED files (.mcp.json / .claude/settings.json are scanned as raw text;
|
|
83
|
+
* package.json lifecycle values are JSON-parsed first, so they are escape-safe).
|
|
84
|
+
* Phase 1 catches what the scanner patterns detect across MORE files; it does
|
|
85
|
+
* not change the patterns.
|
|
86
|
+
*
|
|
87
|
+
* Typed structurally (not against ScanReport) to keep this policy module free of
|
|
88
|
+
* the scanner type graph.
|
|
89
|
+
*/
|
|
90
|
+
export declare function isRejectableScan(report: {
|
|
91
|
+
passed: boolean;
|
|
92
|
+
findings: ReadonlyArray<{
|
|
93
|
+
type: string;
|
|
94
|
+
}>;
|
|
95
|
+
}): boolean;
|
|
96
|
+
//# sourceMappingURL=skill-installation.policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-installation.policy.d.ts","sourceRoot":"","sources":["../../../src/services/skill-installation.policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,GAAG,cAAc,CAAA;AAE/E;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,2IAQrB,CAAA;AAEV,gEAAgE;AAChE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAA;AAoBjE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAEtE;AAqBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAoB1E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC1C,GAAG,OAAO,CAKV"}
|