mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-06 23:20:53 +01:00
chore: follow source comment contribution rules
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
9f59ff36cf
commit
c1b9933a24
35 files changed
+25
-157
No files matched your search
@@ -140,7 +140,6 @@ describe("paperclip runner native dev prerequisite", () => {
|
||||
fs.utimesSync(target, current, current);
|
||||
const input = { repoRoot: checkout.root, nativeRunnerRequired: true, platform: "darwin", architecture };
|
||||
expect(paperclipRunnerBinaryNeedsBuild(input)).toBe(false);
|
||||
// A newer Linux build-host output cannot mask the remote Mac artifact.
|
||||
fs.writeFileSync(checkout.binary, nativeHeader("linux", "x64"));
|
||||
const wrongHostNewer = new Date(Date.now() + 4000);
|
||||
fs.utimesSync(checkout.binary, wrongHostNewer, wrongHostNewer);
|
||||
|
||||
@@ -154,8 +154,6 @@ describeEmbeddedPostgres("environmentService leases", () => {
|
||||
config: { config: { ...config, image: `registry.example.test/runtime@sha256:${"b".repeat(64)}` } },
|
||||
driver: { driver: "ssh", config: { host: "fixture.example.test", username: "fixture" } },
|
||||
};
|
||||
// Interleave the real probe UPDATE after the save is prepared but before its
|
||||
// real UPDATE executes. This reproduces the stale route-read/write window.
|
||||
const delayedWriteDb = {
|
||||
update(table: typeof environments) {
|
||||
const prepared = db.update(table);
|
||||
|
||||
@@ -63,7 +63,6 @@ describe("removeTestHome", () => {
|
||||
const home = makeHome();
|
||||
fs.mkdirSync(path.join(home, "instances", "default"), { recursive: true });
|
||||
fs.writeFileSync(path.join(home, "instances", "default", "paperclip.json"), "{}\n");
|
||||
// An unrelated ENOTEMPTY must not cause permission changes or be swallowed.
|
||||
const error = Object.assign(new Error("unrelated nonempty directory"), { code: "ENOTEMPTY" });
|
||||
const removal = vi.spyOn(fs, "rmSync").mockImplementation(() => { throw error; });
|
||||
const permissionChange = vi.spyOn(fs, "chmodSync");
|
||||
|
||||
@@ -9,8 +9,7 @@ import path from "node:path";
|
||||
* in them read-only (`makeDirectoriesReadOnly` in
|
||||
* services/native-runtime/runtime-context.ts), and a run that is still
|
||||
* finishing when the worker exits can leave such a bundle under the worker's
|
||||
* home. Removing a file inside a read-only directory fails with `EACCES`
|
||||
* or, on macOS, the recursive removal can report `ENOTEMPTY` instead.
|
||||
* home. Removing a file inside a read-only directory fails with `EACCES`,
|
||||
* Vitest reports it as an unhandled error, and the shard fails after every
|
||||
* test passed. So on a permission error every directory in the tree is made
|
||||
* writable first and the removal is tried once more.
|
||||
@@ -23,8 +22,6 @@ export function removeTestHome(home: string): void {
|
||||
const permissionError = isPermissionError(error);
|
||||
if (!permissionError && (error as NodeJS.ErrnoException | null)?.code !== "ENOTEMPTY") throw error;
|
||||
const restored = makeDirectoriesWritable(home);
|
||||
// ENOTEMPTY also has unrelated causes; retry only after restoring an
|
||||
// actual read-only directory, and still surface a failed second removal.
|
||||
if (!permissionError && !restored) throw error;
|
||||
fs.rmSync(home, options);
|
||||
}
|
||||
@@ -51,7 +48,6 @@ function makeDirectoriesWritable(directory: string): boolean {
|
||||
fs.chmodSync(directory, stat.mode | 0o700);
|
||||
restored = true;
|
||||
} catch {
|
||||
// A directory that cannot be changed still fails the removal below, loudly.
|
||||
}
|
||||
}
|
||||
let entries: fs.Dirent[];
|
||||
|
||||
@@ -13,7 +13,6 @@ import { readConfigValueAtPath, writeConfigValueAtPath } from "./json-schema-sec
|
||||
type TemplateRow = typeof environmentCustomImageTemplates.$inferSelect;
|
||||
|
||||
export const ENVIRONMENT_CUSTOM_IMAGE_RUNTIME_CONFIG_BINDING_METADATA_KEY = "runtimeConfigBinding";
|
||||
/** Measured platform evidence is reserved to explicit server-side environment probes. */
|
||||
export const SANDBOX_PLATFORM_PROBE_METADATA_KEY = "paperclipSandboxPlatformProbes";
|
||||
export const ENVIRONMENT_CUSTOM_IMAGE_CONFIG_FINGERPRINT_EXCLUDED_PATHS = [
|
||||
"timeoutMs",
|
||||
|
||||
@@ -41,14 +41,12 @@ async function sandboxBinding(db: Db, environment: Environment, companyId: strin
|
||||
});
|
||||
if (parsed.driver !== "sandbox") return null;
|
||||
const image = parsed.config.image;
|
||||
// Names, mutable tags, provider defaults and snapshot names are not immutable identities.
|
||||
const template = selectedTemplate.value;
|
||||
if (!isImmutableImage(image) || ["snapshot", "template", "templateRef"].some(key => record(parsed.config)[key])
|
||||
|| (template && (template.templateKind !== "image" || template.bindingField !== "image"))) return null;
|
||||
return { baseConfigFingerprint: fingerprint(environment.config), runtimeConfigFingerprint: fingerprint(parsed.config as unknown as Record<string, unknown>), image, template };
|
||||
}
|
||||
|
||||
/** Read measured, company-scoped image evidence without leasing or contacting a provider. */
|
||||
export async function readSandboxPlatformQualification(db: Db, environment: Environment, companyId: string): Promise<PlatformFacts | null> {
|
||||
const proof = record(record(environment.metadata?.[SANDBOX_PLATFORM_PROBE_METADATA_KEY])[companyId]);
|
||||
if (proof.v !== 1 || proof.companyId !== companyId || proof.baseConfigFingerprint !== fingerprint(environment.config)) return null;
|
||||
|
||||
@@ -1144,8 +1144,6 @@ export function environmentService(db: Db) {
|
||||
values.metadata = userMetadata;
|
||||
} else {
|
||||
const replacement = userMetadata === null ? sql`null::jsonb` : sql`${JSON.stringify(userMetadata)}::jsonb`;
|
||||
// Preserve the current private subtree in the same statement. A route's
|
||||
// earlier read must never replace a newer concurrent probe receipt.
|
||||
metadataUpdate = sql`case when ${environments.metadata} ? ${SANDBOX_PLATFORM_PROBE_METADATA_KEY}
|
||||
then coalesce(${replacement}, '{}'::jsonb) || jsonb_build_object(
|
||||
${SANDBOX_PLATFORM_PROBE_METADATA_KEY}::text, ${environments.metadata}->${SANDBOX_PLATFORM_PROBE_METADATA_KEY})
|
||||
|
||||
@@ -45,8 +45,6 @@ function targetPlatform(platform: string, architecture: string, glibc = true, gl
|
||||
}
|
||||
|
||||
function resolveFixtureCodexCommand(home: string): string {
|
||||
// Vitest's global dependency paths can supply a foreign bridge before the
|
||||
// fixture wrapper. Reuse the existing Codex security test's closed Node seam.
|
||||
const source = `
|
||||
import { resolveCodexCommand } from ${JSON.stringify(new URL("../../../packages/paperclip-runner/src/drivers/codex/codex-command.ts", import.meta.url).href)};
|
||||
try { console.log(JSON.stringify({ command: resolveCodexCommand(${JSON.stringify(path.join(root!, "issuer.js"))}, { PATH: "/missing-codex" }, ${JSON.stringify(home)}) })); }
|
||||
|
||||
@@ -56,8 +56,6 @@ export function startLocalBrowserLogin(provider: "anthropic" | "openai", home: s
|
||||
async start(_command: string, onData: (chunk: string) => void): Promise<{ exitCode: number | null }> {
|
||||
let executable = "claude";
|
||||
if (provider === "openai") {
|
||||
// The installed Codex CLI is independent of the runner daemon's glibc floor.
|
||||
// Supported CLI hosts use owned resolution; other platforms keep PATH lookup.
|
||||
const legacyPlatform = !((process.platform === "linux" || process.platform === "darwin")
|
||||
&& (process.arch === "x64" || process.arch === "arm64"));
|
||||
try {
|
||||
|
||||
@@ -208,7 +208,6 @@ export function resolvePaperclipRunnerBinary(
|
||||
);
|
||||
}
|
||||
|
||||
/** Select controller-owned bytes for the actual remote host, never its controller. */
|
||||
export async function resolveRemotePaperclipRunnerBinary(input: {
|
||||
runner: CommandManagedRuntimeRunner;
|
||||
remoteCwd: string;
|
||||
@@ -224,8 +223,6 @@ export async function resolveRemotePaperclipRunnerBinary(input: {
|
||||
}
|
||||
const configured = input.configuredPath?.trim();
|
||||
if (configured && !isAbsolute(configured)) throw new Error("PAPERCLIP_RUNNER_REMOTE_BINARY_PATH must be an absolute path");
|
||||
// A same-host sandbox can use the supervisor's fresh development artifact.
|
||||
// Cross-platform targets must never inherit the controller's override.
|
||||
const controllerOverride = platform === process.platform && architecture === process.arch
|
||||
? process.env.PAPERCLIP_RUNNER_BINARY : undefined;
|
||||
const binary = configured || (controllerOverride
|
||||
|
||||
@@ -12354,8 +12354,6 @@ describe("runnerd provider runtime wiring", () => {
|
||||
{ version: "0.156.0", model: "gpt-6.1-sol", floor: null, recover: true },
|
||||
{ version: "0.158.0", model: "gpt-6.1-sol", floor: null, recover: true },
|
||||
])("lets sandbox Codex $version reach actual model verification ($model, recover=$recover)", async ({ version, model, recover }) => {
|
||||
// Version metadata is diagnostic. A working app-server reaches the model
|
||||
// turn instead of being rejected or replaced by a static CLI version floor.
|
||||
const preparedModel = recover ? resolvePaperclipRunnerNativeProviderInput({
|
||||
backend: "codex_app_server", adapterConfig: { provider: "codex", model }, codexCliVersion: version,
|
||||
}).model : model;
|
||||
|
||||
@@ -13385,7 +13385,6 @@ async function createRunnerdBackendWithinSessionClaim(
|
||||
} satisfies NativeSessionBackend & { bindManagedSession(session: NativeSession): NativeSession };
|
||||
}
|
||||
|
||||
/** Shared task/setup preparation; setup exercises the same remote artifact contract. */
|
||||
export function createRemoteNativeArtifactPreparation(input: {
|
||||
target: Extract<AdapterExecutionTarget, { kind: "remote" }>;
|
||||
runner: CommandManagedRuntimeRunner;
|
||||
@@ -13398,7 +13397,6 @@ export function createRemoteNativeArtifactPreparation(input: {
|
||||
runnerRemoteCodexNpmSpec?: string | null;
|
||||
model?: string | null;
|
||||
reuseRetainedRunner?: boolean;
|
||||
/** The selected Pi companion or bundled provider image verifies its target-platform artifact. */
|
||||
targetPlatformArtifactVerified?: boolean;
|
||||
trace?: NativeRunTrace;
|
||||
onLog?: (stream: "stdout" | "stderr", chunk: string) => Promise<void>;
|
||||
@@ -13451,9 +13449,6 @@ export function createRemoteNativeArtifactPreparation(input: {
|
||||
}
|
||||
const versionOutput = `${versionResult.stdout}\n${versionResult.stderr}`;
|
||||
const version = parseCodexCliVersion(versionOutput);
|
||||
// The install pin describes our tested image, not a CLI admission rule.
|
||||
// Ordinary installations reach the real app-server/model probe; a version
|
||||
// difference alone must neither fail setup nor replace a working CLI.
|
||||
if (version !== REMOTE_PROVIDER_PACK_PINS.codex && !reportedCodexVersions.has(version)) {
|
||||
reportedCodexVersions.add(version);
|
||||
await input.onLog?.(
|
||||
@@ -13463,9 +13458,6 @@ export function createRemoteNativeArtifactPreparation(input: {
|
||||
}
|
||||
};
|
||||
|
||||
// Image policy: keep one latest stable CLI installation shared by native and
|
||||
// local adapters. Preferred bin entries must point to that same installation;
|
||||
// never bake an older global CLI alongside a private runner-only version.
|
||||
const discoverPreinstalledExecutable = async (
|
||||
name: "paperclip-runnerd" | "codex",
|
||||
) => {
|
||||
@@ -13500,8 +13492,6 @@ export function createRemoteNativeArtifactPreparation(input: {
|
||||
};
|
||||
|
||||
const prepare = async (requiredMode: "dial_wss" | "listen_ws") => {
|
||||
// Compatibility metadata does not prove artifact identity. Reuse only the
|
||||
// exact controller-owned bytes when the controller artifact is available.
|
||||
const matchesControllerRunnerArtifact = async (executable: string): Promise<boolean> => {
|
||||
const expected = createHash("sha256")
|
||||
.update(readFileSync(controllerRunnerBinary))
|
||||
@@ -13523,7 +13513,6 @@ export function createRemoteNativeArtifactPreparation(input: {
|
||||
/^[a-f0-9]{64}\s/.test(probe.stdout) &&
|
||||
probe.stdout.trim().split(/\s+/)[0] === expected;
|
||||
} catch {
|
||||
// An unavailable checksum uses the verified staging path.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -13572,9 +13561,6 @@ export function createRemoteNativeArtifactPreparation(input: {
|
||||
}
|
||||
}
|
||||
if (!runnerArtifactPrepared) {
|
||||
// Upload the same artifact used for the controller identity. The server
|
||||
// vendors the runner under vendor/paperclip-runner/bin, so the package
|
||||
// development fallback cannot locate it in a deployed server.
|
||||
const sourceBinary = controllerRunnerBinary;
|
||||
if (!existsSync(sourceBinary)) {
|
||||
throw new Error("runner_remote_artifact_unavailable");
|
||||
|
||||
Reference in new issue
Block a user