lula2 0.6.3-nightly.0 → 0.6.3-nightly.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/_app/immutable/chunks/{MTDiNHJy.js → 1jzXvEnX.js} +1 -1
- package/dist/_app/immutable/chunks/{BXUi170M.js → BaV6jU6m.js} +1 -1
- package/dist/_app/immutable/chunks/{CnwkJbO2.js → C2SR2FDY.js} +1 -1
- package/dist/_app/immutable/chunks/{e7OeeeKP.js → C4K5jMrZ.js} +1 -1
- package/dist/_app/immutable/chunks/{CRa0j_Fx.js → CynYS-Ma.js} +1 -1
- package/dist/_app/immutable/chunks/{rc9CiIba.js → D74fr9ax.js} +2 -2
- package/dist/_app/immutable/chunks/{WlyXjfrM.js → DBdrJbLi.js} +1 -1
- package/dist/_app/immutable/chunks/DmBJsPtc.js +2 -0
- package/dist/_app/immutable/chunks/{Cq7PwVfU.js → _8PUdHCK.js} +1 -1
- package/dist/_app/immutable/entry/{app.C9fkwjMz.js → app.CY89YrVW.js} +2 -2
- package/dist/_app/immutable/entry/start.DWsnY-61.js +1 -0
- package/dist/_app/immutable/nodes/{0.DTEvfwsS.js → 0.Cs_n-oiO.js} +1 -1
- package/dist/_app/immutable/nodes/{1.CVMum2jU.js → 1.B7Z5qFVB.js} +1 -1
- package/dist/_app/immutable/nodes/{2.D-DlyZaW.js → 2.BN5e8rSZ.js} +1 -1
- package/dist/_app/immutable/nodes/{3.CEMIejLc.js → 3.-pzDIQdZ.js} +1 -1
- package/dist/_app/immutable/nodes/{4.BRRWt-Y5.js → 4.D6LQvz4k.js} +1 -1
- package/dist/_app/version.json +1 -1
- package/dist/cli/commands/crawl.js +151 -90
- package/dist/index.html +10 -10
- package/dist/index.js +145 -91
- package/package.json +1 -1
- package/dist/_app/immutable/chunks/DTWPdvjs.js +0 -2
- package/dist/_app/immutable/entry/start.D2hMBZNv.js +0 -1
|
@@ -123,155 +123,209 @@ function containsLulaAnnotations(text) {
|
|
|
123
123
|
const lines = text.split("\n");
|
|
124
124
|
return lines.some((line) => line.includes("@lulaStart") || line.includes("@lulaEnd"));
|
|
125
125
|
}
|
|
126
|
-
function
|
|
127
|
-
return
|
|
128
|
-
new Option("--post-mode <mode>", "How to post findings").choices(["review", "comment"]).default("review")
|
|
129
|
-
).action(async (opts) => {
|
|
130
|
-
let leavePost = false;
|
|
131
|
-
const { owner, repo, pull_number } = getPRContext();
|
|
132
|
-
console.log(`Analyzing PR #${pull_number} in ${owner}/${repo} for compliance changes...`);
|
|
133
|
-
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
|
|
134
|
-
const pr = await octokit.pulls.get({ owner, repo, pull_number });
|
|
135
|
-
const prBranch = pr.data.head.ref;
|
|
136
|
-
const { data: files } = await octokit.pulls.listFiles({ owner, repo, pull_number });
|
|
137
|
-
let commentBody = `${LULA_SIGNATURE}
|
|
126
|
+
function createInitialCommentBody(filesCount) {
|
|
127
|
+
return `${LULA_SIGNATURE}
|
|
138
128
|
## Lula Compliance Overview
|
|
139
129
|
|
|
140
130
|
Please review the changes to ensure they meet compliance standards.
|
|
141
131
|
|
|
142
132
|
### Reviewed Changes
|
|
143
133
|
|
|
144
|
-
Lula reviewed ${
|
|
134
|
+
Lula reviewed ${filesCount} files changed that affect compliance.
|
|
145
135
|
|
|
146
136
|
`;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
137
|
+
}
|
|
138
|
+
async function analyzeDeletedFiles(context) {
|
|
139
|
+
const { octokit, owner, repo, files } = context;
|
|
140
|
+
const deletedFilesWithAnnotations = [];
|
|
141
|
+
for (const file of files) {
|
|
142
|
+
if (file.status === "removed") {
|
|
143
|
+
try {
|
|
144
|
+
const oldText = await fetchRawFileViaAPI({
|
|
145
|
+
octokit,
|
|
146
|
+
owner,
|
|
147
|
+
repo,
|
|
148
|
+
path: file.filename,
|
|
149
|
+
ref: "main"
|
|
150
|
+
});
|
|
151
|
+
if (containsLulaAnnotations(oldText)) {
|
|
152
|
+
deletedFilesWithAnnotations.push(file.filename);
|
|
163
153
|
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
console.error(`Error checking deleted file ${file.filename}: ${err}`);
|
|
164
156
|
}
|
|
165
157
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
}
|
|
159
|
+
if (deletedFilesWithAnnotations.length === 0) {
|
|
160
|
+
return { hasFindings: false, warningContent: "" };
|
|
161
|
+
}
|
|
162
|
+
let warningContent = `
|
|
169
163
|
|
|
170
164
|
**Compliance Warning: Files with Lula annotations were deleted**
|
|
171
165
|
|
|
172
166
|
`;
|
|
173
|
-
|
|
167
|
+
warningContent += `The following files contained compliance annotations (\`@lulaStart\`/\`@lulaEnd\`) and were deleted in this PR. This may affect compliance coverage:
|
|
174
168
|
|
|
175
169
|
`;
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
for (const filename of deletedFilesWithAnnotations) {
|
|
171
|
+
warningContent += `- \`${filename}\`
|
|
178
172
|
`;
|
|
179
|
-
|
|
180
|
-
|
|
173
|
+
}
|
|
174
|
+
warningContent += `
|
|
181
175
|
Please review whether:
|
|
182
176
|
`;
|
|
183
|
-
|
|
177
|
+
warningContent += `- The compliance coverage provided by these files is still needed
|
|
184
178
|
`;
|
|
185
|
-
|
|
179
|
+
warningContent += `- Alternative compliance measures have been implemented
|
|
186
180
|
`;
|
|
187
|
-
|
|
181
|
+
warningContent += `- The deletion is intentional and compliance-approved
|
|
188
182
|
|
|
189
183
|
`;
|
|
190
|
-
|
|
184
|
+
warningContent += `---
|
|
191
185
|
|
|
192
186
|
`;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
]);
|
|
201
|
-
const changedBlocks = getChangedBlocks(oldText, newText);
|
|
202
|
-
const removedBlocks = getRemovedBlocks(oldText, newText);
|
|
203
|
-
for (const block of changedBlocks) {
|
|
204
|
-
console.log(`Commenting regarding \`${file.filename}\`.`);
|
|
205
|
-
leavePost = true;
|
|
206
|
-
commentBody += `
|
|
187
|
+
return { hasFindings: true, warningContent };
|
|
188
|
+
}
|
|
189
|
+
function generateChangedBlocksContent(filename, changedBlocks, newText) {
|
|
190
|
+
let content = "";
|
|
191
|
+
for (const block of changedBlocks) {
|
|
192
|
+
console.log(`Commenting regarding \`${filename}\`.`);
|
|
193
|
+
content += `
|
|
207
194
|
|
|
208
195
|
---
|
|
209
196
|
| File | Lines Changed |
|
|
210
197
|
| ---- | ------------- |
|
|
211
198
|
`;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
199
|
+
const newBlockText = newText.split("\n").slice(block.startLine, block.endLine).join("\n");
|
|
200
|
+
const blockSha256 = createHash("sha256").update(newBlockText).digest("hex");
|
|
201
|
+
content += `| \`${filename}\` | \`${block.startLine + 1}\u2013${block.endLine}\` |
|
|
215
202
|
> **uuid**-\`${block.uuid}\`
|
|
216
203
|
**sha256** \`${blockSha256}\`
|
|
217
204
|
|
|
218
205
|
`;
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
206
|
+
}
|
|
207
|
+
return content;
|
|
208
|
+
}
|
|
209
|
+
function generateRemovedBlocksContent(filename, removedBlocks, oldText) {
|
|
210
|
+
if (removedBlocks.length === 0) {
|
|
211
|
+
return "";
|
|
212
|
+
}
|
|
213
|
+
console.log(`Found removed annotations in \`${filename}\`.`);
|
|
214
|
+
let content = `
|
|
224
215
|
|
|
225
|
-
**Compliance Warning: Lula annotations were removed from \`${
|
|
216
|
+
**Compliance Warning: Lula annotations were removed from \`${filename}\`**
|
|
226
217
|
|
|
227
218
|
`;
|
|
228
|
-
|
|
219
|
+
content += `The following compliance annotation blocks were present in the original file but are missing in the updated version:
|
|
229
220
|
|
|
230
221
|
`;
|
|
231
|
-
|
|
222
|
+
content += `| File | Original Lines | UUID |
|
|
232
223
|
`;
|
|
233
|
-
|
|
224
|
+
content += `| ---- | -------------- | ---- |
|
|
234
225
|
`;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
226
|
+
for (const block of removedBlocks) {
|
|
227
|
+
const oldBlockText = oldText.split("\n").slice(block.startLine, block.endLine).join("\n");
|
|
228
|
+
const blockSha256 = createHash("sha256").update(oldBlockText).digest("hex");
|
|
229
|
+
content += `| \`${filename}\` | \`${block.startLine + 1}\u2013${block.endLine}\` | \`${block.uuid}\` |
|
|
239
230
|
`;
|
|
240
|
-
|
|
231
|
+
content += `> **sha256** \`${blockSha256}\`
|
|
241
232
|
|
|
242
233
|
`;
|
|
243
|
-
|
|
244
|
-
|
|
234
|
+
}
|
|
235
|
+
content += `Please review whether:
|
|
245
236
|
`;
|
|
246
|
-
|
|
237
|
+
content += `- The removal of these compliance annotations is intentional
|
|
247
238
|
`;
|
|
248
|
-
|
|
239
|
+
content += `- Alternative compliance measures have been implemented
|
|
249
240
|
`;
|
|
250
|
-
|
|
241
|
+
content += `- The compliance coverage is still adequate
|
|
251
242
|
|
|
252
243
|
`;
|
|
253
|
-
|
|
244
|
+
content += `---
|
|
254
245
|
|
|
255
246
|
`;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
247
|
+
return content;
|
|
248
|
+
}
|
|
249
|
+
async function analyzeModifiedFiles(context) {
|
|
250
|
+
const { octokit, owner, repo, prBranch, files } = context;
|
|
251
|
+
let changesContent = "";
|
|
252
|
+
let hasFindings = false;
|
|
253
|
+
for (const file of files) {
|
|
254
|
+
if (file.status === "added" || file.status === "removed") continue;
|
|
255
|
+
try {
|
|
256
|
+
const [oldText, newText] = await Promise.all([
|
|
257
|
+
fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: "main" }),
|
|
258
|
+
fetchRawFileViaAPI({ octokit, owner, repo, path: file.filename, ref: prBranch })
|
|
259
|
+
]);
|
|
260
|
+
const changedBlocks = getChangedBlocks(oldText, newText);
|
|
261
|
+
const removedBlocks = getRemovedBlocks(oldText, newText);
|
|
262
|
+
if (changedBlocks.length > 0) {
|
|
263
|
+
hasFindings = true;
|
|
264
|
+
changesContent += generateChangedBlocksContent(file.filename, changedBlocks, newText);
|
|
259
265
|
}
|
|
266
|
+
if (removedBlocks.length > 0) {
|
|
267
|
+
hasFindings = true;
|
|
268
|
+
changesContent += generateRemovedBlocksContent(file.filename, removedBlocks, oldText);
|
|
269
|
+
}
|
|
270
|
+
} catch (err) {
|
|
271
|
+
console.error(`Error processing ${file.filename}: ${err}`);
|
|
260
272
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
273
|
+
}
|
|
274
|
+
return { hasFindings, changesContent };
|
|
275
|
+
}
|
|
276
|
+
async function performComplianceAnalysis(context) {
|
|
277
|
+
let commentBody = createInitialCommentBody(context.files.length);
|
|
278
|
+
let hasFindings = false;
|
|
279
|
+
const deletedAnalysis = await analyzeDeletedFiles(context);
|
|
280
|
+
if (deletedAnalysis.hasFindings) {
|
|
281
|
+
hasFindings = true;
|
|
282
|
+
commentBody += deletedAnalysis.warningContent;
|
|
283
|
+
}
|
|
284
|
+
const modifiedAnalysis = await analyzeModifiedFiles(context);
|
|
285
|
+
if (modifiedAnalysis.hasFindings) {
|
|
286
|
+
hasFindings = true;
|
|
287
|
+
commentBody += modifiedAnalysis.changesContent;
|
|
288
|
+
}
|
|
289
|
+
return { hasFindings, commentBody };
|
|
290
|
+
}
|
|
291
|
+
async function cleanupOldPosts(context, postMode) {
|
|
292
|
+
const { octokit, owner, repo, pull_number } = context;
|
|
293
|
+
if (postMode === "comment") {
|
|
294
|
+
await deleteOldIssueComments({ octokit, owner, repo, pull_number });
|
|
295
|
+
} else {
|
|
296
|
+
await dismissOldReviews({ octokit, owner, repo, pull_number });
|
|
297
|
+
await deleteOldReviewComments({ octokit, owner, repo, pull_number });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function crawlCommand() {
|
|
301
|
+
return new Command().command("crawl").description("Detect compliance-related changes between @lulaStart and @lulaEnd in PR files").addOption(
|
|
302
|
+
new Option("--post-mode <mode>", "How to post findings").choices(["review", "comment"]).default("review")
|
|
303
|
+
).action(async (opts) => {
|
|
304
|
+
const { owner, repo, pull_number } = getPRContext();
|
|
305
|
+
console.log(`Analyzing PR #${pull_number} in ${owner}/${repo} for compliance changes...`);
|
|
306
|
+
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
|
|
307
|
+
const pr = await octokit.pulls.get({ owner, repo, pull_number });
|
|
308
|
+
const prBranch = pr.data.head.ref;
|
|
309
|
+
const { data: files } = await octokit.pulls.listFiles({ owner, repo, pull_number });
|
|
310
|
+
const context = {
|
|
311
|
+
octokit,
|
|
312
|
+
owner,
|
|
313
|
+
repo,
|
|
314
|
+
pull_number,
|
|
315
|
+
prBranch,
|
|
316
|
+
files
|
|
317
|
+
};
|
|
318
|
+
const analysisResult = await performComplianceAnalysis(context);
|
|
319
|
+
await cleanupOldPosts(context, opts.postMode);
|
|
320
|
+
if (analysisResult.hasFindings) {
|
|
321
|
+
const finalBody = analysisResult.commentBody + closingBody;
|
|
268
322
|
await postFinding({
|
|
269
323
|
octokit,
|
|
270
324
|
postMode: opts.postMode,
|
|
271
325
|
owner,
|
|
272
326
|
repo,
|
|
273
327
|
pull_number,
|
|
274
|
-
body:
|
|
328
|
+
body: finalBody
|
|
275
329
|
});
|
|
276
330
|
const header = `Posted (${opts.postMode})`;
|
|
277
331
|
const underline = "-".repeat(header.length);
|
|
@@ -279,7 +333,7 @@ Please review whether:
|
|
|
279
333
|
${header}
|
|
280
334
|
${underline}
|
|
281
335
|
|
|
282
|
-
${
|
|
336
|
+
${finalBody}
|
|
283
337
|
|
|
284
338
|
`);
|
|
285
339
|
}
|
|
@@ -372,15 +426,22 @@ async function dismissOldReviews({
|
|
|
372
426
|
}
|
|
373
427
|
export {
|
|
374
428
|
LULA_SIGNATURE,
|
|
429
|
+
analyzeDeletedFiles,
|
|
430
|
+
analyzeModifiedFiles,
|
|
431
|
+
cleanupOldPosts,
|
|
375
432
|
containsLulaAnnotations,
|
|
376
433
|
crawlCommand,
|
|
434
|
+
createInitialCommentBody,
|
|
377
435
|
deleteOldIssueComments,
|
|
378
436
|
deleteOldReviewComments,
|
|
379
437
|
dismissOldReviews,
|
|
380
438
|
extractMapBlocks,
|
|
381
439
|
fetchRawFileViaAPI,
|
|
440
|
+
generateChangedBlocksContent,
|
|
441
|
+
generateRemovedBlocksContent,
|
|
382
442
|
getChangedBlocks,
|
|
383
443
|
getPRContext,
|
|
384
444
|
getRemovedBlocks,
|
|
445
|
+
performComplianceAnalysis,
|
|
385
446
|
postFinding
|
|
386
447
|
};
|
package/dist/index.html
CHANGED
|
@@ -6,28 +6,28 @@
|
|
|
6
6
|
<link rel="icon" href="/lula.png" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
8
8
|
|
|
9
|
-
<link rel="modulepreload" href="/_app/immutable/entry/start.
|
|
10
|
-
<link rel="modulepreload" href="/_app/immutable/chunks/
|
|
11
|
-
<link rel="modulepreload" href="/_app/immutable/chunks/
|
|
12
|
-
<link rel="modulepreload" href="/_app/immutable/entry/app.
|
|
9
|
+
<link rel="modulepreload" href="/_app/immutable/entry/start.DWsnY-61.js">
|
|
10
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/D74fr9ax.js">
|
|
11
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/DmBJsPtc.js">
|
|
12
|
+
<link rel="modulepreload" href="/_app/immutable/entry/app.CY89YrVW.js">
|
|
13
13
|
<link rel="modulepreload" href="/_app/immutable/chunks/DsnmJJEf.js">
|
|
14
|
-
<link rel="modulepreload" href="/_app/immutable/chunks/
|
|
15
|
-
<link rel="modulepreload" href="/_app/immutable/chunks/
|
|
16
|
-
<link rel="modulepreload" href="/_app/immutable/chunks/
|
|
14
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/BaV6jU6m.js">
|
|
15
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/DBdrJbLi.js">
|
|
16
|
+
<link rel="modulepreload" href="/_app/immutable/chunks/CynYS-Ma.js">
|
|
17
17
|
</head>
|
|
18
18
|
<body data-sveltekit-preload-data="hover">
|
|
19
19
|
<div style="display: contents">
|
|
20
20
|
<script>
|
|
21
21
|
{
|
|
22
|
-
|
|
22
|
+
__sveltekit_1iek8ky = {
|
|
23
23
|
base: ""
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const element = document.currentScript.parentElement;
|
|
27
27
|
|
|
28
28
|
Promise.all([
|
|
29
|
-
import("/_app/immutable/entry/start.
|
|
30
|
-
import("/_app/immutable/entry/app.
|
|
29
|
+
import("/_app/immutable/entry/start.DWsnY-61.js"),
|
|
30
|
+
import("/_app/immutable/entry/app.CY89YrVW.js")
|
|
31
31
|
]).then(([kit, app]) => {
|
|
32
32
|
kit.start(app, element);
|
|
33
33
|
});
|