


























11name: Dependency Change Awareness
2233on:
4-pull_request_target: # zizmor: ignore[dangerous-triggers] metadata-only workflow; no checkout or untrusted code execution
4+pull_request_target: # zizmor: ignore[dangerous-triggers] checks trusted base script only; never checks out PR head
55types: [opened, reopened, synchronize, ready_for_review]
6677permissions:
8+contents: read
89pull-requests: write
910issues: write
1011@@ -18,159 +19,15 @@ jobs:
1819runs-on: ubuntu-24.04
1920timeout-minutes: 5
2021steps:
21- - name: Label and comment on dependency changes
22-uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
22+ - name: Check out trusted base workflow scripts
23+uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2324with:
24-script: |
25- const marker = "<!-- openclaw:dependency-change-awareness -->";
26- const labelName = "dependencies-changed";
27- const maxListedFiles = 25;
28- const pullRequest = context.payload.pull_request;
29-30- if (!pullRequest) {
31- core.info("No pull_request payload found; skipping.");
32- return;
33- }
34-35- const isDependencyFile = (filename) =>
36- filename === "package.json" ||
37- filename === "package-lock.json" ||
38- filename === "npm-shrinkwrap.json" ||
39- filename === "pnpm-lock.yaml" ||
40- filename === "pnpm-workspace.yaml" ||
41- filename === "ui/package.json" ||
42- filename.startsWith("patches/") ||
43- /^packages\/[^/]+\/package\.json$/u.test(filename) ||
44- /^extensions\/[^/]+\/package-lock\.json$/u.test(filename) ||
45- /^extensions\/[^/]+\/npm-shrinkwrap\.json$/u.test(filename) ||
46- /^extensions\/[^/]+\/package\.json$/u.test(filename);
47-48- const sanitizeDisplayValue = (value) =>
49- String(value)
50- .replace(/[\u0000-\u001f\u007f]/gu, "?")
51- .slice(0, 240);
52- const markdownCode = (value) =>
53- `\`${sanitizeDisplayValue(value).replaceAll("`", "\\`")}\``;
54- const ignoreUnavailableWritePermission = (action) => (error) => {
55- if (error?.status === 403) {
56- core.warning(
57- `Skipping dependency change ${action}; token does not have issue write permission.`,
58- );
59- return;
60- }
61- if (error?.status === 404 || error?.status === 422) {
62- core.warning(`Dependency change ${action} is unavailable.`);
63- return;
64- }
65- throw error;
66- };
67-68- const files = await github.paginate(github.rest.pulls.listFiles, {
69- owner: context.repo.owner,
70- repo: context.repo.repo,
71- pull_number: pullRequest.number,
72- per_page: 100,
73- });
74- const dependencyFiles = files
75- .map((file) => file.filename)
76- .filter((filename) => typeof filename === "string" && isDependencyFile(filename))
77- .sort((left, right) => left.localeCompare(right));
78-79- const comments = await github.paginate(github.rest.issues.listComments, {
80- owner: context.repo.owner,
81- repo: context.repo.repo,
82- issue_number: pullRequest.number,
83- per_page: 100,
84- });
85- const existingComment = comments.find(
86- (comment) =>
87- comment.user?.login === "github-actions[bot]" && comment.body?.includes(marker),
88- );
89-90- const labels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
91- owner: context.repo.owner,
92- repo: context.repo.repo,
93- issue_number: pullRequest.number,
94- per_page: 100,
95- });
96- const hasLabel = labels.some((label) => label.name === labelName);
97-98- if (dependencyFiles.length === 0) {
99- if (hasLabel) {
100- await github.rest.issues.removeLabel({
101- owner: context.repo.owner,
102- repo: context.repo.repo,
103- issue_number: pullRequest.number,
104- name: labelName,
105- }).catch(ignoreUnavailableWritePermission("label removal"));
106- }
107- if (existingComment) {
108- await github.rest.issues.deleteComment({
109- owner: context.repo.owner,
110- repo: context.repo.repo,
111- comment_id: existingComment.id,
112- }).catch(ignoreUnavailableWritePermission("comment deletion"));
113- }
114- await core.summary
115- .addHeading("Dependency Change Awareness")
116- .addRaw("No dependency-related file changes detected.")
117- .write();
118- core.info("No dependency-related file changes detected.");
119- return;
120- }
121-122- if (!hasLabel) {
123- await github.rest.issues.addLabels({
124- owner: context.repo.owner,
125- repo: context.repo.repo,
126- issue_number: pullRequest.number,
127- labels: [labelName],
128- }).catch(ignoreUnavailableWritePermission(`label "${labelName}" update`));
129- }
130-131- const listedFiles = dependencyFiles.slice(0, maxListedFiles);
132- const omittedCount = dependencyFiles.length - listedFiles.length;
133- const fileLines = listedFiles.map((filename) => `- ${markdownCode(filename)}`);
134- if (omittedCount > 0) {
135- fileLines.push(`- ${omittedCount} additional dependency-related files not shown`);
136- }
137-138- const body = [
139- marker,
140- "",
141- "### Dependency Changes Detected",
142- "",
143- "This PR changes dependency-related files. Maintainers should confirm these changes are intentional.",
144- "",
145- "Changed files:",
146- ...fileLines,
147- "",
148- "Maintainer follow-up:",
149- "- Review whether the dependency changes are intentional.",
150- "- Inspect resolved package deltas when lockfile, shrinkwrap, or workspace dependency policy changes are present.",
151- "- Treat `package-lock.json` and `npm-shrinkwrap.json` diffs as security-review surfaces.",
152- "- Run `pnpm deps:changes:report -- --base-ref origin/main --markdown /tmp/dependency-changes.md --json /tmp/dependency-changes.json` locally for detailed release-style evidence.",
153- ].join("\n");
154-155- if (existingComment) {
156- await github.rest.issues.updateComment({
157- owner: context.repo.owner,
158- repo: context.repo.repo,
159- comment_id: existingComment.id,
160- body,
161- }).catch(ignoreUnavailableWritePermission("comment update"));
162- } else {
163- await github.rest.issues.createComment({
164- owner: context.repo.owner,
165- repo: context.repo.repo,
166- issue_number: pullRequest.number,
167- body,
168- }).catch(ignoreUnavailableWritePermission("comment creation"));
169- }
170-171- await core.summary
172- .addHeading("Dependency Change Awareness")
173- .addRaw(`Detected ${dependencyFiles.length} dependency-related file change(s).`)
174- .addList(dependencyFiles.map((filename) => markdownCode(filename)))
175- .write();
176- core.notice(`Detected ${dependencyFiles.length} dependency-related file change(s).`);
25+ref: ${{ github.event.pull_request.base.sha }}
26+persist-credentials: false
27+28+ - name: Label, comment, and guard dependency changes
29+env:
30+GITHUB_TOKEN: ${{ github.token }}
31+OPENCLAW_SECURITY_APPROVERS: vincentkoc,steipete,joshavant
32+OPENCLAW_SECURITY_TEAM_SLUG: openclaw-secops
33+run: node scripts/github/dependency-change-awareness.mjs
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。