@kb-labs/shared 1.1.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/.cursorrules +32 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/deploy.yml +28 -0
- package/.github/workflows/docker-build.yml +25 -0
- package/.github/workflows/drift-check.yml +10 -0
- package/.github/workflows/profiles-validate.yml +16 -0
- package/.github/workflows/release.yml +8 -0
- package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
- package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
- package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
- package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
- package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
- package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
- package/.kb/devkit/agents/release-manager/context.globs +7 -0
- package/.kb/devkit/agents/release-manager/prompt.md +27 -0
- package/.kb/devkit/agents/release-manager/runbook.md +17 -0
- package/.kb/devkit/agents/test-generator/context.globs +7 -0
- package/.kb/devkit/agents/test-generator/prompt.md +27 -0
- package/.kb/devkit/agents/test-generator/runbook.md +18 -0
- package/.vscode/settings.json +23 -0
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +117 -0
- package/LICENSE +21 -0
- package/README.md +306 -0
- package/docs/DECLARATIVE-FLAGS-AND-ENV.md +622 -0
- package/docs/DOCUMENTATION.md +70 -0
- package/docs/adr/0000-template.md +52 -0
- package/docs/adr/0001-architecture-and-repository-layout.md +31 -0
- package/docs/adr/0002-plugins-and-extensibility.md +44 -0
- package/docs/adr/0003-package-and-module-boundaries.md +35 -0
- package/docs/adr/0004-versioning-and-release-policy.md +36 -0
- package/docs/adr/0005-reactive-loader-pattern.md +179 -0
- package/docs/adr/0006-declarative-flags-and-env-systems.md +376 -0
- package/eslint.config.js +27 -0
- package/kb-labs.config.json +5 -0
- package/package.json +88 -0
- package/package.json.bin +25 -0
- package/package.json.lib +30 -0
- package/packages/shared-cli-ui/CHANGELOG.md +20 -0
- package/packages/shared-cli-ui/README.md +342 -0
- package/packages/shared-cli-ui/docs/ARCHITECTURE.md +105 -0
- package/packages/shared-cli-ui/eslint.config.js +27 -0
- package/packages/shared-cli-ui/package.json +72 -0
- package/packages/shared-cli-ui/src/__tests__/artifacts-display.spec.ts +89 -0
- package/packages/shared-cli-ui/src/__tests__/format.spec.ts +44 -0
- package/packages/shared-cli-ui/src/__tests__/loader-json-mode.test.ts +119 -0
- package/packages/shared-cli-ui/src/artifacts-display.ts +266 -0
- package/packages/shared-cli-ui/src/cli-auto-discovery.ts +120 -0
- package/packages/shared-cli-ui/src/colors.ts +142 -0
- package/packages/shared-cli-ui/src/command-discovery.ts +72 -0
- package/packages/shared-cli-ui/src/command-output.ts +153 -0
- package/packages/shared-cli-ui/src/command-result.ts +267 -0
- package/packages/shared-cli-ui/src/command-runner.ts +310 -0
- package/packages/shared-cli-ui/src/command-suggestions.ts +204 -0
- package/packages/shared-cli-ui/src/debug/components/output.ts +141 -0
- package/packages/shared-cli-ui/src/debug/components/trace.ts +101 -0
- package/packages/shared-cli-ui/src/debug/components/tree.ts +88 -0
- package/packages/shared-cli-ui/src/debug/formatters/ai.ts +17 -0
- package/packages/shared-cli-ui/src/debug/formatters/human.ts +98 -0
- package/packages/shared-cli-ui/src/debug/formatters/timeline.ts +94 -0
- package/packages/shared-cli-ui/src/debug/index.ts +56 -0
- package/packages/shared-cli-ui/src/debug/types.ts +57 -0
- package/packages/shared-cli-ui/src/debug/utilities.ts +203 -0
- package/packages/shared-cli-ui/src/dynamic-command-discovery.ts +131 -0
- package/packages/shared-cli-ui/src/format.ts +412 -0
- package/packages/shared-cli-ui/src/index.ts +34 -0
- package/packages/shared-cli-ui/src/loader.ts +196 -0
- package/packages/shared-cli-ui/src/manifest-parser.ts +151 -0
- package/packages/shared-cli-ui/src/modern-format.ts +271 -0
- package/packages/shared-cli-ui/src/multi-cli-suggestions.ts +159 -0
- package/packages/shared-cli-ui/src/table.ts +134 -0
- package/packages/shared-cli-ui/src/timing-tracker.ts +68 -0
- package/packages/shared-cli-ui/src/utils/context.ts +12 -0
- package/packages/shared-cli-ui/src/utils/env.ts +164 -0
- package/packages/shared-cli-ui/src/utils/flags.ts +269 -0
- package/packages/shared-cli-ui/src/utils/path.ts +8 -0
- package/packages/shared-cli-ui/tsconfig.build.json +15 -0
- package/packages/shared-cli-ui/tsconfig.json +9 -0
- package/packages/shared-cli-ui/tsup.config.ts +11 -0
- package/packages/shared-cli-ui/vitest.config.ts +15 -0
- package/packages/shared-command-kit/CHANGELOG.md +20 -0
- package/packages/shared-command-kit/LICENSE +22 -0
- package/packages/shared-command-kit/README.md +1030 -0
- package/packages/shared-command-kit/docs/HIGH-LEVEL-API.md +89 -0
- package/packages/shared-command-kit/docs/LOW-LEVEL-API.md +105 -0
- package/packages/shared-command-kit/docs/MIGRATION-GUIDE.md +135 -0
- package/packages/shared-command-kit/eslint.config.js +27 -0
- package/packages/shared-command-kit/eslint.config.ts +14 -0
- package/packages/shared-command-kit/package.json +76 -0
- package/packages/shared-command-kit/prettierrc.json +5 -0
- package/packages/shared-command-kit/src/__tests__/define-command.spec.ts +294 -0
- package/packages/shared-command-kit/src/__tests__/define-route.test.ts +285 -0
- package/packages/shared-command-kit/src/__tests__/define-system-command.spec.ts +508 -0
- package/packages/shared-command-kit/src/__tests__/define-webhook.test.ts +156 -0
- package/packages/shared-command-kit/src/__tests__/define-websocket.test.ts +316 -0
- package/packages/shared-command-kit/src/__tests__/errors.spec.ts +45 -0
- package/packages/shared-command-kit/src/__tests__/flags.spec.ts +353 -0
- package/packages/shared-command-kit/src/__tests__/platform-api.test.ts +135 -0
- package/packages/shared-command-kit/src/__tests__/plugin-context-v3.snapshot.spec.ts +240 -0
- package/packages/shared-command-kit/src/__tests__/ws-types.test.ts +359 -0
- package/packages/shared-command-kit/src/analytics/index.ts +6 -0
- package/packages/shared-command-kit/src/analytics/with-analytics.ts +195 -0
- package/packages/shared-command-kit/src/define-action.ts +100 -0
- package/packages/shared-command-kit/src/define-command.ts +113 -0
- package/packages/shared-command-kit/src/define-route.ts +113 -0
- package/packages/shared-command-kit/src/define-system-command.ts +362 -0
- package/packages/shared-command-kit/src/define-webhook.ts +115 -0
- package/packages/shared-command-kit/src/define-websocket.ts +308 -0
- package/packages/shared-command-kit/src/errors/factory.ts +282 -0
- package/packages/shared-command-kit/src/errors/format-validation.ts +144 -0
- package/packages/shared-command-kit/src/errors/format.ts +92 -0
- package/packages/shared-command-kit/src/errors/index.ts +9 -0
- package/packages/shared-command-kit/src/errors/types.ts +32 -0
- package/packages/shared-command-kit/src/flags/define.ts +92 -0
- package/packages/shared-command-kit/src/flags/index.ts +9 -0
- package/packages/shared-command-kit/src/flags/types.ts +153 -0
- package/packages/shared-command-kit/src/flags/validate.ts +358 -0
- package/packages/shared-command-kit/src/helpers/context.ts +8 -0
- package/packages/shared-command-kit/src/helpers/flags.ts +84 -0
- package/packages/shared-command-kit/src/helpers/index.ts +42 -0
- package/packages/shared-command-kit/src/helpers/patterns.ts +464 -0
- package/packages/shared-command-kit/src/helpers/platform.ts +335 -0
- package/packages/shared-command-kit/src/helpers/use-analytics.ts +95 -0
- package/packages/shared-command-kit/src/helpers/use-cache.ts +97 -0
- package/packages/shared-command-kit/src/helpers/use-config.ts +99 -0
- package/packages/shared-command-kit/src/helpers/use-embeddings.ts +49 -0
- package/packages/shared-command-kit/src/helpers/use-llm.ts +316 -0
- package/packages/shared-command-kit/src/helpers/use-logger.ts +77 -0
- package/packages/shared-command-kit/src/helpers/use-platform.ts +111 -0
- package/packages/shared-command-kit/src/helpers/use-resource-broker.ts +106 -0
- package/packages/shared-command-kit/src/helpers/use-storage.ts +71 -0
- package/packages/shared-command-kit/src/helpers/use-vector-store.ts +49 -0
- package/packages/shared-command-kit/src/helpers/validation.ts +398 -0
- package/packages/shared-command-kit/src/index.ts +410 -0
- package/packages/shared-command-kit/src/jobs.ts +132 -0
- package/packages/shared-command-kit/src/lifecycle/define-handlers.ts +366 -0
- package/packages/shared-command-kit/src/lifecycle/index.ts +6 -0
- package/packages/shared-command-kit/src/manifest.ts +127 -0
- package/packages/shared-command-kit/src/rest/define-handler.ts +187 -0
- package/packages/shared-command-kit/src/rest/index.ts +11 -0
- package/packages/shared-command-kit/src/studio/index.ts +12 -0
- package/packages/shared-command-kit/src/validation/index.ts +6 -0
- package/packages/shared-command-kit/src/validation/schema-builders.ts +409 -0
- package/packages/shared-command-kit/src/ws-types.ts +106 -0
- package/packages/shared-command-kit/tsconfig.build.json +15 -0
- package/packages/shared-command-kit/tsconfig.json +9 -0
- package/packages/shared-command-kit/tsup.config.ts +30 -0
- package/packages/shared-command-kit/vitest.config.ts +4 -0
- package/packages/shared-http/package.json +67 -0
- package/packages/shared-http/src/__tests__/log-correlation.test.ts +81 -0
- package/packages/shared-http/src/__tests__/operation-metrics-tracker.test.ts +55 -0
- package/packages/shared-http/src/http-observability-collector.ts +363 -0
- package/packages/shared-http/src/index.ts +36 -0
- package/packages/shared-http/src/log-correlation.ts +89 -0
- package/packages/shared-http/src/operation-metrics-tracker.ts +107 -0
- package/packages/shared-http/src/register-openapi.ts +108 -0
- package/packages/shared-http/src/resolve-schema-ref.ts +75 -0
- package/packages/shared-http/src/schemas.ts +29 -0
- package/packages/shared-http/src/service-observability.ts +63 -0
- package/packages/shared-http/tsconfig.build.json +15 -0
- package/packages/shared-http/tsconfig.json +9 -0
- package/packages/shared-http/tsup.config.ts +23 -0
- package/packages/shared-http/vitest.config.ts +13 -0
- package/packages/shared-perm-presets/CHANGELOG.md +20 -0
- package/packages/shared-perm-presets/README.md +78 -0
- package/packages/shared-perm-presets/eslint.config.js +27 -0
- package/packages/shared-perm-presets/package.json +45 -0
- package/packages/shared-perm-presets/src/__tests__/combine.test.ts +403 -0
- package/packages/shared-perm-presets/src/__tests__/presets.test.ts +205 -0
- package/packages/shared-perm-presets/src/combine.ts +278 -0
- package/packages/shared-perm-presets/src/index.ts +18 -0
- package/packages/shared-perm-presets/src/presets/ci-environment.ts +34 -0
- package/packages/shared-perm-presets/src/presets/full-env.ts +16 -0
- package/packages/shared-perm-presets/src/presets/git-workflow.ts +40 -0
- package/packages/shared-perm-presets/src/presets/index.ts +8 -0
- package/packages/shared-perm-presets/src/presets/kb-platform.ts +30 -0
- package/packages/shared-perm-presets/src/presets/llm-access.ts +29 -0
- package/packages/shared-perm-presets/src/presets/minimal.ts +21 -0
- package/packages/shared-perm-presets/src/presets/npm-publish.ts +48 -0
- package/packages/shared-perm-presets/src/presets/vector-store.ts +40 -0
- package/packages/shared-perm-presets/src/types.ts +192 -0
- package/packages/shared-perm-presets/tsconfig.build.json +15 -0
- package/packages/shared-perm-presets/tsconfig.json +9 -0
- package/packages/shared-perm-presets/tsup.config.ts +8 -0
- package/packages/shared-perm-presets/vitest.config.ts +9 -0
- package/packages/shared-testing/CHANGELOG.md +20 -0
- package/packages/shared-testing/README.md +430 -0
- package/packages/shared-testing/package.json +51 -0
- package/packages/shared-testing/src/__tests__/create-test-context.test.ts +199 -0
- package/packages/shared-testing/src/__tests__/mock-cache.test.ts +174 -0
- package/packages/shared-testing/src/__tests__/mock-llm.test.ts +212 -0
- package/packages/shared-testing/src/__tests__/setup-platform.test.ts +90 -0
- package/packages/shared-testing/src/__tests__/test-command.test.ts +557 -0
- package/packages/shared-testing/src/create-test-context.ts +550 -0
- package/packages/shared-testing/src/index.ts +77 -0
- package/packages/shared-testing/src/mock-cache.ts +179 -0
- package/packages/shared-testing/src/mock-llm.ts +319 -0
- package/packages/shared-testing/src/mock-logger.ts +97 -0
- package/packages/shared-testing/src/mock-storage.ts +108 -0
- package/packages/shared-testing/src/setup-platform.ts +101 -0
- package/packages/shared-testing/src/test-command.ts +288 -0
- package/packages/shared-testing/tsconfig.build.json +15 -0
- package/packages/shared-testing/tsconfig.json +9 -0
- package/packages/shared-testing/tsup.config.ts +20 -0
- package/packages/shared-testing/vitest.config.ts +3 -0
- package/packages/shared-tool-kit/CHANGELOG.md +20 -0
- package/packages/shared-tool-kit/package.json +47 -0
- package/packages/shared-tool-kit/src/__tests__/factory.test.ts +103 -0
- package/packages/shared-tool-kit/src/__tests__/mock-tool.test.ts +95 -0
- package/packages/shared-tool-kit/src/factory.ts +126 -0
- package/packages/shared-tool-kit/src/index.ts +32 -0
- package/packages/shared-tool-kit/src/testing/index.ts +84 -0
- package/packages/shared-tool-kit/tsconfig.build.json +15 -0
- package/packages/shared-tool-kit/tsconfig.json +9 -0
- package/packages/shared-tool-kit/tsup.config.ts +21 -0
- package/pnpm-workspace.yaml +11070 -0
- package/prettierrc.json +1 -0
- package/scripts/devkit-sync.mjs +37 -0
- package/scripts/hooks/post-push +9 -0
- package/scripts/hooks/pre-commit +9 -0
- package/scripts/hooks/pre-push +9 -0
- package/tsconfig.base.json +9 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsconfig.paths.json +50 -0
- package/tsconfig.tools.json +18 -0
- package/tsup.config.bin.ts +34 -0
- package/tsup.config.cli.ts +41 -0
- package/tsup.config.dual.ts +46 -0
- package/tsup.config.ts +36 -0
- package/tsup.external.json +104 -0
- package/vitest.config.ts +48 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { combine, combinePresets } from '../combine';
|
|
3
|
+
import { minimal, gitWorkflow, npmPublish, kbPlatform } from '../presets';
|
|
4
|
+
import type { PermissionPreset } from '../types';
|
|
5
|
+
|
|
6
|
+
describe('combine()', () => {
|
|
7
|
+
it('should return empty spec when nothing added', () => {
|
|
8
|
+
const result = combine().build();
|
|
9
|
+
expect(result).toEqual({});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should add a single preset', () => {
|
|
13
|
+
const result = combine().with(minimal).build();
|
|
14
|
+
expect(result.env?.read).toContain('PATH');
|
|
15
|
+
expect(result.env?.read).toContain('NODE_ENV');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should merge two presets', () => {
|
|
19
|
+
const result = combine()
|
|
20
|
+
.with(minimal)
|
|
21
|
+
.with(gitWorkflow)
|
|
22
|
+
.build();
|
|
23
|
+
|
|
24
|
+
const envVars = result.env?.read ?? [];
|
|
25
|
+
// From minimal
|
|
26
|
+
expect(envVars).toContain('PATH');
|
|
27
|
+
expect(envVars).toContain('NODE_ENV');
|
|
28
|
+
// From gitWorkflow
|
|
29
|
+
expect(envVars).toContain('HOME');
|
|
30
|
+
expect(envVars).toContain('USER');
|
|
31
|
+
expect(envVars).toContain('GIT_*');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should deduplicate env vars', () => {
|
|
35
|
+
const result = combine()
|
|
36
|
+
.with(gitWorkflow)
|
|
37
|
+
.with(npmPublish)
|
|
38
|
+
.build();
|
|
39
|
+
|
|
40
|
+
const envVars = result.env?.read ?? [];
|
|
41
|
+
// Both have HOME, USER, PATH - should appear once
|
|
42
|
+
const homeCount = envVars.filter(v => v === 'HOME').length;
|
|
43
|
+
expect(homeCount).toBe(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should merge fs.allow arrays and convert to runtime format', () => {
|
|
47
|
+
const result = combine()
|
|
48
|
+
.with(gitWorkflow)
|
|
49
|
+
.with(npmPublish)
|
|
50
|
+
.build();
|
|
51
|
+
|
|
52
|
+
// After build(), format is runtime (read/write arrays)
|
|
53
|
+
const read = result.fs?.read ?? [];
|
|
54
|
+
// From gitWorkflow
|
|
55
|
+
expect(read).toContain('**/.git/**');
|
|
56
|
+
// From npmPublish
|
|
57
|
+
expect(read).toContain('**/package.json');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should merge network domains', () => {
|
|
61
|
+
const result = combine()
|
|
62
|
+
.with(npmPublish)
|
|
63
|
+
.withNetwork({ fetch: ['api.example.com'] })
|
|
64
|
+
.build();
|
|
65
|
+
|
|
66
|
+
const domains = result.network?.fetch ?? [];
|
|
67
|
+
expect(domains).toContain('registry.npmjs.org');
|
|
68
|
+
expect(domains).toContain('api.example.com');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('withEnv()', () => {
|
|
72
|
+
it('should add custom env vars', () => {
|
|
73
|
+
const result = combine()
|
|
74
|
+
.with(minimal)
|
|
75
|
+
.withEnv(['MY_CUSTOM_VAR', 'ANOTHER_VAR'])
|
|
76
|
+
.build();
|
|
77
|
+
|
|
78
|
+
const envVars = result.env?.read ?? [];
|
|
79
|
+
expect(envVars).toContain('MY_CUSTOM_VAR');
|
|
80
|
+
expect(envVars).toContain('ANOTHER_VAR');
|
|
81
|
+
expect(envVars).toContain('PATH');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('withFs()', () => {
|
|
86
|
+
it('should add fs permissions and convert to runtime format', () => {
|
|
87
|
+
const result = combine()
|
|
88
|
+
.with(minimal)
|
|
89
|
+
.withFs({ mode: 'readWrite', allow: ['./data/**'] })
|
|
90
|
+
.build();
|
|
91
|
+
|
|
92
|
+
// After build(), format is runtime (read/write arrays)
|
|
93
|
+
expect(result.fs?.read).toContain('./data/**');
|
|
94
|
+
expect(result.fs?.write).toContain('./data/**');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should merge with existing fs', () => {
|
|
98
|
+
const result = combine()
|
|
99
|
+
.with(gitWorkflow)
|
|
100
|
+
.withFs({ allow: ['./custom/**'] })
|
|
101
|
+
.build();
|
|
102
|
+
|
|
103
|
+
const read = result.fs?.read ?? [];
|
|
104
|
+
expect(read).toContain('**/.git/**');
|
|
105
|
+
expect(read).toContain('./custom/**');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('withQuotas()', () => {
|
|
110
|
+
it('should add quotas', () => {
|
|
111
|
+
const result = combine()
|
|
112
|
+
.with(minimal)
|
|
113
|
+
.withQuotas({ timeoutMs: 30000, memoryMb: 512 })
|
|
114
|
+
.build();
|
|
115
|
+
|
|
116
|
+
expect(result.quotas?.timeoutMs).toBe(30000);
|
|
117
|
+
expect(result.quotas?.memoryMb).toBe(512);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should override quotas (last wins)', () => {
|
|
121
|
+
const result = combine()
|
|
122
|
+
.withQuotas({ timeoutMs: 10000 })
|
|
123
|
+
.withQuotas({ timeoutMs: 30000 })
|
|
124
|
+
.build();
|
|
125
|
+
|
|
126
|
+
expect(result.quotas?.timeoutMs).toBe(30000);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('withPlatform()', () => {
|
|
131
|
+
it('should add platform permissions with booleans', () => {
|
|
132
|
+
const result = combine()
|
|
133
|
+
.with(minimal)
|
|
134
|
+
.withPlatform({
|
|
135
|
+
llm: true,
|
|
136
|
+
cache: true,
|
|
137
|
+
analytics: true,
|
|
138
|
+
})
|
|
139
|
+
.build();
|
|
140
|
+
|
|
141
|
+
expect(result.platform?.llm).toBe(true);
|
|
142
|
+
expect(result.platform?.cache).toBe(true);
|
|
143
|
+
expect(result.platform?.analytics).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should add platform permissions with arrays', () => {
|
|
147
|
+
const result = combine()
|
|
148
|
+
.with(minimal)
|
|
149
|
+
.withPlatform({
|
|
150
|
+
cache: ['git-status:', 'workflow:'],
|
|
151
|
+
storage: ['uploads/', 'temp/'],
|
|
152
|
+
})
|
|
153
|
+
.build();
|
|
154
|
+
|
|
155
|
+
expect(result.platform?.cache).toEqual(['git-status:', 'workflow:']);
|
|
156
|
+
expect(result.platform?.storage).toEqual(['uploads/', 'temp/']);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should add platform permissions with objects', () => {
|
|
160
|
+
const result = combine()
|
|
161
|
+
.with(minimal)
|
|
162
|
+
.withPlatform({
|
|
163
|
+
llm: { models: ['gpt-4', 'claude-3'] },
|
|
164
|
+
vectorStore: { collections: ['docs', 'code'] },
|
|
165
|
+
eventBus: { publish: ['events.*'], subscribe: ['jobs.*'] },
|
|
166
|
+
})
|
|
167
|
+
.build();
|
|
168
|
+
|
|
169
|
+
expect(result.platform?.llm).toEqual({ models: ['gpt-4', 'claude-3'] });
|
|
170
|
+
expect(result.platform?.vectorStore).toEqual({ collections: ['docs', 'code'] });
|
|
171
|
+
expect(result.platform?.eventBus).toEqual({ publish: ['events.*'], subscribe: ['jobs.*'] });
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should merge platform arrays (union)', () => {
|
|
175
|
+
const result = combine()
|
|
176
|
+
.withPlatform({
|
|
177
|
+
cache: ['git-status:'],
|
|
178
|
+
storage: ['uploads/'],
|
|
179
|
+
})
|
|
180
|
+
.withPlatform({
|
|
181
|
+
cache: ['workflow:'],
|
|
182
|
+
storage: ['temp/'],
|
|
183
|
+
})
|
|
184
|
+
.build();
|
|
185
|
+
|
|
186
|
+
// Arrays should be merged (union)
|
|
187
|
+
expect(result.platform?.cache).toEqual(['git-status:', 'workflow:']);
|
|
188
|
+
expect(result.platform?.storage).toEqual(['uploads/', 'temp/']);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should merge platform objects (spread)', () => {
|
|
192
|
+
const result = combine()
|
|
193
|
+
.withPlatform({
|
|
194
|
+
llm: { models: ['gpt-4'] },
|
|
195
|
+
vectorStore: { collections: ['docs'] },
|
|
196
|
+
})
|
|
197
|
+
.withPlatform({
|
|
198
|
+
llm: { models: ['claude-3'] },
|
|
199
|
+
vectorStore: { collections: ['code'] },
|
|
200
|
+
})
|
|
201
|
+
.build();
|
|
202
|
+
|
|
203
|
+
// Objects should be merged (last wins for same keys)
|
|
204
|
+
expect(result.platform?.llm).toEqual({ models: ['claude-3'] });
|
|
205
|
+
expect(result.platform?.vectorStore).toEqual({ collections: ['code'] });
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should override booleans (last wins)', () => {
|
|
209
|
+
const result = combine()
|
|
210
|
+
.withPlatform({ analytics: false })
|
|
211
|
+
.withPlatform({ analytics: true })
|
|
212
|
+
.build();
|
|
213
|
+
|
|
214
|
+
expect(result.platform?.analytics).toBe(true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should merge with existing platform permissions from presets', () => {
|
|
218
|
+
const presetWithPlatform: PermissionPreset = {
|
|
219
|
+
id: 'test-preset',
|
|
220
|
+
description: 'Test preset with platform',
|
|
221
|
+
permissions: {
|
|
222
|
+
platform: {
|
|
223
|
+
llm: true,
|
|
224
|
+
cache: ['preset:'],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const result = combine()
|
|
230
|
+
.with(presetWithPlatform)
|
|
231
|
+
.withPlatform({
|
|
232
|
+
cache: ['custom:'],
|
|
233
|
+
analytics: true,
|
|
234
|
+
})
|
|
235
|
+
.build();
|
|
236
|
+
|
|
237
|
+
expect(result.platform?.llm).toBe(true);
|
|
238
|
+
expect(result.platform?.cache).toEqual(['preset:', 'custom:']);
|
|
239
|
+
expect(result.platform?.analytics).toBe(true);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should deduplicate array values in platform permissions', () => {
|
|
243
|
+
const result = combine()
|
|
244
|
+
.withPlatform({
|
|
245
|
+
cache: ['git-status:', 'workflow:'],
|
|
246
|
+
})
|
|
247
|
+
.withPlatform({
|
|
248
|
+
cache: ['git-status:', 'cache:'], // git-status: is duplicate
|
|
249
|
+
})
|
|
250
|
+
.build();
|
|
251
|
+
|
|
252
|
+
// Should deduplicate git-status:
|
|
253
|
+
const cache = result.platform?.cache as string[];
|
|
254
|
+
expect(cache).toHaveLength(3);
|
|
255
|
+
expect(cache).toContain('git-status:');
|
|
256
|
+
expect(cache).toContain('workflow:');
|
|
257
|
+
expect(cache).toContain('cache:');
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should handle undefined platform gracefully', () => {
|
|
261
|
+
const result = combine()
|
|
262
|
+
.with(minimal)
|
|
263
|
+
.withPlatform(undefined as any)
|
|
264
|
+
.build();
|
|
265
|
+
|
|
266
|
+
expect(result.platform).toBeUndefined();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should pass through platform to runtime format unchanged', () => {
|
|
270
|
+
const result = combine()
|
|
271
|
+
.withPlatform({
|
|
272
|
+
llm: { models: ['gpt-4'] },
|
|
273
|
+
cache: ['git:'],
|
|
274
|
+
analytics: true,
|
|
275
|
+
})
|
|
276
|
+
.build();
|
|
277
|
+
|
|
278
|
+
// Platform permissions should pass through to runtime format unchanged
|
|
279
|
+
expect(result.platform?.llm).toEqual({ models: ['gpt-4'] });
|
|
280
|
+
expect(result.platform?.cache).toEqual(['git:']);
|
|
281
|
+
expect(result.platform?.analytics).toBe(true);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
describe('with raw PermissionSpec', () => {
|
|
286
|
+
it('should accept raw spec without id/description', () => {
|
|
287
|
+
const result = combine()
|
|
288
|
+
.with({ env: { read: ['CUSTOM_VAR'] } })
|
|
289
|
+
.build();
|
|
290
|
+
|
|
291
|
+
expect(result.env?.read).toContain('CUSTOM_VAR');
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('combinePresets()', () => {
|
|
297
|
+
it('should combine multiple presets at once', () => {
|
|
298
|
+
const result = combinePresets(minimal, gitWorkflow, kbPlatform);
|
|
299
|
+
|
|
300
|
+
const envVars = result.env?.read ?? [];
|
|
301
|
+
expect(envVars).toContain('PATH');
|
|
302
|
+
expect(envVars).toContain('HOME');
|
|
303
|
+
expect(envVars).toContain('KB_*');
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should work with single preset', () => {
|
|
307
|
+
const result = combinePresets(gitWorkflow);
|
|
308
|
+
expect(result.env?.read).toContain('HOME');
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should return empty spec with no presets', () => {
|
|
312
|
+
const result = combinePresets();
|
|
313
|
+
expect(result).toEqual({});
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe('Real-world scenarios', () => {
|
|
318
|
+
it('should create commit-plugin permissions (git + kb-platform)', () => {
|
|
319
|
+
const result = combine()
|
|
320
|
+
.with(gitWorkflow)
|
|
321
|
+
.with(kbPlatform)
|
|
322
|
+
.withEnv(['OPENAI_API_KEY'])
|
|
323
|
+
.build();
|
|
324
|
+
|
|
325
|
+
const envVars = result.env?.read ?? [];
|
|
326
|
+
// Git needs
|
|
327
|
+
expect(envVars).toContain('HOME');
|
|
328
|
+
expect(envVars).toContain('USER');
|
|
329
|
+
expect(envVars).toContain('GIT_*');
|
|
330
|
+
// KB platform needs
|
|
331
|
+
expect(envVars).toContain('KB_*');
|
|
332
|
+
// Custom
|
|
333
|
+
expect(envVars).toContain('OPENAI_API_KEY');
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('should create release-plugin permissions (git + npm + kb-platform)', () => {
|
|
337
|
+
const result = combine()
|
|
338
|
+
.with(gitWorkflow)
|
|
339
|
+
.with(npmPublish)
|
|
340
|
+
.with(kbPlatform)
|
|
341
|
+
.withQuotas({ timeoutMs: 300000 })
|
|
342
|
+
.build();
|
|
343
|
+
|
|
344
|
+
const envVars = result.env?.read ?? [];
|
|
345
|
+
expect(envVars).toContain('HOME');
|
|
346
|
+
expect(envVars).toContain('GIT_*');
|
|
347
|
+
expect(envVars).toContain('NPM_TOKEN');
|
|
348
|
+
expect(envVars).toContain('KB_*');
|
|
349
|
+
|
|
350
|
+
const domains = result.network?.fetch ?? [];
|
|
351
|
+
expect(domains).toContain('registry.npmjs.org');
|
|
352
|
+
|
|
353
|
+
expect(result.quotas?.timeoutMs).toBe(300000);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it('should create commit-plugin with platform permissions (git + kb + llm + cache)', () => {
|
|
357
|
+
const result = combine()
|
|
358
|
+
.with(gitWorkflow)
|
|
359
|
+
.with(kbPlatform)
|
|
360
|
+
.withEnv(['OPENAI_API_KEY', 'ANTHROPIC_API_KEY'])
|
|
361
|
+
.withFs({
|
|
362
|
+
mode: 'readWrite',
|
|
363
|
+
allow: ['.kb/commit/**'],
|
|
364
|
+
})
|
|
365
|
+
.withPlatform({
|
|
366
|
+
llm: true,
|
|
367
|
+
cache: ['git-status:'],
|
|
368
|
+
analytics: true,
|
|
369
|
+
})
|
|
370
|
+
.withQuotas({
|
|
371
|
+
timeoutMs: 600000,
|
|
372
|
+
memoryMb: 512,
|
|
373
|
+
})
|
|
374
|
+
.build();
|
|
375
|
+
|
|
376
|
+
// Env vars
|
|
377
|
+
const envVars = result.env?.read ?? [];
|
|
378
|
+
expect(envVars).toContain('HOME');
|
|
379
|
+
expect(envVars).toContain('USER');
|
|
380
|
+
expect(envVars).toContain('GIT_*');
|
|
381
|
+
expect(envVars).toContain('KB_*');
|
|
382
|
+
expect(envVars).toContain('OPENAI_API_KEY');
|
|
383
|
+
expect(envVars).toContain('ANTHROPIC_API_KEY');
|
|
384
|
+
|
|
385
|
+
// File system (runtime format)
|
|
386
|
+
const read = result.fs?.read ?? [];
|
|
387
|
+
const write = result.fs?.write ?? [];
|
|
388
|
+
expect(read).toContain('**/.git/**');
|
|
389
|
+
expect(read).toContain('.kb/**');
|
|
390
|
+
expect(read).toContain('.kb/commit/**');
|
|
391
|
+
expect(write).toContain('.kb/**');
|
|
392
|
+
expect(write).toContain('.kb/commit/**');
|
|
393
|
+
|
|
394
|
+
// Platform services
|
|
395
|
+
expect(result.platform?.llm).toBe(true);
|
|
396
|
+
expect(result.platform?.cache).toEqual(['git-status:']);
|
|
397
|
+
expect(result.platform?.analytics).toBe(true);
|
|
398
|
+
|
|
399
|
+
// Quotas
|
|
400
|
+
expect(result.quotas?.timeoutMs).toBe(600000);
|
|
401
|
+
expect(result.quotas?.memoryMb).toBe(512);
|
|
402
|
+
});
|
|
403
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
minimal,
|
|
4
|
+
gitWorkflow,
|
|
5
|
+
npmPublish,
|
|
6
|
+
fullEnv,
|
|
7
|
+
kbPlatform,
|
|
8
|
+
llmAccess,
|
|
9
|
+
vectorStore,
|
|
10
|
+
ciEnvironment,
|
|
11
|
+
} from '../presets';
|
|
12
|
+
|
|
13
|
+
describe('Permission Presets', () => {
|
|
14
|
+
describe('minimal', () => {
|
|
15
|
+
it('should have id and description', () => {
|
|
16
|
+
expect(minimal.id).toBe('minimal');
|
|
17
|
+
expect(minimal.description).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should include basic system env vars', () => {
|
|
21
|
+
const envVars = minimal.permissions.env?.read ?? [];
|
|
22
|
+
expect(envVars).toContain('PATH');
|
|
23
|
+
expect(envVars).toContain('NODE_ENV');
|
|
24
|
+
expect(envVars).toContain('LANG');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should NOT include HOME or USER', () => {
|
|
28
|
+
const envVars = minimal.permissions.env?.read ?? [];
|
|
29
|
+
expect(envVars).not.toContain('HOME');
|
|
30
|
+
expect(envVars).not.toContain('USER');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('gitWorkflow', () => {
|
|
35
|
+
it('should have id and description', () => {
|
|
36
|
+
expect(gitWorkflow.id).toBe('git-workflow');
|
|
37
|
+
expect(gitWorkflow.description).toBeTruthy();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should include HOME for git config', () => {
|
|
41
|
+
const envVars = gitWorkflow.permissions.env?.read ?? [];
|
|
42
|
+
expect(envVars).toContain('HOME');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should include USER for git author', () => {
|
|
46
|
+
const envVars = gitWorkflow.permissions.env?.read ?? [];
|
|
47
|
+
expect(envVars).toContain('USER');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should include GIT_* wildcard', () => {
|
|
51
|
+
const envVars = gitWorkflow.permissions.env?.read ?? [];
|
|
52
|
+
expect(envVars).toContain('GIT_*');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should include SSH env vars for auth', () => {
|
|
56
|
+
const envVars = gitWorkflow.permissions.env?.read ?? [];
|
|
57
|
+
expect(envVars).toContain('SSH_AUTH_SOCK');
|
|
58
|
+
expect(envVars).toContain('SSH_AGENT_PID');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should allow .git directory access', () => {
|
|
62
|
+
const allow = gitWorkflow.permissions.fs?.allow ?? [];
|
|
63
|
+
expect(allow).toContain('**/.git/**');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('npmPublish', () => {
|
|
68
|
+
it('should have id and description', () => {
|
|
69
|
+
expect(npmPublish.id).toBe('npm-publish');
|
|
70
|
+
expect(npmPublish.description).toBeTruthy();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should include HOME for .npmrc', () => {
|
|
74
|
+
const envVars = npmPublish.permissions.env?.read ?? [];
|
|
75
|
+
expect(envVars).toContain('HOME');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should include npm token vars', () => {
|
|
79
|
+
const envVars = npmPublish.permissions.env?.read ?? [];
|
|
80
|
+
expect(envVars).toContain('NPM_TOKEN');
|
|
81
|
+
expect(envVars).toContain('NPM_AUTH_TOKEN');
|
|
82
|
+
expect(envVars).toContain('NODE_AUTH_TOKEN');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should include npm_* wildcard', () => {
|
|
86
|
+
const envVars = npmPublish.permissions.env?.read ?? [];
|
|
87
|
+
expect(envVars).toContain('npm_*');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should allow package.json and lock files', () => {
|
|
91
|
+
const allow = npmPublish.permissions.fs?.allow ?? [];
|
|
92
|
+
expect(allow).toContain('**/package.json');
|
|
93
|
+
expect(allow).toContain('**/package-lock.json');
|
|
94
|
+
expect(allow).toContain('**/pnpm-lock.yaml');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should allow npm registry domains', () => {
|
|
98
|
+
const domains = npmPublish.permissions.network?.fetch ?? [];
|
|
99
|
+
expect(domains).toContain('registry.npmjs.org');
|
|
100
|
+
expect(domains).toContain('npm.pkg.github.com');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('fullEnv', () => {
|
|
105
|
+
it('should have id and description', () => {
|
|
106
|
+
expect(fullEnv.id).toBe('full-env');
|
|
107
|
+
expect(fullEnv.description).toBeTruthy();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should include wildcard for all env vars', () => {
|
|
111
|
+
const envVars = fullEnv.permissions.env?.read ?? [];
|
|
112
|
+
expect(envVars).toContain('*');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('kbPlatform', () => {
|
|
117
|
+
it('should have id and description', () => {
|
|
118
|
+
expect(kbPlatform.id).toBe('kb-platform');
|
|
119
|
+
expect(kbPlatform.description).toBeTruthy();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should include KB_* wildcard', () => {
|
|
123
|
+
const envVars = kbPlatform.permissions.env?.read ?? [];
|
|
124
|
+
expect(envVars).toContain('KB_*');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should allow .kb directory access', () => {
|
|
128
|
+
const allow = kbPlatform.permissions.fs?.allow ?? [];
|
|
129
|
+
expect(allow).toContain('.kb/**');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('llmAccess', () => {
|
|
134
|
+
it('should have id and description', () => {
|
|
135
|
+
expect(llmAccess.id).toBe('llm-access');
|
|
136
|
+
expect(llmAccess.description).toBeTruthy();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should include OpenAI env vars', () => {
|
|
140
|
+
const envVars = llmAccess.permissions.env?.read ?? [];
|
|
141
|
+
expect(envVars).toContain('OPENAI_API_KEY');
|
|
142
|
+
expect(envVars).toContain('OPENAI_ORG_ID');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should include Anthropic env vars', () => {
|
|
146
|
+
const envVars = llmAccess.permissions.env?.read ?? [];
|
|
147
|
+
expect(envVars).toContain('ANTHROPIC_API_KEY');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should allow LLM API domains', () => {
|
|
151
|
+
const domains = llmAccess.permissions.network?.fetch ?? [];
|
|
152
|
+
expect(domains).toContain('api.openai.com');
|
|
153
|
+
expect(domains).toContain('api.anthropic.com');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('vectorStore', () => {
|
|
158
|
+
it('should have id and description', () => {
|
|
159
|
+
expect(vectorStore.id).toBe('vector-store');
|
|
160
|
+
expect(vectorStore.description).toBeTruthy();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should include Qdrant env vars', () => {
|
|
164
|
+
const envVars = vectorStore.permissions.env?.read ?? [];
|
|
165
|
+
expect(envVars).toContain('QDRANT_URL');
|
|
166
|
+
expect(envVars).toContain('QDRANT_API_KEY');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should include Pinecone env vars', () => {
|
|
170
|
+
const envVars = vectorStore.permissions.env?.read ?? [];
|
|
171
|
+
expect(envVars).toContain('PINECONE_API_KEY');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should allow vector store domains', () => {
|
|
175
|
+
const domains = vectorStore.permissions.network?.fetch ?? [];
|
|
176
|
+
expect(domains).toContain('localhost');
|
|
177
|
+
expect(domains).toContain('*.qdrant.io');
|
|
178
|
+
expect(domains).toContain('*.pinecone.io');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('ciEnvironment', () => {
|
|
183
|
+
it('should have id and description', () => {
|
|
184
|
+
expect(ciEnvironment.id).toBe('ci-environment');
|
|
185
|
+
expect(ciEnvironment.description).toBeTruthy();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('should include CI indicator', () => {
|
|
189
|
+
const envVars = ciEnvironment.permissions.env?.read ?? [];
|
|
190
|
+
expect(envVars).toContain('CI');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should include GitHub Actions vars', () => {
|
|
194
|
+
const envVars = ciEnvironment.permissions.env?.read ?? [];
|
|
195
|
+
expect(envVars).toContain('GITHUB_TOKEN');
|
|
196
|
+
expect(envVars).toContain('GITHUB_*');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should include GitLab CI vars', () => {
|
|
200
|
+
const envVars = ciEnvironment.permissions.env?.read ?? [];
|
|
201
|
+
expect(envVars).toContain('GITLAB_*');
|
|
202
|
+
expect(envVars).toContain('CI_JOB_TOKEN');
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|