@preship/secrets 1.0.0 → 1.0.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.
Files changed (2) hide show
  1. package/dist/index.js +70 -10
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -417,14 +417,17 @@ var genericRules = [
417
417
  keywords: [],
418
418
  // No keyword prefilter; this rule is opt-in via entropy threshold
419
419
  pattern: /[A-Za-z0-9+/]{40,}={0,2}/,
420
- entropyThreshold: 4.5,
420
+ entropyThreshold: 5.5,
421
+ // Raised from 4.5 — base64 is naturally ~5.0-5.5 entropy, so only truly random strings pass
421
422
  allowPatterns: [
422
423
  /^[A-Z]+$/,
423
424
  // All uppercase (likely a constant name)
424
425
  /^[a-z]+$/,
425
426
  // All lowercase (likely a word)
426
- /[A-Za-z]{40,}/
427
+ /[A-Za-z]{40,}/,
427
428
  // Long alphabetic-only strings are typically not secrets
429
+ /={2}$/
430
+ // Strings ending with == are typically short padded data (hashes, encoded values), not secrets
428
431
  ]
429
432
  },
430
433
  {
@@ -434,12 +437,17 @@ var genericRules = [
434
437
  keywords: [],
435
438
  // No keyword prefilter; this rule is opt-in via entropy threshold
436
439
  pattern: /[0-9a-fA-F]{40,}/,
437
- entropyThreshold: 3,
440
+ entropyThreshold: 3.5,
441
+ // Raised from 3.0 — git commit hashes and content hashes typically hit 3.0-3.5
438
442
  allowPatterns: [
439
443
  /^0{10,}$/,
440
444
  // All zeros (placeholder/null hash)
441
- /^[fF]{10,}$/
445
+ /^[fF]{10,}$/,
442
446
  // All f's (mask value)
447
+ /^[0-9a-f]{40}$/,
448
+ // Exactly 40 hex chars = git SHA1 commit hash (not a secret)
449
+ /^[0-9a-f]{64}$/
450
+ // Exactly 64 hex chars = SHA256 hash (integrity check, not a secret)
443
451
  ]
444
452
  }
445
453
  ];
@@ -483,6 +491,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
483
491
  ".output"
484
492
  ]);
485
493
  var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
494
+ // Images
486
495
  ".png",
487
496
  ".jpg",
488
497
  ".jpeg",
@@ -492,11 +501,13 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
492
501
  ".webp",
493
502
  ".bmp",
494
503
  ".tiff",
504
+ // Fonts
495
505
  ".woff",
496
506
  ".woff2",
497
507
  ".ttf",
498
508
  ".eot",
499
509
  ".otf",
510
+ // Documents & archives
500
511
  ".pdf",
501
512
  ".zip",
502
513
  ".tar",
@@ -507,6 +518,7 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
507
518
  ".rar",
508
519
  ".jar",
509
520
  ".war",
521
+ // Binaries
510
522
  ".exe",
511
523
  ".dll",
512
524
  ".so",
@@ -518,18 +530,33 @@ var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
518
530
  ".pyc",
519
531
  ".pyo",
520
532
  ".wasm",
533
+ // Media
521
534
  ".mp3",
522
535
  ".mp4",
523
536
  ".avi",
524
537
  ".mov",
525
538
  ".mkv",
526
539
  ".flac",
527
- ".wav"
540
+ ".wav",
541
+ // Source maps (contain base64 noise, not real secrets)
542
+ ".map",
543
+ // Data files
544
+ ".sqlite",
545
+ ".db"
528
546
  ]);
529
- var ALLOWED_LOCKFILES = /* @__PURE__ */ new Set([
547
+ var SKIP_FILENAMES = /* @__PURE__ */ new Set([
530
548
  "package-lock.json",
531
549
  "yarn.lock",
532
- "pnpm-lock.yaml"
550
+ "pnpm-lock.yaml",
551
+ "npm-shrinkwrap.json",
552
+ "composer.lock",
553
+ "Gemfile.lock",
554
+ "Cargo.lock",
555
+ "poetry.lock",
556
+ "Pipfile.lock",
557
+ // PreShip internal files (encrypted cache + key)
558
+ ".preship-cache.json",
559
+ ".preship-key"
533
560
  ]);
534
561
  var MAX_FILE_SIZE = 1048576;
535
562
  function walkProjectFiles(projectPath, allowPaths, scanPaths) {
@@ -571,7 +598,13 @@ function walkDirectory(rootPath, relativePath, files, allowPaths, scanPaths) {
571
598
  if (SKIP_EXTENSIONS.has(ext)) {
572
599
  continue;
573
600
  }
574
- if (ext === ".lock" && !ALLOWED_LOCKFILES.has(entry.name)) {
601
+ if (SKIP_FILENAMES.has(entry.name)) {
602
+ continue;
603
+ }
604
+ if (ext === ".lock") {
605
+ continue;
606
+ }
607
+ if (entry.name.endsWith(".min.js") || entry.name.endsWith(".min.css")) {
575
608
  continue;
576
609
  }
577
610
  try {
@@ -642,9 +675,15 @@ async function scanSecrets(projectPath, config = {}) {
642
675
  }
643
676
  filesScanned++;
644
677
  const isEnvFile = isEnvironmentFile(relativePath);
645
- const candidateRules = getRulesForKeywords(content).filter(
678
+ const skipEntropyRules = isEntropyNoisyFile(relativePath);
679
+ let candidateRules = getRulesForKeywords(content).filter(
646
680
  (rule) => !mergedConfig.allowRules.includes(rule.id)
647
681
  );
682
+ if (skipEntropyRules) {
683
+ candidateRules = candidateRules.filter(
684
+ (rule) => rule.id !== "high-entropy-base64" && rule.id !== "high-entropy-hex"
685
+ );
686
+ }
648
687
  if (candidateRules.length === 0 && !isEnvFile) {
649
688
  continue;
650
689
  }
@@ -741,7 +780,28 @@ function redactSecret(value, rule) {
741
780
  }
742
781
  function isEnvironmentFile(relativePath) {
743
782
  const basename2 = path2.basename(relativePath);
744
- return basename2 === ".env" || basename2.startsWith(".env.") || basename2 === ".env.local" || basename2 === ".env.development" || basename2 === ".env.production" || basename2 === ".env.staging" || basename2 === ".env.test";
783
+ if (isEnvTemplateFile(basename2)) {
784
+ return false;
785
+ }
786
+ return basename2 === ".env" || basename2.startsWith(".env.");
787
+ }
788
+ function isEnvTemplateFile(basename2) {
789
+ const lower = basename2.toLowerCase();
790
+ return lower === ".env.example" || lower === ".env.sample" || lower === ".env.template" || lower === ".env.defaults" || lower === ".env.dist" || lower.endsWith(".example") || lower.endsWith(".sample") || lower.endsWith(".template");
791
+ }
792
+ function isEntropyNoisyFile(relativePath) {
793
+ const ext = path2.extname(relativePath).toLowerCase();
794
+ const basename2 = path2.basename(relativePath).toLowerCase();
795
+ if (ext === ".css") return true;
796
+ if (basename2.endsWith(".bundle.js") || basename2.endsWith(".chunk.js")) return true;
797
+ if (basename2.includes("manifest") && (ext === ".json" || ext === ".js")) return true;
798
+ if (basename2.includes("webpack") && ext === ".js") return true;
799
+ if (basename2 === "build-manifest.json") return true;
800
+ if (ext === ".svg") return true;
801
+ if (ext === ".json" && basename2 !== ".env.json") {
802
+ return false;
803
+ }
804
+ return false;
745
805
  }
746
806
  function hasEnvSecretContent(content) {
747
807
  const lines = content.split("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@preship/secrets",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Secrets detection for PreShip — find leaked API keys, tokens, and credentials before shipping",
5
5
  "author": "Cyfox Inc.",
6
6
  "license": "Apache-2.0",
@@ -21,6 +21,6 @@
21
21
  "lint": "tsc --noEmit"
22
22
  },
23
23
  "dependencies": {
24
- "@preship/core": "2.0.0"
24
+ "@preship/core": "2.0.1"
25
25
  }
26
26
  }