@aisdlc/core 2.2.4 → 2.4.0
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/dist/index.cjs +975 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +148 -2
- package/dist/index.d.ts +148 -2
- package/dist/index.js +961 -138
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -266,19 +266,26 @@ function extractPythonFunctions(content, filePath) {
|
|
|
266
266
|
}
|
|
267
267
|
return buildMetricsFromBlocks(blocks, content, filePath);
|
|
268
268
|
}
|
|
269
|
-
function
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
function tryStartBraceFunction(line, state, ext) {
|
|
270
|
+
if (state.currentFn || state.inBlockComment || state.rawTerm) return;
|
|
271
|
+
const candidate = matchFunctionHeader(line, ext);
|
|
272
|
+
if (candidate) {
|
|
273
273
|
state.currentFn = candidate;
|
|
274
274
|
state.braceCount = 0;
|
|
275
275
|
state.fnLines = [];
|
|
276
276
|
}
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
}
|
|
278
|
+
function updateBraceScanState(line, state, ext) {
|
|
279
|
+
const res = scanBracesInLine(line, state.inBlockComment, state.rawTerm, ext);
|
|
279
280
|
state.inBlockComment = res.nowInBlock;
|
|
281
|
+
state.rawTerm = res.nowRawTerm;
|
|
280
282
|
state.braceCount += res.delta;
|
|
281
|
-
|
|
283
|
+
}
|
|
284
|
+
function processBraceLine(line, state, blocks, lineIndex, ext) {
|
|
285
|
+
tryStartBraceFunction(line, state, ext);
|
|
286
|
+
if (state.currentFn) state.fnLines.push(line);
|
|
287
|
+
updateBraceScanState(line, state, ext);
|
|
288
|
+
if (state.currentFn && state.braceCount === 0 && state.fnLines.length > 1) {
|
|
282
289
|
blocks.push({ name: state.currentFn, body: state.fnLines.join("\n"), startLine: lineIndex });
|
|
283
290
|
state.currentFn = null;
|
|
284
291
|
state.fnLines = [];
|
|
@@ -288,98 +295,153 @@ function extractBraceFunctions(content, filePath) {
|
|
|
288
295
|
const ext = path4.extname(filePath).toLowerCase();
|
|
289
296
|
const lines = content.split("\n");
|
|
290
297
|
const blocks = [];
|
|
291
|
-
const state = {
|
|
298
|
+
const state = {
|
|
299
|
+
currentFn: null,
|
|
300
|
+
braceCount: 0,
|
|
301
|
+
fnLines: [],
|
|
302
|
+
inBlockComment: false,
|
|
303
|
+
rawTerm: null
|
|
304
|
+
};
|
|
292
305
|
for (let i = 0; i < lines.length; i++) {
|
|
293
306
|
processBraceLine(lines[i], state, blocks, i, ext);
|
|
294
307
|
}
|
|
295
308
|
return buildMetricsFromBlocks(blocks, content, filePath);
|
|
296
309
|
}
|
|
310
|
+
var HEADER_EXCLUSIONS = /* @__PURE__ */ new Set([
|
|
311
|
+
"if",
|
|
312
|
+
"for",
|
|
313
|
+
"foreach",
|
|
314
|
+
"while",
|
|
315
|
+
"switch",
|
|
316
|
+
"catch",
|
|
317
|
+
"select",
|
|
318
|
+
"match",
|
|
319
|
+
"class",
|
|
320
|
+
"struct",
|
|
321
|
+
"interface",
|
|
322
|
+
"record",
|
|
323
|
+
"enum",
|
|
324
|
+
"namespace",
|
|
325
|
+
"using",
|
|
326
|
+
"lock",
|
|
327
|
+
"fixed",
|
|
328
|
+
"synchronized",
|
|
329
|
+
"try",
|
|
330
|
+
"else"
|
|
331
|
+
]);
|
|
297
332
|
function matchCStyleHeader(line) {
|
|
298
333
|
const match = line.match(
|
|
299
|
-
/(?:(?:public|private|protected|static|async|virtual|override|fn)\s+)*(?:function\s+([a-zA-Z0-9_$]+)|(?:[a-zA-Z0-9_<>[\]
|
|
334
|
+
/(?:(?:public|private|protected|internal|static|async|virtual|override|sealed|abstract|final|synchronized|default|fn)\s+)*(?:function\s+([a-zA-Z0-9_$]+)|(?:[a-zA-Z0-9_<>[\]?,.\s]+\s+)+([a-zA-Z0-9_$]+)\s*(?:<[^>]+>)?\s*\([^;{}]*\)\s*(?:where\s+[^{]+|throws\s+[^{]+)?\{|([a-zA-Z0-9_$]+)\s*\([^;{}]*\)\s*(?::\s*[^{]+\s*)?\{)/
|
|
300
335
|
);
|
|
301
336
|
if (!match) return null;
|
|
302
337
|
const candidate = match[1] || match[2] || match[3];
|
|
303
|
-
|
|
304
|
-
return candidate && !exclusions.includes(candidate) ? candidate : null;
|
|
338
|
+
return candidate && !HEADER_EXCLUSIONS.has(candidate) ? candidate : null;
|
|
305
339
|
}
|
|
306
340
|
function matchFunctionHeader(line, ext) {
|
|
307
341
|
const trimmed = line.trim();
|
|
308
|
-
if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*"))
|
|
342
|
+
if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*") || trimmed.startsWith("#")) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
309
345
|
if (ext === ".go") {
|
|
310
|
-
const match = line.match(/func\s+(?:\([^)]*\)\s*)?([a-zA-Z0-9_$]+)\s*\(/);
|
|
346
|
+
const match = line.match(/func\s+(?:\([^)]*\)\s*)?([a-zA-Z0-9_$]+)\s*(?:\[[^\]]*\])?\s*\(/);
|
|
311
347
|
return match ? match[1] : null;
|
|
312
348
|
}
|
|
313
349
|
if (ext === ".rs") {
|
|
314
|
-
const match = line.match(/(?:pub
|
|
350
|
+
const match = line.match(/(?:pub(?:\([^)]*\))?\s+)?(?:async\s+)?(?:unsafe\s+)?(?:const\s+)?fn\s+([a-zA-Z0-9_$]+)\s*(?:<[^>]*>)?\s*\(/);
|
|
315
351
|
return match ? match[1] : null;
|
|
316
352
|
}
|
|
317
353
|
return matchCStyleHeader(line);
|
|
318
354
|
}
|
|
319
|
-
function
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
+
function detectRustOrGoRawString(sub, ext) {
|
|
356
|
+
if (ext === ".rs") {
|
|
357
|
+
const m = sub.match(/^r(#*)"/);
|
|
358
|
+
return m ? { term: `"${m[1]}`, advance: m[0].length - 1 } : null;
|
|
359
|
+
}
|
|
360
|
+
if (ext === ".go" && sub.startsWith("`")) {
|
|
361
|
+
return { term: "`", advance: 0 };
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
function detectCsJavaOrCppRawString(sub, ext) {
|
|
366
|
+
if (ext === ".cs" || ext === ".java") {
|
|
367
|
+
const m = sub.match(/^\$*("{3,})/);
|
|
368
|
+
if (m) return { term: m[1], advance: m[0].length - 1 };
|
|
369
|
+
const v = ext === ".cs" ? sub.match(/^(@\$|\$@|@)"/) : null;
|
|
370
|
+
return v ? { term: '"', advance: v[0].length - 1 } : null;
|
|
371
|
+
}
|
|
372
|
+
const cpp = sub.match(/^R"([a-zA-Z0-9_]*)\(/);
|
|
373
|
+
return cpp ? { term: `)${cpp[1]}"`, advance: cpp[0].length - 1 } : null;
|
|
374
|
+
}
|
|
375
|
+
function detectRawStringOpen(line, index, ext) {
|
|
376
|
+
const sub = line.slice(index);
|
|
377
|
+
return detectRustOrGoRawString(sub, ext) || detectCsJavaOrCppRawString(sub, ext);
|
|
378
|
+
}
|
|
379
|
+
function consumeRawOrBlock(line, index, state) {
|
|
380
|
+
if (state.inBlock) {
|
|
381
|
+
if (line[index] === "*" && line[index + 1] === "/") {
|
|
382
|
+
state.inBlock = false;
|
|
383
|
+
return { advance: 1, handled: true };
|
|
384
|
+
}
|
|
385
|
+
return { advance: 0, handled: true };
|
|
386
|
+
}
|
|
387
|
+
if (state.rawTerm) {
|
|
388
|
+
if (line.startsWith(state.rawTerm, index)) {
|
|
389
|
+
const len = state.rawTerm.length - 1;
|
|
390
|
+
state.rawTerm = null;
|
|
391
|
+
return { advance: len, handled: true };
|
|
392
|
+
}
|
|
393
|
+
return { advance: 0, handled: true };
|
|
394
|
+
}
|
|
395
|
+
return { advance: 0, handled: false };
|
|
396
|
+
}
|
|
397
|
+
function consumeNormalQuote(line, index, state) {
|
|
398
|
+
if (!state.inString) return { advance: 0, handled: false };
|
|
399
|
+
const ch = line[index];
|
|
400
|
+
if (ch === "\\") return { advance: 1, handled: true };
|
|
401
|
+
if (ch === state.inString) state.inString = null;
|
|
402
|
+
return { advance: 0, handled: true };
|
|
403
|
+
}
|
|
404
|
+
function applyQuoteOrBrace(ch, state) {
|
|
405
|
+
if (ch === '"' || ch === "'") {
|
|
406
|
+
state.inString = ch;
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (ch === "{") state.delta++;
|
|
410
|
+
if (ch === "}") state.delta--;
|
|
411
|
+
}
|
|
412
|
+
function stepActiveCodeToken(line, j, ext, state) {
|
|
413
|
+
const pair = line.slice(j, j + 2);
|
|
414
|
+
if (pair === "//") return { advance: 0, stop: true };
|
|
415
|
+
if (pair === "/*") {
|
|
355
416
|
state.inBlock = true;
|
|
356
417
|
return { advance: 1, stop: false };
|
|
357
418
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
419
|
+
const rawOpen = detectRawStringOpen(line, j, ext);
|
|
420
|
+
if (rawOpen) {
|
|
421
|
+
state.rawTerm = rawOpen.term;
|
|
422
|
+
return { advance: rawOpen.advance, stop: false };
|
|
361
423
|
}
|
|
362
|
-
state
|
|
424
|
+
applyQuoteOrBrace(line[j], state);
|
|
363
425
|
return { advance: 0, stop: false };
|
|
364
426
|
}
|
|
365
|
-
function scanBracesInLine(line, wasInBlock, ext) {
|
|
366
|
-
const state = { delta: 0, inBlock: wasInBlock, inString: null };
|
|
427
|
+
function scanBracesInLine(line, wasInBlock, wasRawTerm, ext) {
|
|
428
|
+
const state = { delta: 0, inBlock: wasInBlock, rawTerm: wasRawTerm, inString: null };
|
|
367
429
|
for (let j = 0; j < line.length; j++) {
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
430
|
+
const rawOrBlock = consumeRawOrBlock(line, j, state);
|
|
431
|
+
if (rawOrBlock.handled) {
|
|
432
|
+
j += rawOrBlock.advance;
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
const quoteStep = consumeNormalQuote(line, j, state);
|
|
436
|
+
if (quoteStep.handled) {
|
|
437
|
+
j += quoteStep.advance;
|
|
375
438
|
continue;
|
|
376
439
|
}
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
j += step.advance;
|
|
440
|
+
const codeStep = stepActiveCodeToken(line, j, ext, state);
|
|
441
|
+
if (codeStep.stop) break;
|
|
442
|
+
j += codeStep.advance;
|
|
381
443
|
}
|
|
382
|
-
return { delta: state.delta, nowInBlock: state.inBlock };
|
|
444
|
+
return { delta: state.delta, nowInBlock: state.inBlock, nowRawTerm: state.rawTerm };
|
|
383
445
|
}
|
|
384
446
|
function buildMetricsFromBlocks(blocks, content, filePath) {
|
|
385
447
|
if (blocks.length === 0) {
|
|
@@ -403,11 +465,20 @@ function buildMetricsFromBlocks(blocks, content, filePath) {
|
|
|
403
465
|
}
|
|
404
466
|
function detectPolyglotSmells(body) {
|
|
405
467
|
const smells = [];
|
|
406
|
-
if (/#\s*noqa|#\s*type:\s*ignore|@SuppressWarnings/.test(body)) {
|
|
468
|
+
if (/#\s*noqa|#\s*type:\s*ignore|@SuppressWarnings|#pragma\s+warning\s+disable/.test(body)) {
|
|
407
469
|
smells.push("Supresi\xF3n no autorizada de linter");
|
|
408
470
|
}
|
|
409
471
|
return smells;
|
|
410
472
|
}
|
|
473
|
+
function stripStringsAndComments(body, ext) {
|
|
474
|
+
let cleaned = body;
|
|
475
|
+
if (ext === ".py") {
|
|
476
|
+
cleaned = cleaned.replace(/"""[\s\S]*?"""|'''[\s\S]*?'''/g, '""').replace(/#.*/g, "");
|
|
477
|
+
} else {
|
|
478
|
+
cleaned = cleaned.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "").replace(/r(#+)"[\s\S]*?"\1/g, '""').replace(/R"([a-zA-Z0-9_]*)\([\s\S]*?\)\1"/g, '""').replace(/\$*"{3,}[\s\S]*?"{3,}/g, '""').replace(/`[\s\S]*?`/g, '""');
|
|
479
|
+
}
|
|
480
|
+
return cleaned.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g, '""');
|
|
481
|
+
}
|
|
411
482
|
function computeHalsteadMI(body, cyclomatic, loc, commentCount) {
|
|
412
483
|
const cleanText = body.replace(/\/\*[\s\S]*?\*\/|\/\/.*|#.*/g, "");
|
|
413
484
|
const tokens = cleanText.split(/[\s,;().{}[\]=+\-*/<>!&|:]+/).filter((t) => t.length > 0);
|
|
@@ -432,9 +503,11 @@ function countCommentsAndLoc(rawLines, isPy) {
|
|
|
432
503
|
function calculatePolyglotMetrics(body, name, filePath, startLine) {
|
|
433
504
|
const ext = path4.extname(filePath).toLowerCase();
|
|
434
505
|
const rawLines = body.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
|
|
435
|
-
const { loc, commentCount
|
|
436
|
-
const
|
|
437
|
-
const
|
|
506
|
+
const { loc, commentCount } = countCommentsAndLoc(rawLines, ext === ".py");
|
|
507
|
+
const strippedBody = stripStringsAndComments(body, ext);
|
|
508
|
+
const strippedLines = strippedBody.split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
509
|
+
const cyclomatic = computePolyglotCyclomatic(strippedBody, ext);
|
|
510
|
+
const cognitive = computePolyglotCognitive(strippedLines, ext === ".py");
|
|
438
511
|
const maintainability = computeHalsteadMI(body, cyclomatic, loc, commentCount);
|
|
439
512
|
return {
|
|
440
513
|
functionName: name,
|
|
@@ -447,40 +520,60 @@ function calculatePolyglotMetrics(body, name, filePath, startLine) {
|
|
|
447
520
|
line: startLine ? startLine + 1 : 1
|
|
448
521
|
};
|
|
449
522
|
}
|
|
450
|
-
function
|
|
451
|
-
let regex;
|
|
523
|
+
function getCyclomaticPattern(ext) {
|
|
452
524
|
if (ext === ".py") {
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
525
|
+
return /\b(if|elif|for|while|except|case)\b|\b(and|or)\b/g;
|
|
526
|
+
}
|
|
527
|
+
if (ext === ".go") {
|
|
528
|
+
return /\b(if|for|case|select)\b|&&|\|\|/g;
|
|
529
|
+
}
|
|
530
|
+
if (ext === ".rs") {
|
|
531
|
+
return /\b(if|for|while|match)\b|&&|\|\||\?/g;
|
|
532
|
+
}
|
|
533
|
+
if (ext === ".cs") {
|
|
534
|
+
return /\b(if|else\s+if|for|foreach|while|catch|case|when)\b|\?\?|\?\.(?=[a-zA-Z_])|&&|\|\|/g;
|
|
535
|
+
}
|
|
536
|
+
if (ext === ".java") {
|
|
537
|
+
return /\b(if|else\s+if|for|while|catch|case|when)\b|&&|\|\|/g;
|
|
460
538
|
}
|
|
461
|
-
|
|
462
|
-
|
|
539
|
+
return /\b(if|else\s+if|for|while|catch|case)\b|\?|&&|\|\|/g;
|
|
540
|
+
}
|
|
541
|
+
function computePolyglotCyclomatic(strippedBody, ext) {
|
|
542
|
+
const regex = getCyclomaticPattern(ext);
|
|
543
|
+
const matches = strippedBody.match(regex);
|
|
463
544
|
return 1 + (matches ? matches.length : 0);
|
|
464
545
|
}
|
|
465
|
-
|
|
546
|
+
var PY_COGNITIVE_RE = /\b(if|elif|for|while|except|match)\b/;
|
|
547
|
+
var BRACE_COGNITIVE_RE = /\b(if|for|foreach|while|catch|match|select|switch)\b/;
|
|
548
|
+
function computePythonCognitive(lines) {
|
|
549
|
+
let cognitive = 0;
|
|
550
|
+
const baseIndent = lines.length > 0 ? lines[0].length - lines[0].trimStart().length : 0;
|
|
551
|
+
for (let i = 1; i < lines.length; i++) {
|
|
552
|
+
const line = lines[i];
|
|
553
|
+
if (PY_COGNITIVE_RE.test(line)) {
|
|
554
|
+
const relIndent = Math.max(0, line.length - line.trimStart().length - baseIndent - 4);
|
|
555
|
+
cognitive += 1 + Math.floor(relIndent / 4);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return cognitive;
|
|
559
|
+
}
|
|
560
|
+
function computeBraceCognitive(lines) {
|
|
466
561
|
let cognitive = 0;
|
|
467
562
|
let nesting = 0;
|
|
468
|
-
for (
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
cognitive += 1 + Math.floor(indent / 4);
|
|
473
|
-
}
|
|
474
|
-
} else {
|
|
475
|
-
if (line.includes("{")) nesting++;
|
|
476
|
-
if (line.includes("}")) nesting = Math.max(0, nesting - 1);
|
|
477
|
-
if (/\b(if|for|while|catch|match|select)\b/.test(line)) {
|
|
478
|
-
cognitive += 1 + nesting;
|
|
479
|
-
}
|
|
563
|
+
for (let i = 1; i < lines.length; i++) {
|
|
564
|
+
const line = lines[i];
|
|
565
|
+
if (BRACE_COGNITIVE_RE.test(line)) {
|
|
566
|
+
cognitive += 1 + nesting;
|
|
480
567
|
}
|
|
568
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
569
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
570
|
+
nesting = Math.max(0, nesting + opens - closes);
|
|
481
571
|
}
|
|
482
572
|
return cognitive;
|
|
483
573
|
}
|
|
574
|
+
function computePolyglotCognitive(lines, isPy) {
|
|
575
|
+
return isPy ? computePythonCognitive(lines) : computeBraceCognitive(lines);
|
|
576
|
+
}
|
|
484
577
|
function walkMdFiles(dir, fileList = [], excludeDirs = [
|
|
485
578
|
"node_modules",
|
|
486
579
|
".git",
|
|
@@ -1064,9 +1157,54 @@ function collectTestCorpus(rootDir, allMdFiles) {
|
|
|
1064
1157
|
}
|
|
1065
1158
|
return { gherkinSources, combinedTests: testContents.join("\n") };
|
|
1066
1159
|
}
|
|
1067
|
-
function
|
|
1160
|
+
function isCucumberScenarioPassed(element) {
|
|
1161
|
+
const steps = Array.isArray(element.steps) ? element.steps : [];
|
|
1162
|
+
if (steps.length === 0) return false;
|
|
1163
|
+
return steps.every((s) => {
|
|
1164
|
+
const res = s.result;
|
|
1165
|
+
return res && res.status === "passed";
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
function countCucumberScenarios(raw) {
|
|
1169
|
+
let passed = 0;
|
|
1170
|
+
let failed = 0;
|
|
1171
|
+
for (const feat of raw) {
|
|
1172
|
+
const elements = Array.isArray(feat.elements) ? feat.elements : [];
|
|
1173
|
+
for (const el of elements) {
|
|
1174
|
+
if (isCucumberScenarioPassed(el)) passed++;
|
|
1175
|
+
else failed++;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return { passed, failed };
|
|
1179
|
+
}
|
|
1180
|
+
function parseCucumberReportFile(reportPath) {
|
|
1181
|
+
if (!fs7.existsSync(reportPath)) return void 0;
|
|
1182
|
+
try {
|
|
1183
|
+
const raw = JSON.parse(fs7.readFileSync(reportPath, "utf-8"));
|
|
1184
|
+
if (!Array.isArray(raw)) return void 0;
|
|
1185
|
+
const { passed, failed } = countCucumberScenarios(raw);
|
|
1186
|
+
return {
|
|
1187
|
+
evaluatedFeatures: raw.length,
|
|
1188
|
+
passedScenarios: passed,
|
|
1189
|
+
failedScenarios: failed,
|
|
1190
|
+
passed: passed + failed > 0 && failed === 0
|
|
1191
|
+
};
|
|
1192
|
+
} catch {
|
|
1193
|
+
return void 0;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
function resolveCucumberReport(rootDir, options) {
|
|
1197
|
+
const candidate = options.cucumberReportPath ? path4.isAbsolute(options.cucumberReportPath) ? options.cucumberReportPath : path4.join(rootDir, options.cucumberReportPath) : path4.join(rootDir, "reports", "cucumber-report.json");
|
|
1198
|
+
const parsed = parseCucumberReportFile(candidate);
|
|
1199
|
+
if (parsed) return parsed;
|
|
1200
|
+
if (options.enforceCucumberExecution) {
|
|
1201
|
+
return { evaluatedFeatures: 0, passedScenarios: 0, failedScenarios: 1, passed: false };
|
|
1202
|
+
}
|
|
1203
|
+
return void 0;
|
|
1204
|
+
}
|
|
1205
|
+
function assembleCoverageResult(reqAudit, taskAudit, useCaseFlows, reqErrors, taskErrors, ucErrors, rootDir, options) {
|
|
1068
1206
|
return {
|
|
1069
|
-
success: reqErrors === 0 && taskErrors === 0 && ucErrors === 0,
|
|
1207
|
+
success: reqErrors === 0 && taskErrors === 0 && ucErrors === 0 && (!resolveCucumberReport(rootDir, options) || resolveCucumberReport(rootDir, options).passed),
|
|
1070
1208
|
totalRequirements: reqAudit.length,
|
|
1071
1209
|
passedRequirements: reqAudit.length - reqErrors,
|
|
1072
1210
|
failedRequirements: reqErrors,
|
|
@@ -1077,6 +1215,7 @@ function assembleCoverageResult(reqAudit, taskAudit, useCaseFlows, reqErrors, ta
|
|
|
1077
1215
|
tasks: taskAudit,
|
|
1078
1216
|
useCaseFlows,
|
|
1079
1217
|
failedUseCaseFlows: ucErrors,
|
|
1218
|
+
...resolveCucumberReport(rootDir, options) ? { cucumberExecution: resolveCucumberReport(rootDir, options) } : {},
|
|
1080
1219
|
reportMarkdown: generateTestingCoverageReportMarkdown(reqAudit, taskAudit, reqErrors, taskErrors)
|
|
1081
1220
|
};
|
|
1082
1221
|
}
|
|
@@ -1128,7 +1267,9 @@ function verifyTestingCoverage(options = {}) {
|
|
|
1128
1267
|
state.useCaseFlows,
|
|
1129
1268
|
state.reqErrors,
|
|
1130
1269
|
state.taskErrors,
|
|
1131
|
-
state.ucErrors
|
|
1270
|
+
state.ucErrors,
|
|
1271
|
+
rootDir,
|
|
1272
|
+
options
|
|
1132
1273
|
);
|
|
1133
1274
|
}
|
|
1134
1275
|
|
|
@@ -5504,6 +5645,277 @@ function verifyTasksGovernance(options = {}) {
|
|
|
5504
5645
|
);
|
|
5505
5646
|
return assembleGovernanceResult(data, reportMarkdown);
|
|
5506
5647
|
}
|
|
5648
|
+
var BddStepRegistry = class {
|
|
5649
|
+
definitions = [];
|
|
5650
|
+
register(pattern, handler) {
|
|
5651
|
+
this.definitions.push({ pattern, handler });
|
|
5652
|
+
return this;
|
|
5653
|
+
}
|
|
5654
|
+
given(pattern, handler) {
|
|
5655
|
+
return this.register(pattern, handler);
|
|
5656
|
+
}
|
|
5657
|
+
when(pattern, handler) {
|
|
5658
|
+
return this.register(pattern, handler);
|
|
5659
|
+
}
|
|
5660
|
+
then(pattern, handler) {
|
|
5661
|
+
return this.register(pattern, handler);
|
|
5662
|
+
}
|
|
5663
|
+
getDefinitions() {
|
|
5664
|
+
return this.definitions;
|
|
5665
|
+
}
|
|
5666
|
+
};
|
|
5667
|
+
var STEP_PREFIX_RE = /^(Given|When|Then|And|But|Dado|Cuando|Entonces|Y|Pero)\s+(.+)$/i;
|
|
5668
|
+
var SCENARIO_HEADER_RE = /^(Scenario|Escenario|Scenario Outline|Esquema del escenario):\s*(.+)$/i;
|
|
5669
|
+
function parseTableRowCells(line) {
|
|
5670
|
+
return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
|
|
5671
|
+
}
|
|
5672
|
+
function attachStepTableRow(lastStep, cells) {
|
|
5673
|
+
if (!lastStep || cells.length < 2) return;
|
|
5674
|
+
if (!lastStep.table) lastStep.table = {};
|
|
5675
|
+
lastStep.table[cells[0]] = cells[1];
|
|
5676
|
+
}
|
|
5677
|
+
function attachExampleRow(scenario, headers, cells) {
|
|
5678
|
+
if (!scenario) return headers;
|
|
5679
|
+
if (headers.length === 0) return cells;
|
|
5680
|
+
const row = {};
|
|
5681
|
+
for (let i = 0; i < headers.length; i++) {
|
|
5682
|
+
row[headers[i]] = cells[i] ?? "";
|
|
5683
|
+
}
|
|
5684
|
+
scenario.examples.push(row);
|
|
5685
|
+
return headers;
|
|
5686
|
+
}
|
|
5687
|
+
function createInitialParseState() {
|
|
5688
|
+
return {
|
|
5689
|
+
featureName: "Unnamed Feature",
|
|
5690
|
+
featureTags: [],
|
|
5691
|
+
pendingTags: [],
|
|
5692
|
+
backgroundSteps: [],
|
|
5693
|
+
scenarios: [],
|
|
5694
|
+
currentScenario: null,
|
|
5695
|
+
inBackground: false,
|
|
5696
|
+
inExamples: false,
|
|
5697
|
+
exampleHeaders: []
|
|
5698
|
+
};
|
|
5699
|
+
}
|
|
5700
|
+
function handleStructuralHeaderLine(line, state) {
|
|
5701
|
+
if (/^(Feature|Caracter[ií]stica):/i.test(line)) {
|
|
5702
|
+
state.featureName = line.replace(/^(Feature|Caracter[ií]stica):\s*/i, "").trim();
|
|
5703
|
+
state.featureTags.push(...state.pendingTags);
|
|
5704
|
+
state.pendingTags = [];
|
|
5705
|
+
return true;
|
|
5706
|
+
}
|
|
5707
|
+
if (/^(Background|Antecedentes):/i.test(line)) {
|
|
5708
|
+
state.inBackground = true;
|
|
5709
|
+
state.inExamples = false;
|
|
5710
|
+
state.currentScenario = null;
|
|
5711
|
+
return true;
|
|
5712
|
+
}
|
|
5713
|
+
if (/^(Examples|Ejemplos):/i.test(line)) {
|
|
5714
|
+
state.inExamples = true;
|
|
5715
|
+
state.exampleHeaders = [];
|
|
5716
|
+
return true;
|
|
5717
|
+
}
|
|
5718
|
+
return false;
|
|
5719
|
+
}
|
|
5720
|
+
function startScenarioBlock(scenMatch, state) {
|
|
5721
|
+
state.inBackground = false;
|
|
5722
|
+
state.inExamples = false;
|
|
5723
|
+
const block = {
|
|
5724
|
+
name: scenMatch[2].trim(),
|
|
5725
|
+
tags: [...state.featureTags, ...state.pendingTags],
|
|
5726
|
+
isOutline: /outline|esquema/i.test(scenMatch[1]),
|
|
5727
|
+
steps: [],
|
|
5728
|
+
examples: []
|
|
5729
|
+
};
|
|
5730
|
+
state.pendingTags = [];
|
|
5731
|
+
state.scenarios.push(block);
|
|
5732
|
+
state.currentScenario = block;
|
|
5733
|
+
}
|
|
5734
|
+
function appendParsedStep(stepMatch, state) {
|
|
5735
|
+
const step = { keyword: stepMatch[1], text: stepMatch[2].trim() };
|
|
5736
|
+
if (state.inBackground) {
|
|
5737
|
+
state.backgroundSteps.push(step);
|
|
5738
|
+
} else if (state.currentScenario) {
|
|
5739
|
+
state.currentScenario.steps.push(step);
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
function handleScenarioOrStepLine(line, state) {
|
|
5743
|
+
const scenMatch = line.match(SCENARIO_HEADER_RE);
|
|
5744
|
+
if (scenMatch) {
|
|
5745
|
+
startScenarioBlock(scenMatch, state);
|
|
5746
|
+
return;
|
|
5747
|
+
}
|
|
5748
|
+
const stepMatch = line.match(STEP_PREFIX_RE);
|
|
5749
|
+
if (stepMatch) {
|
|
5750
|
+
appendParsedStep(stepMatch, state);
|
|
5751
|
+
}
|
|
5752
|
+
}
|
|
5753
|
+
function processFeatureLine(rawLine, state) {
|
|
5754
|
+
const line = rawLine.trim();
|
|
5755
|
+
if (!line || line.startsWith("#")) return;
|
|
5756
|
+
if (line.startsWith("@")) {
|
|
5757
|
+
const tags = line.split(/\s+/).filter((t) => t.startsWith("@"));
|
|
5758
|
+
state.pendingTags.push(...tags);
|
|
5759
|
+
return;
|
|
5760
|
+
}
|
|
5761
|
+
if (line.startsWith("|")) {
|
|
5762
|
+
const cells = parseTableRowCells(line);
|
|
5763
|
+
if (state.inExamples) {
|
|
5764
|
+
state.exampleHeaders = attachExampleRow(state.currentScenario, state.exampleHeaders, cells);
|
|
5765
|
+
} else {
|
|
5766
|
+
const targetList = state.inBackground ? state.backgroundSteps : state.currentScenario?.steps || [];
|
|
5767
|
+
attachStepTableRow(targetList[targetList.length - 1], cells);
|
|
5768
|
+
}
|
|
5769
|
+
return;
|
|
5770
|
+
}
|
|
5771
|
+
if (!handleStructuralHeaderLine(line, state)) {
|
|
5772
|
+
handleScenarioOrStepLine(line, state);
|
|
5773
|
+
}
|
|
5774
|
+
}
|
|
5775
|
+
function parseFeatureDocument(content) {
|
|
5776
|
+
const state = createInitialParseState();
|
|
5777
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
5778
|
+
processFeatureLine(rawLine, state);
|
|
5779
|
+
}
|
|
5780
|
+
return {
|
|
5781
|
+
featureName: state.featureName,
|
|
5782
|
+
tags: state.featureTags,
|
|
5783
|
+
backgroundSteps: state.backgroundSteps,
|
|
5784
|
+
scenarios: state.scenarios
|
|
5785
|
+
};
|
|
5786
|
+
}
|
|
5787
|
+
function interpolatePlaceholders(text, row) {
|
|
5788
|
+
let out = text;
|
|
5789
|
+
for (const [k, v] of Object.entries(row)) {
|
|
5790
|
+
out = out.replace(new RegExp(`<${k}>`, "g"), v);
|
|
5791
|
+
}
|
|
5792
|
+
return out;
|
|
5793
|
+
}
|
|
5794
|
+
function expandScenarioOutlines(scenarios) {
|
|
5795
|
+
const expanded = [];
|
|
5796
|
+
for (const sc of scenarios) {
|
|
5797
|
+
if (!sc.isOutline || sc.examples.length === 0) {
|
|
5798
|
+
expanded.push(sc);
|
|
5799
|
+
continue;
|
|
5800
|
+
}
|
|
5801
|
+
sc.examples.forEach((row, idx) => {
|
|
5802
|
+
expanded.push({
|
|
5803
|
+
name: `${sc.name} (Example #${idx + 1})`,
|
|
5804
|
+
tags: sc.tags,
|
|
5805
|
+
isOutline: false,
|
|
5806
|
+
steps: sc.steps.map((st) => ({
|
|
5807
|
+
keyword: st.keyword,
|
|
5808
|
+
text: interpolatePlaceholders(st.text, row),
|
|
5809
|
+
table: st.table
|
|
5810
|
+
})),
|
|
5811
|
+
examples: []
|
|
5812
|
+
});
|
|
5813
|
+
});
|
|
5814
|
+
}
|
|
5815
|
+
return expanded;
|
|
5816
|
+
}
|
|
5817
|
+
function matchStepDefinition(text, definitions) {
|
|
5818
|
+
for (const entry of definitions) {
|
|
5819
|
+
if (typeof entry.pattern === "string") {
|
|
5820
|
+
if (entry.pattern === text) return { entry, args: [] };
|
|
5821
|
+
} else {
|
|
5822
|
+
const m = text.match(entry.pattern);
|
|
5823
|
+
if (m) return { entry, args: m.slice(1) };
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5826
|
+
return null;
|
|
5827
|
+
}
|
|
5828
|
+
async function executeSingleStep(step, definitions) {
|
|
5829
|
+
const matched = matchStepDefinition(step.text, definitions);
|
|
5830
|
+
if (!matched) {
|
|
5831
|
+
return { keyword: step.keyword, text: step.text, status: "undefined", durationMs: 0 };
|
|
5832
|
+
}
|
|
5833
|
+
const start = Date.now();
|
|
5834
|
+
try {
|
|
5835
|
+
await matched.entry.handler(matched.args, step.table);
|
|
5836
|
+
return { keyword: step.keyword, text: step.text, status: "passed", durationMs: Date.now() - start };
|
|
5837
|
+
} catch (err) {
|
|
5838
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5839
|
+
return {
|
|
5840
|
+
keyword: step.keyword,
|
|
5841
|
+
text: step.text,
|
|
5842
|
+
status: "failed",
|
|
5843
|
+
durationMs: Date.now() - start,
|
|
5844
|
+
errorMessage: msg
|
|
5845
|
+
};
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
async function executeScenarioSteps(allSteps, definitions) {
|
|
5849
|
+
const stepResults = [];
|
|
5850
|
+
let status = "passed";
|
|
5851
|
+
for (const step of allSteps) {
|
|
5852
|
+
if (status !== "passed") {
|
|
5853
|
+
stepResults.push({ keyword: step.keyword, text: step.text, status: "skipped", durationMs: 0 });
|
|
5854
|
+
continue;
|
|
5855
|
+
}
|
|
5856
|
+
const res = await executeSingleStep(step, definitions);
|
|
5857
|
+
stepResults.push(res);
|
|
5858
|
+
if (res.status === "failed" || res.status === "undefined") {
|
|
5859
|
+
status = res.status;
|
|
5860
|
+
}
|
|
5861
|
+
}
|
|
5862
|
+
return { stepResults, status };
|
|
5863
|
+
}
|
|
5864
|
+
async function runAllExpandedScenarios(parsed, definitions) {
|
|
5865
|
+
const expanded = expandScenarioOutlines(parsed.scenarios);
|
|
5866
|
+
const out = [];
|
|
5867
|
+
for (const sc of expanded) {
|
|
5868
|
+
const combinedSteps = [...parsed.backgroundSteps, ...sc.steps];
|
|
5869
|
+
const { stepResults, status } = await executeScenarioSteps(combinedSteps, definitions);
|
|
5870
|
+
out.push({ name: sc.name, tags: sc.tags, status, steps: stepResults });
|
|
5871
|
+
}
|
|
5872
|
+
return out;
|
|
5873
|
+
}
|
|
5874
|
+
async function executeBddFeature(featurePath, registry, options = {}) {
|
|
5875
|
+
const rootDir = options.rootDir || process.cwd();
|
|
5876
|
+
const fullPath = path4.isAbsolute(featurePath) ? featurePath : path4.join(rootDir, featurePath);
|
|
5877
|
+
const parsed = parseFeatureDocument(fs7.readFileSync(fullPath, "utf-8"));
|
|
5878
|
+
const scenarios = await runAllExpandedScenarios(parsed, registry.getDefinitions());
|
|
5879
|
+
const report = {
|
|
5880
|
+
uri: path4.relative(rootDir, fullPath).replace(/\\/g, "/"),
|
|
5881
|
+
featureName: parsed.featureName,
|
|
5882
|
+
tags: parsed.tags,
|
|
5883
|
+
scenarios,
|
|
5884
|
+
passed: scenarios.length > 0 && scenarios.every((s) => s.status === "passed")
|
|
5885
|
+
};
|
|
5886
|
+
if (options.writeReportPath) writeCucumberJsonReport([report], options.writeReportPath);
|
|
5887
|
+
return report;
|
|
5888
|
+
}
|
|
5889
|
+
function mapStepToCucumberJson(st) {
|
|
5890
|
+
return {
|
|
5891
|
+
keyword: `${st.keyword} `,
|
|
5892
|
+
name: st.text,
|
|
5893
|
+
result: {
|
|
5894
|
+
status: st.status,
|
|
5895
|
+
duration: st.durationMs * 1e6,
|
|
5896
|
+
...st.errorMessage ? { error_message: st.errorMessage } : {}
|
|
5897
|
+
}
|
|
5898
|
+
};
|
|
5899
|
+
}
|
|
5900
|
+
function mapFeatureToCucumberJson(r) {
|
|
5901
|
+
return {
|
|
5902
|
+
uri: r.uri,
|
|
5903
|
+
name: r.featureName,
|
|
5904
|
+
tags: r.tags.map((t) => ({ name: t })),
|
|
5905
|
+
elements: r.scenarios.map((sc) => ({
|
|
5906
|
+
type: "scenario",
|
|
5907
|
+
name: sc.name,
|
|
5908
|
+
tags: sc.tags.map((t) => ({ name: t })),
|
|
5909
|
+
steps: sc.steps.map(mapStepToCucumberJson)
|
|
5910
|
+
}))
|
|
5911
|
+
};
|
|
5912
|
+
}
|
|
5913
|
+
function writeCucumberJsonReport(reports, outputPath) {
|
|
5914
|
+
const dir = path4.dirname(outputPath);
|
|
5915
|
+
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
5916
|
+
const payload = JSON.stringify(reports.map(mapFeatureToCucumberJson), null, 2);
|
|
5917
|
+
fs7.writeFileSync(outputPath, payload, "utf-8");
|
|
5918
|
+
}
|
|
5507
5919
|
function isToolAvailable(toolName) {
|
|
5508
5920
|
try {
|
|
5509
5921
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
@@ -5657,6 +6069,214 @@ function scanPnpmStore(pnpmDir, directNames, seen) {
|
|
|
5657
6069
|
}
|
|
5658
6070
|
}
|
|
5659
6071
|
}
|
|
6072
|
+
function readTextIfExists(filePath) {
|
|
6073
|
+
if (!fs7.existsSync(filePath)) return null;
|
|
6074
|
+
try {
|
|
6075
|
+
return fs7.readFileSync(filePath, "utf-8");
|
|
6076
|
+
} catch {
|
|
6077
|
+
return null;
|
|
6078
|
+
}
|
|
6079
|
+
}
|
|
6080
|
+
function extractTomlField(block, key) {
|
|
6081
|
+
const m = block.match(new RegExp(`^\\s*${key}\\s*=\\s*["']([^"']+)["']`, "m"));
|
|
6082
|
+
return m ? m[1].trim() : void 0;
|
|
6083
|
+
}
|
|
6084
|
+
function extractPyprojectDirectDeps(content) {
|
|
6085
|
+
const direct = /* @__PURE__ */ new Set();
|
|
6086
|
+
const matches = content.matchAll(/^([a-zA-Z0-9_.-]+)\s*=\s*(?:["'{]|true)/gm);
|
|
6087
|
+
for (const m of matches) {
|
|
6088
|
+
const key = m[1].toLowerCase();
|
|
6089
|
+
if (!["name", "version", "description", "license", "python", "readme"].includes(key)) {
|
|
6090
|
+
direct.add(key);
|
|
6091
|
+
}
|
|
6092
|
+
}
|
|
6093
|
+
return direct;
|
|
6094
|
+
}
|
|
6095
|
+
function parseSingleTomlBlock(block, lockPath, directNames) {
|
|
6096
|
+
const name = extractTomlField(block, "name");
|
|
6097
|
+
const version = extractTomlField(block, "version");
|
|
6098
|
+
if (!name || !version) return null;
|
|
6099
|
+
const spdx = normalizeSpdxLicense(extractTomlField(block, "license") || "UNKNOWN");
|
|
6100
|
+
return {
|
|
6101
|
+
name,
|
|
6102
|
+
version,
|
|
6103
|
+
spdxLicense: spdx,
|
|
6104
|
+
purl: `pkg:pypi/${name.toLowerCase()}@${version}`,
|
|
6105
|
+
path: lockPath,
|
|
6106
|
+
isDirect: directNames.size === 0 || directNames.has(name.toLowerCase())
|
|
6107
|
+
};
|
|
6108
|
+
}
|
|
6109
|
+
function parseTomlPackageBlocks(content, lockPath, directNames, seen) {
|
|
6110
|
+
for (const block of content.split(/\[\[package\]\]/g).slice(1)) {
|
|
6111
|
+
const dep = parseSingleTomlBlock(block, lockPath, directNames);
|
|
6112
|
+
if (dep && !seen.has(`pypi:${dep.name}@${dep.version}`)) {
|
|
6113
|
+
seen.set(`pypi:${dep.name}@${dep.version}`, dep);
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
function parsePipfileSection(pkgs, isDirect, lockPath, seen) {
|
|
6118
|
+
for (const [name, meta] of Object.entries(pkgs)) {
|
|
6119
|
+
const rawVer = String(meta.version || "").replace(/^==/, "") || "unknown";
|
|
6120
|
+
const spdx = normalizeSpdxLicense(meta.license || "UNKNOWN");
|
|
6121
|
+
const key = `pypi:${name}@${rawVer}`;
|
|
6122
|
+
if (!seen.has(key)) {
|
|
6123
|
+
seen.set(key, {
|
|
6124
|
+
name,
|
|
6125
|
+
version: rawVer,
|
|
6126
|
+
spdxLicense: spdx,
|
|
6127
|
+
purl: `pkg:pypi/${name.toLowerCase()}@${rawVer}`,
|
|
6128
|
+
path: lockPath,
|
|
6129
|
+
isDirect
|
|
6130
|
+
});
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
function scanPythonDependencies(rootDir, seen) {
|
|
6135
|
+
const pyproject = readTextIfExists(path4.join(rootDir, "pyproject.toml")) || "";
|
|
6136
|
+
const directNames = extractPyprojectDirectDeps(pyproject);
|
|
6137
|
+
for (const lockName of ["poetry.lock", "uv.lock"]) {
|
|
6138
|
+
const lockPath = path4.join(rootDir, lockName);
|
|
6139
|
+
const content = readTextIfExists(lockPath);
|
|
6140
|
+
if (content) parseTomlPackageBlocks(content, lockPath, directNames, seen);
|
|
6141
|
+
}
|
|
6142
|
+
const pipfileLockPath = path4.join(rootDir, "Pipfile.lock");
|
|
6143
|
+
const pipfileRaw = readTextIfExists(pipfileLockPath);
|
|
6144
|
+
if (!pipfileRaw) return;
|
|
6145
|
+
try {
|
|
6146
|
+
const data = JSON.parse(pipfileRaw);
|
|
6147
|
+
parsePipfileSection(data.default || {}, true, pipfileLockPath, seen);
|
|
6148
|
+
parsePipfileSection(data.develop || {}, false, pipfileLockPath, seen);
|
|
6149
|
+
} catch {
|
|
6150
|
+
}
|
|
6151
|
+
}
|
|
6152
|
+
function parseGoRequireLine(line, goModPath) {
|
|
6153
|
+
const cleaned = line.replace(/^require\s+/, "").trim();
|
|
6154
|
+
const commentIdx = cleaned.indexOf("//");
|
|
6155
|
+
const codePart = (commentIdx >= 0 ? cleaned.slice(0, commentIdx) : cleaned).trim();
|
|
6156
|
+
const commentPart = commentIdx >= 0 ? cleaned.slice(commentIdx + 2).trim() : "";
|
|
6157
|
+
const parts = codePart.split(/\s+/);
|
|
6158
|
+
if (parts.length < 2) return null;
|
|
6159
|
+
const modName = parts[0];
|
|
6160
|
+
const rawVer = parts[1].replace(/^v/, "");
|
|
6161
|
+
const isIndirect = /\bindirect\b/i.test(commentPart);
|
|
6162
|
+
const licenseMatch = commentPart.match(/(?:spdx|license)\s*:\s*([A-Za-z0-9.+-]+)/i);
|
|
6163
|
+
const spdx = licenseMatch ? normalizeSpdxLicense(licenseMatch[1]) : "UNKNOWN";
|
|
6164
|
+
return {
|
|
6165
|
+
name: modName,
|
|
6166
|
+
version: rawVer,
|
|
6167
|
+
spdxLicense: spdx,
|
|
6168
|
+
purl: `pkg:golang/${modName}@v${rawVer}`,
|
|
6169
|
+
path: goModPath,
|
|
6170
|
+
isDirect: !isIndirect
|
|
6171
|
+
};
|
|
6172
|
+
}
|
|
6173
|
+
function extractGoCandidateLines(content) {
|
|
6174
|
+
const out = [];
|
|
6175
|
+
let inBlock = false;
|
|
6176
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
6177
|
+
const trimmed = rawLine.trim();
|
|
6178
|
+
if (/^require\s*\($/.test(trimmed)) inBlock = true;
|
|
6179
|
+
else if (inBlock && trimmed === ")") inBlock = false;
|
|
6180
|
+
else if (inBlock || trimmed.startsWith("require ")) out.push(trimmed);
|
|
6181
|
+
}
|
|
6182
|
+
return out;
|
|
6183
|
+
}
|
|
6184
|
+
function scanGoDependencies(rootDir, seen) {
|
|
6185
|
+
const goModPath = path4.join(rootDir, "go.mod");
|
|
6186
|
+
const content = readTextIfExists(goModPath);
|
|
6187
|
+
if (!content) return;
|
|
6188
|
+
for (const line of extractGoCandidateLines(content)) {
|
|
6189
|
+
const dep = parseGoRequireLine(line, goModPath);
|
|
6190
|
+
if (dep && !seen.has(`golang:${dep.name}@${dep.version}`)) {
|
|
6191
|
+
seen.set(`golang:${dep.name}@${dep.version}`, dep);
|
|
6192
|
+
}
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
function extractCargoDirectDeps(cargoToml) {
|
|
6196
|
+
const map = /* @__PURE__ */ new Map();
|
|
6197
|
+
let inDeps = false;
|
|
6198
|
+
for (const line of cargoToml.split(/\r?\n/)) {
|
|
6199
|
+
const trimmed = line.trim();
|
|
6200
|
+
if (trimmed.startsWith("[")) {
|
|
6201
|
+
inDeps = /^\[(?:dev-|build-)?dependencies\]$/.test(trimmed);
|
|
6202
|
+
continue;
|
|
6203
|
+
}
|
|
6204
|
+
if (!inDeps || !trimmed || trimmed.startsWith("#")) continue;
|
|
6205
|
+
const m = trimmed.match(/^([a-zA-Z0-9_-]+)\s*=\s*(.+)$/);
|
|
6206
|
+
if (m) {
|
|
6207
|
+
const licMatch = m[2].match(/license\s*=\s*["']([^"']+)["']/);
|
|
6208
|
+
map.set(m[1], licMatch ? licMatch[1] : "UNKNOWN");
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
return map;
|
|
6212
|
+
}
|
|
6213
|
+
function parseCargoLockBlock(block, rootName, directMeta, cargoLockPath) {
|
|
6214
|
+
const name = extractTomlField(block, "name");
|
|
6215
|
+
const version = extractTomlField(block, "version");
|
|
6216
|
+
if (!name || !version || name === rootName) return null;
|
|
6217
|
+
const blockLic = extractTomlField(block, "license") || directMeta.get(name) || "UNKNOWN";
|
|
6218
|
+
return {
|
|
6219
|
+
name,
|
|
6220
|
+
version,
|
|
6221
|
+
spdxLicense: normalizeSpdxLicense(blockLic),
|
|
6222
|
+
purl: `pkg:cargo/${name}@${version}`,
|
|
6223
|
+
path: cargoLockPath,
|
|
6224
|
+
isDirect: directMeta.size === 0 || directMeta.has(name)
|
|
6225
|
+
};
|
|
6226
|
+
}
|
|
6227
|
+
function scanRustDependencies(rootDir, seen) {
|
|
6228
|
+
const cargoLockPath = path4.join(rootDir, "Cargo.lock");
|
|
6229
|
+
const lockContent = readTextIfExists(cargoLockPath);
|
|
6230
|
+
if (!lockContent) return;
|
|
6231
|
+
const cargoToml = readTextIfExists(path4.join(rootDir, "Cargo.toml")) || "";
|
|
6232
|
+
const directMeta = extractCargoDirectDeps(cargoToml);
|
|
6233
|
+
const rootName = extractTomlField(cargoToml, "name");
|
|
6234
|
+
for (const block of lockContent.split(/\[\[package\]\]/g).slice(1)) {
|
|
6235
|
+
const dep = parseCargoLockBlock(block, rootName, directMeta, cargoLockPath);
|
|
6236
|
+
if (dep && !seen.has(`cargo:${dep.name}@${dep.version}`)) {
|
|
6237
|
+
seen.set(`cargo:${dep.name}@${dep.version}`, dep);
|
|
6238
|
+
}
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
function extractXmlTag(xml, tag) {
|
|
6242
|
+
const m = xml.match(new RegExp(`<${tag}>([^<]+)</${tag}>`));
|
|
6243
|
+
return m ? m[1].trim() : void 0;
|
|
6244
|
+
}
|
|
6245
|
+
function resolveMavenBlockLicense(block, defaultLic) {
|
|
6246
|
+
const tagLic = extractXmlTag(block, "license");
|
|
6247
|
+
if (tagLic) return tagLic;
|
|
6248
|
+
const commentLic = block.match(/<!--\s*(?:spdx|license)\s*:\s*([A-Za-z0-9.+-]+)\s*-->/i)?.[1];
|
|
6249
|
+
return commentLic || defaultLic;
|
|
6250
|
+
}
|
|
6251
|
+
function parseMavenDepBlock(block, defaultLic, pomPath) {
|
|
6252
|
+
const groupId = extractXmlTag(block, "groupId");
|
|
6253
|
+
const artifactId = extractXmlTag(block, "artifactId");
|
|
6254
|
+
if (!groupId || !artifactId) return null;
|
|
6255
|
+
const version = extractXmlTag(block, "version") || "unknown";
|
|
6256
|
+
const inlineLic = resolveMavenBlockLicense(block, defaultLic);
|
|
6257
|
+
return {
|
|
6258
|
+
name: `${groupId}:${artifactId}`,
|
|
6259
|
+
version,
|
|
6260
|
+
spdxLicense: normalizeSpdxLicense(inlineLic),
|
|
6261
|
+
purl: `pkg:maven/${groupId}/${artifactId}@${version}`,
|
|
6262
|
+
path: pomPath,
|
|
6263
|
+
isDirect: true
|
|
6264
|
+
};
|
|
6265
|
+
}
|
|
6266
|
+
function scanMavenDependencies(rootDir, seen) {
|
|
6267
|
+
const pomPath = path4.join(rootDir, "pom.xml");
|
|
6268
|
+
const content = readTextIfExists(pomPath);
|
|
6269
|
+
if (!content) return;
|
|
6270
|
+
const projectLicBlock = content.match(/<licenses>([\s\S]*?)<\/licenses>/)?.[1] || "";
|
|
6271
|
+
const defaultLic = extractXmlTag(projectLicBlock, "name") || "UNKNOWN";
|
|
6272
|
+
const depBlocks = content.match(/<dependency>[\s\S]*?<\/dependency>/g) || [];
|
|
6273
|
+
for (const block of depBlocks) {
|
|
6274
|
+
const dep = parseMavenDepBlock(block, defaultLic, pomPath);
|
|
6275
|
+
if (dep && !seen.has(`maven:${dep.name}@${dep.version}`)) {
|
|
6276
|
+
seen.set(`maven:${dep.name}@${dep.version}`, dep);
|
|
6277
|
+
}
|
|
6278
|
+
}
|
|
6279
|
+
}
|
|
5660
6280
|
function scanWithNativeFs(rootDir, options = {}) {
|
|
5661
6281
|
const directNames = extractDirectDepNames(rootDir, options.productionOnly);
|
|
5662
6282
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -5667,6 +6287,10 @@ function scanWithNativeFs(rootDir, options = {}) {
|
|
|
5667
6287
|
scanPnpmStore(path4.join(nmDir, ".pnpm"), directNames, seen);
|
|
5668
6288
|
}
|
|
5669
6289
|
}
|
|
6290
|
+
scanPythonDependencies(rootDir, seen);
|
|
6291
|
+
scanGoDependencies(rootDir, seen);
|
|
6292
|
+
scanRustDependencies(rootDir, seen);
|
|
6293
|
+
scanMavenDependencies(rootDir, seen);
|
|
5670
6294
|
const allDeps = Array.from(seen.values());
|
|
5671
6295
|
if (options.depth === "direct") {
|
|
5672
6296
|
return allDeps.filter((d) => d.isDirect);
|
|
@@ -5736,10 +6360,17 @@ var SEVERITY_RANK = {
|
|
|
5736
6360
|
LOW: 1,
|
|
5737
6361
|
UNKNOWN: 0
|
|
5738
6362
|
};
|
|
6363
|
+
function isExemptByVex(v, vexStatements) {
|
|
6364
|
+
if (!vexStatements || vexStatements.length === 0) return false;
|
|
6365
|
+
return vexStatements.some(
|
|
6366
|
+
(stmt) => stmt.id === v.id && (stmt.state === "not_affected" || stmt.state === "fixed") && (!stmt.package || stmt.package === v.packageName)
|
|
6367
|
+
);
|
|
6368
|
+
}
|
|
5739
6369
|
function evaluateVulnerabilityThresholds(vulnerabilities, options) {
|
|
5740
6370
|
const minRank = options?.failOnSeverity ? SEVERITY_RANK[options.failOnSeverity] ?? 3 : void 0;
|
|
5741
6371
|
const maxScore = options?.maxCvssScore;
|
|
5742
6372
|
const failing = vulnerabilities.filter((v) => {
|
|
6373
|
+
if (isExemptByVex(v, options?.vexStatements)) return false;
|
|
5743
6374
|
const rankMatch = minRank !== void 0 && SEVERITY_RANK[v.severity] >= minRank;
|
|
5744
6375
|
const scoreMatch = maxScore !== void 0 && v.cvssV3Score !== void 0 && v.cvssV3Score >= maxScore;
|
|
5745
6376
|
return rankMatch || scoreMatch;
|
|
@@ -5869,42 +6500,77 @@ function buildCycloneDxComponent(dep) {
|
|
|
5869
6500
|
}
|
|
5870
6501
|
return comp;
|
|
5871
6502
|
}
|
|
5872
|
-
function
|
|
6503
|
+
function buildVexAnalysis(vex) {
|
|
6504
|
+
if (!vex) return void 0;
|
|
6505
|
+
return {
|
|
6506
|
+
state: vex.state,
|
|
6507
|
+
justification: vex.justification,
|
|
6508
|
+
detail: vex.detail,
|
|
6509
|
+
response: vex.response
|
|
6510
|
+
};
|
|
6511
|
+
}
|
|
6512
|
+
function mapScaVulnToCycloneDx(v, vexStatements) {
|
|
6513
|
+
const matchingVex = vexStatements.find(
|
|
6514
|
+
(stmt) => stmt.id === v.id && (!stmt.package || stmt.package === v.packageName)
|
|
6515
|
+
);
|
|
6516
|
+
return {
|
|
6517
|
+
id: v.id,
|
|
6518
|
+
source: v.primaryUrl ? { name: "NVD/GHSA", url: v.primaryUrl } : void 0,
|
|
6519
|
+
ratings: [{ score: v.cvssV3Score, severity: v.severity.toLowerCase(), method: "CVSSv3", vector: v.cvssV3Vector }],
|
|
6520
|
+
analysis: buildVexAnalysis(matchingVex),
|
|
6521
|
+
affects: [{ ref: `pkg:npm/${v.packageName}@${v.installedVersion}` }]
|
|
6522
|
+
};
|
|
6523
|
+
}
|
|
6524
|
+
function mapStandaloneVex(stmt) {
|
|
6525
|
+
return {
|
|
6526
|
+
id: stmt.id,
|
|
6527
|
+
analysis: buildVexAnalysis(stmt),
|
|
6528
|
+
affects: stmt.package ? [{ ref: stmt.package }] : void 0
|
|
6529
|
+
};
|
|
6530
|
+
}
|
|
6531
|
+
function buildCycloneDxVulnerabilities(vulnerabilities = [], vexStatements = []) {
|
|
6532
|
+
const out = vulnerabilities.map((v) => mapScaVulnToCycloneDx(v, vexStatements));
|
|
6533
|
+
const seenIds = new Set(out.map((item) => item.id));
|
|
6534
|
+
for (const stmt of vexStatements) {
|
|
6535
|
+
if (!seenIds.has(stmt.id)) {
|
|
6536
|
+
out.push(mapStandaloneVex(stmt));
|
|
6537
|
+
seenIds.add(stmt.id);
|
|
6538
|
+
}
|
|
6539
|
+
}
|
|
6540
|
+
return out;
|
|
6541
|
+
}
|
|
6542
|
+
function resolveProjectIdentity(options) {
|
|
5873
6543
|
let name = options.projectName || "ai-sdlc-project";
|
|
5874
6544
|
let version = options.projectVersion || "1.0.0";
|
|
5875
|
-
if (options.rootDir) {
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
}
|
|
5884
|
-
}
|
|
6545
|
+
if (!options.rootDir) return { name, version };
|
|
6546
|
+
const pkgPath = path4.join(options.rootDir, "package.json");
|
|
6547
|
+
if (!fs7.existsSync(pkgPath)) return { name, version };
|
|
6548
|
+
try {
|
|
6549
|
+
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
6550
|
+
if (pkg.name) name = pkg.name;
|
|
6551
|
+
if (pkg.version) version = pkg.version;
|
|
6552
|
+
} catch {
|
|
5885
6553
|
}
|
|
5886
|
-
|
|
6554
|
+
return { name, version };
|
|
6555
|
+
}
|
|
6556
|
+
function buildBomMetadata(name, version) {
|
|
6557
|
+
return {
|
|
6558
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6559
|
+
tools: [{ vendor: "AI-SDLC", name: "@aisdlc/core", version: "2.4.0" }],
|
|
6560
|
+
component: { type: "application", name, version }
|
|
6561
|
+
};
|
|
6562
|
+
}
|
|
6563
|
+
function generateCycloneDxSbom(dependencies, options = {}) {
|
|
6564
|
+
const { name, version } = resolveProjectIdentity(options);
|
|
6565
|
+
const cdxVulns = buildCycloneDxVulnerabilities(options.vulnerabilities, options.vexStatements);
|
|
5887
6566
|
return {
|
|
5888
6567
|
bomFormat: "CycloneDX",
|
|
5889
6568
|
specVersion: "1.5",
|
|
5890
6569
|
version: 1,
|
|
5891
6570
|
serialNumber: `urn:uuid:${crypto.randomUUID()}`,
|
|
5892
|
-
metadata:
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
{
|
|
5896
|
-
vendor: "AI-SDLC",
|
|
5897
|
-
name: "@aisdlc/core",
|
|
5898
|
-
version: "1.0.0"
|
|
5899
|
-
}
|
|
5900
|
-
],
|
|
5901
|
-
component: {
|
|
5902
|
-
type: "application",
|
|
5903
|
-
name,
|
|
5904
|
-
version
|
|
5905
|
-
}
|
|
5906
|
-
},
|
|
5907
|
-
components
|
|
6571
|
+
metadata: buildBomMetadata(name, version),
|
|
6572
|
+
components: dependencies.map(buildCycloneDxComponent),
|
|
6573
|
+
...cdxVulns.length > 0 ? { vulnerabilities: cdxVulns } : {}
|
|
5908
6574
|
};
|
|
5909
6575
|
}
|
|
5910
6576
|
function tryAtomicWrite(filePath, content) {
|
|
@@ -6072,17 +6738,24 @@ function parseExceptions(exceptions) {
|
|
|
6072
6738
|
}
|
|
6073
6739
|
return map;
|
|
6074
6740
|
}
|
|
6741
|
+
function parseVexStatements(doc) {
|
|
6742
|
+
const rawList = doc?.vex_statements || doc?.exceptions?.vex_statements || [];
|
|
6743
|
+
if (!Array.isArray(rawList)) return [];
|
|
6744
|
+
return rawList.filter((item) => Boolean(item && typeof item.id === "string" && typeof item.state === "string"));
|
|
6745
|
+
}
|
|
6075
6746
|
function parseLicensePolicy(content) {
|
|
6076
6747
|
try {
|
|
6077
6748
|
const doc = yaml3.load(content);
|
|
6078
6749
|
const { permitted, restricted, blocked } = classifyCategories(doc?.categories);
|
|
6079
6750
|
const exception_packages = parseExceptions(doc?.exceptions);
|
|
6751
|
+
const vex_statements = parseVexStatements(doc);
|
|
6080
6752
|
return {
|
|
6081
6753
|
version: doc?.version || "1.0",
|
|
6082
6754
|
permitted: permitted.length > 0 ? permitted : DEFAULT_PERMITTED,
|
|
6083
6755
|
restricted: restricted.length > 0 ? restricted : DEFAULT_RESTRICTED,
|
|
6084
6756
|
blocked: blocked.length > 0 ? blocked : DEFAULT_BLOCKED,
|
|
6085
6757
|
exception_packages,
|
|
6758
|
+
vex_statements,
|
|
6086
6759
|
rawPolicy: doc
|
|
6087
6760
|
};
|
|
6088
6761
|
} catch {
|
|
@@ -6091,7 +6764,8 @@ function parseLicensePolicy(content) {
|
|
|
6091
6764
|
permitted: DEFAULT_PERMITTED,
|
|
6092
6765
|
restricted: DEFAULT_RESTRICTED,
|
|
6093
6766
|
blocked: DEFAULT_BLOCKED,
|
|
6094
|
-
exception_packages: {}
|
|
6767
|
+
exception_packages: {},
|
|
6768
|
+
vex_statements: []
|
|
6095
6769
|
};
|
|
6096
6770
|
}
|
|
6097
6771
|
}
|
|
@@ -6266,10 +6940,10 @@ function shouldGenerateSbom(options, rawPolicy) {
|
|
|
6266
6940
|
if (options.generateSbom === false) return false;
|
|
6267
6941
|
return Boolean(options.generateSbom || options.sbomPath || rawPolicy?.ci_gates?.generate_sbom);
|
|
6268
6942
|
}
|
|
6269
|
-
function maybeGenerateSbom(options, rootDir, rawPolicy, dependencies) {
|
|
6943
|
+
function maybeGenerateSbom(options, rootDir, rawPolicy, dependencies, vulnerabilities, vexStatements) {
|
|
6270
6944
|
if (!shouldGenerateSbom(options, rawPolicy)) return void 0;
|
|
6271
6945
|
const sbomPath = options.sbomPath || path4.join(rootDir, "reports", "sbom.cdx.json");
|
|
6272
|
-
const sbom = generateCycloneDxSbom(dependencies, { rootDir });
|
|
6946
|
+
const sbom = generateCycloneDxSbom(dependencies, { rootDir, vulnerabilities, vexStatements });
|
|
6273
6947
|
writeCycloneDxSbom(sbom, sbomPath);
|
|
6274
6948
|
return sbomPath;
|
|
6275
6949
|
}
|
|
@@ -6282,9 +6956,9 @@ function maybeGenerateNotices(options, rootDir, rawPolicy, dependencies) {
|
|
|
6282
6956
|
writeThirdPartyNotices(noticesContent, noticesPath);
|
|
6283
6957
|
return noticesPath;
|
|
6284
6958
|
}
|
|
6285
|
-
function handleDynamicScaArtifacts(options, rootDir, rawPolicy, dependencies) {
|
|
6959
|
+
function handleDynamicScaArtifacts(options, rootDir, rawPolicy, dependencies, vulnerabilities, vexStatements) {
|
|
6286
6960
|
return {
|
|
6287
|
-
sbomPath: maybeGenerateSbom(options, rootDir, rawPolicy, dependencies),
|
|
6961
|
+
sbomPath: maybeGenerateSbom(options, rootDir, rawPolicy, dependencies, vulnerabilities, vexStatements),
|
|
6288
6962
|
noticesPath: maybeGenerateNotices(options, rootDir, rawPolicy, dependencies)
|
|
6289
6963
|
};
|
|
6290
6964
|
}
|
|
@@ -6313,7 +6987,7 @@ function buildSkippedVulnResult() {
|
|
|
6313
6987
|
skipReason: "Trivy scanner is not installed on host environment. Vulnerability check gracefully skipped."
|
|
6314
6988
|
};
|
|
6315
6989
|
}
|
|
6316
|
-
function checkVulnerabilities(rootDir, options) {
|
|
6990
|
+
function checkVulnerabilities(rootDir, options, vexStatements) {
|
|
6317
6991
|
if (options.scanVulnerabilities === false) {
|
|
6318
6992
|
return { vulnerabilities: [], blocked: false };
|
|
6319
6993
|
}
|
|
@@ -6321,7 +6995,10 @@ function checkVulnerabilities(rootDir, options) {
|
|
|
6321
6995
|
if (!res.executed) {
|
|
6322
6996
|
return buildSkippedVulnResult();
|
|
6323
6997
|
}
|
|
6324
|
-
const evalResult = evaluateVulnerabilityThresholds(res.vulnerabilities,
|
|
6998
|
+
const evalResult = evaluateVulnerabilityThresholds(res.vulnerabilities, {
|
|
6999
|
+
...options.vulnerabilityThresholds,
|
|
7000
|
+
vexStatements
|
|
7001
|
+
});
|
|
6325
7002
|
return { vulnerabilities: res.vulnerabilities, blocked: evalResult.blocked };
|
|
6326
7003
|
}
|
|
6327
7004
|
function assembleDynamicLicenseResult(dependencies, permittedCount, violations, reportMarkdown, artifacts, vulnData) {
|
|
@@ -6345,7 +7022,8 @@ function toCleanPolicy(policyWithRaw) {
|
|
|
6345
7022
|
permitted: policyWithRaw.permitted,
|
|
6346
7023
|
restricted: policyWithRaw.restricted,
|
|
6347
7024
|
blocked: policyWithRaw.blocked,
|
|
6348
|
-
exception_packages: policyWithRaw.exception_packages
|
|
7025
|
+
exception_packages: policyWithRaw.exception_packages,
|
|
7026
|
+
vex_statements: policyWithRaw.vex_statements
|
|
6349
7027
|
};
|
|
6350
7028
|
}
|
|
6351
7029
|
function scanDependenciesForVerification(options, rootDir, rawPolicy) {
|
|
@@ -6365,8 +7043,15 @@ function verifyLicenses(options = {}) {
|
|
|
6365
7043
|
}
|
|
6366
7044
|
const dependencies = scanDependenciesForVerification(options, rootDir, policyWithRaw.rawPolicy);
|
|
6367
7045
|
const { violations, permittedCount } = evaluateDependencyList(dependencies, policy);
|
|
6368
|
-
const
|
|
6369
|
-
const
|
|
7046
|
+
const vulnData = checkVulnerabilities(rootDir, options, policy.vex_statements);
|
|
7047
|
+
const artifacts = handleDynamicScaArtifacts(
|
|
7048
|
+
options,
|
|
7049
|
+
rootDir,
|
|
7050
|
+
policyWithRaw.rawPolicy,
|
|
7051
|
+
dependencies,
|
|
7052
|
+
vulnData.vulnerabilities,
|
|
7053
|
+
policy.vex_statements
|
|
7054
|
+
);
|
|
6370
7055
|
const reportMarkdown = generateLicenseReportMarkdown(dependencies, violations, policy, artifacts.sbomPath);
|
|
6371
7056
|
return assembleDynamicLicenseResult(dependencies, permittedCount, violations, reportMarkdown, artifacts, vulnData);
|
|
6372
7057
|
}
|
|
@@ -15906,7 +16591,145 @@ function initProject(options = {}) {
|
|
|
15906
16591
|
tryInstallGitHook(destDir, options.dryRun)
|
|
15907
16592
|
);
|
|
15908
16593
|
}
|
|
16594
|
+
var DEFAULT_DLP_RULES = [
|
|
16595
|
+
{
|
|
16596
|
+
id: "DLP-001-PRIVATE-KEY",
|
|
16597
|
+
description: "PEM / RSA / EC / OPENSSH Private Key Block",
|
|
16598
|
+
pattern: "-----BEGIN (?:[A-Z0-9_-]+ )?PRIVATE KEY-----[\\s\\S]*?-----END (?:[A-Z0-9_-]+ )?PRIVATE KEY-----",
|
|
16599
|
+
replacement: "[REDACTED:PRIVATE_KEY]",
|
|
16600
|
+
enabled: true
|
|
16601
|
+
},
|
|
16602
|
+
{
|
|
16603
|
+
id: "DLP-002-API-TOKEN",
|
|
16604
|
+
description: "Cloud, GitHub, Slack, OpenAI, Stripe, and AWS Access Tokens",
|
|
16605
|
+
pattern: "\\b(?:gh[pousr]_[A-Za-z0-9_]{36,255}|github_pat_[0-9a-zA-Z_]{82}|sk-(?:proj-|live-)?[a-zA-Z0-9_-]{32,}|AKIA[0-9A-Z]{16}|xox[baprs]-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*|(?:sk|rk)_(?:live|test)_[0-9a-zA-Z]{24,99})\\b",
|
|
16606
|
+
replacement: "[REDACTED:API_TOKEN]",
|
|
16607
|
+
enabled: true
|
|
16608
|
+
},
|
|
16609
|
+
{
|
|
16610
|
+
id: "DLP-003-JWT",
|
|
16611
|
+
description: "Plaintext JSON Web Token (JWT)",
|
|
16612
|
+
pattern: "\\beyJ[A-Za-z0-9_-]{10,}\\.eyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\b",
|
|
16613
|
+
replacement: "[REDACTED:JWT_TOKEN]",
|
|
16614
|
+
enabled: true
|
|
16615
|
+
},
|
|
16616
|
+
{
|
|
16617
|
+
id: "DLP-004-CREDIT-CARD",
|
|
16618
|
+
description: "Payment Card Number (13-19 digits formatted)",
|
|
16619
|
+
pattern: "\\b(?:\\d{4}[- ]\\d{4}[- ]\\d{4}[- ]\\d{4}|\\d{16})\\b",
|
|
16620
|
+
replacement: "[REDACTED:CREDIT_CARD]",
|
|
16621
|
+
enabled: true
|
|
16622
|
+
},
|
|
16623
|
+
{
|
|
16624
|
+
id: "DLP-005-EMAIL",
|
|
16625
|
+
description: "Personal or Corporate Email Address",
|
|
16626
|
+
pattern: "\\b[A-Za-z0-9._%+-]+@(?!example\\.com|localhost|test\\.local)[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b",
|
|
16627
|
+
replacement: "[REDACTED:EMAIL]",
|
|
16628
|
+
enabled: true
|
|
16629
|
+
},
|
|
16630
|
+
{
|
|
16631
|
+
id: "DLP-006-INTERNAL-URL",
|
|
16632
|
+
description: "Internal Intranet / Corp Service URL",
|
|
16633
|
+
pattern: "https?://(?:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+@|[A-Za-z0-9.-]+\\.(?:internal|corp|intranet|local)\\b)[^\\s\"'`<>]*",
|
|
16634
|
+
replacement: "[REDACTED:INTERNAL_URL]",
|
|
16635
|
+
enabled: true
|
|
16636
|
+
}
|
|
16637
|
+
];
|
|
16638
|
+
function createDefaultDlpPolicy() {
|
|
16639
|
+
return {
|
|
16640
|
+
version: "1.0",
|
|
16641
|
+
enabled: true,
|
|
16642
|
+
zero_data_retention_required: true,
|
|
16643
|
+
rules: [...DEFAULT_DLP_RULES]
|
|
16644
|
+
};
|
|
16645
|
+
}
|
|
16646
|
+
function normalizeParsedRule(raw, idx) {
|
|
16647
|
+
if (typeof raw.pattern !== "string" || !raw.pattern) return null;
|
|
16648
|
+
return {
|
|
16649
|
+
id: typeof raw.id === "string" ? raw.id : `DLP-CUSTOM-${idx + 1}`,
|
|
16650
|
+
description: typeof raw.description === "string" ? raw.description : "Custom DLP rule",
|
|
16651
|
+
pattern: raw.pattern,
|
|
16652
|
+
replacement: typeof raw.replacement === "string" ? raw.replacement : "[REDACTED]",
|
|
16653
|
+
enabled: raw.enabled !== false
|
|
16654
|
+
};
|
|
16655
|
+
}
|
|
16656
|
+
function parseDlpPolicy(yamlContent) {
|
|
16657
|
+
const fallback = createDefaultDlpPolicy();
|
|
16658
|
+
if (!yamlContent || !yamlContent.trim()) return fallback;
|
|
16659
|
+
try {
|
|
16660
|
+
const doc = yaml3.load(yamlContent);
|
|
16661
|
+
if (!doc || typeof doc !== "object") return fallback;
|
|
16662
|
+
const rawRules = Array.isArray(doc.rules) ? doc.rules : [];
|
|
16663
|
+
const parsedRules = rawRules.map((r, i) => normalizeParsedRule(r, i)).filter((r) => r !== null);
|
|
16664
|
+
return {
|
|
16665
|
+
version: typeof doc.version === "string" ? doc.version : "1.0",
|
|
16666
|
+
enabled: doc.enabled !== false,
|
|
16667
|
+
zero_data_retention_required: Boolean(doc.zero_data_retention_required ?? true),
|
|
16668
|
+
rules: parsedRules.length > 0 ? parsedRules : fallback.rules
|
|
16669
|
+
};
|
|
16670
|
+
} catch {
|
|
16671
|
+
return fallback;
|
|
16672
|
+
}
|
|
16673
|
+
}
|
|
16674
|
+
function loadDlpPolicy(rootDir, customPolicyPath) {
|
|
16675
|
+
const base = rootDir || process.cwd();
|
|
16676
|
+
const filePath = customPolicyPath ? path4.isAbsolute(customPolicyPath) ? customPolicyPath : path4.join(base, customPolicyPath) : path4.join(base, "dlp-policy.yaml");
|
|
16677
|
+
if (!fs7.existsSync(filePath)) return createDefaultDlpPolicy();
|
|
16678
|
+
try {
|
|
16679
|
+
return parseDlpPolicy(fs7.readFileSync(filePath, "utf-8"));
|
|
16680
|
+
} catch {
|
|
16681
|
+
return createDefaultDlpPolicy();
|
|
16682
|
+
}
|
|
16683
|
+
}
|
|
16684
|
+
function applySingleDlpRule(text, rule) {
|
|
16685
|
+
if (rule.enabled === false) return { output: text, matches: 0 };
|
|
16686
|
+
try {
|
|
16687
|
+
const regex = new RegExp(rule.pattern, "g");
|
|
16688
|
+
let matches = 0;
|
|
16689
|
+
const output = text.replace(regex, () => {
|
|
16690
|
+
matches++;
|
|
16691
|
+
return rule.replacement;
|
|
16692
|
+
});
|
|
16693
|
+
return { output, matches };
|
|
16694
|
+
} catch {
|
|
16695
|
+
return { output: text, matches: 0 };
|
|
16696
|
+
}
|
|
16697
|
+
}
|
|
16698
|
+
function sanitizeDlpText(text, policy = createDefaultDlpPolicy()) {
|
|
16699
|
+
if (!policy.enabled || !text) {
|
|
16700
|
+
return { sanitizedText: text, redactionCount: 0, triggeredRuleIds: [] };
|
|
16701
|
+
}
|
|
16702
|
+
let current = text;
|
|
16703
|
+
let totalRedactions = 0;
|
|
16704
|
+
const triggered = [];
|
|
16705
|
+
for (const rule of policy.rules) {
|
|
16706
|
+
const res = applySingleDlpRule(current, rule);
|
|
16707
|
+
if (res.matches > 0) {
|
|
16708
|
+
current = res.output;
|
|
16709
|
+
totalRedactions += res.matches;
|
|
16710
|
+
triggered.push(rule.id);
|
|
16711
|
+
}
|
|
16712
|
+
}
|
|
16713
|
+
return {
|
|
16714
|
+
sanitizedText: current,
|
|
16715
|
+
redactionCount: totalRedactions,
|
|
16716
|
+
triggeredRuleIds: triggered
|
|
16717
|
+
};
|
|
16718
|
+
}
|
|
16719
|
+
function sanitizeDlpPayload(payload, policy = createDefaultDlpPolicy()) {
|
|
16720
|
+
if (!policy.enabled || payload === null || payload === void 0) return payload;
|
|
16721
|
+
if (typeof payload === "string") {
|
|
16722
|
+
return sanitizeDlpText(payload, policy).sanitizedText;
|
|
16723
|
+
}
|
|
16724
|
+
const serialized = JSON.stringify(payload);
|
|
16725
|
+
const { sanitizedText } = sanitizeDlpText(serialized, policy);
|
|
16726
|
+
try {
|
|
16727
|
+
return JSON.parse(sanitizedText);
|
|
16728
|
+
} catch {
|
|
16729
|
+
return payload;
|
|
16730
|
+
}
|
|
16731
|
+
}
|
|
15909
16732
|
|
|
15910
|
-
export { ALL_ARCHITECTURE_TEMPLATES, BRANCH_PATTERNS, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_EXCLUDES, DEFAULT_EXTENSIONS, DEFAULT_PRIVACY_POLICY, DEFAULT_SAST_EXCLUDES, GENERAL_SOURCE_EXTENSIONS, KPI_SUMMARY_END_TAG, KPI_SUMMARY_START_TAG, LIFECYCLE_SKILL_TEMPLATES, OpenSpecAdapter, PII_SAST_RULES, PREPARE_COMMIT_MSG_SCRIPT, PROMPT_INJECTION_SIGNATURES, PROTECTED_BYPASS_PATTERNS, SARIF_SCHEMA_2_1_0, SARIF_VERSION, SAST_RULES, SCHEMA_SCHEMAS_ARCHITECTURE_ADR_SCHEMA_JSON, SCHEMA_SCHEMAS_ARCHITECTURE_COMPONENT_SCHEMA_JSON, SCHEMA_SCHEMAS_ARCHITECTURE_INTRODUCTION_AND_GOALS_SCHEMA_JSON, SCHEMA_SCHEMAS_COMPLIANCE_LICENSE_MANIFEST_SCHEMA_JSON, SCHEMA_SCHEMAS_COMPLIANCE_LICENSE_POLICY_SCHEMA_JSON, SCHEMA_SCHEMAS_COMPLIANCE_QUALITY_POLICY_SCHEMA_JSON, SCHEMA_SCHEMAS_IDE_MCP_CONFIG_SCHEMA_JSON, SCHEMA_SCHEMAS_MANUALS_PRODUCTION_MANUAL_SCHEMA_JSON, SCHEMA_SCHEMAS_MANUALS_USER_MANUAL_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_DATA_ASSET_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_PRIVACY_POLICY_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_PRIVACY_REQ_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_PRIVACY_ROPA_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_ACTOR_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_BOUNDED_CONTEXT_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_BUSINESS_RULE_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_JOURNEY_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_REQUIREMENT_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_TERM_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_USE_CASE_SCHEMA_JSON, SCHEMA_SCHEMAS_SAFETY_HAZARD_SCHEMA_JSON, SCHEMA_SCHEMAS_SAFETY_SAFETY_REQ_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_DESIGN_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_HANDOFF_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_PROPOSAL_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_RELEASE_KPIS_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_SESSION_TELEMETRY_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_SPEC_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_TASKS_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_ABUSE_CASE_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_ENCLAVE_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_SECURITY_REQ_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_THREAT_ACTOR_SCHEMA_JSON, SCHEMA_SCHEMAS_WORKFLOW_AGENT_HANDOFF_SCHEMA_JSON, SECRET_RULES, SPECIALIZED_AGENT_TEMPLATES, STARTER_ANTIGRAVITY_MCP, STARTER_ANTIGRAVITY_RULES, STARTER_ARCH_ADR, STARTER_ARCH_ARCHITECTURE_CONSTRAINTS, STARTER_ARCH_COMPONENT, STARTER_ARCH_CONTEXT_AND_SCOPE, STARTER_ARCH_CROSS_CUTTING_CONCEPTS, STARTER_ARCH_DEPLOYMENT_VIEW, STARTER_ARCH_GLOSSARY, STARTER_ARCH_INTRODUCTION_AND_GOALS, STARTER_ARCH_LEVEL_1_WHITEBOX, STARTER_ARCH_QUALITY_REQUIREMENTS, STARTER_ARCH_RISKS_AND_TECHNICAL_DEBT, STARTER_ARCH_RUNTIME_VIEW, STARTER_ARCH_SOLUTION_STRATEGY, STARTER_AZURE_PIPELINES, STARTER_BASE_TEMPLATES, STARTER_BITBUCKET_PIPELINES, STARTER_CLAUDE_RULES, STARTER_COMPLIANCE_LICENSE_MANIFEST_YAML, STARTER_COPILOT_RULES, STARTER_CURSOR_CORE_RULES, STARTER_CURSOR_MCP, STARTER_CURSOR_PRODUCT_RULES, STARTER_CURSOR_QUALITY_RULES, STARTER_GITHUB_CI, STARTER_GITHUB_DEPLOY_DASHBOARD, STARTER_GITHUB_PR_KPI, STARTER_GITHUB_PULL_REQUEST_TEMPLATE, STARTER_GITHUB_SDD_INTEGRATE, STARTER_GITLAB_CI, STARTER_LICENSE_POLICY, STARTER_PRIVACY_POLICY, STARTER_PROCESS_README, STARTER_PULL_REQUEST_TEMPLATE, STARTER_QUALITY_POLICY, STARTER_REQUIREMENT_TEMPLATE, STARTER_SCHEMAS, STARTER_SCHEMAS_MAP, STARTER_TASK_TEMPLATE, STARTER_TEMPLATES_CI_AZURE_PIPELINES_YML, STARTER_TEMPLATES_CI_BITBUCKET_PIPELINES_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_CI_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_DEPLOY_DASHBOARD_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_PR_KPI_SUMMARY_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_SDD_INTEGRATE_ON_MERGE_YML, STARTER_TEMPLATES_CI__GITLAB_CI_YML, STARTER_TEMPLATES_COMPLIANCE_COMMERCIAL_ACQUISITION_REQUEST_TEMPLATE_MD, STARTER_TEMPLATES_MANUALS_PRODUCTION_MANUAL_TEMPLATE_MD, STARTER_TEMPLATES_MANUALS_USER_MANUAL_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_DATA_ASSET_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_DPIA_REQUEST_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_PRIVACY_REQ_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_PRIVACY_ROPA_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_ACTOR_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_BOUNDED_CONTEXT_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_BUSINESS_RULE_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_JOURNEY_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_REQUIREMENT_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_TERM_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_USER_DESIGN_FEEDBACK_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_USE_CASE_TEMPLATE_MD, STARTER_TEMPLATES_SAFETY_HAZARD_TEMPLATE_MD, STARTER_TEMPLATES_SAFETY_SAFETY_REQ_TEMPLATE_MD, STARTER_TEMPLATES_SDD_DESIGN_TEMPLATE_MD, STARTER_TEMPLATES_SDD_HANDOFF_TEMPLATE_YAML, STARTER_TEMPLATES_SDD_PROPOSAL_TEMPLATE_MD, STARTER_TEMPLATES_SDD_PULL_REQUEST_TEMPLATE_MD, STARTER_TEMPLATES_SDD_SPEC_TEMPLATE_MD, STARTER_TEMPLATES_SDD_TASKS_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_ABUSE_CASE_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_ENCLAVE_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_SECURITY_REQ_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_THREAT_ACTOR_TEMPLATE_MD, STARTER_TEMPLATES_WORKFLOW_AGENT_HANDOFF_TEMPLATE_MD, STARTER_VSCODE_MCP, STARTER_WORKFLOW_HANDOFF_TEMPLATE, STARTER__GITHUB_PULL_REQUEST_TEMPLATE_MD, SpecKitAdapter, TYPE_TO_SCHEMA_MAP, VALID_AGENT_TARGETS, VALID_ARCHITECTURE_GRANULARITIES, VALID_AUTONOMY_MODES, VALID_CHANGE_PROFILES, VALID_CI_PROVIDERS, aggregateCommitKpiRecords, aggregatePrKpis, aggregateReleaseKpis, analyzeBddVariantsForRequirement, appendRevisionHistoryRow, applyRatchetMode, buildCycloneDxComponent, buildFeatureFileContent, buildGraphElements, calculateJaccardSimilarity, calculateMetrics, calculateRating, calculateShannonEntropy, checkGherkinInSync, checkoutTaskBranch, classifyBranch, classifyMetricFromMessage, collectAgentFiles, collectDashboardMetrics, collectHistoricalKpis, computeCanonicalSha256, computeSha256, computeViolationSignature, createDefaultQualityPolicy, depositProductHandoffSidecar, detectActiveChangeForIntegration, detectAuthorIdentity, detectLanguage, detectProfileFromChange, detectPromptInjection, emitCiOutput, evaluateCompoundLicense, evaluateSingleDependency, evaluateVulnerabilityThresholds, extractBaselineEntriesFromResults, extractCitations, extractCommitKpisFromRange, extractDirectDepNames, extractFeatureTags, extractFrontmatter, extractFunctions, extractFunctionsBraceLanguages, extractFunctionsPolyglot, extractFunctionsPython, extractFunctionsTypeScriptAst, extractGherkinBlock, extractGherkinFeatures, extractNormativeText, findChangeWorkspaceDir, findLicenseFile, formatCommitTrailers, formatPrKpiMarkdown, formatReleaseKpiMarkdown, generateBranchHierarchyPlan, generateCycloneDxSbom, generateDashboardReport, generateDuplicatesReportMarkdown, generateGovernanceReportMarkdown, generateLicenseReportMarkdown, generatePdacReportMarkdown, generatePrivacyReportMarkdown, generateQualityReport, generateRopaInventoryMarkdown, generateSastReportMarkdown, generateSecretsReportMarkdown, generateSecuritySarifReport, generateSuppressionsAuditReport, generateTestingCoverageReportMarkdown, generateThirdPartyNotices, generateTraceabilityReportMarkdown, getArchitectureTemplates, getCytoscapeScript, getGitDiffLines, getNextCorrelativeNumber, getSddAdapter, inferArtifactTypeFromId, inferMissingTrailers, initProject, injectKpisIntoPrBody, installGitHooks, integrateSddChange, isGitleaksInstalled, isMetricWorsened, isPathProtectedFromPatch, isPlaceholderOrIgnored, isRequirementArtifact2 as isRequirementArtifact, isSemgrepInstalled, isToolAvailable, loadPrivacyPolicy, loadProductHandoffSidecar, loadQualityBaseline, locateTaskInActiveChanges, mapSastSeverityToSarifLevel, maskSecret, normalizeSpdxLicense, normalizeUri, parseCommitTrailers, parseFrontmatter, parseFrontmatterId, parseGenericDoc, parseLicensePolicy, parseMarkdownFrontmatter, parseQualityPolicy, parseRequirementFile, parseSecuritySuppression, parseSpecCatalogScope, parseTasksDoc, parseTasksFromContent, parseTrivyVulnerabilities, processPackageDir, readCodeCoverageSummary, readPackageJson, renderAntigravityAgentFile, renderAntigravitySkillFile, renderAutonomyModeSection, renderClaudeAgentFile, renderClaudeSkillFile, renderCopilotAgentFile, renderCopilotSkillFile, renderCursorAgentFile, renderCursorSkillFile, renderDashboardHtml, renderManualsTab, resolveAgentTargets, resolveBranchHierarchy, resolveCiEnvironment, resolveCytoscapePath, resolveDefaultBranchBase, resolveFeatureFilePath, resolveGitRef, resolveLicenseFromFile, resolveReleaseBaseBranch, resolveSastCwe, resolveSastOwasp, resolveSchemaForArtifact, resolveTargetFiles, runGitleaksCli, runSemgrepCli, scaffoldSddChange, scanAllProductHandoffs, scanAllTestArtifacts, scanContentForSecrets, scanFileForPrivacyViolations, scanFileForSast, scanInstalledLicenses, scanManualsInWorkspace, scanPnpmStore, scanSubdirectories, scanWithNativeFs, scanWithSyft, scanWithTrivy, serializeSarifDocument, slugify, syncPdacDigests, tokenizeTitle, updateCitationsInContent, validateAgainstSchema, validateArtifactSchema, verifyArtifactDuplicates, verifyArtifactsSchemas, verifyLicenses, verifyManuals, verifyPdacGraph, verifyPrivacy, verifyProgressiveFriction, verifyQualityGate, verifySast, verifySddIntegration, verifySecrets, verifyTasksGovernance, verifyTestingCoverage, verifyTraceability, walkDir, walkMdFiles, walkProjectFiles, walkSourceFiles, walkTaskFiles, writeCycloneDxSbom, writeQualityBaseline, writeReleaseKpiReport, writeSecuritySarifReport, writeThirdPartyNotices };
|
|
16733
|
+
export { ALL_ARCHITECTURE_TEMPLATES, BRANCH_PATTERNS, BddStepRegistry, DEFAULT_DLP_RULES, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_EXCLUDES, DEFAULT_EXTENSIONS, DEFAULT_PRIVACY_POLICY, DEFAULT_SAST_EXCLUDES, GENERAL_SOURCE_EXTENSIONS, KPI_SUMMARY_END_TAG, KPI_SUMMARY_START_TAG, LIFECYCLE_SKILL_TEMPLATES, OpenSpecAdapter, PII_SAST_RULES, PREPARE_COMMIT_MSG_SCRIPT, PROMPT_INJECTION_SIGNATURES, PROTECTED_BYPASS_PATTERNS, SARIF_SCHEMA_2_1_0, SARIF_VERSION, SAST_RULES, SCHEMA_SCHEMAS_ARCHITECTURE_ADR_SCHEMA_JSON, SCHEMA_SCHEMAS_ARCHITECTURE_COMPONENT_SCHEMA_JSON, SCHEMA_SCHEMAS_ARCHITECTURE_INTRODUCTION_AND_GOALS_SCHEMA_JSON, SCHEMA_SCHEMAS_COMPLIANCE_LICENSE_MANIFEST_SCHEMA_JSON, SCHEMA_SCHEMAS_COMPLIANCE_LICENSE_POLICY_SCHEMA_JSON, SCHEMA_SCHEMAS_COMPLIANCE_QUALITY_POLICY_SCHEMA_JSON, SCHEMA_SCHEMAS_IDE_MCP_CONFIG_SCHEMA_JSON, SCHEMA_SCHEMAS_MANUALS_PRODUCTION_MANUAL_SCHEMA_JSON, SCHEMA_SCHEMAS_MANUALS_USER_MANUAL_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_DATA_ASSET_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_PRIVACY_POLICY_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_PRIVACY_REQ_SCHEMA_JSON, SCHEMA_SCHEMAS_PRIVACY_PRIVACY_ROPA_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_ACTOR_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_BOUNDED_CONTEXT_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_BUSINESS_RULE_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_JOURNEY_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_REQUIREMENT_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_TERM_SCHEMA_JSON, SCHEMA_SCHEMAS_PRODUCT_USE_CASE_SCHEMA_JSON, SCHEMA_SCHEMAS_SAFETY_HAZARD_SCHEMA_JSON, SCHEMA_SCHEMAS_SAFETY_SAFETY_REQ_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_DESIGN_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_HANDOFF_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_PROPOSAL_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_RELEASE_KPIS_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_SESSION_TELEMETRY_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_SPEC_SCHEMA_JSON, SCHEMA_SCHEMAS_SDD_TASKS_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_ABUSE_CASE_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_ENCLAVE_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_SECURITY_REQ_SCHEMA_JSON, SCHEMA_SCHEMAS_SECURITY_THREAT_ACTOR_SCHEMA_JSON, SCHEMA_SCHEMAS_WORKFLOW_AGENT_HANDOFF_SCHEMA_JSON, SECRET_RULES, SPECIALIZED_AGENT_TEMPLATES, STARTER_ANTIGRAVITY_MCP, STARTER_ANTIGRAVITY_RULES, STARTER_ARCH_ADR, STARTER_ARCH_ARCHITECTURE_CONSTRAINTS, STARTER_ARCH_COMPONENT, STARTER_ARCH_CONTEXT_AND_SCOPE, STARTER_ARCH_CROSS_CUTTING_CONCEPTS, STARTER_ARCH_DEPLOYMENT_VIEW, STARTER_ARCH_GLOSSARY, STARTER_ARCH_INTRODUCTION_AND_GOALS, STARTER_ARCH_LEVEL_1_WHITEBOX, STARTER_ARCH_QUALITY_REQUIREMENTS, STARTER_ARCH_RISKS_AND_TECHNICAL_DEBT, STARTER_ARCH_RUNTIME_VIEW, STARTER_ARCH_SOLUTION_STRATEGY, STARTER_AZURE_PIPELINES, STARTER_BASE_TEMPLATES, STARTER_BITBUCKET_PIPELINES, STARTER_CLAUDE_RULES, STARTER_COMPLIANCE_LICENSE_MANIFEST_YAML, STARTER_COPILOT_RULES, STARTER_CURSOR_CORE_RULES, STARTER_CURSOR_MCP, STARTER_CURSOR_PRODUCT_RULES, STARTER_CURSOR_QUALITY_RULES, STARTER_GITHUB_CI, STARTER_GITHUB_DEPLOY_DASHBOARD, STARTER_GITHUB_PR_KPI, STARTER_GITHUB_PULL_REQUEST_TEMPLATE, STARTER_GITHUB_SDD_INTEGRATE, STARTER_GITLAB_CI, STARTER_LICENSE_POLICY, STARTER_PRIVACY_POLICY, STARTER_PROCESS_README, STARTER_PULL_REQUEST_TEMPLATE, STARTER_QUALITY_POLICY, STARTER_REQUIREMENT_TEMPLATE, STARTER_SCHEMAS, STARTER_SCHEMAS_MAP, STARTER_TASK_TEMPLATE, STARTER_TEMPLATES_CI_AZURE_PIPELINES_YML, STARTER_TEMPLATES_CI_BITBUCKET_PIPELINES_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_CI_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_DEPLOY_DASHBOARD_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_PR_KPI_SUMMARY_YML, STARTER_TEMPLATES_CI_GITHUB_WORKFLOWS_SDD_INTEGRATE_ON_MERGE_YML, STARTER_TEMPLATES_CI__GITLAB_CI_YML, STARTER_TEMPLATES_COMPLIANCE_COMMERCIAL_ACQUISITION_REQUEST_TEMPLATE_MD, STARTER_TEMPLATES_MANUALS_PRODUCTION_MANUAL_TEMPLATE_MD, STARTER_TEMPLATES_MANUALS_USER_MANUAL_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_DATA_ASSET_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_DPIA_REQUEST_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_PRIVACY_REQ_TEMPLATE_MD, STARTER_TEMPLATES_PRIVACY_PRIVACY_ROPA_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_ACTOR_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_BOUNDED_CONTEXT_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_BUSINESS_RULE_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_JOURNEY_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_REQUIREMENT_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_TERM_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_USER_DESIGN_FEEDBACK_TEMPLATE_MD, STARTER_TEMPLATES_PRODUCT_USE_CASE_TEMPLATE_MD, STARTER_TEMPLATES_SAFETY_HAZARD_TEMPLATE_MD, STARTER_TEMPLATES_SAFETY_SAFETY_REQ_TEMPLATE_MD, STARTER_TEMPLATES_SDD_DESIGN_TEMPLATE_MD, STARTER_TEMPLATES_SDD_HANDOFF_TEMPLATE_YAML, STARTER_TEMPLATES_SDD_PROPOSAL_TEMPLATE_MD, STARTER_TEMPLATES_SDD_PULL_REQUEST_TEMPLATE_MD, STARTER_TEMPLATES_SDD_SPEC_TEMPLATE_MD, STARTER_TEMPLATES_SDD_TASKS_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_ABUSE_CASE_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_ENCLAVE_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_SECURITY_REQ_TEMPLATE_MD, STARTER_TEMPLATES_SECURITY_THREAT_ACTOR_TEMPLATE_MD, STARTER_TEMPLATES_WORKFLOW_AGENT_HANDOFF_TEMPLATE_MD, STARTER_VSCODE_MCP, STARTER_WORKFLOW_HANDOFF_TEMPLATE, STARTER__GITHUB_PULL_REQUEST_TEMPLATE_MD, SpecKitAdapter, TYPE_TO_SCHEMA_MAP, VALID_AGENT_TARGETS, VALID_ARCHITECTURE_GRANULARITIES, VALID_AUTONOMY_MODES, VALID_CHANGE_PROFILES, VALID_CI_PROVIDERS, aggregateCommitKpiRecords, aggregatePrKpis, aggregateReleaseKpis, analyzeBddVariantsForRequirement, appendRevisionHistoryRow, applyRatchetMode, buildCycloneDxComponent, buildCycloneDxVulnerabilities, buildFeatureFileContent, buildGraphElements, calculateJaccardSimilarity, calculateMetrics, calculateRating, calculateShannonEntropy, checkGherkinInSync, checkoutTaskBranch, classifyBranch, classifyMetricFromMessage, collectAgentFiles, collectDashboardMetrics, collectHistoricalKpis, computeCanonicalSha256, computeSha256, computeViolationSignature, createDefaultDlpPolicy, createDefaultQualityPolicy, depositProductHandoffSidecar, detectActiveChangeForIntegration, detectAuthorIdentity, detectLanguage, detectProfileFromChange, detectPromptInjection, emitCiOutput, evaluateCompoundLicense, evaluateSingleDependency, evaluateVulnerabilityThresholds, executeBddFeature, extractBaselineEntriesFromResults, extractCitations, extractCommitKpisFromRange, extractDirectDepNames, extractFeatureTags, extractFrontmatter, extractFunctions, extractFunctionsBraceLanguages, extractFunctionsPolyglot, extractFunctionsPython, extractFunctionsTypeScriptAst, extractGherkinBlock, extractGherkinFeatures, extractNormativeText, findChangeWorkspaceDir, findLicenseFile, formatCommitTrailers, formatPrKpiMarkdown, formatReleaseKpiMarkdown, generateBranchHierarchyPlan, generateCycloneDxSbom, generateDashboardReport, generateDuplicatesReportMarkdown, generateGovernanceReportMarkdown, generateLicenseReportMarkdown, generatePdacReportMarkdown, generatePrivacyReportMarkdown, generateQualityReport, generateRopaInventoryMarkdown, generateSastReportMarkdown, generateSecretsReportMarkdown, generateSecuritySarifReport, generateSuppressionsAuditReport, generateTestingCoverageReportMarkdown, generateThirdPartyNotices, generateTraceabilityReportMarkdown, getArchitectureTemplates, getCytoscapeScript, getGitDiffLines, getNextCorrelativeNumber, getSddAdapter, inferArtifactTypeFromId, inferMissingTrailers, initProject, injectKpisIntoPrBody, installGitHooks, integrateSddChange, isGitleaksInstalled, isMetricWorsened, isPathProtectedFromPatch, isPlaceholderOrIgnored, isRequirementArtifact2 as isRequirementArtifact, isSemgrepInstalled, isToolAvailable, loadDlpPolicy, loadPrivacyPolicy, loadProductHandoffSidecar, loadQualityBaseline, locateTaskInActiveChanges, mapSastSeverityToSarifLevel, maskSecret, normalizeSpdxLicense, normalizeUri, parseCommitTrailers, parseDlpPolicy, parseFeatureDocument, parseFrontmatter, parseFrontmatterId, parseGenericDoc, parseLicensePolicy, parseMarkdownFrontmatter, parseQualityPolicy, parseRequirementFile, parseSecuritySuppression, parseSpecCatalogScope, parseTasksDoc, parseTasksFromContent, parseTrivyVulnerabilities, processPackageDir, readCodeCoverageSummary, readPackageJson, renderAntigravityAgentFile, renderAntigravitySkillFile, renderAutonomyModeSection, renderClaudeAgentFile, renderClaudeSkillFile, renderCopilotAgentFile, renderCopilotSkillFile, renderCursorAgentFile, renderCursorSkillFile, renderDashboardHtml, renderManualsTab, resolveAgentTargets, resolveBranchHierarchy, resolveCiEnvironment, resolveCytoscapePath, resolveDefaultBranchBase, resolveFeatureFilePath, resolveGitRef, resolveLicenseFromFile, resolveReleaseBaseBranch, resolveSastCwe, resolveSastOwasp, resolveSchemaForArtifact, resolveTargetFiles, runGitleaksCli, runSemgrepCli, sanitizeDlpPayload, sanitizeDlpText, scaffoldSddChange, scanAllProductHandoffs, scanAllTestArtifacts, scanContentForSecrets, scanFileForPrivacyViolations, scanFileForSast, scanGoDependencies, scanInstalledLicenses, scanManualsInWorkspace, scanMavenDependencies, scanPnpmStore, scanPythonDependencies, scanRustDependencies, scanSubdirectories, scanWithNativeFs, scanWithSyft, scanWithTrivy, serializeSarifDocument, slugify, syncPdacDigests, tokenizeTitle, updateCitationsInContent, validateAgainstSchema, validateArtifactSchema, verifyArtifactDuplicates, verifyArtifactsSchemas, verifyLicenses, verifyManuals, verifyPdacGraph, verifyPrivacy, verifyProgressiveFriction, verifyQualityGate, verifySast, verifySddIntegration, verifySecrets, verifyTasksGovernance, verifyTestingCoverage, verifyTraceability, walkDir, walkMdFiles, walkProjectFiles, walkSourceFiles, walkTaskFiles, writeCucumberJsonReport, writeCycloneDxSbom, writeQualityBaseline, writeReleaseKpiReport, writeSecuritySarifReport, writeThirdPartyNotices };
|
|
15911
16734
|
//# sourceMappingURL=index.js.map
|
|
15912
16735
|
//# sourceMappingURL=index.js.map
|