diff --git a/packages/core/src/plugin-loader.ts b/packages/core/src/plugin-loader.ts index 8e402e8f16..f54dc9f440 100644 --- a/packages/core/src/plugin-loader.ts +++ b/packages/core/src/plugin-loader.ts @@ -32,10 +32,11 @@ export interface ServiceRegistration { } /** - * Plugin Configuration Validator + * Plugin Configuration Validator Interface * Uses Zod for runtime validation of plugin configurations + * @deprecated Use the PluginConfigValidator class from security module instead */ -export interface PluginConfigValidator { +export interface IPluginConfigValidator { schema: z.ZodSchema; validate(config: any): any; } diff --git a/packages/core/src/security/plugin-config-validator.test.ts b/packages/core/src/security/plugin-config-validator.test.ts index dc028a15e7..5e5604df40 100644 --- a/packages/core/src/security/plugin-config-validator.test.ts +++ b/packages/core/src/security/plugin-config-validator.test.ts @@ -1,15 +1,15 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { z } from 'zod'; -import { PluginConfigValidator } from '../plugin-config-validator.js'; -import { createLogger } from '../../logger.js'; -import type { PluginMetadata } from '../../plugin-loader.js'; +import { PluginConfigValidator } from './plugin-config-validator.js'; +import { createLogger } from '../logger.js'; +import type { PluginMetadata } from '../plugin-loader.js'; describe('PluginConfigValidator', () => { let validator: PluginConfigValidator; let logger: ReturnType; beforeEach(() => { - logger = createLogger({ level: 'silent' }); + logger = createLogger({ level: 'error' }); validator = new PluginConfigValidator(logger); }); diff --git a/packages/core/src/security/plugin-config-validator.ts b/packages/core/src/security/plugin-config-validator.ts index a70e67772f..817e20b672 100644 --- a/packages/core/src/security/plugin-config-validator.ts +++ b/packages/core/src/security/plugin-config-validator.ts @@ -62,7 +62,7 @@ export class PluginConfigValidator { ...formattedErrors.map(e => ` - ${e.path}: ${e.message}`), ].join('\n'); - this.logger.error(errorMessage, { + this.logger.error(errorMessage, undefined, { plugin: plugin.name, errors: formattedErrors, }); @@ -89,7 +89,8 @@ export class PluginConfigValidator { try { // Use Zod's partial() method for partial validation - const partialSchema = plugin.configSchema.partial(); + // Cast to ZodObject to access partial() method + const partialSchema = (plugin.configSchema as any).partial(); const validatedConfig = partialSchema.parse(partialConfig); this.logger.debug(`✅ Partial config validated: ${plugin.name}`); @@ -171,8 +172,8 @@ export class PluginConfigValidator { // Private methods - private formatZodErrors(error: z.ZodError): Array<{path: string; message: string}> { - return error.errors.map(e => ({ + private formatZodErrors(error: z.ZodError): Array<{path: string; message: string}> { + return error.issues.map((e: z.ZodIssue) => ({ path: e.path.join('.') || 'root', message: e.message, })); diff --git a/packages/core/src/security/plugin-permission-enforcer.test.ts b/packages/core/src/security/plugin-permission-enforcer.test.ts index 1ab7eaed93..0524c3fb93 100644 --- a/packages/core/src/security/plugin-permission-enforcer.test.ts +++ b/packages/core/src/security/plugin-permission-enforcer.test.ts @@ -1,15 +1,15 @@ import { describe, it, expect, beforeEach } from 'vitest'; -import { PluginPermissionEnforcer, SecurePluginContext } from '../plugin-permission-enforcer.js'; -import { createLogger } from '../../logger.js'; +import { PluginPermissionEnforcer, SecurePluginContext } from './plugin-permission-enforcer.js'; +import { createLogger } from '../logger.js'; import type { PluginCapability } from '@objectstack/spec/system'; -import type { PluginContext } from '../../types.js'; +import type { PluginContext } from '../types.js'; describe('PluginPermissionEnforcer', () => { let enforcer: PluginPermissionEnforcer; let logger: ReturnType; beforeEach(() => { - logger = createLogger({ level: 'silent' }); + logger = createLogger({ level: 'error' }); enforcer = new PluginPermissionEnforcer(logger); }); @@ -23,6 +23,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -43,6 +44,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -63,6 +65,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -82,6 +85,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -106,6 +110,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -125,6 +130,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -146,6 +152,7 @@ describe('PluginPermissionEnforcer', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -165,12 +172,12 @@ describe('SecurePluginContext', () => { let mockBaseContext: PluginContext; beforeEach(() => { - logger = createLogger({ level: 'silent' }); + logger = createLogger({ level: 'error' }); enforcer = new PluginPermissionEnforcer(logger); mockBaseContext = { registerService: () => {}, - getService: (name: string) => ({ name }), + getService: (name: string): T => ({ name } as any), getServices: () => new Map(), hook: () => {}, trigger: async () => {}, @@ -189,6 +196,7 @@ describe('SecurePluginContext', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; @@ -221,6 +229,7 @@ describe('SecurePluginContext', () => { version: { major: 1, minor: 0, patch: 0 }, }, conformance: 'full', + certified: false, }, ]; diff --git a/packages/core/src/security/plugin-signature-verifier.ts b/packages/core/src/security/plugin-signature-verifier.ts index 57212b6470..0766bbf426 100644 --- a/packages/core/src/security/plugin-signature-verifier.ts +++ b/packages/core/src/security/plugin-signature-verifier.ts @@ -3,7 +3,7 @@ import type { PluginMetadata } from '../plugin-loader.js'; // Conditionally import crypto for Node.js environments let cryptoModule: typeof import('crypto') | null = null; -if (typeof window === 'undefined') { +if (typeof (globalThis as any).window === 'undefined') { try { // Dynamic import for Node.js crypto module // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -132,7 +132,7 @@ export class PluginSignatureVerifier { if (!isValid) { const error = `Signature verification failed for plugin: ${plugin.name}`; - this.logger.error(error, { plugin: plugin.name, publisherId }); + this.logger.error(error, undefined, { plugin: plugin.name, publisherId }); throw new Error(error); } @@ -190,7 +190,7 @@ export class PluginSignatureVerifier { private handleUnsignedPlugin(plugin: PluginMetadata): SignatureVerificationResult { if (this.config.strictMode) { const error = `Plugin missing signature (strict mode): ${plugin.name}`; - this.logger.error(error, { plugin: plugin.name }); + this.logger.error(error, undefined, { plugin: plugin.name }); throw new Error(error); } @@ -220,7 +220,7 @@ export class PluginSignatureVerifier { private computePluginHash(plugin: PluginMetadata): string { // In browser environment, use SubtleCrypto - if (typeof window !== 'undefined') { + if (typeof (globalThis as any).window !== 'undefined') { return this.computePluginHashBrowser(plugin); } @@ -287,7 +287,7 @@ export class PluginSignatureVerifier { publicKey: string ): Promise { // In browser environment, use SubtleCrypto - if (typeof window !== 'undefined') { + if (typeof (globalThis as any).window !== 'undefined') { return this.verifyCryptoSignatureBrowser(data, signature, publicKey); }