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.
- package/dist/src/analyzers/git-history/analyzer.d.ts +1 -1
- package/dist/src/analyzers/git-history/analyzer.js +89 -44
- package/dist/src/analyzers/git-history/analyzer.js.map +1 -1
- package/dist/src/commands/score.js +20 -3
- package/dist/src/commands/score.js.map +1 -1
- package/dist/src/core/score.d.ts +22 -0
- package/dist/src/core/score.js +138 -13
- package/dist/src/core/score.js.map +1 -1
- package/package.json +4 -3
|
@@ -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.
|
|
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
|
-
|
|
74
|
+
return output
|
|
66
75
|
.split('__TOOLIP_COMMIT__')
|
|
67
|
-
.filter(Boolean)
|
|
68
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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.
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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":"AAAA,OAAO,EACL,KAAK,EACN,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAOzC,OAAO,EACL,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;
|
|
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 {
|
|
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 =
|
|
12
|
-
const score = calculateScore({
|
|
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":"
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/commands/score.ts"],"names":[],"mappings":"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"}
|
package/dist/src/core/score.d.ts
CHANGED
|
@@ -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;
|
package/dist/src/core/score.js
CHANGED
|
@@ -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 +
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (finding.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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":"
|
|
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.
|
|
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",
|