Skip to content

Adds oci-javascript-mcp-server Kubernetes/Kata Isolation Provider - #431

Open
dustin-sale wants to merge 33 commits into
oracle:mainfrom
gebhardtr:dustin-sale/oci-javascript-k8s-isolation-provider
Open

dustin-sale wants to merge 33 commits into
oracle:mainfrom
gebhardtr:dustin-sale/oci-javascript-k8s-isolation-provider

Conversation

@dustin-sale

@dustin-sale dustin-sale commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Description

Extends the existing oci-javascript-mcp-server with 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:

  • Explicit local-development, in-cluster, and kata-in-cluster profiles behind a shared isolation-provider interface.
  • A fresh, credential-free Kubernetes pod for each JavaScript execution, connected to the trusted host over a bounded framed exec channel while OCI credentials and SDK clients remain on the host.
  • Fixed non-root pod security settings, disabled service-account token mounting and service links, bounded memory-backed temporary storage, and reviewed CPU, memory, and ephemeral-storage ranges.
  • Startup preflight checks for namespaces, exact RBAC permissions, admission-policy behavior, image digest pinning, and the Kata RuntimeClass and handler where applicable.
  • Fail-closed lifecycle handling with absolute deadlines, cancellation, bounded cleanup tails, concurrent channel shutdown and zero-grace pod deletion, and deletion confirmation.
  • A cleanup-only reconciler for expired managed pods with separately constrained permissions and per-candidate time bounds.
  • Hardened worker-channel validation and budgets for framing, RPC IDs, messages, logs, results, concurrency, egress, and transport backpressure.
  • Versioned standard Kubernetes and Kata manifests, container build assets, an OCI session-secret synchronization helper, local dry-run tooling, OpenSpec artifacts, deployment guidance, and security limitations.
  • Fake-API, provider, lifecycle, cancellation, reconciliation, hostile-channel, manifest, configuration, and optional real-cluster tests across all three profiles.

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-node and 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 Kata RuntimeClass for kata-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:

  • Kubernetes readiness now requires an observed Running pod. Normal watch EOF
    fails closed, and the initial readiness GET and watch both respect
    cancellation and the absolute execution deadline.
  • OCI authentication selection now follows SDK profile inheritance, including
    named profiles that inherit a DEFAULT security-token path and profiles that
    explicitly override or clear that value.
  • Final JavaScript expression results are preserved when followed by comments,
    with regression cases for strings, templates, regular expressions, postfix
    division, and JavaScript line terminators.
  • discover_oci examples 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

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

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% coverage

Additionally, I tested in both local-development and in-cluster kubernetes 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.
  • 326 tests passed, 6 skipped, 0 failed.
  • Aggregate coverage: 95.75% statements, 91.29% branches, 95.58% functions,
    and 95.75% lines. All configured 90% coverage thresholds passed.
  • The four behavior fixes have regressions demonstrated failing before the
    corrections and passing afterward. Additional review regressions cover
    late readiness events and JavaScript source-preservation edge cases.
  • git diff --check passed.

--no-actions bypassed dependency setup/synchronization after npm dedupe
stalled; 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:

  • Firmware version: Not applicable
  • Hardware: Apple Silicon (arm64)
  • Toolchain: macOS 26.6.2; Node.js 22.14.0; npm 11.18.0; TypeScript 5.9.3
  • SDK: oci-sdk 2.132.x; @kubernetes/client-node 2.x; @modelcontextprotocol/sdk 1.29.x

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@oracle-contributor-agreement oracle-contributor-agreement Bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Sep 3, 2026
@dustin-sale dustin-sale changed the title Dustin sale/oci javascript k8s isolation provider Adds oci-javascript-mcp-server Kubernetes/Kata Isolation Provider Sep 3, 2026
@dustin-sale
dustin-sale force-pushed the dustin-sale/oci-javascript-k8s-isolation-provider branch 2 times, most recently from a5b46e4 to 0fa9f5b Compare September 3, 2026 19:43
@dustin-sale
dustin-sale force-pushed the dustin-sale/oci-javascript-k8s-isolation-provider branch from 0fa9f5b to a652aab Compare September 3, 2026 19:52
@dustin-sale
dustin-sale force-pushed the dustin-sale/oci-javascript-k8s-isolation-provider branch from e576b6d to 2f92241 Compare September 4, 2026 14:39
@dustin-sale
dustin-sale marked this pull request as ready for review September 4, 2026 18:21
@dustin-sale
dustin-sale marked this pull request as draft September 4, 2026 19:05
@dustin-sale
dustin-sale marked this pull request as ready for review September 4, 2026 20:09
@dustin-sale
dustin-sale force-pushed the dustin-sale/oci-javascript-k8s-isolation-provider branch from 2f92241 to 831ae23 Compare September 16, 2026 13:03
@dustin-sale
dustin-sale marked this pull request as draft September 30, 2026 13:24
@dustin-sale
dustin-sale force-pushed the dustin-sale/oci-javascript-k8s-isolation-provider branch 3 times, most recently from b7aebd3 to d5f71a4 Compare September 30, 2026 16:49
Resolve the Kubernetes isolation provider on the shared protobuf gRPC transport with mTLS and pod port-forwarding.
@dustin-sale
dustin-sale force-pushed the dustin-sale/oci-javascript-k8s-isolation-provider branch from d5f71a4 to 055ac40 Compare September 30, 2026 17:14
@gebhardtr

gebhardtr commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Notes from the automated review:

  1. It reintroduces runtime admission probing and “assurance” descriptors—the deployment-policy responsibility we previously moved out of the server. I’d keep those checks in deployment validation.
  2. It carries gRPC through a Kubernetes port-forward tunnel, alongside an exec bootstrap channel. That preserves our RPC contract, but puts execution traffic through the Kubernetes control plane and adds tunnel lifecycle code. This deserves an explicit architecture decision.
  3. Parser fixes, OCI profile inheritance changes, and native-install hardening should be separate contributions. They broaden review beyond Kubernetes support.
  4. The provider factory eagerly imports Kubernetes dependencies even for Podman; loading them only when selected is a small, useful trim.

For 2, I'm thinking this is a bit more idiomatic Kube:

  1. Create an execution-specific Secret containing only the runner’s TLS material.
  2. Mount it read-only into that runner.
  3. Start the runner normally; it reads the files and opens its gRPC listener.
  4. Connect directly using mTLS, then clean up the pod and Secret afterward.

If we use Istio or Maistra, then we can mTLS for free.

@dustin-sale

Copy link
Copy Markdown
Contributor Author

@gebhardtr I have addressed items 1,2, and 4 from your prior comment.

  1. Moved runtime admission policy checks to a separate deployment script.

  2. Addressed the gRPC gaps:
    Direct host-to-runner connections: The trusted host connects to each runner’s pod IP on TCP 50051, replacing exec bootstrap and port-forward tunnels. Workstation local-development keeps its tunnel path.
    Per-execution mTLS Secrets: Each runner starts with a read-only TLS Secret containing its certificate/key and the host’s public certificate. OCI credentials and the host’s private key stay on the host.
    Updated deployment controls: Host RBAC now grants Secret lifecycle operations instead of exec/port-forward access. Admission rules enforce the TLS mount, and NetworkPolicy permits gRPC ingress only from the trusted host.
    Stronger cleanup and cancellation: Cleanup removes both the runner pod and TLS Secret, including orphaned Secrets. The latest tests verify cancellation after execution actually starts, and direct connections now support IPv6 runner addresses.

  3. Provider factory now lazy loads the provider imports.

Signed-off-by: Dustin Sale <dustin.sale@oracle.com>
}

async preflight(options: { startReconciliation?: boolean } = {}): Promise<void> {
this.#ready = false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need checks for namespace, identity, RBAC, admission behavior, RuntimeClass, and node-profile evidence

@dustin-sale dustin-sale Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You requested that I move the admission probing out of the server in this comment, do I need to add it back?

if (user.exec != null || user.authProvider != null) {
throw new ValidationInputError("Kubeconfig exec and auth-provider helpers are unsupported; use token or client-certificate credentials");
}
if (options.impersonate) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relies on Kubernetes’ service-account impersonation behavior: when Impersonate-User names a service account and no Impersonate-Group headers are supplied, the API server derives its normal service-account groups and adds system:authenticated. See the upstream implementation.

The check below verifies the effective identity returned by SelfSubjectReview, including those groups, rather than assuming impersonation succeeded. Missing or unexpected groups fail validation.

I think the current approach is valid, but it deserves an explanatory comment and verification against our target Kubernetes release—the fake-API tests alone don’t establish that behavior.

() => api.selfCan({ resource, subresource, verb, namespace: options.config.namespace }, signal),
passed => ({ passed, detail: "Required execution permission must be allowed" }))) return report;
}
const policy = runtimePolicyFor(options.config);

@gebhardtr gebhardtr Nov 4, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we also have an exact Kata profile and a dedicated execution worker pool check here?

and does the policy validation here have to be code that checks individual properties? or do we just hash/version the policy yaml and verify the deployed policy and binding against that version?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants