mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 12:04:41 +01:00
fix(hermes): pin v7 permission policy in the independent server launch
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
b0f54fc1a2
commit
2922f65ba1
3 files changed
+36
-4
No files matched your search
@@ -1,4 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildNativeExecutionInput, isNativeAcpxPermissionModePinned } from "./native-execution-input.js";
|
||||
import { nativeRuntimeContextFixture } from "./runtime-context.test-fixture.js";
|
||||
import { parseNativeExecutionInput } from "../../vendor/paperclip-runner/index.js";
|
||||
import { projectHermesConnection, restoreHermesCredential } from "./hermes-connection.js";
|
||||
import type { AiConnectionMetadata } from "@paperclipai/shared";
|
||||
describe("Hermes Connections projection", () => {
|
||||
@@ -63,3 +66,25 @@ describe("Hermes Connections projection", () => {
|
||||
expect(() => restoreHermesCredential("xai", original, JSON.stringify(refreshed))).toThrow("account identity");
|
||||
});
|
||||
});
|
||||
|
||||
// Use the server constructor and the same policy projection as its transport factory.
|
||||
describe("server-launched Hermes permission policy", () => {
|
||||
it.each(["approve-all", "approve-reads"] as const)("pins v7 %s policy before native transport admission", permissionMode => {
|
||||
const input = buildNativeExecutionInput({
|
||||
companyId: "company", runId: "run", agentId: "agent",
|
||||
issue: { id: "issue", identifier: "HERMES-1", title: "Server launch", description: null, workMode: "standard" },
|
||||
taskPrompt: "Run the task.", workspace: { id: "workspace", cwd: "/workspace", repoUrl: null, repoRef: null, branchName: null },
|
||||
normalizedSessionId: null, provider: "acpx", acpxAgent: "hermes", model: "hermes-fixture",
|
||||
hermesConnectionFingerprint: "1".repeat(64), acpxPermissionMode: permissionMode,
|
||||
completionContract: { id: "contract", sha256: "a".repeat(64), schemaVersion: "paperclip.run-result.v1",
|
||||
contract: { revision: "1", objective: "Run the task.", criteria: [{ id: "output", requirement: "Run the task." }] } },
|
||||
runtimeContext: nativeRuntimeContextFixture(),
|
||||
});
|
||||
expect(input.schema).toBe("paperclip.native-execution-input.v7");
|
||||
expect(input.provider).toMatchObject({ kind: "acpx", agent: "hermes", permissionMode });
|
||||
expect(isNativeAcpxPermissionModePinned(input)).toBe(true);
|
||||
expect(isNativeAcpxPermissionModePinned(parseNativeExecutionInput({ ...input, schema: "paperclip.native-execution-input.v6" }))).toBe(true);
|
||||
expect(isNativeAcpxPermissionModePinned({ ...input, schema: "paperclip.native-execution-input.v3" })).toBe(false);
|
||||
expect(isNativeAcpxPermissionModePinned({ ...input, provider: { kind: "codex", model: null, approvalPolicy: "never" } })).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
NativeAcpxAgent,
|
||||
NativeAcpxPermissionMode,
|
||||
NativeCodexApprovalPolicy,
|
||||
NativeExecutionInput,
|
||||
NativeExecutionInputV5,
|
||||
NativeExecutionInputV6,
|
||||
NativeExecutionInputV7,
|
||||
@@ -33,6 +34,14 @@ const NATIVE_GITHUB_ATTACHMENT_RECOVERY_GUIDANCE = [
|
||||
"A task URL missing from your prompt or tool results is not evidence that no task link can be provided; do not claim that a link is unavailable merely because you cannot see its URL. Do not invent a URL or promise that a link will appear. Briefly explain the unavailable input and ask the user to attach it directly to this Paperclip task or paste the needed text. Never infer the file's contents or substitute an older file.",
|
||||
].join("\n");
|
||||
|
||||
/** Persisted provider policy is authoritative only in the explicit permission contracts. */
|
||||
export function isNativeAcpxPermissionModePinned(input: Pick<NativeExecutionInput, "schema" | "provider">): boolean {
|
||||
return input.provider.kind === "acpx" && [
|
||||
"paperclip.native-execution-input.v4", "paperclip.native-execution-input.v5",
|
||||
"paperclip.native-execution-input.v6", "paperclip.native-execution-input.v7",
|
||||
].includes(input.schema);
|
||||
}
|
||||
|
||||
/** Closed constructor: callers cannot spread legacy context or environment data. */
|
||||
export interface BuildNativeExecutionInput {
|
||||
companyId: string;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isNativeAcpxPermissionModePinned } from "./native-execution-input.js";
|
||||
import { agents } from "@paperclipai/db";
|
||||
import { dotRunnerBroker } from "../dot-runner-broker.js";
|
||||
import { configuredEnvironment } from "../../vendor/paperclip-runner/index.js";
|
||||
@@ -12961,10 +12962,7 @@ async function createRunnerdBackendWithinSessionClaim(
|
||||
acpxCandidateProfile: resolveAcpxQualification(input.execution.provider, process.env),
|
||||
acpxPermissionMode: input.execution.provider.permissionMode,
|
||||
acpxMode: input.execution.provider.mode,
|
||||
acpxPermissionModePinned:
|
||||
input.execution.schema === "paperclip.native-execution-input.v4" ||
|
||||
input.execution.schema === "paperclip.native-execution-input.v5" ||
|
||||
input.execution.schema === "paperclip.native-execution-input.v6",
|
||||
acpxPermissionModePinned: isNativeAcpxPermissionModePinned(input.execution),
|
||||
acpxRuntimeDirectory: remoteRunnerFilesystemRoot
|
||||
? posix.join(remoteRunnerFilesystemRoot, "acpx")
|
||||
: resolve(
|
||||
|
||||
Reference in new issue
Block a user