mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-07 16:35:48 +01:00
PAP-10287 redact catalog approval secrets
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
59fdc1b850
commit
8d779318fd
2 files changed
+31
-2
No files matched your search
@@ -386,6 +386,8 @@ describe("teams CLI commands", () => {
|
||||
"manager-1",
|
||||
"--collision-strategy",
|
||||
"rename",
|
||||
"--secret-value",
|
||||
"agent:cto:OPENAI_API_KEY=sk-live-secret",
|
||||
"--company-id",
|
||||
"company-1",
|
||||
"--request-approval-on-forbidden",
|
||||
@@ -406,6 +408,7 @@ describe("teams CLI commands", () => {
|
||||
body: JSON.stringify({
|
||||
targetManagerAgentId: "manager-1",
|
||||
collisionStrategy: "rename",
|
||||
secretValues: { "agent:cto:OPENAI_API_KEY": "sk-live-secret" },
|
||||
}),
|
||||
}),
|
||||
);
|
||||
@@ -443,8 +446,15 @@ describe("teams CLI commands", () => {
|
||||
companyId: "company-1",
|
||||
catalogRef: "product-engineering",
|
||||
deniedReason: "Missing permission: can create agents",
|
||||
options: {
|
||||
targetManagerAgentId: "manager-1",
|
||||
collisionStrategy: "rename",
|
||||
secretValues: { "agent:cto:OPENAI_API_KEY": "[redacted]" },
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(JSON.stringify(approvalPayload)).not.toContain("sk-live-secret");
|
||||
expect(String(logSpy.mock.calls[0]?.[0])).not.toContain("sk-live-secret");
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -373,6 +373,7 @@ const INSTALL_APPROVAL_FALLBACK_MESSAGES = [
|
||||
"missing permission: agents:create",
|
||||
"missing permission: can create agents",
|
||||
];
|
||||
const SECRET_VALUE_REDACTION = "[redacted]";
|
||||
|
||||
function shouldRequestInstallApproval(error: unknown, opts: TeamInstallOptions): error is ApiRequestError {
|
||||
if (!(opts.requestApprovalOnForbidden || isPaperclipTaskRun())) return false;
|
||||
@@ -395,6 +396,8 @@ async function requestInstallApproval(
|
||||
if (!ctx.companyId) throw new Error("Company ID is required.");
|
||||
const trimmedRef = catalogRef.trim();
|
||||
const issueIds = resolveApprovalIssueIds(opts);
|
||||
const approvalInstallOptions = omitInstallSecretValues(installOptions);
|
||||
const returnedInstallOptions = redactInstallSecretValues(installOptions);
|
||||
const payload = {
|
||||
type: "request_board_approval",
|
||||
issueIds,
|
||||
@@ -412,7 +415,7 @@ async function requestInstallApproval(
|
||||
installAttempt: {
|
||||
companyId: ctx.companyId,
|
||||
catalogRef: trimmedRef,
|
||||
options: installOptions,
|
||||
options: approvalInstallOptions,
|
||||
deniedReason: error.message,
|
||||
},
|
||||
},
|
||||
@@ -427,12 +430,28 @@ async function requestInstallApproval(
|
||||
installAttempt: {
|
||||
companyId: ctx.companyId,
|
||||
catalogRef: trimmedRef,
|
||||
options: installOptions,
|
||||
options: returnedInstallOptions,
|
||||
deniedReason: error.message,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function omitInstallSecretValues(options: CatalogTeamInstallOptions): CatalogTeamInstallOptions {
|
||||
if (!options.secretValues) return options;
|
||||
const { secretValues: _secretValues, ...safeOptions } = options;
|
||||
return safeOptions;
|
||||
}
|
||||
|
||||
function redactInstallSecretValues(options: CatalogTeamInstallOptions): CatalogTeamInstallOptions {
|
||||
if (!options.secretValues) return options;
|
||||
return {
|
||||
...options,
|
||||
secretValues: Object.fromEntries(
|
||||
Object.keys(options.secretValues).map((key) => [key, SECRET_VALUE_REDACTION]),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveApprovalIssueIds(opts: TeamInstallOptions): string[] | undefined {
|
||||
const issueId = opts.approvalIssueId?.trim() || process.env.PAPERCLIP_TASK_ID?.trim();
|
||||
if (!issueId) return undefined;
|
||||
|
||||
Reference in new issue
Block a user