skill-checker 0.1.11 → 0.1.12
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/cli.js +152 -71
- package/dist/cli.js.map +1 -1
- package/dist/index.js +152 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -328,6 +328,70 @@ var structuralChecks = {
|
|
|
328
328
|
}
|
|
329
329
|
};
|
|
330
330
|
|
|
331
|
+
// src/types.ts
|
|
332
|
+
var SEVERITY_SCORES = {
|
|
333
|
+
CRITICAL: 25,
|
|
334
|
+
HIGH: 10,
|
|
335
|
+
MEDIUM: 3,
|
|
336
|
+
LOW: 1
|
|
337
|
+
};
|
|
338
|
+
function computeGrade(score) {
|
|
339
|
+
if (score >= 90) return "A";
|
|
340
|
+
if (score >= 75) return "B";
|
|
341
|
+
if (score >= 60) return "C";
|
|
342
|
+
if (score >= 40) return "D";
|
|
343
|
+
return "F";
|
|
344
|
+
}
|
|
345
|
+
var REDUCE_MAP = {
|
|
346
|
+
CRITICAL: "HIGH",
|
|
347
|
+
HIGH: "MEDIUM",
|
|
348
|
+
MEDIUM: "LOW",
|
|
349
|
+
LOW: "LOW"
|
|
350
|
+
};
|
|
351
|
+
function reduceSeverity(original, reason) {
|
|
352
|
+
let reduced = REDUCE_MAP[original];
|
|
353
|
+
if (original === "CRITICAL" && reduced === "LOW") {
|
|
354
|
+
reduced = "MEDIUM";
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
severity: reduced,
|
|
358
|
+
reducedFrom: original,
|
|
359
|
+
annotation: `[reduced: ${reason}]`
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
var DEFAULT_CONFIG = {
|
|
363
|
+
policy: "balanced",
|
|
364
|
+
overrides: {},
|
|
365
|
+
ignore: []
|
|
366
|
+
};
|
|
367
|
+
function getHookAction(policy, severity) {
|
|
368
|
+
const matrix = {
|
|
369
|
+
strict: {
|
|
370
|
+
CRITICAL: "deny",
|
|
371
|
+
HIGH: "deny",
|
|
372
|
+
MEDIUM: "ask",
|
|
373
|
+
LOW: "report"
|
|
374
|
+
},
|
|
375
|
+
balanced: {
|
|
376
|
+
CRITICAL: "deny",
|
|
377
|
+
HIGH: "ask",
|
|
378
|
+
MEDIUM: "report",
|
|
379
|
+
LOW: "report"
|
|
380
|
+
},
|
|
381
|
+
permissive: {
|
|
382
|
+
CRITICAL: "ask",
|
|
383
|
+
HIGH: "report",
|
|
384
|
+
MEDIUM: "report",
|
|
385
|
+
LOW: "report"
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
const row = matrix[policy];
|
|
389
|
+
if (!row) {
|
|
390
|
+
return matrix.balanced[severity];
|
|
391
|
+
}
|
|
392
|
+
return row[severity];
|
|
393
|
+
}
|
|
394
|
+
|
|
331
395
|
// src/utils/context.ts
|
|
332
396
|
function isInCodeBlock(lines, lineIndex) {
|
|
333
397
|
let inBlock = false;
|
|
@@ -391,6 +455,49 @@ function isLicenseFile(filePath) {
|
|
|
391
455
|
function isLocalhostURL(url) {
|
|
392
456
|
return /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])/i.test(url);
|
|
393
457
|
}
|
|
458
|
+
function isInEducationalContext(lines, lineIndex) {
|
|
459
|
+
const line = lines[lineIndex];
|
|
460
|
+
if (/^#{1,6}\s+/.test(line)) return true;
|
|
461
|
+
if (/^\s*[-*]?\s*(\*\*[^*]+\*\*\s*:|[A-Z][^:]{0,40}:)\s/.test(line))
|
|
462
|
+
return true;
|
|
463
|
+
for (let i = lineIndex; i >= Math.max(0, lineIndex - 15); i--) {
|
|
464
|
+
if (/^#{1,4}\s+.*(strateg|guide|framework|structure|model|overview|comparison|concept|principle|example|tutorial|reference|approach|method)/i.test(
|
|
465
|
+
lines[i]
|
|
466
|
+
)) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
var PROMOTIONAL_INTENT_PATTERNS = [
|
|
473
|
+
/\d+%\s*off\b/i,
|
|
474
|
+
/\blimited\s+time\b/i,
|
|
475
|
+
/\bact\s+now\b/i,
|
|
476
|
+
/\bhurry\b/i,
|
|
477
|
+
/\btoday\s+only\b/i,
|
|
478
|
+
/\bdon'?t\s+miss\b/i,
|
|
479
|
+
/\bsave\s+\d+%/i,
|
|
480
|
+
/\bexclusive\s+(offer|deal)\b/i,
|
|
481
|
+
/\bsign\s+up\s+(now|today)\b/i,
|
|
482
|
+
/\bget\s+started\b/i,
|
|
483
|
+
/\bclaim\s+(now|yours?)\b/i,
|
|
484
|
+
/\boffer\s+ends?\b/i,
|
|
485
|
+
/\blast\s+chance\b/i,
|
|
486
|
+
/\bonly\s+\d+\s+left\b/i,
|
|
487
|
+
/\bends?\s+in\s+\d+/i,
|
|
488
|
+
/\bstart\s+(your\s+)?free\s+trial\b/i
|
|
489
|
+
];
|
|
490
|
+
function hasPromotionalIntent(line) {
|
|
491
|
+
return PROMOTIONAL_INTENT_PATTERNS.some((p) => p.test(line));
|
|
492
|
+
}
|
|
493
|
+
function hasPromotionalIntentNearby(lines, lineIndex, window = 3) {
|
|
494
|
+
const start = Math.max(0, lineIndex - window);
|
|
495
|
+
const end = Math.min(lines.length - 1, lineIndex + window);
|
|
496
|
+
for (let i = start; i <= end; i++) {
|
|
497
|
+
if (hasPromotionalIntent(lines[i])) return true;
|
|
498
|
+
}
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
394
501
|
function parseURLPath(url) {
|
|
395
502
|
try {
|
|
396
503
|
const u = new URL(url);
|
|
@@ -422,16 +529,18 @@ var LOREM_PATTERNS = [
|
|
|
422
529
|
/dolor\s+sit\s+amet/i,
|
|
423
530
|
/consectetur\s+adipiscing/i
|
|
424
531
|
];
|
|
425
|
-
var
|
|
532
|
+
var STRONG_AD_PATTERNS = [
|
|
426
533
|
/\bbuy\s+now\b/i,
|
|
427
|
-
/\
|
|
534
|
+
/\bclick\s+here\s+to\s+(buy|subscribe|download)/i,
|
|
535
|
+
/\buse\s+code\b.*\b\d+%?\s*off\b/i
|
|
536
|
+
];
|
|
537
|
+
var SOFT_AD_PATTERNS = [
|
|
428
538
|
/\bdiscount\b/i,
|
|
539
|
+
/\bfree\s+trial\b/i,
|
|
429
540
|
/\bpromo\s*code\b/i,
|
|
430
541
|
/\bsubscribe\s+(to|now)\b/i,
|
|
431
542
|
/\bsponsored\s+by\b/i,
|
|
432
543
|
/\baffiliate\s+link\b/i,
|
|
433
|
-
/\bclick\s+here\s+to\s+(buy|subscribe|download)/i,
|
|
434
|
-
/\buse\s+code\b.*\b\d+%?\s*off\b/i,
|
|
435
544
|
/\bcheck\s+out\s+my\b/i
|
|
436
545
|
];
|
|
437
546
|
var contentChecks = {
|
|
@@ -496,7 +605,8 @@ var contentChecks = {
|
|
|
496
605
|
checkDescriptionMismatch(results, skill);
|
|
497
606
|
for (let i = 0; i < skill.bodyLines.length; i++) {
|
|
498
607
|
const line = skill.bodyLines[i];
|
|
499
|
-
|
|
608
|
+
let matched = false;
|
|
609
|
+
for (const pattern of STRONG_AD_PATTERNS) {
|
|
500
610
|
if (pattern.test(line)) {
|
|
501
611
|
results.push({
|
|
502
612
|
id: "CONT-005",
|
|
@@ -505,8 +615,43 @@ var contentChecks = {
|
|
|
505
615
|
title: "Promotional/advertising content",
|
|
506
616
|
message: `Line ${skill.bodyStartLine + i}: Contains ad-like content.`,
|
|
507
617
|
line: skill.bodyStartLine + i,
|
|
508
|
-
snippet: line.trim().slice(0, 120)
|
|
618
|
+
snippet: line.trim().slice(0, 120),
|
|
619
|
+
source: "SKILL.md"
|
|
509
620
|
});
|
|
621
|
+
matched = true;
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (matched) continue;
|
|
626
|
+
for (const pattern of SOFT_AD_PATTERNS) {
|
|
627
|
+
if (pattern.test(line)) {
|
|
628
|
+
const inCode = isInCodeBlock(skill.bodyLines, i);
|
|
629
|
+
const inEducational = isInEducationalContext(skill.bodyLines, i);
|
|
630
|
+
if ((inCode || inEducational) && !hasPromotionalIntentNearby(skill.bodyLines, i)) {
|
|
631
|
+
const reduction = reduceSeverity("HIGH", "educational/descriptive context");
|
|
632
|
+
results.push({
|
|
633
|
+
id: "CONT-005",
|
|
634
|
+
category: "CONT",
|
|
635
|
+
severity: reduction.severity,
|
|
636
|
+
title: "Promotional/advertising content",
|
|
637
|
+
message: `Line ${skill.bodyStartLine + i}: Contains ad-like content. ${reduction.annotation}`,
|
|
638
|
+
line: skill.bodyStartLine + i,
|
|
639
|
+
snippet: line.trim().slice(0, 120),
|
|
640
|
+
reducedFrom: reduction.reducedFrom,
|
|
641
|
+
source: "SKILL.md"
|
|
642
|
+
});
|
|
643
|
+
} else {
|
|
644
|
+
results.push({
|
|
645
|
+
id: "CONT-005",
|
|
646
|
+
category: "CONT",
|
|
647
|
+
severity: "HIGH",
|
|
648
|
+
title: "Promotional/advertising content",
|
|
649
|
+
message: `Line ${skill.bodyStartLine + i}: Contains ad-like content.`,
|
|
650
|
+
line: skill.bodyStartLine + i,
|
|
651
|
+
snippet: line.trim().slice(0, 120),
|
|
652
|
+
source: "SKILL.md"
|
|
653
|
+
});
|
|
654
|
+
}
|
|
510
655
|
break;
|
|
511
656
|
}
|
|
512
657
|
}
|
|
@@ -985,70 +1130,6 @@ function dedup(results) {
|
|
|
985
1130
|
});
|
|
986
1131
|
}
|
|
987
1132
|
|
|
988
|
-
// src/types.ts
|
|
989
|
-
var SEVERITY_SCORES = {
|
|
990
|
-
CRITICAL: 25,
|
|
991
|
-
HIGH: 10,
|
|
992
|
-
MEDIUM: 3,
|
|
993
|
-
LOW: 1
|
|
994
|
-
};
|
|
995
|
-
function computeGrade(score) {
|
|
996
|
-
if (score >= 90) return "A";
|
|
997
|
-
if (score >= 75) return "B";
|
|
998
|
-
if (score >= 60) return "C";
|
|
999
|
-
if (score >= 40) return "D";
|
|
1000
|
-
return "F";
|
|
1001
|
-
}
|
|
1002
|
-
var REDUCE_MAP = {
|
|
1003
|
-
CRITICAL: "HIGH",
|
|
1004
|
-
HIGH: "MEDIUM",
|
|
1005
|
-
MEDIUM: "LOW",
|
|
1006
|
-
LOW: "LOW"
|
|
1007
|
-
};
|
|
1008
|
-
function reduceSeverity(original, reason) {
|
|
1009
|
-
let reduced = REDUCE_MAP[original];
|
|
1010
|
-
if (original === "CRITICAL" && reduced === "LOW") {
|
|
1011
|
-
reduced = "MEDIUM";
|
|
1012
|
-
}
|
|
1013
|
-
return {
|
|
1014
|
-
severity: reduced,
|
|
1015
|
-
reducedFrom: original,
|
|
1016
|
-
annotation: `[reduced: ${reason}]`
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
|
-
var DEFAULT_CONFIG = {
|
|
1020
|
-
policy: "balanced",
|
|
1021
|
-
overrides: {},
|
|
1022
|
-
ignore: []
|
|
1023
|
-
};
|
|
1024
|
-
function getHookAction(policy, severity) {
|
|
1025
|
-
const matrix = {
|
|
1026
|
-
strict: {
|
|
1027
|
-
CRITICAL: "deny",
|
|
1028
|
-
HIGH: "deny",
|
|
1029
|
-
MEDIUM: "ask",
|
|
1030
|
-
LOW: "report"
|
|
1031
|
-
},
|
|
1032
|
-
balanced: {
|
|
1033
|
-
CRITICAL: "deny",
|
|
1034
|
-
HIGH: "ask",
|
|
1035
|
-
MEDIUM: "report",
|
|
1036
|
-
LOW: "report"
|
|
1037
|
-
},
|
|
1038
|
-
permissive: {
|
|
1039
|
-
CRITICAL: "ask",
|
|
1040
|
-
HIGH: "report",
|
|
1041
|
-
MEDIUM: "report",
|
|
1042
|
-
LOW: "report"
|
|
1043
|
-
}
|
|
1044
|
-
};
|
|
1045
|
-
const row = matrix[policy];
|
|
1046
|
-
if (!row) {
|
|
1047
|
-
return matrix.balanced[severity];
|
|
1048
|
-
}
|
|
1049
|
-
return row[severity];
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
1133
|
// src/checks/code-safety.ts
|
|
1053
1134
|
var EVAL_PATTERNS = [
|
|
1054
1135
|
/\beval\s*\(/,
|
|
@@ -1535,7 +1616,7 @@ var DEFAULT_IOC = {
|
|
|
1535
1616
|
"45.155.205.233"
|
|
1536
1617
|
],
|
|
1537
1618
|
malicious_hashes: {
|
|
1538
|
-
// NOTE: Never add the
|
|
1619
|
+
// NOTE: Never add the SHA256 of an empty file (e3b0c44298fc...b855)
|
|
1539
1620
|
// as it causes false positives on any empty file.
|
|
1540
1621
|
"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2": "clawhavoc-exfiltrator"
|
|
1541
1622
|
},
|