memory-journal-mcp 6.1.2 → 6.2.1
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/README.md +44 -28
- package/dist/{chunk-X4SWFATC.js → chunk-BI4ZNSKA.js} +38 -24
- package/dist/{chunk-HCEWINSB.js → chunk-N6EBIDN7.js} +99 -102
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/tools-WPRY5MJ6.js +2 -0
- package/package.json +10 -1
- package/skills/github-commander/SKILL.md +151 -0
- package/skills/github-commander/config/project-config.example.md +125 -0
- package/skills/github-commander/workflows/code-quality-audit.md +80 -0
- package/skills/github-commander/workflows/full-audit.md +134 -0
- package/skills/github-commander/workflows/issue-triage.md +239 -0
- package/skills/github-commander/workflows/milestone-sprint.md +81 -0
- package/skills/github-commander/workflows/perf-audit.md +142 -0
- package/skills/github-commander/workflows/pr-review.md +123 -0
- package/skills/github-commander/workflows/security-audit.md +170 -0
- package/skills/github-commander/workflows/update-deps.md +109 -0
- package/.dockerignore +0 -139
- package/.gitattributes +0 -20
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -95
- package/.github/ISSUE_TEMPLATE/config.yml +0 -11
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -110
- package/.github/ISSUE_TEMPLATE/question.md +0 -78
- package/.github/aw/actions-lock.json +0 -14
- package/.github/copilot-instructions.md +0 -122
- package/.github/dependabot.yml +0 -93
- package/.github/pull_request_template.md +0 -135
- package/.github/workflows/README.md +0 -133
- package/.github/workflows/agentics-maintenance.yml +0 -141
- package/.github/workflows/auto-release.yml +0 -68
- package/.github/workflows/ci-health-monitor.lock.yml +0 -1121
- package/.github/workflows/ci-health-monitor.md +0 -87
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-auto-merge.yml +0 -42
- package/.github/workflows/dependency-maintenance.lock.yml +0 -1182
- package/.github/workflows/dependency-maintenance.md +0 -147
- package/.github/workflows/docker-publish.yml +0 -254
- package/.github/workflows/docs-drift-detector.lock.yml +0 -1142
- package/.github/workflows/docs-drift-detector.md +0 -115
- package/.github/workflows/lint-and-test.yml +0 -60
- package/.github/workflows/publish-npm.yml +0 -85
- package/.github/workflows/secrets-scanning.yml +0 -32
- package/.github/workflows/security-update.yml +0 -127
- package/.gitleaks.toml +0 -9
- package/.prettierignore +0 -21
- package/.prettierrc +0 -33
- package/.scout-ignore +0 -12
- package/.trivyignore +0 -21
- package/CHANGELOG.md +0 -1814
- package/CODE_OF_CONDUCT.md +0 -133
- package/CONTRIBUTING.md +0 -263
- package/DOCKER_README.md +0 -331
- package/Dockerfile +0 -128
- package/SECURITY.md +0 -227
- package/UNRELEASED.md +0 -1
- package/dist/tools-T4U5A3X4.js +0 -2
- package/docker-compose.yml +0 -71
- package/docs/README.md +0 -18
- package/docs/agentic-journal-synergy.md +0 -175
- package/docs/copilot-setup.md +0 -72
- package/eslint.config.js +0 -110
- package/mcp-config-example.json +0 -21
- package/playwright.config.ts +0 -35
- package/releases/v2.1.0.md +0 -220
- package/releases/v2.2.0.md +0 -168
- package/releases/v3.0.0.md +0 -237
- package/releases/v3.1.0.md +0 -104
- package/releases/v3.1.1.md +0 -42
- package/releases/v3.1.2.md +0 -40
- package/releases/v3.1.3.md +0 -64
- package/releases/v3.1.4.md +0 -32
- package/releases/v3.1.5.md +0 -44
- package/releases/v4.0.0.md +0 -71
- package/releases/v4.1.0.md +0 -88
- package/releases/v4.2.0.md +0 -90
- package/releases/v4.3.0.md +0 -92
- package/releases/v4.3.1.md +0 -69
- package/releases/v4.4.0.md +0 -120
- package/releases/v4.4.1.md +0 -33
- package/releases/v4.4.2.md +0 -31
- package/releases/v4.5.0.md +0 -116
- package/releases/v5.0.0.md +0 -105
- package/releases/v5.0.1.md +0 -25
- package/releases/v5.1.0.md +0 -83
- package/releases/v5.1.1.md +0 -10
- package/releases/v6.0.0.md +0 -48
- package/releases/v6.0.1.md +0 -36
- package/releases/v6.1.0.md +0 -68
- package/releases/v6.1.1.md +0 -30
- package/releases/v6.1.2.md +0 -23
- package/scripts/generate-server-instructions.ts +0 -306
- package/scripts/server-instructions-function-body.ts +0 -107
- package/scripts/server-instructions-gotchas.ts +0 -45
- package/server.json +0 -42
- package/social-preview.png +0 -0
- package/src/auth/auth-context.ts +0 -78
- package/src/auth/authorization-server-discovery.ts +0 -263
- package/src/auth/errors.ts +0 -215
- package/src/auth/index.ts +0 -58
- package/src/auth/middleware.ts +0 -392
- package/src/auth/oauth-resource-server.ts +0 -170
- package/src/auth/scope-map.ts +0 -46
- package/src/auth/scopes.ts +0 -256
- package/src/auth/token-validator.ts +0 -293
- package/src/auth/transport-agnostic.ts +0 -164
- package/src/auth/types.ts +0 -372
- package/src/cli.ts +0 -279
- package/src/codemode/api-constants.ts +0 -263
- package/src/codemode/api.ts +0 -302
- package/src/codemode/auto-return.ts +0 -65
- package/src/codemode/index.ts +0 -47
- package/src/codemode/sandbox-factory.ts +0 -144
- package/src/codemode/sandbox.ts +0 -220
- package/src/codemode/security.ts +0 -155
- package/src/codemode/types.ts +0 -228
- package/src/codemode/worker-sandbox.ts +0 -277
- package/src/codemode/worker-script.ts +0 -239
- package/src/constants/icons.ts +0 -183
- package/src/constants/server-instructions.md +0 -166
- package/src/constants/server-instructions.ts +0 -514
- package/src/database/adapter-factory.ts +0 -16
- package/src/database/core/entry-columns.ts +0 -10
- package/src/database/core/interfaces.ts +0 -188
- package/src/database/core/schema.ts +0 -152
- package/src/database/sqlite-adapter/backup.ts +0 -167
- package/src/database/sqlite-adapter/entries/crud.ts +0 -233
- package/src/database/sqlite-adapter/entries/importance.ts +0 -76
- package/src/database/sqlite-adapter/entries/index.ts +0 -142
- package/src/database/sqlite-adapter/entries/search.ts +0 -294
- package/src/database/sqlite-adapter/entries/shared.ts +0 -102
- package/src/database/sqlite-adapter/entries/statistics.ts +0 -162
- package/src/database/sqlite-adapter/index.ts +0 -265
- package/src/database/sqlite-adapter/native-connection.ts +0 -301
- package/src/database/sqlite-adapter/relationships.ts +0 -70
- package/src/database/sqlite-adapter/tags.ts +0 -182
- package/src/filtering/tool-filter.ts +0 -312
- package/src/github/github-integration/client.ts +0 -114
- package/src/github/github-integration/index.ts +0 -297
- package/src/github/github-integration/insights.ts +0 -155
- package/src/github/github-integration/issues.ts +0 -213
- package/src/github/github-integration/milestones.ts +0 -262
- package/src/github/github-integration/projects.ts +0 -414
- package/src/github/github-integration/pull-requests.ts +0 -235
- package/src/github/github-integration/repository.ts +0 -110
- package/src/github/github-integration/types.ts +0 -43
- package/src/handlers/prompts/github.ts +0 -210
- package/src/handlers/prompts/index.ts +0 -97
- package/src/handlers/prompts/workflow.ts +0 -361
- package/src/handlers/resources/core/briefing/context-section.ts +0 -182
- package/src/handlers/resources/core/briefing/github-section.ts +0 -354
- package/src/handlers/resources/core/briefing/index.ts +0 -106
- package/src/handlers/resources/core/briefing/user-message.ts +0 -114
- package/src/handlers/resources/core/health.ts +0 -75
- package/src/handlers/resources/core/index.ts +0 -31
- package/src/handlers/resources/core/instructions.ts +0 -45
- package/src/handlers/resources/core/utilities.ts +0 -310
- package/src/handlers/resources/github.ts +0 -340
- package/src/handlers/resources/graph.ts +0 -218
- package/src/handlers/resources/help.ts +0 -410
- package/src/handlers/resources/index.ts +0 -143
- package/src/handlers/resources/shared.ts +0 -219
- package/src/handlers/resources/team.ts +0 -134
- package/src/handlers/resources/templates.ts +0 -334
- package/src/handlers/tools/admin.ts +0 -351
- package/src/handlers/tools/analytics.ts +0 -346
- package/src/handlers/tools/backup.ts +0 -272
- package/src/handlers/tools/codemode.ts +0 -188
- package/src/handlers/tools/core.ts +0 -359
- package/src/handlers/tools/error-fields-mixin.ts +0 -10
- package/src/handlers/tools/export.ts +0 -150
- package/src/handlers/tools/github/copilot-tools.ts +0 -72
- package/src/handlers/tools/github/helpers.ts +0 -125
- package/src/handlers/tools/github/insights-tools.ts +0 -112
- package/src/handlers/tools/github/issue-tools.ts +0 -442
- package/src/handlers/tools/github/kanban-tools.ts +0 -153
- package/src/handlers/tools/github/milestone-tools.ts +0 -371
- package/src/handlers/tools/github/mutation-tools.ts +0 -17
- package/src/handlers/tools/github/read-tools.ts +0 -302
- package/src/handlers/tools/github/schemas.ts +0 -435
- package/src/handlers/tools/github.ts +0 -39
- package/src/handlers/tools/index.ts +0 -255
- package/src/handlers/tools/relationships.ts +0 -390
- package/src/handlers/tools/schemas.ts +0 -165
- package/src/handlers/tools/search.ts +0 -448
- package/src/handlers/tools/team/admin-tools.ts +0 -164
- package/src/handlers/tools/team/analytics-tools.ts +0 -233
- package/src/handlers/tools/team/backup-tools.ts +0 -83
- package/src/handlers/tools/team/core-tools.ts +0 -197
- package/src/handlers/tools/team/export-tools.ts +0 -130
- package/src/handlers/tools/team/helpers.ts +0 -66
- package/src/handlers/tools/team/index.ts +0 -45
- package/src/handlers/tools/team/relationship-tools.ts +0 -219
- package/src/handlers/tools/team/schemas.ts +0 -558
- package/src/handlers/tools/team/search-tools.ts +0 -145
- package/src/handlers/tools/team/vector-tools.ts +0 -261
- package/src/index.ts +0 -57
- package/src/server/mcp-server.ts +0 -446
- package/src/server/registration.ts +0 -141
- package/src/server/scheduler.ts +0 -283
- package/src/transports/http/handlers.ts +0 -78
- package/src/transports/http/index.ts +0 -8
- package/src/transports/http/security.ts +0 -147
- package/src/transports/http/server/index.ts +0 -397
- package/src/transports/http/server/legacy-sse.ts +0 -87
- package/src/transports/http/server/stateful.ts +0 -222
- package/src/transports/http/server/stateless.ts +0 -42
- package/src/transports/http/types.ts +0 -132
- package/src/types/entities.ts +0 -145
- package/src/types/error-types.ts +0 -92
- package/src/types/errors.ts +0 -200
- package/src/types/filtering.ts +0 -55
- package/src/types/github.ts +0 -216
- package/src/types/index.ts +0 -348
- package/src/utils/error-helpers.ts +0 -78
- package/src/utils/errors/error-response-fields.ts +0 -29
- package/src/utils/errors/suggestions.ts +0 -94
- package/src/utils/github-helpers.ts +0 -33
- package/src/utils/logger.ts +0 -107
- package/src/utils/mcp-logger.ts +0 -155
- package/src/utils/progress-utils.ts +0 -100
- package/src/utils/query-helpers.ts +0 -78
- package/src/utils/resource-annotations.ts +0 -75
- package/src/utils/security-utils.ts +0 -198
- package/src/utils/vector-index-helpers.ts +0 -24
- package/src/vector/vector-search-manager.ts +0 -409
- package/src/version.ts +0 -15
- package/test-server/README.md +0 -193
- package/test-server/code-map.md +0 -399
- package/test-server/test-agent-experience.md +0 -213
- package/test-server/test-filter-instructions.mjs +0 -295
- package/test-server/test-instruction-levels.mjs +0 -102
- package/test-server/test-preflight.md +0 -55
- package/test-server/test-prompts.mjs +0 -185
- package/test-server/test-scheduler.mjs +0 -174
- package/test-server/test-tool-annotations.mjs +0 -115
- package/test-server/test-tools-codemode.md +0 -632
- package/test-server/test-tools-codemode2.md +0 -1218
- package/test-server/test-tools-team.md +0 -215
- package/test-server/test-tools.md +0 -429
- package/test-server/test-tools2.md +0 -361
- package/test-server/test-tools3.md +0 -396
- package/test-server/tool-reference.md +0 -231
- package/tests/README.md +0 -54
- package/tests/auth/auth-context.test.ts +0 -162
- package/tests/auth/authorization-server-discovery.test.ts +0 -265
- package/tests/auth/errors.test.ts +0 -170
- package/tests/auth/middleware.test.ts +0 -585
- package/tests/auth/oauth-resource-server.test.ts +0 -173
- package/tests/auth/scope-map.test.ts +0 -66
- package/tests/auth/scopes.test.ts +0 -347
- package/tests/auth/token-validator.test.ts +0 -271
- package/tests/codemode/api.test.ts +0 -396
- package/tests/codemode/auto-return.test.ts +0 -167
- package/tests/codemode/codemode-tool-handlers.test.ts +0 -197
- package/tests/codemode/sandbox-factory.test.ts +0 -152
- package/tests/codemode/sandbox.test.ts +0 -190
- package/tests/codemode/security.test.ts +0 -242
- package/tests/codemode/worker-sandbox.test.ts +0 -106
- package/tests/constants/icons.test.ts +0 -101
- package/tests/constants/server-instructions.test.ts +0 -514
- package/tests/database/crud-workflow-branches.test.ts +0 -418
- package/tests/database/database-branches.test.ts +0 -132
- package/tests/database/entries-auth-branches.test.ts +0 -390
- package/tests/database/native-connection.test.ts +0 -249
- package/tests/database/shared-helpers.test.ts +0 -103
- package/tests/database/sqlite-adapter.bench.ts +0 -63
- package/tests/database/sqlite-adapter.test.ts +0 -690
- package/tests/database/tags.test.ts +0 -134
- package/tests/e2e/README.md +0 -39
- package/tests/e2e/auth.spec.ts +0 -106
- package/tests/e2e/codemode-abuse.spec.ts +0 -75
- package/tests/e2e/health.spec.ts +0 -63
- package/tests/e2e/helpers.ts +0 -139
- package/tests/e2e/oauth-discovery.spec.ts +0 -102
- package/tests/e2e/oauth-scopes.spec.ts +0 -222
- package/tests/e2e/payloads-admin.spec.ts +0 -76
- package/tests/e2e/payloads-analytics.spec.ts +0 -37
- package/tests/e2e/payloads-backup-restore.spec.ts +0 -102
- package/tests/e2e/payloads-backup.spec.ts +0 -44
- package/tests/e2e/payloads-codemode-api.spec.ts +0 -131
- package/tests/e2e/payloads-codemode-readonly.spec.ts +0 -116
- package/tests/e2e/payloads-codemode.spec.ts +0 -116
- package/tests/e2e/payloads-core.spec.ts +0 -82
- package/tests/e2e/payloads-error-contracts.spec.ts +0 -159
- package/tests/e2e/payloads-export.spec.ts +0 -46
- package/tests/e2e/payloads-github-degradation.spec.ts +0 -73
- package/tests/e2e/payloads-github.spec.ts +0 -176
- package/tests/e2e/payloads-relationships.spec.ts +0 -56
- package/tests/e2e/payloads-search.spec.ts +0 -64
- package/tests/e2e/payloads-team-happy.spec.ts +0 -231
- package/tests/e2e/payloads-team.spec.ts +0 -174
- package/tests/e2e/prompts-expanded.spec.ts +0 -137
- package/tests/e2e/prompts.spec.ts +0 -62
- package/tests/e2e/protocols.spec.ts +0 -134
- package/tests/e2e/rate-limiting.spec.ts +0 -291
- package/tests/e2e/resources-briefing-env.spec.ts +0 -106
- package/tests/e2e/resources-complete.spec.ts +0 -180
- package/tests/e2e/resources-expanded.spec.ts +0 -83
- package/tests/e2e/resources-instructions-levels.spec.ts +0 -145
- package/tests/e2e/resources-templates.spec.ts +0 -123
- package/tests/e2e/resources.spec.ts +0 -103
- package/tests/e2e/scheduler.spec.ts +0 -79
- package/tests/e2e/security.spec.ts +0 -112
- package/tests/e2e/session-advanced.spec.ts +0 -152
- package/tests/e2e/sessions.spec.ts +0 -95
- package/tests/e2e/stateless.spec.ts +0 -79
- package/tests/e2e/streaming.spec.ts +0 -176
- package/tests/e2e/tool-filtering-presets.spec.ts +0 -192
- package/tests/e2e/tool-filtering.spec.ts +0 -77
- package/tests/e2e/tools.spec.ts +0 -111
- package/tests/filtering/tool-filter.test.ts +0 -314
- package/tests/github/client-issues-errors.test.ts +0 -433
- package/tests/github/github-integration-branches.test.ts +0 -490
- package/tests/github/github-integration.test.ts +0 -1015
- package/tests/github/github-managers-branches.test.ts +0 -907
- package/tests/github/pull-requests.test.ts +0 -334
- package/tests/handlers/analytics-branches.test.ts +0 -222
- package/tests/handlers/backup-branches.test.ts +0 -270
- package/tests/handlers/briefing-context-section.test.ts +0 -388
- package/tests/handlers/briefing-github-section.test.ts +0 -392
- package/tests/handlers/briefing-user-message.test.ts +0 -405
- package/tests/handlers/codemode-tools.test.ts +0 -85
- package/tests/handlers/copilot-tools.test.ts +0 -126
- package/tests/handlers/error-path-coverage.test.ts +0 -324
- package/tests/handlers/export-tools.test.ts +0 -203
- package/tests/handlers/github-resource-handlers.test.ts +0 -929
- package/tests/handlers/github-tool-handlers.test.ts +0 -1452
- package/tests/handlers/handler-error-branches.test.ts +0 -346
- package/tests/handlers/help-resource.test.ts +0 -92
- package/tests/handlers/prompt-handler-coverage.test.ts +0 -108
- package/tests/handlers/prompt-handlers.test.ts +0 -131
- package/tests/handlers/resource-handler-coverage.test.ts +0 -281
- package/tests/handlers/resource-handlers.test.ts +0 -357
- package/tests/handlers/resource-prompt-branches.test.ts +0 -495
- package/tests/handlers/search-tool-handlers.test.ts +0 -379
- package/tests/handlers/targeted-gap-closure.test.ts +0 -387
- package/tests/handlers/team-admin.test.ts +0 -291
- package/tests/handlers/team-analytics.test.ts +0 -220
- package/tests/handlers/team-core.test.ts +0 -148
- package/tests/handlers/team-data.test.ts +0 -198
- package/tests/handlers/team-relationships.test.ts +0 -271
- package/tests/handlers/team-resource-handlers.test.ts +0 -161
- package/tests/handlers/team-search.test.ts +0 -134
- package/tests/handlers/team-tool-handlers.test.ts +0 -301
- package/tests/handlers/team-vector.test.ts +0 -213
- package/tests/handlers/template-github-branches.test.ts +0 -676
- package/tests/handlers/tool-annotations.test.ts +0 -90
- package/tests/handlers/tool-handler-coverage.test.ts +0 -514
- package/tests/handlers/tool-handlers.test.ts +0 -510
- package/tests/handlers/tool-output-schemas.test.ts +0 -116
- package/tests/handlers/vector-tool-handlers.test.ts +0 -238
- package/tests/security/sql-injection.test.ts +0 -284
- package/tests/server/mcp-server.bench.ts +0 -55
- package/tests/server/mcp-server.test.ts +0 -1326
- package/tests/server/scheduler.test.ts +0 -400
- package/tests/transports/http-legacy-sse.test.ts +0 -275
- package/tests/transports/http-security.test.ts +0 -322
- package/tests/transports/http-stateful.test.ts +0 -487
- package/tests/transports/http-transport-server.test.ts +0 -301
- package/tests/transports/http-transport.test.ts +0 -771
- package/tests/utils/github-helpers.test.ts +0 -58
- package/tests/utils/logger.test.ts +0 -180
- package/tests/utils/mcp-logger.test.ts +0 -211
- package/tests/utils/progress-utils.test.ts +0 -156
- package/tests/utils/query-helpers.test.ts +0 -80
- package/tests/utils/security-utils.test.ts +0 -82
- package/tests/vector/vector-search-branches.test.ts +0 -111
- package/tests/vector/vector-search-manager.test.ts +0 -375
- package/tests/vector/vector-search.bench.ts +0 -48
- package/tsconfig.json +0 -42
- package/tsup.config.ts +0 -19
- package/vitest.config.ts +0 -25
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Code Mode Sandbox Tests (VM-based)
|
|
3
|
-
*
|
|
4
|
-
* Tests for CodeModeSandbox and SandboxPool non-execution paths.
|
|
5
|
-
* Note: Actual code execution is tested via Playwright E2E tests because
|
|
6
|
-
* vm.createContext async IIFEs don't resolve Promises correctly in vitest's
|
|
7
|
-
* module environment (the Promise microtask queue in the VM context doesn't
|
|
8
|
-
* interop with the host event loop).
|
|
9
|
-
*
|
|
10
|
-
* Covers:
|
|
11
|
-
* - Sandbox construction and options
|
|
12
|
-
* - Compilation cache (LRU)
|
|
13
|
-
* - Pool construction and configuration
|
|
14
|
-
* - Pool concurrency tracking
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
|
|
18
|
-
import * as vm from 'node:vm'
|
|
19
|
-
import { CodeModeSandbox, SandboxPool } from '../../src/codemode/index.js'
|
|
20
|
-
|
|
21
|
-
describe('CodeModeSandbox', () => {
|
|
22
|
-
let sandbox: CodeModeSandbox
|
|
23
|
-
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
sandbox = new CodeModeSandbox()
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
// =========================================================================
|
|
29
|
-
// Construction
|
|
30
|
-
// =========================================================================
|
|
31
|
-
|
|
32
|
-
describe('construction', () => {
|
|
33
|
-
it('should create with default options', () => {
|
|
34
|
-
expect(sandbox).toBeDefined()
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('should accept custom options', () => {
|
|
38
|
-
const custom = new CodeModeSandbox({
|
|
39
|
-
timeoutMs: 5000,
|
|
40
|
-
memoryLimitMb: 64,
|
|
41
|
-
cpuLimitMs: 5000,
|
|
42
|
-
})
|
|
43
|
-
expect(custom).toBeDefined()
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
// =========================================================================
|
|
48
|
-
// Compilation Cache
|
|
49
|
-
// =========================================================================
|
|
50
|
-
|
|
51
|
-
describe('cache', () => {
|
|
52
|
-
it('should start with empty cache', () => {
|
|
53
|
-
expect(sandbox.getCacheSize()).toBe(0)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should clear cache without errors', () => {
|
|
57
|
-
sandbox.clearCache()
|
|
58
|
-
expect(sandbox.getCacheSize()).toBe(0)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('should report cache size as a number', () => {
|
|
62
|
-
expect(typeof sandbox.getCacheSize()).toBe('number')
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
// =========================================================================
|
|
67
|
-
// Execution
|
|
68
|
-
// =========================================================================
|
|
69
|
-
|
|
70
|
-
describe('execute', () => {
|
|
71
|
-
let runInContextSpy: any
|
|
72
|
-
|
|
73
|
-
beforeEach(() => {
|
|
74
|
-
runInContextSpy = vi
|
|
75
|
-
.spyOn(vm.Script.prototype, 'runInContext')
|
|
76
|
-
.mockReturnValue(Promise.resolve(42) as any)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
afterEach(() => {
|
|
80
|
-
if (runInContextSpy) runInContextSpy.mockRestore()
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('should execute code returning a valid result', async () => {
|
|
84
|
-
const result = await sandbox.execute('return 42', {})
|
|
85
|
-
expect(result.success).toBe(true)
|
|
86
|
-
if (result.success) {
|
|
87
|
-
expect(result.result).toBe(42)
|
|
88
|
-
expect(result.metrics).toBeDefined()
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('should catch errors thrown during execution', async () => {
|
|
93
|
-
runInContextSpy.mockImplementation(() => {
|
|
94
|
-
throw new Error('VM crash')
|
|
95
|
-
})
|
|
96
|
-
const result = await sandbox.execute('throw new Error("Crash")', {})
|
|
97
|
-
expect(result.success).toBe(false)
|
|
98
|
-
if (!result.success) {
|
|
99
|
-
expect(result.error).toBe('VM crash')
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('should provide wrapped console methods', async () => {
|
|
104
|
-
// This will execute against the mock, but the console wrappers are created
|
|
105
|
-
// within the 'execute' setup before runInContext is called.
|
|
106
|
-
const result = await sandbox.execute(
|
|
107
|
-
`
|
|
108
|
-
console.log("log entry");
|
|
109
|
-
console.warn("warn entry");
|
|
110
|
-
console.error("error entry");
|
|
111
|
-
return true;
|
|
112
|
-
`,
|
|
113
|
-
{}
|
|
114
|
-
)
|
|
115
|
-
expect(result.success).toBe(true)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('should evict oldest entries when cache exceeds capacity', async () => {
|
|
119
|
-
// Max capacity of ScriptCache is 50. Generate 55 unique scripts.
|
|
120
|
-
for (let i = 0; i < 55; i++) {
|
|
121
|
-
await sandbox.execute(`return ${i}`, {})
|
|
122
|
-
}
|
|
123
|
-
expect(sandbox.getCacheSize()).toBe(50)
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// =============================================================================
|
|
129
|
-
// SandboxPool
|
|
130
|
-
// =============================================================================
|
|
131
|
-
|
|
132
|
-
describe('SandboxPool', () => {
|
|
133
|
-
it('should create with default options', () => {
|
|
134
|
-
const pool = new SandboxPool()
|
|
135
|
-
expect(pool).toBeDefined()
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('should create with custom options', () => {
|
|
139
|
-
const pool = new SandboxPool(
|
|
140
|
-
{ timeoutMs: 5000 },
|
|
141
|
-
{ maxInstances: 5, minInstances: 1, idleTimeoutMs: 30000 }
|
|
142
|
-
)
|
|
143
|
-
expect(pool).toBeDefined()
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('should track active count starting at zero', () => {
|
|
147
|
-
const pool = new SandboxPool()
|
|
148
|
-
expect(pool.getActiveCount()).toBe(0)
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should have a unique pool ID', () => {
|
|
152
|
-
const pool1 = new SandboxPool()
|
|
153
|
-
const pool2 = new SandboxPool()
|
|
154
|
-
expect(pool1.poolId).toBeDefined()
|
|
155
|
-
expect(pool2.poolId).toBeDefined()
|
|
156
|
-
expect(pool1.poolId).not.toBe(pool2.poolId)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('should generate valid UUID pool IDs', () => {
|
|
160
|
-
const pool = new SandboxPool()
|
|
161
|
-
// UUID v4 format: 8-4-4-4-12 hex characters
|
|
162
|
-
expect(pool.poolId).toMatch(
|
|
163
|
-
/^[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}$/i
|
|
164
|
-
)
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('should refuse execution if max instances exceeded', async () => {
|
|
168
|
-
const pool = new SandboxPool({}, { maxInstances: 0 })
|
|
169
|
-
const result = await pool.execute('return 1', {})
|
|
170
|
-
expect(result.success).toBe(false)
|
|
171
|
-
expect(result.error).toContain('exhausted')
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
it('should decrement active count on execution completion', async () => {
|
|
175
|
-
const pool = new SandboxPool({}, { maxInstances: 5 })
|
|
176
|
-
expect(pool.getActiveCount()).toBe(0)
|
|
177
|
-
|
|
178
|
-
// Mock the actual execution to avoid vm hanging in vitest
|
|
179
|
-
const executeSpy = vi.spyOn(CodeModeSandbox.prototype, 'execute').mockResolvedValue({
|
|
180
|
-
success: true,
|
|
181
|
-
result: 1,
|
|
182
|
-
metrics: { durationMs: 1, memoryBytes: 0, peakMemoryBytes: 0 },
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
await pool.execute('return 1', {})
|
|
186
|
-
expect(pool.getActiveCount()).toBe(0)
|
|
187
|
-
|
|
188
|
-
executeSpy.mockRestore()
|
|
189
|
-
})
|
|
190
|
-
})
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Code Mode Security Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for CodeModeSecurityManager:
|
|
5
|
-
* - Code validation (length, empty, blocked patterns)
|
|
6
|
-
* - Rate limiting (allow, deny, window reset)
|
|
7
|
-
* - Result size validation (pass, oversized, non-serializable)
|
|
8
|
-
* - Config accessors
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { describe, it, expect, beforeEach } from 'vitest'
|
|
12
|
-
import { CodeModeSecurityManager, DEFAULT_SECURITY_CONFIG } from '../../src/codemode/index.js'
|
|
13
|
-
|
|
14
|
-
describe('CodeModeSecurityManager', () => {
|
|
15
|
-
let security: CodeModeSecurityManager
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
security = new CodeModeSecurityManager()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
// =========================================================================
|
|
22
|
-
// Code Validation
|
|
23
|
-
// =========================================================================
|
|
24
|
-
|
|
25
|
-
describe('validateCode', () => {
|
|
26
|
-
it('should accept valid code', () => {
|
|
27
|
-
const result = security.validateCode('const x = 1 + 2; return x;')
|
|
28
|
-
expect(result.valid).toBe(true)
|
|
29
|
-
expect(result.errors).toHaveLength(0)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('should reject empty code', () => {
|
|
33
|
-
const result = security.validateCode(' ')
|
|
34
|
-
expect(result.valid).toBe(false)
|
|
35
|
-
expect(result.errors).toContain('Code cannot be empty')
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('should reject code exceeding max length', () => {
|
|
39
|
-
const mgr = new CodeModeSecurityManager({ maxCodeLength: 100 })
|
|
40
|
-
const longCode = 'a'.repeat(200)
|
|
41
|
-
const result = mgr.validateCode(longCode)
|
|
42
|
-
expect(result.valid).toBe(false)
|
|
43
|
-
expect(result.errors[0]).toContain('maximum length')
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('should reject require() calls', () => {
|
|
47
|
-
const result = security.validateCode('const fs = require("fs")')
|
|
48
|
-
expect(result.valid).toBe(false)
|
|
49
|
-
expect(result.errors.some((e) => e.includes('blocked pattern'))).toBe(true)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('should reject dynamic import()', () => {
|
|
53
|
-
const result = security.validateCode('const m = await import("os")')
|
|
54
|
-
expect(result.valid).toBe(false)
|
|
55
|
-
expect(result.errors.some((e) => e.includes('blocked pattern'))).toBe(true)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('should reject process access', () => {
|
|
59
|
-
const result = security.validateCode('process.exit(1)')
|
|
60
|
-
expect(result.valid).toBe(false)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('should reject global access', () => {
|
|
64
|
-
const result = security.validateCode('global.foo = "bar"')
|
|
65
|
-
expect(result.valid).toBe(false)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('should reject globalThis access', () => {
|
|
69
|
-
const result = security.validateCode('globalThis.foo = "bar"')
|
|
70
|
-
expect(result.valid).toBe(false)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('should reject eval()', () => {
|
|
74
|
-
const result = security.validateCode('eval("1+1")')
|
|
75
|
-
expect(result.valid).toBe(false)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('should reject Function constructor', () => {
|
|
79
|
-
const result = security.validateCode('new Function ("return 1")')
|
|
80
|
-
expect(result.valid).toBe(false)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('should reject __proto__ access', () => {
|
|
84
|
-
const result = security.validateCode('const x = {}.__proto__')
|
|
85
|
-
expect(result.valid).toBe(false)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should reject constructor.constructor chaining', () => {
|
|
89
|
-
const result = security.validateCode('x.constructor.constructor("alert")')
|
|
90
|
-
expect(result.valid).toBe(false)
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should reject child_process', () => {
|
|
94
|
-
const result = security.validateCode('const cp = child_process.exec("ls")')
|
|
95
|
-
expect(result.valid).toBe(false)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should reject fs access', () => {
|
|
99
|
-
const result = security.validateCode('fs.readFileSync("/etc/passwd")')
|
|
100
|
-
expect(result.valid).toBe(false)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
it('should reject net access', () => {
|
|
104
|
-
const result = security.validateCode('net.createServer()')
|
|
105
|
-
expect(result.valid).toBe(false)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('should reject http access', () => {
|
|
109
|
-
const result = security.validateCode('http.createServer()')
|
|
110
|
-
expect(result.valid).toBe(false)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('should reject https access', () => {
|
|
114
|
-
const result = security.validateCode('https.get("http://evil.com")')
|
|
115
|
-
expect(result.valid).toBe(false)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
it('should reject bracket-notation constructor access', () => {
|
|
119
|
-
const result = security.validateCode('x["constructor"]')
|
|
120
|
-
expect(result.valid).toBe(false)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('should reject Reflect.construct', () => {
|
|
124
|
-
const result = security.validateCode('Reflect.construct(Function, ["return 1"])')
|
|
125
|
-
expect(result.valid).toBe(false)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
it('should accumulate multiple violations', () => {
|
|
129
|
-
const result = security.validateCode('require("fs"); process.exit(1)')
|
|
130
|
-
expect(result.valid).toBe(false)
|
|
131
|
-
expect(result.errors.length).toBeGreaterThanOrEqual(2)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
it('should allow safe API calls', () => {
|
|
135
|
-
const result = security.validateCode(
|
|
136
|
-
'const entries = await mj.core.getRecentEntries({ limit: 5 }); return entries;'
|
|
137
|
-
)
|
|
138
|
-
expect(result.valid).toBe(true)
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
// =========================================================================
|
|
143
|
-
// Rate Limiting
|
|
144
|
-
// =========================================================================
|
|
145
|
-
|
|
146
|
-
describe('checkRateLimit', () => {
|
|
147
|
-
it('should allow first execution', () => {
|
|
148
|
-
expect(security.checkRateLimit('client-a')).toBe(true)
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should allow up to maxExecutionsPerMinute', () => {
|
|
152
|
-
const mgr = new CodeModeSecurityManager({ maxExecutionsPerMinute: 3 })
|
|
153
|
-
expect(mgr.checkRateLimit('client-b')).toBe(true)
|
|
154
|
-
expect(mgr.checkRateLimit('client-b')).toBe(true)
|
|
155
|
-
expect(mgr.checkRateLimit('client-b')).toBe(true)
|
|
156
|
-
// 4th should be denied
|
|
157
|
-
expect(mgr.checkRateLimit('client-b')).toBe(false)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('should track clients independently', () => {
|
|
161
|
-
const mgr = new CodeModeSecurityManager({ maxExecutionsPerMinute: 1 })
|
|
162
|
-
expect(mgr.checkRateLimit('client-x')).toBe(true)
|
|
163
|
-
expect(mgr.checkRateLimit('client-x')).toBe(false)
|
|
164
|
-
// Different client should still be allowed
|
|
165
|
-
expect(mgr.checkRateLimit('client-y')).toBe(true)
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
it('should reset after window expires', () => {
|
|
169
|
-
const mgr = new CodeModeSecurityManager({ maxExecutionsPerMinute: 1 })
|
|
170
|
-
expect(mgr.checkRateLimit('client-z')).toBe(true)
|
|
171
|
-
expect(mgr.checkRateLimit('client-z')).toBe(false)
|
|
172
|
-
|
|
173
|
-
// Simulate window expiry by cleaning up (entry will be stale next check)
|
|
174
|
-
mgr.cleanupRateLimits()
|
|
175
|
-
// The cleanup only removes entries past resetTime — not enough time has passed
|
|
176
|
-
// But the state should still be consistent
|
|
177
|
-
expect(mgr.checkRateLimit('client-z')).toBe(false)
|
|
178
|
-
})
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
describe('cleanupRateLimits', () => {
|
|
182
|
-
it('should not throw when empty', () => {
|
|
183
|
-
expect(() => security.cleanupRateLimits()).not.toThrow()
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
it('should remove expired entries', () => {
|
|
187
|
-
// Add an entry, then cleanup — entry should still be present (not expired yet)
|
|
188
|
-
security.checkRateLimit('cleanup-test')
|
|
189
|
-
security.cleanupRateLimits()
|
|
190
|
-
// The entry should still exist since it hasn't expired
|
|
191
|
-
expect(security.checkRateLimit('cleanup-test')).toBe(true)
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
// =========================================================================
|
|
196
|
-
// Result Size Validation
|
|
197
|
-
// =========================================================================
|
|
198
|
-
|
|
199
|
-
describe('validateResultSize', () => {
|
|
200
|
-
it('should accept small results', () => {
|
|
201
|
-
const result = security.validateResultSize({ data: 'hello' })
|
|
202
|
-
expect(result.valid).toBe(true)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should reject oversized results', () => {
|
|
206
|
-
const mgr = new CodeModeSecurityManager({ maxResultSize: 100 })
|
|
207
|
-
const largeData = { data: 'x'.repeat(200) }
|
|
208
|
-
const result = mgr.validateResultSize(largeData)
|
|
209
|
-
expect(result.valid).toBe(false)
|
|
210
|
-
expect(result.errors[0]).toContain('maximum size')
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('should reject non-serializable results', () => {
|
|
214
|
-
const circular: Record<string, unknown> = {}
|
|
215
|
-
circular['self'] = circular
|
|
216
|
-
const result = security.validateResultSize(circular)
|
|
217
|
-
expect(result.valid).toBe(false)
|
|
218
|
-
expect(result.errors[0]).toContain('serialized')
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
// =========================================================================
|
|
223
|
-
// Config Access
|
|
224
|
-
// =========================================================================
|
|
225
|
-
|
|
226
|
-
describe('getConfig', () => {
|
|
227
|
-
it('should return default config', () => {
|
|
228
|
-
const config = security.getConfig()
|
|
229
|
-
expect(config.maxCodeLength).toBe(DEFAULT_SECURITY_CONFIG.maxCodeLength)
|
|
230
|
-
expect(config.maxExecutionsPerMinute).toBe(
|
|
231
|
-
DEFAULT_SECURITY_CONFIG.maxExecutionsPerMinute
|
|
232
|
-
)
|
|
233
|
-
expect(config.maxResultSize).toBe(DEFAULT_SECURITY_CONFIG.maxResultSize)
|
|
234
|
-
expect(config.blockedPatterns.length).toBeGreaterThan(0)
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
it('should reflect custom config', () => {
|
|
238
|
-
const mgr = new CodeModeSecurityManager({ maxCodeLength: 999 })
|
|
239
|
-
expect(mgr.getConfig().maxCodeLength).toBe(999)
|
|
240
|
-
})
|
|
241
|
-
})
|
|
242
|
-
})
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
-
import { execSync } from 'node:child_process'
|
|
3
|
-
import * as fs from 'node:fs'
|
|
4
|
-
import * as path from 'node:path'
|
|
5
|
-
import { WorkerSandbox, WorkerSandboxPool } from '../../src/codemode/index.js'
|
|
6
|
-
|
|
7
|
-
const workerScriptSrc = path.join(__dirname, '../../src/codemode/worker-script.ts')
|
|
8
|
-
const workerScriptJs = path.join(__dirname, '../../src/codemode/worker-script.js')
|
|
9
|
-
|
|
10
|
-
beforeAll(() => {
|
|
11
|
-
// Compile worker-script.ts to .js specifically for test execution
|
|
12
|
-
// worker_threads cannot run .ts files directly in this vitest setup
|
|
13
|
-
if (!fs.existsSync(workerScriptJs)) {
|
|
14
|
-
execSync(
|
|
15
|
-
`npx esbuild ${workerScriptSrc} --bundle --platform=node --format=esm --outfile=${workerScriptJs}`
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
afterAll(() => {
|
|
21
|
-
// Cleanup generated JS file
|
|
22
|
-
if (fs.existsSync(workerScriptJs)) {
|
|
23
|
-
fs.unlinkSync(workerScriptJs)
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('WorkerSandbox', () => {
|
|
28
|
-
it('should execute basic code successfully', async () => {
|
|
29
|
-
const sandbox = new WorkerSandbox()
|
|
30
|
-
const result = await sandbox.execute('return 42', {})
|
|
31
|
-
expect(result.success).toBe(true)
|
|
32
|
-
expect(result.result).toBe(42)
|
|
33
|
-
expect(result.metrics).toBeDefined()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should call api bindings correctly', async () => {
|
|
37
|
-
const sandbox = new WorkerSandbox()
|
|
38
|
-
const bindings = {
|
|
39
|
-
core: {
|
|
40
|
-
testFunc: async (x: number) => x * 2,
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
const code = 'return await mj.core.testFunc(21)'
|
|
44
|
-
const result = await sandbox.execute(code, bindings)
|
|
45
|
-
expect(result.success).toBe(true)
|
|
46
|
-
expect(result.result).toBe(42)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('should handle top-level bindings correctly', async () => {
|
|
50
|
-
const sandbox = new WorkerSandbox()
|
|
51
|
-
const bindings = {
|
|
52
|
-
testFunc: async (x: number) => x * 3,
|
|
53
|
-
}
|
|
54
|
-
const code = 'return await mj.testFunc(14)'
|
|
55
|
-
const result = await sandbox.execute(code, bindings)
|
|
56
|
-
expect(result.success).toBe(true)
|
|
57
|
-
expect(result.result).toBe(42)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('should enforce timeout limiting', async () => {
|
|
61
|
-
// Provide a very short timeout
|
|
62
|
-
const sandbox = new WorkerSandbox({ timeoutMs: 50 })
|
|
63
|
-
const code = `
|
|
64
|
-
while(true) {
|
|
65
|
-
// Infinite loop
|
|
66
|
-
}
|
|
67
|
-
`
|
|
68
|
-
const result = await sandbox.execute(code, {})
|
|
69
|
-
expect(result.success).toBe(false)
|
|
70
|
-
expect(result.error).toContain('timed out')
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('should catch synchronous syntax errors or throw', async () => {
|
|
74
|
-
const sandbox = new WorkerSandbox()
|
|
75
|
-
const result = await sandbox.execute('throw new Error("test abort")', {})
|
|
76
|
-
expect(result.success).toBe(false)
|
|
77
|
-
expect(result.error).toContain('test abort')
|
|
78
|
-
})
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
describe('WorkerSandboxPool', () => {
|
|
82
|
-
it('should create and execute using pool', async () => {
|
|
83
|
-
const pool = new WorkerSandboxPool({}, { maxInstances: 2 })
|
|
84
|
-
const result = await pool.execute('return "pooled"', {})
|
|
85
|
-
expect(result.success).toBe(true)
|
|
86
|
-
expect(result.result).toBe('pooled')
|
|
87
|
-
expect(pool.getActiveCount()).toBe(0)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('should enforce max instances exhaustion', async () => {
|
|
91
|
-
const pool = new WorkerSandboxPool({}, { maxInstances: 1 })
|
|
92
|
-
|
|
93
|
-
// Start one long-running execution that won't finish immediately
|
|
94
|
-
const slowCode = 'await new Promise(r => setTimeout(r, 200)); return 1;'
|
|
95
|
-
const exec1 = pool.execute(slowCode, {}).catch((e) => null)
|
|
96
|
-
|
|
97
|
-
// Pool is now at 1/1 active count
|
|
98
|
-
// Attempting a second execution should fail immediately with an exhausted error
|
|
99
|
-
const result2 = await pool.execute('return 2', {})
|
|
100
|
-
expect(result2.success).toBe(false)
|
|
101
|
-
expect(result2.error).toContain('Sandbox pool exhausted')
|
|
102
|
-
|
|
103
|
-
await exec1 // wait for the first to finish
|
|
104
|
-
expect(pool.getActiveCount()).toBe(0)
|
|
105
|
-
})
|
|
106
|
-
})
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Icons Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests icon constants and getToolIcon function.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect } from 'vitest'
|
|
8
|
-
import {
|
|
9
|
-
ICON_CORE,
|
|
10
|
-
ICON_SEARCH,
|
|
11
|
-
ICON_ANALYTICS,
|
|
12
|
-
ICON_RELATIONSHIPS,
|
|
13
|
-
ICON_EXPORT,
|
|
14
|
-
ICON_ADMIN,
|
|
15
|
-
ICON_GITHUB,
|
|
16
|
-
ICON_BACKUP,
|
|
17
|
-
ICON_BRIEFING,
|
|
18
|
-
ICON_CLOCK,
|
|
19
|
-
ICON_TAG,
|
|
20
|
-
ICON_STAR,
|
|
21
|
-
ICON_ISSUE,
|
|
22
|
-
ICON_PR,
|
|
23
|
-
ICON_PROMPT,
|
|
24
|
-
getToolIcon,
|
|
25
|
-
} from '../../src/constants/icons.js'
|
|
26
|
-
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// Tool Group Icons
|
|
29
|
-
// ============================================================================
|
|
30
|
-
|
|
31
|
-
describe('Tool group icons', () => {
|
|
32
|
-
const toolIcons = [
|
|
33
|
-
{ name: 'ICON_CORE', icon: ICON_CORE },
|
|
34
|
-
{ name: 'ICON_SEARCH', icon: ICON_SEARCH },
|
|
35
|
-
{ name: 'ICON_ANALYTICS', icon: ICON_ANALYTICS },
|
|
36
|
-
{ name: 'ICON_RELATIONSHIPS', icon: ICON_RELATIONSHIPS },
|
|
37
|
-
{ name: 'ICON_EXPORT', icon: ICON_EXPORT },
|
|
38
|
-
{ name: 'ICON_ADMIN', icon: ICON_ADMIN },
|
|
39
|
-
{ name: 'ICON_GITHUB', icon: ICON_GITHUB },
|
|
40
|
-
{ name: 'ICON_BACKUP', icon: ICON_BACKUP },
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
it.each(toolIcons)('$name should have valid SVG data URI', ({ icon }) => {
|
|
44
|
-
expect(icon.src).toMatch(/^data:image\/svg\+xml/)
|
|
45
|
-
expect(icon.mimeType).toBe('image/svg+xml')
|
|
46
|
-
expect(icon.sizes).toContain('24x24')
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
// ============================================================================
|
|
51
|
-
// Resource Icons
|
|
52
|
-
// ============================================================================
|
|
53
|
-
|
|
54
|
-
describe('Resource icons', () => {
|
|
55
|
-
const resourceIcons = [
|
|
56
|
-
{ name: 'ICON_BRIEFING', icon: ICON_BRIEFING },
|
|
57
|
-
{ name: 'ICON_CLOCK', icon: ICON_CLOCK },
|
|
58
|
-
{ name: 'ICON_TAG', icon: ICON_TAG },
|
|
59
|
-
|
|
60
|
-
{ name: 'ICON_STAR', icon: ICON_STAR },
|
|
61
|
-
{ name: 'ICON_ISSUE', icon: ICON_ISSUE },
|
|
62
|
-
{ name: 'ICON_PR', icon: ICON_PR },
|
|
63
|
-
{ name: 'ICON_PROMPT', icon: ICON_PROMPT },
|
|
64
|
-
]
|
|
65
|
-
|
|
66
|
-
it.each(resourceIcons)('$name should have valid SVG data URI', ({ icon }) => {
|
|
67
|
-
expect(icon.src).toMatch(/^data:image\/svg\+xml/)
|
|
68
|
-
expect(icon.mimeType).toBe('image/svg+xml')
|
|
69
|
-
expect(icon.sizes).toContain('24x24')
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// ============================================================================
|
|
74
|
-
// getToolIcon
|
|
75
|
-
// ============================================================================
|
|
76
|
-
|
|
77
|
-
describe('getToolIcon', () => {
|
|
78
|
-
it('should return icon array for valid groups', () => {
|
|
79
|
-
const groups = [
|
|
80
|
-
'core',
|
|
81
|
-
'search',
|
|
82
|
-
'analytics',
|
|
83
|
-
'relationships',
|
|
84
|
-
'export',
|
|
85
|
-
'admin',
|
|
86
|
-
'github',
|
|
87
|
-
'backup',
|
|
88
|
-
]
|
|
89
|
-
|
|
90
|
-
for (const group of groups) {
|
|
91
|
-
const icons = getToolIcon(group)
|
|
92
|
-
expect(icons).toBeDefined()
|
|
93
|
-
expect(Array.isArray(icons)).toBe(true)
|
|
94
|
-
expect(icons!.length).toBeGreaterThan(0)
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should return undefined for unknown group', () => {
|
|
99
|
-
expect(getToolIcon('nonexistent')).toBeUndefined()
|
|
100
|
-
})
|
|
101
|
-
})
|