toolip 1.0.6 → 1.0.7
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/commands/alternatives.d.ts +2 -0
- package/dist/src/commands/alternatives.js +17 -0
- package/dist/src/commands/alternatives.js.map +1 -0
- package/dist/src/commands/compare.d.ts +2 -0
- package/dist/src/commands/compare.js +19 -0
- package/dist/src/commands/compare.js.map +1 -0
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +42 -0
- package/dist/src/commands/doctor.js.map +1 -0
- package/dist/src/commands/git-audit.d.ts +2 -0
- package/dist/src/commands/git-audit.js +37 -0
- package/dist/src/commands/git-audit.js.map +1 -0
- package/dist/src/commands/hook.d.ts +2 -0
- package/dist/src/commands/hook.js +16 -0
- package/dist/src/commands/hook.js.map +1 -0
- package/dist/src/commands/inspect.d.ts +2 -0
- package/dist/src/commands/inspect.js +24 -0
- package/dist/src/commands/inspect.js.map +1 -0
- package/dist/src/commands/learn.d.ts +2 -0
- package/dist/src/commands/learn.js +42 -0
- package/dist/src/commands/learn.js.map +1 -0
- package/dist/src/commands/licenses.d.ts +2 -0
- package/dist/src/commands/licenses.js +40 -0
- package/dist/src/commands/licenses.js.map +1 -0
- package/dist/src/commands/pre-commit.d.ts +2 -0
- package/dist/src/commands/pre-commit.js +37 -0
- package/dist/src/commands/pre-commit.js.map +1 -0
- package/dist/src/commands/profile.d.ts +2 -0
- package/dist/src/commands/profile.js +18 -0
- package/dist/src/commands/profile.js.map +1 -0
- package/dist/src/commands/scan.d.ts +2 -0
- package/dist/src/commands/scan.js +48 -0
- package/dist/src/commands/scan.js.map +1 -0
- package/dist/src/commands/score.d.ts +2 -0
- package/dist/src/commands/score.js +24 -0
- package/dist/src/commands/score.js.map +1 -0
- package/dist/src/commands/self-test.d.ts +2 -0
- package/dist/src/commands/self-test.js +63 -0
- package/dist/src/commands/self-test.js.map +1 -0
- package/dist/src/commands/tree.d.ts +2 -0
- package/dist/src/commands/tree.js +21 -0
- package/dist/src/commands/tree.js.map +1 -0
- package/dist/src/commands/vault.d.ts +2 -0
- package/dist/src/commands/vault.js +86 -0
- package/dist/src/commands/vault.js.map +1 -0
- package/dist/src/config/version.d.ts +6 -0
- package/dist/src/config/version.js +29 -0
- package/dist/src/config/version.js.map +1 -0
- package/dist/src/core/alternatives.d.ts +8 -0
- package/dist/src/core/alternatives.js +35 -0
- package/dist/src/core/alternatives.js.map +1 -0
- package/dist/src/core/analyze-package.d.ts +2 -0
- package/dist/src/core/analyze-package.js +49 -0
- package/dist/src/core/analyze-package.js.map +1 -0
- package/dist/src/core/compare-packages.d.ts +7 -0
- package/dist/src/core/compare-packages.js +19 -0
- package/dist/src/core/compare-packages.js.map +1 -0
- package/dist/src/core/dependency-scan.d.ts +17 -0
- package/dist/src/core/dependency-scan.js +70 -0
- package/dist/src/core/dependency-scan.js.map +1 -0
- package/dist/src/core/dependency-tree.d.ts +16 -0
- package/dist/src/core/dependency-tree.js +19 -0
- package/dist/src/core/dependency-tree.js.map +1 -0
- package/dist/src/core/dependency-types.d.ts +17 -0
- package/dist/src/core/dependency-types.js +2 -0
- package/dist/src/core/dependency-types.js.map +1 -0
- package/dist/src/core/file-walker.d.ts +6 -0
- package/dist/src/core/file-walker.js +27 -0
- package/dist/src/core/file-walker.js.map +1 -0
- package/dist/src/core/git-audit.d.ts +12 -0
- package/dist/src/core/git-audit.js +111 -0
- package/dist/src/core/git-audit.js.map +1 -0
- package/dist/src/core/hooks.d.ts +1 -0
- package/dist/src/core/hooks.js +14 -0
- package/dist/src/core/hooks.js.map +1 -0
- package/dist/src/core/learn.d.ts +11 -0
- package/dist/src/core/learn.js +163 -0
- package/dist/src/core/learn.js.map +1 -0
- package/dist/src/core/license-analysis.d.ts +18 -0
- package/dist/src/core/license-analysis.js +98 -0
- package/dist/src/core/license-analysis.js.map +1 -0
- package/dist/src/core/load-toolip-ignore.d.ts +5 -0
- package/dist/src/core/load-toolip-ignore.js +35 -0
- package/dist/src/core/load-toolip-ignore.js.map +1 -0
- package/dist/src/core/npm-registry.d.ts +3 -0
- package/dist/src/core/npm-registry.js +5 -0
- package/dist/src/core/npm-registry.js.map +1 -0
- package/dist/src/core/pre-commit.d.ts +11 -0
- package/dist/src/core/pre-commit.js +22 -0
- package/dist/src/core/pre-commit.js.map +1 -0
- package/dist/src/core/profile-project.d.ts +23 -0
- package/dist/src/core/profile-project.js +119 -0
- package/dist/src/core/profile-project.js.map +1 -0
- package/dist/src/core/read-dependencies.d.ts +2 -0
- package/dist/src/core/read-dependencies.js +24 -0
- package/dist/src/core/read-dependencies.js.map +1 -0
- package/dist/src/core/report-writer.d.ts +5 -0
- package/dist/src/core/report-writer.js +61 -0
- package/dist/src/core/report-writer.js.map +1 -0
- package/dist/src/core/report.d.ts +34 -0
- package/dist/src/core/report.js +26 -0
- package/dist/src/core/report.js.map +1 -0
- package/dist/src/core/risk-score.d.ts +5 -0
- package/dist/src/core/risk-score.js +14 -0
- package/dist/src/core/risk-score.js.map +1 -0
- package/dist/src/core/scanner-context.d.ts +12 -0
- package/dist/src/core/scanner-context.js +27 -0
- package/dist/src/core/scanner-context.js.map +1 -0
- package/dist/src/core/score.d.ts +13 -0
- package/dist/src/core/score.js +44 -0
- package/dist/src/core/score.js.map +1 -0
- package/dist/src/core/security-doctor.d.ts +12 -0
- package/dist/src/core/security-doctor.js +144 -0
- package/dist/src/core/security-doctor.js.map +1 -0
- package/dist/src/core/security-patterns.d.ts +14 -0
- package/dist/src/core/security-patterns.js +139 -0
- package/dist/src/core/security-patterns.js.map +1 -0
- package/dist/src/core/typosquat.d.ts +6 -0
- package/dist/src/core/typosquat.js +50 -0
- package/dist/src/core/typosquat.js.map +1 -0
- package/dist/src/core/vault.d.ts +48 -0
- package/dist/src/core/vault.js +127 -0
- package/dist/src/core/vault.js.map +1 -0
- package/dist/src/errors/toolip-error.d.ts +8 -0
- package/dist/src/errors/toolip-error.js +11 -0
- package/dist/src/errors/toolip-error.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +51 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/utils/error-handler.d.ts +1 -0
- package/dist/src/utils/error-handler.js +24 -0
- package/dist/src/utils/error-handler.js.map +1 -0
- package/dist/src/utils/output.d.ts +6 -0
- package/dist/src/utils/output.js +72 -0
- package/dist/src/utils/output.js.map +1 -0
- package/dist/src/utils/package-output.d.ts +4 -0
- package/dist/src/utils/package-output.js +40 -0
- package/dist/src/utils/package-output.js.map +1 -0
- package/package.json +9 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/core/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAAY;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEnD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,SAAS,CACb,QAAQ,EACR;;;CAGH,EACG,MAAM,CACP,CAAC;IAEF,MAAM,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAE7B,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type LearnTopic = {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
explanation: string;
|
|
5
|
+
risks: string[];
|
|
6
|
+
mistakes: string[];
|
|
7
|
+
secureExamples: string[];
|
|
8
|
+
bestPractices: string[];
|
|
9
|
+
};
|
|
10
|
+
export declare function listLearnTopics(): LearnTopic[];
|
|
11
|
+
export declare function getLearnTopic(topic: string): LearnTopic | null;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
const topics = {
|
|
2
|
+
cors: {
|
|
3
|
+
id: 'cors',
|
|
4
|
+
title: 'CORS Security',
|
|
5
|
+
explanation: 'CORS controls which origins can access browser-protected resources from your API.',
|
|
6
|
+
risks: [
|
|
7
|
+
'Overly broad origins can expose APIs to untrusted frontends.',
|
|
8
|
+
'Credentials with wildcard origins can create serious access-control mistakes.'
|
|
9
|
+
],
|
|
10
|
+
mistakes: [
|
|
11
|
+
'Using origin: "*" for authenticated APIs.',
|
|
12
|
+
'Using the same CORS policy in development and production.'
|
|
13
|
+
],
|
|
14
|
+
secureExamples: [
|
|
15
|
+
'Allow only https://yourdomain.com in production.',
|
|
16
|
+
'Use environment-specific allowed origin lists.'
|
|
17
|
+
],
|
|
18
|
+
bestPractices: [
|
|
19
|
+
'Avoid wildcard origins for sensitive APIs.',
|
|
20
|
+
'Review CORS together with cookies, credentials, and authentication.'
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
jwt: {
|
|
24
|
+
id: 'jwt',
|
|
25
|
+
title: 'JWT Security',
|
|
26
|
+
explanation: 'JWTs are signed tokens used to represent claims, identity, and authorization context.',
|
|
27
|
+
risks: [
|
|
28
|
+
'Weak secrets allow token forgery.',
|
|
29
|
+
'Long-lived tokens increase impact after theft.'
|
|
30
|
+
],
|
|
31
|
+
mistakes: [
|
|
32
|
+
'Using "secret" or "password" as the JWT secret.',
|
|
33
|
+
'Setting access tokens to last for months or years.'
|
|
34
|
+
],
|
|
35
|
+
secureExamples: [
|
|
36
|
+
'Use a long random secret from a secret manager.',
|
|
37
|
+
'Use short access-token lifetimes with refresh-token rotation.'
|
|
38
|
+
],
|
|
39
|
+
bestPractices: [
|
|
40
|
+
'Validate issuer, audience, signature, and expiry.',
|
|
41
|
+
'Never store JWT secrets in source code.'
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
xss: {
|
|
45
|
+
id: 'xss',
|
|
46
|
+
title: 'Cross-Site Scripting',
|
|
47
|
+
explanation: 'XSS happens when untrusted input is rendered as executable browser code.',
|
|
48
|
+
risks: [
|
|
49
|
+
'Session theft.',
|
|
50
|
+
'Account takeover.',
|
|
51
|
+
'Malicious actions performed as the user.'
|
|
52
|
+
],
|
|
53
|
+
mistakes: [
|
|
54
|
+
'Rendering raw HTML from users.',
|
|
55
|
+
'Trusting sanitized content without context-aware escaping.'
|
|
56
|
+
],
|
|
57
|
+
secureExamples: [
|
|
58
|
+
'Escape output by default.',
|
|
59
|
+
'Use CSP to reduce script execution risk.'
|
|
60
|
+
],
|
|
61
|
+
bestPractices: [
|
|
62
|
+
'Avoid dangerous HTML injection APIs.',
|
|
63
|
+
'Sanitize rich text with a trusted sanitizer.'
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
csrf: {
|
|
67
|
+
id: 'csrf',
|
|
68
|
+
title: 'Cross-Site Request Forgery',
|
|
69
|
+
explanation: 'CSRF tricks a logged-in browser into sending unwanted authenticated requests.',
|
|
70
|
+
risks: [
|
|
71
|
+
'Unauthorized state changes.',
|
|
72
|
+
'Account setting changes.',
|
|
73
|
+
'Financial or administrative actions triggered silently.'
|
|
74
|
+
],
|
|
75
|
+
mistakes: [
|
|
76
|
+
'Relying only on cookies for authentication.',
|
|
77
|
+
'Not using SameSite cookie settings.'
|
|
78
|
+
],
|
|
79
|
+
secureExamples: [
|
|
80
|
+
'Use SameSite=Lax or SameSite=Strict cookies.',
|
|
81
|
+
'Use CSRF tokens for sensitive state-changing requests.'
|
|
82
|
+
],
|
|
83
|
+
bestPractices: [
|
|
84
|
+
'Require explicit anti-CSRF protection for cookie-authenticated apps.',
|
|
85
|
+
'Avoid GET requests for state-changing operations.'
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
secrets: {
|
|
89
|
+
id: 'secrets',
|
|
90
|
+
title: 'Secrets Management',
|
|
91
|
+
explanation: 'Secrets are credentials such as API keys, tokens, passwords, and private keys.',
|
|
92
|
+
risks: [
|
|
93
|
+
'Committed secrets can be copied forever from Git history.',
|
|
94
|
+
'Leaked credentials can grant attackers access to production systems.'
|
|
95
|
+
],
|
|
96
|
+
mistakes: [
|
|
97
|
+
'Storing secrets in .env files committed to Git.',
|
|
98
|
+
'Hardcoding API keys in source files.'
|
|
99
|
+
],
|
|
100
|
+
secureExamples: [
|
|
101
|
+
'Use environment variables or encrypted local vaults.',
|
|
102
|
+
'Rotate credentials after exposure.'
|
|
103
|
+
],
|
|
104
|
+
bestPractices: [
|
|
105
|
+
'Keep .env files ignored.',
|
|
106
|
+
'Commit only safe .env.example files.',
|
|
107
|
+
'Scan before committing.'
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
auth: {
|
|
111
|
+
id: 'auth',
|
|
112
|
+
title: 'Authentication and Authorization',
|
|
113
|
+
explanation: 'Authentication verifies identity; authorization decides what that identity can access.',
|
|
114
|
+
risks: [
|
|
115
|
+
'Broken access control.',
|
|
116
|
+
'Privilege escalation.',
|
|
117
|
+
'Session compromise.'
|
|
118
|
+
],
|
|
119
|
+
mistakes: [
|
|
120
|
+
'Checking only if a user is logged in.',
|
|
121
|
+
'Trusting client-side roles.'
|
|
122
|
+
],
|
|
123
|
+
secureExamples: [
|
|
124
|
+
'Check permissions on the server for every protected action.',
|
|
125
|
+
'Use least privilege access rules.'
|
|
126
|
+
],
|
|
127
|
+
bestPractices: [
|
|
128
|
+
'Separate authentication from authorization.',
|
|
129
|
+
'Log sensitive access and permission changes.'
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
dependencies: {
|
|
133
|
+
id: 'dependencies',
|
|
134
|
+
title: 'Dependency Security',
|
|
135
|
+
explanation: 'Dependency security is about managing risk from third-party packages.',
|
|
136
|
+
risks: [
|
|
137
|
+
'Deprecated packages may stop receiving fixes.',
|
|
138
|
+
'Typosquatted packages can impersonate popular libraries.',
|
|
139
|
+
'Transitive dependencies can introduce hidden risk.'
|
|
140
|
+
],
|
|
141
|
+
mistakes: [
|
|
142
|
+
'Installing packages without checking maintainers.',
|
|
143
|
+
'Ignoring deprecated package warnings.',
|
|
144
|
+
'Allowing dependency bloat.'
|
|
145
|
+
],
|
|
146
|
+
secureExamples: [
|
|
147
|
+
'Inspect package health before adoption.',
|
|
148
|
+
'Prefer maintained packages with active releases.'
|
|
149
|
+
],
|
|
150
|
+
bestPractices: [
|
|
151
|
+
'Review lockfile changes.',
|
|
152
|
+
'Use small dependency surfaces.',
|
|
153
|
+
'Replace abandoned packages early.'
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
export function listLearnTopics() {
|
|
158
|
+
return Object.values(topics);
|
|
159
|
+
}
|
|
160
|
+
export function getLearnTopic(topic) {
|
|
161
|
+
return topics[topic.toLowerCase()] ?? null;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=learn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learn.js","sourceRoot":"","sources":["../../../src/core/learn.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,GAA+B;IACzC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,mFAAmF;QAChG,KAAK,EAAE;YACL,8DAA8D;YAC9D,+EAA+E;SAChF;QACD,QAAQ,EAAE;YACR,2CAA2C;YAC3C,2DAA2D;SAC5D;QACD,cAAc,EAAE;YACd,kDAAkD;YAClD,gDAAgD;SACjD;QACD,aAAa,EAAE;YACb,4CAA4C;YAC5C,qEAAqE;SACtE;KACF;IACD,GAAG,EAAE;QACH,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,uFAAuF;QACpG,KAAK,EAAE;YACL,mCAAmC;YACnC,gDAAgD;SACjD;QACD,QAAQ,EAAE;YACR,iDAAiD;YACjD,oDAAoD;SACrD;QACD,cAAc,EAAE;YACd,iDAAiD;YACjD,+DAA+D;SAChE;QACD,aAAa,EAAE;YACb,mDAAmD;YACnD,yCAAyC;SAC1C;KACF;IACD,GAAG,EAAE;QACH,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,0EAA0E;QACvF,KAAK,EAAE;YACL,gBAAgB;YAChB,mBAAmB;YACnB,0CAA0C;SAC3C;QACD,QAAQ,EAAE;YACR,gCAAgC;YAChC,4DAA4D;SAC7D;QACD,cAAc,EAAE;YACd,2BAA2B;YAC3B,0CAA0C;SAC3C;QACD,aAAa,EAAE;YACb,sCAAsC;YACtC,8CAA8C;SAC/C;KACF;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,4BAA4B;QACnC,WAAW,EAAE,+EAA+E;QAC5F,KAAK,EAAE;YACL,6BAA6B;YAC7B,0BAA0B;YAC1B,yDAAyD;SAC1D;QACD,QAAQ,EAAE;YACR,6CAA6C;YAC7C,qCAAqC;SACtC;QACD,cAAc,EAAE;YACd,8CAA8C;YAC9C,wDAAwD;SACzD;QACD,aAAa,EAAE;YACb,sEAAsE;YACtE,mDAAmD;SACpD;KACF;IACD,OAAO,EAAE;QACP,EAAE,EAAE,SAAS;QACb,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EAAE,gFAAgF;QAC7F,KAAK,EAAE;YACL,2DAA2D;YAC3D,sEAAsE;SACvE;QACD,QAAQ,EAAE;YACR,iDAAiD;YACjD,sCAAsC;SACvC;QACD,cAAc,EAAE;YACd,sDAAsD;YACtD,oCAAoC;SACrC;QACD,aAAa,EAAE;YACb,0BAA0B;YAC1B,sCAAsC;YACtC,yBAAyB;SAC1B;KACF;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,kCAAkC;QACzC,WAAW,EAAE,wFAAwF;QACrG,KAAK,EAAE;YACL,wBAAwB;YACxB,uBAAuB;YACvB,qBAAqB;SACtB;QACD,QAAQ,EAAE;YACR,uCAAuC;YACvC,6BAA6B;SAC9B;QACD,cAAc,EAAE;YACd,6DAA6D;YAC7D,mCAAmC;SACpC;QACD,aAAa,EAAE;YACb,6CAA6C;YAC7C,8CAA8C;SAC/C;KACF;IACD,YAAY,EAAE;QACZ,EAAE,EAAE,cAAc;QAClB,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,uEAAuE;QACpF,KAAK,EAAE;YACL,+CAA+C;YAC/C,0DAA0D;YAC1D,oDAAoD;SACrD;QACD,QAAQ,EAAE;YACR,mDAAmD;YACnD,uCAAuC;YACvC,4BAA4B;SAC7B;QACD,cAAc,EAAE;YACd,yCAAyC;YACzC,kDAAkD;SACnD;QACD,aAAa,EAAE;YACb,0BAA0B;YAC1B,gCAAgC;YAChC,mCAAmC;SACpC;KACF;CACF,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ToolipFinding } from './report.js';
|
|
2
|
+
export type LicenseEntry = {
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
license: string;
|
|
6
|
+
type: 'dependency' | 'devDependency';
|
|
7
|
+
};
|
|
8
|
+
export type LicenseAnalysisResult = {
|
|
9
|
+
licenses: LicenseEntry[];
|
|
10
|
+
findings: ToolipFinding[];
|
|
11
|
+
summary: {
|
|
12
|
+
total: number;
|
|
13
|
+
unknown: number;
|
|
14
|
+
restrictive: number;
|
|
15
|
+
distribution: Record<string, number>;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function analyzeLicenses(root: string): Promise<LicenseAnalysisResult>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const restrictiveLicenses = new Set([
|
|
4
|
+
'GPL',
|
|
5
|
+
'GPL-2.0',
|
|
6
|
+
'GPL-3.0',
|
|
7
|
+
'AGPL',
|
|
8
|
+
'AGPL-3.0',
|
|
9
|
+
'LGPL',
|
|
10
|
+
'LGPL-2.1',
|
|
11
|
+
'LGPL-3.0'
|
|
12
|
+
]);
|
|
13
|
+
export async function analyzeLicenses(root) {
|
|
14
|
+
const packageJsonPath = path.join(root, 'package.json');
|
|
15
|
+
const raw = await readFile(packageJsonPath, 'utf8');
|
|
16
|
+
const pkg = JSON.parse(raw);
|
|
17
|
+
const entries = [
|
|
18
|
+
...Object.entries(pkg.dependencies ?? {}).map(([name, version]) => ({
|
|
19
|
+
name,
|
|
20
|
+
version,
|
|
21
|
+
license: inferLicense(name),
|
|
22
|
+
type: 'dependency'
|
|
23
|
+
})),
|
|
24
|
+
...Object.entries(pkg.devDependencies ?? {}).map(([name, version]) => ({
|
|
25
|
+
name,
|
|
26
|
+
version,
|
|
27
|
+
license: inferLicense(name),
|
|
28
|
+
type: 'devDependency'
|
|
29
|
+
}))
|
|
30
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
31
|
+
const findings = entries.flatMap(licenseToFindings);
|
|
32
|
+
const distribution = entries.reduce((summary, entry) => {
|
|
33
|
+
summary[entry.license] = (summary[entry.license] ?? 0) + 1;
|
|
34
|
+
return summary;
|
|
35
|
+
}, {});
|
|
36
|
+
return {
|
|
37
|
+
licenses: entries,
|
|
38
|
+
findings,
|
|
39
|
+
summary: {
|
|
40
|
+
total: entries.length,
|
|
41
|
+
unknown: entries.filter((entry) => entry.license === 'UNKNOWN').length,
|
|
42
|
+
restrictive: entries.filter((entry) => restrictiveLicenses.has(entry.license)).length,
|
|
43
|
+
distribution
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function inferLicense(packageName) {
|
|
48
|
+
const known = {
|
|
49
|
+
'@types/node': 'MIT',
|
|
50
|
+
'@types/semver': 'MIT',
|
|
51
|
+
axios: 'MIT',
|
|
52
|
+
chalk: 'MIT',
|
|
53
|
+
commander: 'MIT',
|
|
54
|
+
express: 'MIT',
|
|
55
|
+
'fast-glob': 'MIT',
|
|
56
|
+
ignore: 'MIT',
|
|
57
|
+
ora: 'MIT',
|
|
58
|
+
pacote: 'ISC',
|
|
59
|
+
react: 'MIT',
|
|
60
|
+
request: 'Apache-2.0',
|
|
61
|
+
semver: 'ISC',
|
|
62
|
+
tsx: 'MIT',
|
|
63
|
+
typescript: 'Apache-2.0',
|
|
64
|
+
vitest: 'MIT',
|
|
65
|
+
zod: 'MIT'
|
|
66
|
+
};
|
|
67
|
+
return known[packageName] ?? 'UNKNOWN';
|
|
68
|
+
}
|
|
69
|
+
function licenseToFindings(entry) {
|
|
70
|
+
if (entry.license === 'UNKNOWN') {
|
|
71
|
+
return [
|
|
72
|
+
{
|
|
73
|
+
id: `TOOLIP-LICENSE-UNKNOWN-${entry.name.toUpperCase().replaceAll(/[^A-Z0-9]/g, '-')}`,
|
|
74
|
+
title: `Unknown license: ${entry.name}`,
|
|
75
|
+
severity: 'medium',
|
|
76
|
+
category: 'license',
|
|
77
|
+
message: `${entry.name} does not have a known license in Toolip's local license intelligence map.`,
|
|
78
|
+
recommendation: 'Manually verify the package license before using it in commercial or distributed software.',
|
|
79
|
+
evidence: entry.version
|
|
80
|
+
}
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
if (restrictiveLicenses.has(entry.license)) {
|
|
84
|
+
return [
|
|
85
|
+
{
|
|
86
|
+
id: `TOOLIP-LICENSE-RESTRICTIVE-${entry.name.toUpperCase().replaceAll(/[^A-Z0-9]/g, '-')}`,
|
|
87
|
+
title: `Restrictive license detected: ${entry.name}`,
|
|
88
|
+
severity: 'high',
|
|
89
|
+
category: 'license',
|
|
90
|
+
message: `${entry.name} appears to use ${entry.license}, which may introduce redistribution obligations.`,
|
|
91
|
+
recommendation: 'Review the license terms with care before using this package in proprietary software.',
|
|
92
|
+
evidence: entry.license
|
|
93
|
+
}
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=license-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license-analysis.js","sourceRoot":"","sources":["../../../src/core/license-analysis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import ignore from 'ignore';
|
|
4
|
+
const defaultPatterns = [
|
|
5
|
+
'node_modules',
|
|
6
|
+
'dist',
|
|
7
|
+
'coverage',
|
|
8
|
+
'build',
|
|
9
|
+
'.git',
|
|
10
|
+
'.toolip-vault.json'
|
|
11
|
+
];
|
|
12
|
+
export async function loadToolipIgnore(root) {
|
|
13
|
+
const ignoreFile = path.join(root, '.toolipignore');
|
|
14
|
+
let customPatterns = [];
|
|
15
|
+
try {
|
|
16
|
+
const raw = await readFile(ignoreFile, 'utf8');
|
|
17
|
+
customPatterns = raw
|
|
18
|
+
.split('\n')
|
|
19
|
+
.map((line) => line.trim())
|
|
20
|
+
.filter((line) => line.length > 0 && !line.startsWith('#'));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
customPatterns = [];
|
|
24
|
+
}
|
|
25
|
+
const patterns = [...defaultPatterns, ...customPatterns];
|
|
26
|
+
const ig = ignore().add(patterns);
|
|
27
|
+
return {
|
|
28
|
+
patterns,
|
|
29
|
+
ignores(filePath) {
|
|
30
|
+
const relativePath = path.relative(root, filePath).replaceAll('\\', '/');
|
|
31
|
+
return relativePath.length > 0 && ig.ignores(relativePath);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=load-toolip-ignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-toolip-ignore.js","sourceRoot":"","sources":["../../../src/core/load-toolip-ignore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,QAAQ,CAAC;AAO5B,MAAM,eAAe,GAAG;IACtB,cAAc;IACd,MAAM;IACN,UAAU;IACV,OAAO;IACP,MAAM;IACN,oBAAoB;CACrB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACpD,IAAI,cAAc,GAAa,EAAE,CAAC;IAElC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC/C,cAAc,GAAG,GAAG;aACjB,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,cAAc,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,cAAc,CAAC,CAAC;IACzD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAElC,OAAO;QACL,QAAQ;QACR,OAAO,CAAC,QAAgB;YACtB,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACzE,OAAO,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm-registry.js","sourceRoot":"","sources":["../../../src/core/npm-registry.ts"],"names":[],"mappings":"AAAA,OAAO,MAAgC,MAAM,QAAQ,CAAC;AAItD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,WAAmB;IAC5D,OAAO,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ToolipFinding } from './report.js';
|
|
2
|
+
export type PreCommitResult = {
|
|
3
|
+
passed: boolean;
|
|
4
|
+
findings: ToolipFinding[];
|
|
5
|
+
summary: {
|
|
6
|
+
critical: number;
|
|
7
|
+
high: number;
|
|
8
|
+
blocking: number;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export declare function runPreCommit(root: string): Promise<PreCommitResult>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { runGitAudit } from './git-audit.js';
|
|
2
|
+
import { runSecurityDoctor } from './security-doctor.js';
|
|
3
|
+
export async function runPreCommit(root) {
|
|
4
|
+
const [doctor, gitAudit] = await Promise.all([
|
|
5
|
+
runSecurityDoctor(root),
|
|
6
|
+
runGitAudit(root)
|
|
7
|
+
]);
|
|
8
|
+
const findings = [...doctor.findings, ...gitAudit.findings];
|
|
9
|
+
const critical = findings.filter((finding) => finding.severity === 'critical').length;
|
|
10
|
+
const high = findings.filter((finding) => finding.severity === 'high').length;
|
|
11
|
+
const blocking = critical + high;
|
|
12
|
+
return {
|
|
13
|
+
passed: blocking === 0,
|
|
14
|
+
findings,
|
|
15
|
+
summary: {
|
|
16
|
+
critical,
|
|
17
|
+
high,
|
|
18
|
+
blocking
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=pre-commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-commit.js","sourceRoot":"","sources":["../../../src/core/pre-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAazD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC3C,iBAAiB,CAAC,IAAI,CAAC;QACvB,WAAW,CAAC,IAAI,CAAC;KAClB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;IACtF,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAC9E,MAAM,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IAEjC,OAAO;QACL,MAAM,EAAE,QAAQ,KAAK,CAAC;QACtB,QAAQ;QACR,OAAO,EAAE;YACP,QAAQ;YACR,IAAI;YACJ,QAAQ;SACT;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ProjectProfile = {
|
|
2
|
+
root: string;
|
|
3
|
+
name: string;
|
|
4
|
+
version: string;
|
|
5
|
+
description: string;
|
|
6
|
+
packageManager: 'npm' | 'pnpm' | 'yarn' | 'unknown';
|
|
7
|
+
hasTypeScript: boolean;
|
|
8
|
+
hasJavaScript: boolean;
|
|
9
|
+
hasReact: boolean;
|
|
10
|
+
hasExpress: boolean;
|
|
11
|
+
hasFastify: boolean;
|
|
12
|
+
hasPrisma: boolean;
|
|
13
|
+
hasDocker: boolean;
|
|
14
|
+
hasVitest: boolean;
|
|
15
|
+
hasJest: boolean;
|
|
16
|
+
hasESLint: boolean;
|
|
17
|
+
hasPrettier: boolean;
|
|
18
|
+
hasGitHubActions: boolean;
|
|
19
|
+
detected: string[];
|
|
20
|
+
languages: Record<string, number>;
|
|
21
|
+
packageScripts: string[];
|
|
22
|
+
};
|
|
23
|
+
export declare function profileProject(root: string): Promise<ProjectProfile>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { access, readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { walkProjectFiles } from './file-walker.js';
|
|
4
|
+
async function fileExists(filePath) {
|
|
5
|
+
try {
|
|
6
|
+
await access(filePath);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async function readPackageJson(root) {
|
|
14
|
+
const packagePath = path.join(root, 'package.json');
|
|
15
|
+
if (!(await fileExists(packagePath))) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
const raw = await readFile(packagePath, 'utf8');
|
|
19
|
+
return JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
function dependencyNames(packageJson) {
|
|
22
|
+
const dependencies = packageJson.dependencies;
|
|
23
|
+
const devDependencies = packageJson.devDependencies;
|
|
24
|
+
return [
|
|
25
|
+
...Object.keys(dependencies ?? {}),
|
|
26
|
+
...Object.keys(devDependencies ?? {})
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
function packageScripts(packageJson) {
|
|
30
|
+
const scripts = packageJson.scripts;
|
|
31
|
+
return Object.keys(scripts ?? {});
|
|
32
|
+
}
|
|
33
|
+
async function detectPackageManager(root) {
|
|
34
|
+
if (await fileExists(path.join(root, 'pnpm-lock.yaml')))
|
|
35
|
+
return 'pnpm';
|
|
36
|
+
if (await fileExists(path.join(root, 'yarn.lock')))
|
|
37
|
+
return 'yarn';
|
|
38
|
+
if (await fileExists(path.join(root, 'package-lock.json')))
|
|
39
|
+
return 'npm';
|
|
40
|
+
return 'unknown';
|
|
41
|
+
}
|
|
42
|
+
function summarizeLanguages(files) {
|
|
43
|
+
const languageMap = {
|
|
44
|
+
ts: 'TypeScript',
|
|
45
|
+
tsx: 'TypeScript React',
|
|
46
|
+
js: 'JavaScript',
|
|
47
|
+
jsx: 'JavaScript React',
|
|
48
|
+
json: 'JSON',
|
|
49
|
+
yml: 'YAML',
|
|
50
|
+
yaml: 'YAML',
|
|
51
|
+
md: 'Markdown',
|
|
52
|
+
css: 'CSS',
|
|
53
|
+
html: 'HTML',
|
|
54
|
+
env: 'Environment',
|
|
55
|
+
dockerfile: 'Docker'
|
|
56
|
+
};
|
|
57
|
+
return files.reduce((summary, file) => {
|
|
58
|
+
const extension = file.extension || file.relativePath.toLowerCase();
|
|
59
|
+
const language = languageMap[extension] ?? extension.toUpperCase();
|
|
60
|
+
summary[language] = (summary[language] ?? 0) + 1;
|
|
61
|
+
return summary;
|
|
62
|
+
}, {});
|
|
63
|
+
}
|
|
64
|
+
export async function profileProject(root) {
|
|
65
|
+
const absoluteRoot = path.resolve(root);
|
|
66
|
+
const packageJson = await readPackageJson(absoluteRoot);
|
|
67
|
+
const deps = dependencyNames(packageJson);
|
|
68
|
+
const scripts = packageScripts(packageJson);
|
|
69
|
+
const files = await walkProjectFiles(absoluteRoot);
|
|
70
|
+
const packageManager = await detectPackageManager(absoluteRoot);
|
|
71
|
+
const profile = {
|
|
72
|
+
root: absoluteRoot,
|
|
73
|
+
name: typeof packageJson.name === 'string' ? packageJson.name : 'unknown',
|
|
74
|
+
version: typeof packageJson.version === 'string' ? packageJson.version : 'unknown',
|
|
75
|
+
description: typeof packageJson.description === 'string' ? packageJson.description : '',
|
|
76
|
+
packageManager,
|
|
77
|
+
hasTypeScript: deps.includes('typescript') || await fileExists(path.join(absoluteRoot, 'tsconfig.json')),
|
|
78
|
+
hasJavaScript: files.some((file) => ['js', 'jsx'].includes(file.extension)),
|
|
79
|
+
hasReact: deps.includes('react'),
|
|
80
|
+
hasExpress: deps.includes('express'),
|
|
81
|
+
hasFastify: deps.includes('fastify'),
|
|
82
|
+
hasPrisma: deps.includes('prisma') || deps.includes('@prisma/client'),
|
|
83
|
+
hasDocker: await fileExists(path.join(absoluteRoot, 'Dockerfile')) || await fileExists(path.join(absoluteRoot, 'docker-compose.yml')),
|
|
84
|
+
hasVitest: deps.includes('vitest'),
|
|
85
|
+
hasJest: deps.includes('jest'),
|
|
86
|
+
hasESLint: deps.includes('eslint'),
|
|
87
|
+
hasPrettier: deps.includes('prettier'),
|
|
88
|
+
hasGitHubActions: await fileExists(path.join(absoluteRoot, '.github', 'workflows')),
|
|
89
|
+
detected: [],
|
|
90
|
+
languages: summarizeLanguages(files),
|
|
91
|
+
packageScripts: scripts
|
|
92
|
+
};
|
|
93
|
+
if (profile.hasTypeScript)
|
|
94
|
+
profile.detected.push('TypeScript');
|
|
95
|
+
if (profile.hasJavaScript)
|
|
96
|
+
profile.detected.push('JavaScript');
|
|
97
|
+
if (profile.hasReact)
|
|
98
|
+
profile.detected.push('React');
|
|
99
|
+
if (profile.hasExpress)
|
|
100
|
+
profile.detected.push('Express');
|
|
101
|
+
if (profile.hasFastify)
|
|
102
|
+
profile.detected.push('Fastify');
|
|
103
|
+
if (profile.hasPrisma)
|
|
104
|
+
profile.detected.push('Prisma');
|
|
105
|
+
if (profile.hasDocker)
|
|
106
|
+
profile.detected.push('Docker');
|
|
107
|
+
if (profile.hasVitest)
|
|
108
|
+
profile.detected.push('Vitest');
|
|
109
|
+
if (profile.hasJest)
|
|
110
|
+
profile.detected.push('Jest');
|
|
111
|
+
if (profile.hasESLint)
|
|
112
|
+
profile.detected.push('ESLint');
|
|
113
|
+
if (profile.hasPrettier)
|
|
114
|
+
profile.detected.push('Prettier');
|
|
115
|
+
if (profile.hasGitHubActions)
|
|
116
|
+
profile.detected.push('GitHub Actions');
|
|
117
|
+
return profile;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=profile-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-project.js","sourceRoot":"","sources":["../../../src/core/profile-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export async function readDependencies(root) {
|
|
4
|
+
const packageJsonPath = path.join(root, 'package.json');
|
|
5
|
+
const raw = await readFile(packageJsonPath, 'utf8');
|
|
6
|
+
const pkg = JSON.parse(raw);
|
|
7
|
+
const results = [];
|
|
8
|
+
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
9
|
+
results.push({
|
|
10
|
+
name,
|
|
11
|
+
version,
|
|
12
|
+
type: 'dependency'
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
for (const [name, version] of Object.entries(pkg.devDependencies ?? {})) {
|
|
16
|
+
results.push({
|
|
17
|
+
name,
|
|
18
|
+
version,
|
|
19
|
+
type: 'devDependency'
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return results.sort((a, b) => a.name.localeCompare(b.name));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=read-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-dependencies.js","sourceRoot":"","sources":["../../../src/core/read-dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAEpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAGzB,CAAC;IAEF,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,OAAO;YACP,IAAI,EAAE,YAAY;SACnB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,OAAO;YACP,IAAI,EAAE,eAAe;SACtB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ToolipReport } from './report.js';
|
|
2
|
+
export type ReportFormat = 'json' | 'md';
|
|
3
|
+
export declare function detectReportFormat(outputPath: string): ReportFormat;
|
|
4
|
+
export declare function writeReport(outputPath: string, report: ToolipReport): Promise<void>;
|
|
5
|
+
export declare function renderMarkdownReport(report: ToolipReport): string;
|