Preserve explicit Pi setup network settings and current SDK fixtures

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-05 14:27:02 -05:00
1 parent ec67ba1e05
commit fcef1eae9b
6 files changed
+77 -15

No files matched your search

+8 -1
View File
@@ -4,7 +4,7 @@ import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { Command } from "commander";
import { afterEach, expect, it } from "vitest";
import { registerRuntimeCommands, resolvePiProvisioner, resolveRemoteCompanionImporter } from "../commands/runtime.js";
import { buildPiSetupEnvironment, registerRuntimeCommands, resolvePiProvisioner, resolveRemoteCompanionImporter } from "../commands/runtime.js";
const roots: string[] = [];
afterEach(async () => { await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true }))); });
async function fixture() {
@@ -43,3 +43,10 @@ it("requires an explicit digest for the companion import command", async () => {
const program = new Command(); program.exitOverride().configureOutput({ writeErr() {} }); registerRuntimeCommands(program);
await expect(program.parseAsync(["node", "paperclipai", "runtime", "import-remote", "/unused"])).rejects.toThrow("sha256");
});
it("passes explicit setup network settings without provider keys or ambient Node/npm configuration", () => {
const network = { PATH: "/public/bin", LC_ALL: "C.UTF-8", HTTPS_PROXY: "http://proxy.example:8080", HTTP_PROXY: "http://proxy.example:8080", NO_PROXY: "localhost", SSL_CERT_FILE: "/public/ca.pem", SSL_CERT_DIR: "/public/certs", NODE_EXTRA_CA_CERTS: "/public/extra-ca.pem" };
const environment = buildPiSetupEnvironment({ ...network, LANG: "foreign", HOME: "/private/home", OPENROUTER_API_KEY: "must-not-forward", ANTHROPIC_API_KEY: "must-not-forward", NPM_TOKEN: "must-not-forward", npm_config_registry: "https://foreign.example", NODE_OPTIONS: "--require /foreign.js", NODE_PATH: "/foreign/modules", NODE_TLS_REJECT_UNAUTHORIZED: "0" });
expect(environment).toEqual({ ...network, LANG: "C.UTF-8" });
expect(buildPiSetupEnvironment({})).toEqual({ PATH: "/usr/bin:/bin", LANG: "C.UTF-8" });
});
+13 -4
View File
@@ -27,12 +27,21 @@ export async function resolveRemoteCompanionImporter(serverUrl: string): Promise
return modulePath;
}
/** Public downloads may use operator network settings, never application secrets. */
export function buildPiSetupEnvironment(source: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
const environment: NodeJS.ProcessEnv = { PATH: source.PATH ?? "/usr/bin:/bin", LANG: "C.UTF-8" };
for (const key of ["LC_ALL", "HTTPS_PROXY", "HTTP_PROXY", "NO_PROXY", "SSL_CERT_FILE", "SSL_CERT_DIR", "NODE_EXTRA_CA_CERTS"]) {
if (typeof source[key] === "string") environment[key] = source[key];
}
return environment;
}
export async function setupPiRuntime(): Promise<void> {
const provisioner = await resolvePiProvisioner(import.meta.resolve("@paperclipai/server"));
// Only the explicit setup command can download pinned public dependencies.
// Do not forward provider credentials, proxy/npm config, HOME or NODE_OPTIONS.
const child = spawn(process.execPath, [provisioner], {
stdio: "inherit", env: { PATH: process.env.PATH ?? "/usr/bin:/bin", LANG: "C.UTF-8" },
// Only explicit setup downloads. Enable Node's proxy handling for the helper;
// provider keys, npm configuration, HOME and Node injection remain excluded.
const child = spawn(process.execPath, ["--use-env-proxy", provisioner], {
stdio: "inherit", env: buildPiSetupEnvironment(),
});
const cancel = () => { if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM"); };
process.on("SIGINT", cancel); process.on("SIGTERM", cancel);