Repository navigation
Adds oci-javascript-mcp-server Kubernetes/Kata Isolation Provider - #431
dustin-sale wants to merge 18 commits into
Conversation
…cal development profiles
a5b46e4 to
0fa9f5b
Compare
0fa9f5b to
a652aab
Compare
e576b6d to
2f92241
Compare
2f92241 to
831ae23
Compare
b7aebd3 to
d5f71a4
Compare
Resolve the Kubernetes isolation provider on the shared protobuf gRPC transport with mTLS and pod port-forwarding.
d5f71a4 to
055ac40
Compare
| async deletePod(namespace: string, name: string, signal?: AbortSignal): Promise<void> { | ||
| try { | ||
| await this.#core.deleteNamespacedPod( | ||
| { name, namespace, gracePeriodSeconds: 0 }, |
There was a problem hiding this comment.
nit: could this leave stuff running if the delete fails?
There was a problem hiding this comment.
Yes, a failed DELETE can leave the pod present. Non-404 errors propagate and cause cleanup to fail; pod active deadlines and expiry reconciliation provide additional cleanup attempts.
I've clarified the README and architecture guide that zero-grace deletion and API NotFound confirm object removal, not that the process has stopped on its node. The safeguards depend on kubelet/control-plane availability and cannot prove termination during a node outage.
| timeout.unref(); | ||
| void this.#watch.watch( | ||
| `/api/v1/namespaces/${encodeURIComponent(namespace)}/pods`, | ||
| { fieldSelector: `metadata.name=${name}` }, |
There was a problem hiding this comment.
if a delete happens between the get and the watch, the watch can miss it and report a failure. you can connect them through resourceVersion.
| accepted?.destroy(); | ||
| closeWebSocket(websocket); | ||
| await closeServer(server); | ||
| finish(); |
There was a problem hiding this comment.
this resolves closed before the websocket close is confirmed.
There was a problem hiding this comment.
Fixed. The deletion watch now starts from the resource version observed by the initial GET, closing that gap.
Expired watch versions trigger a fresh read and a filtered LIST to obtain the current collection version—a GET alone can still return the pod's old, compacted version. Recovery stays within the original deadline.
Added regressions for deletion between GET and watch establishment, compaction recovery with an unchanged pod version, repeated expiry, and cancellation during recovery.
| candidateTimeoutMs = 5_000 | ||
| ): Promise<ReconciliationSummary> { | ||
| const summary: ReconciliationSummary = { deletedNames: [], failureCount: 0 }; | ||
| const pods = await api.listManagedPods(namespace, profile); |
There was a problem hiding this comment.
this happens before deadline enforcement so it can hang reconciliation.
There was a problem hiding this comment.
Fixed. Tunnel cleanup now waits for actual WebSocket closure separately from the execution outcome. Closing the local TCP socket or receiving a transport error no longer satisfies that cleanup wait.
The wait includes forwarding handles acquired after shutdown begins and remains bounded by the existing cleanup deadline. Added regressions for a WebSocket held in CLOSING, closure timeout, errors before closure, and late acquisition. A provider-level test also verifies that pod deletion proceeds while tunnel closure is stuck.
| } | ||
|
|
||
| if ( | ||
| process.argv[1] |
There was a problem hiding this comment.
This is the direct-execution guard. It starts the server when invoked as the entry point while allowing tests to import startServer() and inject fake providers without automatically starting another server. realpathSync() makes the comparison work through symlinks, including npm executable links.
There was a problem hiding this comment.
In short, it allows unit tests to import the server without starting it.
|
Notes from the automated review:
For 2, I'm thinking this is a bit more idiomatic Kube:
If we use Istio or Maistra, then we can mTLS for free. |
…cript-k8s-isolation-provider # Conflicts: # src/oci-javascript-mcp-server/package-lock.json # src/oci-javascript-mcp-server/package.json
Description
Extends the existing
oci-javascript-mcp-serverwith a Kubernetes isolation provider while preserving Podman as the default. Provider and profile selection are trusted startup configuration, use exact accepted values, and fail closed without falling back to another runtime or credential source.The Kubernetes provider includes:
local-development,in-cluster, andkata-in-clusterprofiles behind a shared isolation-provider interface.RuntimeClassand handler where applicable.The motivation is to support cluster-managed execution and an optional Kata-backed deployment profile without weakening the server's trusted-host boundary or changing existing Podman deployments. The standard Kubernetes profiles provide container isolation only. The Kata profile is intentionally documented as a proof of concept and still requires deployment-specific runtime evidence and a current security review before it can be treated as a VM-grade boundary.
The implementation adds
@kubernetes/client-nodeand its WebSocket type support. Kubernetes deployments require access to a compatible cluster, the documented namespaces and RBAC/admission/network controls, a digest-pinned runner image, and a reviewed KataRuntimeClassforkata-in-cluster. The credential synchronization helper additionally requires Python 3 and an existing OCI CLI configuration. Podman remains the default and gains no new Kubernetes dependency at runtime. No downstream module changes are required.Additional unit-test coverage identified and corrected four behavior defects:
fails closed, and the initial readiness GET and watch both respect
cancellation and the absolute execution deadline.
named profiles that inherit a DEFAULT security-token path and profiles that
explicitly override or clear that value.
with regression cases for strings, templates, regular expressions, postfix
division, and JavaScript line terminators.
discover_ociexamples now represent required array fields as arrays,including model arrays, while retaining bounded model expansion.
The suite also verifies concurrent RPC response correlation with reversed
replies and mixed success/failure outcomes, plus background reconciliation's
immediate execution, prevention of overlapping cycles, recovery after failure,
and idempotent stop behavior. These tests use fake APIs and controlled responses.
The RPC protocol and reconciliation shutdown contract are unchanged.
Type of change
How Has This Been Tested?
Run the following from
src/oci-javascript-mcp-server:npm run check— TypeScript validation passed.npm run packcheck— npm package dry-run verification passed.npm run check:kubernetes-manifests— all 14 standard and Kata Kubernetes manifest tests passed.git diff --check 6633b602248bf44dbaf9aebe2e584c4a53622f1a...HEAD— passed with no whitespace errors.npm run ci— 184 tests passed with 95.39% coverageAdditionally, I tested in both
local-developmentandin-clusterkubernetes isolation provider profile modes.Latest whole-server validation, run from the repository root:
moon run --no-actions oci-javascript-mcp-server:check oci-javascript-mcp-server:test— native setup, protobuf compilation, TypeScript checking, and the c8 test
task passed.
and 95.75% lines. All configured 90% coverage thresholds passed.
corrections and passing afterward. Additional review regressions cover
late readiness events and JavaScript source-preservation edge cases.
git diff --checkpassed.--no-actionsbypassed dependency setup/synchronization after npm dedupestalled; compilation, checking, tests, and coverage enforcement still ran.
These results validate the installed dependency environment. Fake API tests
do not establish real-cluster runtime or admission-policy behavior.
Test Configuration:
arm64)oci-sdk2.132.x;@kubernetes/client-node2.x;@modelcontextprotocol/sdk1.29.xChecklist: