@objectstack/core 1.0.4 → 1.0.6

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.
Files changed (127) hide show
  1. package/.turbo/turbo-build.log +22 -0
  2. package/CHANGELOG.md +19 -0
  3. package/dist/index.cjs +4304 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +1777 -0
  6. package/dist/index.d.ts +1776 -21
  7. package/dist/index.js +4246 -23
  8. package/dist/index.js.map +1 -0
  9. package/package.json +5 -5
  10. package/src/logger.ts +2 -2
  11. package/src/security/plugin-signature-verifier.ts +12 -11
  12. package/tsconfig.json +1 -3
  13. package/dist/api-registry-plugin.d.ts +0 -54
  14. package/dist/api-registry-plugin.d.ts.map +0 -1
  15. package/dist/api-registry-plugin.js +0 -53
  16. package/dist/api-registry-plugin.test.d.ts +0 -2
  17. package/dist/api-registry-plugin.test.d.ts.map +0 -1
  18. package/dist/api-registry-plugin.test.js +0 -334
  19. package/dist/api-registry.d.ts +0 -259
  20. package/dist/api-registry.d.ts.map +0 -1
  21. package/dist/api-registry.js +0 -600
  22. package/dist/api-registry.test.d.ts +0 -2
  23. package/dist/api-registry.test.d.ts.map +0 -1
  24. package/dist/api-registry.test.js +0 -957
  25. package/dist/contracts/data-engine.d.ts +0 -62
  26. package/dist/contracts/data-engine.d.ts.map +0 -1
  27. package/dist/contracts/data-engine.js +0 -1
  28. package/dist/contracts/http-server.d.ts +0 -119
  29. package/dist/contracts/http-server.d.ts.map +0 -1
  30. package/dist/contracts/http-server.js +0 -11
  31. package/dist/contracts/logger.d.ts +0 -63
  32. package/dist/contracts/logger.d.ts.map +0 -1
  33. package/dist/contracts/logger.js +0 -1
  34. package/dist/dependency-resolver.d.ts +0 -62
  35. package/dist/dependency-resolver.d.ts.map +0 -1
  36. package/dist/dependency-resolver.js +0 -317
  37. package/dist/dependency-resolver.test.d.ts +0 -2
  38. package/dist/dependency-resolver.test.d.ts.map +0 -1
  39. package/dist/dependency-resolver.test.js +0 -241
  40. package/dist/health-monitor.d.ts +0 -65
  41. package/dist/health-monitor.d.ts.map +0 -1
  42. package/dist/health-monitor.js +0 -269
  43. package/dist/health-monitor.test.d.ts +0 -2
  44. package/dist/health-monitor.test.d.ts.map +0 -1
  45. package/dist/health-monitor.test.js +0 -68
  46. package/dist/hot-reload.d.ts +0 -79
  47. package/dist/hot-reload.d.ts.map +0 -1
  48. package/dist/hot-reload.js +0 -313
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/kernel-base.d.ts +0 -84
  51. package/dist/kernel-base.d.ts.map +0 -1
  52. package/dist/kernel-base.js +0 -219
  53. package/dist/kernel.d.ts +0 -113
  54. package/dist/kernel.d.ts.map +0 -1
  55. package/dist/kernel.js +0 -472
  56. package/dist/kernel.test.d.ts +0 -2
  57. package/dist/kernel.test.d.ts.map +0 -1
  58. package/dist/kernel.test.js +0 -414
  59. package/dist/lite-kernel.d.ts +0 -55
  60. package/dist/lite-kernel.d.ts.map +0 -1
  61. package/dist/lite-kernel.js +0 -112
  62. package/dist/lite-kernel.test.d.ts +0 -2
  63. package/dist/lite-kernel.test.d.ts.map +0 -1
  64. package/dist/lite-kernel.test.js +0 -161
  65. package/dist/logger.d.ts +0 -71
  66. package/dist/logger.d.ts.map +0 -1
  67. package/dist/logger.js +0 -312
  68. package/dist/logger.test.d.ts +0 -2
  69. package/dist/logger.test.d.ts.map +0 -1
  70. package/dist/logger.test.js +0 -92
  71. package/dist/plugin-loader.d.ts +0 -164
  72. package/dist/plugin-loader.d.ts.map +0 -1
  73. package/dist/plugin-loader.js +0 -319
  74. package/dist/plugin-loader.test.d.ts +0 -2
  75. package/dist/plugin-loader.test.d.ts.map +0 -1
  76. package/dist/plugin-loader.test.js +0 -348
  77. package/dist/qa/adapter.d.ts +0 -14
  78. package/dist/qa/adapter.d.ts.map +0 -1
  79. package/dist/qa/adapter.js +0 -1
  80. package/dist/qa/http-adapter.d.ts +0 -16
  81. package/dist/qa/http-adapter.d.ts.map +0 -1
  82. package/dist/qa/http-adapter.js +0 -107
  83. package/dist/qa/index.d.ts +0 -4
  84. package/dist/qa/index.d.ts.map +0 -1
  85. package/dist/qa/index.js +0 -3
  86. package/dist/qa/runner.d.ts +0 -27
  87. package/dist/qa/runner.d.ts.map +0 -1
  88. package/dist/qa/runner.js +0 -157
  89. package/dist/security/index.d.ts +0 -17
  90. package/dist/security/index.d.ts.map +0 -1
  91. package/dist/security/index.js +0 -17
  92. package/dist/security/permission-manager.d.ts +0 -96
  93. package/dist/security/permission-manager.d.ts.map +0 -1
  94. package/dist/security/permission-manager.js +0 -235
  95. package/dist/security/permission-manager.test.d.ts +0 -2
  96. package/dist/security/permission-manager.test.d.ts.map +0 -1
  97. package/dist/security/permission-manager.test.js +0 -220
  98. package/dist/security/plugin-config-validator.d.ts +0 -79
  99. package/dist/security/plugin-config-validator.d.ts.map +0 -1
  100. package/dist/security/plugin-config-validator.js +0 -166
  101. package/dist/security/plugin-config-validator.test.d.ts +0 -2
  102. package/dist/security/plugin-config-validator.test.d.ts.map +0 -1
  103. package/dist/security/plugin-config-validator.test.js +0 -223
  104. package/dist/security/plugin-permission-enforcer.d.ts +0 -154
  105. package/dist/security/plugin-permission-enforcer.d.ts.map +0 -1
  106. package/dist/security/plugin-permission-enforcer.js +0 -323
  107. package/dist/security/plugin-permission-enforcer.test.d.ts +0 -2
  108. package/dist/security/plugin-permission-enforcer.test.d.ts.map +0 -1
  109. package/dist/security/plugin-permission-enforcer.test.js +0 -205
  110. package/dist/security/plugin-signature-verifier.d.ts +0 -96
  111. package/dist/security/plugin-signature-verifier.d.ts.map +0 -1
  112. package/dist/security/plugin-signature-verifier.js +0 -250
  113. package/dist/security/sandbox-runtime.d.ts +0 -115
  114. package/dist/security/sandbox-runtime.d.ts.map +0 -1
  115. package/dist/security/sandbox-runtime.js +0 -311
  116. package/dist/security/security-scanner.d.ts +0 -92
  117. package/dist/security/security-scanner.d.ts.map +0 -1
  118. package/dist/security/security-scanner.js +0 -273
  119. package/dist/types.d.ts +0 -89
  120. package/dist/types.d.ts.map +0 -1
  121. package/dist/types.js +0 -1
  122. package/dist/utils/env.d.ts +0 -20
  123. package/dist/utils/env.d.ts.map +0 -1
  124. package/dist/utils/env.js +0 -46
  125. package/dist/utils/env.test.d.ts +0 -2
  126. package/dist/utils/env.test.d.ts.map +0 -1
  127. package/dist/utils/env.test.js +0 -52
@@ -1,323 +0,0 @@
1
- /**
2
- * Plugin Permission Enforcer
3
- *
4
- * Implements capability-based security model to enforce:
5
- * 1. Service access control - which services a plugin can use
6
- * 2. Hook restrictions - which hooks a plugin can trigger
7
- * 3. File system permissions - what files a plugin can read/write
8
- * 4. Network permissions - what URLs a plugin can access
9
- *
10
- * Architecture:
11
- * - Uses capability declarations from plugin manifest
12
- * - Checks permissions before allowing operations
13
- * - Logs all permission denials for security audit
14
- * - Supports allowlist and denylist patterns
15
- *
16
- * Security Model:
17
- * - Principle of least privilege - plugins get minimal permissions
18
- * - Explicit declaration - all capabilities must be declared
19
- * - Runtime enforcement - checks happen at operation time
20
- * - Audit trail - all denials are logged
21
- *
22
- * Usage:
23
- * ```typescript
24
- * const enforcer = new PluginPermissionEnforcer(logger);
25
- * enforcer.registerPluginPermissions(pluginName, capabilities);
26
- * enforcer.enforceServiceAccess(pluginName, 'database');
27
- * ```
28
- */
29
- export class PluginPermissionEnforcer {
30
- constructor(logger) {
31
- this.permissionRegistry = new Map();
32
- this.capabilityRegistry = new Map();
33
- this.logger = logger;
34
- }
35
- /**
36
- * Register plugin capabilities and build permission set
37
- *
38
- * @param pluginName - Plugin identifier
39
- * @param capabilities - Array of capability declarations
40
- */
41
- registerPluginPermissions(pluginName, capabilities) {
42
- this.capabilityRegistry.set(pluginName, capabilities);
43
- const permissions = {
44
- canAccessService: (service) => this.checkServiceAccess(capabilities, service),
45
- canTriggerHook: (hook) => this.checkHookAccess(capabilities, hook),
46
- canReadFile: (path) => this.checkFileRead(capabilities, path),
47
- canWriteFile: (path) => this.checkFileWrite(capabilities, path),
48
- canNetworkRequest: (url) => this.checkNetworkAccess(capabilities, url),
49
- };
50
- this.permissionRegistry.set(pluginName, permissions);
51
- this.logger.info(`Permissions registered for plugin: ${pluginName}`, {
52
- plugin: pluginName,
53
- capabilityCount: capabilities.length,
54
- });
55
- }
56
- /**
57
- * Enforce service access permission
58
- *
59
- * @param pluginName - Plugin requesting access
60
- * @param serviceName - Service to access
61
- * @throws Error if permission denied
62
- */
63
- enforceServiceAccess(pluginName, serviceName) {
64
- const result = this.checkPermission(pluginName, (perms) => perms.canAccessService(serviceName));
65
- if (!result.allowed) {
66
- const error = `Permission denied: Plugin ${pluginName} cannot access service ${serviceName}`;
67
- this.logger.warn(error, {
68
- plugin: pluginName,
69
- service: serviceName,
70
- reason: result.reason,
71
- });
72
- throw new Error(error);
73
- }
74
- this.logger.debug(`Service access granted: ${pluginName} -> ${serviceName}`);
75
- }
76
- /**
77
- * Enforce hook trigger permission
78
- *
79
- * @param pluginName - Plugin requesting access
80
- * @param hookName - Hook to trigger
81
- * @throws Error if permission denied
82
- */
83
- enforceHookTrigger(pluginName, hookName) {
84
- const result = this.checkPermission(pluginName, (perms) => perms.canTriggerHook(hookName));
85
- if (!result.allowed) {
86
- const error = `Permission denied: Plugin ${pluginName} cannot trigger hook ${hookName}`;
87
- this.logger.warn(error, {
88
- plugin: pluginName,
89
- hook: hookName,
90
- reason: result.reason,
91
- });
92
- throw new Error(error);
93
- }
94
- this.logger.debug(`Hook trigger granted: ${pluginName} -> ${hookName}`);
95
- }
96
- /**
97
- * Enforce file read permission
98
- *
99
- * @param pluginName - Plugin requesting access
100
- * @param path - File path to read
101
- * @throws Error if permission denied
102
- */
103
- enforceFileRead(pluginName, path) {
104
- const result = this.checkPermission(pluginName, (perms) => perms.canReadFile(path));
105
- if (!result.allowed) {
106
- const error = `Permission denied: Plugin ${pluginName} cannot read file ${path}`;
107
- this.logger.warn(error, {
108
- plugin: pluginName,
109
- path,
110
- reason: result.reason,
111
- });
112
- throw new Error(error);
113
- }
114
- this.logger.debug(`File read granted: ${pluginName} -> ${path}`);
115
- }
116
- /**
117
- * Enforce file write permission
118
- *
119
- * @param pluginName - Plugin requesting access
120
- * @param path - File path to write
121
- * @throws Error if permission denied
122
- */
123
- enforceFileWrite(pluginName, path) {
124
- const result = this.checkPermission(pluginName, (perms) => perms.canWriteFile(path));
125
- if (!result.allowed) {
126
- const error = `Permission denied: Plugin ${pluginName} cannot write file ${path}`;
127
- this.logger.warn(error, {
128
- plugin: pluginName,
129
- path,
130
- reason: result.reason,
131
- });
132
- throw new Error(error);
133
- }
134
- this.logger.debug(`File write granted: ${pluginName} -> ${path}`);
135
- }
136
- /**
137
- * Enforce network request permission
138
- *
139
- * @param pluginName - Plugin requesting access
140
- * @param url - URL to access
141
- * @throws Error if permission denied
142
- */
143
- enforceNetworkRequest(pluginName, url) {
144
- const result = this.checkPermission(pluginName, (perms) => perms.canNetworkRequest(url));
145
- if (!result.allowed) {
146
- const error = `Permission denied: Plugin ${pluginName} cannot access URL ${url}`;
147
- this.logger.warn(error, {
148
- plugin: pluginName,
149
- url,
150
- reason: result.reason,
151
- });
152
- throw new Error(error);
153
- }
154
- this.logger.debug(`Network request granted: ${pluginName} -> ${url}`);
155
- }
156
- /**
157
- * Get plugin capabilities
158
- *
159
- * @param pluginName - Plugin identifier
160
- * @returns Array of capabilities or undefined
161
- */
162
- getPluginCapabilities(pluginName) {
163
- return this.capabilityRegistry.get(pluginName);
164
- }
165
- /**
166
- * Get plugin permissions
167
- *
168
- * @param pluginName - Plugin identifier
169
- * @returns Permissions object or undefined
170
- */
171
- getPluginPermissions(pluginName) {
172
- return this.permissionRegistry.get(pluginName);
173
- }
174
- /**
175
- * Revoke all permissions for a plugin
176
- *
177
- * @param pluginName - Plugin identifier
178
- */
179
- revokePermissions(pluginName) {
180
- this.permissionRegistry.delete(pluginName);
181
- this.capabilityRegistry.delete(pluginName);
182
- this.logger.warn(`Permissions revoked for plugin: ${pluginName}`);
183
- }
184
- // Private methods
185
- checkPermission(pluginName, check) {
186
- const permissions = this.permissionRegistry.get(pluginName);
187
- if (!permissions) {
188
- return {
189
- allowed: false,
190
- reason: 'Plugin permissions not registered',
191
- };
192
- }
193
- const allowed = check(permissions);
194
- return {
195
- allowed,
196
- reason: allowed ? undefined : 'No matching capability found',
197
- };
198
- }
199
- checkServiceAccess(capabilities, serviceName) {
200
- // Check if plugin has capability to access this service
201
- return capabilities.some(cap => {
202
- const protocolId = cap.protocol.id;
203
- // Check for wildcard service access
204
- if (protocolId.includes('protocol.service.all')) {
205
- return true;
206
- }
207
- // Check for specific service protocol
208
- if (protocolId.includes(`protocol.service.${serviceName}`)) {
209
- return true;
210
- }
211
- // Check for service category match
212
- const serviceCategory = serviceName.split('.')[0];
213
- if (protocolId.includes(`protocol.service.${serviceCategory}`)) {
214
- return true;
215
- }
216
- return false;
217
- });
218
- }
219
- checkHookAccess(capabilities, hookName) {
220
- // Check if plugin has capability to trigger this hook
221
- return capabilities.some(cap => {
222
- const protocolId = cap.protocol.id;
223
- // Check for wildcard hook access
224
- if (protocolId.includes('protocol.hook.all')) {
225
- return true;
226
- }
227
- // Check for specific hook protocol
228
- if (protocolId.includes(`protocol.hook.${hookName}`)) {
229
- return true;
230
- }
231
- // Check for hook category match
232
- const hookCategory = hookName.split(':')[0];
233
- if (protocolId.includes(`protocol.hook.${hookCategory}`)) {
234
- return true;
235
- }
236
- return false;
237
- });
238
- }
239
- checkFileRead(capabilities, _path) {
240
- // Check if plugin has capability to read this file
241
- return capabilities.some(cap => {
242
- const protocolId = cap.protocol.id;
243
- // Check for file read capability
244
- if (protocolId.includes('protocol.filesystem.read')) {
245
- // TODO: Add path pattern matching
246
- return true;
247
- }
248
- return false;
249
- });
250
- }
251
- checkFileWrite(capabilities, _path) {
252
- // Check if plugin has capability to write this file
253
- return capabilities.some(cap => {
254
- const protocolId = cap.protocol.id;
255
- // Check for file write capability
256
- if (protocolId.includes('protocol.filesystem.write')) {
257
- // TODO: Add path pattern matching
258
- return true;
259
- }
260
- return false;
261
- });
262
- }
263
- checkNetworkAccess(capabilities, _url) {
264
- // Check if plugin has capability to access this URL
265
- return capabilities.some(cap => {
266
- const protocolId = cap.protocol.id;
267
- // Check for network capability
268
- if (protocolId.includes('protocol.network')) {
269
- // TODO: Add URL pattern matching
270
- return true;
271
- }
272
- return false;
273
- });
274
- }
275
- }
276
- /**
277
- * Secure Plugin Context
278
- * Wraps PluginContext with permission checks
279
- */
280
- export class SecurePluginContext {
281
- constructor(pluginName, permissionEnforcer, baseContext) {
282
- this.pluginName = pluginName;
283
- this.permissionEnforcer = permissionEnforcer;
284
- this.baseContext = baseContext;
285
- }
286
- registerService(name, service) {
287
- // No permission check for service registration (handled during init)
288
- this.baseContext.registerService(name, service);
289
- }
290
- getService(name) {
291
- // Check permission before accessing service
292
- this.permissionEnforcer.enforceServiceAccess(this.pluginName, name);
293
- return this.baseContext.getService(name);
294
- }
295
- getServices() {
296
- // Return all services (no permission check for listing)
297
- return this.baseContext.getServices();
298
- }
299
- hook(name, handler) {
300
- // No permission check for registering hooks (handled during init)
301
- this.baseContext.hook(name, handler);
302
- }
303
- async trigger(name, ...args) {
304
- // Check permission before triggering hook
305
- this.permissionEnforcer.enforceHookTrigger(this.pluginName, name);
306
- await this.baseContext.trigger(name, ...args);
307
- }
308
- get logger() {
309
- return this.baseContext.logger;
310
- }
311
- getKernel() {
312
- return this.baseContext.getKernel();
313
- }
314
- }
315
- /**
316
- * Create a plugin permission enforcer
317
- *
318
- * @param logger - Logger instance
319
- * @returns Plugin permission enforcer
320
- */
321
- export function createPluginPermissionEnforcer(logger) {
322
- return new PluginPermissionEnforcer(logger);
323
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=plugin-permission-enforcer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-permission-enforcer.test.d.ts","sourceRoot":"","sources":["../../src/security/plugin-permission-enforcer.test.ts"],"names":[],"mappings":""}
@@ -1,205 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { PluginPermissionEnforcer, SecurePluginContext } from './plugin-permission-enforcer.js';
3
- import { createLogger } from '../logger.js';
4
- describe('PluginPermissionEnforcer', () => {
5
- let enforcer;
6
- let logger;
7
- beforeEach(() => {
8
- logger = createLogger({ level: 'error' });
9
- enforcer = new PluginPermissionEnforcer(logger);
10
- });
11
- describe('registerPluginPermissions', () => {
12
- it('should register plugin capabilities', () => {
13
- const capabilities = [
14
- {
15
- protocol: {
16
- id: 'com.objectstack.protocol.service.database.v1',
17
- label: 'Database Service',
18
- version: { major: 1, minor: 0, patch: 0 },
19
- },
20
- conformance: 'full',
21
- certified: false,
22
- },
23
- ];
24
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
25
- const registeredCapabilities = enforcer.getPluginCapabilities('com.test.plugin');
26
- expect(registeredCapabilities).toEqual(capabilities);
27
- });
28
- });
29
- describe('enforceServiceAccess', () => {
30
- it('should allow access to declared services', () => {
31
- const capabilities = [
32
- {
33
- protocol: {
34
- id: 'com.objectstack.protocol.service.database.v1',
35
- label: 'Database Service',
36
- version: { major: 1, minor: 0, patch: 0 },
37
- },
38
- conformance: 'full',
39
- certified: false,
40
- },
41
- ];
42
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
43
- // Should not throw
44
- expect(() => {
45
- enforcer.enforceServiceAccess('com.test.plugin', 'database');
46
- }).not.toThrow();
47
- });
48
- it('should deny access to undeclared services', () => {
49
- const capabilities = [
50
- {
51
- protocol: {
52
- id: 'com.objectstack.protocol.service.database.v1',
53
- label: 'Database Service',
54
- version: { major: 1, minor: 0, patch: 0 },
55
- },
56
- conformance: 'full',
57
- certified: false,
58
- },
59
- ];
60
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
61
- expect(() => {
62
- enforcer.enforceServiceAccess('com.test.plugin', 'network');
63
- }).toThrow(/Permission denied/);
64
- });
65
- it('should allow wildcard service access', () => {
66
- const capabilities = [
67
- {
68
- protocol: {
69
- id: 'com.objectstack.protocol.service.all.v1',
70
- label: 'All Services',
71
- version: { major: 1, minor: 0, patch: 0 },
72
- },
73
- conformance: 'full',
74
- certified: false,
75
- },
76
- ];
77
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
78
- // Should allow any service
79
- expect(() => {
80
- enforcer.enforceServiceAccess('com.test.plugin', 'database');
81
- enforcer.enforceServiceAccess('com.test.plugin', 'network');
82
- enforcer.enforceServiceAccess('com.test.plugin', 'filesystem');
83
- }).not.toThrow();
84
- });
85
- });
86
- describe('enforceHookTrigger', () => {
87
- it('should allow triggering declared hooks', () => {
88
- const capabilities = [
89
- {
90
- protocol: {
91
- id: 'com.objectstack.protocol.hook.data.v1',
92
- label: 'Data Hooks',
93
- version: { major: 1, minor: 0, patch: 0 },
94
- },
95
- conformance: 'full',
96
- certified: false,
97
- },
98
- ];
99
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
100
- expect(() => {
101
- enforcer.enforceHookTrigger('com.test.plugin', 'data:beforeCreate');
102
- }).not.toThrow();
103
- });
104
- it('should deny triggering undeclared hooks', () => {
105
- const capabilities = [
106
- {
107
- protocol: {
108
- id: 'com.objectstack.protocol.hook.data.v1',
109
- label: 'Data Hooks',
110
- version: { major: 1, minor: 0, patch: 0 },
111
- },
112
- conformance: 'full',
113
- certified: false,
114
- },
115
- ];
116
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
117
- expect(() => {
118
- enforcer.enforceHookTrigger('com.test.plugin', 'kernel:shutdown');
119
- }).toThrow(/Permission denied/);
120
- });
121
- });
122
- describe('revokePermissions', () => {
123
- it('should revoke plugin permissions', () => {
124
- const capabilities = [
125
- {
126
- protocol: {
127
- id: 'com.objectstack.protocol.service.database.v1',
128
- label: 'Database Service',
129
- version: { major: 1, minor: 0, patch: 0 },
130
- },
131
- conformance: 'full',
132
- certified: false,
133
- },
134
- ];
135
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
136
- enforcer.revokePermissions('com.test.plugin');
137
- expect(() => {
138
- enforcer.enforceServiceAccess('com.test.plugin', 'database');
139
- }).toThrow(/Permission denied/);
140
- });
141
- });
142
- });
143
- describe('SecurePluginContext', () => {
144
- let enforcer;
145
- let logger;
146
- let mockBaseContext;
147
- beforeEach(() => {
148
- logger = createLogger({ level: 'error' });
149
- enforcer = new PluginPermissionEnforcer(logger);
150
- mockBaseContext = {
151
- registerService: () => { },
152
- getService: (name) => ({ name }),
153
- getServices: () => new Map(),
154
- hook: () => { },
155
- trigger: async () => { },
156
- logger,
157
- getKernel: () => ({}),
158
- };
159
- });
160
- describe('getService', () => {
161
- it('should check permission before accessing service', () => {
162
- const capabilities = [
163
- {
164
- protocol: {
165
- id: 'com.objectstack.protocol.service.database.v1',
166
- label: 'Database Service',
167
- version: { major: 1, minor: 0, patch: 0 },
168
- },
169
- conformance: 'full',
170
- certified: false,
171
- },
172
- ];
173
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
174
- const secureContext = new SecurePluginContext('com.test.plugin', enforcer, mockBaseContext);
175
- // Should succeed with permission
176
- const service = secureContext.getService('database');
177
- expect(service).toBeDefined();
178
- // Should fail without permission
179
- expect(() => {
180
- secureContext.getService('network');
181
- }).toThrow(/Permission denied/);
182
- });
183
- });
184
- describe('trigger', () => {
185
- it('should check permission before triggering hook', async () => {
186
- const capabilities = [
187
- {
188
- protocol: {
189
- id: 'com.objectstack.protocol.hook.data.v1',
190
- label: 'Data Hooks',
191
- version: { major: 1, minor: 0, patch: 0 },
192
- },
193
- conformance: 'full',
194
- certified: false,
195
- },
196
- ];
197
- enforcer.registerPluginPermissions('com.test.plugin', capabilities);
198
- const secureContext = new SecurePluginContext('com.test.plugin', enforcer, mockBaseContext);
199
- // Should succeed with permission
200
- await expect(secureContext.trigger('data:beforeCreate')).resolves.not.toThrow();
201
- // Should fail without permission
202
- await expect(secureContext.trigger('kernel:shutdown')).rejects.toThrow(/Permission denied/);
203
- });
204
- });
205
- });
@@ -1,96 +0,0 @@
1
- import type { Logger } from '@objectstack/spec/contracts';
2
- import type { PluginMetadata } from '../plugin-loader.js';
3
- /**
4
- * Plugin Signature Configuration
5
- * Controls how plugin signatures are verified
6
- */
7
- export interface PluginSignatureConfig {
8
- /**
9
- * Map of publisher IDs to their trusted public keys
10
- * Format: { 'com.objectstack': '-----BEGIN PUBLIC KEY-----...' }
11
- */
12
- trustedPublicKeys: Map<string, string>;
13
- /**
14
- * Signature algorithm to use
15
- * - RS256: RSA with SHA-256
16
- * - ES256: ECDSA with SHA-256
17
- */
18
- algorithm: 'RS256' | 'ES256';
19
- /**
20
- * Strict mode: reject plugins without signatures
21
- * - true: All plugins must be signed
22
- * - false: Unsigned plugins are allowed with warning
23
- */
24
- strictMode: boolean;
25
- /**
26
- * Allow self-signed plugins in development
27
- */
28
- allowSelfSigned?: boolean;
29
- }
30
- /**
31
- * Plugin Signature Verification Result
32
- */
33
- export interface SignatureVerificationResult {
34
- verified: boolean;
35
- error?: string;
36
- publisherId?: string;
37
- algorithm?: string;
38
- signedAt?: Date;
39
- }
40
- /**
41
- * Plugin Signature Verifier
42
- *
43
- * Implements cryptographic verification of plugin signatures to ensure:
44
- * 1. Plugin integrity - code hasn't been tampered with
45
- * 2. Publisher authenticity - plugin comes from trusted source
46
- * 3. Non-repudiation - publisher cannot deny signing
47
- *
48
- * Architecture:
49
- * - Uses Node.js crypto module for signature verification
50
- * - Supports RSA (RS256) and ECDSA (ES256) algorithms
51
- * - Verifies against trusted public key registry
52
- * - Computes hash of plugin code for integrity check
53
- *
54
- * Security Model:
55
- * - Public keys are pre-registered and trusted
56
- * - Plugin signature is verified before loading
57
- * - Strict mode rejects unsigned plugins
58
- * - Development mode allows self-signed plugins
59
- */
60
- export declare class PluginSignatureVerifier {
61
- private config;
62
- private logger;
63
- constructor(config: PluginSignatureConfig, logger: Logger);
64
- /**
65
- * Verify plugin signature
66
- *
67
- * @param plugin - Plugin metadata with signature
68
- * @returns Verification result
69
- * @throws Error if verification fails in strict mode
70
- */
71
- verifyPluginSignature(plugin: PluginMetadata): Promise<SignatureVerificationResult>;
72
- /**
73
- * Register a trusted public key for a publisher
74
- */
75
- registerPublicKey(publisherId: string, publicKey: string): void;
76
- /**
77
- * Remove a trusted public key
78
- */
79
- revokePublicKey(publisherId: string): void;
80
- /**
81
- * Get list of trusted publishers
82
- */
83
- getTrustedPublishers(): string[];
84
- private handleUnsignedPlugin;
85
- private extractPublisherId;
86
- private computePluginHash;
87
- private computePluginHashNode;
88
- private computePluginHashBrowser;
89
- private computePluginHashFallback;
90
- private serializePluginCode;
91
- private verifyCryptoSignature;
92
- private verifyCryptoSignatureNode;
93
- private verifyCryptoSignatureBrowser;
94
- private validateConfig;
95
- }
96
- //# sourceMappingURL=plugin-signature-verifier.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-signature-verifier.d.ts","sourceRoot":"","sources":["../../src/security/plugin-signature-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAc1D;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEvC;;;;OAIG;IACH,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC;IAE7B;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM;IAOzD;;;;;;OAMG;IACG,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAqEzF;;OAEG;IACH,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAK/D;;OAEG;IACH,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAK1C;;OAEG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAMhC,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,yBAAyB;IAcjC,OAAO,CAAC,mBAAmB;YAoBb,qBAAqB;IAcnC,OAAO,CAAC,yBAAyB;YAqCnB,4BAA4B;IAW1C,OAAO,CAAC,cAAc;CAavB"}