50 lines
2.7 KiB
TypeScript
50 lines
2.7 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { shellQuote } from "@paperclipai/adapter-utils/ssh";
|
|
import type { SandboxManagedRuntimeAssetProvision } from "@paperclipai/adapter-utils/sandbox-managed-runtime";
|
|
|
|
// Codex-specific inbound auth-merge assets. These live alongside the Codex
|
|
// adapter server code; the two script files (`codex-auth-merge-extract.sh` and
|
|
// `codex-auth-merge-decision.cjs`) are read from this directory at runtime and
|
|
// staged into the sandbox. The sandbox runtime *core*
|
|
// (`sandbox-managed-runtime.ts`) is intentionally free of any Codex knowledge —
|
|
// the adapter supplies this contribution through the generic `provision` seam.
|
|
|
|
export const CODEX_AUTH_MERGE_EXTRACT_SCRIPT_NAME = "codex-auth-merge-extract.sh";
|
|
export const CODEX_AUTH_MERGE_DECISION_SCRIPT_NAME = "codex-auth-merge-decision.cjs";
|
|
|
|
const CODEX_AUTH_MERGE_EXTRACT_SCRIPT_BYTES = readFileSync(
|
|
new URL(`./${CODEX_AUTH_MERGE_EXTRACT_SCRIPT_NAME}`, import.meta.url),
|
|
);
|
|
const CODEX_AUTH_MERGE_DECISION_SCRIPT_BYTES = readFileSync(
|
|
new URL(`./${CODEX_AUTH_MERGE_DECISION_SCRIPT_NAME}`, import.meta.url),
|
|
);
|
|
|
|
/**
|
|
* Builds the inbound (host→sandbox) provisioning contribution for the Codex
|
|
* managed-home asset as **files + an ordered post-upload merge command**: the two
|
|
* merge scripts ride the sync operation's `files` (staged into the runtime root
|
|
* alongside the uploaded home tar via native `uploadFiles`), and the merge-extract
|
|
* script runs as the operation's ordered **post-upload command** instead of a
|
|
* plain `tar -xf`, so a sandbox that already carries a Codex `auth.json` keeps
|
|
* whichever credential is newer (newer-`auth.json`-wins, same-identity, atomic
|
|
* `0600` install — all inside the opaque script, unchanged).
|
|
*
|
|
* The command string handed to the provider is opaque and fully shell-quoted from
|
|
* already-confined paths (Security Conditions C1/C3): it invokes only the staged
|
|
* script by path — no `auth.json` bytes, token fields, or workspace content are
|
|
* interpolated into the shell (C5). This is behaviour-identical to the extraction
|
|
* the sandbox core previously drove through the custom-provision tar path.
|
|
*/
|
|
export function buildCodexAuthInboundProvision(): SandboxManagedRuntimeAssetProvision {
|
|
return {
|
|
stageFiles: [
|
|
{ name: CODEX_AUTH_MERGE_EXTRACT_SCRIPT_NAME, contents: CODEX_AUTH_MERGE_EXTRACT_SCRIPT_BYTES },
|
|
{ name: CODEX_AUTH_MERGE_DECISION_SCRIPT_NAME, contents: CODEX_AUTH_MERGE_DECISION_SCRIPT_BYTES },
|
|
],
|
|
postUploadCommand: ({ assetTarPath, assetDir, runtimeRootDir }) =>
|
|
`sh ${shellQuote(path.posix.join(runtimeRootDir, CODEX_AUTH_MERGE_EXTRACT_SCRIPT_NAME))} ` +
|
|
`${shellQuote(assetDir)} ${shellQuote(assetTarPath)}`,
|
|
};
|
|
}
|