Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ee/apps/den-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"build:den-db": "pnpm --filter @openwork-ee/den-db build",
"backfill:desktop-policies": "pnpm run build:den-db && tsx scripts/backfill-desktop-policies.ts",
"seed:demo-org": "pnpm run build:den-db && sh -lc 'DEN_WEB_PORT=${DEN_WEB_PORT:-3005}; OPENWORK_DEV_MODE=${OPENWORK_DEV_MODE:-1} DATABASE_URL=${DATABASE_URL:-mysql://root:password@127.0.0.1:3306/openwork_den} DEN_DB_ENCRYPTION_KEY=${DEN_DB_ENCRYPTION_KEY:-local-dev-db-encryption-key-please-change-1234567890} BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-local-dev-secret-not-for-production-use!!} BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:$DEN_WEB_PORT} tsx scripts/seed-demo-org.ts'",
"smoke:daytona-provider-seed": "tsx scripts/daytona-provider-seed-smoke.ts",
"start": "node dist/server.js"
},
"dependencies": {
Expand Down
145 changes: 145 additions & 0 deletions ee/apps/den-api/scripts/daytona-provider-seed-smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { Daytona } from "@daytonaio/sdk"
import {
buildDaytonaProviderSeed,
buildDaytonaProviderSeedScript,
buildShellEnvAssignments,
daytonaProviderSeedConfigPath,
daytonaProviderSeedManifestPath,
shellQuote,
} from "../src/workers/daytona-provider-seed.js"

function requiredEnv(name: string) {
const value = process.env[name]?.trim()
if (!value) {
throw new Error(`${name} is required`)
}
return value
}

function optionalEnv(name: string, fallback: string) {
const value = process.env[name]?.trim()
return value ? value : fallback
}

function slug(value: string) {
return value
.toLowerCase()
.replace(/[^a-z0-9-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "")
}

async function main() {
const apiKey = requiredEnv("DAYTONA_API_KEY")
const apiUrl = optionalEnv("DAYTONA_API_URL", "https://app.daytona.io/api")
const target = process.env.DAYTONA_TARGET?.trim()
const snapshot = process.env.DAYTONA_SNAPSHOT?.trim()
const image = optionalEnv("DAYTONA_SANDBOX_IMAGE", "node:22-bookworm-slim")
const createTimeoutSeconds = Number(process.env.DAYTONA_CREATE_TIMEOUT_SECONDS ?? "300")
const deleteTimeoutSeconds = Number(process.env.DAYTONA_DELETE_TIMEOUT_SECONDS ?? "120")
const commandTimeoutSeconds = Number(process.env.DAYTONA_SMOKE_COMMAND_TIMEOUT_SECONDS ?? "120")
const name = slug(`den-provider-seed-smoke-${Date.now().toString(36)}`).slice(0, 63)

const daytona = new Daytona({
apiKey,
apiUrl,
...(target ? { target } : {}),
})

const common = {
name,
public: false,
autoStopInterval: 0,
autoArchiveInterval: 0,
autoDeleteInterval: 0,
ephemeral: true,
labels: {
"openwork.den.provider": "daytona",
"openwork.den.type": "provider-seed-smoke",
},
envVars: {
DEN_RUNTIME_PROVIDER: "daytona-provider-seed-smoke",
},
resources: {
cpu: 1,
memory: 1,
disk: 4,
},
}

const sandbox = await daytona.create(
snapshot ? { ...common, snapshot } : { ...common, image },
{ timeout: createTimeoutSeconds },
)

try {
const smokeKey = "ow_inf_smoke_key"
const seed = buildDaytonaProviderSeed([
{
providerId: "openwork",
providerConfig: {
id: "openwork",
name: "OpenWork",
npm: "@openrouter/ai-sdk-provider",
env: ["OPENWORK_API_KEY"],
api: "https://inference.openwork.test/api/v1",
options: {
baseURL: "https://inference.openwork.test/api/v1",
},
},
apiKey: smokeKey,
},
])

const workspacePath = "/tmp/openwork-daytona-provider-seed"
const configPath = daytonaProviderSeedConfigPath(workspacePath)
const manifestPath = daytonaProviderSeedManifestPath(workspacePath)
const validateConfigScript = [
'const fs = require("node:fs")',
'const config = JSON.parse(fs.readFileSync(process.argv[1], "utf8"))',
'if (!config.provider || !config.provider.openwork) throw new Error("openwork_provider_missing")',
`if (JSON.stringify(config).includes(${JSON.stringify(smokeKey)})) throw new Error("api_key_written_to_config")`,
].join("; ")
const validateManifestScript = [
'const fs = require("node:fs")',
'const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"))',
'if (!manifest.providerIds.includes("openwork")) throw new Error("openwork_manifest_missing")',
'if (!manifest.envNames.includes("OPENWORK_API_KEY")) throw new Error("openwork_manifest_env_missing")',
`if (JSON.stringify(manifest).includes(${JSON.stringify(smokeKey)})) throw new Error("api_key_written_to_manifest")`,
].join("; ")
const validateEnvScript = `if (process.env.OPENWORK_API_KEY !== ${JSON.stringify(smokeKey)}) throw new Error("openwork_api_key_env_missing")`
const commandScript = [
"set -eu",
buildDaytonaProviderSeedScript({ configPath, manifestPath, seed }),
`node -e ${shellQuote(validateConfigScript)} ${shellQuote(configPath)}`,
`node -e ${shellQuote(validateManifestScript)} ${shellQuote(manifestPath)}`,
`${buildShellEnvAssignments(seed?.env ?? {})} node -e ${shellQuote(validateEnvScript)}`,
"command -v opencode >/dev/null 2>&1 || { echo 'opencode missing; set DAYTONA_SNAPSHOT to the OpenWork runtime snapshot' >&2; exit 2; }",
"opencode --version",
].join("\n")

const result = await sandbox.process.executeCommand(
`sh -lc ${shellQuote(commandScript)}`,
undefined,
undefined,
commandTimeoutSeconds,
)

if (result.exitCode !== 0) {
throw new Error(result.result?.trim() || `smoke command exited with ${result.exitCode}`)
}

console.log(JSON.stringify({ ok: true, sandboxId: sandbox.id, output: result.result?.trim() ?? "" }, null, 2))
} finally {
await sandbox.delete(deleteTimeoutSeconds).catch((error) => {
const message = error instanceof Error ? error.message : "unknown_error"
console.warn(`[daytona-smoke] failed to delete sandbox ${sandbox.id}: ${message}`)
})
}
}

main().catch((error) => {
const message = error instanceof Error ? error.message : "unknown_error"
console.error(message)
process.exit(1)
})
3 changes: 3 additions & 0 deletions ee/apps/den-api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { MemberTeamsContext, OrganizationContextVariables, UserOrganization
import { buildOperationId, emptyResponse, htmlResponse, jsonResponse } from "./openapi.js"
import { registerAdminRoutes } from "./routes/admin/index.js"
import { registerAuthRoutes } from "./routes/auth/index.js"
import { registerCloudTaskRoutes } from "./routes/cloud-tasks/index.js"
import { registerMeRoutes } from "./routes/me/index.js"
import { registerOrgRoutes } from "./routes/org/index.js"
import { registerTelemetryRoutes } from "./routes/telemetry/index.js"
Expand Down Expand Up @@ -117,6 +118,7 @@ app.get(

registerAdminRoutes(app)
registerAuthRoutes(app)
registerCloudTaskRoutes(app)
registerMeRoutes(app)
registerOrgRoutes(app)
registerVersionRoutes(app)
Expand Down Expand Up @@ -169,6 +171,7 @@ app.get(
{ name: "LLM Providers", description: "Organization LLM provider catalog, configuration, and access routes." },
{ name: "Skills", description: "Organization skill authoring and sharing routes." },
{ name: "Skill Hubs", description: "Organization skill hub management and access routes." },
{ name: "Cloud Tasks", description: "Task-first OpenWork Cloud automations and run dispatch." },
{ name: "Workers", description: "Worker lifecycle, billing, and runtime routes." },
{ name: "Worker Runtime", description: "Worker runtime inspection and upgrade routes." },
{ name: "Worker Activity", description: "Worker heartbeat and activity reporting routes." },
Expand Down
5 changes: 5 additions & 0 deletions ee/apps/den-api/src/mcp/policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const SAFE_INCLUDED_TAGS = new Set([
"LLM Providers",
"Skills",
"Skill Hubs",
"Cloud Tasks",
"Workers",
"Worker Runtime",
"Worker Activity",
Expand All @@ -31,6 +32,10 @@ const BLOCKED_OPERATION_IDS = new Set([
"deleteV1OrgsByOrgId",
"postWorkersByWorkerIdTokens",
"postV1WorkersByWorkerIdTokens",
"postWorkersByIdBackgroundJobs",
"postV1WorkersByIdBackgroundJobs",
"postWorkersByWorkerIdBackgroundJobs",
"postV1WorkersByWorkerIdBackgroundJobs",
])

export type OpenApiOperation = {
Expand Down
Loading
Loading