mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-20 22:01:39 +00:00
fix: keep CLI prepare credentials private
This commit is contained in:
@@ -412,6 +412,70 @@ describe("shouldSkipLocalCliCredentialEpoch", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("does not expose auth profile credentials to non-Gemini CLI prepare hooks", async () => {
|
||||
const { dir, sessionFile } = createSessionFile();
|
||||
const agentDir = path.join(dir, "agents", "main", "agent");
|
||||
const authProfileId = "test-cli:secret";
|
||||
const prepareExecution = vi.fn(async () => undefined);
|
||||
fs.mkdirSync(agentDir, { recursive: true });
|
||||
saveAuthProfileStore(
|
||||
{
|
||||
version: 1,
|
||||
profiles: {
|
||||
[authProfileId]: {
|
||||
type: "api_key",
|
||||
provider: "test-cli",
|
||||
key: "secret-key",
|
||||
},
|
||||
},
|
||||
},
|
||||
agentDir,
|
||||
);
|
||||
cliBackendsTesting.setDepsForTest({
|
||||
resolvePluginSetupCliBackend: () => undefined,
|
||||
resolveRuntimeCliBackends: () => [
|
||||
{
|
||||
id: "test-cli",
|
||||
pluginId: "test-plugin",
|
||||
bundleMcp: false,
|
||||
prepareExecution,
|
||||
config: {
|
||||
command: "test-cli",
|
||||
args: ["--prompt", "{prompt}"],
|
||||
output: "json",
|
||||
input: "arg",
|
||||
sessionMode: "existing",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
try {
|
||||
await prepareCliRunContext({
|
||||
sessionId: "session-test",
|
||||
sessionKey: "agent:main:main",
|
||||
sessionFile,
|
||||
workspaceDir: dir,
|
||||
prompt: "latest ask",
|
||||
provider: "test-cli",
|
||||
model: "test-model",
|
||||
timeoutMs: 1_000,
|
||||
runId: "run-test-non-gemini-credential-boundary",
|
||||
authProfileId,
|
||||
config: {},
|
||||
});
|
||||
|
||||
expect(prepareExecution).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
authProfileId,
|
||||
}),
|
||||
);
|
||||
expect(prepareExecution.mock.calls[0]?.[0]).not.toHaveProperty("authCredential");
|
||||
} finally {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("prepares side questions without agent-turn context, tools, hooks, or reusable sessions", async () => {
|
||||
const { dir, sessionFile } = createSessionFile();
|
||||
appendTranscriptEntry(sessionFile, {
|
||||
|
||||
@@ -463,20 +463,28 @@ export async function prepareCliRunContext(
|
||||
: undefined,
|
||||
warn: (message) => cliBackendLog.warn(message),
|
||||
});
|
||||
const preparedExecution = await backendResolved.prepareExecution?.({
|
||||
const prepareExecutionContext = {
|
||||
config: params.config,
|
||||
workspaceDir,
|
||||
agentDir,
|
||||
provider: params.provider,
|
||||
modelId,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
// Private bridge for bundled Gemini CLI. This is intentionally not part
|
||||
// of the public Plugin SDK until a credential-forwarding contract exists.
|
||||
authCredential,
|
||||
executionMode,
|
||||
} as Parameters<NonNullable<typeof backendResolved.prepareExecution>>[0] & {
|
||||
authCredential?: AuthProfileCredential;
|
||||
});
|
||||
} as Parameters<NonNullable<typeof backendResolved.prepareExecution>>[0];
|
||||
const preparedExecution = await backendResolved.prepareExecution?.(
|
||||
(backendResolved.id === "google-gemini-cli"
|
||||
? {
|
||||
...prepareExecutionContext,
|
||||
// Private bridge for bundled Gemini CLI. This is intentionally not
|
||||
// part of the public Plugin SDK until a credential-forwarding
|
||||
// contract exists.
|
||||
authCredential,
|
||||
}
|
||||
: prepareExecutionContext) as typeof prepareExecutionContext & {
|
||||
authCredential?: AuthProfileCredential;
|
||||
},
|
||||
);
|
||||
const skipLocalCredentialEpoch = shouldSkipLocalCliCredentialEpoch({
|
||||
authEpochMode: backendResolved.authEpochMode,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
|
||||
Reference in New Issue
Block a user