refactor: dedupe cli config cron and install flows
This commit is contained in:
@@ -27,6 +27,46 @@ describe("secret ref resolver", () => {
|
||||
return dir;
|
||||
};
|
||||
|
||||
type ExecProviderConfig = {
|
||||
source: "exec";
|
||||
command: string;
|
||||
passEnv?: string[];
|
||||
jsonOnly?: boolean;
|
||||
allowSymlinkCommand?: boolean;
|
||||
trustedDirs?: string[];
|
||||
args?: string[];
|
||||
};
|
||||
|
||||
function createExecProviderConfig(
|
||||
command: string,
|
||||
overrides: Partial<ExecProviderConfig> = {},
|
||||
): ExecProviderConfig {
|
||||
return {
|
||||
source: "exec",
|
||||
command,
|
||||
passEnv: ["PATH"],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveExecSecret(
|
||||
command: string,
|
||||
overrides: Partial<ExecProviderConfig> = {},
|
||||
): Promise<string> {
|
||||
return resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: createExecProviderConfig(command, overrides),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-secrets-resolve-"));
|
||||
const sharedExecDir = path.join(fixtureRoot, "shared-exec");
|
||||
@@ -134,22 +174,7 @@ describe("secret ref resolver", () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = await resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: execProtocolV1ScriptPath,
|
||||
passEnv: ["PATH"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
const value = await resolveExecSecret(execProtocolV1ScriptPath);
|
||||
expect(value).toBe("value:openai/api-key");
|
||||
});
|
||||
|
||||
@@ -158,23 +183,7 @@ describe("secret ref resolver", () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = await resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: execPlainScriptPath,
|
||||
passEnv: ["PATH"],
|
||||
jsonOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
const value = await resolveExecSecret(execPlainScriptPath, { jsonOnly: false });
|
||||
expect(value).toBe("plain-secret");
|
||||
});
|
||||
|
||||
@@ -210,25 +219,9 @@ describe("secret ref resolver", () => {
|
||||
const symlinkPath = path.join(root, "resolver-link.mjs");
|
||||
await fs.symlink(execPlainScriptPath, symlinkPath);
|
||||
|
||||
await expect(
|
||||
resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: symlinkPath,
|
||||
passEnv: ["PATH"],
|
||||
jsonOnly: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
).rejects.toThrow("must not be a symlink");
|
||||
await expect(resolveExecSecret(symlinkPath, { jsonOnly: false })).rejects.toThrow(
|
||||
"must not be a symlink",
|
||||
);
|
||||
});
|
||||
|
||||
it("allows symlink command paths when allowSymlinkCommand is enabled", async () => {
|
||||
@@ -240,25 +233,11 @@ describe("secret ref resolver", () => {
|
||||
await fs.symlink(execPlainScriptPath, symlinkPath);
|
||||
const trustedRoot = await fs.realpath(fixtureRoot);
|
||||
|
||||
const value = await resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: symlinkPath,
|
||||
passEnv: ["PATH"],
|
||||
jsonOnly: false,
|
||||
allowSymlinkCommand: true,
|
||||
trustedDirs: [trustedRoot],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
const value = await resolveExecSecret(symlinkPath, {
|
||||
jsonOnly: false,
|
||||
allowSymlinkCommand: true,
|
||||
trustedDirs: [trustedRoot],
|
||||
});
|
||||
expect(value).toBe("plain-secret");
|
||||
});
|
||||
|
||||
@@ -287,44 +266,15 @@ describe("secret ref resolver", () => {
|
||||
await fs.symlink(targetCommand, symlinkCommand);
|
||||
const trustedRoot = await fs.realpath(root);
|
||||
|
||||
await expect(
|
||||
resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: symlinkCommand,
|
||||
args: ["brew"],
|
||||
passEnv: ["PATH"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
).rejects.toThrow("must not be a symlink");
|
||||
|
||||
const value = await resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: symlinkCommand,
|
||||
args: ["brew"],
|
||||
allowSymlinkCommand: true,
|
||||
trustedDirs: [trustedRoot],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
await expect(resolveExecSecret(symlinkCommand, { args: ["brew"] })).rejects.toThrow(
|
||||
"must not be a symlink",
|
||||
);
|
||||
|
||||
const value = await resolveExecSecret(symlinkCommand, {
|
||||
args: ["brew"],
|
||||
allowSymlinkCommand: true,
|
||||
trustedDirs: [trustedRoot],
|
||||
});
|
||||
expect(value).toBe("brew:openai/api-key");
|
||||
});
|
||||
|
||||
@@ -337,25 +287,11 @@ describe("secret ref resolver", () => {
|
||||
await fs.symlink(execPlainScriptPath, symlinkPath);
|
||||
|
||||
await expect(
|
||||
resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: symlinkPath,
|
||||
passEnv: ["PATH"],
|
||||
jsonOnly: false,
|
||||
allowSymlinkCommand: true,
|
||||
trustedDirs: [root],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
resolveExecSecret(symlinkPath, {
|
||||
jsonOnly: false,
|
||||
allowSymlinkCommand: true,
|
||||
trustedDirs: [root],
|
||||
}),
|
||||
).rejects.toThrow("outside trustedDirs");
|
||||
});
|
||||
|
||||
@@ -363,73 +299,27 @@ describe("secret ref resolver", () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
await expect(
|
||||
resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: execProtocolV2ScriptPath,
|
||||
passEnv: ["PATH"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
).rejects.toThrow("protocolVersion must be 1");
|
||||
await expect(resolveExecSecret(execProtocolV2ScriptPath)).rejects.toThrow(
|
||||
"protocolVersion must be 1",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects exec refs when response omits requested id", async () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
await expect(
|
||||
resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: execMissingIdScriptPath,
|
||||
passEnv: ["PATH"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
).rejects.toThrow('response missing id "openai/api-key"');
|
||||
await expect(resolveExecSecret(execMissingIdScriptPath)).rejects.toThrow(
|
||||
'response missing id "openai/api-key"',
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects exec refs with invalid JSON when jsonOnly is true", async () => {
|
||||
if (process.platform === "win32") {
|
||||
return;
|
||||
}
|
||||
await expect(
|
||||
resolveSecretRefString(
|
||||
{ source: "exec", provider: "execmain", id: "openai/api-key" },
|
||||
{
|
||||
config: {
|
||||
secrets: {
|
||||
providers: {
|
||||
execmain: {
|
||||
source: "exec",
|
||||
command: execInvalidJsonScriptPath,
|
||||
passEnv: ["PATH"],
|
||||
jsonOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
).rejects.toThrow("returned invalid JSON");
|
||||
await expect(resolveExecSecret(execInvalidJsonScriptPath, { jsonOnly: true })).rejects.toThrow(
|
||||
"returned invalid JSON",
|
||||
);
|
||||
});
|
||||
|
||||
it("supports file singleValue mode with id=value", async () => {
|
||||
|
||||
Reference in New Issue
Block a user