本文へスキップ
Z-CMS is being built in the open on GitHub. コミュニティに参加する

記事一覧

Z-CMS が Node.js VM ではなく V8 Isolate を採用する理由

2026年7月10日 · Z-SOFT Admin · 約 6 分で読めます

モダンな open-source CMS のための、より安全な plugin runtime 設計

Plugin system の背後にある設計課題

Z-CMS の plugin system を設計する際、中心となった問いは「別の JavaScript module をどう load するか」ではありませんでした。本当の課題は、third-party developer に CMS を拡張する自由を与えながら、各 plugin に server への無制限な権限を与えないことです。

Plugin は platform を十分に拡張できる必要があります。一方で、単一の bug、memory leak、無限 loop が CMS 全体を不安定にしない程度に isolation されていなければなりません。すべての plugin を CMS Core と同じ Node.js runtime で動かすと、1 つの plugin が全 tenant と全 request に影響を与える可能性があります。

従来の Node.js アプローチ

基本的な plugin loader は require() や dynamic import で実装できます。分かりやすく短期間で作れますが、plugin は Core と同じ process、event loop、memory space、environment variables、Node.js APIs を共有します。意図しないコードでも重大な incident を引き起こし得ます。

Node.js vm が最終的な security boundary ではない理由

標準の vm module は独立した JavaScript context を作成できます。Controlled scripting には有効ですが、その context は同じ V8 Isolate、同じ operating-system process の中に存在します。そのため event loop、process memory、garbage collector は CMS Core と共有されます。

Z-CMS が必要としたのは context separation だけではなく、plugin ごとの independent memory limit、execution timeout、lifecycle control です。

CMS Core
│
├── Plugin SEO
│   └── V8 Isolate
├── Plugin AI
│   └── V8 Isolate
└── Plugin Analytics
    └── V8 Isolate

V8 Isolate モデル

V8 Isolate は V8 engine 内の独立した JavaScript execution environment です。各 isolate は専用の heap、global object、execution context、garbage collector を持ちます。

Plugin は process.env、host filesystem、child_process、Core 内部 object に自動的にはアクセスできません。Z-CMS が明示的に expose した capability だけを受け取ります。

Capability-based API

Z-CMS は Node.js runtime 全体を expose せず、管理された SDK を提供します。Plugin は manifest に従って content、storage、cache、event、logging、HTTP、settings capability を利用します。

すべての bridge call は Core 側で validate されます。storage:write permission を持たない plugin が write method を呼んでも、その operation は拒否されます。

{
  "name": "@z-cms/plugin-seo",
  "permissions": [
    "content:read",
    "content:update",
    "settings:read"
  ],
  "runtime": {
    "memoryLimitMb": 64,
    "timeoutMs": 2000
  }
}

CPU、timeout、memory limit

Request lifecycle 内で実行される hook は無期限に動作してはいけません。Z-CMS は execution ごとに maximum duration を設定し、policy を超えた isolate を terminate または recycle できます。

Memory policy も plugin 単位で定義できます。小規模 plugin には小さな heap を割り当て、承認済みの processing plugin にはより大きな allocation を与えます。

Isolate だけで完全な sandbox になるわけではない

Isolation の強度は host が expose する bridge に依存します。Core が危険な system command API を提供すれば、isolate では補えません。Z-CMS は raw Node.js API や database connection を expose せず、filesystem と network access を制限し、runtime boundary を越える値を validate・serialize し、tenant・user・plugin permission を Core で enforce します。

Plugin ごとに container を使わない理由

Container は強い operating-system isolation を提供しますが、image distribution、network management、service discovery、startup latency、logging complexity、resource overhead が増えます。一般的な plugin business logic では、V8 Isolate が isolation、startup speed、operational cost の現実的なバランスになります。

Failure containment と結論

Plugin が失敗した場合、isolate だけを terminate し、CMS Core は稼働を継続できます。Repeated failure には circuit breaker を適用し、platform 全体を維持したまま plugin を一時 suspend できます。

Marketplace-driven CMS において plugin isolation は付加機能ではなく platform foundation です。V8 Isolate により、各 plugin に独立 runtime、explicit capability、resource limit、制御可能な lifecycle を提供できます。

Key takeaways

  • Security boundary は plugin の善意ではなく Core 側で enforce する必要があります。
  • Lifecycle、permission、tenant context、observability は同じ platform contract の一部です。
  • 優れた developer experience は、安全な runtime と supply chain の設計によって持続可能になります。

GitHub: https://github.com/zscontributor/z-cms
Website: https://z-cms.org