@shipsafe/cli 0.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/README.md +167 -0
- package/dist/bin/shipsafe.d.ts +3 -0
- package/dist/bin/shipsafe.d.ts.map +1 -0
- package/dist/bin/shipsafe.js +33 -0
- package/dist/bin/shipsafe.js.map +1 -0
- package/dist/src/autofix/pr-generator.d.ts +48 -0
- package/dist/src/autofix/pr-generator.d.ts.map +1 -0
- package/dist/src/autofix/pr-generator.js +359 -0
- package/dist/src/autofix/pr-generator.js.map +1 -0
- package/dist/src/autofix/scaffolding.d.ts +26 -0
- package/dist/src/autofix/scaffolding.d.ts.map +1 -0
- package/dist/src/autofix/scaffolding.js +249 -0
- package/dist/src/autofix/scaffolding.js.map +1 -0
- package/dist/src/autofix/secret-fixer.d.ts +27 -0
- package/dist/src/autofix/secret-fixer.d.ts.map +1 -0
- package/dist/src/autofix/secret-fixer.js +138 -0
- package/dist/src/autofix/secret-fixer.js.map +1 -0
- package/dist/src/claude-md/manager.d.ts +17 -0
- package/dist/src/claude-md/manager.d.ts.map +1 -0
- package/dist/src/claude-md/manager.js +143 -0
- package/dist/src/claude-md/manager.js.map +1 -0
- package/dist/src/cli/activate.d.ts +4 -0
- package/dist/src/cli/activate.d.ts.map +1 -0
- package/dist/src/cli/activate.js +53 -0
- package/dist/src/cli/activate.js.map +1 -0
- package/dist/src/cli/config.d.ts +21 -0
- package/dist/src/cli/config.d.ts.map +1 -0
- package/dist/src/cli/config.js +128 -0
- package/dist/src/cli/config.js.map +1 -0
- package/dist/src/cli/connect.d.ts +36 -0
- package/dist/src/cli/connect.d.ts.map +1 -0
- package/dist/src/cli/connect.js +107 -0
- package/dist/src/cli/connect.js.map +1 -0
- package/dist/src/cli/init.d.ts +12 -0
- package/dist/src/cli/init.d.ts.map +1 -0
- package/dist/src/cli/init.js +45 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/license-check.d.ts +7 -0
- package/dist/src/cli/license-check.d.ts.map +1 -0
- package/dist/src/cli/license-check.js +69 -0
- package/dist/src/cli/license-check.js.map +1 -0
- package/dist/src/cli/license-gate.d.ts +9 -0
- package/dist/src/cli/license-gate.d.ts.map +1 -0
- package/dist/src/cli/license-gate.js +25 -0
- package/dist/src/cli/license-gate.js.map +1 -0
- package/dist/src/cli/scan.d.ts +9 -0
- package/dist/src/cli/scan.d.ts.map +1 -0
- package/dist/src/cli/scan.js +75 -0
- package/dist/src/cli/scan.js.map +1 -0
- package/dist/src/cli/setup.d.ts +27 -0
- package/dist/src/cli/setup.d.ts.map +1 -0
- package/dist/src/cli/setup.js +134 -0
- package/dist/src/cli/setup.js.map +1 -0
- package/dist/src/cli/status.d.ts +4 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +52 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/cli/upload-sourcemaps.d.ts +13 -0
- package/dist/src/cli/upload-sourcemaps.d.ts.map +1 -0
- package/dist/src/cli/upload-sourcemaps.js +157 -0
- package/dist/src/cli/upload-sourcemaps.js.map +1 -0
- package/dist/src/config/manager.d.ts +37 -0
- package/dist/src/config/manager.d.ts.map +1 -0
- package/dist/src/config/manager.js +131 -0
- package/dist/src/config/manager.js.map +1 -0
- package/dist/src/constants.d.ts +28 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +34 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/engines/graph/data-flow.d.ts +36 -0
- package/dist/src/engines/graph/data-flow.d.ts.map +1 -0
- package/dist/src/engines/graph/data-flow.js +189 -0
- package/dist/src/engines/graph/data-flow.js.map +1 -0
- package/dist/src/engines/graph/index.d.ts +20 -0
- package/dist/src/engines/graph/index.d.ts.map +1 -0
- package/dist/src/engines/graph/index.js +100 -0
- package/dist/src/engines/graph/index.js.map +1 -0
- package/dist/src/engines/graph/parser.d.ts +13 -0
- package/dist/src/engines/graph/parser.d.ts.map +1 -0
- package/dist/src/engines/graph/parser.js +620 -0
- package/dist/src/engines/graph/parser.js.map +1 -0
- package/dist/src/engines/graph/queries.d.ts +11 -0
- package/dist/src/engines/graph/queries.d.ts.map +1 -0
- package/dist/src/engines/graph/queries.js +196 -0
- package/dist/src/engines/graph/queries.js.map +1 -0
- package/dist/src/engines/graph/store.d.ts +35 -0
- package/dist/src/engines/graph/store.d.ts.map +1 -0
- package/dist/src/engines/graph/store.js +284 -0
- package/dist/src/engines/graph/store.js.map +1 -0
- package/dist/src/engines/pattern/gitleaks.d.ts +4 -0
- package/dist/src/engines/pattern/gitleaks.d.ts.map +1 -0
- package/dist/src/engines/pattern/gitleaks.js +78 -0
- package/dist/src/engines/pattern/gitleaks.js.map +1 -0
- package/dist/src/engines/pattern/index.d.ts +11 -0
- package/dist/src/engines/pattern/index.d.ts.map +1 -0
- package/dist/src/engines/pattern/index.js +111 -0
- package/dist/src/engines/pattern/index.js.map +1 -0
- package/dist/src/engines/pattern/semgrep.d.ts +4 -0
- package/dist/src/engines/pattern/semgrep.d.ts.map +1 -0
- package/dist/src/engines/pattern/semgrep.js +83 -0
- package/dist/src/engines/pattern/semgrep.js.map +1 -0
- package/dist/src/engines/pattern/trivy.d.ts +4 -0
- package/dist/src/engines/pattern/trivy.d.ts.map +1 -0
- package/dist/src/engines/pattern/trivy.js +90 -0
- package/dist/src/engines/pattern/trivy.js.map +1 -0
- package/dist/src/github/api.d.ts +19 -0
- package/dist/src/github/api.d.ts.map +1 -0
- package/dist/src/github/api.js +75 -0
- package/dist/src/github/api.js.map +1 -0
- package/dist/src/github/app-manifest.d.ts +28 -0
- package/dist/src/github/app-manifest.d.ts.map +1 -0
- package/dist/src/github/app-manifest.js +27 -0
- package/dist/src/github/app-manifest.js.map +1 -0
- package/dist/src/github/checks.d.ts +36 -0
- package/dist/src/github/checks.d.ts.map +1 -0
- package/dist/src/github/checks.js +90 -0
- package/dist/src/github/checks.js.map +1 -0
- package/dist/src/github/scanner.d.ts +20 -0
- package/dist/src/github/scanner.d.ts.map +1 -0
- package/dist/src/github/scanner.js +78 -0
- package/dist/src/github/scanner.js.map +1 -0
- package/dist/src/github/webhook.d.ts +39 -0
- package/dist/src/github/webhook.d.ts.map +1 -0
- package/dist/src/github/webhook.js +80 -0
- package/dist/src/github/webhook.js.map +1 -0
- package/dist/src/hooks/installer.d.ts +4 -0
- package/dist/src/hooks/installer.d.ts.map +1 -0
- package/dist/src/hooks/installer.js +146 -0
- package/dist/src/hooks/installer.js.map +1 -0
- package/dist/src/mcp/server.d.ts +2 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +96 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/check-package.d.ts +30 -0
- package/dist/src/mcp/tools/check-package.d.ts.map +1 -0
- package/dist/src/mcp/tools/check-package.js +196 -0
- package/dist/src/mcp/tools/check-package.js.map +1 -0
- package/dist/src/mcp/tools/fix.d.ts +41 -0
- package/dist/src/mcp/tools/fix.d.ts.map +1 -0
- package/dist/src/mcp/tools/fix.js +98 -0
- package/dist/src/mcp/tools/fix.js.map +1 -0
- package/dist/src/mcp/tools/graph-query.d.ts +7 -0
- package/dist/src/mcp/tools/graph-query.d.ts.map +1 -0
- package/dist/src/mcp/tools/graph-query.js +139 -0
- package/dist/src/mcp/tools/graph-query.js.map +1 -0
- package/dist/src/mcp/tools/production-errors.d.ts +23 -0
- package/dist/src/mcp/tools/production-errors.d.ts.map +1 -0
- package/dist/src/mcp/tools/production-errors.js +46 -0
- package/dist/src/mcp/tools/production-errors.js.map +1 -0
- package/dist/src/mcp/tools/scan.d.ts +7 -0
- package/dist/src/mcp/tools/scan.d.ts.map +1 -0
- package/dist/src/mcp/tools/scan.js +9 -0
- package/dist/src/mcp/tools/scan.js.map +1 -0
- package/dist/src/mcp/tools/status.d.ts +9 -0
- package/dist/src/mcp/tools/status.d.ts.map +1 -0
- package/dist/src/mcp/tools/status.js +18 -0
- package/dist/src/mcp/tools/status.js.map +1 -0
- package/dist/src/mcp/tools/verify-resolution.d.ts +12 -0
- package/dist/src/mcp/tools/verify-resolution.d.ts.map +1 -0
- package/dist/src/mcp/tools/verify-resolution.js +45 -0
- package/dist/src/mcp/tools/verify-resolution.js.map +1 -0
- package/dist/src/types.d.ts +136 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffolding.d.ts","sourceRoot":"","sources":["../../../src/autofix/scaffolding.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,sBAAsB,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EACA,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,aAAa,GACb,oBAAoB,GACpB,iBAAiB,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CACrC;AAED,UAAU,WAAW;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAavE;AA4MD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAmDjC"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Detect the framework from package.json dependencies.
|
|
5
|
+
*/
|
|
6
|
+
export function detectFramework(packageJson) {
|
|
7
|
+
const allDeps = {
|
|
8
|
+
...packageJson.dependencies,
|
|
9
|
+
...packageJson.devDependencies,
|
|
10
|
+
};
|
|
11
|
+
// Order matters — more specific frameworks first
|
|
12
|
+
if (allDeps['next'])
|
|
13
|
+
return 'nextjs';
|
|
14
|
+
if (allDeps['hono'])
|
|
15
|
+
return 'hono';
|
|
16
|
+
if (allDeps['fastify'])
|
|
17
|
+
return 'fastify';
|
|
18
|
+
if (allDeps['express'])
|
|
19
|
+
return 'express';
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if a package is present in the project dependencies.
|
|
24
|
+
*/
|
|
25
|
+
function hasDep(packageJson, name) {
|
|
26
|
+
return !!(packageJson.dependencies?.[name] || packageJson.devDependencies?.[name]);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if .env is listed in .gitignore.
|
|
30
|
+
*/
|
|
31
|
+
async function checkEnvInGitignore(projectDir) {
|
|
32
|
+
try {
|
|
33
|
+
const content = await fs.readFile(path.join(projectDir, '.gitignore'), 'utf-8');
|
|
34
|
+
return content.split('\n').some((line) => {
|
|
35
|
+
const trimmed = line.trim();
|
|
36
|
+
return trimmed === '.env' || trimmed === '.env*' || trimmed === '.env.*';
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate Express-specific security recommendations.
|
|
45
|
+
*/
|
|
46
|
+
function getExpressRecommendations(packageJson) {
|
|
47
|
+
const recs = [];
|
|
48
|
+
if (!hasDep(packageJson, 'helmet')) {
|
|
49
|
+
recs.push({
|
|
50
|
+
type: 'missing_helmet',
|
|
51
|
+
description: 'Express app is missing Helmet — HTTP headers are not secured against common attacks (XSS, clickjacking, MIME sniffing).',
|
|
52
|
+
fix: `// npm install helmet
|
|
53
|
+
import helmet from 'helmet';
|
|
54
|
+
app.use(helmet());`,
|
|
55
|
+
file: 'src/app.ts',
|
|
56
|
+
priority: 'high',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (!hasDep(packageJson, 'cors')) {
|
|
60
|
+
recs.push({
|
|
61
|
+
type: 'missing_cors',
|
|
62
|
+
description: 'No CORS middleware detected. Without explicit CORS configuration, the API may reject legitimate cross-origin requests or allow unintended origins.',
|
|
63
|
+
fix: `// npm install cors
|
|
64
|
+
import cors from 'cors';
|
|
65
|
+
app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') ?? [] }));`,
|
|
66
|
+
file: 'src/app.ts',
|
|
67
|
+
priority: 'medium',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (!hasDep(packageJson, 'express-rate-limit') && !hasDep(packageJson, 'rate-limiter-flexible')) {
|
|
71
|
+
recs.push({
|
|
72
|
+
type: 'missing_rate_limit',
|
|
73
|
+
description: 'No rate limiting middleware detected. API endpoints are vulnerable to brute-force and denial-of-service attacks.',
|
|
74
|
+
fix: `// npm install express-rate-limit
|
|
75
|
+
import rateLimit from 'express-rate-limit';
|
|
76
|
+
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));`,
|
|
77
|
+
file: 'src/app.ts',
|
|
78
|
+
priority: 'high',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return recs;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate Next.js-specific security recommendations.
|
|
85
|
+
*/
|
|
86
|
+
function getNextjsRecommendations(packageJson) {
|
|
87
|
+
const recs = [];
|
|
88
|
+
// Next.js CSP headers
|
|
89
|
+
recs.push({
|
|
90
|
+
type: 'missing_csp',
|
|
91
|
+
description: 'No Content Security Policy headers detected. CSP prevents XSS, data injection, and other code-injection attacks.',
|
|
92
|
+
fix: `// In next.config.js or middleware.ts:
|
|
93
|
+
const cspHeader = \`
|
|
94
|
+
default-src 'self';
|
|
95
|
+
script-src 'self';
|
|
96
|
+
style-src 'self';
|
|
97
|
+
img-src 'self' blob: data:;
|
|
98
|
+
font-src 'self';
|
|
99
|
+
connect-src 'self';
|
|
100
|
+
frame-ancestors 'none';
|
|
101
|
+
\`;
|
|
102
|
+
|
|
103
|
+
// next.config.js
|
|
104
|
+
const nextConfig = {
|
|
105
|
+
async headers() {
|
|
106
|
+
return [{
|
|
107
|
+
source: '/(.*)',
|
|
108
|
+
headers: [{ key: 'Content-Security-Policy', value: cspHeader.replace(/\\n/g, '') }],
|
|
109
|
+
}];
|
|
110
|
+
},
|
|
111
|
+
};`,
|
|
112
|
+
file: 'next.config.js',
|
|
113
|
+
priority: 'high',
|
|
114
|
+
});
|
|
115
|
+
if (!hasDep(packageJson, 'rate-limiter-flexible') && !hasDep(packageJson, '@upstash/ratelimit')) {
|
|
116
|
+
recs.push({
|
|
117
|
+
type: 'missing_rate_limit',
|
|
118
|
+
description: 'No rate limiting detected for API routes. Next.js API routes are vulnerable to abuse without rate limiting.',
|
|
119
|
+
fix: `// npm install @upstash/ratelimit @upstash/redis
|
|
120
|
+
// In your API route or middleware:
|
|
121
|
+
import { Ratelimit } from '@upstash/ratelimit';
|
|
122
|
+
import { Redis } from '@upstash/redis';
|
|
123
|
+
|
|
124
|
+
const ratelimit = new Ratelimit({
|
|
125
|
+
redis: Redis.fromEnv(),
|
|
126
|
+
limiter: Ratelimit.slidingWindow(10, '10 s'),
|
|
127
|
+
});`,
|
|
128
|
+
file: 'src/middleware.ts',
|
|
129
|
+
priority: 'medium',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return recs;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Generate Fastify-specific security recommendations.
|
|
136
|
+
*/
|
|
137
|
+
function getFastifyRecommendations(packageJson) {
|
|
138
|
+
const recs = [];
|
|
139
|
+
if (!hasDep(packageJson, '@fastify/helmet')) {
|
|
140
|
+
recs.push({
|
|
141
|
+
type: 'missing_helmet',
|
|
142
|
+
description: 'Fastify app is missing @fastify/helmet — HTTP security headers are not configured.',
|
|
143
|
+
fix: `// npm install @fastify/helmet
|
|
144
|
+
import helmet from '@fastify/helmet';
|
|
145
|
+
await app.register(helmet);`,
|
|
146
|
+
file: 'src/app.ts',
|
|
147
|
+
priority: 'high',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (!hasDep(packageJson, '@fastify/cors')) {
|
|
151
|
+
recs.push({
|
|
152
|
+
type: 'missing_cors',
|
|
153
|
+
description: 'No CORS plugin registered. Cross-origin requests may not be handled correctly.',
|
|
154
|
+
fix: `// npm install @fastify/cors
|
|
155
|
+
import cors from '@fastify/cors';
|
|
156
|
+
await app.register(cors, { origin: process.env.ALLOWED_ORIGINS?.split(',') ?? [] });`,
|
|
157
|
+
file: 'src/app.ts',
|
|
158
|
+
priority: 'medium',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (!hasDep(packageJson, '@fastify/rate-limit')) {
|
|
162
|
+
recs.push({
|
|
163
|
+
type: 'missing_rate_limit',
|
|
164
|
+
description: 'No rate limiting plugin detected. API endpoints are vulnerable to brute-force attacks.',
|
|
165
|
+
fix: `// npm install @fastify/rate-limit
|
|
166
|
+
import rateLimit from '@fastify/rate-limit';
|
|
167
|
+
await app.register(rateLimit, { max: 100, timeWindow: '15 minutes' });`,
|
|
168
|
+
file: 'src/app.ts',
|
|
169
|
+
priority: 'high',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return recs;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Generate Hono-specific security recommendations.
|
|
176
|
+
*/
|
|
177
|
+
function getHonoRecommendations(packageJson) {
|
|
178
|
+
const recs = [];
|
|
179
|
+
recs.push({
|
|
180
|
+
type: 'missing_cors',
|
|
181
|
+
description: 'Ensure CORS middleware is configured for your Hono app to control cross-origin access.',
|
|
182
|
+
fix: `import { cors } from 'hono/cors';
|
|
183
|
+
app.use('*', cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') ?? [] }));`,
|
|
184
|
+
file: 'src/index.ts',
|
|
185
|
+
priority: 'medium',
|
|
186
|
+
});
|
|
187
|
+
recs.push({
|
|
188
|
+
type: 'missing_csp',
|
|
189
|
+
description: 'Add security headers middleware to protect against common web attacks.',
|
|
190
|
+
fix: `import { secureHeaders } from 'hono/secure-headers';
|
|
191
|
+
app.use('*', secureHeaders());`,
|
|
192
|
+
file: 'src/index.ts',
|
|
193
|
+
priority: 'high',
|
|
194
|
+
});
|
|
195
|
+
return recs;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Detect the project framework and generate security recommendations.
|
|
199
|
+
* Returns null if the framework cannot be detected.
|
|
200
|
+
*/
|
|
201
|
+
export async function detectAndRecommend(projectDir) {
|
|
202
|
+
const dir = projectDir ?? process.cwd();
|
|
203
|
+
const packageJsonPath = path.join(dir, 'package.json');
|
|
204
|
+
let packageJson;
|
|
205
|
+
try {
|
|
206
|
+
const raw = await fs.readFile(packageJsonPath, 'utf-8');
|
|
207
|
+
packageJson = JSON.parse(raw);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return null; // No package.json — can't detect framework
|
|
211
|
+
}
|
|
212
|
+
const framework = detectFramework(packageJson);
|
|
213
|
+
if (!framework)
|
|
214
|
+
return null;
|
|
215
|
+
// Get framework-specific recommendations
|
|
216
|
+
let recommendations;
|
|
217
|
+
switch (framework) {
|
|
218
|
+
case 'express':
|
|
219
|
+
recommendations = getExpressRecommendations(packageJson);
|
|
220
|
+
break;
|
|
221
|
+
case 'nextjs':
|
|
222
|
+
recommendations = getNextjsRecommendations(packageJson);
|
|
223
|
+
break;
|
|
224
|
+
case 'fastify':
|
|
225
|
+
recommendations = getFastifyRecommendations(packageJson);
|
|
226
|
+
break;
|
|
227
|
+
case 'hono':
|
|
228
|
+
recommendations = getHonoRecommendations(packageJson);
|
|
229
|
+
break;
|
|
230
|
+
default:
|
|
231
|
+
recommendations = [];
|
|
232
|
+
}
|
|
233
|
+
// Common check: .env in .gitignore
|
|
234
|
+
const hasEnvInGitignore = await checkEnvInGitignore(dir);
|
|
235
|
+
if (!hasEnvInGitignore) {
|
|
236
|
+
recommendations.push({
|
|
237
|
+
type: 'missing_env_config',
|
|
238
|
+
description: '.env file is not listed in .gitignore. Environment variables containing secrets may be committed to version control.',
|
|
239
|
+
fix: `# Add to .gitignore:
|
|
240
|
+
.env
|
|
241
|
+
.env.*
|
|
242
|
+
.env.local`,
|
|
243
|
+
file: '.gitignore',
|
|
244
|
+
priority: 'high',
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return { framework, recommendations };
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=scaffolding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffolding.js","sourceRoot":"","sources":["../../../src/autofix/scaffolding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AA0BlC;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,WAAwB;IACtD,MAAM,OAAO,GAAG;QACd,GAAG,WAAW,CAAC,YAAY;QAC3B,GAAG,WAAW,CAAC,eAAe;KAC/B,CAAC;IAEF,iDAAiD;IACjD,IAAI,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,IAAI,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,MAAM,CAAC,WAAwB,EAAE,IAAY;IACpD,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACrF,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,mBAAmB,CAAC,UAAkB;IACnD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;QAChF,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,QAAQ,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAAC,WAAwB;IACzD,MAAM,IAAI,GAA6B,EAAE,CAAC;IAE1C,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,gBAAgB;YACtB,WAAW,EACT,yHAAyH;YAC3H,GAAG,EAAE;;mBAEQ;YACb,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,cAAc;YACpB,WAAW,EACT,oJAAoJ;YACtJ,GAAG,EAAE;;0EAE+D;YACpE,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,uBAAuB,CAAC,EAAE,CAAC;QAChG,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EACT,kHAAkH;YACpH,GAAG,EAAE;;4DAEiD;YACtD,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,WAAwB;IACxD,MAAM,IAAI,GAA6B,EAAE,CAAC;IAE1C,sBAAsB;IACtB,IAAI,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,aAAa;QACnB,WAAW,EACT,kHAAkH;QACpH,GAAG,EAAE;;;;;;;;;;;;;;;;;;;GAmBN;QACC,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,oBAAoB,CAAC,EAAE,CAAC;QAChG,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EACT,6GAA6G;YAC/G,GAAG,EAAE;;;;;;;;IAQP;YACE,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAAC,WAAwB;IACzD,MAAM,IAAI,GAA6B,EAAE,CAAC;IAE1C,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,gBAAgB;YACtB,WAAW,EACT,oFAAoF;YACtF,GAAG,EAAE;;4BAEiB;YACtB,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,gFAAgF;YAC7F,GAAG,EAAE;;qFAE0E;YAC/E,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,qBAAqB,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EACT,wFAAwF;YAC1F,GAAG,EAAE;;uEAE4D;YACjE,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,WAAwB;IACtD,MAAM,IAAI,GAA6B,EAAE,CAAC;IAE1C,IAAI,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,cAAc;QACpB,WAAW,EACT,wFAAwF;QAC1F,GAAG,EAAE;+EACsE;QAC3E,IAAI,EAAE,cAAc;QACpB,QAAQ,EAAE,QAAQ;KACnB,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC;QACR,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,wEAAwE;QACrF,GAAG,EAAE;+BACsB;QAC3B,IAAI,EAAE,cAAc;QACpB,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAAmB;IAEnB,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACxC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAEvD,IAAI,WAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACxD,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,CAAC,2CAA2C;IAC1D,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAE5B,yCAAyC;IACzC,IAAI,eAAyC,CAAC;IAC9C,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,SAAS;YACZ,eAAe,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;YACzD,MAAM;QACR,KAAK,QAAQ;YACX,eAAe,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;YACxD,MAAM;QACR,KAAK,SAAS;YACZ,eAAe,GAAG,yBAAyB,CAAC,WAAW,CAAC,CAAC;YACzD,MAAM;QACR,KAAK,MAAM;YACT,eAAe,GAAG,sBAAsB,CAAC,WAAW,CAAC,CAAC;YACtD,MAAM;QACR;YACE,eAAe,GAAG,EAAE,CAAC;IACzB,CAAC;IAED,mCAAmC;IACnC,MAAM,iBAAiB,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACzD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,eAAe,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,oBAAoB;YAC1B,WAAW,EACT,sHAAsH;YACxH,GAAG,EAAE;;;WAGA;YACL,IAAI,EAAE,YAAY;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Finding } from '../types.js';
|
|
2
|
+
export interface SecretFix {
|
|
3
|
+
file: string;
|
|
4
|
+
line: number;
|
|
5
|
+
secretType: string;
|
|
6
|
+
envVarName: string;
|
|
7
|
+
filesModified: string[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Generate an appropriate env var name from the secret type and surrounding context.
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateEnvVarName(secretType: string, context: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Detect the type of secret from the value or context.
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectSecretType(value: string, context: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Ensure .env is in .gitignore. Creates .gitignore if it doesn't exist.
|
|
19
|
+
* Returns true if .gitignore was modified, false if .env was already present.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ensureGitignoreHasEnv(projectDir?: string): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Detect and fix a hardcoded secret by moving it to .env and replacing
|
|
24
|
+
* the inline value with a process.env reference.
|
|
25
|
+
*/
|
|
26
|
+
export declare function fixHardcodedSecret(finding: Finding, projectDir?: string): Promise<SecretFix>;
|
|
27
|
+
//# sourceMappingURL=secret-fixer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-fixer.d.ts","sourceRoot":"","sources":["../../../src/autofix/secret-fixer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAwB9E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBvE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBjF;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAkEpB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Generate an appropriate env var name from the secret type and surrounding context.
|
|
5
|
+
*/
|
|
6
|
+
export function generateEnvVarName(secretType, context) {
|
|
7
|
+
// Combine type and context, remove non-alphanumeric chars, convert to UPPER_SNAKE_CASE
|
|
8
|
+
let raw = context || secretType;
|
|
9
|
+
// Remove common prefixes like 'const', 'let', 'var'
|
|
10
|
+
raw = raw.replace(/^(?:const|let|var)\s+/, '');
|
|
11
|
+
// Take just the first identifier if there's an assignment (include hyphens for kebab-case)
|
|
12
|
+
const identMatch = raw.match(/^([\w-]+)/);
|
|
13
|
+
if (identMatch) {
|
|
14
|
+
raw = identMatch[1];
|
|
15
|
+
}
|
|
16
|
+
// Convert camelCase / PascalCase to UPPER_SNAKE_CASE
|
|
17
|
+
const snaked = raw
|
|
18
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
|
19
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
|
|
20
|
+
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
21
|
+
.toUpperCase();
|
|
22
|
+
// Remove leading/trailing underscores
|
|
23
|
+
const cleaned = snaked.replace(/^_+|_+$/g, '').replace(/_+/g, '_');
|
|
24
|
+
return cleaned || 'SECRET_VALUE';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Detect the type of secret from the value or context.
|
|
28
|
+
*/
|
|
29
|
+
export function detectSecretType(value, context) {
|
|
30
|
+
const lower = (value + ' ' + context).toLowerCase();
|
|
31
|
+
if (/AKIA[0-9A-Z]{16}/.test(value))
|
|
32
|
+
return 'aws_access_key';
|
|
33
|
+
if (lower.includes('database') || lower.includes('postgres') || lower.includes('mysql'))
|
|
34
|
+
return 'database_url';
|
|
35
|
+
if (lower.includes('stripe') && lower.includes('sk_'))
|
|
36
|
+
return 'stripe_secret_key';
|
|
37
|
+
if (lower.includes('supabase'))
|
|
38
|
+
return 'supabase_key';
|
|
39
|
+
if (lower.includes('firebase'))
|
|
40
|
+
return 'firebase_key';
|
|
41
|
+
if (lower.includes('jwt') || lower.includes('token'))
|
|
42
|
+
return 'token';
|
|
43
|
+
if (lower.includes('password') || lower.includes('passwd'))
|
|
44
|
+
return 'password';
|
|
45
|
+
if (lower.includes('key') || lower.includes('apikey') || lower.includes('api_key'))
|
|
46
|
+
return 'api_key';
|
|
47
|
+
if (lower.includes('secret'))
|
|
48
|
+
return 'secret';
|
|
49
|
+
return 'api_key';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Ensure .env is in .gitignore. Creates .gitignore if it doesn't exist.
|
|
53
|
+
* Returns true if .gitignore was modified, false if .env was already present.
|
|
54
|
+
*/
|
|
55
|
+
export async function ensureGitignoreHasEnv(projectDir) {
|
|
56
|
+
const dir = projectDir ?? process.cwd();
|
|
57
|
+
const gitignorePath = path.join(dir, '.gitignore');
|
|
58
|
+
let content = '';
|
|
59
|
+
try {
|
|
60
|
+
content = await fs.readFile(gitignorePath, 'utf-8');
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// .gitignore doesn't exist — we'll create it
|
|
64
|
+
}
|
|
65
|
+
// Check if .env is already covered
|
|
66
|
+
const lines = content.split('\n');
|
|
67
|
+
const hasEnv = lines.some((line) => {
|
|
68
|
+
const trimmed = line.trim();
|
|
69
|
+
return trimmed === '.env' || trimmed === '.env*' || trimmed === '.env.*';
|
|
70
|
+
});
|
|
71
|
+
if (hasEnv)
|
|
72
|
+
return false;
|
|
73
|
+
// Append .env entry
|
|
74
|
+
const separator = content.length > 0 && !content.endsWith('\n') ? '\n' : '';
|
|
75
|
+
await fs.writeFile(gitignorePath, content + separator + '.env\n', 'utf-8');
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Detect and fix a hardcoded secret by moving it to .env and replacing
|
|
80
|
+
* the inline value with a process.env reference.
|
|
81
|
+
*/
|
|
82
|
+
export async function fixHardcodedSecret(finding, projectDir) {
|
|
83
|
+
const dir = projectDir ?? process.cwd();
|
|
84
|
+
const filePath = path.resolve(dir, finding.file);
|
|
85
|
+
const filesModified = [];
|
|
86
|
+
// 1. Read the file containing the hardcoded secret
|
|
87
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
88
|
+
const lines = content.split('\n');
|
|
89
|
+
const targetLine = lines[finding.line - 1];
|
|
90
|
+
if (!targetLine) {
|
|
91
|
+
throw new Error(`Line ${finding.line} not found in ${finding.file}`);
|
|
92
|
+
}
|
|
93
|
+
// 2. Extract the secret value
|
|
94
|
+
const secretMatch = targetLine.match(/['"`]([A-Za-z0-9_\-./+=:@]{8,})['"`]/);
|
|
95
|
+
if (!secretMatch) {
|
|
96
|
+
throw new Error(`Could not extract secret value from line ${finding.line} in ${finding.file}`);
|
|
97
|
+
}
|
|
98
|
+
const secretValue = secretMatch[1];
|
|
99
|
+
// 3. Determine variable context
|
|
100
|
+
const varNameMatch = targetLine.match(/(?:const|let|var)\s+(\w+)|(\w+)\s*[:=]/);
|
|
101
|
+
const context = varNameMatch?.[1] ?? varNameMatch?.[2] ?? '';
|
|
102
|
+
// 4. Detect secret type
|
|
103
|
+
const secretType = detectSecretType(secretValue, context);
|
|
104
|
+
// 5. Generate env var name
|
|
105
|
+
const envVarName = generateEnvVarName(secretType, context);
|
|
106
|
+
// 6. Replace hardcoded value with process.env reference
|
|
107
|
+
const newLine = targetLine.replace(secretMatch[0], `process.env.${envVarName}`);
|
|
108
|
+
lines[finding.line - 1] = newLine;
|
|
109
|
+
await fs.writeFile(filePath, lines.join('\n'), 'utf-8');
|
|
110
|
+
filesModified.push(finding.file);
|
|
111
|
+
// 7. Append to .env
|
|
112
|
+
const envPath = path.join(dir, '.env');
|
|
113
|
+
let envContent = '';
|
|
114
|
+
try {
|
|
115
|
+
envContent = await fs.readFile(envPath, 'utf-8');
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// .env doesn't exist yet — will be created
|
|
119
|
+
}
|
|
120
|
+
if (!envContent.includes(`${envVarName}=`)) {
|
|
121
|
+
const separator = envContent.length > 0 && !envContent.endsWith('\n') ? '\n' : '';
|
|
122
|
+
await fs.writeFile(envPath, envContent + separator + `${envVarName}=${secretValue}\n`, 'utf-8');
|
|
123
|
+
filesModified.push('.env');
|
|
124
|
+
}
|
|
125
|
+
// 8. Ensure .env is in .gitignore
|
|
126
|
+
const gitignoreModified = await ensureGitignoreHasEnv(dir);
|
|
127
|
+
if (gitignoreModified) {
|
|
128
|
+
filesModified.push('.gitignore');
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
file: finding.file,
|
|
132
|
+
line: finding.line,
|
|
133
|
+
secretType,
|
|
134
|
+
envVarName,
|
|
135
|
+
filesModified,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=secret-fixer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-fixer.js","sourceRoot":"","sources":["../../../src/autofix/secret-fixer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAWlC;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,UAAkB,EAAE,OAAe;IACpE,uFAAuF;IACvF,IAAI,GAAG,GAAG,OAAO,IAAI,UAAU,CAAC;IAEhC,oDAAoD;IACpD,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE/C,2FAA2F;IAC3F,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC1C,IAAI,UAAU,EAAE,CAAC;QACf,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED,qDAAqD;IACrD,MAAM,MAAM,GAAG,GAAG;SACf,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;SACnC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;SAC7B,WAAW,EAAE,CAAC;IAEjB,sCAAsC;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEnE,OAAO,OAAO,IAAI,cAAc,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,OAAe;IAC7D,MAAM,KAAK,GAAG,CAAC,KAAK,GAAG,GAAG,GAAG,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IAEpD,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,gBAAgB,CAAC;IAC5D,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QACrF,OAAO,cAAc,CAAC;IACxB,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,mBAAmB,CAAC;IAClF,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,cAAc,CAAC;IACtD,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,cAAc,CAAC;IACtD,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IACrE,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,UAAU,CAAC;IAC9E,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;QAChF,OAAO,SAAS,CAAC;IACnB,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAE9C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,UAAmB;IAC7D,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACxC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAEnD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;IAC/C,CAAC;IAED,mCAAmC;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,OAAO,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,QAAQ,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,IAAI,MAAM;QAAE,OAAO,KAAK,CAAC;IAEzB,oBAAoB;IACpB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,MAAM,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAgB,EAChB,UAAmB;IAEnB,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,mDAAmD;IACnD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAE3C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,QAAQ,OAAO,CAAC,IAAI,iBAAiB,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,8BAA8B;IAC9B,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC7E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,4CAA4C,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAEnC,gCAAgC;IAChC,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE7D,wBAAwB;IACxB,MAAM,UAAU,GAAG,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAE1D,2BAA2B;IAC3B,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAE3D,wDAAwD;IACxD,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,eAAe,UAAU,EAAE,CAAC,CAAC;IAChF,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;IAClC,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACxD,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjC,oBAAoB;IACpB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACvC,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,MAAM,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,GAAG,GAAG,UAAU,IAAI,WAAW,IAAI,EAAE,OAAO,CAAC,CAAC;QAChG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,kCAAkC;IAClC,MAAM,iBAAiB,GAAG,MAAM,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,iBAAiB,EAAE,CAAC;QACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,UAAU;QACV,UAAU;QACV,aAAa;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injects or updates the ShipSafe instruction block in a project's CLAUDE.md file.
|
|
3
|
+
* - If CLAUDE.md doesn't exist, creates it with just the ShipSafe block.
|
|
4
|
+
* - If it exists but has no ShipSafe block, appends the block.
|
|
5
|
+
* - If it exists and has a ShipSafe block, replaces it with the latest template.
|
|
6
|
+
*/
|
|
7
|
+
export declare function injectClaudeMd(projectDir?: string): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Removes the ShipSafe block from CLAUDE.md, preserving the rest.
|
|
10
|
+
* Deletes the file if it would be empty after removal.
|
|
11
|
+
*/
|
|
12
|
+
export declare function removeClaudeMd(projectDir?: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Checks whether CLAUDE.md contains a ShipSafe instruction block.
|
|
15
|
+
*/
|
|
16
|
+
export declare function hasClaudeMdBlock(projectDir?: string): Promise<boolean>;
|
|
17
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/claude-md/manager.ts"],"names":[],"mappings":"AA0CA;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCvE;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+CvE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU5E"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { CLAUDE_MD_START, CLAUDE_MD_END } from '../constants.js';
|
|
4
|
+
const SHIPSAFE_TEMPLATE = `${CLAUDE_MD_START}
|
|
5
|
+
# ShipSafe Security & Monitoring Agent
|
|
6
|
+
|
|
7
|
+
## Session Start (MANDATORY)
|
|
8
|
+
At the start of EVERY session, do the following:
|
|
9
|
+
1. Ask the user: "ShipSafe is active on this project. Keep security protection enabled? (yes/no)"
|
|
10
|
+
2. If yes: call the \`shipsafe_status\` tool to check project state and queued production errors
|
|
11
|
+
3. If there are queued production errors, present them to the user and offer to fix them BEFORE starting new work
|
|
12
|
+
4. Print the one-line status: "ShipSafe: [score] | [issue count] issues | [error count] production errors"
|
|
13
|
+
|
|
14
|
+
## Rules (Active Copilot Mode - user said yes)
|
|
15
|
+
|
|
16
|
+
### Pre-Commit
|
|
17
|
+
- Before EVERY git commit, call \`shipsafe_scan\` and wait for results
|
|
18
|
+
- If critical or high issues are found, fix them before committing. Do NOT commit with unresolved critical/high findings.
|
|
19
|
+
- If medium/low issues are found, inform the user and let them decide
|
|
20
|
+
|
|
21
|
+
### Security Practices
|
|
22
|
+
- NEVER hardcode API keys, tokens, secrets, or credentials. Always use environment variables.
|
|
23
|
+
- If you detect a hardcoded secret, move it to .env, add .env to .gitignore, and replace with process.env reference
|
|
24
|
+
- When installing packages, call \`shipsafe_check_package\` to verify safety before installing
|
|
25
|
+
- Use parameterized queries. Never concatenate user input into SQL strings.
|
|
26
|
+
|
|
27
|
+
### Monitoring
|
|
28
|
+
- If this project does not have the ShipSafe monitoring snippet installed and it is a deployable web application, add it
|
|
29
|
+
- Do NOT remove or modify the ShipSafe monitoring snippet or git hooks
|
|
30
|
+
|
|
31
|
+
### Production Errors
|
|
32
|
+
- When production errors are delivered at session start, address them BEFORE working on new features
|
|
33
|
+
- Use the full context provided (stack trace, root cause, suggested fix)
|
|
34
|
+
- After fixing a production error, inform the user what was fixed and why
|
|
35
|
+
|
|
36
|
+
## Rules (Silent Guardian Mode - user said no)
|
|
37
|
+
- ShipSafe tools are available but do not proactively use them
|
|
38
|
+
- Git hooks will still run on commit/push
|
|
39
|
+
- Do NOT ask the user about ShipSafe again during this session
|
|
40
|
+
${CLAUDE_MD_END}`;
|
|
41
|
+
/**
|
|
42
|
+
* Injects or updates the ShipSafe instruction block in a project's CLAUDE.md file.
|
|
43
|
+
* - If CLAUDE.md doesn't exist, creates it with just the ShipSafe block.
|
|
44
|
+
* - If it exists but has no ShipSafe block, appends the block.
|
|
45
|
+
* - If it exists and has a ShipSafe block, replaces it with the latest template.
|
|
46
|
+
*/
|
|
47
|
+
export async function injectClaudeMd(projectDir) {
|
|
48
|
+
const dir = projectDir ?? process.cwd();
|
|
49
|
+
const filePath = path.join(dir, 'CLAUDE.md');
|
|
50
|
+
let existing = null;
|
|
51
|
+
try {
|
|
52
|
+
existing = await fs.readFile(filePath, 'utf-8');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// File doesn't exist
|
|
56
|
+
}
|
|
57
|
+
if (existing === null) {
|
|
58
|
+
// No file — create with just the block
|
|
59
|
+
await fs.writeFile(filePath, SHIPSAFE_TEMPLATE + '\n', 'utf-8');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (existing.includes(CLAUDE_MD_START)) {
|
|
63
|
+
// Replace existing block
|
|
64
|
+
const startIdx = existing.indexOf(CLAUDE_MD_START);
|
|
65
|
+
const endIdx = existing.indexOf(CLAUDE_MD_END);
|
|
66
|
+
if (endIdx === -1) {
|
|
67
|
+
// Malformed — has start but no end. Replace from start to EOF.
|
|
68
|
+
const before = existing.substring(0, startIdx);
|
|
69
|
+
await fs.writeFile(filePath, before + SHIPSAFE_TEMPLATE + '\n', 'utf-8');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const before = existing.substring(0, startIdx);
|
|
73
|
+
const after = existing.substring(endIdx + CLAUDE_MD_END.length);
|
|
74
|
+
await fs.writeFile(filePath, before + SHIPSAFE_TEMPLATE + after, 'utf-8');
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
// Append with blank line separator
|
|
78
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
79
|
+
await fs.writeFile(filePath, existing + separator + SHIPSAFE_TEMPLATE + '\n', 'utf-8');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Removes the ShipSafe block from CLAUDE.md, preserving the rest.
|
|
84
|
+
* Deletes the file if it would be empty after removal.
|
|
85
|
+
*/
|
|
86
|
+
export async function removeClaudeMd(projectDir) {
|
|
87
|
+
const dir = projectDir ?? process.cwd();
|
|
88
|
+
const filePath = path.join(dir, 'CLAUDE.md');
|
|
89
|
+
let content;
|
|
90
|
+
try {
|
|
91
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// File doesn't exist — nothing to do
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!content.includes(CLAUDE_MD_START)) {
|
|
98
|
+
// No ShipSafe block — nothing to do
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const startIdx = content.indexOf(CLAUDE_MD_START);
|
|
102
|
+
const endIdx = content.indexOf(CLAUDE_MD_END);
|
|
103
|
+
if (endIdx === -1) {
|
|
104
|
+
// Malformed — has start but no end. Remove from start to EOF.
|
|
105
|
+
const before = content.substring(0, startIdx);
|
|
106
|
+
const trimmed = before.replace(/\n+$/, '');
|
|
107
|
+
if (trimmed.length === 0) {
|
|
108
|
+
await fs.unlink(filePath);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
await fs.writeFile(filePath, trimmed + '\n', 'utf-8');
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const before = content.substring(0, startIdx);
|
|
116
|
+
const after = content.substring(endIdx + CLAUDE_MD_END.length);
|
|
117
|
+
let result = before + after;
|
|
118
|
+
// Clean up multiple consecutive blank lines (3+ newlines -> 2 newlines)
|
|
119
|
+
result = result.replace(/\n{3,}/g, '\n\n');
|
|
120
|
+
// Trim trailing whitespace
|
|
121
|
+
result = result.replace(/\s+$/, '');
|
|
122
|
+
if (result.length === 0) {
|
|
123
|
+
await fs.unlink(filePath);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await fs.writeFile(filePath, result + '\n', 'utf-8');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Checks whether CLAUDE.md contains a ShipSafe instruction block.
|
|
131
|
+
*/
|
|
132
|
+
export async function hasClaudeMdBlock(projectDir) {
|
|
133
|
+
const dir = projectDir ?? process.cwd();
|
|
134
|
+
const filePath = path.join(dir, 'CLAUDE.md');
|
|
135
|
+
try {
|
|
136
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
137
|
+
return content.includes(CLAUDE_MD_START);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/claude-md/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activate.d.ts","sourceRoot":"","sources":["../../../src/cli/activate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO9D"}
|