From 456dc5273ae130bfe1a554ddde241c4109c19163 Mon Sep 17 00:00:00 2001 From: Ben U Date: Thu, 30 Jul 2026 14:04:22 -0600 Subject: [PATCH] feat: add dormant Boss protected provider --- package.json | 8 +- provider/entry.ts | 37 ++++ provider/protected-service.test.ts | 293 +++++++++++++++++++++++++++ provider/protected-service.ts | 162 +++++++++++++++ provider/provider.mjs | 34 ++++ scripts/build-protected-provider.mjs | 58 ++++++ test/package-contents.test.ts | 66 ++++++ tsconfig.json | 2 +- 8 files changed, 658 insertions(+), 2 deletions(-) create mode 100644 provider/entry.ts create mode 100644 provider/protected-service.test.ts create mode 100644 provider/protected-service.ts create mode 100644 provider/provider.mjs create mode 100644 scripts/build-protected-provider.mjs create mode 100644 test/package-contents.test.ts diff --git a/package.json b/package.json index fa09fb3..fa43dcf 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,11 @@ "!opencode/**/*.test.ts", "broker/**/*.ts", "!broker/**/*.test.ts", + "provider/protected-service.ts", + "provider/provider.mjs", + "!provider/entry.ts", "scripts/**/*", + "!scripts/build-protected-provider.mjs", "types.ts", "config.ts", "durable-json.ts", @@ -34,8 +38,10 @@ ], "scripts": { "build": "node scripts/build.mjs", + "build:protected-provider": "node scripts/build-protected-provider.mjs", + "prepack": "npm run build:protected-provider", "prepare": "npm run build", - "test": "tsx --test broker/*.test.ts opencode/contact.test.ts opencode/control.test.ts opencode/fleet.test.ts opencode/health.test.ts opencode/inbound-store.test.ts opencode/notice-ingress.test.ts opencode/runtime.test.ts opencode/team.test.ts opencode/tui.test.ts test/*.test.ts", + "test": "tsx --test broker/*.test.ts opencode/contact.test.ts opencode/control.test.ts opencode/fleet.test.ts opencode/health.test.ts opencode/inbound-store.test.ts opencode/notice-ingress.test.ts opencode/runtime.test.ts opencode/team.test.ts opencode/tui.test.ts provider/*.test.ts test/*.test.ts", "typecheck": "tsc --noEmit" }, "keywords": [ diff --git a/provider/entry.ts b/provider/entry.ts new file mode 100644 index 0000000..2ca7874 --- /dev/null +++ b/provider/entry.ts @@ -0,0 +1,37 @@ +const supportedBossFeature = Object.freeze({ + version: "intercom.broker-feature.v1", + feature: "boss-run-v1", + featureVersion: 1, + semanticsHash: "91dc85ea8c896b9394ebc30db4689803004dbb1c5455eca763a09d0caef167f1", + controlEnvelopeVersion: 1, + capabilityDigest: "6090d92d87223209c653111e2d22a6921e818f71c76b61679f1480ebe021a119", +}); + +/** Immutable build-time contract only; it is not an installed-provider claim. */ +export const OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY = Object.freeze({ + contractVersion: "opencode.boss-protected-provider.v1", + adapterId: "opencode", + providerPackage: "@dataforxyz/agent-intercom-opencode", + supportedBaseProtocolVersions: Object.freeze([3]), + supportedFeatures: Object.freeze([supportedBossFeature]), + protocolFeatureContractHash: "3532c82524f651a5ea8c18a5d8d9689955237d6f68227fc32b1c38e7ea8825d0", + authoritative: false, + providerStartAvailable: false, + bossAdvertisementEnabled: false, +} as const); + +const BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE = "BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE" as const; + +class OpenCodeBossProtectedProviderStartUnavailableError extends Error { + readonly code = BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE; + + constructor() { + super(`${BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE}: protected provider execution is not installed`); + this.name = "OpenCodeBossProtectedProviderStartUnavailableError"; + } +} + +/** A later protected service may replace this dormant entry after release gates. */ +export function startOpenCodeBossProtectedProvider(_request: unknown): never { + throw new OpenCodeBossProtectedProviderStartUnavailableError(); +} diff --git a/provider/protected-service.test.ts b/provider/protected-service.test.ts new file mode 100644 index 0000000..c44ac1d --- /dev/null +++ b/provider/protected-service.test.ts @@ -0,0 +1,293 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; +import { readFileSync, readdirSync } from "node:fs"; +import { join } from "node:path"; +import test from "node:test"; +import { + BOSS_CAPABILITY_FEATURE_DIGEST, + BOSS_RUN_FEATURE_CONTRACT, + BOSS_RUN_PROTOCOL_FEATURE_CONTRACT_HASH, + BROKER_FEATURE_ATTESTATION_VERSION, + BROKER_PROTECTED_PROVIDER_ROOT, + INTERCOM_BASE_PROTOCOL_VERSION, +} from "@dataforxyz/agent-intercom-core/boss"; +import { DORMANT_BROKER_CAPABILITIES } from "../broker/negotiation.ts"; +import { + BOSS_PROTECTED_SERVICE_UNAVAILABLE, + ensureOpenCodeBossProtectedService, + OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH, + OPENCODE_BOSS_PROTECTED_PROVIDER_ID, + OPENCODE_BOSS_PROTECTED_PROVIDER_PACKAGE, + OpenCodeBossProtectedServiceError, + parseOpenCodeBossProtectedProviderArtifactCandidate, +} from "./protected-service.ts"; +import { + OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY, + startOpenCodeBossProtectedProvider, +} from "./entry.ts"; + +const repositoryRoot = new URL("..", import.meta.url); +const generatedProviderUrl = new URL("provider/provider.mjs", repositoryRoot); +const buildScriptUrl = new URL("scripts/build-protected-provider.mjs", repositoryRoot); +const ordinaryDistNames = ["broker.mjs", "plugin.mjs", "tui.mjs"]; + +function generatedProviderBytes(): Buffer { + return readFileSync(generatedProviderUrl); +} + +function ordinaryDistSnapshot(): Record { + const distUrl = new URL("dist/", repositoryRoot); + assert.deepEqual(readdirSync(distUrl).filter((name) => name.endsWith(".mjs")).sort(), ordinaryDistNames); + return Object.fromEntries(ordinaryDistNames.map((name) => [name, readFileSync(join(distUrl.pathname, name))])); +} + +function providerCandidate(): Record { + return { + adapterId: OPENCODE_BOSS_PROTECTED_PROVIDER_ID, + providerPackage: OPENCODE_BOSS_PROTECTED_PROVIDER_PACKAGE, + providerVersion: "0.10.0", + providerDigest: createHash("sha256").update(generatedProviderBytes()).digest("hex"), + artifactPath: OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH, + artifactOwnerUid: 0, + artifactOwnerGid: 0, + artifactMode: "0555", + }; +} + +function expectCandidateInvalid(value: unknown): OpenCodeBossProtectedServiceError { + let observed: unknown; + try { + parseOpenCodeBossProtectedProviderArtifactCandidate(value); + } catch (error) { + observed = error; + } + assert.ok(observed instanceof OpenCodeBossProtectedServiceError); + assert.equal(observed.code, "INVALID_OPENCODE_PROTECTED_PROVIDER_CANDIDATE"); + return observed; +} + +test("normalizes only the canonical unsigned non-authoritative OpenCode provider candidate", () => { + assert.equal( + OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH, + `${BROKER_PROTECTED_PROVIDER_ROOT}opencode/provider.mjs`, + ); + const candidate = providerCandidate(); + const snapshot = structuredClone(candidate); + const parsed = parseOpenCodeBossProtectedProviderArtifactCandidate(candidate); + + assert.deepEqual(candidate, snapshot); + assert.deepEqual(parsed, candidate); + assert.deepEqual(Reflect.ownKeys(parsed), [ + "adapterId", "providerPackage", "providerVersion", "providerDigest", + "artifactPath", "artifactOwnerUid", "artifactOwnerGid", "artifactMode", + ]); + assert.ok(Object.isFrozen(parsed)); + assert.equal(Object.hasOwn(parsed, "signature"), false); + assert.equal(Object.hasOwn(parsed, "attestationKeyId"), false); +}); + +test("accepts canonical semantic-version forms without changing candidate data", () => { + for (const providerVersion of ["0.0.0", "1.2.3", "1.2.3-alpha.1+build.5", "10.20.30+001"]) { + const candidate = providerCandidate(); + candidate.providerVersion = providerVersion; + assert.equal(parseOpenCodeBossProtectedProviderArtifactCandidate(candidate).providerVersion, providerVersion); + } +}); + +test("rejects substitution, writable artifacts, noncanonical versions, and non-lowercase digests", () => { + const mutations: Array<[string, unknown]> = [ + ["adapterId", "codex"], + ["providerPackage", "@attacker/agent-intercom-opencode"], + ["providerVersion", "01.0.0"], + ["providerVersion", "1.0.0-01"], + ["providerVersion", "1.2"], + ["providerVersion", "1.2.3.4"], + ["providerVersion", "v1.2.3"], + ["providerVersion", "latest"], + ...["\n", "\r", "\u2028", "\u2029"].map((terminator) => ["providerVersion", `1.2.3${terminator}`] as [string, unknown]), + ["providerDigest", "A".repeat(64)], + ["providerDigest", "a".repeat(63)], + ["providerDigest", "a".repeat(65)], + ...["\n", "\r", "\u2028", "\u2029"].map((terminator) => ["providerDigest", `${"a".repeat(64)}${terminator}`] as [string, unknown]), + ["artifactPath", "/usr/lib/agent-intercom/providers/opencode/../evil/provider.mjs"], + ["artifactPath", "/tmp/opencode/provider.mjs"], + ["artifactOwnerUid", 1000], + ["artifactOwnerGid", 1000], + ["artifactMode", "0755"], + ]; + + for (const [field, replacement] of mutations) { + const candidate = providerCandidate(); + candidate[field] = replacement; + expectCandidateInvalid(candidate); + } +}); + +test("never accepts caller-supplied attestation, trust, identity, credential, or installation facts", () => { + for (const forbidden of [ + "version", + "userWritable", + "authoritative", + "signature", + "attestationKeyId", + "trustedReleaseKeys", + "ownerUid", + "brokerServiceUid", + "controllerServiceUid", + "identityKeyId", + "brokerGeneration", + "serviceCapability", + "credential", + "installed", + ]) { + const candidate = providerCandidate(); + candidate[forbidden] = forbidden === "installed" ? true : "attacker-controlled"; + expectCandidateInvalid(candidate); + } +}); + +test("rejects proxies, inheritance, accessors, symbols, and non-data fields without getter execution", () => { + let invoked = false; + const proxied = new Proxy(providerCandidate(), { + get() { invoked = true; throw new Error("must not read proxy"); }, + getOwnPropertyDescriptor() { invoked = true; throw new Error("must not inspect proxy"); }, + getPrototypeOf() { invoked = true; throw new Error("must not inspect proxy"); }, + ownKeys() { invoked = true; throw new Error("must not enumerate proxy"); }, + }); + expectCandidateInvalid(proxied); + assert.equal(invoked, false); + + expectCandidateInvalid(Object.create(providerCandidate())); + + const accessor = providerCandidate(); + Object.defineProperty(accessor, "providerVersion", { + enumerable: true, + get() { invoked = true; throw new Error("must not invoke getter"); }, + }); + expectCandidateInvalid(accessor); + assert.equal(invoked, false); + + const symbol = providerCandidate(); + symbol[Symbol("authority")] = true; + expectCandidateInvalid(symbol); + + const hidden = providerCandidate(); + Object.defineProperty(hidden, "providerDigest", { + enumerable: false, + value: hidden.providerDigest, + }); + expectCandidateInvalid(hidden); +}); + +test("production ensure reports unavailability before hostile request inspection", () => { + let invoked = false; + const request = new Proxy({}, { + get() { invoked = true; throw new Error("must not inspect request"); }, + getOwnPropertyDescriptor() { invoked = true; throw new Error("must not inspect request"); }, + getPrototypeOf() { invoked = true; throw new Error("must not inspect request"); }, + ownKeys() { invoked = true; throw new Error("must not enumerate request"); }, + }); + + assert.throws( + () => ensureOpenCodeBossProtectedService(request), + (error: unknown) => error instanceof OpenCodeBossProtectedServiceError + && error.code === BOSS_PROTECTED_SERVICE_UNAVAILABLE + && error.path === "$provisioner", + ); + assert.equal(invoked, false); +}); + +test("generated provider is deterministic and leaves ordinary dist bytes unchanged", async () => { + const { buildProtectedProvider } = await import(buildScriptUrl.href) as { + buildProtectedProvider(): string; + }; + const ordinaryBefore = ordinaryDistSnapshot(); + const committed = generatedProviderBytes(); + const firstOutput = buildProtectedProvider(); + const first = generatedProviderBytes(); + const secondOutput = buildProtectedProvider(); + const second = generatedProviderBytes(); + + assert.deepEqual(first, committed); + assert.deepEqual(second, first); + assert.equal(firstOutput, first.toString("utf8")); + assert.equal(secondOutput, firstOutput); + assert.deepEqual(ordinaryDistSnapshot(), ordinaryBefore); + const source = second.toString("utf8"); + assert.doesNotMatch(source, /\/home\/|\/Users\/|[A-Z]:\\/); + assert.doesNotMatch(source, /\/usr\/lib\/agent-intercom|\/run\/agent-intercom|\/var\/lib\/agent-intercom/); +}); + +test("source and generated provider expose the same immutable dormant build identity", async () => { + const generated = await import(generatedProviderUrl.href) as typeof import("./entry.ts"); + assert.deepEqual(Object.keys(generated).sort(), [ + "OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY", + "startOpenCodeBossProtectedProvider", + ]); + assert.deepEqual( + generated.OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY, + OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY, + ); + + for (const identity of [ + OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY, + generated.OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY, + ]) { + assert.ok(Object.isFrozen(identity)); + assert.ok(Object.isFrozen(identity.supportedBaseProtocolVersions)); + assert.ok(Object.isFrozen(identity.supportedFeatures)); + assert.ok(Object.isFrozen(identity.supportedFeatures[0])); + assert.equal(identity.contractVersion, "opencode.boss-protected-provider.v1"); + assert.equal(identity.adapterId, "opencode"); + assert.equal(identity.providerPackage, "@dataforxyz/agent-intercom-opencode"); + assert.equal(identity.authoritative, false); + assert.equal(identity.providerStartAvailable, false); + assert.equal(identity.bossAdvertisementEnabled, false); + assert.deepEqual(identity.supportedBaseProtocolVersions, [INTERCOM_BASE_PROTOCOL_VERSION]); + assert.deepEqual(identity.supportedFeatures, [{ + version: BROKER_FEATURE_ATTESTATION_VERSION, + feature: BOSS_RUN_FEATURE_CONTRACT.feature, + featureVersion: BOSS_RUN_FEATURE_CONTRACT.version, + semanticsHash: BOSS_RUN_FEATURE_CONTRACT.semanticsHash, + controlEnvelopeVersion: BOSS_RUN_FEATURE_CONTRACT.controlEnvelopeVersion, + capabilityDigest: BOSS_CAPABILITY_FEATURE_DIGEST, + }]); + assert.equal(identity.protocolFeatureContractHash, BOSS_RUN_PROTOCOL_FEATURE_CONTRACT_HASH); + } +}); + +test("provider has zero runtime imports or integration and start fails before request inspection", async () => { + const source = readFileSync(new URL("provider/entry.ts", repositoryRoot), "utf8"); + const generatedSource = generatedProviderBytes().toString("utf8"); + for (const value of [source, generatedSource]) { + assert.doesNotMatch(value, /^\s*import\s/m); + assert.doesNotMatch(value, /\brequire\s*\(/); + assert.doesNotMatch(value, /\bimport\s*\(/); + assert.doesNotMatch(value, /node:(?:fs|child_process|net|process|os)/); + assert.doesNotMatch(value, /systemctl|\.listen\(|\.connect\(|\.kill\(|\.spawn\(|broker\/(?:broker|spawn|paths|ownership)/); + assert.doesNotMatch(value, /@opencode-ai|OpenCodeIntercomPlugin|startOpenCodeControlServer|invokeAgentFleet/); + } + + const generated = await import(generatedProviderUrl.href) as typeof import("./entry.ts"); + for (const start of [startOpenCodeBossProtectedProvider, generated.startOpenCodeBossProtectedProvider]) { + let invoked = false; + const request = Object.defineProperty({}, "ownerUid", { + enumerable: true, + get() { invoked = true; throw new Error("must not inspect start request"); }, + }); + assert.throws( + () => start(request), + (error: unknown) => typeof error === "object" + && error !== null + && (error as { code?: unknown }).code === "BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE", + ); + assert.equal(invoked, false); + } +}); + +test("protected-provider packaging does not activate or advertise Boss", () => { + assert.deepEqual(DORMANT_BROKER_CAPABILITIES, { + baseProtocolVersion: 3, + features: [], + }); +}); diff --git a/provider/protected-service.ts b/provider/protected-service.ts new file mode 100644 index 0000000..273d8d3 --- /dev/null +++ b/provider/protected-service.ts @@ -0,0 +1,162 @@ +import { types as nodeUtilTypes } from "node:util"; +import { BROKER_PROTECTED_PROVIDER_ROOT } from "@dataforxyz/agent-intercom-core/boss"; + +export const OPENCODE_BOSS_PROTECTED_PROVIDER_ID = "opencode" as const; +export const OPENCODE_BOSS_PROTECTED_PROVIDER_PACKAGE = "@dataforxyz/agent-intercom-opencode" as const; +export const OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH = + `${BROKER_PROTECTED_PROVIDER_ROOT}${OPENCODE_BOSS_PROTECTED_PROVIDER_ID}/provider.mjs` as const; +export const BOSS_PROTECTED_SERVICE_UNAVAILABLE = "BOSS_PROTECTED_SERVICE_UNAVAILABLE" as const; + +const OPENCODE_BOSS_PROTECTED_PROVIDER_MODE = "0555" as const; +const CANONICAL_SEMANTIC_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:(?:0|[1-9]\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/; +const CANDIDATE_KEYS = [ + "adapterId", + "providerPackage", + "providerVersion", + "providerDigest", + "artifactPath", + "artifactOwnerUid", + "artifactOwnerGid", + "artifactMode", +] as const; + +export interface OpenCodeBossProtectedProviderArtifactCandidate { + adapterId: typeof OPENCODE_BOSS_PROTECTED_PROVIDER_ID; + providerPackage: typeof OPENCODE_BOSS_PROTECTED_PROVIDER_PACKAGE; + providerVersion: string; + providerDigest: string; + artifactPath: typeof OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH; + artifactOwnerUid: 0; + artifactOwnerGid: 0; + artifactMode: typeof OPENCODE_BOSS_PROTECTED_PROVIDER_MODE; +} + +export type OpenCodeBossProtectedServiceErrorCode = + | "INVALID_OPENCODE_PROTECTED_PROVIDER_CANDIDATE" + | typeof BOSS_PROTECTED_SERVICE_UNAVAILABLE; + +export class OpenCodeBossProtectedServiceError extends Error { + readonly code: OpenCodeBossProtectedServiceErrorCode; + readonly path: string; + + constructor(code: OpenCodeBossProtectedServiceErrorCode, path: string, message: string) { + super(`${path}: ${message}`); + this.name = "OpenCodeBossProtectedServiceError"; + this.code = code; + this.path = path; + } +} + +function invalid(path: string, message: string): never { + throw new OpenCodeBossProtectedServiceError( + "INVALID_OPENCODE_PROTECTED_PROVIDER_CANDIDATE", + path, + message, + ); +} + +function assertExactOwnDataCandidate(value: unknown): asserts value is Record { + const path = "$candidate"; + if ( + typeof value !== "object" + || value === null + || nodeUtilTypes.isProxy(value) + || Array.isArray(value) + || Object.getPrototypeOf(value) !== Object.prototype + ) { + invalid(path, "must be a non-proxy plain data object"); + } + + const keys = Reflect.ownKeys(value); + if ( + keys.length !== CANDIDATE_KEYS.length + || keys.some((key) => typeof key !== "string" || !CANDIDATE_KEYS.includes(key as typeof CANDIDATE_KEYS[number])) + ) { + invalid(path, "must contain exactly the canonical unsigned OpenCode provider candidate fields"); + } + + for (const key of CANDIDATE_KEYS) { + const descriptor = Object.getOwnPropertyDescriptor(value, key); + if ( + descriptor === undefined + || !descriptor.enumerable + || !Object.hasOwn(descriptor, "value") + ) { + invalid(`${path}.${key}`, "must be an own enumerable data property"); + } + } +} + +function ownValue(value: Record, key: typeof CANDIDATE_KEYS[number]): unknown { + return Object.getOwnPropertyDescriptor(value, key)!.value; +} + +function readProviderVersion(value: unknown): string { + if ( + typeof value !== "string" + || value.length > 128 + || /[\r\n\u2028\u2029]/.test(value) + || !CANONICAL_SEMANTIC_VERSION.test(value) + ) { + invalid("$candidate.providerVersion", "must be a canonical semantic version"); + } + return value; +} + +function readProviderDigest(value: unknown): string { + if (typeof value !== "string" || value.length !== 64 || !/^[a-f0-9]{64}$/.test(value)) { + invalid("$candidate.providerDigest", "must be a lowercase SHA-256 digest"); + } + return value; +} + +/** + * Normalize an unsigned release candidate for the packaged OpenCode provider. + * This parser cannot verify installation, signatures, service identities, or + * authority. Its frozen result remains explicitly non-authoritative. + */ +export function parseOpenCodeBossProtectedProviderArtifactCandidate( + value: unknown, +): Readonly { + assertExactOwnDataCandidate(value); + + if (ownValue(value, "adapterId") !== OPENCODE_BOSS_PROTECTED_PROVIDER_ID) { + invalid("$candidate.adapterId", "must identify the OpenCode provider"); + } + if (ownValue(value, "providerPackage") !== OPENCODE_BOSS_PROTECTED_PROVIDER_PACKAGE) { + invalid("$candidate.providerPackage", "must identify the canonical OpenCode package"); + } + if (ownValue(value, "artifactPath") !== OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH) { + invalid("$candidate.artifactPath", "must equal the canonical protected OpenCode provider path"); + } + if (ownValue(value, "artifactOwnerUid") !== 0 || ownValue(value, "artifactOwnerGid") !== 0) { + invalid("$candidate.artifactOwnerUid", "must describe a root:root artifact"); + } + if (ownValue(value, "artifactMode") !== OPENCODE_BOSS_PROTECTED_PROVIDER_MODE) { + invalid("$candidate.artifactMode", "must be read/execute-only mode 0555"); + } + + return Object.freeze({ + adapterId: OPENCODE_BOSS_PROTECTED_PROVIDER_ID, + providerPackage: OPENCODE_BOSS_PROTECTED_PROVIDER_PACKAGE, + providerVersion: readProviderVersion(ownValue(value, "providerVersion")), + providerDigest: readProviderDigest(ownValue(value, "providerDigest")), + artifactPath: OPENCODE_BOSS_PROTECTED_PROVIDER_ARTIFACT_PATH, + artifactOwnerUid: 0, + artifactOwnerGid: 0, + artifactMode: OPENCODE_BOSS_PROTECTED_PROVIDER_MODE, + }); +} + +/** + * Production ensure is intentionally unavailable until a protected + * provisioner supplies release and service identity facts outside caller data. + * The request is never inspected while that provisioner is absent. + */ +export function ensureOpenCodeBossProtectedService(_request: unknown): never { + throw new OpenCodeBossProtectedServiceError( + BOSS_PROTECTED_SERVICE_UNAVAILABLE, + "$provisioner", + "the protected OpenCode broker service provisioner is not installed", + ); +} diff --git a/provider/provider.mjs b/provider/provider.mjs new file mode 100644 index 0000000..2a6ecd2 --- /dev/null +++ b/provider/provider.mjs @@ -0,0 +1,34 @@ +// Generated from provider/entry.ts by scripts/build-protected-provider.mjs. +// Do not edit this artifact directly. +const supportedBossFeature = Object.freeze({ + version: "intercom.broker-feature.v1", + feature: "boss-run-v1", + featureVersion: 1, + semanticsHash: "91dc85ea8c896b9394ebc30db4689803004dbb1c5455eca763a09d0caef167f1", + controlEnvelopeVersion: 1, + capabilityDigest: "6090d92d87223209c653111e2d22a6921e818f71c76b61679f1480ebe021a119", +}); +/** Immutable build-time contract only; it is not an installed-provider claim. */ +export const OPENCODE_BOSS_PROTECTED_PROVIDER_BUILD_IDENTITY = Object.freeze({ + contractVersion: "opencode.boss-protected-provider.v1", + adapterId: "opencode", + providerPackage: "@dataforxyz/agent-intercom-opencode", + supportedBaseProtocolVersions: Object.freeze([3]), + supportedFeatures: Object.freeze([supportedBossFeature]), + protocolFeatureContractHash: "3532c82524f651a5ea8c18a5d8d9689955237d6f68227fc32b1c38e7ea8825d0", + authoritative: false, + providerStartAvailable: false, + bossAdvertisementEnabled: false, +}); +const BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE = "BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE"; +class OpenCodeBossProtectedProviderStartUnavailableError extends Error { + code = BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE; + constructor() { + super(`${BOSS_PROTECTED_PROVIDER_START_UNAVAILABLE}: protected provider execution is not installed`); + this.name = "OpenCodeBossProtectedProviderStartUnavailableError"; + } +} +/** A later protected service may replace this dormant entry after release gates. */ +export function startOpenCodeBossProtectedProvider(_request) { + throw new OpenCodeBossProtectedProviderStartUnavailableError(); +} diff --git a/scripts/build-protected-provider.mjs b/scripts/build-protected-provider.mjs new file mode 100644 index 0000000..3595af5 --- /dev/null +++ b/scripts/build-protected-provider.mjs @@ -0,0 +1,58 @@ +import { readFileSync, mkdirSync, writeFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import ts from "typescript"; + +const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const sourcePath = resolve(repositoryRoot, "provider/entry.ts"); +const outputPath = resolve(repositoryRoot, "provider/provider.mjs"); + +export function buildProtectedProvider() { + const source = readFileSync(sourcePath, "utf8"); + const result = ts.transpileModule(source, { + fileName: "provider/entry.ts", + reportDiagnostics: true, + compilerOptions: { + target: ts.ScriptTarget.ES2022, + module: ts.ModuleKind.ES2022, + importsNotUsedAsValues: ts.ImportsNotUsedAsValues.Remove, + newLine: ts.NewLineKind.LineFeed, + removeComments: false, + sourceMap: false, + inlineSourceMap: false, + inlineSources: false, + }, + }); + + const errors = (result.diagnostics ?? []).filter( + (diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error, + ); + if (errors.length > 0) { + throw new Error(ts.formatDiagnostics(errors, { + getCanonicalFileName: (fileName) => fileName, + getCurrentDirectory: () => ".", + getNewLine: () => "\n", + })); + } + + const generated = [ + "// Generated from provider/entry.ts by scripts/build-protected-provider.mjs.", + "// Do not edit this artifact directly.", + result.outputText.replace(/\r\n/g, "\n").trimEnd(), + "", + ].join("\n"); + + mkdirSync(dirname(outputPath), { recursive: true }); + let previous; + try { + previous = readFileSync(outputPath, "utf8"); + } catch { + previous = undefined; + } + if (previous !== generated) writeFileSync(outputPath, generated, "utf8"); + return generated; +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + buildProtectedProvider(); +} diff --git a/test/package-contents.test.ts b/test/package-contents.test.ts new file mode 100644 index 0000000..4aac4ac --- /dev/null +++ b/test/package-contents.test.ts @@ -0,0 +1,66 @@ +import assert from "node:assert/strict"; +import { existsSync, readFileSync } from "node:fs"; +import test from "node:test"; + +const repositoryRoot = new URL("..", import.meta.url); + +function manifest(): Record { + return JSON.parse(readFileSync(new URL("package.json", repositoryRoot), "utf8")) as Record; +} + +test("published package contains exactly the intended protected-provider source and artifact", () => { + const packageManifest = manifest(); + const providerRules = packageManifest.files.filter((path: string) => path.replace(/^!/, "").startsWith("provider/")); + + assert.deepEqual(providerRules, [ + "provider/protected-service.ts", + "provider/provider.mjs", + "!provider/entry.ts", + ]); + assert.ok(packageManifest.files.includes("!scripts/build-protected-provider.mjs")); + assert.equal(providerRules.some((path: string) => path.includes("*")), false); + assert.ok(existsSync(new URL("provider/protected-service.ts", repositoryRoot))); + assert.ok(existsSync(new URL("provider/provider.mjs", repositoryRoot))); + assert.ok(existsSync(new URL("provider/entry.ts", repositoryRoot))); + assert.ok(existsSync(new URL("provider/protected-service.test.ts", repositoryRoot))); + +}); + +test("protected provider is neither an export, plugin, executable, nor ordinary build entry", () => { + const packageManifest = manifest(); + const ordinaryBuild = readFileSync(new URL("scripts/build.mjs", repositoryRoot), "utf8"); + + assert.equal(packageManifest.main, "dist/plugin.mjs"); + assert.deepEqual(packageManifest.exports, { + ".": "./dist/plugin.mjs", + "./tui": "./dist/tui.mjs", + }); + assert.equal(packageManifest.bin, undefined); + assert.equal(Object.values(packageManifest.exports).includes("./provider/provider.mjs"), false); + assert.doesNotMatch(ordinaryBuild, /protected-provider|provider\/provider\.mjs|provider\/entry\.ts/); + assert.deepEqual(Array.from(ordinaryBuild.matchAll(/entryPoints: \["([^"]+)"\]/g), (match) => match[1]), [ + "opencode/plugin.ts", + "opencode/tui.ts", + "broker/broker.ts", + ]); + assert.equal(packageManifest.scripts.build, "node scripts/build.mjs"); + assert.equal(packageManifest.scripts.prepare, "npm run build"); + assert.equal(packageManifest.scripts.prepack, "npm run build:protected-provider"); +}); + +test("ordinary builds retain the shared Core externalizer and exactly three dist bundles", () => { + const ordinaryBuild = readFileSync(new URL("scripts/build.mjs", repositoryRoot), "utf8"); + const coreExternalizer = readFileSync(new URL("scripts/core-external.mjs", repositoryRoot), "utf8"); + + assert.match(ordinaryBuild, /import \{ externalizeCorePlugin \} from "\.\/core-external\.mjs"/); + assert.match(ordinaryBuild, /plugins: \[externalizeCorePlugin\]/); + assert.deepEqual(Array.from(ordinaryBuild.matchAll(/outfile: "dist\/([^"]+)"/g), (match) => match[1]), [ + "plugin.mjs", + "tui.mjs", + "broker.mjs", + ]); + assert.match(coreExternalizer, /export const CORE_PACKAGE = "@dataforxyz\/agent-intercom-core"/); + assert.match(coreExternalizer, /\^@dataforxyz\\\/agent-intercom-core\(\?:\\\/\.\*\)\?\$/); + assert.match(coreExternalizer, /external: true/); + assert.doesNotMatch(coreExternalizer, /protected-provider|provider\/provider\.mjs|provider\/entry\.ts/); +}); diff --git a/tsconfig.json b/tsconfig.json index 07b528a..ded216d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,6 @@ "types": ["node"], "allowImportingTsExtensions": true }, - "include": ["*.ts", "broker/**/*.ts", "opencode/**/*.ts"], + "include": ["*.ts", "broker/**/*.ts", "opencode/**/*.ts", "provider/**/*.ts"], "exclude": ["node_modules", "**/*.test.ts"] }