@objectstack/core 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +58 -0
- package/CHANGELOG.md +12 -0
- package/dist/index.cjs +4294 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1777 -0
- package/dist/index.d.ts +1776 -21
- package/dist/index.js +4246 -23
- package/dist/index.js.map +1 -0
- package/package.json +4 -4
- package/tsconfig.json +1 -3
- package/dist/api-registry-plugin.d.ts +0 -54
- package/dist/api-registry-plugin.d.ts.map +0 -1
- package/dist/api-registry-plugin.js +0 -53
- package/dist/api-registry-plugin.test.d.ts +0 -2
- package/dist/api-registry-plugin.test.d.ts.map +0 -1
- package/dist/api-registry-plugin.test.js +0 -334
- package/dist/api-registry.d.ts +0 -259
- package/dist/api-registry.d.ts.map +0 -1
- package/dist/api-registry.js +0 -600
- package/dist/api-registry.test.d.ts +0 -2
- package/dist/api-registry.test.d.ts.map +0 -1
- package/dist/api-registry.test.js +0 -957
- package/dist/contracts/data-engine.d.ts +0 -62
- package/dist/contracts/data-engine.d.ts.map +0 -1
- package/dist/contracts/data-engine.js +0 -1
- package/dist/contracts/http-server.d.ts +0 -119
- package/dist/contracts/http-server.d.ts.map +0 -1
- package/dist/contracts/http-server.js +0 -11
- package/dist/contracts/logger.d.ts +0 -63
- package/dist/contracts/logger.d.ts.map +0 -1
- package/dist/contracts/logger.js +0 -1
- package/dist/dependency-resolver.d.ts +0 -62
- package/dist/dependency-resolver.d.ts.map +0 -1
- package/dist/dependency-resolver.js +0 -317
- package/dist/dependency-resolver.test.d.ts +0 -2
- package/dist/dependency-resolver.test.d.ts.map +0 -1
- package/dist/dependency-resolver.test.js +0 -241
- package/dist/health-monitor.d.ts +0 -65
- package/dist/health-monitor.d.ts.map +0 -1
- package/dist/health-monitor.js +0 -269
- package/dist/health-monitor.test.d.ts +0 -2
- package/dist/health-monitor.test.d.ts.map +0 -1
- package/dist/health-monitor.test.js +0 -68
- package/dist/hot-reload.d.ts +0 -79
- package/dist/hot-reload.d.ts.map +0 -1
- package/dist/hot-reload.js +0 -313
- package/dist/index.d.ts.map +0 -1
- package/dist/kernel-base.d.ts +0 -84
- package/dist/kernel-base.d.ts.map +0 -1
- package/dist/kernel-base.js +0 -219
- package/dist/kernel.d.ts +0 -113
- package/dist/kernel.d.ts.map +0 -1
- package/dist/kernel.js +0 -472
- package/dist/kernel.test.d.ts +0 -2
- package/dist/kernel.test.d.ts.map +0 -1
- package/dist/kernel.test.js +0 -414
- package/dist/lite-kernel.d.ts +0 -55
- package/dist/lite-kernel.d.ts.map +0 -1
- package/dist/lite-kernel.js +0 -112
- package/dist/lite-kernel.test.d.ts +0 -2
- package/dist/lite-kernel.test.d.ts.map +0 -1
- package/dist/lite-kernel.test.js +0 -161
- package/dist/logger.d.ts +0 -71
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -312
- package/dist/logger.test.d.ts +0 -2
- package/dist/logger.test.d.ts.map +0 -1
- package/dist/logger.test.js +0 -92
- package/dist/plugin-loader.d.ts +0 -164
- package/dist/plugin-loader.d.ts.map +0 -1
- package/dist/plugin-loader.js +0 -319
- package/dist/plugin-loader.test.d.ts +0 -2
- package/dist/plugin-loader.test.d.ts.map +0 -1
- package/dist/plugin-loader.test.js +0 -348
- package/dist/qa/adapter.d.ts +0 -14
- package/dist/qa/adapter.d.ts.map +0 -1
- package/dist/qa/adapter.js +0 -1
- package/dist/qa/http-adapter.d.ts +0 -16
- package/dist/qa/http-adapter.d.ts.map +0 -1
- package/dist/qa/http-adapter.js +0 -107
- package/dist/qa/index.d.ts +0 -4
- package/dist/qa/index.d.ts.map +0 -1
- package/dist/qa/index.js +0 -3
- package/dist/qa/runner.d.ts +0 -27
- package/dist/qa/runner.d.ts.map +0 -1
- package/dist/qa/runner.js +0 -157
- package/dist/security/index.d.ts +0 -17
- package/dist/security/index.d.ts.map +0 -1
- package/dist/security/index.js +0 -17
- package/dist/security/permission-manager.d.ts +0 -96
- package/dist/security/permission-manager.d.ts.map +0 -1
- package/dist/security/permission-manager.js +0 -235
- package/dist/security/permission-manager.test.d.ts +0 -2
- package/dist/security/permission-manager.test.d.ts.map +0 -1
- package/dist/security/permission-manager.test.js +0 -220
- package/dist/security/plugin-config-validator.d.ts +0 -79
- package/dist/security/plugin-config-validator.d.ts.map +0 -1
- package/dist/security/plugin-config-validator.js +0 -166
- package/dist/security/plugin-config-validator.test.d.ts +0 -2
- package/dist/security/plugin-config-validator.test.d.ts.map +0 -1
- package/dist/security/plugin-config-validator.test.js +0 -223
- package/dist/security/plugin-permission-enforcer.d.ts +0 -154
- package/dist/security/plugin-permission-enforcer.d.ts.map +0 -1
- package/dist/security/plugin-permission-enforcer.js +0 -323
- package/dist/security/plugin-permission-enforcer.test.d.ts +0 -2
- package/dist/security/plugin-permission-enforcer.test.d.ts.map +0 -1
- package/dist/security/plugin-permission-enforcer.test.js +0 -205
- package/dist/security/plugin-signature-verifier.d.ts +0 -96
- package/dist/security/plugin-signature-verifier.d.ts.map +0 -1
- package/dist/security/plugin-signature-verifier.js +0 -250
- package/dist/security/sandbox-runtime.d.ts +0 -115
- package/dist/security/sandbox-runtime.d.ts.map +0 -1
- package/dist/security/sandbox-runtime.js +0 -311
- package/dist/security/security-scanner.d.ts +0 -92
- package/dist/security/security-scanner.d.ts.map +0 -1
- package/dist/security/security-scanner.js +0 -273
- package/dist/types.d.ts +0 -89
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
- package/dist/utils/env.d.ts +0 -20
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/env.js +0 -46
- package/dist/utils/env.test.d.ts +0 -2
- package/dist/utils/env.test.d.ts.map +0 -1
- package/dist/utils/env.test.js +0 -52
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { PluginPermissionManager } from './permission-manager.js';
|
|
3
|
-
import { createLogger } from '../logger.js';
|
|
4
|
-
describe('PluginPermissionManager', () => {
|
|
5
|
-
let manager;
|
|
6
|
-
let logger;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
logger = createLogger({ level: 'silent' });
|
|
9
|
-
manager = new PluginPermissionManager(logger);
|
|
10
|
-
});
|
|
11
|
-
describe('registerPermissions', () => {
|
|
12
|
-
it('should register permissions for a plugin', () => {
|
|
13
|
-
const permissionSet = {
|
|
14
|
-
permissions: [
|
|
15
|
-
{
|
|
16
|
-
id: 'read-data',
|
|
17
|
-
resource: 'data.object',
|
|
18
|
-
actions: ['read'],
|
|
19
|
-
scope: 'plugin',
|
|
20
|
-
description: 'Read object data',
|
|
21
|
-
required: true,
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
defaultGrant: 'prompt',
|
|
25
|
-
};
|
|
26
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
27
|
-
const permissions = manager.getPluginPermissions('test-plugin');
|
|
28
|
-
expect(permissions).toHaveLength(1);
|
|
29
|
-
expect(permissions[0].id).toBe('read-data');
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
describe('grantPermission', () => {
|
|
33
|
-
it('should grant a permission to a plugin', () => {
|
|
34
|
-
const permissionSet = {
|
|
35
|
-
permissions: [
|
|
36
|
-
{
|
|
37
|
-
id: 'read-data',
|
|
38
|
-
resource: 'data.object',
|
|
39
|
-
actions: ['read'],
|
|
40
|
-
scope: 'plugin',
|
|
41
|
-
description: 'Read object data',
|
|
42
|
-
required: true,
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
defaultGrant: 'prompt',
|
|
46
|
-
};
|
|
47
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
48
|
-
manager.grantPermission('test-plugin', 'read-data');
|
|
49
|
-
expect(manager.hasPermission('test-plugin', 'read-data')).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
it('should throw error for non-existent permission', () => {
|
|
52
|
-
const permissionSet = {
|
|
53
|
-
permissions: [],
|
|
54
|
-
defaultGrant: 'prompt',
|
|
55
|
-
};
|
|
56
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
57
|
-
expect(() => {
|
|
58
|
-
manager.grantPermission('test-plugin', 'invalid-permission');
|
|
59
|
-
}).toThrow();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
describe('revokePermission', () => {
|
|
63
|
-
it('should revoke a permission from a plugin', () => {
|
|
64
|
-
const permissionSet = {
|
|
65
|
-
permissions: [
|
|
66
|
-
{
|
|
67
|
-
id: 'read-data',
|
|
68
|
-
resource: 'data.object',
|
|
69
|
-
actions: ['read'],
|
|
70
|
-
scope: 'plugin',
|
|
71
|
-
description: 'Read object data',
|
|
72
|
-
required: true,
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
defaultGrant: 'prompt',
|
|
76
|
-
};
|
|
77
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
78
|
-
manager.grantPermission('test-plugin', 'read-data');
|
|
79
|
-
manager.revokePermission('test-plugin', 'read-data');
|
|
80
|
-
expect(manager.hasPermission('test-plugin', 'read-data')).toBe(false);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
describe('checkAccess', () => {
|
|
84
|
-
it('should allow access when permission is granted', () => {
|
|
85
|
-
const permissionSet = {
|
|
86
|
-
permissions: [
|
|
87
|
-
{
|
|
88
|
-
id: 'read-data',
|
|
89
|
-
resource: 'data.object',
|
|
90
|
-
actions: ['read'],
|
|
91
|
-
scope: 'plugin',
|
|
92
|
-
description: 'Read object data',
|
|
93
|
-
required: true,
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
defaultGrant: 'prompt',
|
|
97
|
-
};
|
|
98
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
99
|
-
manager.grantPermission('test-plugin', 'read-data');
|
|
100
|
-
const result = manager.checkAccess('test-plugin', 'data.object', 'read');
|
|
101
|
-
expect(result.allowed).toBe(true);
|
|
102
|
-
});
|
|
103
|
-
it('should deny access when permission is not granted', () => {
|
|
104
|
-
const permissionSet = {
|
|
105
|
-
permissions: [
|
|
106
|
-
{
|
|
107
|
-
id: 'read-data',
|
|
108
|
-
resource: 'data.object',
|
|
109
|
-
actions: ['read'],
|
|
110
|
-
scope: 'plugin',
|
|
111
|
-
description: 'Read object data',
|
|
112
|
-
required: true,
|
|
113
|
-
},
|
|
114
|
-
],
|
|
115
|
-
defaultGrant: 'prompt',
|
|
116
|
-
};
|
|
117
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
118
|
-
const result = manager.checkAccess('test-plugin', 'data.object', 'read');
|
|
119
|
-
expect(result.allowed).toBe(false);
|
|
120
|
-
});
|
|
121
|
-
it('should deny access when permission does not exist', () => {
|
|
122
|
-
const permissionSet = {
|
|
123
|
-
permissions: [],
|
|
124
|
-
defaultGrant: 'prompt',
|
|
125
|
-
};
|
|
126
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
127
|
-
const result = manager.checkAccess('test-plugin', 'data.object', 'read');
|
|
128
|
-
expect(result.allowed).toBe(false);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
describe('getMissingPermissions', () => {
|
|
132
|
-
it('should return missing required permissions', () => {
|
|
133
|
-
const permissionSet = {
|
|
134
|
-
permissions: [
|
|
135
|
-
{
|
|
136
|
-
id: 'read-data',
|
|
137
|
-
resource: 'data.object',
|
|
138
|
-
actions: ['read'],
|
|
139
|
-
scope: 'plugin',
|
|
140
|
-
description: 'Read object data',
|
|
141
|
-
required: true,
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
id: 'write-data',
|
|
145
|
-
resource: 'data.object',
|
|
146
|
-
actions: ['create', 'update'],
|
|
147
|
-
scope: 'plugin',
|
|
148
|
-
description: 'Write object data',
|
|
149
|
-
required: true,
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
defaultGrant: 'prompt',
|
|
153
|
-
};
|
|
154
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
155
|
-
manager.grantPermission('test-plugin', 'read-data');
|
|
156
|
-
const missing = manager.getMissingPermissions('test-plugin');
|
|
157
|
-
expect(missing).toHaveLength(1);
|
|
158
|
-
expect(missing[0].id).toBe('write-data');
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
describe('hasAllRequiredPermissions', () => {
|
|
162
|
-
it('should return true when all required permissions are granted', () => {
|
|
163
|
-
const permissionSet = {
|
|
164
|
-
permissions: [
|
|
165
|
-
{
|
|
166
|
-
id: 'read-data',
|
|
167
|
-
resource: 'data.object',
|
|
168
|
-
actions: ['read'],
|
|
169
|
-
scope: 'plugin',
|
|
170
|
-
description: 'Read object data',
|
|
171
|
-
required: true,
|
|
172
|
-
},
|
|
173
|
-
],
|
|
174
|
-
defaultGrant: 'prompt',
|
|
175
|
-
};
|
|
176
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
177
|
-
manager.grantPermission('test-plugin', 'read-data');
|
|
178
|
-
expect(manager.hasAllRequiredPermissions('test-plugin')).toBe(true);
|
|
179
|
-
});
|
|
180
|
-
it('should return false when required permissions are missing', () => {
|
|
181
|
-
const permissionSet = {
|
|
182
|
-
permissions: [
|
|
183
|
-
{
|
|
184
|
-
id: 'read-data',
|
|
185
|
-
resource: 'data.object',
|
|
186
|
-
actions: ['read'],
|
|
187
|
-
scope: 'plugin',
|
|
188
|
-
description: 'Read object data',
|
|
189
|
-
required: true,
|
|
190
|
-
},
|
|
191
|
-
],
|
|
192
|
-
defaultGrant: 'prompt',
|
|
193
|
-
};
|
|
194
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
195
|
-
expect(manager.hasAllRequiredPermissions('test-plugin')).toBe(false);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
describe('clearPluginPermissions', () => {
|
|
199
|
-
it('should clear all permissions for a plugin', () => {
|
|
200
|
-
const permissionSet = {
|
|
201
|
-
permissions: [
|
|
202
|
-
{
|
|
203
|
-
id: 'read-data',
|
|
204
|
-
resource: 'data.object',
|
|
205
|
-
actions: ['read'],
|
|
206
|
-
scope: 'plugin',
|
|
207
|
-
description: 'Read object data',
|
|
208
|
-
required: true,
|
|
209
|
-
},
|
|
210
|
-
],
|
|
211
|
-
defaultGrant: 'prompt',
|
|
212
|
-
};
|
|
213
|
-
manager.registerPermissions('test-plugin', permissionSet);
|
|
214
|
-
manager.grantPermission('test-plugin', 'read-data');
|
|
215
|
-
manager.clearPluginPermissions('test-plugin');
|
|
216
|
-
expect(manager.getPluginPermissions('test-plugin')).toHaveLength(0);
|
|
217
|
-
expect(manager.getGrantedPermissions('test-plugin')).toHaveLength(0);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type { Logger } from '@objectstack/spec/contracts';
|
|
2
|
-
import type { PluginMetadata } from '../plugin-loader.js';
|
|
3
|
-
/**
|
|
4
|
-
* Plugin Configuration Validator
|
|
5
|
-
*
|
|
6
|
-
* Validates plugin configurations against Zod schemas to ensure:
|
|
7
|
-
* 1. Type safety - all config values have correct types
|
|
8
|
-
* 2. Business rules - values meet constraints (min/max, regex, etc.)
|
|
9
|
-
* 3. Required fields - all mandatory configuration is provided
|
|
10
|
-
* 4. Default values - missing optional fields get defaults
|
|
11
|
-
*
|
|
12
|
-
* Architecture:
|
|
13
|
-
* - Uses Zod for runtime validation
|
|
14
|
-
* - Provides detailed error messages with field paths
|
|
15
|
-
* - Supports nested configuration objects
|
|
16
|
-
* - Allows partial validation for incremental updates
|
|
17
|
-
*
|
|
18
|
-
* Usage:
|
|
19
|
-
* ```typescript
|
|
20
|
-
* const validator = new PluginConfigValidator(logger);
|
|
21
|
-
* const validConfig = validator.validatePluginConfig(plugin, userConfig);
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export declare class PluginConfigValidator {
|
|
25
|
-
private logger;
|
|
26
|
-
constructor(logger: Logger);
|
|
27
|
-
/**
|
|
28
|
-
* Validate plugin configuration against its Zod schema
|
|
29
|
-
*
|
|
30
|
-
* @param plugin - Plugin metadata with configSchema
|
|
31
|
-
* @param config - User-provided configuration
|
|
32
|
-
* @returns Validated and typed configuration
|
|
33
|
-
* @throws Error with detailed validation errors
|
|
34
|
-
*/
|
|
35
|
-
validatePluginConfig<T = any>(plugin: PluginMetadata, config: any): T;
|
|
36
|
-
/**
|
|
37
|
-
* Validate partial configuration (for incremental updates)
|
|
38
|
-
*
|
|
39
|
-
* @param plugin - Plugin metadata
|
|
40
|
-
* @param partialConfig - Partial configuration to validate
|
|
41
|
-
* @returns Validated partial configuration
|
|
42
|
-
*/
|
|
43
|
-
validatePartialConfig<T = any>(plugin: PluginMetadata, partialConfig: any): Partial<T>;
|
|
44
|
-
/**
|
|
45
|
-
* Get default configuration from schema
|
|
46
|
-
*
|
|
47
|
-
* @param plugin - Plugin metadata
|
|
48
|
-
* @returns Default configuration object
|
|
49
|
-
*/
|
|
50
|
-
getDefaultConfig<T = any>(plugin: PluginMetadata): T | undefined;
|
|
51
|
-
/**
|
|
52
|
-
* Check if configuration is valid without throwing
|
|
53
|
-
*
|
|
54
|
-
* @param plugin - Plugin metadata
|
|
55
|
-
* @param config - Configuration to check
|
|
56
|
-
* @returns True if valid, false otherwise
|
|
57
|
-
*/
|
|
58
|
-
isConfigValid(plugin: PluginMetadata, config: any): boolean;
|
|
59
|
-
/**
|
|
60
|
-
* Get configuration errors without throwing
|
|
61
|
-
*
|
|
62
|
-
* @param plugin - Plugin metadata
|
|
63
|
-
* @param config - Configuration to check
|
|
64
|
-
* @returns Array of validation errors, or empty array if valid
|
|
65
|
-
*/
|
|
66
|
-
getConfigErrors(plugin: PluginMetadata, config: any): Array<{
|
|
67
|
-
path: string;
|
|
68
|
-
message: string;
|
|
69
|
-
}>;
|
|
70
|
-
private formatZodErrors;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Create a plugin config validator
|
|
74
|
-
*
|
|
75
|
-
* @param logger - Logger instance
|
|
76
|
-
* @returns Plugin config validator
|
|
77
|
-
*/
|
|
78
|
-
export declare function createPluginConfigValidator(logger: Logger): PluginConfigValidator;
|
|
79
|
-
//# sourceMappingURL=plugin-config-validator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-config-validator.d.ts","sourceRoot":"","sources":["../../src/security/plugin-config-validator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAI1B;;;;;;;OAOG;IACH,oBAAoB,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAqCrE;;;;;;OAMG;IACH,qBAAqB,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IA4BtF;;;;;OAKG;IACH,gBAAgB,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,SAAS;IAiBhE;;;;;;OAMG;IACH,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO;IAS3D;;;;;;OAMG;IACH,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;IAgB5F,OAAO,CAAC,eAAe;CAMxB;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,CAEjF"}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
/**
|
|
3
|
-
* Plugin Configuration Validator
|
|
4
|
-
*
|
|
5
|
-
* Validates plugin configurations against Zod schemas to ensure:
|
|
6
|
-
* 1. Type safety - all config values have correct types
|
|
7
|
-
* 2. Business rules - values meet constraints (min/max, regex, etc.)
|
|
8
|
-
* 3. Required fields - all mandatory configuration is provided
|
|
9
|
-
* 4. Default values - missing optional fields get defaults
|
|
10
|
-
*
|
|
11
|
-
* Architecture:
|
|
12
|
-
* - Uses Zod for runtime validation
|
|
13
|
-
* - Provides detailed error messages with field paths
|
|
14
|
-
* - Supports nested configuration objects
|
|
15
|
-
* - Allows partial validation for incremental updates
|
|
16
|
-
*
|
|
17
|
-
* Usage:
|
|
18
|
-
* ```typescript
|
|
19
|
-
* const validator = new PluginConfigValidator(logger);
|
|
20
|
-
* const validConfig = validator.validatePluginConfig(plugin, userConfig);
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export class PluginConfigValidator {
|
|
24
|
-
constructor(logger) {
|
|
25
|
-
this.logger = logger;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Validate plugin configuration against its Zod schema
|
|
29
|
-
*
|
|
30
|
-
* @param plugin - Plugin metadata with configSchema
|
|
31
|
-
* @param config - User-provided configuration
|
|
32
|
-
* @returns Validated and typed configuration
|
|
33
|
-
* @throws Error with detailed validation errors
|
|
34
|
-
*/
|
|
35
|
-
validatePluginConfig(plugin, config) {
|
|
36
|
-
if (!plugin.configSchema) {
|
|
37
|
-
this.logger.debug(`Plugin ${plugin.name} has no config schema - skipping validation`);
|
|
38
|
-
return config;
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
// Use Zod to parse and validate
|
|
42
|
-
const validatedConfig = plugin.configSchema.parse(config);
|
|
43
|
-
this.logger.debug(`✅ Plugin config validated: ${plugin.name}`, {
|
|
44
|
-
plugin: plugin.name,
|
|
45
|
-
configKeys: Object.keys(config || {}).length,
|
|
46
|
-
});
|
|
47
|
-
return validatedConfig;
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
if (error instanceof z.ZodError) {
|
|
51
|
-
const formattedErrors = this.formatZodErrors(error);
|
|
52
|
-
const errorMessage = [
|
|
53
|
-
`Plugin ${plugin.name} configuration validation failed:`,
|
|
54
|
-
...formattedErrors.map(e => ` - ${e.path}: ${e.message}`),
|
|
55
|
-
].join('\n');
|
|
56
|
-
this.logger.error(errorMessage, undefined, {
|
|
57
|
-
plugin: plugin.name,
|
|
58
|
-
errors: formattedErrors,
|
|
59
|
-
});
|
|
60
|
-
throw new Error(errorMessage);
|
|
61
|
-
}
|
|
62
|
-
// Re-throw other errors
|
|
63
|
-
throw error;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Validate partial configuration (for incremental updates)
|
|
68
|
-
*
|
|
69
|
-
* @param plugin - Plugin metadata
|
|
70
|
-
* @param partialConfig - Partial configuration to validate
|
|
71
|
-
* @returns Validated partial configuration
|
|
72
|
-
*/
|
|
73
|
-
validatePartialConfig(plugin, partialConfig) {
|
|
74
|
-
if (!plugin.configSchema) {
|
|
75
|
-
return partialConfig;
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
// Use Zod's partial() method for partial validation
|
|
79
|
-
// Cast to ZodObject to access partial() method
|
|
80
|
-
const partialSchema = plugin.configSchema.partial();
|
|
81
|
-
const validatedConfig = partialSchema.parse(partialConfig);
|
|
82
|
-
this.logger.debug(`✅ Partial config validated: ${plugin.name}`);
|
|
83
|
-
return validatedConfig;
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
if (error instanceof z.ZodError) {
|
|
87
|
-
const formattedErrors = this.formatZodErrors(error);
|
|
88
|
-
const errorMessage = [
|
|
89
|
-
`Plugin ${plugin.name} partial configuration validation failed:`,
|
|
90
|
-
...formattedErrors.map(e => ` - ${e.path}: ${e.message}`),
|
|
91
|
-
].join('\n');
|
|
92
|
-
throw new Error(errorMessage);
|
|
93
|
-
}
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Get default configuration from schema
|
|
99
|
-
*
|
|
100
|
-
* @param plugin - Plugin metadata
|
|
101
|
-
* @returns Default configuration object
|
|
102
|
-
*/
|
|
103
|
-
getDefaultConfig(plugin) {
|
|
104
|
-
if (!plugin.configSchema) {
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
try {
|
|
108
|
-
// Parse empty object to get defaults
|
|
109
|
-
const defaults = plugin.configSchema.parse({});
|
|
110
|
-
this.logger.debug(`Default config extracted: ${plugin.name}`);
|
|
111
|
-
return defaults;
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
// Schema may require some fields - return undefined
|
|
115
|
-
this.logger.debug(`No default config available: ${plugin.name}`);
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Check if configuration is valid without throwing
|
|
121
|
-
*
|
|
122
|
-
* @param plugin - Plugin metadata
|
|
123
|
-
* @param config - Configuration to check
|
|
124
|
-
* @returns True if valid, false otherwise
|
|
125
|
-
*/
|
|
126
|
-
isConfigValid(plugin, config) {
|
|
127
|
-
if (!plugin.configSchema) {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
const result = plugin.configSchema.safeParse(config);
|
|
131
|
-
return result.success;
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Get configuration errors without throwing
|
|
135
|
-
*
|
|
136
|
-
* @param plugin - Plugin metadata
|
|
137
|
-
* @param config - Configuration to check
|
|
138
|
-
* @returns Array of validation errors, or empty array if valid
|
|
139
|
-
*/
|
|
140
|
-
getConfigErrors(plugin, config) {
|
|
141
|
-
if (!plugin.configSchema) {
|
|
142
|
-
return [];
|
|
143
|
-
}
|
|
144
|
-
const result = plugin.configSchema.safeParse(config);
|
|
145
|
-
if (result.success) {
|
|
146
|
-
return [];
|
|
147
|
-
}
|
|
148
|
-
return this.formatZodErrors(result.error);
|
|
149
|
-
}
|
|
150
|
-
// Private methods
|
|
151
|
-
formatZodErrors(error) {
|
|
152
|
-
return error.issues.map((e) => ({
|
|
153
|
-
path: e.path.join('.') || 'root',
|
|
154
|
-
message: e.message,
|
|
155
|
-
}));
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Create a plugin config validator
|
|
160
|
-
*
|
|
161
|
-
* @param logger - Logger instance
|
|
162
|
-
* @returns Plugin config validator
|
|
163
|
-
*/
|
|
164
|
-
export function createPluginConfigValidator(logger) {
|
|
165
|
-
return new PluginConfigValidator(logger);
|
|
166
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-config-validator.test.d.ts","sourceRoot":"","sources":["../../src/security/plugin-config-validator.test.ts"],"names":[],"mappings":""}
|