toolip 2.0.0 → 2.1.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.
@@ -2,7 +2,7 @@ import type { Analyzer, AnalyzerContext, AnalyzerResult } from '../../contracts/
2
2
  export declare class GitHistorySecretAnalyzer implements Analyzer {
3
3
  private readonly maxCommits;
4
4
  readonly id = "git-history-secrets";
5
- readonly version = "1.0.0";
5
+ readonly version = "1.0.1";
6
6
  constructor(maxCommits?: number);
7
7
  analyze(context: AnalyzerContext): Promise<AnalyzerResult>;
8
8
  }
@@ -14,6 +14,15 @@ function fingerprint(value) {
14
14
  .update(value)
15
15
  .digest('hex');
16
16
  }
17
+ function isTestFile(file) {
18
+ if (!file) {
19
+ return false;
20
+ }
21
+ return (file.startsWith('tests/') ||
22
+ file.includes('/tests/') ||
23
+ file.includes('/__tests__/') ||
24
+ /\.(test|spec)\.[cm]?[jt]sx?$/.test(file));
25
+ }
17
26
  async function gitLog(root, maxCommits, signal) {
18
27
  return new Promise((resolve, reject) => {
19
28
  const child = spawn('git', [
@@ -62,10 +71,10 @@ async function gitLog(root, maxCommits, signal) {
62
71
  });
63
72
  }
64
73
  function sections(output) {
65
- const rawSections = output
74
+ return output
66
75
  .split('__TOOLIP_COMMIT__')
67
- .filter(Boolean);
68
- return rawSections.map((section) => {
76
+ .filter(Boolean)
77
+ .map((section) => {
69
78
  const newline = section.indexOf('\n');
70
79
  const header = newline === -1
71
80
  ? section
@@ -83,16 +92,31 @@ function sections(output) {
83
92
  });
84
93
  }
85
94
  function addedLines(body) {
86
- return body
87
- .split('\n')
88
- .filter((line) => line.startsWith('+') &&
89
- !line.startsWith('+++'))
90
- .map((line) => line.slice(1));
95
+ const output = [];
96
+ let currentFile;
97
+ for (const line of body.split('\n')) {
98
+ if (line.startsWith('+++ b/')) {
99
+ currentFile = line.slice('+++ b/'.length);
100
+ continue;
101
+ }
102
+ if (line.startsWith('+++ /dev/null')) {
103
+ currentFile = undefined;
104
+ continue;
105
+ }
106
+ if (line.startsWith('+') &&
107
+ !line.startsWith('+++')) {
108
+ output.push({
109
+ file: currentFile,
110
+ content: line.slice(1)
111
+ });
112
+ }
113
+ }
114
+ return output;
91
115
  }
92
116
  export class GitHistorySecretAnalyzer {
93
117
  maxCommits;
94
118
  id = 'git-history-secrets';
95
- version = '1.0.0';
119
+ version = '1.0.1';
96
120
  constructor(maxCommits = 1000) {
97
121
  this.maxCommits = maxCommits;
98
122
  }
@@ -103,42 +127,62 @@ export class GitHistorySecretAnalyzer {
103
127
  const seen = new Set();
104
128
  const commitSections = sections(output);
105
129
  for (const section of commitSections) {
106
- const content = addedLines(section.body).join('\n');
107
- for (const pattern of historicalSecretPatterns) {
108
- pattern.regex.lastIndex = 0;
109
- for (const match of content.matchAll(pattern.regex)) {
110
- const value = match[0];
111
- const secretFingerprint = fingerprint(value);
112
- const key = `${pattern.id}:${section.commit}:` +
113
- secretFingerprint;
114
- if (seen.has(key)) {
115
- continue;
116
- }
117
- seen.add(key);
118
- findings.push({
119
- id: key,
120
- ruleId: pattern.id,
121
- title: pattern.title,
122
- category: 'git-history-secret',
123
- severity: pattern.severity,
124
- confidence: 'high',
125
- message: `A secret-like value was introduced in commit ${section.commit}.`,
126
- source: 'git-history',
127
- evidence: [
128
- {
129
- summary: redact(value),
130
- fingerprint: secretFingerprint
131
- }
132
- ],
133
- remediation: {
134
- summary: 'Revoke or rotate the credential immediately, then remove it from repository history using an approved history-rewrite process.'
135
- },
136
- metadata: {
137
- commit: section.commit,
138
- author: section.author,
139
- date: section.date
130
+ for (const line of addedLines(section.body)) {
131
+ for (const pattern of historicalSecretPatterns) {
132
+ pattern.regex.lastIndex = 0;
133
+ for (const match of line.content.matchAll(pattern.regex)) {
134
+ const value = match[0];
135
+ const secretFingerprint = fingerprint(value);
136
+ const key = `${pattern.id}:${section.commit}:` +
137
+ `${line.file ?? 'unknown'}:` +
138
+ secretFingerprint;
139
+ if (seen.has(key)) {
140
+ continue;
140
141
  }
141
- });
142
+ seen.add(key);
143
+ const testFixture = isTestFile(line.file);
144
+ findings.push({
145
+ id: key,
146
+ ruleId: pattern.id,
147
+ title: testFixture
148
+ ? `Potential historical test fixture: ${pattern.title}`
149
+ : pattern.title,
150
+ category: 'git-history-secret',
151
+ severity: testFixture
152
+ ? 'low'
153
+ : pattern.severity,
154
+ confidence: testFixture
155
+ ? 'medium'
156
+ : 'high',
157
+ message: testFixture
158
+ ? `A secret-like value was introduced in test file ${line.file ?? 'unknown'} in commit ${section.commit}. Confirm that it is synthetic fixture data.`
159
+ : `A secret-like value was introduced in commit ${section.commit}.`,
160
+ source: 'git-history',
161
+ location: line.file
162
+ ? {
163
+ file: line.file
164
+ }
165
+ : undefined,
166
+ evidence: [
167
+ {
168
+ summary: redact(value),
169
+ fingerprint: secretFingerprint
170
+ }
171
+ ],
172
+ remediation: {
173
+ summary: testFixture
174
+ ? 'Confirm that the value is synthetic test data. Replace realistic credential fixtures with clearly fake placeholders where possible.'
175
+ : 'Revoke or rotate the credential immediately, then remove it from repository history using an approved history-rewrite process.'
176
+ },
177
+ metadata: {
178
+ commit: section.commit,
179
+ author: section.author,
180
+ date: section.date,
181
+ file: line.file,
182
+ testFixture
183
+ }
184
+ });
185
+ }
142
186
  }
143
187
  }
144
188
  }
@@ -149,6 +193,7 @@ export class GitHistorySecretAnalyzer {
149
193
  metadata: {
150
194
  commitsScanned: commitSections.length,
151
195
  findings: findings.length,
196
+ testFixtures: findings.filter((finding) => finding.metadata?.testFixture === true).length,
152
197
  maxCommits: this.maxCommits
153
198
  }
154
199
  };
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../../src/analyzers/git-history/analyzer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../../src/analyzers/git-history/analyzer.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,26 @@
1
1
  import chalk from 'chalk';
2
2
  import { scanDependencies } from '../core/dependency-scan.js';
3
- import { calculateDependencyHealth, calculateScore } from '../core/score.js';
3
+ import { calculateDependencyHealthFromPackages, calculateScore } from '../core/score.js';
4
4
  export function registerScoreCommand(program) {
5
5
  program
6
6
  .command('score')
7
7
  .description('Calculate a Toolip security scorecard for the current project.')
8
8
  .option('-p, --path <path>', 'Project path to score.', process.cwd())
9
+ .option('--json', 'Print structured JSON output.')
9
10
  .action(async (options) => {
10
11
  const dependencyScan = await scanDependencies(options.path);
11
- const dependencyHealth = calculateDependencyHealth(dependencyScan.findings);
12
- const score = calculateScore({ dependencyHealth });
12
+ const dependencyHealth = calculateDependencyHealthFromPackages(dependencyScan.packages);
13
+ const score = calculateScore({
14
+ dependencyHealth: dependencyHealth.score
15
+ });
16
+ if (options.json) {
17
+ console.log(JSON.stringify({
18
+ score,
19
+ dependencyHealth,
20
+ dependencySummary: dependencyScan.summary
21
+ }, null, 2));
22
+ return;
23
+ }
13
24
  console.log(chalk.bold('Toolip Security Scorecard'));
14
25
  console.log('');
15
26
  console.log(`${chalk.dim('Dependency Health ....')} ${score.dependencyHealth}`);
@@ -19,6 +30,12 @@ export function registerScoreCommand(program) {
19
30
  console.log('');
20
31
  console.log(`${chalk.dim('Overall Score ........')} ${score.overall}`);
21
32
  console.log(`${chalk.dim('Grade ................')} ${score.grade}`);
33
+ console.log('');
34
+ console.log(chalk.dim('Dependency score breakdown'));
35
+ console.log(`${chalk.dim('Vulnerability penalty')} ${dependencyHealth.vulnerabilityPenalty}`);
36
+ console.log(`${chalk.dim('Deprecation penalty ..')} ${dependencyHealth.deprecationPenalty}`);
37
+ console.log(`${chalk.dim('Maintenance penalty ..')} ${dependencyHealth.maintenancePenalty}`);
38
+ console.log(`${chalk.dim('Freshness penalty ....')} ${dependencyHealth.freshnessPenalty}`);
22
39
  });
23
40
  }
24
41
  //# sourceMappingURL=score.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/commands/score.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE7E,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,gEAAgE,CAAC;SAC7E,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;SACpE,MAAM,CAAC,KAAK,EAAE,OAAyB,EAAE,EAAE;QAC1C,MAAM,cAAc,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAEnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAChF,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC;QAC7E,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC,qBAAqB,EAAE,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/commands/score.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { PackageHealth } from './dependency-types.js';
1
2
  import type { ToolipFinding } from './report.js';
2
3
  export type ScoreGrade = 'A' | 'B' | 'C' | 'D' | 'F';
3
4
  export type ToolipScore = {
@@ -8,6 +9,27 @@ export type ToolipScore = {
8
9
  overall: number;
9
10
  grade: ScoreGrade;
10
11
  };
12
+ export type DependencyHealthBreakdown = {
13
+ score: number;
14
+ vulnerabilityPenalty: number;
15
+ deprecationPenalty: number;
16
+ maintenancePenalty: number;
17
+ freshnessPenalty: number;
18
+ outdated: {
19
+ major: number;
20
+ minor: number;
21
+ patch: number;
22
+ unknown: number;
23
+ };
24
+ };
11
25
  export declare function calculateScore(input?: Partial<Omit<ToolipScore, 'overall' | 'grade'>>): ToolipScore;
26
+ export declare function calculateDependencyHealthFromPackages(packages: PackageHealth[], vulnerabilityFindings?: ToolipFinding[]): DependencyHealthBreakdown;
27
+ /**
28
+ * Backward-compatible finding-based score.
29
+ *
30
+ * Outdated-package findings are treated as maintenance
31
+ * signals and capped so they cannot independently collapse
32
+ * dependency health to zero.
33
+ */
12
34
  export declare function calculateDependencyHealth(findings: ToolipFinding[]): number;
13
35
  export declare function gradeScore(score: number): ScoreGrade;
@@ -1,9 +1,13 @@
1
+ import semver from 'semver';
1
2
  export function calculateScore(input) {
2
3
  const dependencyHealth = clamp(input?.dependencyHealth ?? 100);
3
4
  const secretHygiene = clamp(input?.secretHygiene ?? 100);
4
5
  const configurationSecurity = clamp(input?.configurationSecurity ?? 100);
5
6
  const gitSafety = clamp(input?.gitSafety ?? 100);
6
- const overall = Math.round((dependencyHealth + secretHygiene + configurationSecurity + gitSafety) / 4);
7
+ const overall = Math.round((dependencyHealth +
8
+ secretHygiene +
9
+ configurationSecurity +
10
+ gitSafety) / 4);
7
11
  return {
8
12
  dependencyHealth,
9
13
  secretHygiene,
@@ -13,19 +17,140 @@ export function calculateScore(input) {
13
17
  grade: gradeScore(overall)
14
18
  };
15
19
  }
20
+ export function calculateDependencyHealthFromPackages(packages, vulnerabilityFindings = []) {
21
+ let criticalVulnerabilities = 0;
22
+ let highVulnerabilities = 0;
23
+ let mediumVulnerabilities = 0;
24
+ let lowVulnerabilities = 0;
25
+ for (const finding of vulnerabilityFindings) {
26
+ if (finding.category !== 'vulnerability') {
27
+ continue;
28
+ }
29
+ if (finding.severity === 'critical') {
30
+ criticalVulnerabilities += 1;
31
+ }
32
+ else if (finding.severity === 'high') {
33
+ highVulnerabilities += 1;
34
+ }
35
+ else if (finding.severity === 'medium') {
36
+ mediumVulnerabilities += 1;
37
+ }
38
+ else if (finding.severity === 'low') {
39
+ lowVulnerabilities += 1;
40
+ }
41
+ }
42
+ const vulnerabilityPenalty = Math.min(100, criticalVulnerabilities * 40 +
43
+ highVulnerabilities * 25 +
44
+ mediumVulnerabilities * 12 +
45
+ lowVulnerabilities * 4);
46
+ const deprecated = packages.filter((pkg) => pkg.deprecated).length;
47
+ const noMaintainers = packages.filter((pkg) => pkg.maintainers === 0).length;
48
+ const stale = packages.filter((pkg) => pkg.ageInDays !== null &&
49
+ pkg.ageInDays > 730).length;
50
+ const outdated = {
51
+ major: 0,
52
+ minor: 0,
53
+ patch: 0,
54
+ unknown: 0
55
+ };
56
+ for (const pkg of packages) {
57
+ if (!pkg.outdated ||
58
+ !pkg.latestVersion) {
59
+ continue;
60
+ }
61
+ const installed = semver.coerce(pkg.installedVersion);
62
+ const latest = semver.coerce(pkg.latestVersion);
63
+ if (!installed || !latest) {
64
+ outdated.unknown += 1;
65
+ continue;
66
+ }
67
+ if (latest.major > installed.major) {
68
+ outdated.major += 1;
69
+ }
70
+ else if (latest.minor > installed.minor) {
71
+ outdated.minor += 1;
72
+ }
73
+ else if (latest.patch > installed.patch) {
74
+ outdated.patch += 1;
75
+ }
76
+ else {
77
+ outdated.unknown += 1;
78
+ }
79
+ }
80
+ const deprecationPenalty = Math.min(40, deprecated * 18);
81
+ const maintenancePenalty = Math.min(20, noMaintainers * 4);
82
+ const freshnessPenalty = Math.min(15, outdated.major * 3 +
83
+ outdated.minor * 1 +
84
+ outdated.patch * 0.25 +
85
+ outdated.unknown * 1 +
86
+ stale * 1);
87
+ const score = clamp(100 -
88
+ vulnerabilityPenalty -
89
+ deprecationPenalty -
90
+ maintenancePenalty -
91
+ freshnessPenalty);
92
+ return {
93
+ score,
94
+ vulnerabilityPenalty,
95
+ deprecationPenalty,
96
+ maintenancePenalty,
97
+ freshnessPenalty: Math.round(freshnessPenalty * 100) /
98
+ 100,
99
+ outdated
100
+ };
101
+ }
102
+ /**
103
+ * Backward-compatible finding-based score.
104
+ *
105
+ * Outdated-package findings are treated as maintenance
106
+ * signals and capped so they cannot independently collapse
107
+ * dependency health to zero.
108
+ */
16
109
  export function calculateDependencyHealth(findings) {
17
- const penalty = findings.reduce((total, finding) => {
18
- if (finding.severity === 'critical')
19
- return total + 35;
20
- if (finding.severity === 'high')
21
- return total + 25;
22
- if (finding.severity === 'medium')
23
- return total + 12;
24
- if (finding.severity === 'low')
25
- return total + 5;
26
- return total + 0;
27
- }, 0);
28
- return clamp(100 - penalty);
110
+ let vulnerabilityPenalty = 0;
111
+ let deprecationPenalty = 0;
112
+ let maintenancePenalty = 0;
113
+ let freshnessPenalty = 0;
114
+ for (const finding of findings) {
115
+ if (finding.category === 'vulnerability') {
116
+ vulnerabilityPenalty +=
117
+ severityPenalty(finding.severity);
118
+ continue;
119
+ }
120
+ if (finding.id.startsWith('TOOLIP-DEP-DEPRECATED-')) {
121
+ deprecationPenalty += 18;
122
+ continue;
123
+ }
124
+ if (finding.id.startsWith('TOOLIP-DEP-OUTDATED-')) {
125
+ freshnessPenalty += 1;
126
+ continue;
127
+ }
128
+ if (finding.id.startsWith('TOOLIP-DEP-NO-MAINTAINERS-')) {
129
+ maintenancePenalty += 4;
130
+ continue;
131
+ }
132
+ if (finding.id.startsWith('TOOLIP-DEP-STALE-')) {
133
+ freshnessPenalty += 1;
134
+ continue;
135
+ }
136
+ maintenancePenalty += Math.min(10, severityPenalty(finding.severity));
137
+ }
138
+ return clamp(100 -
139
+ Math.min(100, vulnerabilityPenalty) -
140
+ Math.min(40, deprecationPenalty) -
141
+ Math.min(20, maintenancePenalty) -
142
+ Math.min(15, freshnessPenalty));
143
+ }
144
+ function severityPenalty(severity) {
145
+ if (severity === 'critical')
146
+ return 40;
147
+ if (severity === 'high')
148
+ return 25;
149
+ if (severity === 'medium')
150
+ return 12;
151
+ if (severity === 'low')
152
+ return 4;
153
+ return 0;
29
154
  }
30
155
  function clamp(value) {
31
156
  return Math.max(0, Math.min(100, Math.round(value)));
@@ -1 +1 @@
1
- {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/core/score.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,cAAc,CAAC,KAAuD;IACpF,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,EAAE,gBAAgB,IAAI,GAAG,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,EAAE,aAAa,IAAI,GAAG,CAAC,CAAC;IACzD,MAAM,qBAAqB,GAAG,KAAK,CAAC,KAAK,EAAE,qBAAqB,IAAI,GAAG,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,GAAG,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CACxB,CAAC,gBAAgB,GAAG,aAAa,GAAG,qBAAqB,GAAG,SAAS,CAAC,GAAG,CAAC,CAC3E,CAAC;IAEF,OAAO;QACL,gBAAgB;QAChB,aAAa;QACb,qBAAqB;QACrB,SAAS;QACT,OAAO;QACP,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAyB;IACjE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACjD,IAAI,OAAO,CAAC,QAAQ,KAAK,UAAU;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACnD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACrD,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK;YAAE,OAAO,KAAK,GAAG,CAAC,CAAC;QACjD,OAAO,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC,EAAE,CAAC,CAAC,CAAC;IAEN,OAAO,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,KAAK,CAAC,KAAa;IAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,GAAG,CAAC;IAC5B,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/core/score.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolip",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "A TypeScript-powered developer security companion CLI for supply chain security, dependency intelligence, secret detection, security auditing, encrypted local secrets management, Git security checks, and secure development education.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,10 +21,11 @@
21
21
  "test:watch": "vitest",
22
22
  "typecheck": "tsc --noEmit",
23
23
  "verify:package": "node scripts/verify-package.mjs",
24
- "verify": "npm run typecheck && npm test && npm run clean && npm run build && npm run verify:package",
24
+ "verify": "npm run verify:changelog && npm run typecheck && npm test && npm run clean && npm run build && npm run verify:package",
25
25
  "prepack": "npm run verify",
26
26
  "pack:check": "npm pack --dry-run",
27
- "release:check": "bash scripts/release-check.sh"
27
+ "release:check": "bash scripts/release-check.sh",
28
+ "verify:changelog": "node scripts/verify-changelog.mjs"
28
29
  },
29
30
  "keywords": [
30
31
  "typescript",