diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbf0c207..4ed813a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,6 +9,27 @@ on: permissions: contents: read jobs: + javascript: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: "26" + cache: npm + cache-dependency-path: src/oci-javascript-mcp-server/package-lock.json + + - name: Install dependencies + working-directory: src/oci-javascript-mcp-server + run: npm ci + + - name: Test, coverage, type check, and package verification + working-directory: src/oci-javascript-mcp-server + run: npm run ci + build: runs-on: ubuntu-latest needs: get-directories @@ -77,7 +98,7 @@ jobs: - name: Get directories id: get-directories run: | - directories=$(ls src | grep -v dbtools-mcp-server | grep -v mysql-mcp-server | grep -v oci-pricing-mcp-server | grep -v oracle-db-doc-mcp-server | grep -v oracle-db-mcp-java-toolkit | jq -R -s -c 'split("\n")[:-1]') + directories=$(ls src | grep -v dbtools-mcp-server | grep -v mysql-mcp-server | grep -v oci-javascript-mcp-server | grep -v oci-pricing-mcp-server | grep -v oracle-db-doc-mcp-server | grep -v oracle-db-mcp-java-toolkit | jq -R -s -c 'split("\n")[:-1]') echo "directories=$directories" >> $GITHUB_OUTPUT combined-coverage: diff --git a/README.md b/README.md index 1c64850e..b9e3b2d3 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,12 @@ Use [`oci-api-mcp-server`](src/oci-api-mcp-server/README.md) instead when you sp Choose one of the other purpose-built servers when you already know the Oracle product or OCI domain you want to work with. These servers target specific service and product workflows rather than providing a general OCI entry point. Browse the [`src/`](src/) directories and read the relevant `src//README.md` before configuring one. +For the experimental Node.js code-execution workflow, see +[`oci-javascript-mcp-server`](src/oci-javascript-mcp-server/README.md). Its +locally runnable process provider is explicitly development-only; production +startup remains disabled until an approved VM-backed isolation provider is +implemented. + ### Recommended: OCI Cloud MCP Server Run the server over stdio: diff --git a/src/oci-javascript-mcp-server/.dockerignore b/src/oci-javascript-mcp-server/.dockerignore new file mode 100644 index 00000000..91d8632e --- /dev/null +++ b/src/oci-javascript-mcp-server/.dockerignore @@ -0,0 +1,8 @@ +* +!package.json +!src/ +!src/facade.ts +!src/oci.ts +!src/protocol.ts +!src/runner.ts +!src/types.ts diff --git a/src/oci-javascript-mcp-server/.gitignore b/src/oci-javascript-mcp-server/.gitignore new file mode 100644 index 00000000..e1b28706 --- /dev/null +++ b/src/oci-javascript-mcp-server/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +coverage/ +.nyc_output/ +dist/ diff --git a/src/oci-javascript-mcp-server/Containerfile b/src/oci-javascript-mcp-server/Containerfile new file mode 100644 index 00000000..866b2574 --- /dev/null +++ b/src/oci-javascript-mcp-server/Containerfile @@ -0,0 +1,14 @@ +# Copyright (c) 2026, Oracle and/or its affiliates. +# Licensed under the Universal Permissive License v1.0 as shown at +# https://oss.oracle.com/licenses/upl. + +FROM node:26-bookworm-slim@sha256:cd565714d4da3e84bfd341e31448f81d47c6362198f152345297c9c1154e6341 + +WORKDIR /app + +COPY --chown=65532:65532 package.json ./package.json +COPY --chown=65532:65532 src/facade.ts src/oci.ts src/protocol.ts src/runner.ts src/types.ts ./src/ + +USER 65532:65532 + +CMD ["node", "--experimental-strip-types", "--max-old-space-size=256", "/app/src/runner.ts"] diff --git a/src/oci-javascript-mcp-server/LICENSE.txt b/src/oci-javascript-mcp-server/LICENSE.txt new file mode 100644 index 00000000..50602a0c --- /dev/null +++ b/src/oci-javascript-mcp-server/LICENSE.txt @@ -0,0 +1,37 @@ +Copyright (c) 2026, Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely licensable +by each licensor hereunder covering either (i) the unmodified Software as +contributed to or provided by such licensor, or (ii) the Larger Works (as +defined below), to deal in both + +(a) the Software, and + +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if one +is included with the Software (each a “Larger Work” to which the Software is +contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the Software +and the Larger Work(s), and to sublicense the foregoing rights on either these +or other terms. + +This license is subject to the following condition: + +The above copyright notice and either this complete permission notice or at a +minimum a reference to the UPL must be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/oci-javascript-mcp-server/README.md b/src/oci-javascript-mcp-server/README.md new file mode 100644 index 00000000..49a8fbfd --- /dev/null +++ b/src/oci-javascript-mcp-server/README.md @@ -0,0 +1,325 @@ +# OCI JavaScript MCP Server + +`oci-javascript-mcp-server` is a stdio MCP server that runs complete JavaScript +programs with an SDK-shaped OCI facade. OCI credentials, SDK clients, signing, +network access, request authorization, deadlines, and byte budgets remain in a +trusted host broker. + +This repository version is a locally testable vertical slice of a VM-oriented +architecture. For Apple-silicon development machines, the preferred +`apple-container` provider runs every execution in a fresh lightweight Linux VM. +An **insecure local process provider** remains available for development and CI. +Neither provider is admitted in production. + +## Architecture and trust boundary + +```text +MCP client + -> trusted stdio MCP host + -> host-owned execution policy + -> bounded, versioned JSON broker channel + -> OCI SDK + host credentials + OCI network + -> isolation provider + -> fresh Apple container VM, or ordinary Node.js process + -> Node.js runner + -> vm.Context + -> user JavaScript + narrow oci facade +``` + +The provider creates the runner and gives it one pre-opened, execution-bound +channel. No bearer token is placed in the runner. Both included providers map +that channel to stdin/stdout pipes. OCI credentials, configuration files, SDK +clients, and the MCP transport remain outside the runner. + +Node's `vm.Context` only shapes the JavaScript API. It is **not** a secure +sandbox for hostile code. A context escape is treated as compromise of the +whole runner, including its memory and open descriptors. The host therefore +validates and authorizes every raw channel message as hostile input. + +## Requirements and installation + +Node.js 26 or newer is required. + +```sh +cd src/oci-javascript-mcp-server +npm install +``` + +No `isolated-vm` or other native V8 isolation dependency is used. + +## Run locally with an Apple container VM + +This is the recommended development configuration on Apple silicon. Apple's +[`container`](https://github.com/apple/container) requires macOS 26 or newer. +Install its latest signed package from the +[`container` releases page](https://github.com/apple/container/releases/latest). +The package installs the CLI at `/usr/local/bin/container`. From the repository +root, prepare and verify the local runtime: + +```sh +cd src/oci-javascript-mcp-server +/usr/local/bin/container --version +/usr/local/bin/container system start +/usr/local/bin/container system status +npm run apple-container:build +/usr/local/bin/container network create --internal oci-javascript-mcp-internal +``` + +The image build is required after runner-image changes. The network creation +command is a one-time setup step; do not repeat it if the network already +exists. Then start the MCP server directly: + +```sh +OCI_JAVASCRIPT_MODE=development \ +OCI_JAVASCRIPT_ISOLATION_PROVIDER=apple-container \ +OCI_JAVASCRIPT_APPLE_CONTAINER_CLI=/usr/local/bin/container \ +npm start +``` + +When using this server through Codex, add the equivalent STDIO entry to +`~/.codex/config.toml`, restart Codex, and use `/mcp` to confirm that the server +connected. + +### Shut down + +If the MCP server was started directly with `npm start`, press `Ctrl-C` in that +terminal. Active execution containers are removed automatically when execution +completes or is cancelled. + +After the MCP server has exited and no other workloads need Apple's container +runtime, stop the subsystem: + +```sh +/usr/local/bin/container system stop +``` + +Every execution launches a fresh, named VM using the locally built +`localhost/oci-javascript-mcp-runner:dev` image. The loopback-qualified name +also prevents a missing development image from resolving to a similarly named +public registry repository. The provider mounts no host paths, passes no host +credentials or OCI environment variables, runs as UID/GID 65532, uses a +read-only root filesystem, drops all Linux capabilities, disables DNS, and +limits the guest to one CPU, 512 MiB of memory, and 64 open files. Completion, +cancellation, protocol failure, and timeout all trigger forced cleanup by +execution name. + +The default image and internal network can be overridden when necessary: + +```sh +OCI_JAVASCRIPT_APPLE_CONTAINER_IMAGE=registry.example/runner@sha256:... \ +OCI_JAVASCRIPT_APPLE_CONTAINER_NETWORK=my-internal-network +``` + +The image reference should be pinned by digest outside local iteration. The +included `Containerfile` pins its Node base image by multi-platform digest. + +Apple's [command reference](https://github.com/apple/container/blob/main/docs/command-reference.md) +defines an `--internal` network as host-only, not as the absence of a network +device. A compromised guest can therefore still create sockets and probe +reachable host or peer services. This limitation is represented by +`networkCreationBlocked: false`; the provider is stronger than a host process +but remains development-only and is rejected in production. + +## Insecure process fallback + +The insecure process provider requires both development mode and explicit +opt-in: + +```sh +OCI_JAVASCRIPT_MODE=development \ +OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS=1 \ +npm start +``` + +The host reads OCI credentials using the standard JavaScript SDK configuration. +Select a non-default local profile when needed: + +```sh +OCI_CONFIG_PROFILE=MY_PROFILE \ +OCI_JAVASCRIPT_MODE=development \ +OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS=1 \ +npm start +``` + +The development policy is read-only by default. Mutating OCI operations require +a deliberate additional local opt-in: + +```sh +OCI_JAVASCRIPT_ALLOW_MUTATIONS=1 +``` + +That setting does not make either included provider production-eligible. + +## MCP client configuration + +Use `node` directly so npm lifecycle output cannot interfere with stdio MCP +messages: + +```json +{ + "mcpServers": { + "oci-javascript-mcp-server": { + "type": "stdio", + "command": "node", + "args": [ + "--experimental-strip-types", + "/absolute/path/to/mcp/src/oci-javascript-mcp-server/src/server.ts" + ], + "env": { + "OCI_JAVASCRIPT_MODE": "development", + "OCI_JAVASCRIPT_ISOLATION_PROVIDER": "apple-container", + "OCI_CONFIG_PROFILE": "DEFAULT" + } + } + } +} +``` + +## MCP tools + +### `run_javascript` + +Inputs: + +- `code`: required JavaScript source string. +- `timeout`: optional seconds, default `30`, range `1` through `120`. + +The tool returns: + +```json +{ + "result": null, + "error": null, + "stdout": "", + "stderr": "", + "exit_code": 0, + "timed_out": false +} +``` + +The last JavaScript expression becomes `result`: + +```js +const config = await oci.config(); +const response = await oci.identity.IdentityClient.listRegionSubscriptions({ + tenancyId: config.tenancyId +}); +response.items.map(item => item.regionName); +``` + +Constructed clients and per-client region selection are supported: + +```js +const compute = new oci.core.ComputeClient({ region: "us-ashburn-1" }); +const response = await compute.listInstances({ + compartmentId, + limit: 50 +}); +response.items.map(instance => instance.displayName); +``` + +Only `region` is accepted as a client option. Arbitrary endpoints, credential +providers, signers, and retry configuration are rejected. SDK pagination +helpers and local utility methods are not exposed; use request `page` and +response `opcNextPage` fields directly. + +Shallow reflection works with `Object.keys(oci)`, `Object.keys(oci.core)`, and +`Object.keys(new oci.core.ComputeClient())`. + +### `discover_oci` + +`discover_oci` accepts optional `service`, `client`, and `operation` filters. It +reads installed SDK declarations without running untrusted code and reports: + +- supported services and client classes; +- actual API operations that have SDK request types; +- operation request fields and required-field metadata; +- basic response and pagination information. + +## Validation + +Run these commands from `src/oci-javascript-mcp-server`: + +```sh +npm test +npm run coverage +npm run check +npm run ci +``` + +`npm run coverage` enforces at least 90% line coverage. `npm run ci` runs +coverage, TypeScript checking, and a package dry-run. + +## Production admission + +Production is the default mode. Both included providers fail closed in +production: + +- Without `OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS=1`, startup rejects the + insecure provider opt-in. +- With that opt-in but `OCI_JAVASCRIPT_MODE=production`, trusted admission still + rejects the provider because it lacks a separate guest kernel, hardware + virtualization, and enforced blocking of new network sockets. +- The Apple container provider has a separate hardware-virtualized guest kernel, + but production still rejects it because its host-only network does not prevent + socket creation and the provider remains explicitly development-only. +- Selecting an unimplemented provider also fails startup. + +A production provider must report and independently demonstrate an approved +virtual-machine boundary, a separate guest kernel, hardware virtualization, +network-creation blocking, deterministic teardown, and a host-bound channel. +Capability metadata is descriptive; the trusted host admission decision is +authoritative. + +## Security controls in this slice + +- Four-byte length-prefixed, versioned JSON frames with a 2 MiB hard ceiling. +- Oversized frame rejection from the length header before parsing the body. +- Fatal UTF-8 decoding and inert JSON parsing. +- Recursive rejection of `__proto__`, `prototype`, `constructor`, and type-tag + keys. +- Depth, string, array, object-key, node, request, response, result, and output + limits. +- Exact message schemas and rejection of unknown versions, message types, and + fields. +- Fresh null-prototype canonical OCI request objects built from SDK request + field allowlists. +- Host-owned operation, mutation, region, tenancy, compartment, resource, + deadline, call, concurrency, request-byte, and response-byte policy seams. +- OCI response sanitization removes credential-like and HTTP transport fields. +- A scrubbed runner environment and no `process`, `require`, filesystem, + child-process, or general network globals in the `vm.Context`. +- Cancellation and deadlines forcibly terminate the runner process group. +- Apple container executions add a fresh VM boundary, no host mounts, read-only + rootfs, non-root execution, dropped capabilities, resource limits, and named + forced cleanup. + +## Deliberately deferred work and limitations + +This spike does not yet implement Firecracker, Kata Containers, or another +production-approved VM provider with independently enforced network-creation +blocking. Consequently it is suitable only for local development and CI, not +hostile production execution. + +The Apple container provider requires Apple silicon and macOS 26 or newer. Its +internal network prevents external routing but remains host-only rather than +socketless, so a compromised guest may reach services on that network. The +runner image must be built before starting the MCP server; the provider does not +build or update images during execution. + +The process provider cannot stop a fully compromised runner process from using +the host kernel or creating sockets. That limitation is explicit in its +capability metadata and is why production admission rejects it. The broker is +still designed and tested to remain authorization-safe when a compromised +runner bypasses the facade and drives the pre-opened channel directly. + +The final production source for per-execution tenancy, compartment, resource, +and operation policy is not yet selected. Production defaults therefore expose +no OCI operations. Development policy is generated explicitly from installed +SDK request declarations and defaults to read-only. + +## License + +Copyright (c) 2026, Oracle and/or its affiliates. + +Released under the Universal Permissive License v1.0; see `LICENSE.txt`. diff --git a/src/oci-javascript-mcp-server/package-lock.json b/src/oci-javascript-mcp-server/package-lock.json new file mode 100644 index 00000000..63fb546e --- /dev/null +++ b/src/oci-javascript-mcp-server/package-lock.json @@ -0,0 +1,3772 @@ +{ + "name": "oci-javascript-mcp-server", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "oci-javascript-mcp-server", + "version": "0.1.0", + "license": "UPL-1.0", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "oci-common": "^2.132.0", + "oci-sdk": "^2.132.0", + "zod": "^4.4.3" + }, + "bin": { + "oci-javascript-mcp-server": "src/server.ts" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "c8": "^12.0.0", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=26" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@hono/node-server": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.0.tgz", + "integrity": "sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@types/isomorphic-fetch": { + "version": "0.0.35", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.3", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "25.9.1", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/opossum": { + "version": "4.1.1", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/sshpk": { + "version": "1.10.3", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/await-semaphore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", + "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "license": "BSD-3-Clause" + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c8": { + "version": "12.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^8.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^18.0.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "4.2.6", + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.0.tgz", + "integrity": "sha512-jhunvfHWxd7J5EFfSgH4xsYJzSe/lfqbUCxiyyeaQasUsXeEHXtzVid+7EOGByc5JnFa23SSFL3Y2RV/z1T+eQ==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-signature": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz", + "integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jose": { + "version": "6.2.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "license": "BSD-2-Clause" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/jssha": { + "version": "3.3.1", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.5.2", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oci-accessgovernancecp": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-accessgovernancecp/-/oci-accessgovernancecp-2.139.0.tgz", + "integrity": "sha512-z9fTz7b/g4cY+Ul51wTwNzZ3BIEav2V9u1O0Rp5FNWZtlK79g94JdP2thdguF5gS8b5nbJrNxUHSEoq2f6YrzA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-adm": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-adm/-/oci-adm-2.139.0.tgz", + "integrity": "sha512-x4fmi3hR+7Nkxt7XHMoSObHd5thTphB5gcZYYftP2ulyu4FgtxWfF7D+w3E3jZH4frYJk3vNs7YT7YreCXg2NA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-aidataplatform": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-aidataplatform/-/oci-aidataplatform-2.139.0.tgz", + "integrity": "sha512-kurIZpVoZ0vdgR9A1z56j6mpFxZiJ2y5n9qKhP9wC1YzUbbG2DojdaQor08wjAhvrHeGu7jS3c1j/m+aPGjeYw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-aidocument": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-aidocument/-/oci-aidocument-2.139.0.tgz", + "integrity": "sha512-E0M5NW8C46kSZpY4qKx7asiUDAadAXPHojFOUL1APJAAHVfaFEjV6tNB3FpBuAFIQRDg1rg1J/PaMHAJJuLSQg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-ailanguage": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-ailanguage/-/oci-ailanguage-2.139.0.tgz", + "integrity": "sha512-pUashLUKIziC7EjNkdn+IbE3cCi8pwN9X2HsTQKwBEgZ4PkmXGRV0aHIEavTYuoO2+MpRTiK12FaqeJb4V8Xrw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-aispeech": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-aispeech/-/oci-aispeech-2.139.0.tgz", + "integrity": "sha512-LkMrSB3+jHTbvDTSLMA4dgxYRPzZHC3m6sCB0ykLn0CWRs6jlptHnZ/061K7FYQ2DpeQQ3eCj6h7HcZHDrbnkA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-aivision": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-aivision/-/oci-aivision-2.139.0.tgz", + "integrity": "sha512-EUsNGyq4OyhBSF4heR12dCHDQQT4HgP2pF4OMRUWHiDcF4/2CKyGKu+WefF9Q0pchVL+dM7TguUQY0ETecMPhA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-analytics": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-analytics/-/oci-analytics-2.139.0.tgz", + "integrity": "sha512-ExJ4OY/v/TjisfMs3xJCYBJX0QvjtWnna3nGgp84QcxVwcfyvHfOI0KxX0FVxd0LXm4UVJC3m1WnuuYLiv9eBw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-announcementsservice": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-announcementsservice/-/oci-announcementsservice-2.139.0.tgz", + "integrity": "sha512-CX75CTZDCFp3HL7OJFPxx0LM0IuO+N798YmFiiN+hJjZDd0mUdUNet04PYIXKVYDPX4owE+NWZVgT2e0l3sC5w==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apiaccesscontrol": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apiaccesscontrol/-/oci-apiaccesscontrol-2.139.0.tgz", + "integrity": "sha512-KTgQZ1kOfdk4l2H6G2uOVh2UDFBWSdH4mQRJNsr0vZrfSAUPb2u7UDYQKdWvz8bXl28GGum2/+BAZk4FM5GpoA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apigateway": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apigateway/-/oci-apigateway-2.139.0.tgz", + "integrity": "sha512-v7v/yhcslI2PPoOHvxLewgEzjXAo1qCjnt8SjuRqsfpCRkkFDkGy8AOQolQRPIkNE8si4LwB98GEdyUzIgrZUA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apiplatform": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apiplatform/-/oci-apiplatform-2.139.0.tgz", + "integrity": "sha512-3ARdVH2vJ9WjW9u0qdpQ50yE0m/s9G5DlAQtDBnHQT7oUs2+31Ek/SKnDTI05G5FKnywKTSNPCJadiesOlRcTg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apmconfig": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apmconfig/-/oci-apmconfig-2.139.0.tgz", + "integrity": "sha512-q+z1ZGJKcx2TOKCm5afOVdKThWv5S9tZAc+/uDwkkzpx8TEip1uSpFo5wfjD2e/Sc50VNVkGHg0WnCUYjOFHKw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apmcontrolplane": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apmcontrolplane/-/oci-apmcontrolplane-2.139.0.tgz", + "integrity": "sha512-p1kl6gVRJ4+PK6vUE6hYzHSZfrhKI42kMH+Vx8FEYU4qeli4q+8XbttPm3UbnKrH7irgSYSn3b9RiSB9x2a8OQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apmsynthetics": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apmsynthetics/-/oci-apmsynthetics-2.139.0.tgz", + "integrity": "sha512-+bnaRh20OJkpzlOrVx/DgAkUFczTwgEZc6N6hf0w7dGNzxd27R96AF+EUI2q5ZNGC4oNosXrqYK2k9oYOv545A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-apmtraces": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-apmtraces/-/oci-apmtraces-2.139.0.tgz", + "integrity": "sha512-WiDK9ovOGGFc/NccZXmD4VgXE9BTDpGy83kE84mZsXdAtNzWyFDMt0lvI7tFi3aQhhaNSKrSR84AoocEm60Fhg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-appmgmtcontrol": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-appmgmtcontrol/-/oci-appmgmtcontrol-2.139.0.tgz", + "integrity": "sha512-N34q+/FoXukR3W1HJGAoCgXhv5Mugj6k4Ktqu+3ZgSht/7jzN0I4OmJ3HHDqHJtMxk/iprY4JizFomUcpVE0rg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-artifacts": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-artifacts/-/oci-artifacts-2.139.0.tgz", + "integrity": "sha512-KgUQ6UH3QZ2eZz4eSCQmetXqZJbGjRTRXEbdMomszi4ju2DhCPxBvHrVvqkjEpQn/Lgm0i2UKjBIoMupFDXFWw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-audit": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-audit/-/oci-audit-2.139.0.tgz", + "integrity": "sha512-4ULfJMzO5XyLNTexB1dVI17qLcwtY3LmPEYb+RldsZBbA6K0Y4z86g+S+UEhfGBXipFL/fTLyMrO+uxJdWQapQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-autoscaling": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-autoscaling/-/oci-autoscaling-2.139.0.tgz", + "integrity": "sha512-KGMXihW0r2U9Ux3NYUkuVpGi8W7zU5TdE8orkTbdF6SXsJK7TWvWRdaeMmW5+onF4HnlrECW7LE5R2EhKKQpWw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-bastion": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-bastion/-/oci-bastion-2.139.0.tgz", + "integrity": "sha512-g/Zh2hWOlyE9AthLpemL3kShAhpkoXJiS3Msyexh6Xm6pzDYr2GBomZgO4iX87ovCNFsQKuqJvHzHbFoz4PWUw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-batch": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-batch/-/oci-batch-2.139.0.tgz", + "integrity": "sha512-x5zf+zrvf226/6FMibcUr3tQKiM78yKjquXnYRClhjBtIOkk2b5uYL+NX1NnqY2lAf3Phffztj+xENiyGkDREQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-bds": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-bds/-/oci-bds-2.139.0.tgz", + "integrity": "sha512-V2Y2ZbTjr/rSHKbtC6pPfFKv7kURWFr2Ob+FUzGPlyFXVncoePEwhu1yZBD4zL4P9kixtZULQJqWR67KZAI3RA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-blockchain": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-blockchain/-/oci-blockchain-2.139.0.tgz", + "integrity": "sha512-8K48cpZviW12ys6DYnelLyieqC094gjwqZgie4yT0ud3khyI7nYa3btTfg4kANNS892kclHCa9ujOVAkf4PfvQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-budget": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-budget/-/oci-budget-2.139.0.tgz", + "integrity": "sha512-w44z88qtfr8o9N62AusCH+yyEX6wGK4pqekoup0SdZw7uoCamjxBT6VDXDQmO74UkBtbus9XEby3OKmM4Ackww==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-capacitymanagement": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-capacitymanagement/-/oci-capacitymanagement-2.139.0.tgz", + "integrity": "sha512-89y08Ly5TZkzkP3lV99Ki9vzxUWtsR43MPtyFA5a8EoCTAbLuV0x/+ZVINBmPeM+kbiSl4EiTtpWD0Rqz713VQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-certificates": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-certificates/-/oci-certificates-2.139.0.tgz", + "integrity": "sha512-8YwBxixEFvWMOPwKEXYs3swk8kNrzd97NXWIga5smzLJJvDDQiOhXnpnw6hLJc0WNJyd7NVJMc1/yevAwQMRrQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-certificatesmanagement": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-certificatesmanagement/-/oci-certificatesmanagement-2.139.0.tgz", + "integrity": "sha512-xfhxjc8LcZmALresWlJ/dcyB+ucew2UoROo3RoBU25SelockSAn3vekHaa2x4JR+on/qGP6nGAQgOCphjWIK7g==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-cims": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-cims/-/oci-cims-2.139.0.tgz", + "integrity": "sha512-mUjOr7Oe9mnE4FWE4D0ynJcgJhcXCQiUoPRBoTdUs9POKX9ryKY7no+tREiYflZJBcAc1A55vJyQS1dOkFc71Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-cloudbridge": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-cloudbridge/-/oci-cloudbridge-2.139.0.tgz", + "integrity": "sha512-Df5HB3XFZXu0NKKYf9ZEjA9oQEuMvfVCSmVQsiVsXLbe1pITlALkiVp0jN7Uhwl87tgCD0j2t6OirYG1Axtocw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-cloudguard": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-cloudguard/-/oci-cloudguard-2.139.0.tgz", + "integrity": "sha512-3yaNeGbmgTIuJ0jd3N5xzJPos23gFiXBgCY8ApNdmM5EMIY5vh3K0hNRkt83aD8hci9PubXR+e5KjaP/2UC4Kg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-cloudmigrations": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-cloudmigrations/-/oci-cloudmigrations-2.139.0.tgz", + "integrity": "sha512-ZyVTenr8GgpZw7rcL61/5Rw9DRE9JS3uU4o9ReEUdpw7P3adMvPe20YDpPAqTqOrRwGiFQeB2K9ff2eL4kxaHw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-clusterplacementgroups": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-clusterplacementgroups/-/oci-clusterplacementgroups-2.139.0.tgz", + "integrity": "sha512-LgN6cpsQmzMRiOG8C/0KLZ9qhqKpdiFSw9EylZsJccgUv3BknwSliIvlChBntSsJHaCMJ3shD/OI73mN4E2/jA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-common": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-common/-/oci-common-2.139.0.tgz", + "integrity": "sha512-2CF5HWy9EmpKG2XwNYnHvJLATX71zfpirTJ8nLNL5KYJsp+hyOoTPVuTcdoz1zd+RvuSuD4OlPVSIAWpBcd4kw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "@types/isomorphic-fetch": "0.0.35", + "@types/jsonwebtoken": "9.0.3", + "@types/opossum": "4.1.1", + "@types/sshpk": "1.10.3", + "@types/uuid": "8.3.4", + "es6-promise": "4.2.6", + "http-signature": "1.3.1", + "isomorphic-fetch": "3.0.0", + "jsonwebtoken": "9.0.3", + "jssha": "3.3.1", + "opossum": "5.0.1", + "sshpk": "1.18.0", + "uuid": "11.1.1" + } + }, + "node_modules/oci-computecloudatcustomer": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-computecloudatcustomer/-/oci-computecloudatcustomer-2.139.0.tgz", + "integrity": "sha512-WtG2Y0YNC8a4/I++V0beoqRLpUzIfoYfU+j3JZQIwyqj4ehYcxi2dJ3q7msg+uSPKMsmctHVwF8DiVXfnBAcBA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-computeinstanceagent": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-computeinstanceagent/-/oci-computeinstanceagent-2.139.0.tgz", + "integrity": "sha512-QB6sct5xk+VJb19OGpE57ghnbkMBz7/tXLpqI/8xUWyzTZv7jd9pxKP+nYCaYt8AeH8qDXwzEOIsP/HXXhSlew==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-containerengine": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-containerengine/-/oci-containerengine-2.139.0.tgz", + "integrity": "sha512-yJgA4PeUwAhv+L9mpRcec5TdGTt0z5Gt5kE4A/iH8Jg1tlsqVAeYsJrQz5wqYFpfGFncr4N1BpZedvuo460vxA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-containerinstances": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-containerinstances/-/oci-containerinstances-2.139.0.tgz", + "integrity": "sha512-/8X/5S9lC70A3f07caLb9JjC/bhI/llNqVW+v9u6XkgrmI1fwdulXuJj8kAnxsZRULXtWo8HljzV3EHR5cEAHw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-containerregistry": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-containerregistry/-/oci-containerregistry-2.139.0.tgz", + "integrity": "sha512-gL8G3Trzrv8euQD9vHV4j5XQoHse/+oP9/lrHGj3yt+Ljip1i9Kp4vrdqVjiR8XeruklSp/MxQgB/rj4ogGSKA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-core": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-core/-/oci-core-2.139.0.tgz", + "integrity": "sha512-Qo8x7z3a/ZWdrvY7BapqlY0sgNK0/oQJgVgkGMW5S55zvnDUTkq4gMlfqGfsy+uKxkOwsnRVi3mfqzZhlF5vxQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "oci-workrequests": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-costad": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-costad/-/oci-costad-2.139.0.tgz", + "integrity": "sha512-+4j4u4zhnflD0I+p5YIatZiBQOrgn6PXCJSaJpSnUbL7+C9Lc7VMSXaAmHjzsTOYz6xOwtU1dIa0Z4BQGcS2Nw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dashboardservice": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dashboardservice/-/oci-dashboardservice-2.139.0.tgz", + "integrity": "sha512-HBqGD8+kgEgeM+89ziI6mGAUCuw4bta8Nt0YWFd/95EcrePI6+fvHddYIFosWjozJFMT+7lWeZbtvgMS/vRk5Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-database": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-database/-/oci-database-2.139.0.tgz", + "integrity": "sha512-o/Hw096b6TVx04XvmqiuAsxzqoxRjue2sGpAD6k9pU+/xhgI8i4a7jJCtZw5fK4UKlSPCpMC1FEQD5WB2NR6Jg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "oci-workrequests": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-databasemanagement": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-databasemanagement/-/oci-databasemanagement-2.139.0.tgz", + "integrity": "sha512-JuO8m2ipHay/52OHGNgwp9QyPSOABKT7CNxVP87WMyXLT+o9q5jeuTRACAfPyJxf6Bg+QcqheEiSGB38cOSQEQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-databasemigration": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-databasemigration/-/oci-databasemigration-2.139.0.tgz", + "integrity": "sha512-qCNbp5OcUrlG+DIGhELdKpLxoGHcN3XniQVGD8WW7OvVINJyl2j1Ng/+4OjHLRgnXqQp+IafziFNQl+N+0nDZA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-databasetools": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-databasetools/-/oci-databasetools-2.139.0.tgz", + "integrity": "sha512-KoKBDEZr/7PymBMMHNQuJm4MGoixDN5xMpvi5OPaj6/aS2vW2z6Y5Z4wLbyT8bvLLaiGXFgRwBmfzG5JznFKGw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-databasetoolsruntime": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-databasetoolsruntime/-/oci-databasetoolsruntime-2.139.0.tgz", + "integrity": "sha512-JoxkqHj8ELwlIl6dqv7yLnZeQmb+VkCZI7yH/5IT+qqQkGtonMCA1A1rUxsDTi3yBNlCr2W6sEwURq+v4B2d9A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-datacatalog": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-datacatalog/-/oci-datacatalog-2.139.0.tgz", + "integrity": "sha512-FI2yB1MLHYeRCfQcQ9kQ/BY1oeeEIWP/oNG0FwN8PSr1nWvop8XA9lEDsrCX8B+6GbQBpSLhOTwG6SS6APkDRw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-datacc": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-datacc/-/oci-datacc-2.139.0.tgz", + "integrity": "sha512-WY7iL40rFkiZySxYOypzMODPVmrmtfwwSCFx9gnW36ERYL5RWSKO6wtXDGoMgjsOnDweQb2lXrws2r4+Q/AoOA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dataflow": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dataflow/-/oci-dataflow-2.139.0.tgz", + "integrity": "sha512-nxv0qkJC9HSug9sFmoQU52MR7ElTDw1pIbKBb1f13ffhHZIOht4LYAaFEROgaUFf6yJ5G1T5YWXHinDMkWmAPg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dataintegration": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dataintegration/-/oci-dataintegration-2.139.0.tgz", + "integrity": "sha512-w7dm046ThIO5RyCdbfbQuAdkaVvvfWuS85HQSxw5WeiPIzudvlzLN1WTybrgazI2Mv/cQkS5gyGbEyihOX6P+A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-datalabelingservice": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-datalabelingservice/-/oci-datalabelingservice-2.139.0.tgz", + "integrity": "sha512-lMTWu0UDC2Wd7ZXOZOQvztdynK8SA+P6n/mrcqX7/7iWaFg00GRfA+sy8AOvM4J8iudv8G+yP9Fv3gE5wf1AMw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-datalabelingservicedataplane": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-datalabelingservicedataplane/-/oci-datalabelingservicedataplane-2.139.0.tgz", + "integrity": "sha512-N0rqh04FvGWB4DIhhwn8SV9EIHSd+yKaYqBJG7mqZFUx7cVOOhfPBqH1CjkP8XSOENDatXVGOc/m58InYL6ABw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-datasafe": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-datasafe/-/oci-datasafe-2.139.0.tgz", + "integrity": "sha512-Y7YMdZcvxaLZWQ3Cq1nYdYnlLA8PF/pgUzPx6t0gAHwZqsuY9AewGPPhKCqU4QaCps0V2l32ZyAM/ikXYVmyew==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-datascience": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-datascience/-/oci-datascience-2.139.0.tgz", + "integrity": "sha512-UuPV6pBE9ZJnn+6VwpazCkFu742yj7R2YiY6QUqwViOW6LAi5TOx30qXggDQw40FIsHSqPqOtT1l7atiAV8VdA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dblm": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dblm/-/oci-dblm-2.139.0.tgz", + "integrity": "sha512-uPgUb/DlJqPqSQ8lwDPeiBvRMFdIHtKmYeroK6gB/gDtiJlzFYYIg/y/D6uq0huNwTubmSPGVPDghZob/6yTwQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dbmulticloud": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dbmulticloud/-/oci-dbmulticloud-2.139.0.tgz", + "integrity": "sha512-/C0K8COX2tL4DJNTSyBMe/JKQ4IkN6ktjhl5vXP4e04+AT+ugUgA0Dp/QH7jkp7B3LGSvmcl/eCy3Syz2WA7oQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-delegateaccesscontrol": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-delegateaccesscontrol/-/oci-delegateaccesscontrol-2.139.0.tgz", + "integrity": "sha512-zcSFZdvjt5UdNBirOJOVJrmmYzU4jErG1q431wDIW/SCuq4IUwSExAVJQe+C7BwYWmvacCYR7Ku2QgXf7kz3DQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-demandsignal": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-demandsignal/-/oci-demandsignal-2.139.0.tgz", + "integrity": "sha512-wNIyMypy6mUobeZ6Fx+ueHIIGnP0Ao56Ns/dgF28quAOznE5yvHAmsRNOMlGaimB9cTwWyYuHixko27bv8nZmg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-desktops": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-desktops/-/oci-desktops-2.139.0.tgz", + "integrity": "sha512-OunCcakP5tmn3IcQwUP4cYqWdMI4w2ylQD+iYkuhgmSV+RXLRoiDZDhCGcJj9Gbx2BLhqNNIlIxi4uFUD9bXaA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-devops": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-devops/-/oci-devops-2.139.0.tgz", + "integrity": "sha512-08uU6e7PR9A+j7/LbY5W/ThdJyMohr3n+qkZJ5KhMhP9C2CbU8p7U7j9O8LdShssICQtcaFDQu0gWtqkAELkJA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dif": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dif/-/oci-dif-2.139.0.tgz", + "integrity": "sha512-vOQdKHWkuoVOLgaC5tlUeZe78OxoyCfcz+JJWkfaimdVe2pbAKQGAIIBf4HEiwxdgMKT2+UqX/wAZ99uG05HCQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-disasterrecovery": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-disasterrecovery/-/oci-disasterrecovery-2.139.0.tgz", + "integrity": "sha512-zIV1OqDbXtbqPZoWC0+xilFxt5wCEEH/czWrB8053q/ACTehDLkTJpvhjyyrwMVCvgCPtt9gDTTKSMSgo8PP3Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-distributeddatabase": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-distributeddatabase/-/oci-distributeddatabase-2.139.0.tgz", + "integrity": "sha512-hRVghLJOyfvFV05j/S4XNuiyN7it9iGFdmVN+UKzomAlswoaR43ST1iEaN5bAkdgqAX7oCsQys4x6Q4Gz+2PZg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-dns": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-dns/-/oci-dns-2.139.0.tgz", + "integrity": "sha512-8pIhTE3CxqaJ1W4YhttZRziCvObIQ4H6Aw4N7dC1G5mPgViB1VbCQRL9xcliktsoS+7ZKF2QRElljhuQGpIrYw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "oci-workrequests": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-email": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-email/-/oci-email-2.139.0.tgz", + "integrity": "sha512-d28uk9Dko3eZ8yimrLGPuJtmPT0C4qrasfXu7YI1981Tj43e9x/xTCnyYhDYt5ZMXQM72t+dUrN/tTZeMttmyA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-emaildataplane": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-emaildataplane/-/oci-emaildataplane-2.139.0.tgz", + "integrity": "sha512-x4yQIoLYqE8G5GGVjI40oV+MPCejBHMSY0qF9rrHQ/F4TSoWW2/e1yOgHJjgS4AHqUvAZ2yiv1KmHdzRzSTW7Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-emwarehouse": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-emwarehouse/-/oci-emwarehouse-2.139.0.tgz", + "integrity": "sha512-PeGAK/qJNRejYAYACIINNRKogBy4gLpH+Di4Kf2GUTlpsdY4v7WvDioXxAcF/vM/NMjbFf56EXqtTHurfDxN1Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-events": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-events/-/oci-events-2.139.0.tgz", + "integrity": "sha512-Y5Mt7Fb0r7soU8pd72LKoirG1e2yCt6Biy0/XOCzi2h+ieIN4YlXsQLVNucJKSUfjNYfm8w/+lPmLR011geBCg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-filestorage": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-filestorage/-/oci-filestorage-2.139.0.tgz", + "integrity": "sha512-pM6JHWosEEefGneup7/MBCp3FkKquY/TFK5WQAChtFASF7+L8/jdPmFYqFK69d3Ptc2m1Qk2GvhNGNRodiDHYQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-fleetappsmanagement": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-fleetappsmanagement/-/oci-fleetappsmanagement-2.139.0.tgz", + "integrity": "sha512-w/z1cZuq9QiaY1XghIxiHhGruTygZ1Bi+0T+N4oxtnhjSpPatBp6bsp4ViVl7uQnsE1BA4uZhbIWZ3DgntoTUw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-fleetsoftwareupdate": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-fleetsoftwareupdate/-/oci-fleetsoftwareupdate-2.139.0.tgz", + "integrity": "sha512-U1CZVNtx+KUo/Eg9me04HAZL0BTLxpmazpjfjsMihGrKo9V8SzjyGWloojk18pWwUU5MiH3EbieQdE4LVUG1EA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-functions": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-functions/-/oci-functions-2.139.0.tgz", + "integrity": "sha512-22tt1N5Em1eMV+pGEYAR0hRgR/CuszZjjb6Z5GlR7nJCS21AwDPsWNNUwmd5cfpAO3Rz0t6sicHFQZMaiCAZDA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-fusionapps": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-fusionapps/-/oci-fusionapps-2.139.0.tgz", + "integrity": "sha512-kfq985MrYH11gnd3qZOdTkAhrHdGcWnraIVu7YeM6mzsdjwvvWhXszBqQkTnZ2YcvXoJ/iYYfnTKt8W0qMmeOg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-gdp": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-gdp/-/oci-gdp-2.139.0.tgz", + "integrity": "sha512-JMbQT/trtAS15JIBnTF9mP0Fa2f5CDEbqXUlE1pMhBGFAW5Brq49emOPSUX5i7sJ4E/RwhpRfSvcV9jY5m/sxw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-generativeai": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-generativeai/-/oci-generativeai-2.139.0.tgz", + "integrity": "sha512-xGcyAtIOqtVVIdmmyaPMIOYsHV4vNaSyplObnCp1hbbVx8horTEt5jSbQmBXx6ckjy+Vlc/yudLdriJsdL8tfg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-generativeaiagent": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-generativeaiagent/-/oci-generativeaiagent-2.139.0.tgz", + "integrity": "sha512-3ONUe0Z+buRh21flDnZmFd80soaS+azbysX53TN3OWvnq6Za8zGT++nkKw9gYOpskC1HsCgxhfXqMQ4Ypt4EBQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-generativeaiagentruntime": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-generativeaiagentruntime/-/oci-generativeaiagentruntime-2.139.0.tgz", + "integrity": "sha512-6vjEcF4PYGgBnQ2bCcMtga3KVVIOur/SgcHjzSpC65gFfNbMi8FKX5zNIqEhTfHpOYjo+OYyK1S6RraRS/q5ig==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-generativeaidata": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-generativeaidata/-/oci-generativeaidata-2.139.0.tgz", + "integrity": "sha512-nRlMCKn3wFxJlSUHRtfyNBcNmmjvWLgNlgFbad3dbRC77rSqMcBvXRBt0kDf5QyxH34Y3lzwq4LdkDA64Ecjzg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-generativeaiinference": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-generativeaiinference/-/oci-generativeaiinference-2.139.0.tgz", + "integrity": "sha512-JeOFGAL3d+QOOfeuj1qlKIzcMHHfJLRu66ViE7G8DeKS65jW8Dn08RprfORnyBUYzrPnkOcUveePNIeWGJIouQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-genericartifactscontent": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-genericartifactscontent/-/oci-genericartifactscontent-2.139.0.tgz", + "integrity": "sha512-5e+SE6+fJGHTTlVlsDPyFH6VC7nuFlvomREn+pHwmZ9zmJfqNqbR1fgwTIvCVQHsYEl+raTFvM4QfFqbPPkYMA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-goldengate": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-goldengate/-/oci-goldengate-2.139.0.tgz", + "integrity": "sha512-UCxrXHoEZ6D5HlqKEw+5nb6yFZZGi/OnqQzsM4o+IA0T/HaaVBy6aBKIAx3j9DugwxREHbX2O1AFkP5t5KN/3g==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-governancerulescontrolplane": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-governancerulescontrolplane/-/oci-governancerulescontrolplane-2.139.0.tgz", + "integrity": "sha512-o5oPIq+6iLeUn+H82G0odc76RoSOltrT0LoY2ZD2FjT9k2X0cjMwL0lK/P5fRXHUOCo03kLSNc6lINpf438e0g==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-healthchecks": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-healthchecks/-/oci-healthchecks-2.139.0.tgz", + "integrity": "sha512-wDzFfOlNxn7iElU/jkUw4gsFliXacZMm8/S7tuPG6432bR9xfCn2qp0BJIYVoMI/MAzVoKXnQCzC0oeVCl9PnQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-identity": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-identity/-/oci-identity-2.139.0.tgz", + "integrity": "sha512-SRgJPQiaHtV6hiRfKLYsPoETd5GdG9S5P9nYX/M26wK5Mb5PpLUe601Yf7izQ72yP+yaXaezi7gvkMf4tS03tA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-identitydataplane": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-identitydataplane/-/oci-identitydataplane-2.139.0.tgz", + "integrity": "sha512-KmDQKyT9qX5YlvodjaqXspai8GHTOx311v4qn+GOCoP1R2wjg41DuhNRnWjiFx3S3RO8U0j0lJR02DTggbvmmw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-identitydomains": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-identitydomains/-/oci-identitydomains-2.139.0.tgz", + "integrity": "sha512-7AFRsjuYYSflFGBBrEe907fycxggKMk3rGGAtg0OfG7hQORqQ9hM/5rzpb7NsO5yM2lZrY+7OiJvQyEgP42flw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-integration": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-integration/-/oci-integration-2.139.0.tgz", + "integrity": "sha512-RgOEnoTgp9VwZcl2CwZPb1zV8DW0SmH1VwcVlOc0ejeJZ7kjpsuZk5BgiQDtVu/S4NetbrH/rqfFzNiWKU5ImA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-iot": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-iot/-/oci-iot-2.139.0.tgz", + "integrity": "sha512-7vbRM31gqBcxTUl55TwWFf3QClAKOnRANo/g2RO06X5MlaKb4tnIy4QItx87tfcl0GSEP5lXnRnaEr/EY0ZfwA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-jms": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-jms/-/oci-jms-2.139.0.tgz", + "integrity": "sha512-bzJicJ0pXurQlx5EnMmKPN6oFZ//EiB3QPSfdoFeA/IcH3cHkDmdlfFrAvFpPfziT90ns1NPBzVNqBZiuWUJdg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-jmsjavadownloads": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-jmsjavadownloads/-/oci-jmsjavadownloads-2.139.0.tgz", + "integrity": "sha512-nIzfJbwLMK4jmoleWqL+2K26LVhuH+UJOYtTqxcaQpweOfNz8OpI/owM7T3ZbY5RRZoRHydfNwFl4stuWZ0okQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-jmsutils": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-jmsutils/-/oci-jmsutils-2.139.0.tgz", + "integrity": "sha512-ya8w6jqV3u3VitgmRo1mHUqPPYRfLa1wpA0s5mQ6s0Pa8GUUP9aD0gzc0oRsif32X5kZCX+/cdJR+OSpMAmGPg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-keymanagement": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-keymanagement/-/oci-keymanagement-2.139.0.tgz", + "integrity": "sha512-/ZEZMrshdnfEjPKx5JIWdSI5BAmIqJJ+oUhBofWwB7Vdf4+uOG2cYhl83pOLnSJl+BWnDJTjhaOY6sdXE34jEA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-licensemanager": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-licensemanager/-/oci-licensemanager-2.139.0.tgz", + "integrity": "sha512-rvnnlajVN2L7/vSKZwwqBYARb+czJqEZrCrArMEV29lE1c1zgX8yJUhSjkj3q7xupV/YRe8V4fLF1vaDGspt1A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-limits": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-limits/-/oci-limits-2.139.0.tgz", + "integrity": "sha512-kGXyJP6A00kQiK1xVK9NmgXkIh5VHC58m9aR+C+RJuTHuqS8/gYCUvBk1rFHGta4joEic7l6jviYZznEpqWgpA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-limitsincrease": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-limitsincrease/-/oci-limitsincrease-2.139.0.tgz", + "integrity": "sha512-yUhSTC36exa5JHxhGPvA00/zMbPXiWY1QVFBOlbbl/JtEyjSKQ+EW+3CuERRqdI46OwFxaVxI3ZlMwyS0sSL9A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-loadbalancer": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-loadbalancer/-/oci-loadbalancer-2.139.0.tgz", + "integrity": "sha512-rKBdo5CJqi7XUIzTvHcj0pT2ScwyuAE3Sx14Zwlf/agCxQZEhsk5zuDLGTZcpUBSuddL0+NdynN0RnOKQHoTyQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-lockbox": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-lockbox/-/oci-lockbox-2.139.0.tgz", + "integrity": "sha512-5slFiLputDm2eN6fwX74UHF3CXnuZJHwKbMmT7jrJry8+C/p6GBO0ya7KbnjKv4Aym9HplsSHOio4slM15382g==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-loganalytics": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-loganalytics/-/oci-loganalytics-2.139.0.tgz", + "integrity": "sha512-oXHEM/3EGiH0rxG+eczNgPT7S5cMFtPrJfFZ3gO2XKQqDIJAVCsLv1GmD5/aWTB1GguY1OcqArr9/puRF+iiQQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-logging": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-logging/-/oci-logging-2.139.0.tgz", + "integrity": "sha512-dcF1/y4XXGMRT5K6QrLb8DH4DErYIYFhhHPyRkDwlenNUg/vi0Oz/B1czO/kCuA0uwsdd5f/3acM67VaUbeTdQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-loggingingestion": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-loggingingestion/-/oci-loggingingestion-2.139.0.tgz", + "integrity": "sha512-r8dK8+VSNsR18pZvfPKmLHQTIzE3h7Gs9fChjHcYU6oER8zwu2mx3F3EjO2Cf+FBpc1TpSWUZ5+Dh6svZf/80Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-loggingsearch": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-loggingsearch/-/oci-loggingsearch-2.139.0.tgz", + "integrity": "sha512-2zX1KB/QfjYWUx+1sKAd44xrn3a7Y9w7E20f6lqPyH/Xf7T2a06u2wEngaQ1KgX03Y0WD/IapG8MKRXzt0PJKg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-lustrefilestorage": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-lustrefilestorage/-/oci-lustrefilestorage-2.139.0.tgz", + "integrity": "sha512-GidLvBECgUm+YF+dQVeGBX2m90ewMJwMJNVKOdh8NcYLdU2jodg3o7vbjucBqvCZtmSmdoCIuiOjCjaEi08bAw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-managedkafka": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-managedkafka/-/oci-managedkafka-2.139.0.tgz", + "integrity": "sha512-KjrByb2QU3Vr7nF5SgwXjV687Fvnif8AZBmE6ZpTCqLENWtQpqBO925eIxzREBXtIIAZB4+xYf5kCY3GHnH7eA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-managementagent": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-managementagent/-/oci-managementagent-2.139.0.tgz", + "integrity": "sha512-tMV2yY5MUK13sHcP5HWftLCwPh+aQgY0TWBXLqyHs96G1KFPuYAwzt8e/he0rpWPH+E89xJOZN1zQfEYtHtKcg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-managementdashboard": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-managementdashboard/-/oci-managementdashboard-2.139.0.tgz", + "integrity": "sha512-iwOsVXJExVNfOHhZzMbCLDa6KDMnHq7DYahC0pdS455AehrVjKo0VYvCpA05V3fTPmvedU3OIMDeyEPsOE4O7w==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-marketplace": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-marketplace/-/oci-marketplace-2.139.0.tgz", + "integrity": "sha512-xA+DnTMKbqr4f86Ufg2l1VsItbNoXhSMFsEjX6qTwf//cQkEOm40Ie0jICLBpJGgCDoIE4cPUy2Ik4UL1peAOQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-marketplaceprivateoffer": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-marketplaceprivateoffer/-/oci-marketplaceprivateoffer-2.139.0.tgz", + "integrity": "sha512-ScB2DhnNMH8ZH4bqMgDrtirFXT+ye/AC/qrHrodIvATM4BixlDZUhoz2CrYdOgY6yz/qM+orcZUIksdF3lDaqw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-marketplacepublisher": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-marketplacepublisher/-/oci-marketplacepublisher-2.139.0.tgz", + "integrity": "sha512-CtX0DuCTIbb69GGvAWPGX3aQYtnn4k7uP2O8ngI5YxnEHrkQmgPaKhTqRNpf9ToLAJJpVDvh/aTxOTOp6f9phA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-mediaservices": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-mediaservices/-/oci-mediaservices-2.139.0.tgz", + "integrity": "sha512-uhgKnPDB77g05s0nS420wuGs0jKVexM48ZjkRMT1IQCPoh8UV8zKlbr9SJfblIo/sznNVA6Iw2tCO69KVQ2eKg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-mngdmac": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-mngdmac/-/oci-mngdmac-2.139.0.tgz", + "integrity": "sha512-KBz1EF2U9FNRKy//JczQZ2QhQV6sq8MTHnUOFsbj1XfAdSyyXP7TvrbhCjAwwWux4stqEqq7Q1c5VT4ogg1Hmg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-modeldeployment": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-modeldeployment/-/oci-modeldeployment-2.139.0.tgz", + "integrity": "sha512-nR/0Z9p7fzeKNhYxDKgo6YxvC3SIBStWW/Sfs98MHpPNoApNCI8M6ayXvlqgSB2DMvXc6oxrpxtjtdGi+noUSQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-monitoring": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-monitoring/-/oci-monitoring-2.139.0.tgz", + "integrity": "sha512-siilScK1atSn87mm+DX9tXn/A8MryGFiZLpMSgG46ZHptEDhtelKTsQMwrzDeOq43aIgNdYWG+AlQIpH0mcz0A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-multicloud": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-multicloud/-/oci-multicloud-2.139.0.tgz", + "integrity": "sha512-XGnwuajoH9zkxmTaAHqkkQPdsgy1XOdMTMz67nXImbDcj8GtLqSjpkHGieIU0EXXThXSlL+SolNfv8Y6nazWVw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-mysql": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-mysql/-/oci-mysql-2.139.0.tgz", + "integrity": "sha512-CabXDw/A85P72D2jq1F/DX9KSlFpTXj6J8QV228DketlxjkP70hybuslDR8pXb2RBWwAMOpfMSiq66YHjCFhxQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-networkfirewall": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-networkfirewall/-/oci-networkfirewall-2.139.0.tgz", + "integrity": "sha512-AAsTRrEGwCrENyadm5FjDX+34UfUV5QXQibxasa0SufcsHcwmomwowt3NRb4lv0e/M9S4YcPGSPMEan5rNmPZA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-networkloadbalancer": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-networkloadbalancer/-/oci-networkloadbalancer-2.139.0.tgz", + "integrity": "sha512-6/9Hqq5Z6HKZXG9yYd6jrmmq++oxHL2t5Nj5eBDh8pzEdge70G1ehXOllOExAdNZtdW5qxyIYf0+e274KD+J0g==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-nosql": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-nosql/-/oci-nosql-2.139.0.tgz", + "integrity": "sha512-nadZag/NgaVQvPCViBMcDM46rnNC3bRNlXhOUfDJ3iD7/sCjRPii9cdD0AI753955K0I7SZbxAcrw+VkXP+vtA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-objectstorage": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-objectstorage/-/oci-objectstorage-2.139.0.tgz", + "integrity": "sha512-DeW47RAWBSdEBP3Xrc/ubiVRASgGy/mIzdC22Wnyo69jkJmcC11oKt5YaeSdomyVkfYECoZB7Cokg3Q5vnMXPQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "await-semaphore": "^0.1.3", + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-oce": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-oce/-/oci-oce-2.139.0.tgz", + "integrity": "sha512-Ajbqa8PNia4jMmOkhhXICsmQWM52QHZxseS2FXC4yT1V4BkbwYSTbWDfIwqr5c3A4Re8SmXFTeAxNRge+V5bug==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-ocicontrolcenter": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-ocicontrolcenter/-/oci-ocicontrolcenter-2.139.0.tgz", + "integrity": "sha512-pC49SyhtVaE4ppnTjb5x5qUMT4uUTwimcsSS+BqgE8qNSK5nDX7P/qQcip3Df7VfN227MFHa050LoX5JZHlxmQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-ocvp": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-ocvp/-/oci-ocvp-2.139.0.tgz", + "integrity": "sha512-FTYqUfqbHnvgPGhKd6gpODAOUXiCldEotiElE0vl9dbWWMwZR3GomyPVvqLajwXGoAFe0vXyBZU3Dw4R6xARlQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-oda": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-oda/-/oci-oda-2.139.0.tgz", + "integrity": "sha512-pwfJCbr+n/CUHlIUAg+spSP9VZy3qBHIM3AsWxhhQv2YhtpFZA0UQeiGw9vCqnNaYjbn+cBKlVEaSV/iXu1F+Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-onesubscription": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-onesubscription/-/oci-onesubscription-2.139.0.tgz", + "integrity": "sha512-rR4Muc+ZgYgdlh7PW33JbD7qt9CSQsJVllnioKs4NA39Xz/Rm934fjRQ9rfyIZ4p7Ry+ehtcc3V81GssDMz0vA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-ons": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-ons/-/oci-ons-2.139.0.tgz", + "integrity": "sha512-oIEZlyV3O8F0jmAAhxvNWwN25V/Vn1B5pm2PC7Su+p7UJSmsBmHj5yZyza81g2ITPfTEVj4o6r7tL4fQFJ0TwQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-opa": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-opa/-/oci-opa-2.139.0.tgz", + "integrity": "sha512-ahKf/TZji/1s+nCnIqblWvZAkYebzFIG2dkVGJbpNEHQr66xXDGlRTj9/AX+bSxEsJ5aiCykCWATHVw6JB31Gw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-opensearch": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-opensearch/-/oci-opensearch-2.139.0.tgz", + "integrity": "sha512-RiOn6kvPt8uzc1jYRVKi238oXGK/MeMKcwTt1mMkRY8Sv97FQvgebEkB4ahQHOtFU8jOmzibpsvoRrddfLTE/A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-operatoraccesscontrol": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-operatoraccesscontrol/-/oci-operatoraccesscontrol-2.139.0.tgz", + "integrity": "sha512-jiCiZIDC5TYpay44xbC0uMBCWOfIp5n+uhmQ4h54sdqjJOiJtsnXJ5zRPew8OMfV9066QEZlpHvViY81qIiAGA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-opsi": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-opsi/-/oci-opsi-2.139.0.tgz", + "integrity": "sha512-UDGHDQg3cY8GVf3ZJQ+ebPOSR43Q/HDJZdwleHz8qcszDsR1+R7SjPJpO6bHxmemkAp3Nrf2icmk+EXQ9b6DXA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-optimizer": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-optimizer/-/oci-optimizer-2.139.0.tgz", + "integrity": "sha512-Mbx1LEbFGwhNQFP/jC4P/C7hyaPuu4J9bWaV0rHb7O6Mr2E0q5dwsS9g6elBEdm+O+L7vY9U96LVJNToDSwuFg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-osmanagementhub": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-osmanagementhub/-/oci-osmanagementhub-2.139.0.tgz", + "integrity": "sha512-73fzeZuCpzQbIqNSnMWaa6T02ig1EPVRAPqigDLO32hRlBow3wbcyjFj1YIphs6h3OAQd9XW985ravPfk41IPQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-ospgateway": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-ospgateway/-/oci-ospgateway-2.139.0.tgz", + "integrity": "sha512-q7h4J6V/SVA7u7hRtUxmgPWeHcu/2QlTZ6uQ9VOEfLg7bHqri7mKktAKXBtAT+blMmHUwFoQ4x0/tW2a13aAMA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-osubbillingschedule": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-osubbillingschedule/-/oci-osubbillingschedule-2.139.0.tgz", + "integrity": "sha512-ocrC1YL9lpfQkvqo6qosd67+CzxJb+T2CjPBNtO3LYNK01wmgNIyZ947qoWH1gN5fj6jgT+2X3bz601aQamItw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-osuborganizationsubscription": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-osuborganizationsubscription/-/oci-osuborganizationsubscription-2.139.0.tgz", + "integrity": "sha512-rg6oqa3/k/Yb31NoSpAtFMD/drdxBnRXDYrsx178Pdp0XpkMJX3yO5/kgnE70Mlmm5oRoFHbgZbgTf8iJ0m+ZA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-osubsubscription": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-osubsubscription/-/oci-osubsubscription-2.139.0.tgz", + "integrity": "sha512-lxQoSdZ9w8coN9NRUZa4OK/vwksK+P6E5h0D2sM5neiUpgiv/i+EmVxQYKBw7ZHUQinqrwchkpGNoMkt+/6H2Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-osubusage": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-osubusage/-/oci-osubusage-2.139.0.tgz", + "integrity": "sha512-HTnSi3/1PkMRkBe0DQABAgMqUkzn6Ft7OCfi1ThFwybvvhCzhi3riYO5ywIBnCNK0qPh2lWWWrSgiQuVsATWPg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-psa": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-psa/-/oci-psa-2.139.0.tgz", + "integrity": "sha512-q0jpQYQggb0S/hvc1vUo4714GIn3QKmerApRImPt3jkxs4aOiVAvMeDsIBCFN4l3SVF+s7YyMlLYL36ObCxJ/w==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-psql": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-psql/-/oci-psql-2.139.0.tgz", + "integrity": "sha512-BYCyK8zBGHtFDTKyQNouvzsi2+g5/+kgaeII1hvW2O7IZ6FbNez8SHg+Ws051cs9icSlINTm/+rODTForUoEiw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-queue": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-queue/-/oci-queue-2.139.0.tgz", + "integrity": "sha512-Sijpg7h2ofqQBRER8C7DGXs7feXzWjKhSOASOC6mgKjMM6Fr7crhM8O8Ea0gWFDvwk4A3FT4lXVEbHrKmf+xrg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-recovery": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-recovery/-/oci-recovery-2.139.0.tgz", + "integrity": "sha512-n7BLtydjh3mRDV2bOSkpgGr+PjZyBNyfNvSofdqVqQXWJAywcNB1aodnWsOf4t2dlzZVQNd3ZdEVac7QzwHo9Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-redis": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-redis/-/oci-redis-2.139.0.tgz", + "integrity": "sha512-4jnlQJnzcY8TyOfCnjkFN1uhz4JEM6XhZwZect2/63S/IDOPemdF5KNc8PTBLR2Z/UYSrZMBi/x4kQSuCVFDKA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-resourceanalytics": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-resourceanalytics/-/oci-resourceanalytics-2.139.0.tgz", + "integrity": "sha512-dq2VZkp6tEftmUqLk6oc+dLtccitp2WcHhZWe0i3BzSWAncPYkld+7JOCm4w4sN0NEUnnMjW0gVy+tlMcljjkw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-resourcemanager": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-resourcemanager/-/oci-resourcemanager-2.139.0.tgz", + "integrity": "sha512-Eor3oFYW4F2hw6YCC46OHiP0e/WDLFZaOhxvSXSuwg8vh5damp6avhVRVMckhiNx422kjgBPdKoufEUy0ieviQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-resourcescheduler": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-resourcescheduler/-/oci-resourcescheduler-2.139.0.tgz", + "integrity": "sha512-viGtR25HjK33NG2eH1G5rm//ISVpHKZ0Pe1uX31xUsk5N6kBEYcNm4irJnAgwdhPBYXAUD82ev+fTwufpx/hog==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-resourcesearch": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-resourcesearch/-/oci-resourcesearch-2.139.0.tgz", + "integrity": "sha512-9qkMLcTj5K9Zxy9NPBkH3Ln+jyRSGdxR5+KmrY6x2lCc7VjcB6ixXgE4YmP8xxUNl3cwNDwNokVIrkYuiuYg1g==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-rover": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-rover/-/oci-rover-2.139.0.tgz", + "integrity": "sha512-Toetp6QubW3pUtKIt9r4kZckD20BnGgpmSU3UgCVJ7L13TTiS7rg5cKk3JZZwPdRUTRuD87kMqK3EiYwBuNntQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-sch": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-sch/-/oci-sch-2.139.0.tgz", + "integrity": "sha512-ELZQXdqndEvH+MGL2ljkP/vDpa33+OOCHY6kxvdCAMLrRpkw3LC/fzpY32RRl+9jm2S+UAdvBLLL+4yzOqEjhw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-sdk": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-sdk/-/oci-sdk-2.139.0.tgz", + "integrity": "sha512-d8tPLVz+cpNECSnW4cP+llbq0+TcfOqFsbTYk5Yqv988BWkgOjoM9gI8wIF+1r9Irp1DmVUsUFMYzVDqYb4/Pw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-accessgovernancecp": "2.139.0", + "oci-adm": "2.139.0", + "oci-aidataplatform": "2.139.0", + "oci-aidocument": "2.139.0", + "oci-ailanguage": "2.139.0", + "oci-aispeech": "2.139.0", + "oci-aivision": "2.139.0", + "oci-analytics": "2.139.0", + "oci-announcementsservice": "2.139.0", + "oci-apiaccesscontrol": "2.139.0", + "oci-apigateway": "2.139.0", + "oci-apiplatform": "2.139.0", + "oci-apmconfig": "2.139.0", + "oci-apmcontrolplane": "2.139.0", + "oci-apmsynthetics": "2.139.0", + "oci-apmtraces": "2.139.0", + "oci-appmgmtcontrol": "2.139.0", + "oci-artifacts": "2.139.0", + "oci-audit": "2.139.0", + "oci-autoscaling": "2.139.0", + "oci-bastion": "2.139.0", + "oci-batch": "2.139.0", + "oci-bds": "2.139.0", + "oci-blockchain": "2.139.0", + "oci-budget": "2.139.0", + "oci-capacitymanagement": "2.139.0", + "oci-certificates": "2.139.0", + "oci-certificatesmanagement": "2.139.0", + "oci-cims": "2.139.0", + "oci-cloudbridge": "2.139.0", + "oci-cloudguard": "2.139.0", + "oci-cloudmigrations": "2.139.0", + "oci-clusterplacementgroups": "2.139.0", + "oci-common": "2.139.0", + "oci-computecloudatcustomer": "2.139.0", + "oci-computeinstanceagent": "2.139.0", + "oci-containerengine": "2.139.0", + "oci-containerinstances": "2.139.0", + "oci-containerregistry": "2.139.0", + "oci-core": "2.139.0", + "oci-costad": "2.139.0", + "oci-dashboardservice": "2.139.0", + "oci-database": "2.139.0", + "oci-databasemanagement": "2.139.0", + "oci-databasemigration": "2.139.0", + "oci-databasetools": "2.139.0", + "oci-databasetoolsruntime": "2.139.0", + "oci-datacatalog": "2.139.0", + "oci-datacc": "2.139.0", + "oci-dataflow": "2.139.0", + "oci-dataintegration": "2.139.0", + "oci-datalabelingservice": "2.139.0", + "oci-datalabelingservicedataplane": "2.139.0", + "oci-datasafe": "2.139.0", + "oci-datascience": "2.139.0", + "oci-dblm": "2.139.0", + "oci-dbmulticloud": "2.139.0", + "oci-delegateaccesscontrol": "2.139.0", + "oci-demandsignal": "2.139.0", + "oci-desktops": "2.139.0", + "oci-devops": "2.139.0", + "oci-dif": "2.139.0", + "oci-disasterrecovery": "2.139.0", + "oci-distributeddatabase": "2.139.0", + "oci-dns": "2.139.0", + "oci-email": "2.139.0", + "oci-emaildataplane": "2.139.0", + "oci-emwarehouse": "2.139.0", + "oci-events": "2.139.0", + "oci-filestorage": "2.139.0", + "oci-fleetappsmanagement": "2.139.0", + "oci-fleetsoftwareupdate": "2.139.0", + "oci-functions": "2.139.0", + "oci-fusionapps": "2.139.0", + "oci-gdp": "2.139.0", + "oci-generativeai": "2.139.0", + "oci-generativeaiagent": "2.139.0", + "oci-generativeaiagentruntime": "2.139.0", + "oci-generativeaidata": "2.139.0", + "oci-generativeaiinference": "2.139.0", + "oci-genericartifactscontent": "2.139.0", + "oci-goldengate": "2.139.0", + "oci-governancerulescontrolplane": "2.139.0", + "oci-healthchecks": "2.139.0", + "oci-identity": "2.139.0", + "oci-identitydataplane": "2.139.0", + "oci-identitydomains": "2.139.0", + "oci-integration": "2.139.0", + "oci-iot": "2.139.0", + "oci-jms": "2.139.0", + "oci-jmsjavadownloads": "2.139.0", + "oci-jmsutils": "2.139.0", + "oci-keymanagement": "2.139.0", + "oci-licensemanager": "2.139.0", + "oci-limits": "2.139.0", + "oci-limitsincrease": "2.139.0", + "oci-loadbalancer": "2.139.0", + "oci-lockbox": "2.139.0", + "oci-loganalytics": "2.139.0", + "oci-logging": "2.139.0", + "oci-loggingingestion": "2.139.0", + "oci-loggingsearch": "2.139.0", + "oci-lustrefilestorage": "2.139.0", + "oci-managedkafka": "2.139.0", + "oci-managementagent": "2.139.0", + "oci-managementdashboard": "2.139.0", + "oci-marketplace": "2.139.0", + "oci-marketplaceprivateoffer": "2.139.0", + "oci-marketplacepublisher": "2.139.0", + "oci-mediaservices": "2.139.0", + "oci-mngdmac": "2.139.0", + "oci-modeldeployment": "2.139.0", + "oci-monitoring": "2.139.0", + "oci-multicloud": "2.139.0", + "oci-mysql": "2.139.0", + "oci-networkfirewall": "2.139.0", + "oci-networkloadbalancer": "2.139.0", + "oci-nosql": "2.139.0", + "oci-objectstorage": "2.139.0", + "oci-oce": "2.139.0", + "oci-ocicontrolcenter": "2.139.0", + "oci-ocvp": "2.139.0", + "oci-oda": "2.139.0", + "oci-onesubscription": "2.139.0", + "oci-ons": "2.139.0", + "oci-opa": "2.139.0", + "oci-opensearch": "2.139.0", + "oci-operatoraccesscontrol": "2.139.0", + "oci-opsi": "2.139.0", + "oci-optimizer": "2.139.0", + "oci-osmanagementhub": "2.139.0", + "oci-ospgateway": "2.139.0", + "oci-osubbillingschedule": "2.139.0", + "oci-osuborganizationsubscription": "2.139.0", + "oci-osubsubscription": "2.139.0", + "oci-osubusage": "2.139.0", + "oci-psa": "2.139.0", + "oci-psql": "2.139.0", + "oci-queue": "2.139.0", + "oci-recovery": "2.139.0", + "oci-redis": "2.139.0", + "oci-resourceanalytics": "2.139.0", + "oci-resourcemanager": "2.139.0", + "oci-resourcescheduler": "2.139.0", + "oci-resourcesearch": "2.139.0", + "oci-rover": "2.139.0", + "oci-sch": "2.139.0", + "oci-secrets": "2.139.0", + "oci-securityattribute": "2.139.0", + "oci-self": "2.139.0", + "oci-servicecatalog": "2.139.0", + "oci-servicemanagerproxy": "2.139.0", + "oci-stackmonitoring": "2.139.0", + "oci-streaming": "2.139.0", + "oci-tenantmanagercontrolplane": "2.139.0", + "oci-threatintelligence": "2.139.0", + "oci-usage": "2.139.0", + "oci-usageapi": "2.139.0", + "oci-vault": "2.139.0", + "oci-vbsinst": "2.139.0", + "oci-visualbuilder": "2.139.0", + "oci-vnmonitoring": "2.139.0", + "oci-vulnerabilityscanning": "2.139.0", + "oci-waa": "2.139.0", + "oci-waas": "2.139.0", + "oci-waf": "2.139.0", + "oci-wlms": "2.139.0", + "oci-workrequests": "2.139.0", + "oci-zpr": "2.139.0" + } + }, + "node_modules/oci-secrets": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-secrets/-/oci-secrets-2.139.0.tgz", + "integrity": "sha512-6jC4VyLorFpobtj97k0M8Z1MCQkjR6VgdxRiojBmdm3gzbZ4dTk3rlEFeMO6tDh28KXbdWGWxx1H2pVQTUHjMw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-securityattribute": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-securityattribute/-/oci-securityattribute-2.139.0.tgz", + "integrity": "sha512-DQ4S1ei49SoVCgSbuF7b9yS2g6czjcf/W9WZ2Ve/0Fwfl7YzHo8i/v6TjpQy0Gf7oNV/ekHVf5vNQ4NnphHrKQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-self": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-self/-/oci-self-2.139.0.tgz", + "integrity": "sha512-XU86b1knfcQDPQDQ0rI11AmsVNKSV5FXjIFP7CdKD/4sczLrYi6BicMlKIxz87t/+10tz+SgCQWkHUePEshIBQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-servicecatalog": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-servicecatalog/-/oci-servicecatalog-2.139.0.tgz", + "integrity": "sha512-ZWvCJp08XgHRwMQlOBD2d+BL8ZelF96lkHGBgz/g1ZWb11yZkJNfNGvC6Ak2vV8Oe0Q5ww+U/yIaNkcWaZn2nQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-servicemanagerproxy": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-servicemanagerproxy/-/oci-servicemanagerproxy-2.139.0.tgz", + "integrity": "sha512-Vq9rzrbCgYU0lKAaU5D7JLIj1LpdyaOF/UCAzrLfqkqBUz9MKopXgN2W6dtFWdH+GZmaYsxmJiDGucOi0E7ZEw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-stackmonitoring": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-stackmonitoring/-/oci-stackmonitoring-2.139.0.tgz", + "integrity": "sha512-x1L3cmFp4mF8m9CsJxTbGndTSAjuX8zC0sAjiiWv7xEoEoA7ZFjLvY7yIa/Kc0hvrtMpf9xYBgxA+gd9z+vI4w==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-streaming": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-streaming/-/oci-streaming-2.139.0.tgz", + "integrity": "sha512-VZXWR9EC5TecBvHrJfWS2ss1woVDb5j60c87T/wdq7VOVwyiRQnlhFzCBeUoGkTS7Ynt+td1HSP1I2zkvejYLg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-tenantmanagercontrolplane": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-tenantmanagercontrolplane/-/oci-tenantmanagercontrolplane-2.139.0.tgz", + "integrity": "sha512-UKzuwrWsFAczXwG/+SMrfVCXlpQrckGs82L57iZO2HlF9FMBcv+5xHgXXexRrLz/slDC8DBMQVQMCp8p9dvzNw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-threatintelligence": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-threatintelligence/-/oci-threatintelligence-2.139.0.tgz", + "integrity": "sha512-9WBBa5snQUTfu9R3S5npBWXQv1TXKSXBdPygIXUQPot3BW1CC/ciwW7nJ+l8scYjTo/PVm9u7XkXrYpg4wmVEA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-usage": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-usage/-/oci-usage-2.139.0.tgz", + "integrity": "sha512-xx5IJHFqQJqBMSMqX+rcCtvAgWeWo/kfG32Ibb9f8TGyQ6qXpPuLkaEGo9g0vrMF8iRP6RggSKIbh1zMUhc/vw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-usageapi": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-usageapi/-/oci-usageapi-2.139.0.tgz", + "integrity": "sha512-lp0PqX1bBp02x/7Pd3Kte+rq4V4dwTOBWmCWtDTbuEnawE5+v5t3tHxgvhD+ergHh3LenK7dhH9ldRGdb3a4Ng==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-vault": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-vault/-/oci-vault-2.139.0.tgz", + "integrity": "sha512-FQYmnISz/QHoSDrvGcKCPRbWBaFVLvmItKwxGL3lsZitJuoZUu5G39ay5Y2fRD0cwor4VuH+cZgd9u6WnrXUEg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "oci-workrequests": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-vbsinst": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-vbsinst/-/oci-vbsinst-2.139.0.tgz", + "integrity": "sha512-62I0vUUBYIXFtdzy2NL7FvheZvhh13qs7z2rIFYVGfGHPscJWGp+jlSUg+IhMLY8UNhdD53oHSyfHkVE1Rt3jA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-visualbuilder": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-visualbuilder/-/oci-visualbuilder-2.139.0.tgz", + "integrity": "sha512-GYlQPwyBtJTMAsy/ds8Ys630UFV3dsCvSB2tqxOMkgVaHEh9MTfWmfyWPUN6sCjOObuSgoRNUT7ZdQ2uVHv86A==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-vnmonitoring": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-vnmonitoring/-/oci-vnmonitoring-2.139.0.tgz", + "integrity": "sha512-NAnikCchIzca7Izx9PjYI5/k8yXme+mrE2alshLqtCVFLIPEtkL1t1enoE+o8czBX/ki7jQCoJBJ3MQWNFujcg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-vulnerabilityscanning": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-vulnerabilityscanning/-/oci-vulnerabilityscanning-2.139.0.tgz", + "integrity": "sha512-axoh24cqowgav476i52E1tDbzzruu/LGaD36XcTHUHhmEY0Vr5BP8S4UanHAyCch1a4zNXAoaKnNLhAhwJg3uQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-waa": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-waa/-/oci-waa-2.139.0.tgz", + "integrity": "sha512-JQ996i5yffvb2UqeOdBcQcSlPif4H0JY5eGPD6p8FbNpCfMu0+aZ+np0JFGuCLDdbY9/RFYrZ9BmcjxFk25/KA==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-waas": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-waas/-/oci-waas-2.139.0.tgz", + "integrity": "sha512-FoMPbucaSmmj9qHCSWWDWXK7XL06BmGQqSJK8t/TMJtdBYtJfyUEBLZFmBw6rRi6upKB/+T2eFInmW0+PjhG2w==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-waf": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-waf/-/oci-waf-2.139.0.tgz", + "integrity": "sha512-vDoBCeBgFximLw5I5aUsfRlaTO+Vf6jmwh5TB8zOcJ20OghB9rNeLTCl8R05VzMYT7Z9RJWE7jY2Fl0ysKAr/Q==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-wlms": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-wlms/-/oci-wlms-2.139.0.tgz", + "integrity": "sha512-lRP9NHx8C0r/11TXwePFmIFV8zG/ynZifM9AidkbhcymhJ4yFpnG+M8qOjScgUwvc1tWnyoH9hHRB/NG3aiqaw==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-workrequests": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-workrequests/-/oci-workrequests-2.139.0.tgz", + "integrity": "sha512-/8lvEPIhGr35XbBPtUg4QZSH35pVypJURWnXXFBb2YgXafwj5oiQseC2Q9F+rFQtVqg0cTCHxGiXCl6UdXgekg==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/oci-zpr": { + "version": "2.139.0", + "resolved": "https://registry.npmjs.org/oci-zpr/-/oci-zpr-2.139.0.tgz", + "integrity": "sha512-RD2bEdqTlET3vIaWGjcQV/ZdD7OUPhbe4nSizmrljPL6ZK6qHyp1xlIPQts8A/H4PaY+IycZczfcyo7dyaoAOQ==", + "license": "(UPL-1.0 OR Apache-2.0)", + "dependencies": { + "oci-common": "2.139.0", + "opossum": "5.0.1" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opossum": { + "version": "5.0.1", + "license": "Apache-2.0", + "engines": { + "node": ">= 10" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.2", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/router": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sshpk": { + "version": "1.18.0", + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude": { + "version": "8.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^13.0.6", + "minimatch": "^10.2.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "license": "Unlicense" + }, + "node_modules/type-is": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "18.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "22.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/src/oci-javascript-mcp-server/package.json b/src/oci-javascript-mcp-server/package.json new file mode 100644 index 00000000..72ce42ee --- /dev/null +++ b/src/oci-javascript-mcp-server/package.json @@ -0,0 +1,57 @@ +{ + "name": "oci-javascript-mcp-server", + "version": "0.1.0", + "description": "OCI JavaScript execution MCP server with a VM-oriented isolation provider contract", + "type": "module", + "bin": { + "oci-javascript-mcp-server": "src/server.ts" + }, + "files": [ + "src/", + "README.md", + "LICENSE.txt", + "Containerfile", + ".dockerignore" + ], + "scripts": { + "start": "node --experimental-strip-types src/server.ts", + "apple-container:build": "container build --pull -t localhost/oci-javascript-mcp-runner:dev .", + "test": "node --experimental-strip-types --test test/*.test.ts", + "coverage": "c8 npm test", + "check": "tsc --noEmit", + "packcheck": "npm --cache \"${TMPDIR:-/tmp}/oci-javascript-mcp-server-npm-cache\" pack --dry-run --json > /dev/null", + "ci": "npm run coverage && npm run check && npm run packcheck", + "prepublishOnly": "npm run ci" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "oci-common": "^2.132.0", + "oci-sdk": "^2.132.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "c8": "^12.0.0", + "typescript": "^5.9.3" + }, + "c8": { + "all": true, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/types.ts", + "src/runner.ts" + ], + "check-coverage": true, + "lines": 90, + "reporter": [ + "text" + ] + }, + "engines": { + "node": ">=26" + }, + "packageManager": "npm@11.17.0", + "license": "UPL-1.0" +} diff --git a/src/oci-javascript-mcp-server/src/execution.ts b/src/oci-javascript-mcp-server/src/execution.ts new file mode 100644 index 00000000..26a4f674 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/execution.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { HostExecutionBroker, developmentPolicy, productionPolicy } from "./policy.ts"; +import { admitProvider } from "./isolation/admission.ts"; +import { OciSdkRuntime } from "./oci.ts"; +import type { ExecutionPolicy, ExecutionResult, IsolationProvider } from "./types.ts"; + +const MAX_CODE_BYTES = 1024 * 1024; +const MAX_RESULT_BYTES = 1024 * 1024; +const MAX_OUTPUT_BYTES = 1024 * 1024; + +export async function runJavaScript( + code: string, + options: { + timeoutSeconds?: number; + provider: IsolationProvider; + runtime?: OciSdkRuntime; + mode?: "development" | "production"; + policy?: ExecutionPolicy; + signal?: AbortSignal; + } +): Promise { + if (typeof code !== "string") throw new Error("code must be a string"); + if (Buffer.byteLength(code, "utf8") > MAX_CODE_BYTES) { + throw new Error(`code exceeds ${MAX_CODE_BYTES} bytes`); + } + const timeoutSeconds = options.timeoutSeconds ?? 30; + if (!Number.isFinite(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > 120) { + throw new Error("timeout must be between 1 and 120 seconds"); + } + const mode = options.mode ?? "production"; + admitProvider(options.provider, mode); + const runtime = options.runtime ?? new OciSdkRuntime(); + const manifest = runtime.manifest(); + const deadlineMs = Date.now() + Math.ceil(timeoutSeconds * 1000); + const policy = options.policy ?? (mode === "development" + ? developmentPolicy(manifest, deadlineMs, { + allowMutations: process.env.OCI_JAVASCRIPT_ALLOW_MUTATIONS === "1" + }) + : productionPolicy(deadlineMs)); + const broker = new HostExecutionBroker(runtime, policy); + const execution = await options.provider.start({ + code, + manifest, + deadlineMs, + maxResultBytes: MAX_RESULT_BYTES, + maxOutputBytes: MAX_OUTPUT_BYTES, + broker: request => broker.handle(request), + signal: options.signal + }); + try { + return await execution.result; + } finally { + broker.cancel(); + await execution.destroy(); + } +} diff --git a/src/oci-javascript-mcp-server/src/facade.ts b/src/oci-javascript-mcp-server/src/facade.ts new file mode 100644 index 00000000..f87956a6 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/facade.ts @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import type { Json, JsonObject, ReflectionManifest, RpcOperation } from "./types.ts"; + +const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_]*$/; +const REGION = /^[a-z][a-z0-9-]*-[a-z0-9-]+-[0-9]+$/; +const RESERVED = new Set(["then", "catch", "finally", "toJSON"]); + +export type FacadeRpc = (operation: RpcOperation, payload: JsonObject) => Promise; + +export function createOciFacade(manifest: ReflectionManifest, rpc: FacadeRpc): object { + const services = new Map(); + const clients = new Map(); + + const makeClient = (service: string, client: string, options?: unknown): object => { + validateName(service, "service"); + validateName(client, "client"); + const normalized = normalizeOptions(options); + const cacheKey = `${service}.${client}.${normalized.region ?? ""}`; + const cached = clients.get(cacheKey); + if (cached) return cached; + const operations = manifest.services[service]?.clients[client]?.operations ?? []; + const target = Object.create(null) as Record; + let proxy!: Record; + proxy = new Proxy(target, { + get(_target, property) { + if (typeof property !== "string" || property.startsWith("_") || RESERVED.has(property)) { + return undefined; + } + validateName(property, "operation"); + return async (request: JsonObject = {}) => rpc("invoke", { + service, + client: Object.keys(normalized).length > 0 + ? { name: client, options: normalized } + : { name: client }, + operation: property, + request + }); + }, + ownKeys() { return [...operations]; }, + getOwnPropertyDescriptor(_target, property) { + if (typeof property === "string" && operations.includes(property)) { + return { value: proxy[property], enumerable: true, configurable: true }; + } + return undefined; + } + }); + clients.set(cacheKey, proxy); + return proxy; + }; + + const makeClientFactory = (service: string, client: string): Function => { + const operations = manifest.services[service]?.clients[client]?.operations ?? []; + const target = function OciClient(options?: unknown) { + return makeClient(service, client, options); + }; + return new Proxy(target, { + construct(_target, args) { return makeClient(service, client, args[0]); }, + get(targetValue, property) { + if (Reflect.has(targetValue, property)) return Reflect.get(targetValue, property); + if (typeof property !== "string" || RESERVED.has(property)) return undefined; + return (makeClient(service, client) as Record)[property]; + }, + ownKeys(targetValue) { + return mergeKeys(Reflect.ownKeys(targetValue), operations); + }, + getOwnPropertyDescriptor(targetValue, property) { + return Reflect.getOwnPropertyDescriptor(targetValue, property) + ?? (typeof property === "string" && operations.includes(property) + ? { value: (makeClient(service, client) as Record)[property], enumerable: true, configurable: true } + : undefined); + } + }); + }; + + const makeService = (service: string): object => { + const cached = services.get(service); + if (cached) return cached; + const clientNames = Object.keys(manifest.services[service]?.clients ?? {}); + const target = Object.create(null) as Record; + const proxy = new Proxy(target, { + get(_target, property) { + if (typeof property !== "string" || property.startsWith("_") || RESERVED.has(property)) { + return undefined; + } + validateName(property, "client"); + return makeClientFactory(service, property); + }, + ownKeys() { return clientNames; }, + getOwnPropertyDescriptor(_target, property) { + if (typeof property === "string" && clientNames.includes(property)) { + return { value: makeClientFactory(service, property), enumerable: true, configurable: true }; + } + return undefined; + } + }); + services.set(service, proxy); + return proxy; + }; + + const serviceNames = Object.keys(manifest.services); + const target = Object.create(null) as Record; + Object.defineProperty(target, "config", { + value: async () => rpc("config", {}), enumerable: true, writable: false, configurable: false + }); + return new Proxy(target, { + get(targetValue, property) { + if (Reflect.has(targetValue, property)) return Reflect.get(targetValue, property); + if (typeof property !== "string" || property.startsWith("_") || RESERVED.has(property)) { + return undefined; + } + return serviceNames.includes(property) ? makeService(property) : undefined; + }, + ownKeys(targetValue) { return mergeKeys(Reflect.ownKeys(targetValue), serviceNames); }, + getOwnPropertyDescriptor(targetValue, property) { + return Reflect.getOwnPropertyDescriptor(targetValue, property) + ?? (typeof property === "string" && serviceNames.includes(property) + ? { value: makeService(property), enumerable: true, configurable: true } + : undefined); + } + }); +} + +export function inferFinalExpression(code: string): string { + const trimmed = code.replace(/[\s;]*$/g, ""); + for (const start of finalExpressionStarts(trimmed)) { + const expression = trimmed.slice(start).trim(); + if (expression && isExpression(expression)) { + return `${trimmed.slice(0, start)}\nreturn (${expression});`; + } + } + return code; +} + +function finalExpressionStarts(code: string): number[] { + const starts = [0]; + let depth = 0; + let quote: string | null = null; + let escaped = false; + let lineComment = false; + let blockComment = false; + for (let index = 0; index < code.length; index += 1) { + const char = code[index]!; + const next = code[index + 1]; + if (lineComment) { + if (char === "\n") { lineComment = false; starts.push(index + 1); } + continue; + } + if (blockComment) { + if (char === "*" && next === "/") { blockComment = false; index += 1; } + continue; + } + if (quote) { + if (escaped) escaped = false; + else if (char === "\\") escaped = true; + else if (char === quote) quote = null; + continue; + } + if (char === "/" && next === "/") { lineComment = true; index += 1; continue; } + if (char === "/" && next === "*") { blockComment = true; index += 1; continue; } + if (char === "\"" || char === "'" || char === "`") { quote = char; continue; } + if ("([{ ".trim().includes(char)) depth += 1; + else if (")] }".replace(" ", "").includes(char)) depth = Math.max(0, depth - 1); + else if (depth === 0 && (char === ";" || char === "\n")) starts.push(index + 1); + } + return starts.reverse(); +} + +function isExpression(source: string): boolean { + try { + new Function(`return (async () => (${source}));`); + return true; + } catch { + return false; + } +} + +function normalizeOptions(value: unknown): { region?: string } { + if (value === undefined || value === null) return {}; + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error("OCI client options must be a plain object"); + } + const record = value as Record; + for (const key of Object.keys(record)) { + if (key !== "region") { + throw new Error(`Unsupported OCI client option '${key}'. Client options only support region.`); + } + } + if (record.region !== undefined && (typeof record.region !== "string" || !REGION.test(record.region))) { + throw new Error(`Invalid OCI client option region '${String(record.region)}'`); + } + return typeof record.region === "string" ? { region: record.region } : {}; +} + +function validateName(value: string, label: string): void { + if (!IDENTIFIER.test(value)) throw new Error(`Invalid OCI ${label} '${value}'`); +} + +function mergeKeys(first: Array, second: string[]): Array { + return [...new Set([...first, ...second])]; +} diff --git a/src/oci-javascript-mcp-server/src/isolation/admission.ts b/src/oci-javascript-mcp-server/src/isolation/admission.ts new file mode 100644 index 00000000..c25f0564 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/isolation/admission.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import type { IsolationProvider } from "../types.ts"; + +export function admitProvider(provider: IsolationProvider, mode: "development" | "production"): void { + const capabilities = provider.capabilities; + if (mode === "development") return; + if (capabilities.developmentOnly + || capabilities.boundary !== "virtual-machine" + || !capabilities.separateGuestKernel + || !capabilities.hardwareVirtualization + || !capabilities.networkCreationBlocked) { + throw new Error( + `isolation provider '${capabilities.provider}' is not admitted in production: ` + + "an approved VM boundary with a separate guest kernel and blocked network creation is required" + ); + } +} diff --git a/src/oci-javascript-mcp-server/src/isolation/apple-container.ts b/src/oci-javascript-mcp-server/src/isolation/apple-container.ts new file mode 100644 index 00000000..6b524f8c --- /dev/null +++ b/src/oci-javascript-mcp-server/src/isolation/apple-container.ts @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { spawn } from "node:child_process"; +import { randomUUID } from "node:crypto"; +import { + runCleanupCommand, + runnerEnvironment, + startPipeExecution +} from "./pipe-execution.ts"; +import type { + IsolationExecution, + IsolationProvider, + ProviderCapabilities +} from "../types.ts"; + +const DEFAULT_IMAGE = "localhost/oci-javascript-mcp-runner:dev"; +const DEFAULT_NETWORK = "oci-javascript-mcp-internal"; +const SAFE_IMAGE_REFERENCE = /^[A-Za-z0-9][A-Za-z0-9._/:@-]{0,255}$/; +const SAFE_NETWORK_NAME = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,62}$/; + +export class AppleContainerIsolationProvider implements IsolationProvider { + readonly #cliPath: string; + readonly #image: string; + readonly #network: string; + readonly capabilities: ProviderCapabilities = Object.freeze({ + provider: "apple-container", + boundary: "virtual-machine", + developmentOnly: true, + separateGuestKernel: true, + hardwareVirtualization: true, + networkCreationBlocked: false + }); + + constructor(options: { + cliPath?: string; + image?: string; + network?: string; + } = {}) { + this.#cliPath = options.cliPath ?? "container"; + if (!this.#cliPath || this.#cliPath.includes("\0")) { + throw new Error("Apple container CLI path is invalid"); + } + this.#image = validateName( + options.image ?? DEFAULT_IMAGE, + SAFE_IMAGE_REFERENCE, + "Apple container image" + ); + this.#network = validateName( + options.network ?? DEFAULT_NETWORK, + SAFE_NETWORK_NAME, + "Apple container network" + ); + } + + async start(input: Parameters[0]): Promise { + const name = `oci-javascript-${randomUUID()}`; + const child = spawn(this.#cliPath, [ + "run", + "--rm", + "--interactive", + "--name", name, + "--cpus", "1", + "--memory", "512M", + "--read-only", + "--cap-drop", "ALL", + "--no-dns", + "--network", this.#network, + "--user", "65532:65532", + "--ulimit", "nofile=64:64", + this.#image + ], { + env: runnerEnvironment(), + stdio: ["pipe", "pipe", "pipe"], + detached: process.platform !== "win32" + }); + return startPipeExecution( + child, + input, + () => runCleanupCommand(this.#cliPath, ["delete", "--force", name]) + ); + } +} + +function validateName(value: string, pattern: RegExp, label: string): string { + if (!pattern.test(value)) throw new Error(`${label} is invalid`); + return value; +} diff --git a/src/oci-javascript-mcp-server/src/isolation/pipe-execution.ts b/src/oci-javascript-mcp-server/src/isolation/pipe-execution.ts new file mode 100644 index 00000000..83073344 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/isolation/pipe-execution.ts @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process"; +import { + FrameDecoder, + ProtocolError, + assertExactFields, + encodeFrame, + protocolMessage +} from "../protocol.ts"; +import type { + ExecutionResult, + GuestRpcRequest, + IsolationExecution, + IsolationProvider, + Json, + JsonObject +} from "../types.ts"; + +export function startPipeExecution( + child: ChildProcessWithoutNullStreams, + input: Parameters[0], + afterClose?: () => Promise +): IsolationExecution { + const decoder = new FrameDecoder(); + let stdout = ""; + let stderr = ""; + let settled = false; + let ready = false; + let resolveResult!: (value: ExecutionResult) => void; + const result = new Promise(resolve => { resolveResult = resolve; }); + const close = new Promise(resolve => child.once("close", () => resolve())); + let cleanup: Promise | undefined; + const destroy = () => cleanup ??= (async () => { + killChildTree(child); + await close; + await afterClose?.(); + })(); + + const finish = (value: ExecutionResult, terminate = false) => { + if (settled) return; + settled = true; + resolveResult({ ...value, stdout, stderr }); + if (terminate) void destroy(); + }; + const fail = (message: string, terminate = true) => finish({ + result: null, + error: { message: "JavaScript execution failed", category: message }, + stdout: "", + stderr: "", + exitCode: 1, + timedOut: false + }, terminate); + + child.stdout.on("data", chunk => { + try { + for (const message of decoder.push(chunk)) { + void handleGuestMessage(message, child, input, { + appendLog(stream, text) { + if (stream === "stdout") stdout = appendBounded(stdout, text, input.maxOutputBytes); + else stderr = appendBounded(stderr, text, input.maxOutputBytes); + }, + ready() { + if (ready) throw new ProtocolError("runner sent duplicate health message"); + ready = true; + send(child, "execute", { + code: input.code, + manifest: input.manifest as unknown as Json, + timeoutMs: Math.max(1, input.deadlineMs - Date.now()), + maxResultBytes: input.maxResultBytes, + maxOutputBytes: input.maxOutputBytes + }); + }, + finish + }).catch(error => fail(`protocol error: ${errorMessage(error)}`)); + } + } catch (error) { + fail(`protocol error: ${errorMessage(error)}`); + } + }); + child.stderr.on("data", chunk => { + stderr = appendBounded(stderr, String(chunk), input.maxOutputBytes); + }); + child.once("error", () => fail("runner process error", false)); + child.once("close", (code, signal) => { + if (!settled) fail(`runner exited before returning a result (${signal ?? code ?? "unknown"})`, false); + }); + const timeout = setTimeout(() => { + finish({ + result: null, + error: { message: "JavaScript execution timed out" }, + stdout: "", + stderr: "", + exitCode: -1, + timedOut: true + }, true); + }, Math.max(1, input.deadlineMs - Date.now())); + timeout.unref(); + const abort = () => { + if (child.stdin.writable) { + try { send(child, "cancel", {}); } catch {} + } + finish({ + result: null, + error: { message: "JavaScript execution cancelled" }, + stdout: "", + stderr: "", + exitCode: -1, + timedOut: false + }, true); + }; + input.signal?.addEventListener("abort", abort, { once: true }); + result.finally(() => { + clearTimeout(timeout); + input.signal?.removeEventListener("abort", abort); + }); + + return { + result, + destroy + }; +} + +export function runnerEnvironment(): NodeJS.ProcessEnv { + const environment: NodeJS.ProcessEnv = {}; + for (const name of ["PATH", "TMPDIR", "TMP", "TEMP", "NODE_V8_COVERAGE"]) { + if (process.env[name]) environment[name] = process.env[name]; + } + return environment; +} + +export function runCleanupCommand(command: string, args: string[]): Promise { + return new Promise(resolve => { + let settled = false; + const cleanup = spawn(command, args, { + env: runnerEnvironment(), + stdio: "ignore" + }); + const finish = () => { + if (settled) return; + settled = true; + clearTimeout(timeout); + resolve(); + }; + cleanup.once("error", finish); + cleanup.once("close", finish); + const timeout = setTimeout(() => { + cleanup.kill("SIGKILL"); + finish(); + }, 5_000); + }); +} + +async function handleGuestMessage( + message: JsonObject, + child: ChildProcessWithoutNullStreams, + input: Parameters[0], + callbacks: { + appendLog(stream: "stdout" | "stderr", text: string): void; + ready(): void; + finish(result: ExecutionResult, terminate?: boolean): void; + } +): Promise { + if (message.type === "health") { + assertExactFields(message, ["version", "type", "status"]); + if (message.status !== "ready") throw new ProtocolError("invalid runner health status"); + callbacks.ready(); + return; + } + if (message.type === "log") { + assertExactFields(message, ["version", "type", "stream", "text"]); + if ((message.stream !== "stdout" && message.stream !== "stderr") || typeof message.text !== "string") { + throw new ProtocolError("invalid log message"); + } + callbacks.appendLog(message.stream, message.text); + return; + } + if (message.type === "rpc") { + assertExactFields(message, ["version", "type", "id", "operation", "payload"]); + if (!Number.isInteger(message.id) || (message.operation !== "config" && message.operation !== "invoke") + || !isObject(message.payload)) { + throw new ProtocolError("invalid RPC message"); + } + const request: GuestRpcRequest = { + operation: message.operation, + payload: message.payload + }; + try { + const value = await input.broker(request); + send(child, "rpc_result", { id: message.id, ok: true, value }); + } catch (error) { + send(child, "rpc_result", { + id: message.id, + ok: false, + error: { message: publicBrokerError(error) } + }); + } + return; + } + if (message.type === "result") { + assertExactFields(message, ["version", "type", "result", "error", "exitCode", "timedOut"]); + if (!Number.isInteger(message.exitCode) || typeof message.timedOut !== "boolean" + || (message.error !== null && !isObject(message.error))) { + throw new ProtocolError("invalid result message"); + } + if (((message.exitCode as number) === 0) !== (message.error === null) + || (message.timedOut && message.error === null)) { + throw new ProtocolError("result status fields are inconsistent"); + } + const bytes = Buffer.byteLength(JSON.stringify(message.result), "utf8"); + if (bytes > input.maxResultBytes) throw new ProtocolError("runner result exceeds configured limit"); + callbacks.finish({ + result: message.result, + error: message.error as ExecutionResult["error"], + stdout: "", + stderr: "", + exitCode: message.exitCode as number, + timedOut: message.timedOut as boolean + }); + return; + } + if (message.type === "protocol_error") { + assertExactFields(message, ["version", "type", "error"]); + throw new ProtocolError("runner reported a protocol failure"); + } + throw new ProtocolError(`unsupported guest message type '${String(message.type)}'`); +} + +function send(child: ChildProcessWithoutNullStreams, type: string, fields: JsonObject): void { + if (!child.stdin.writable) throw new Error("runner channel is closed"); + child.stdin.write(encodeFrame(protocolMessage(type, fields))); +} + +function appendBounded(current: string, text: string, maximum: number): string { + const combined = current + text; + const bytes = Buffer.from(combined, "utf8"); + return bytes.length <= maximum ? combined : bytes.subarray(0, maximum).toString("utf8"); +} + +function killChildTree(child: ChildProcessWithoutNullStreams): void { + if (child.exitCode !== null || child.signalCode !== null) return; + if (process.platform !== "win32" && child.pid) { + try { process.kill(-child.pid, "SIGKILL"); return; } catch {} + } + child.kill("SIGKILL"); +} + +function publicBrokerError(error: unknown): string { + const message = errorMessage(error); + return /not authorized|limit|deadline|cancelled|Unknown OCI|Invalid OCI|Unsupported OCI/i.test(message) + ? message + : "OCI operation failed"; +} + +function errorMessage(error: unknown): string { + return error instanceof Error ? error.message : String(error); +} + +function isObject(value: Json | undefined): value is JsonObject { + return !!value && typeof value === "object" && !Array.isArray(value); +} diff --git a/src/oci-javascript-mcp-server/src/isolation/process.ts b/src/oci-javascript-mcp-server/src/isolation/process.ts new file mode 100644 index 00000000..867559fb --- /dev/null +++ b/src/oci-javascript-mcp-server/src/isolation/process.ts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { spawn } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { runnerEnvironment, startPipeExecution } from "./pipe-execution.ts"; +import type { + IsolationExecution, + IsolationProvider, + ProviderCapabilities +} from "../types.ts"; + +const RUNNER_PATH = fileURLToPath(new URL("../runner.ts", import.meta.url)); + +export class ProcessIsolationProvider implements IsolationProvider { + readonly #runnerPath: string; + readonly capabilities: ProviderCapabilities = Object.freeze({ + provider: "process", + boundary: "process", + developmentOnly: true, + separateGuestKernel: false, + hardwareVirtualization: false, + networkCreationBlocked: false + }); + + constructor(options: { allowInsecure: boolean; runnerPath?: string }) { + if (!options.allowInsecure) { + throw new Error( + "local process isolation is insecure and requires OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS=1" + ); + } + this.#runnerPath = options.runnerPath ?? RUNNER_PATH; + } + + async start(input: Parameters[0]): Promise { + const child = spawn(process.execPath, [ + "--experimental-strip-types", + "--max-old-space-size=256", + this.#runnerPath + ], { + env: runnerEnvironment(), + stdio: ["pipe", "pipe", "pipe"], + detached: process.platform !== "win32" + }); + return startPipeExecution(child, input); + } +} diff --git a/src/oci-javascript-mcp-server/src/oci.ts b/src/oci-javascript-mcp-server/src/oci.ts new file mode 100644 index 00000000..f92344f0 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/oci.ts @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { createRequire } from "node:module"; +import { existsSync, readFileSync } from "node:fs"; +import { homedir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import type { + Json, + JsonObject, + OciDiscoverFilter, + OciInvokePayload, + ReflectionManifest +} from "./types.ts"; + +const require = createRequire(import.meta.url); +const packageMetadata = require("../package.json") as { name?: unknown; version?: unknown }; +const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_]*$/; +const REGION = /^[a-z][a-z0-9-]*-[a-z0-9-]+-[0-9]+$/; +const SENSITIVE_FIELD = /^(authenticationDetailsProvider|authProvider|signer|privateKey|sessionToken|securityToken)$/i; +const MAX_SANITIZE_DEPTH = 32; + +export type SdkBundle = { + sdk: Record; + common: Record; +}; + +export type SdkLoader = () => SdkBundle; +export type AuthProviderFactory = (bundle: SdkBundle) => any; + +export type RequestField = { + name: string; + required: boolean; + type: string; +}; + +export class OciSdkRuntime { + readonly #loadSdk: SdkLoader; + readonly #createAuthProvider: AuthProviderFactory; + #manifest: ReflectionManifest | undefined; + + constructor( + loadSdk: SdkLoader = loadDefaultSdk, + createAuthProvider: AuthProviderFactory = defaultAuthProvider + ) { + this.#loadSdk = loadSdk; + this.#createAuthProvider = createAuthProvider; + } + + manifest(): ReflectionManifest { + if (this.#manifest) { + return this.#manifest; + } + const { sdk } = this.#loadSdk(); + const services: ReflectionManifest["services"] = Object.create(null); + for (const service of Object.keys(sdk).sort()) { + const serviceModule = sdk[service]; + if (!serviceModule || typeof serviceModule !== "object") { + continue; + } + const clients: ReflectionManifest["services"][string]["clients"] = Object.create(null); + for (const client of clientNames(serviceModule)) { + const operations = operationNames(service, serviceModule[client]); + if (operations.length === 0) { + continue; + } + const requestFields: Record = Object.create(null); + for (const operation of operations) { + requestFields[operation] = operationRequestFields(service, operation).map(field => field.name); + } + clients[client] = { operations, requestFields }; + } + if (Object.keys(clients).length > 0) { + services[service] = { clients }; + } + } + this.#manifest = { services }; + return this.#manifest; + } + + discover(filter: OciDiscoverFilter): JsonObject { + assertOnlyFields(filter as Record, ["service", "client", "operation"], "discovery filter"); + const manifest = this.manifest(); + if (!filter.service) { + return { type: "index", services: Object.keys(manifest.services) }; + } + validateIdentifier(filter.service, "service"); + const service = manifest.services[filter.service]; + if (!service) { + throw new Error(`Unknown OCI SDK service '${filter.service}'`); + } + if (!filter.client) { + return { type: "service", service: filter.service, clients: Object.keys(service.clients) }; + } + validateIdentifier(filter.client, "client"); + const client = service.clients[filter.client]; + if (!client) { + throw new Error(`Unknown OCI SDK client '${filter.service}.${filter.client}'`); + } + if (!filter.operation) { + return { + type: "client", + service: filter.service, + client: filter.client, + operations: client.operations + }; + } + validateIdentifier(filter.operation, "operation"); + if (!client.operations.includes(filter.operation)) { + throw new Error(`Unknown OCI SDK operation '${filter.service}.${filter.client}.${filter.operation}'`); + } + const fields = operationRequestFields(filter.service, filter.operation); + return { + type: "operation", + service: filter.service, + client: filter.client, + operation: filter.operation, + requestType: `${pascalCase(filter.operation)}Request`, + requestFields: fields.map(field => ({ + name: field.name, + required: field.required, + fieldType: field.type + })) as Json, + response: operationResponseShape(filter.service, filter.operation) + }; + } + + config(): JsonObject { + const bundle = this.#loadSdk(); + const provider = this.#createAuthProvider(bundle); + const userId = optionalCall(provider, "getUserId") ?? optionalCall(provider, "getUser") ?? null; + const region = optionalCall(provider, "getRegion")?.regionId + ?? optionalCall(provider, "getRegionId") + ?? null; + return sanitizeJson({ + tenancyId: optionalCall(provider, "getTenantId") ?? null, + userId, + region, + principal: typeof userId === "string" + ? { type: userId.startsWith("ocid1.user.") ? "user" : "unknown", id: userId } + : null + }) as JsonObject; + } + + async invoke(payload: OciInvokePayload, timeoutMs: number, maxRetries = 0): Promise { + const { sdk, common } = this.#loadSdk(); + const serviceModule = sdk[payload.service]; + const Client = serviceModule?.[payload.client.name]; + if (typeof Client !== "function") { + throw new Error(`OCI client '${payload.service}.${payload.client.name}' is unavailable`); + } + const provider = this.#createAuthProvider({ sdk, common }); + if (payload.client.options?.region) { + if (typeof provider?.setRegion !== "function") { + throw new Error("OCI authentication provider does not support region selection"); + } + provider.setRegion(payload.client.options.region); + } + const configuration: Record = {}; + if (typeof common.CircuitBreaker === "function") { + configuration.circuitBreaker = new common.CircuitBreaker({ timeout: Math.max(1, timeoutMs) }); + } + if (maxRetries === 0 && common.NoRetryConfigurationDetails) { + configuration.retryConfiguration = common.NoRetryConfigurationDetails; + } else if (maxRetries > 0 && common.OciSdkDefaultRetryConfiguration + && typeof common.MaxAttemptsTerminationStrategy === "function") { + configuration.retryConfiguration = { + ...common.OciSdkDefaultRetryConfiguration, + terminationStrategy: new common.MaxAttemptsTerminationStrategy(maxRetries + 1) + }; + } + const client = new Client({ + authenticationDetailsProvider: provider, + additionalUserAgent: additionalUserAgent(packageMetadata) + }, Object.keys(configuration).length > 0 ? configuration : undefined); + try { + const operation = client[payload.operation]; + if (typeof operation !== "function") { + throw new Error(`OCI operation '${payload.operation}' is unavailable`); + } + return sanitizeJson(await operation.call(client, payload.request ?? Object.create(null))); + } finally { + if (typeof client.close === "function") { + client.close(); + } + } + } +} + +export function validateClientOptions(value: unknown): { region?: string } { + if (value === undefined) { + return Object.create(null) as { region?: string }; + } + if (!isObject(value)) { + throw new Error("OCI client options must be an object"); + } + assertOnlyFields(value, ["region"], "OCI client options"); + if (value.region !== undefined && (typeof value.region !== "string" || !REGION.test(value.region))) { + throw new Error(`Invalid OCI region '${String(value.region)}'`); + } + const result = Object.create(null) as { region?: string }; + if (typeof value.region === "string") { + result.region = value.region; + } + return result; +} + +export function operationKey(service: string, client: string, operation: string): string { + return `${service}.${client}.${operation}`; +} + +export function isMutationOperation(operation: string): boolean { + return !/^(get|list|search|head|summarize|retrieve)/i.test(operation); +} + +export function sanitizeJson(value: unknown, maxDepth = MAX_SANITIZE_DEPTH): Json { + const seen = new WeakSet(); + const visit = (item: unknown, depth: number): Json => { + if (depth > maxDepth) { + return "[MaxDepth]"; + } + if (item === null || typeof item === "string" || typeof item === "boolean") { + return item; + } + if (typeof item === "number") { + return Number.isFinite(item) ? item : String(item); + } + if (typeof item === "bigint") { + return item.toString(); + } + if (item instanceof Date) { + return item.toISOString(); + } + if (item instanceof Uint8Array) { + return Buffer.from(item).toString("base64"); + } + if (!item || typeof item !== "object") { + return String(item); + } + if (seen.has(item)) { + return "[Circular]"; + } + seen.add(item); + try { + if (Array.isArray(item)) { + return item.map(entry => visit(entry, depth + 1)); + } + const result = Object.create(null) as JsonObject; + for (const [key, child] of Object.entries(item)) { + if (SENSITIVE_FIELD.test(key) || isTransportObject(key, child)) { + continue; + } + result[key] = visit(child, depth + 1); + } + return result; + } finally { + seen.delete(item); + } + }; + return visit(value, 0); +} + +function loadDefaultSdk(): SdkBundle { + return { sdk: require("oci-sdk"), common: require("oci-common") }; +} + +function defaultAuthProvider(bundle: SdkBundle): any { + const configFile = process.env.OCI_CONFIG_FILE + ? resolve(process.env.OCI_CONFIG_FILE) + : join(homedir(), ".oci", "config"); + const profile = process.env.OCI_CONFIG_PROFILE ?? "DEFAULT"; + const profileValues = readProfile(configFile, profile); + if (profileValues.security_token_file && typeof bundle.common.SessionAuthDetailProvider === "function") { + return new bundle.common.SessionAuthDetailProvider(configFile, profile); + } + const Provider = bundle.sdk.ConfigFileAuthenticationDetailsProvider + ?? bundle.common.ConfigFileAuthenticationDetailsProvider; + if (typeof Provider !== "function") { + throw new Error("OCI authentication provider is unavailable"); + } + return new Provider(configFile, profile); +} + +function clientNames(service: Record): string[] { + return Object.keys(service) + .filter(name => name.endsWith("Client") && typeof service[name] === "function") + .sort(); +} + +function operationNames(service: string, Client: any): string[] { + return Object.getOwnPropertyNames(Client.prototype) + .filter(name => name !== "constructor" && !name.startsWith("_")) + .filter(name => typeof Client.prototype[name] === "function") + .filter(name => requestFile(service, name) !== null) + .sort(); +} + +function operationRequestFields(service: string, operation: string): RequestField[] { + const path = requestFile(service, operation); + if (!path) { + return []; + } + const interfaceName = `${pascalCase(operation)}Request`; + const body = interfaceBody(readFileSync(path, "utf8"), interfaceName); + if (!body) { + return []; + } + const fields: RequestField[] = []; + const pattern = /^\s{4}"([^"]+)"(\?)?:\s*([^;\n]+(?:\n\s{8}[^;\n]+)*);/gm; + let match: RegExpExecArray | null; + while ((match = pattern.exec(body)) !== null) { + fields.push({ + name: match[1]!, + required: match[2] !== "?", + type: match[3]!.replace(/\s+/g, " ").trim() + }); + } + return fields; +} + +function operationResponseShape(service: string, operation: string): JsonObject { + const root = servicePackageRoot(service); + if (!root) { + return { description: "OCI SDK response object" }; + } + const path = join(root, "lib", "client.js"); + if (!existsSync(path)) { + return { description: "OCI SDK response object" }; + } + const source = readFileSync(path, "utf8"); + const start = source.indexOf(` ${operation}(${operation}Request) {`); + const snippet = start >= 0 ? source.slice(start, start + 12_000) : ""; + const bodyKey = /bodyKey:\s*"([^"]+)"/.exec(snippet)?.[1]; + return { + description: "Sanitized OCI SDK response object", + ...(bodyKey ? { bodyField: bodyKey } : {}), + ...(snippet.includes("opc-next-page") + ? { pagination: { responseField: "opcNextPage", requestField: "page" } } + : {}) + }; +} + +function requestFile(service: string, operation: string): string | null { + const root = servicePackageRoot(service); + if (!root) { + return null; + } + const path = join(root, "lib", "request", `${kebabCase(`${pascalCase(operation)}Request`)}.d.ts`); + return existsSync(path) ? path : null; +} + +function servicePackageRoot(service: string): string | null { + try { + return dirname(require.resolve(`oci-${service}/package.json`)); + } catch { + return null; + } +} + +function interfaceBody(source: string, name: string): string | null { + const match = new RegExp(`export\\s+interface\\s+${name}\\b[^\\{]*\\{`, "m").exec(source); + if (!match) { + return null; + } + let depth = 1; + const start = match.index + match[0].length; + for (let index = start; index < source.length; index += 1) { + if (source[index] === "{") depth += 1; + if (source[index] === "}") depth -= 1; + if (depth === 0) return source.slice(start, index); + } + return null; +} + +function pascalCase(value: string): string { + return value.replace(/(^|[_-])([A-Za-z0-9])/g, (_match, _separator, char: string) => char.toUpperCase()) + .replace(/[^A-Za-z0-9]/g, ""); +} + +function kebabCase(value: string): string { + return value.replace(/([a-z0-9])([A-Z])/g, "$1-$2") + .replace(/([A-Z])([A-Z][a-z])/g, "$1-$2") + .toLowerCase(); +} + +function additionalUserAgent(metadata: { name?: unknown; version?: unknown }): string { + const name = typeof metadata.name === "string" ? metadata.name : "oci-javascript-mcp-server"; + const version = typeof metadata.version === "string" ? metadata.version : "0.0.0"; + return `${name.replace(/^@[^/]+\//, "").replace(/^oracle\./, "").replace(/-server$/, "")}/${version}`; +} + +function validateIdentifier(value: unknown, label: string): asserts value is string { + if (typeof value !== "string" || !IDENTIFIER.test(value)) { + throw new Error(`Invalid OCI ${label} '${String(value)}'`); + } +} + +function assertOnlyFields(value: Record, allowed: string[], label: string): void { + const fields = new Set(allowed); + for (const key of Object.keys(value)) { + if (!fields.has(key)) { + throw new Error(`Unsupported ${label} field '${key}'`); + } + } +} + +function isObject(value: unknown): value is Record { + return !!value && typeof value === "object" && !Array.isArray(value); +} + +function optionalCall(target: any, name: string): any { + try { + return typeof target?.[name] === "function" ? target[name]() : null; + } catch { + return null; + } +} + +function readProfile(path: string, profile: string): Record { + if (!existsSync(path)) { + return {}; + } + const result: Record = {}; + let active = false; + for (const raw of readFileSync(path, "utf8").split(/\r?\n/)) { + const line = raw.trim(); + const section = /^\[(.+)]$/.exec(line); + if (section) { + active = section[1]!.toUpperCase() === profile.toUpperCase(); + } else if (active && line && !line.startsWith("#") && line.includes("=")) { + const index = line.indexOf("="); + result[line.slice(0, index).trim()] = line.slice(index + 1).trim(); + } + } + return result; +} + +function isTransportObject(key: string, value: unknown): boolean { + if (!isObject(value)) { + return false; + } + if (key === "httpRequest" || key === "httpResponse") { + return true; + } + const keys = new Set(Object.keys(value).map(field => field.toLowerCase())); + return (key === "request" || key === "response") + && keys.has("headers") + && (["method", "uri", "url", "status", "body"].some(field => keys.has(field))); +} diff --git a/src/oci-javascript-mcp-server/src/policy.ts b/src/oci-javascript-mcp-server/src/policy.ts new file mode 100644 index 00000000..ef5af82e --- /dev/null +++ b/src/oci-javascript-mcp-server/src/policy.ts @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import type { + ExecutionPolicy, + GuestRpcRequest, + Json, + JsonObject, + OciInvokePayload, + ReflectionManifest +} from "./types.ts"; +import { + OciSdkRuntime, + isMutationOperation, + operationKey, + validateClientOptions +} from "./oci.ts"; + +const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_]*$/; +const IDENTITY_CLAIMS = new Set([ + "executionId", "execution_id", "policy", "principal", "principalId", + "credential", "credentials", "auth", "authorization", "signer", "token" +]); + +export class HostExecutionBroker { + readonly #runtime: OciSdkRuntime; + readonly #policy: ExecutionPolicy; + #calls = 0; + #inFlight = 0; + #cancelled = false; + + constructor(runtime: OciSdkRuntime, policy: ExecutionPolicy) { + this.#runtime = runtime; + this.#policy = policy; + } + + cancel(): void { + this.#cancelled = true; + } + + async handle(request: GuestRpcRequest): Promise { + this.#assertLive(); + if (request.operation === "config") { + assertExactObject(request.payload, [], "config payload"); + this.#acquireCall(); + try { + const response = this.#runtime.config(); + if (jsonBytes(response, "OCI config response") > this.#policy.maxResponseBytes) { + throw new Error(`OCI config response exceeds ${this.#policy.maxResponseBytes} bytes`); + } + return response; + } finally { + this.#inFlight -= 1; + } + } + if (request.operation !== "invoke") { + throw new Error(`Unsupported broker operation '${String(request.operation)}'`); + } + const encodedBytes = jsonBytes(request.payload, "OCI request"); + if (encodedBytes > this.#policy.maxRequestBytes) { + throw new Error(`OCI request exceeds ${this.#policy.maxRequestBytes} bytes`); + } + const payload = canonicalInvoke(request.payload, this.#runtime.manifest(), this.#policy); + this.#acquireCall(); + try { + this.#assertLive(); + const response = await this.#runtime.invoke(payload, this.#remainingMs(), this.#policy.maxRetries); + this.#assertLive(); + const responseBytes = jsonBytes(response, "OCI response"); + if (responseBytes > this.#policy.maxResponseBytes) { + throw new Error(`OCI response exceeds ${this.#policy.maxResponseBytes} bytes`); + } + return response; + } finally { + this.#inFlight -= 1; + } + } + + #remainingMs(): number { + return Math.max(0, this.#policy.deadlineMs - Date.now()); + } + + #acquireCall(): void { + if (this.#calls >= this.#policy.maxCalls) { + throw new Error(`OCI call limit exceeded (${this.#policy.maxCalls})`); + } + if (this.#inFlight >= this.#policy.maxConcurrentCalls) { + throw new Error(`OCI concurrency limit exceeded (${this.#policy.maxConcurrentCalls})`); + } + this.#calls += 1; + this.#inFlight += 1; + } + + #assertLive(): void { + if (this.#cancelled) { + throw new Error("execution was cancelled"); + } + if (Date.now() >= this.#policy.deadlineMs) { + throw new Error("execution deadline exceeded"); + } + } +} + +export function developmentPolicy( + manifest: ReflectionManifest, + deadlineMs: number, + overrides: Partial> = {} +): ExecutionPolicy { + const operations = new Set(); + const fields = new Map>(); + for (const [service, serviceEntry] of Object.entries(manifest.services)) { + for (const [client, clientEntry] of Object.entries(serviceEntry.clients)) { + for (const operation of clientEntry.operations) { + const key = operationKey(service, client, operation); + operations.add(key); + fields.set(key, new Set(clientEntry.requestFields?.[operation] ?? [])); + } + } + } + return Object.freeze({ + allowedOperations: operations, + allowMutations: false, + allowedRequestFields: fields, + maxCalls: 32, + maxConcurrentCalls: 4, + maxRequestBytes: 256 * 1024, + maxResponseBytes: 1024 * 1024, + deadlineMs, + maxRetries: 0, + ...overrides + }); +} + +export function productionPolicy(deadlineMs: number): ExecutionPolicy { + return Object.freeze({ + allowedOperations: new Set(), + allowMutations: false, + maxCalls: 0, + maxConcurrentCalls: 0, + maxRequestBytes: 0, + maxResponseBytes: 0, + deadlineMs, + maxRetries: 0 + }); +} + +export function canonicalInvoke( + value: JsonObject, + manifest: ReflectionManifest, + policy: ExecutionPolicy +): OciInvokePayload { + assertExactObject(value, ["service", "client", "operation"], "invoke payload", ["request"]); + const service = identifier(value.service, "service"); + const clientValue = object(value.client, "client"); + assertExactObject(clientValue, ["name"], "client", ["options"]); + const client = identifier(clientValue.name, "client"); + const operation = identifier(value.operation, "operation"); + const key = operationKey(service, client, operation); + const manifestClient = manifest.services[service]?.clients[client]; + if (!manifestClient?.operations.includes(operation)) { + throw new Error(`Unknown OCI SDK operation '${key}'`); + } + if (!policy.allowedOperations.has(key)) { + throw new Error(`OCI operation '${key}' is not authorized`); + } + if (!policy.allowMutations && isMutationOperation(operation)) { + throw new Error(`OCI mutation '${key}' is not authorized for a read-only execution`); + } + const options = validateClientOptions(clientValue.options); + if (options.region && policy.allowedRegions && !policy.allowedRegions.has(options.region)) { + throw new Error(`OCI region '${options.region}' is not authorized`); + } + const requestValue = value.request === undefined ? Object.create(null) : object(value.request, "request"); + rejectIdentityClaims(requestValue); + const allowedFields = policy.allowedRequestFields?.get(key) + ?? new Set(manifestClient.requestFields?.[operation] ?? []); + const request = Object.create(null) as JsonObject; + for (const [field, item] of Object.entries(requestValue)) { + if (!allowedFields.has(field)) { + throw new Error(`OCI request field '${field}' is not authorized for '${key}'`); + } + enforceScope(field, item as Json, policy); + request[field] = copyJson(item as Json); + } + return { + service, + client: Object.keys(options).length > 0 ? { name: client, options } : { name: client }, + operation, + request + }; +} + +export function assertExactObject( + value: Record, + required: string[], + label: string, + optional: string[] = [] +): void { + const allowed = new Set([...required, ...optional]); + for (const key of Object.keys(value)) { + if (!allowed.has(key)) { + throw new Error(`Unsupported ${label} field '${key}'`); + } + } + for (const key of required) { + if (!Object.hasOwn(value, key)) { + throw new Error(`Missing ${label} field '${key}'`); + } + } +} + +function rejectIdentityClaims(value: JsonObject): void { + for (const key of Object.keys(value)) { + if (IDENTITY_CLAIMS.has(key)) { + throw new Error(`Guest-supplied identity or policy claim '${key}' is not allowed`); + } + } +} + +function enforceScope(field: string, value: Json, policy: ExecutionPolicy): void { + if (field === "tenancyId" && policy.allowedTenancyIds && !policy.allowedTenancyIds.has(String(value))) { + throw new Error(`tenancy '${String(value)}' is not authorized`); + } + if (field === "compartmentId" && policy.allowedCompartmentIds + && !policy.allowedCompartmentIds.has(String(value))) { + throw new Error(`compartment '${String(value)}' is not authorized`); + } + if (field === "region" && policy.allowedRegions && !policy.allowedRegions.has(String(value))) { + throw new Error(`region '${String(value)}' is not authorized`); + } + if (/Id$/.test(field) && field !== "tenancyId" && field !== "compartmentId" + && policy.allowedResourceIds && !policy.allowedResourceIds.has(String(value))) { + throw new Error(`resource '${String(value)}' is not authorized`); + } +} + +function copyJson(value: Json): Json { + if (Array.isArray(value)) { + return value.map(copyJson); + } + if (value && typeof value === "object") { + const result = Object.create(null) as JsonObject; + for (const [key, child] of Object.entries(value)) { + result[key] = copyJson(child); + } + return result; + } + return value; +} + +function identifier(value: Json | undefined, label: string): string { + if (typeof value !== "string" || !IDENTIFIER.test(value)) { + throw new Error(`Invalid OCI ${label} '${String(value)}'`); + } + return value; +} + +function object(value: Json | undefined, label: string): JsonObject { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error(`OCI ${label} must be an object`); + } + return value; +} + +function jsonBytes(value: Json, label: string): number { + try { + return Buffer.byteLength(JSON.stringify(value), "utf8"); + } catch { + throw new Error(`${label} is not valid JSON`); + } +} diff --git a/src/oci-javascript-mcp-server/src/protocol.ts b/src/oci-javascript-mcp-server/src/protocol.ts new file mode 100644 index 00000000..986be846 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/protocol.ts @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { TextDecoder } from "node:util"; +import type { Json, JsonObject } from "./types.ts"; + +export const PROTOCOL_VERSION = 1; +export const DEFAULT_MAX_FRAME_BYTES = 2 * 1024 * 1024; + +export type DecodeLimits = Readonly<{ + maxFrameBytes: number; + maxDepth: number; + maxStringBytes: number; + maxArrayLength: number; + maxObjectKeys: number; + maxNodes: number; +}>; + +export const DEFAULT_DECODE_LIMITS: DecodeLimits = Object.freeze({ + maxFrameBytes: DEFAULT_MAX_FRAME_BYTES, + maxDepth: 32, + maxStringBytes: 1024 * 1024, + maxArrayLength: 10_000, + maxObjectKeys: 10_000, + maxNodes: 50_000 +}); + +const DANGEROUS_KEYS = new Set(["__proto__", "prototype", "constructor"]); +const TYPE_TAG_KEYS = new Set(["$type", "__oci_wire_type"]); + +export type ProtocolMessage = JsonObject & { + version: number; + type: string; +}; + +export function encodeFrame(message: JsonObject, maxBytes = DEFAULT_MAX_FRAME_BYTES): Buffer { + const body = Buffer.from(JSON.stringify(message), "utf8"); + if (body.length > maxBytes) { + throw new ProtocolError(`frame length ${body.length} exceeds limit ${maxBytes}`); + } + const header = Buffer.allocUnsafe(4); + header.writeUInt32BE(body.length, 0); + return Buffer.concat([header, body]); +} + +export function decodePayload( + body: Uint8Array, + limits: DecodeLimits = DEFAULT_DECODE_LIMITS +): ProtocolMessage { + if (body.byteLength > limits.maxFrameBytes) { + throw new ProtocolError(`frame length ${body.byteLength} exceeds limit ${limits.maxFrameBytes}`); + } + let text: string; + try { + text = new TextDecoder("utf-8", { fatal: true }).decode(body); + } catch { + throw new ProtocolError("frame is not valid UTF-8"); + } + let parsed: unknown; + try { + parsed = JSON.parse(text) as unknown; + } catch { + throw new ProtocolError("frame is not valid JSON"); + } + const value = canonicalize(parsed, limits); + if (!isRecord(value)) { + throw new ProtocolError("protocol message must be an object"); + } + if (value.version !== PROTOCOL_VERSION) { + throw new ProtocolError(`unsupported protocol version '${String(value.version)}'`); + } + if (typeof value.type !== "string") { + throw new ProtocolError("protocol message type must be a string"); + } + return value as ProtocolMessage; +} + +export class FrameDecoder { + readonly #limits: DecodeLimits; + #buffer = Buffer.alloc(0); + #expected: number | undefined; + + constructor(limits: DecodeLimits = DEFAULT_DECODE_LIMITS) { + this.#limits = limits; + } + + push(chunk: Uint8Array): ProtocolMessage[] { + if (chunk.byteLength === 0) { + return []; + } + this.#buffer = this.#buffer.length === 0 + ? Buffer.from(chunk) + : Buffer.concat([this.#buffer, chunk]); + const messages: ProtocolMessage[] = []; + while (true) { + if (this.#expected === undefined) { + if (this.#buffer.length < 4) { + break; + } + this.#expected = this.#buffer.readUInt32BE(0); + this.#buffer = this.#buffer.subarray(4); + if (this.#expected === 0) { + throw new ProtocolError("empty frames are not allowed"); + } + if (this.#expected > this.#limits.maxFrameBytes) { + throw new ProtocolError( + `frame length ${this.#expected} exceeds limit ${this.#limits.maxFrameBytes}` + ); + } + } + if (this.#buffer.length < this.#expected) { + break; + } + const body = this.#buffer.subarray(0, this.#expected); + this.#buffer = this.#buffer.subarray(this.#expected); + this.#expected = undefined; + messages.push(decodePayload(body, this.#limits)); + } + return messages; + } + + end(): void { + if (this.#expected !== undefined || this.#buffer.length !== 0) { + throw new ProtocolError("truncated protocol frame"); + } + } +} + +export function assertExactFields( + value: JsonObject, + required: readonly string[], + optional: readonly string[] = [] +): void { + const allowed = new Set([...required, ...optional]); + for (const key of Object.keys(value)) { + if (!allowed.has(key)) { + throw new ProtocolError(`unknown field '${key}' in ${String(value.type ?? "message")}`); + } + } + for (const key of required) { + if (!Object.hasOwn(value, key)) { + throw new ProtocolError(`missing field '${key}' in ${String(value.type ?? "message")}`); + } + } +} + +export function protocolMessage(type: string, fields: JsonObject = {}): JsonObject { + return { version: PROTOCOL_VERSION, type, ...fields }; +} + +export class ProtocolError extends Error { + constructor(message: string) { + super(message); + this.name = "ProtocolError"; + } +} + +function canonicalize(value: unknown, limits: DecodeLimits): Json { + let nodes = 0; + let keys = 0; + const visit = (item: unknown, depth: number): Json => { + nodes += 1; + if (nodes > limits.maxNodes) { + throw new ProtocolError(`decoded value exceeds node limit ${limits.maxNodes}`); + } + if (depth > limits.maxDepth) { + throw new ProtocolError(`decoded value exceeds depth limit ${limits.maxDepth}`); + } + if (item === null || typeof item === "boolean") { + return item; + } + if (typeof item === "number") { + if (!Number.isFinite(item)) { + throw new ProtocolError("non-finite numbers are not allowed"); + } + return item; + } + if (typeof item === "string") { + if (Buffer.byteLength(item, "utf8") > limits.maxStringBytes) { + throw new ProtocolError(`string exceeds limit ${limits.maxStringBytes}`); + } + return item; + } + if (Array.isArray(item)) { + if (item.length > limits.maxArrayLength) { + throw new ProtocolError(`array exceeds length limit ${limits.maxArrayLength}`); + } + return item.map(entry => visit(entry, depth + 1)); + } + if (!item || typeof item !== "object") { + throw new ProtocolError(`unsupported JSON value '${typeof item}'`); + } + const entries = Object.entries(item); + keys += entries.length; + if (keys > limits.maxObjectKeys) { + throw new ProtocolError(`decoded value exceeds object-key limit ${limits.maxObjectKeys}`); + } + const output = Object.create(null) as JsonObject; + for (const [key, child] of entries) { + if (DANGEROUS_KEYS.has(key)) { + throw new ProtocolError(`dangerous key '${key}' is not allowed`); + } + if (TYPE_TAG_KEYS.has(key)) { + throw new ProtocolError(`unsupported type tag '${key}'`); + } + if (Buffer.byteLength(key, "utf8") > limits.maxStringBytes) { + throw new ProtocolError(`object key exceeds limit ${limits.maxStringBytes}`); + } + output[key] = visit(child, depth + 1); + } + return output; + }; + return visit(value, 0); +} + +function isRecord(value: Json): value is JsonObject { + return value !== null && typeof value === "object" && !Array.isArray(value); +} diff --git a/src/oci-javascript-mcp-server/src/runner.ts b/src/oci-javascript-mcp-server/src/runner.ts new file mode 100755 index 00000000..d9bd31ca --- /dev/null +++ b/src/oci-javascript-mcp-server/src/runner.ts @@ -0,0 +1,183 @@ +#!/usr/bin/env -S node --experimental-strip-types +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import vm from "node:vm"; +import { inspect } from "node:util"; +import { createOciFacade, inferFinalExpression } from "./facade.ts"; +import { + FrameDecoder, + ProtocolError, + DEFAULT_DECODE_LIMITS, + assertExactFields, + encodeFrame, + protocolMessage +} from "./protocol.ts"; +import { sanitizeJson } from "./oci.ts"; +import type { Json, JsonObject, ReflectionManifest, RpcOperation } from "./types.ts"; + +// The execute frame contains a trusted host-generated SDK manifest. Guest frames +// are decoded by the host with the tighter defaults. +const decoder = new FrameDecoder({ + ...DEFAULT_DECODE_LIMITS, + maxObjectKeys: 100_000, + maxNodes: 250_000 +}); +const pending = new Map(); +let nextRpcId = 1; +let running = false; + +send("health", { status: "ready" }); +process.stdin.on("data", chunk => { + try { + for (const message of decoder.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk)) { + void handle(message).catch(fatal); + } + } catch (error) { + fatal(error); + } +}); +process.stdin.on("end", () => { + try { decoder.end(); } catch (error) { fatal(error); return; } + rejectPending(new Error("broker channel closed")); + process.exitCode = 1; +}); +process.stdin.resume(); + +async function handle(message: JsonObject): Promise { + if (message.type === "execute") { + assertExactFields(message, [ + "version", "type", "code", "manifest", "timeoutMs", "maxResultBytes", "maxOutputBytes" + ]); + if (running) throw new ProtocolError("runner accepts exactly one execution"); + if (typeof message.code !== "string" || !isObject(message.manifest) + || !Number.isInteger(message.timeoutMs) || !Number.isInteger(message.maxResultBytes) + || !Number.isInteger(message.maxOutputBytes)) { + throw new ProtocolError("invalid execute message"); + } + running = true; + await execute( + message.code, + message.manifest as unknown as ReflectionManifest, + message.timeoutMs as number, + message.maxResultBytes as number, + message.maxOutputBytes as number + ); + return; + } + if (message.type === "rpc_result") { + assertExactFields(message, ["version", "type", "id", "ok"], ["value", "error"]); + if (!Number.isInteger(message.id) || typeof message.ok !== "boolean") { + throw new ProtocolError("invalid rpc_result message"); + } + const waiter = pending.get(message.id as number); + if (!waiter) throw new ProtocolError("unknown RPC response id"); + pending.delete(message.id as number); + if (message.ok) waiter.resolve(message.value ?? null); + else waiter.reject(new Error(errorMessage(message.error))); + return; + } + if (message.type === "cancel") { + assertExactFields(message, ["version", "type"], ["reason"]); + rejectPending(new Error(typeof message.reason === "string" ? message.reason : "execution cancelled")); + process.exit(124); + } + throw new ProtocolError(`unsupported host message type '${String(message.type)}'`); +} + +async function execute( + code: string, + manifest: ReflectionManifest, + timeoutMs: number, + maxResultBytes: number, + maxOutputBytes: number +): Promise { + let stdout = ""; + let stderr = ""; + const log = (stream: "stdout" | "stderr", values: unknown[]) => { + const text = `${values.map(value => typeof value === "string" ? value : inspect(value, { depth: 4 })).join(" ")}\n`; + const current = stream === "stdout" ? stdout : stderr; + const remaining = Math.max(0, maxOutputBytes - Buffer.byteLength(current, "utf8")); + const bounded = Buffer.from(text, "utf8").subarray(0, remaining).toString("utf8"); + if (stream === "stdout") stdout += bounded; + else stderr += bounded; + if (bounded) send("log", { stream, text: bounded }); + }; + const facade = createOciFacade(manifest, rpc); + const sandbox = Object.create(null) as Record; + Object.defineProperties(sandbox, { + oci: { value: facade, enumerable: true, writable: false, configurable: false }, + console: { + value: Object.freeze({ log: (...values: unknown[]) => log("stdout", values), error: (...values: unknown[]) => log("stderr", values), warn: (...values: unknown[]) => log("stderr", values) }), + enumerable: true, writable: false, configurable: false + } + }); + const context = vm.createContext(sandbox, { + name: "oci-javascript-runner-context", + codeGeneration: { strings: false, wasm: false } + }); + try { + const wrapped = `"use strict"; (async () => {\n${inferFinalExpression(code)}\n})()`; + const script = new vm.Script(wrapped, { filename: "agent-code.js" }); + const promise = script.runInContext(context, { timeout: Math.max(1, timeoutMs) }); + const result = sanitizeJson(await promise); + const bytes = Buffer.byteLength(JSON.stringify(result), "utf8"); + if (bytes > maxResultBytes) throw new Error(`result exceeds ${maxResultBytes} bytes`); + sendAndExit("result", { result, error: null, exitCode: 0, timedOut: false }, 0); + } catch (error) { + sendAndExit("result", { + result: null, + error: safeError(error), + exitCode: 1, + timedOut: /timed out|deadline/i.test(errorMessage(error)) + }, 1); + } +} + +function rpc(operation: RpcOperation, payload: JsonObject): Promise { + const id = nextRpcId++; + return new Promise((resolve, reject) => { + pending.set(id, { resolve, reject }); + send("rpc", { id, operation, payload }); + }); +} + +function send(type: string, fields: JsonObject): void { + process.stdout.write(encodeFrame(protocolMessage(type, fields))); +} + +function sendAndExit(type: string, fields: JsonObject, exitCode: number): void { + process.stdout.write(encodeFrame(protocolMessage(type, fields)), () => process.exit(exitCode)); +} + +function fatal(error: unknown): void { + try { send("protocol_error", { error: safeError(error) }); } catch {} + rejectPending(new Error("protocol failure")); + process.exit(70); +} + +function rejectPending(error: Error): void { + for (const waiter of pending.values()) waiter.reject(error); + pending.clear(); +} + +function safeError(error: unknown): JsonObject { + return { + message: errorMessage(error), + name: error instanceof Error ? error.name : "Error" + }; +} + +function errorMessage(error: unknown): string { + if (error && typeof error === "object" && typeof (error as { message?: unknown }).message === "string") { + return (error as { message: string }).message; + } + return String(error); +} + +function isObject(value: unknown): value is JsonObject { + return !!value && typeof value === "object" && !Array.isArray(value); +} diff --git a/src/oci-javascript-mcp-server/src/server.ts b/src/oci-javascript-mcp-server/src/server.ts new file mode 100755 index 00000000..3ac3308b --- /dev/null +++ b/src/oci-javascript-mcp-server/src/server.ts @@ -0,0 +1,152 @@ +#!/usr/bin/env -S node --experimental-strip-types +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import { pathToFileURL } from "node:url"; +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import { z } from "zod"; +import { runJavaScript } from "./execution.ts"; +import { OciSdkRuntime } from "./oci.ts"; +import { admitProvider } from "./isolation/admission.ts"; +import { AppleContainerIsolationProvider } from "./isolation/apple-container.ts"; +import { ProcessIsolationProvider } from "./isolation/process.ts"; +import type { IsolationProvider, JsonObject } from "./types.ts"; + +const VERSION = "0.1.0"; + +export type ServerDependencies = { + provider: IsolationProvider; + runtime: OciSdkRuntime; + mode: "development" | "production"; +}; + +export function createMcpServer(dependencies: ServerDependencies): McpServer { + admitProvider(dependencies.provider, dependencies.mode); + const server = new McpServer({ + name: "oci-javascript-mcp-server", + version: VERSION + }, { + instructions: ( + "Run complete JavaScript programs using the injected OCI SDK-compatible `oci` facade. " + + "Leave the desired value as the final expression. OCI credentials and clients stay in " + + "the trusted host broker. Use discover_oci only when the SDK shape is unclear." + ) + }); + + server.registerTool("run_javascript", { + description: ( + "Run one complete JavaScript program in a fresh execution environment. The program receives " + + "an injected `oci` facade, and its final expression becomes result. stdout and stderr are captured." + ), + inputSchema: { + code: z.string().describe("JavaScript source. Leave the desired value as the final expression."), + timeout: z.number().min(1).max(120).default(30) + .describe("Maximum wall-clock execution duration in seconds (1-120).") + }, + annotations: { openWorldHint: true, readOnlyHint: false } + }, async (args, extra) => { + try { + const result = await runJavaScript(args.code, { + timeoutSeconds: args.timeout, + provider: dependencies.provider, + runtime: dependencies.runtime, + mode: dependencies.mode, + signal: extra.signal + }); + return jsonToolResult({ + result: result.result, + error: result.error, + stdout: result.stdout, + stderr: result.stderr, + exit_code: result.exitCode, + timed_out: result.timedOut + }); + } catch (error) { + return jsonToolResult({ + result: null, + error: { message: publicExecutionError(error) }, + stdout: "", + stderr: "", + exit_code: 1, + timed_out: false + }); + } + }); + + server.registerTool("discover_oci", { + description: ( + "Inspect installed OCI SDK services, clients, API operations, request fields, and response " + + "information without running untrusted JavaScript." + ), + inputSchema: { + service: z.string().optional().describe("OCI SDK service export, such as core or identity."), + client: z.string().optional().describe("OCI SDK client class, such as ComputeClient."), + operation: z.string().optional().describe("OCI SDK operation, such as listInstances.") + }, + annotations: { openWorldHint: false, readOnlyHint: true } + }, async args => { + try { + return jsonToolResult(dependencies.runtime.discover(args)); + } catch (error) { + return jsonToolResult({ error: { message: publicDiscoveryError(error) } }); + } + }); + + return server; +} + +export function dependenciesFromEnvironment(): ServerDependencies { + const mode = process.env.OCI_JAVASCRIPT_MODE === "development" ? "development" : "production"; + const providerName = process.env.OCI_JAVASCRIPT_ISOLATION_PROVIDER ?? "process"; + let provider: IsolationProvider; + if (providerName === "process") { + provider = new ProcessIsolationProvider({ + allowInsecure: process.env.OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS === "1" + }); + } else if (providerName === "apple-container") { + provider = new AppleContainerIsolationProvider({ + cliPath: process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_CLI, + image: process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_IMAGE, + network: process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_NETWORK + }); + } else { + throw new Error(`isolation provider '${providerName}' is not implemented`); + } + admitProvider(provider, mode); + return { provider, runtime: new OciSdkRuntime(), mode }; +} + +export async function main(): Promise { + const server = createMcpServer(dependenciesFromEnvironment()); + await server.connect(new StdioServerTransport()); +} + +function jsonToolResult(result: JsonObject): CallToolResult { + return { + content: [{ type: "text", text: JSON.stringify(result, null, 2) }], + structuredContent: result + }; +} + +function publicExecutionError(error: unknown): string { + const message = error instanceof Error ? error.message : String(error); + return /code exceeds|timeout must|not admitted|requires OCI_JAVASCRIPT/i.test(message) + ? message + : "JavaScript execution could not be started"; +} + +function publicDiscoveryError(error: unknown): string { + const message = error instanceof Error ? error.message : String(error); + return /Unknown OCI SDK|Invalid OCI|Unsupported discovery/i.test(message) + ? message + : "OCI discovery failed"; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + await main(); +} diff --git a/src/oci-javascript-mcp-server/src/types.ts b/src/oci-javascript-mcp-server/src/types.ts new file mode 100644 index 00000000..fad35c40 --- /dev/null +++ b/src/oci-javascript-mcp-server/src/types.ts @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +export type Json = null | boolean | number | string | Json[] | JsonObject; +export type JsonObject = { [key: string]: Json }; + +export type ExecutionError = JsonObject & { message: string }; + +export type ExecutionResult = { + result: Json; + error: ExecutionError | null; + stdout: string; + stderr: string; + exitCode: number; + timedOut: boolean; +}; + +export type ClientOptions = { region?: string }; + +export type OciInvokePayload = { + service: string; + client: { name: string; options?: ClientOptions }; + operation: string; + request?: JsonObject; +}; + +export type OciDiscoverFilter = { + service?: string; + client?: string; + operation?: string; +}; + +export type ReflectionManifest = { + services: Record; + }>; + }>; +}; + +export type RpcOperation = "config" | "invoke"; + +export type GuestRpcRequest = { + operation: RpcOperation; + payload: JsonObject; +}; + +export type ProviderCapabilities = Readonly<{ + provider: string; + boundary: "process" | "container" | "virtual-machine"; + developmentOnly: boolean; + separateGuestKernel: boolean; + hardwareVirtualization: boolean; + networkCreationBlocked: boolean; +}>; + +export type ExecutionPolicy = Readonly<{ + allowedOperations: ReadonlySet; + allowMutations: boolean; + allowedRegions?: ReadonlySet; + allowedTenancyIds?: ReadonlySet; + allowedCompartmentIds?: ReadonlySet; + allowedResourceIds?: ReadonlySet; + allowedRequestFields?: ReadonlyMap>; + maxCalls: number; + maxConcurrentCalls: number; + maxRequestBytes: number; + maxResponseBytes: number; + deadlineMs: number; + maxRetries: number; +}>; + +export type BrokerHandler = (request: GuestRpcRequest) => Promise; + +export type IsolationExecution = { + result: Promise; + destroy(): Promise; +}; + +export interface IsolationProvider { + readonly capabilities: ProviderCapabilities; + start(input: { + code: string; + manifest: ReflectionManifest; + deadlineMs: number; + maxResultBytes: number; + maxOutputBytes: number; + broker: BrokerHandler; + signal?: AbortSignal; + }): Promise; +} diff --git a/src/oci-javascript-mcp-server/test/execution.test.ts b/src/oci-javascript-mcp-server/test/execution.test.ts new file mode 100644 index 00000000..2d5d12de --- /dev/null +++ b/src/oci-javascript-mcp-server/test/execution.test.ts @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { fileURLToPath } from "node:url"; +import { runJavaScript } from "../src/execution.ts"; +import { OciSdkRuntime } from "../src/oci.ts"; +import { admitProvider } from "../src/isolation/admission.ts"; +import { AppleContainerIsolationProvider } from "../src/isolation/apple-container.ts"; +import { ProcessIsolationProvider } from "../src/isolation/process.ts"; +import type { OciInvokePayload, ReflectionManifest } from "../src/types.ts"; + +const manifest: ReflectionManifest = { + services: { + identity: { + clients: { + IdentityClient: { + operations: ["listRegionSubscriptions"], + requestFields: { listRegionSubscriptions: ["tenancyId", "limit"] } + } + } + }, + core: { + clients: { + ComputeClient: { + operations: ["listInstances", "terminateInstance"], + requestFields: { + listInstances: ["compartmentId", "limit"], + terminateInstance: ["instanceId"] + } + } + } + } + } +}; + +function mockRuntime(): OciSdkRuntime { + const instance = new OciSdkRuntime(() => ({ sdk: {}, common: {} }), () => ({})); + Object.defineProperties(instance, { + manifest: { value: () => manifest }, + config: { value: () => ({ tenancyId: "tenancy", region: "us-phoenix-1" }) }, + invoke: { + value: async (payload: OciInvokePayload) => ({ + service: payload.service, + client: payload.client.name, + operation: payload.operation, + region: payload.client.options?.region ?? null, + request: payload.request ?? {} + }) + } + }); + return instance; +} + +function provider(): ProcessIsolationProvider { + return new ProcessIsolationProvider({ allowInsecure: true }); +} + +async function run(code: string, timeoutSeconds = 3) { + return runJavaScript(code, { + provider: provider(), + runtime: mockRuntime(), + mode: "development", + timeoutSeconds + }); +} + +test("executes final expressions and captures stdout and stderr", async () => { + const result = await run('console.log("hello", 7); console.error("oops"); 20 + 22'); + assert.equal(result.result, 42); + assert.equal(result.stdout, "hello 7\n"); + assert.equal(result.stderr, "oops\n"); + assert.equal(result.exitCode, 0); + assert.equal(result.error, null); +}); + +test("supports oci.config, static calls, constructed clients, and shallow reflection", async () => { + const result = await run(` + const config = await oci.config(); + const direct = await oci.identity.IdentityClient.listRegionSubscriptions({tenancyId: config.tenancyId}); + const compute = new oci.core.ComputeClient({region: "us-ashburn-1"}); + const instances = await compute.listInstances({compartmentId: "c1", limit: 2}); + ({ + config, + direct, + instances, + services: Object.keys(oci), + identityClients: Object.keys(oci.identity), + computeOperations: Object.keys(compute) + }) + `); + assert.equal((result.result as any).config.tenancyId, "tenancy"); + assert.equal((result.result as any).direct.operation, "listRegionSubscriptions"); + assert.equal((result.result as any).instances.region, "us-ashburn-1"); + assert.ok((result.result as any).services.includes("config")); + assert.ok((result.result as any).services.includes("core")); + assert.deepEqual((result.result as any).identityClients, ["IdentityClient"]); + assert.ok((result.result as any).computeOperations.includes("listInstances")); +}); + +test("does not expose Node globals or arbitrary client endpoints", async () => { + const globals = await run("({process: typeof process, require: typeof require, fetch: typeof fetch})"); + assert.deepEqual(JSON.parse(JSON.stringify(globals.result)), { + process: "undefined", require: "undefined", fetch: "undefined" + }); + const endpoint = await run('new oci.core.ComputeClient({endpoint: "https://evil.example"})'); + assert.match(endpoint.error?.message ?? "", /only support region/); +}); + +test("returns structured JavaScript errors", async () => { + const result = await run('throw new Error("boom")'); + assert.equal(result.result, null); + assert.equal(result.exitCode, 1); + assert.equal(result.timedOut, false); + assert.match(result.error?.message ?? "", /boom/); +}); + +test("bounds captured output", async () => { + const result = await run('console.log("x".repeat(1100000)); "done"'); + assert.equal(result.result, "done"); + assert.ok(Buffer.byteLength(result.stdout, "utf8") <= 1024 * 1024); +}); + +test("times out and tears down a pending runner", async () => { + const result = await run("await new Promise(() => {})", 1); + assert.equal(result.timedOut, true); + assert.equal(result.exitCode, -1); + assert.match(result.error?.message ?? "", /timed out/); +}); + +test("AbortSignal cancels and tears down the runner", async () => { + const controller = new AbortController(); + const promise = runJavaScript("await new Promise(() => {})", { + provider: provider(), runtime: mockRuntime(), mode: "development", + timeoutSeconds: 10, signal: controller.signal + }); + setTimeout(() => controller.abort(), 50); + const result = await promise; + assert.match(result.error?.message ?? "", /cancelled/); + assert.equal(result.timedOut, false); +}); + +test("direct raw-channel mutation is denied after runner compromise", async () => { + const rawRunner = fileURLToPath(new URL("./raw-runner.ts", import.meta.url)); + const result = await runJavaScript("0", { + provider: new ProcessIsolationProvider({ allowInsecure: true, runnerPath: rawRunner }), + runtime: mockRuntime(), + mode: "development", + timeoutSeconds: 3 + }); + assert.match((result.result as any).message, /read-only/); +}); + +test("local provider requires opt-in and is rejected in production", () => { + assert.throws(() => new ProcessIsolationProvider({ allowInsecure: false }), /requires/); + assert.throws(() => admitProvider(provider(), "production"), /not admitted in production/); + assert.doesNotThrow(() => admitProvider(provider(), "development")); + assert.doesNotThrow(() => admitProvider({ + capabilities: { + provider: "test-vm", + boundary: "virtual-machine", + developmentOnly: false, + separateGuestKernel: true, + hardwareVirtualization: true, + networkCreationBlocked: true + }, + async start() { throw new Error("not used"); } + }, "production")); +}); + +test("Apple container provider runs over pipes with hardened development capabilities", async () => { + const fakeCli = fileURLToPath(new URL("./fake-apple-container.ts", import.meta.url)); + const appleProvider = new AppleContainerIsolationProvider({ + cliPath: fakeCli, + image: "test-runner:dev", + network: "test-internal" + }); + const result = await runJavaScript("20 + 22", { + provider: appleProvider, + runtime: mockRuntime(), + mode: "development", + timeoutSeconds: 3 + }); + assert.equal(result.result, 42); + assert.deepEqual(appleProvider.capabilities, { + provider: "apple-container", + boundary: "virtual-machine", + developmentOnly: true, + separateGuestKernel: true, + hardwareVirtualization: true, + networkCreationBlocked: false + }); + assert.throws(() => admitProvider(appleProvider, "production"), /not admitted in production/); +}); + +test("Apple container provider rejects unsafe CLI-controlled values", () => { + assert.throws( + () => new AppleContainerIsolationProvider({ image: "--volume=/Users" }), + /image is invalid/ + ); + assert.throws( + () => new AppleContainerIsolationProvider({ network: "bad network" }), + /network is invalid/ + ); + assert.throws( + () => new AppleContainerIsolationProvider({ cliPath: "" }), + /CLI path is invalid/ + ); +}); diff --git a/src/oci-javascript-mcp-server/test/facade.test.ts b/src/oci-javascript-mcp-server/test/facade.test.ts new file mode 100644 index 00000000..d7550edf --- /dev/null +++ b/src/oci-javascript-mcp-server/test/facade.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { createOciFacade, inferFinalExpression } from "../src/facade.ts"; +import type { Json, JsonObject, ReflectionManifest } from "../src/types.ts"; + +const manifest: ReflectionManifest = { + services: { + core: { + clients: { + ComputeClient: { + operations: ["listInstances"], + requestFields: { listInstances: ["compartmentId"] } + } + } + } + } +}; + +test("facade exposes reflective static and constructed OCI calls", async () => { + const calls: Array<{ operation: string; payload: JsonObject }> = []; + const facade = createOciFacade(manifest, async (operation, payload): Promise => { + calls.push({ operation, payload }); + if (operation === "config") return { tenancyId: "t1" }; + return { items: [] }; + }) as any; + assert.deepEqual(Object.keys(facade), ["config", "core"]); + assert.deepEqual(Object.keys(facade.core), ["ComputeClient"]); + assert.deepEqual(Object.keys(new facade.core.ComputeClient()), ["listInstances"]); + assert.equal((await facade.config()).tenancyId, "t1"); + await facade.core.ComputeClient.listInstances({ compartmentId: "c1" }); + await new facade.core.ComputeClient({ region: "us-ashburn-1" }).listInstances({ compartmentId: "c2" }); + assert.equal(calls[1]?.payload.operation, "listInstances"); + assert.equal((calls[2]?.payload.client as any).options.region, "us-ashburn-1"); + assert.equal(facade.unknown, undefined); + assert.equal(facade.core.UnknownClient.then, undefined); +}); + +test("facade rejects invalid names and options", () => { + const facade = createOciFacade(manifest, async () => null) as any; + assert.throws(() => new facade.core.ComputeClient({ endpoint: "https://evil.example" }), /only support region/); + assert.throws(() => new facade.core.ComputeClient({ region: "not-a-region" }), /Invalid/); + assert.throws(() => facade.core["bad-name"], /Invalid OCI client/); +}); + +test("final-expression inference handles expressions, statements, strings, and comments", () => { + assert.match(inferFinalExpression("const x = 1;\nx + 2;"), /return \(x \+ 2\)/); + assert.match(inferFinalExpression("({ value: ';' })"), /return \(\(\{ value/); + assert.match(inferFinalExpression("const x = 1; // comment\nx"), /return \(x\)/); + assert.equal(inferFinalExpression("throw new Error('x')"), "throw new Error('x')"); +}); diff --git a/src/oci-javascript-mcp-server/test/fake-apple-container.ts b/src/oci-javascript-mcp-server/test/fake-apple-container.ts new file mode 100755 index 00000000..614bb8f7 --- /dev/null +++ b/src/oci-javascript-mcp-server/test/fake-apple-container.ts @@ -0,0 +1,25 @@ +#!/usr/bin/env -S node --experimental-strip-types +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import assert from "node:assert/strict"; + +const [command, ...args] = process.argv.slice(2); +if (command === "run") { + const nameIndex = args.indexOf("--name"); + assert.match(args[nameIndex + 1] ?? "", /^oci-javascript-[0-9a-f-]{36}$/); + for (const expected of [ + "--rm", "--interactive", "--name", "--cpus", "1", "--memory", "512M", + "--read-only", "--cap-drop", "ALL", "--no-dns", + "--network", "test-internal", "--user", "65532:65532", "--ulimit", "nofile=64:64", + "test-runner:dev" + ]) { + assert.ok(args.includes(expected), `missing hardened run argument: ${expected}`); + } + await import("../src/runner.ts"); +} else if (command !== "delete") { + throw new Error(`unexpected fake container command: ${String(command)}`); +} diff --git a/src/oci-javascript-mcp-server/test/oci-policy.test.ts b/src/oci-javascript-mcp-server/test/oci-policy.test.ts new file mode 100644 index 00000000..0023a93e --- /dev/null +++ b/src/oci-javascript-mcp-server/test/oci-policy.test.ts @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { OciSdkRuntime, sanitizeJson } from "../src/oci.ts"; +import { HostExecutionBroker, canonicalInvoke, developmentPolicy, productionPolicy } from "../src/policy.ts"; +import type { ReflectionManifest } from "../src/types.ts"; + +const manifest: ReflectionManifest = { + services: { + core: { + clients: { + ComputeClient: { + operations: ["listInstances", "terminateInstance"], + requestFields: { + listInstances: ["compartmentId", "limit"], + terminateInstance: ["instanceId"] + } + } + } + } + } +}; + +function runtime() { + class ComputeClient { + static lastOptions: unknown; + constructor(options: unknown) { ComputeClient.lastOptions = options; } + async listInstances(request: unknown) { return { items: [request], httpResponse: { headers: {}, status: 200 } }; } + async terminateInstance() { return {}; } + close() {} + } + Object.assign(ComputeClient.prototype, { listInstances: ComputeClient.prototype.listInstances }); + const sdk = { core: { ComputeClient } }; + const provider = { + region: "us-phoenix-1", + getTenantId: () => "ocid1.tenancy.oc1..test", + getUserId: () => "ocid1.user.oc1..test", + getRegion: () => ({ regionId: "us-phoenix-1" }), + setRegion(value: string) { this.region = value; } + }; + return new OciSdkRuntime(() => ({ sdk, common: {} }), () => provider); +} + +test("discovers installed SDK services and operation request details", () => { + const real = new OciSdkRuntime(); + const index = real.discover({}); + assert.ok((index.services as string[]).includes("identity")); + const client = real.discover({ service: "identity", client: "IdentityClient" }); + assert.ok((client.operations as string[]).includes("listRegionSubscriptions")); + const operation = real.discover({ + service: "identity", + client: "IdentityClient", + operation: "listRegionSubscriptions" + }); + assert.equal(operation.requestType, "ListRegionSubscriptionsRequest"); + assert.ok((operation.requestFields as Array<{ name: string }>).some(field => field.name === "tenancyId")); +}); + +test("config exposes identity metadata without credentials", () => { + assert.deepEqual(JSON.parse(JSON.stringify(runtime().config())), { + tenancyId: "ocid1.tenancy.oc1..test", + userId: "ocid1.user.oc1..test", + region: "us-phoenix-1", + principal: { type: "user", id: "ocid1.user.oc1..test" } + }); +}); + +test("runtime invocation pins user agent, region, deadlines, retries, and client teardown", async () => { + const observations: Record = {}; + class CircuitBreaker { constructor(options: unknown) { observations.circuitBreaker = options; } } + class MaxAttemptsTerminationStrategy { + constructor(attempts: number) { observations.attempts = attempts; } + } + class ComputeClient { + constructor(options: unknown, configuration: unknown) { + observations.options = options; + observations.configuration = configuration; + } + async listInstances(request: unknown) { + observations.request = request; + return { items: [], authenticationDetailsProvider: "remove", httpResponse: { headers: {}, status: 200 } }; + } + close() { observations.closed = true; } + } + const provider = { setRegion: (region: string) => { observations.region = region; } }; + const sdk = new OciSdkRuntime(() => ({ + sdk: { core: { ComputeClient } }, + common: { + CircuitBreaker, + NoRetryConfigurationDetails: { retry: false }, + OciSdkDefaultRetryConfiguration: { retryCondition: () => true }, + MaxAttemptsTerminationStrategy + } + }), () => provider); + const value = await sdk.invoke({ + service: "core", + client: { name: "ComputeClient", options: { region: "us-ashburn-1" } }, + operation: "listInstances", + request: { compartmentId: "c1" } + }, 500, 2); + assert.equal(observations.region, "us-ashburn-1"); + assert.equal(observations.options.additionalUserAgent, "oci-javascript-mcp/0.1.0"); + assert.equal(observations.attempts, 3); + assert.equal(observations.closed, true); + assert.deepEqual(JSON.parse(JSON.stringify(value)), { items: [] }); + + await assert.rejects(() => sdk.invoke({ + service: "missing", client: { name: "NoClient" }, operation: "getThing", request: {} + }, 10), /unavailable/); +}); + +test("discovery and client option validation fail closed", () => { + const sdk = new OciSdkRuntime(); + assert.throws(() => sdk.discover({ service: "missing" }), /Unknown OCI SDK service/); + assert.throws(() => sdk.discover({ service: "bad-name" }), /Invalid OCI service/); + assert.throws(() => sdk.discover({ unexpected: "claim" } as any), /Unsupported discovery/); +}); + +test("canonical request validation is allowlisted and read-only", () => { + const policy = developmentPolicy(manifest, Date.now() + 10_000); + const valid = canonicalInvoke({ + service: "core", + client: { name: "ComputeClient", options: { region: "us-ashburn-1" } }, + operation: "listInstances", + request: { compartmentId: "ocid1.compartment.oc1..test", limit: 5 } + }, manifest, policy); + assert.equal(valid.request?.limit, 5); + assert.equal(Object.getPrototypeOf(valid.request), null); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient" }, operation: "listInstances", + request: { endpoint: "https://evil.example" } + }, manifest, policy), /not authorized/); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient", options: { endpoint: "evil" } }, + operation: "listInstances", request: {} + }, manifest, policy), /only support|Unsupported/); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient" }, operation: "terminateInstance", + request: { instanceId: "ocid1.instance.oc1..test" } + }, manifest, policy), /read-only/); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient" }, operation: "listInstances", + request: { executionId: "another" } + }, manifest, policy), /identity or policy claim/); +}); + +test("policy enforces region, tenancy, compartment, resource, and operation scopes", () => { + const base = developmentPolicy(manifest, Date.now() + 10_000, { + allowMutations: true, + allowedRegions: new Set(["us-phoenix-1"]), + allowedTenancyIds: new Set(["t1"]), + allowedCompartmentIds: new Set(["c1"]), + allowedResourceIds: new Set(["i1"]) + }); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient", options: { region: "us-ashburn-1" } }, + operation: "listInstances", request: { compartmentId: "c1" } + }, manifest, base), /region/); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient" }, operation: "listInstances", + request: { compartmentId: "c2" } + }, manifest, base), /compartment/); + assert.throws(() => canonicalInvoke({ + service: "core", client: { name: "ComputeClient" }, operation: "terminateInstance", + request: { instanceId: "i2" } + }, manifest, base), /resource/); + assert.equal(productionPolicy(Date.now() + 1000).allowedOperations.size, 0); +}); + +test("broker enforces call, concurrency, request, response, deadline, and cancellation budgets", async () => { + const sdk = runtime(); + Object.defineProperty(sdk, "manifest", { value: () => manifest }); + const oneCall = developmentPolicy(manifest, Date.now() + 10_000, { maxCalls: 1 }); + const broker = new HostExecutionBroker(sdk, oneCall); + const request = { + operation: "invoke" as const, + payload: { + service: "core", client: { name: "ComputeClient" }, operation: "listInstances", + request: { compartmentId: "c1" } + } + }; + await broker.handle(request); + await assert.rejects(() => broker.handle(request), /call limit/); + const cancelled = new HostExecutionBroker(sdk, developmentPolicy(manifest, Date.now() + 10_000)); + cancelled.cancel(); + await assert.rejects(() => cancelled.handle(request), /cancelled/); + const expired = new HostExecutionBroker(sdk, developmentPolicy(manifest, Date.now() - 1)); + await assert.rejects(() => expired.handle(request), /deadline/); + const tiny = new HostExecutionBroker(sdk, developmentPolicy(manifest, Date.now() + 10_000, { maxRequestBytes: 2 })); + await assert.rejects(() => tiny.handle(request), /request exceeds/); + + const largeResponseRuntime = runtime(); + Object.defineProperties(largeResponseRuntime, { + manifest: { value: () => manifest }, + invoke: { value: async () => ({ value: "x".repeat(100) }) } + }); + const responseLimited = new HostExecutionBroker( + largeResponseRuntime, + developmentPolicy(manifest, Date.now() + 10_000, { maxResponseBytes: 10 }) + ); + await assert.rejects(() => responseLimited.handle(request), /response exceeds/); + + let release!: () => void; + const blockedRuntime = runtime(); + Object.defineProperties(blockedRuntime, { + manifest: { value: () => manifest }, + invoke: { value: () => new Promise(resolve => { release = () => resolve({}); }) } + }); + const concurrent = new HostExecutionBroker( + blockedRuntime, + developmentPolicy(manifest, Date.now() + 10_000, { maxConcurrentCalls: 1 }) + ); + const first = concurrent.handle(request); + await new Promise(resolve => setImmediate(resolve)); + await assert.rejects(() => concurrent.handle(request), /concurrency limit/); + release(); + await first; +}); + +test("response sanitizer removes credentials, transports, cycles, and unsupported values", () => { + const value: Record = { + ok: true, + privateKey: "secret", + response: { headers: {}, status: 200 }, + date: new Date("2026-01-01T00:00:00.000Z"), + bytes: new Uint8Array([1, 2]) + }; + value.self = value; + assert.deepEqual(JSON.parse(JSON.stringify(sanitizeJson(value))), { + ok: true, + date: "2026-01-01T00:00:00.000Z", + bytes: "AQI=", + self: "[Circular]" + }); + assert.equal(sanitizeJson(12n), "12"); + assert.equal(sanitizeJson(Number.POSITIVE_INFINITY), "Infinity"); + assert.equal(sanitizeJson(undefined), "undefined"); + assert.equal((sanitizeJson({ nested: { value: 1 } }, 0) as any).nested, "[MaxDepth]"); +}); diff --git a/src/oci-javascript-mcp-server/test/protocol.test.ts b/src/oci-javascript-mcp-server/test/protocol.test.ts new file mode 100644 index 00000000..ce5e35b7 --- /dev/null +++ b/src/oci-javascript-mcp-server/test/protocol.test.ts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { + DEFAULT_DECODE_LIMITS, + FrameDecoder, + ProtocolError, + decodePayload, + encodeFrame, + protocolMessage, + assertExactFields +} from "../src/protocol.ts"; + +test("round trips split and coalesced frames", () => { + const first = encodeFrame(protocolMessage("health", { status: "ready" })); + const second = encodeFrame(protocolMessage("log", { stream: "stdout", text: "hello" })); + const decoder = new FrameDecoder(); + assert.deepEqual(decoder.push(first.subarray(0, 2)), []); + const messages = decoder.push(Buffer.concat([first.subarray(2), second])); + assert.equal(messages.length, 2); + assert.equal(messages[0]?.type, "health"); + assert.equal(messages[1]?.type, "log"); + decoder.end(); +}); + +test("rejects oversized length before receiving a body", () => { + const header = Buffer.alloc(4); + header.writeUInt32BE(DEFAULT_DECODE_LIMITS.maxFrameBytes + 1); + assert.throws(() => new FrameDecoder().push(header), /exceeds limit/); +}); + +test("rejects malformed, empty, truncated, invalid UTF-8, and unknown versions", () => { + assert.throws(() => decodePayload(Buffer.from("{")), /valid JSON/); + assert.throws(() => new FrameDecoder().push(Buffer.alloc(4)), /empty frames/); + const decoder = new FrameDecoder(); + decoder.push(Buffer.from([0, 0, 0, 2, 0x7b])); + assert.throws(() => decoder.end(), /truncated/); + assert.throws(() => decodePayload(Buffer.from([0xff])), /UTF-8/); + assert.throws( + () => decodePayload(Buffer.from('{"version":2,"type":"health"}')), + /unsupported protocol version/ + ); +}); + +test("rejects dangerous keys and type tags recursively without pollution", () => { + for (const key of ["__proto__", "prototype", "constructor"]) { + const body = Buffer.from(`{"version":1,"type":"rpc","payload":{"safe":{"${key}":{}}}}`); + assert.throws(() => decodePayload(body), new RegExp(`dangerous key '${key}'`)); + } + assert.throws( + () => decodePayload(Buffer.from('{"version":1,"type":"rpc","payload":{"$type":"Date"}}')), + /unsupported type tag/ + ); + assert.equal(({} as { polluted?: unknown }).polluted, undefined); +}); + +test("enforces structural and allocation limits", () => { + const limits = { + ...DEFAULT_DECODE_LIMITS, + maxDepth: 2, + maxStringBytes: 10, + maxArrayLength: 2, + maxObjectKeys: 5, + maxNodes: 8 + }; + assert.throws(() => decodePayload(Buffer.from('{"version":1,"type":"12345678901"}'), limits), /string/); + assert.throws(() => decodePayload(Buffer.from('{"version":1,"type":"x","a":[1,2,3]}'), limits), /array/); + assert.throws(() => decodePayload(Buffer.from('{"version":1,"type":"x","a":{"b":{"c":1}}}'), limits), /depth/); + assert.throws(() => decodePayload(Buffer.from('{"version":1,"type":"x","a":1,"b":2,"c":3,"d":4}'), limits), /object-key/); + assert.throws(() => encodeFrame({ value: "12345" }, 4), ProtocolError); +}); + +test("strict schemas reject unknown and missing fields", () => { + const message = decodePayload(Buffer.from('{"version":1,"type":"health","status":"ready","claim":"x"}')); + assert.throws( + () => assertExactFields(message, ["version", "type", "status"]), + /unknown field 'claim'/ + ); + assert.throws( + () => assertExactFields(protocolMessage("health"), ["version", "type", "status"]), + /missing field 'status'/ + ); +}); diff --git a/src/oci-javascript-mcp-server/test/raw-runner.ts b/src/oci-javascript-mcp-server/test/raw-runner.ts new file mode 100755 index 00000000..51c27e0d --- /dev/null +++ b/src/oci-javascript-mcp-server/test/raw-runner.ts @@ -0,0 +1,35 @@ +#!/usr/bin/env -S node --experimental-strip-types +/* Test fixture: emulates a compromised runner that bypasses the OCI facade. */ +import { FrameDecoder, encodeFrame, protocolMessage } from "../src/protocol.ts"; +import type { JsonObject } from "../src/types.ts"; + +const decoder = new FrameDecoder(); +send("health", { status: "ready" }); +process.stdin.on("data", chunk => { + for (const message of decoder.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk)) { + if (message.type === "execute") { + send("rpc", { + id: 7, + operation: "invoke", + payload: { + service: "core", + client: { name: "ComputeClient" }, + operation: "terminateInstance", + request: { instanceId: "ocid1.instance.oc1..blocked" } + } + }); + } else if (message.type === "rpc_result") { + send("result", { + result: message.error ?? null, + error: null, + exitCode: 0, + timedOut: false + }); + setImmediate(() => process.exit(0)); + } + } +}); + +function send(type: string, fields: JsonObject): void { + process.stdout.write(encodeFrame(protocolMessage(type, fields))); +} diff --git a/src/oci-javascript-mcp-server/test/server.test.ts b/src/oci-javascript-mcp-server/test/server.test.ts new file mode 100644 index 00000000..bf76be43 --- /dev/null +++ b/src/oci-javascript-mcp-server/test/server.test.ts @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. + * Licensed under the Universal Permissive License v1.0 as shown at + * https://oss.oracle.com/licenses/upl. + */ + +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; +import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; +import { createMcpServer, dependenciesFromEnvironment } from "../src/server.ts"; +import { OciSdkRuntime } from "../src/oci.ts"; +import type { IsolationProvider, ReflectionManifest } from "../src/types.ts"; + +test("stdio server advertises and executes both MCP tools", async () => { + const environment = Object.fromEntries( + Object.entries(process.env).filter((entry): entry is [string, string] => entry[1] !== undefined) + ); + environment.OCI_JAVASCRIPT_MODE = "development"; + environment.OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS = "1"; + const transport = new StdioClientTransport({ + command: process.execPath, + args: ["--experimental-strip-types", "src/server.ts"], + env: environment + }); + const client = new Client({ name: "oci-javascript-test", version: "1.0.0" }); + await client.connect(transport); + try { + const tools = await client.listTools(); + assert.deepEqual(tools.tools.map(tool => tool.name), ["run_javascript", "discover_oci"]); + const run = await client.callTool({ + name: "run_javascript", + arguments: { code: "40 + 2", timeout: 5 } + }); + assert.deepEqual(run.structuredContent, { + result: 42, + error: null, + stdout: "", + stderr: "", + exit_code: 0, + timed_out: false + }); + const discovery = await client.callTool({ name: "discover_oci", arguments: {} }); + assert.equal((discovery.structuredContent as { type?: unknown }).type, "index"); + } finally { + await client.close(); + } +}); + +test("in-memory MCP handlers return structured results and safe failures", async () => { + const manifest: ReflectionManifest = { services: {} }; + const runtime = new OciSdkRuntime(() => ({ sdk: {}, common: {} }), () => ({})); + Object.defineProperties(runtime, { + manifest: { value: () => manifest }, + discover: { + value: (filter: Record) => ({ type: "test", ...filter }), + writable: true + } + }); + const provider: IsolationProvider = { + capabilities: { + provider: "test", boundary: "process", developmentOnly: true, + separateGuestKernel: false, hardwareVirtualization: false, networkCreationBlocked: false + }, + async start() { + return { + result: Promise.resolve({ + result: 9, error: null, stdout: "out", stderr: "", exitCode: 0, timedOut: false + }), + async destroy() {} + }; + } + }; + const server = createMcpServer({ provider, runtime, mode: "development" }); + const client = new Client({ name: "in-memory-test", version: "1" }); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]); + try { + const run = await client.callTool({ name: "run_javascript", arguments: { code: "3 * 3" } }); + assert.equal((run.structuredContent as any).result, 9); + const discover = await client.callTool({ + name: "discover_oci", arguments: { service: "core" } + }); + assert.deepEqual(discover.structuredContent, { type: "test", service: "core" }); + + provider.start = async () => { throw new Error("private provider detail"); }; + const failedRun = await client.callTool({ + name: "run_javascript", arguments: { code: "1" } + }); + assert.equal( + (failedRun.structuredContent as any).error.message, + "JavaScript execution could not be started" + ); + (runtime as any).discover = () => { throw new Error("private discovery detail"); }; + const failedDiscovery = await client.callTool({ + name: "discover_oci", arguments: { service: "core" } + }); + assert.equal((failedDiscovery.structuredContent as any).error.message, "OCI discovery failed"); + } finally { + await client.close(); + await server.close(); + } +}); + +test("environment dependency selection requires known provider and explicit development opt-in", () => { + const saved = { + mode: process.env.OCI_JAVASCRIPT_MODE, + provider: process.env.OCI_JAVASCRIPT_ISOLATION_PROVIDER, + allow: process.env.OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS, + image: process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_IMAGE, + network: process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_NETWORK + }; + try { + process.env.OCI_JAVASCRIPT_ISOLATION_PROVIDER = "unknown"; + assert.throws(() => dependenciesFromEnvironment(), /not implemented/); + process.env.OCI_JAVASCRIPT_ISOLATION_PROVIDER = "process"; + process.env.OCI_JAVASCRIPT_MODE = "development"; + process.env.OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS = "1"; + const dependencies = dependenciesFromEnvironment(); + assert.equal(dependencies.mode, "development"); + assert.equal(dependencies.provider.capabilities.provider, "process"); + + process.env.OCI_JAVASCRIPT_ISOLATION_PROVIDER = "apple-container"; + process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_IMAGE = "custom-runner:dev"; + process.env.OCI_JAVASCRIPT_APPLE_CONTAINER_NETWORK = "custom-internal"; + const appleDependencies = dependenciesFromEnvironment(); + assert.equal(appleDependencies.provider.capabilities.provider, "apple-container"); + assert.equal(appleDependencies.provider.capabilities.boundary, "virtual-machine"); + } finally { + restoreEnvironment("OCI_JAVASCRIPT_MODE", saved.mode); + restoreEnvironment("OCI_JAVASCRIPT_ISOLATION_PROVIDER", saved.provider); + restoreEnvironment("OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS", saved.allow); + restoreEnvironment("OCI_JAVASCRIPT_APPLE_CONTAINER_IMAGE", saved.image); + restoreEnvironment("OCI_JAVASCRIPT_APPLE_CONTAINER_NETWORK", saved.network); + } +}); + +function restoreEnvironment(name: string, value: string | undefined): void { + if (value === undefined) delete process.env[name]; + else process.env[name] = value; +} + +test("server startup fails closed without development process opt-in", async () => { + const { spawn } = await import("node:child_process"); + const child = spawn(process.execPath, ["--experimental-strip-types", "src/server.ts"], { + env: { PATH: process.env.PATH ?? "" }, + stdio: ["ignore", "ignore", "pipe"] + }); + let stderr = ""; + child.stderr.on("data", chunk => { stderr += String(chunk); }); + const code = await new Promise(resolve => child.once("exit", resolve)); + assert.notEqual(code, 0); + assert.match(stderr, /local process isolation is insecure/); +}); + +test("production rejects the process provider even when process opt-in is present", async () => { + const { spawn } = await import("node:child_process"); + const child = spawn(process.execPath, ["--experimental-strip-types", "src/server.ts"], { + env: { + PATH: process.env.PATH ?? "", + OCI_JAVASCRIPT_MODE: "production", + OCI_JAVASCRIPT_ALLOW_INSECURE_PROCESS: "1" + }, + stdio: ["ignore", "ignore", "pipe"] + }); + let stderr = ""; + child.stderr.on("data", chunk => { stderr += String(chunk); }); + const code = await new Promise(resolve => child.once("exit", resolve)); + assert.notEqual(code, 0); + assert.match(stderr, /not admitted in production/); +}); diff --git a/src/oci-javascript-mcp-server/tsconfig.json b/src/oci-javascript-mcp-server/tsconfig.json new file mode 100644 index 00000000..b7b0c8db --- /dev/null +++ b/src/oci-javascript-mcp-server/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2024", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "erasableSyntaxOnly": true, + "types": ["node"] + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +}