mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 17:53:39 +00:00
fix(ci): clarify security review comments (#152578)
* fix(ci): clarify security review warning comments * fix(ci): simplify security approval comments * fix(ci): remove hyphen from maintainer security warning * fix(ci): list dependency changes in maintainer warnings * fix(ci): simplify dependency graph filename lists
This commit is contained in:
parent
90ab8619b3
commit
5a2bc22ce9
4 changed files with 110 additions and 68 deletions
|
|
@ -157,24 +157,44 @@ export function isDependencyGuardMarkerComment(comment, marker, trustedAuthors)
|
|||
return Boolean(login && trustedAuthors.has(login) && comment.body?.includes(marker));
|
||||
}
|
||||
|
||||
function renderApprovedDependencyComment(approval) {
|
||||
function renderDependencyChangeLines({
|
||||
lockfileChanges,
|
||||
dependencyFiles = [],
|
||||
dependencyManifestChanges,
|
||||
}) {
|
||||
const files = new Set([...lockfileChanges, ...dependencyFiles]);
|
||||
for (const change of dependencyManifestChanges) {
|
||||
if (change.previousPath) {
|
||||
files.add(change.previousPath);
|
||||
}
|
||||
files.add(change.path);
|
||||
}
|
||||
return [...files].map((path) => `- ${markdownCode(path)}`);
|
||||
}
|
||||
|
||||
function renderApprovedDependencyComment(approval, changes) {
|
||||
return [
|
||||
dependencyGraphGuardMarker,
|
||||
"",
|
||||
approval.kind === "author"
|
||||
? "### Dependency graph changes noted"
|
||||
: "### Dependency graph changes approved",
|
||||
? "### ⚠️ Dependency graph changes"
|
||||
: "### ✅ Dependency graph changes approved",
|
||||
"",
|
||||
approval.kind === "author"
|
||||
? "This PR changes dependency resolution. The guard is informational because the PR author has repository Maintain or Admin access."
|
||||
: "A maintainer approved this revision with an explicit dependency approval comment. SecOps approval is not required.",
|
||||
? "This PR makes dependency graph changes. This comment is informational because the PR author has repository Maintain or Admin access."
|
||||
: "A maintainer approved this revision with an explicit dependency approval comment.",
|
||||
"",
|
||||
`- Current SHA: ${markdownCode(approval.sha)}`,
|
||||
`- Maintainer: @${sanitizeGuardDisplayValue(approval.login)}`,
|
||||
`- Repository role: ${markdownCode(approval.role)}`,
|
||||
...(approval.kind === "comment" ? [`- Approval comment: ${approval.url}`] : []),
|
||||
"",
|
||||
"Review resolved package changes and dependency policy before merging. A later push requires a fresh approval comment for an external contributor's PR.",
|
||||
...(approval.kind === "author"
|
||||
? ["These dependency graph changes were made:", ...renderDependencyChangeLines(changes), ""]
|
||||
: []),
|
||||
approval.kind === "author"
|
||||
? "Carefully review these changes before merging."
|
||||
: "A later push requires a fresh approval comment for an external contributor's PR.",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
|
|
@ -254,13 +274,6 @@ export function renderBlockedDependencyComment({
|
|||
}) {
|
||||
const safeBranch = sanitizeGuardDisplayValue(baseBranch ?? "main");
|
||||
const baseRef = shellQuote(`origin/${safeBranch}`);
|
||||
const reasons = [];
|
||||
for (const path of new Set([...lockfileChanges, ...dependencyFiles])) {
|
||||
reasons.push(`- ${markdownCode(path)} changed.`);
|
||||
}
|
||||
for (const change of dependencyManifestChanges) {
|
||||
reasons.push(renderManifestChangeLine(change));
|
||||
}
|
||||
const autoscrubLines = renderAutoscrubStatusLines(autoscrubStatus);
|
||||
const removalSteps =
|
||||
lockfileChanges.length > 0
|
||||
|
|
@ -279,12 +292,14 @@ export function renderBlockedDependencyComment({
|
|||
return [
|
||||
dependencyGraphGuardMarker,
|
||||
"",
|
||||
"### Maintainer dependency review required",
|
||||
"### ⚠️ Maintainer dependency review required",
|
||||
"",
|
||||
"This external contributor PR changes dependency resolution. A maintainer with repository Maintain or Admin access must review the resolved packages and dependency policy before merging.",
|
||||
"This external contributor PR changes the dependency graph. A maintainer must review these changes before merging.",
|
||||
"",
|
||||
"Detected dependency graph changes:",
|
||||
...reasons,
|
||||
`Current SHA: ${markdownCode(headSha ?? "<head-sha>")}`,
|
||||
"",
|
||||
"These dependency graph changes were made:",
|
||||
...renderDependencyChangeLines({ lockfileChanges, dependencyFiles, dependencyManifestChanges }),
|
||||
...autoscrubLines,
|
||||
...removalSteps,
|
||||
"",
|
||||
|
|
@ -294,9 +309,7 @@ export function renderBlockedDependencyComment({
|
|||
dependencyApprovalCommand,
|
||||
"```",
|
||||
"",
|
||||
"Post the comment after this guard notice identifies the current head SHA below. Do not edit an earlier comment. A normal GitHub Approve review does not satisfy this check. SecOps approval is not required; this check updates automatically.",
|
||||
"",
|
||||
`Current head SHA: ${markdownCode(headSha ?? "<head-sha>")}. A later push requires a fresh approval comment.`,
|
||||
"A later push requires a fresh approval comment.",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +327,10 @@ function renderAutoscrubStatusLines(status) {
|
|||
return [
|
||||
"",
|
||||
"Auto-scrub was not attempted because this PR changes package manifest dependency graph fields:",
|
||||
...status.changes.map(renderManifestChangeLine),
|
||||
...renderDependencyChangeLines({
|
||||
lockfileChanges: [],
|
||||
dependencyManifestChanges: status.changes,
|
||||
}),
|
||||
"",
|
||||
"Dependency graph changes require maintainer review. Please remove lockfile changes manually if they are not needed.",
|
||||
];
|
||||
|
|
@ -337,15 +353,6 @@ function renderAutoscrubStatusLines(status) {
|
|||
return [];
|
||||
}
|
||||
|
||||
function renderManifestChangeLine(change) {
|
||||
const location = change.previousPath
|
||||
? `${markdownCode(change.previousPath)} moved to ${markdownCode(change.path)}`
|
||||
: markdownCode(change.path);
|
||||
const fields =
|
||||
change.fields.length > 0 ? ` changed ${change.fields.map(markdownCode).join(", ")}` : "";
|
||||
return `- ${location}${fields}.`;
|
||||
}
|
||||
|
||||
export function githubApi(token, options = {}) {
|
||||
const api = createGitHubApi(token, { ...options, userAgent: "openclaw-dependency-guard" });
|
||||
return {
|
||||
|
|
@ -707,7 +714,14 @@ export async function reviewDependencyChanges(
|
|||
dependencyGraphChanges,
|
||||
headSha: pullRequest.head.sha,
|
||||
})
|
||||
: withApprovalRequest(guard, renderApprovedDependencyComment(guard.approval));
|
||||
: withApprovalRequest(
|
||||
guard,
|
||||
renderApprovedDependencyComment(guard.approval, {
|
||||
lockfileChanges,
|
||||
dependencyFiles,
|
||||
dependencyManifestChanges,
|
||||
}),
|
||||
);
|
||||
await upsertComment(existingGuardComment, body);
|
||||
await writeSummary(body);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -14,25 +14,56 @@ function code(value) {
|
|||
}
|
||||
|
||||
function renderComment({ changes, pullRequest, approval }) {
|
||||
if (changes.length > 0 && approval?.kind === "comment") {
|
||||
return [
|
||||
marker,
|
||||
"",
|
||||
"### ✅ Maintainer security changes approved",
|
||||
"",
|
||||
"A maintainer approved this revision with an explicit security approval comment.",
|
||||
"",
|
||||
`- Current SHA: ${code(approval.sha)}`,
|
||||
`- Maintainer: @${sanitizeGuardDisplayValue(approval.login)}`,
|
||||
`- Repository role: ${code(approval.role)}`,
|
||||
`- Approval comment: ${approval.url}`,
|
||||
"",
|
||||
"A later push requires a fresh approval comment for an external contributor's PR.",
|
||||
].join("\n");
|
||||
}
|
||||
const heading =
|
||||
changes.length === 0
|
||||
? "Security-sensitive guard cleared"
|
||||
: approval?.kind === "author"
|
||||
? "Security-sensitive changes noted"
|
||||
: approval
|
||||
? "Maintainer security review complete"
|
||||
: "Maintainer security review required";
|
||||
const lines = [
|
||||
marker,
|
||||
"",
|
||||
`### ${heading}`,
|
||||
"",
|
||||
`Current revision: ${code(pullRequest.head.sha)}`,
|
||||
];
|
||||
? "⚠️ Security sensitive changes"
|
||||
: "⚠️ Maintainer security review required";
|
||||
const lines = [marker, "", `### ${heading}`, ""];
|
||||
if (changes.length > 0 && approval?.kind === "author") {
|
||||
lines.push(
|
||||
"This PR makes security sensitive changes. This comment is informational because the PR author has repository Maintain or Admin access.",
|
||||
"",
|
||||
`- Current SHA: ${code(pullRequest.head.sha)}`,
|
||||
`- Maintainer: @${sanitizeGuardDisplayValue(approval.login)}`,
|
||||
`- Repository role: ${code(approval.role)}`,
|
||||
);
|
||||
} else if (changes.length > 0 && !approval) {
|
||||
lines.push(
|
||||
"This external contributor PR changes sensitive security components. A maintainer must review these changes before merging.",
|
||||
"",
|
||||
`Current SHA: ${code(pullRequest.head.sha)}`,
|
||||
);
|
||||
} else {
|
||||
lines.push(`Current revision: ${code(pullRequest.head.sha)}`);
|
||||
}
|
||||
if (changes.length === 0) {
|
||||
lines.push("", "This PR no longer changes files in the maintainer security-review tier.");
|
||||
} else {
|
||||
lines.push("", "Review these security responsibilities:", "");
|
||||
lines.push(
|
||||
"",
|
||||
approval?.kind === "author"
|
||||
? "These security sensitive changes were made:"
|
||||
: "These sensitive security changes were made:",
|
||||
"",
|
||||
);
|
||||
for (const change of changes.slice(0, 25)) {
|
||||
lines.push(`- ${code(change.path)}: ${change.reason}`);
|
||||
}
|
||||
|
|
@ -41,28 +72,25 @@ function renderComment({ changes, pullRequest, approval }) {
|
|||
}
|
||||
lines.push("");
|
||||
if (approval?.kind === "author") {
|
||||
lines.push(
|
||||
`Informational: author @${approval.login} has repository ${code(approval.role)} access.`,
|
||||
);
|
||||
} else if (approval) {
|
||||
lines.push(
|
||||
`@${approval.login} approved this revision with ${code("/allow-security-sensitive-change")} and repository ${code(approval.role)} access.`,
|
||||
);
|
||||
lines.push("Carefully review these changes before merging.");
|
||||
} else {
|
||||
lines.push(
|
||||
"A GitHub user account with repository `maintain` or `admin` access must post a new comment containing `/allow-security-sensitive-change` after this notice names the current revision. SecOps approval is not required for this tier.",
|
||||
"Use only the command, or include `/allow-dependencies-change` on a separate line if both guards need approval. A normal GitHub Approve review does not satisfy this check.",
|
||||
"After reviewing the changes, post a new PR comment containing only approval commands, each on its own line:",
|
||||
"",
|
||||
"```text",
|
||||
"/allow-security-sensitive-change",
|
||||
"```",
|
||||
"",
|
||||
"A later push requires a fresh approval comment.",
|
||||
);
|
||||
}
|
||||
}
|
||||
if (changes.length === 0) {
|
||||
lines.push(
|
||||
"",
|
||||
"A later push requires a new approval comment after the notice updates. Editing an old comment does not renew approval; deleting the command removes its approval.",
|
||||
"Separate CODEOWNERS requirements still apply to security policy and enforcement files.",
|
||||
);
|
||||
}
|
||||
lines.push(
|
||||
"",
|
||||
"Separate CODEOWNERS requirements still apply to security policy and enforcement files.",
|
||||
);
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue