dep-oracle 1.1.4 → 1.2.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/cli/index.js CHANGED
@@ -539,7 +539,7 @@ function normalizePyPIName(name) {
539
539
  return name.toLowerCase().replace(/[-_.]+/g, "-");
540
540
  }
541
541
  function parsePep508(spec) {
542
- const cleaned = spec.split("#")[0].trim();
542
+ const cleaned = spec.replace(/\s+#.*$/, "").trim();
543
543
  if (!cleaned || cleaned.startsWith("-")) return null;
544
544
  const withoutMarkers = cleaned.split(";")[0].trim();
545
545
  const match = withoutMarkers.match(
@@ -900,7 +900,11 @@ var CacheManager = class {
900
900
  const raw = readFileSync(this.filePath, "utf-8");
901
901
  return JSON.parse(raw);
902
902
  }
903
- } catch {
903
+ } catch (err) {
904
+ if (err instanceof SyntaxError) {
905
+ } else {
906
+ console.error(`Cache load error: ${err instanceof Error ? err.message : String(err)}`);
907
+ }
904
908
  }
905
909
  return {};
906
910
  }
@@ -1208,7 +1212,11 @@ var GitHubCollector = class extends BaseCollector {
1208
1212
  /github\.com\/([^/]+)\/([^/]+)/
1209
1213
  );
1210
1214
  if (!match) return null;
1211
- return { owner: match[1], repo: match[2] };
1215
+ const owner = match[1];
1216
+ const repo = match[2];
1217
+ const GITHUB_NAME = /^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?$/;
1218
+ if (!GITHUB_NAME.test(owner) || !GITHUB_NAME.test(repo)) return null;
1219
+ return { owner, repo };
1212
1220
  }
1213
1221
  // ---------------------------------------------------------------------------
1214
1222
  // GitHub API calls
@@ -1645,8 +1653,11 @@ var FundingCollector = class extends BaseCollector {
1645
1653
  const ghMatch = fundingYml.match(/github:\s*(.+)/i);
1646
1654
  if (ghMatch) {
1647
1655
  const sponsors = ghMatch[1].trim().replace(/^\[/, "").replace(/]$/, "").split(",").map((s) => s.trim().replace(/['"]/g, "")).filter(Boolean);
1656
+ const GITHUB_USERNAME = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$/;
1648
1657
  for (const sponsor of sponsors) {
1649
- urls.push(`https://github.com/sponsors/${sponsor}`);
1658
+ if (GITHUB_USERNAME.test(sponsor)) {
1659
+ urls.push(`https://github.com/sponsors/${sponsor}`);
1660
+ }
1650
1661
  }
1651
1662
  }
1652
1663
  const ocMatch = fundingYml.match(/open_collective:\s*(\S+)/i);
@@ -2046,9 +2057,30 @@ var CollectorOrchestrator = class {
2046
2057
  { key: "license", collector: this.licenseCollector }
2047
2058
  ];
2048
2059
  const results = {};
2060
+ const COLLECTOR_TIMEOUT = 3e4;
2049
2061
  const tasks = entries.map(
2050
2062
  ({ key, collector }) => limit(async () => {
2051
- const result = this.options.offline ? await this.offlineCollect(collector, packageName, version) : await this.onlineCollect(collector, packageName, version);
2063
+ let result;
2064
+ if (this.options.offline) {
2065
+ result = await this.offlineCollect(collector, packageName, version);
2066
+ } else {
2067
+ try {
2068
+ result = await Promise.race([
2069
+ this.onlineCollect(collector, packageName, version),
2070
+ new Promise(
2071
+ (_, reject) => setTimeout(() => reject(new Error("Collector timeout")), COLLECTOR_TIMEOUT)
2072
+ )
2073
+ ]);
2074
+ } catch {
2075
+ logger.warn(`[${collector.name}] ${packageName}@${version} => timeout (${COLLECTOR_TIMEOUT}ms)`);
2076
+ result = {
2077
+ status: "error",
2078
+ data: null,
2079
+ error: `Timeout after ${COLLECTOR_TIMEOUT / 1e3}s`,
2080
+ collectedAt: (/* @__PURE__ */ new Date()).toISOString()
2081
+ };
2082
+ }
2083
+ }
2052
2084
  logger.info(
2053
2085
  `[${collector.name}] ${packageName}@${version} => ${result.status}`
2054
2086
  );
@@ -2125,6 +2157,10 @@ var TrustScoreEngine = class {
2125
2157
  weights;
2126
2158
  constructor(weights) {
2127
2159
  this.weights = { ...DEFAULT_WEIGHTS, ...weights };
2160
+ const total = Object.values(this.weights).reduce((a, b) => a + b, 0);
2161
+ if (Math.abs(total - 1) > 0.01) {
2162
+ throw new Error(`Trust score weights must sum to 1.0, got ${total.toFixed(4)}`);
2163
+ }
2128
2164
  }
2129
2165
  /**
2130
2166
  * Calculate a full trust score from all collector results.
@@ -2183,10 +2219,10 @@ var TrustScoreEngine = class {
2183
2219
  } else {
2184
2220
  score = Math.max(20, 100 - vulns * 12);
2185
2221
  }
2186
- if (data.averagePatchDays !== null && data.averagePatchDays > 0) {
2222
+ if (vulns > 0 && data.averagePatchDays !== null && data.averagePatchDays > 0) {
2187
2223
  if (data.averagePatchDays <= 7) {
2188
2224
  score = Math.min(100, score + 10);
2189
- } else {
2225
+ } else if (data.averagePatchDays <= 30) {
2190
2226
  score = Math.min(100, score + 5);
2191
2227
  }
2192
2228
  }
@@ -4960,13 +4996,13 @@ var TyposquatDetector = class _TyposquatDetector {
4960
4996
  const allowed = substitutions[target[i]];
4961
4997
  if (allowed && allowed.includes(input[i])) {
4962
4998
  subCount++;
4963
- if (subCount > 1) return false;
4999
+ if (subCount > 2) return false;
4964
5000
  } else {
4965
5001
  return false;
4966
5002
  }
4967
5003
  }
4968
5004
  }
4969
- return subCount === 1;
5005
+ return subCount >= 1 && subCount <= 2;
4970
5006
  }
4971
5007
  };
4972
5008
  function levenshtein(a, b) {
@@ -7037,7 +7073,7 @@ var pkgVersion = (() => {
7037
7073
  const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
7038
7074
  return pkg.version;
7039
7075
  } catch {
7040
- return "1.1.1";
7076
+ return "1.2.0";
7041
7077
  }
7042
7078
  })();
7043
7079
  var program = new Command3().name("dep-oracle").description("Predictive dependency security engine").version(pkgVersion).option("--verbose", "Enable verbose logging output").hook("preAction", (_thisCommand, actionCommand) => {