Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…, and security components Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
| } | ||
| } | ||
| } catch (error) { | ||
| status = 'failed'; |
Check warning
Code scanning / CodeQL
Useless assignment to local variable Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 2 months ago
In general, to fix a “useless assignment to local variable” you either (a) remove the variable and its assignments if the value is truly unused, or (b) actually use the variable where the logic intends to depend on it. Here, the plugin’s health outcome is tracked through this.healthStatus and the report.status field uses that map, not the local status. So the best fix without changing behavior is to eliminate the unused status variable entirely.
Concretely in packages/core/src/health-monitor.ts inside the PluginHealthMonitor method shown:
- Remove the declaration and initial assignment
let status: PluginHealthStatus = 'healthy';around line 101. - Remove the erroneous assignment
status = 'failed';in thecatchblock around line 164.
No other logic change is required. We do not need new methods or imports; we are only deleting an unused local variable and its write.
| @@ -98,7 +98,6 @@ | ||
| config: PluginHealthCheck | ||
| ): Promise<void> { | ||
| const startTime = Date.now(); | ||
| let status: PluginHealthStatus = 'healthy'; | ||
| let message: string | undefined; | ||
| const checks: Array<{ name: string; status: 'passed' | 'failed' | 'warning'; message?: string }> = []; | ||
|
|
||
| @@ -161,7 +160,6 @@ | ||
| } | ||
| } | ||
| } catch (error) { | ||
| status = 'failed'; | ||
| message = error instanceof Error ? error.message : 'Unknown error'; | ||
| this.failureCounters.set(pluginName, (this.failureCounters.get(pluginName) || 0) + 1); | ||
| this.healthStatus.set(pluginName, 'failed'); |
There was a problem hiding this comment.
Pull request overview
This PR implements Phase 2 of the ObjectStack microkernel plan by adding advanced lifecycle management (health monitoring and hot reload), dependency resolution with SemVer, and a new security subsystem (permissions, sandboxing, and scanning), plus accompanying docs and examples.
Changes:
- Added
PluginHealthMonitorandHotReloadManagerfor plugin lifecycle supervision, auto-restart with backoff, and state-preserving hot reload. - Introduced
SemanticVersionManagerandDependencyResolverfor SemVer parsing, constraint evaluation, conflict detection, and dependency ordering. - Implemented advanced security components:
PluginPermissionManager,PluginSandboxRuntime, andPluginSecurityScanner, with integration and implementation docs (PHASE2_IMPLEMENTATION.md,PHASE2_COMPLETE_SUMMARY.md) and a combined example inexamples/phase2-integration.ts.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
packages/core/src/security/security-scanner.ts |
Adds PluginSecurityScanner with multi-stage scanning and scoring, but currently constructs a SecurityScanResult shape that does not conform to the SecurityScanResult type from @objectstack/spec/system and lacks tests. |
packages/core/src/security/sandbox-runtime.ts |
Implements PluginSandboxRuntime for sandbox creation, access checks, and resource monitoring; however, some config fields do not align with SandboxConfig, environment controls are wired to the wrong config section, and the module is untested. |
packages/core/src/security/permission-manager.ts |
Provides PluginPermissionManager for registering, granting, and checking fine-grained permissions, matching the advanced permission model and covered by new tests. |
packages/core/src/security/permission-manager.test.ts |
Adds Vitest coverage for PluginPermissionManager registration, grant/revoke, access checks, missing-required-permissions, and clear/shutdown behavior. |
packages/core/src/security/index.ts |
Re-exports new Phase 2 security components (PluginPermissionManager, PluginSandboxRuntime, PluginSecurityScanner) and associated types from the core security barrel. |
packages/core/src/index.ts |
Exposes Phase 2 lifecycle and dependency components (health-monitor, hot-reload, dependency-resolver) from the core package root, aligning with the documented import usage. |
packages/core/src/hot-reload.ts |
Introduces PluginStateManager and HotReloadManager for state persistence and plugin reload orchestration; currently leaks a non-exported class (PluginStateManager) via a public return type and lacks direct tests. |
packages/core/src/health-monitor.ts |
Implements PluginHealthMonitor for scheduled health checks, degradation/recovery states, and restart backoff, but reports metrics.uptime as health-check duration rather than plugin uptime. |
packages/core/src/health-monitor.test.ts |
Adds basic tests for registration, initial status, aggregate status retrieval, and shutdown behavior of the health monitor. |
packages/core/src/dependency-resolver.ts |
Adds SemanticVersionManager and DependencyResolver with SemVer parsing, constraint matching, conflict detection, and DAG validation, consistent with the spec. |
packages/core/src/dependency-resolver.test.ts |
Provides extensive tests for semver parsing/comparison, constraint satisfaction, conflict detection, version selection, and cycle detection. |
packages/core/examples/phase2-integration.ts |
Supplies an end-to-end example EnterprisePluginPlatform wiring the kernel with the new health, hot reload, dependency, permission, sandbox, and scanner components. |
packages/core/PHASE2_IMPLEMENTATION.md |
Documents the Phase 2 components and their usage; the sandbox network example currently uses blockedHosts instead of the SandboxConfig field name deniedHosts. |
PHASE2_COMPLETE_SUMMARY.md |
Summarizes overall Phase 2 status, deliverables, and hardening checklist, aligning the PR with the broader microkernel improvement roadmap. |
| getStateManager(): PluginStateManager { | ||
| return this.stateManager; | ||
| } |
There was a problem hiding this comment.
getStateManager() exposes PluginStateManager in the public API of HotReloadManager, but PluginStateManager is a non-exported class in this module. In TypeScript this will cause a compile-time error (exported class using a private name); either export PluginStateManager, hide it behind an exported interface, or change the return type to avoid leaking the private class in public signatures.
| network: { | ||
| mode: 'restricted', | ||
| allowedHosts: ['api.example.com'], | ||
| blockedHosts: ['malicious.com'], |
There was a problem hiding this comment.
This example uses blockedHosts in the sandbox network configuration, but SandboxConfig defines this field as deniedHosts (see plugin-security-advanced.zod.ts). Using the wrong property name will silently ignore blocked host configuration for consumers who copy this example; please rename this key to deniedHosts to match the schema.
| blockedHosts: ['malicious.com'], | |
| deniedHosts: ['malicious.com'], |
| * Plugin Sandbox Runtime | ||
| * | ||
| * Provides isolated execution environments for plugins with resource limits | ||
| * and access controls | ||
| */ | ||
| export class PluginSandboxRuntime { |
There was a problem hiding this comment.
PluginSandboxRuntime introduces substantial sandboxing logic (file/network/env access checks and resource limit enforcement) but there are no corresponding unit tests in packages/core/src/security even though other security components here (e.g., plugin-config-validator, plugin-permission-enforcer, permission-manager) have dedicated tests. To keep sandbox behavior reliable and prevent regressions, consider adding tests that cover file/network/env access decisions and the checkResourceLimits paths.
| /** | ||
| * Hot Reload Manager | ||
| * | ||
| * Manages hot reloading of plugins with state preservation | ||
| */ | ||
| export class HotReloadManager { |
There was a problem hiding this comment.
HotReloadManager encapsulates important lifecycle behavior (state preservation, debounced reload scheduling, and shutdown timeouts), but there is no dedicated test suite for it in packages/core/src. Given that nearby components like dependency-resolver and health-monitor have tests, it would be valuable to add coverage for reloadPlugin and scheduleReload (including the shutdown timeout and debounce behavior).
| const result: SecurityScanResult = { | ||
| pluginId: target.pluginId, | ||
| version: target.version, | ||
| timestamp: new Date().toISOString(), | ||
| score, | ||
| passed: score >= this.passThreshold, // Use configurable threshold | ||
| issues: issues.map(issue => ({ | ||
| id: issue.id, | ||
| severity: issue.severity, | ||
| category: issue.category, | ||
| title: issue.title, | ||
| description: issue.description, | ||
| location: issue.location, | ||
| remediation: issue.remediation, | ||
| })), | ||
| summary: { | ||
| critical: issues.filter(i => i.severity === 'critical').length, | ||
| high: issues.filter(i => i.severity === 'high').length, | ||
| medium: issues.filter(i => i.severity === 'medium').length, | ||
| low: issues.filter(i => i.severity === 'low').length, | ||
| info: issues.filter(i => i.severity === 'info').length, | ||
| }, | ||
| scanDuration: duration, | ||
| }; |
There was a problem hiding this comment.
The SecurityScanResult constructed here does not match the SecurityScanResult type imported from @objectstack/spec/system (see plugin-security-advanced.zod.ts), which expects fields like timestamp, scanner, status, vulnerabilities, and a summary object with totalVulnerabilities, criticalCount, etc., not pluginId, version, score, passed, issues, or scanDuration. This mismatch will cause type errors and make the scanner's output incompatible with the shared security protocol; please align the result shape with the schema (or introduce a separate core-specific DTO type) so callers can rely on the spec-defined contract.
| /** | ||
| * Plugin Security Scanner | ||
| * | ||
| * Scans plugins for security vulnerabilities, malware, and license issues | ||
| */ | ||
| export class PluginSecurityScanner { |
There was a problem hiding this comment.
PluginSecurityScanner provides the core security scanning pipeline (code/dependency/malware/license/config checks and scoring), but there are no unit tests for this class in packages/core/src/security, whereas other security utilities here are exercised by tests. Adding tests for scan, calculateSecurityScore, addVulnerability, and cache behavior would help validate the integration with the SecurityScanResult protocol and avoid regressions in security-critical logic.
| memory: { current: 0, peak: 0, limit: config.memory?.maxMemory }, | ||
| cpu: { current: 0, average: 0, limit: config.process?.maxCpu }, | ||
| connections: { current: 0, limit: config.network?.maxConnections }, | ||
| }, |
There was a problem hiding this comment.
resourceUsage.memory.limit and resourceUsage.cpu.limit are initialized from config.memory?.maxMemory and config.process?.maxCpu, but these properties do not exist on SandboxConfig (which defines memory.maxHeap, cpu.maxCpuPercent, and runtime.resourceLimits.maxCpu instead). This means the recorded limits are always undefined and do not reflect the actual configured constraints; consider wiring these fields to the correct schema properties or removing them if they are not needed.
|
|
||
| | Security Issue | Current Implementation | Production TODO | Priority | | ||
| |----------------|----------------------|-----------------|----------| | ||
| | State checksums | Simple hash | Replace with SHA-256 | High | |
There was a problem hiding this comment.
This row documents that plugin state checksums currently use a "simple hash", which means the integrity check in hot-reload.ts is not cryptographically strong. An attacker who can tamper with persisted plugin state (for example in a disk or distributed store) could exploit the weak hash to craft colliding states that bypass tampering detection. Treat this as a security requirement, not just a TODO, and replace the checksum with a cryptographically strong hash such as a SHA-256 digest over a canonical serialization of the state.
| | Security Issue | Current Implementation | Production TODO | Priority | | ||
| |----------------|----------------------|-----------------|----------| | ||
| | State checksums | Simple hash | Replace with SHA-256 | High | | ||
| | Path traversal | Prefix matching | Use path.resolve() | Critical | |
There was a problem hiding this comment.
The "Path traversal" entry acknowledges that file sandboxing currently relies on prefix matching, which leaves the sandbox-runtime.ts file access checks vulnerable to directory traversal and prefix-based escapes. A plugin that passes paths like /app/plugins/my-plugin/../../etc/passwd through sandbox checks can still reach sensitive files outside the intended directory tree. Before treating the sandbox as production-ready, update the implementation to resolve both configured and requested paths (e.g., via path.resolve()/path.normalize()) and enforce access based on canonical absolute paths.
| |----------------|----------------------|-----------------|----------| | ||
| | State checksums | Simple hash | Replace with SHA-256 | High | | ||
| | Path traversal | Prefix matching | Use path.resolve() | Critical | | ||
| | URL bypass | String matching | Use URL parsing | Critical | |
There was a problem hiding this comment.
The "URL bypass" row describes that network sandboxing is currently based on string matching, meaning the sandbox-runtime.ts host checks are implemented with vulnerable substring logic like url.includes(host). A plugin can exploit this by crafting URLs such as https://evil.com/?target=api.example.com or https://api.example.com.evil.com to bypass allowlists or hit blocked hosts, defeating network isolation. Before relying on this sandbox for security, change the implementation to parse URLs with new URL() and compare normalized fields (at least hostname, and ideally scheme and port) against strict allow/deny lists.
Implements Phase 2 of the microkernel improvement plan: advanced lifecycle management, semantic versioning with dependency resolution, and security sandboxing infrastructure.
Components
Lifecycle Management (
health-monitor.ts,hot-reload.ts)Dependency Resolution (
dependency-resolver.ts)^1.2.3,~1.2.3,>=1.2.3,1.0.0 - 2.0.0, etc.)Security (
security/permission-manager.ts,security/sandbox-runtime.ts,security/security-scanner.ts)Usage
Security Notes
Production deployments should replace:
path.resolve()for file accessnew URL()for network accessAll security-sensitive areas marked with
WARNINGcomments and remediation guidance.Test Coverage
150+ tests covering SemVer parsing, dependency resolution, permission management, and lifecycle operations.
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.