@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.
Files changed (166) hide show
  1. package/README.md +167 -0
  2. package/dist/bin/shipsafe.d.ts +3 -0
  3. package/dist/bin/shipsafe.d.ts.map +1 -0
  4. package/dist/bin/shipsafe.js +33 -0
  5. package/dist/bin/shipsafe.js.map +1 -0
  6. package/dist/src/autofix/pr-generator.d.ts +48 -0
  7. package/dist/src/autofix/pr-generator.d.ts.map +1 -0
  8. package/dist/src/autofix/pr-generator.js +359 -0
  9. package/dist/src/autofix/pr-generator.js.map +1 -0
  10. package/dist/src/autofix/scaffolding.d.ts +26 -0
  11. package/dist/src/autofix/scaffolding.d.ts.map +1 -0
  12. package/dist/src/autofix/scaffolding.js +249 -0
  13. package/dist/src/autofix/scaffolding.js.map +1 -0
  14. package/dist/src/autofix/secret-fixer.d.ts +27 -0
  15. package/dist/src/autofix/secret-fixer.d.ts.map +1 -0
  16. package/dist/src/autofix/secret-fixer.js +138 -0
  17. package/dist/src/autofix/secret-fixer.js.map +1 -0
  18. package/dist/src/claude-md/manager.d.ts +17 -0
  19. package/dist/src/claude-md/manager.d.ts.map +1 -0
  20. package/dist/src/claude-md/manager.js +143 -0
  21. package/dist/src/claude-md/manager.js.map +1 -0
  22. package/dist/src/cli/activate.d.ts +4 -0
  23. package/dist/src/cli/activate.d.ts.map +1 -0
  24. package/dist/src/cli/activate.js +53 -0
  25. package/dist/src/cli/activate.js.map +1 -0
  26. package/dist/src/cli/config.d.ts +21 -0
  27. package/dist/src/cli/config.d.ts.map +1 -0
  28. package/dist/src/cli/config.js +128 -0
  29. package/dist/src/cli/config.js.map +1 -0
  30. package/dist/src/cli/connect.d.ts +36 -0
  31. package/dist/src/cli/connect.d.ts.map +1 -0
  32. package/dist/src/cli/connect.js +107 -0
  33. package/dist/src/cli/connect.js.map +1 -0
  34. package/dist/src/cli/init.d.ts +12 -0
  35. package/dist/src/cli/init.d.ts.map +1 -0
  36. package/dist/src/cli/init.js +45 -0
  37. package/dist/src/cli/init.js.map +1 -0
  38. package/dist/src/cli/license-check.d.ts +7 -0
  39. package/dist/src/cli/license-check.d.ts.map +1 -0
  40. package/dist/src/cli/license-check.js +69 -0
  41. package/dist/src/cli/license-check.js.map +1 -0
  42. package/dist/src/cli/license-gate.d.ts +9 -0
  43. package/dist/src/cli/license-gate.d.ts.map +1 -0
  44. package/dist/src/cli/license-gate.js +25 -0
  45. package/dist/src/cli/license-gate.js.map +1 -0
  46. package/dist/src/cli/scan.d.ts +9 -0
  47. package/dist/src/cli/scan.d.ts.map +1 -0
  48. package/dist/src/cli/scan.js +75 -0
  49. package/dist/src/cli/scan.js.map +1 -0
  50. package/dist/src/cli/setup.d.ts +27 -0
  51. package/dist/src/cli/setup.d.ts.map +1 -0
  52. package/dist/src/cli/setup.js +134 -0
  53. package/dist/src/cli/setup.js.map +1 -0
  54. package/dist/src/cli/status.d.ts +4 -0
  55. package/dist/src/cli/status.d.ts.map +1 -0
  56. package/dist/src/cli/status.js +52 -0
  57. package/dist/src/cli/status.js.map +1 -0
  58. package/dist/src/cli/upload-sourcemaps.d.ts +13 -0
  59. package/dist/src/cli/upload-sourcemaps.d.ts.map +1 -0
  60. package/dist/src/cli/upload-sourcemaps.js +157 -0
  61. package/dist/src/cli/upload-sourcemaps.js.map +1 -0
  62. package/dist/src/config/manager.d.ts +37 -0
  63. package/dist/src/config/manager.d.ts.map +1 -0
  64. package/dist/src/config/manager.js +131 -0
  65. package/dist/src/config/manager.js.map +1 -0
  66. package/dist/src/constants.d.ts +28 -0
  67. package/dist/src/constants.d.ts.map +1 -0
  68. package/dist/src/constants.js +34 -0
  69. package/dist/src/constants.js.map +1 -0
  70. package/dist/src/engines/graph/data-flow.d.ts +36 -0
  71. package/dist/src/engines/graph/data-flow.d.ts.map +1 -0
  72. package/dist/src/engines/graph/data-flow.js +189 -0
  73. package/dist/src/engines/graph/data-flow.js.map +1 -0
  74. package/dist/src/engines/graph/index.d.ts +20 -0
  75. package/dist/src/engines/graph/index.d.ts.map +1 -0
  76. package/dist/src/engines/graph/index.js +100 -0
  77. package/dist/src/engines/graph/index.js.map +1 -0
  78. package/dist/src/engines/graph/parser.d.ts +13 -0
  79. package/dist/src/engines/graph/parser.d.ts.map +1 -0
  80. package/dist/src/engines/graph/parser.js +620 -0
  81. package/dist/src/engines/graph/parser.js.map +1 -0
  82. package/dist/src/engines/graph/queries.d.ts +11 -0
  83. package/dist/src/engines/graph/queries.d.ts.map +1 -0
  84. package/dist/src/engines/graph/queries.js +196 -0
  85. package/dist/src/engines/graph/queries.js.map +1 -0
  86. package/dist/src/engines/graph/store.d.ts +35 -0
  87. package/dist/src/engines/graph/store.d.ts.map +1 -0
  88. package/dist/src/engines/graph/store.js +284 -0
  89. package/dist/src/engines/graph/store.js.map +1 -0
  90. package/dist/src/engines/pattern/gitleaks.d.ts +4 -0
  91. package/dist/src/engines/pattern/gitleaks.d.ts.map +1 -0
  92. package/dist/src/engines/pattern/gitleaks.js +78 -0
  93. package/dist/src/engines/pattern/gitleaks.js.map +1 -0
  94. package/dist/src/engines/pattern/index.d.ts +11 -0
  95. package/dist/src/engines/pattern/index.d.ts.map +1 -0
  96. package/dist/src/engines/pattern/index.js +111 -0
  97. package/dist/src/engines/pattern/index.js.map +1 -0
  98. package/dist/src/engines/pattern/semgrep.d.ts +4 -0
  99. package/dist/src/engines/pattern/semgrep.d.ts.map +1 -0
  100. package/dist/src/engines/pattern/semgrep.js +83 -0
  101. package/dist/src/engines/pattern/semgrep.js.map +1 -0
  102. package/dist/src/engines/pattern/trivy.d.ts +4 -0
  103. package/dist/src/engines/pattern/trivy.d.ts.map +1 -0
  104. package/dist/src/engines/pattern/trivy.js +90 -0
  105. package/dist/src/engines/pattern/trivy.js.map +1 -0
  106. package/dist/src/github/api.d.ts +19 -0
  107. package/dist/src/github/api.d.ts.map +1 -0
  108. package/dist/src/github/api.js +75 -0
  109. package/dist/src/github/api.js.map +1 -0
  110. package/dist/src/github/app-manifest.d.ts +28 -0
  111. package/dist/src/github/app-manifest.d.ts.map +1 -0
  112. package/dist/src/github/app-manifest.js +27 -0
  113. package/dist/src/github/app-manifest.js.map +1 -0
  114. package/dist/src/github/checks.d.ts +36 -0
  115. package/dist/src/github/checks.d.ts.map +1 -0
  116. package/dist/src/github/checks.js +90 -0
  117. package/dist/src/github/checks.js.map +1 -0
  118. package/dist/src/github/scanner.d.ts +20 -0
  119. package/dist/src/github/scanner.d.ts.map +1 -0
  120. package/dist/src/github/scanner.js +78 -0
  121. package/dist/src/github/scanner.js.map +1 -0
  122. package/dist/src/github/webhook.d.ts +39 -0
  123. package/dist/src/github/webhook.d.ts.map +1 -0
  124. package/dist/src/github/webhook.js +80 -0
  125. package/dist/src/github/webhook.js.map +1 -0
  126. package/dist/src/hooks/installer.d.ts +4 -0
  127. package/dist/src/hooks/installer.d.ts.map +1 -0
  128. package/dist/src/hooks/installer.js +146 -0
  129. package/dist/src/hooks/installer.js.map +1 -0
  130. package/dist/src/mcp/server.d.ts +2 -0
  131. package/dist/src/mcp/server.d.ts.map +1 -0
  132. package/dist/src/mcp/server.js +96 -0
  133. package/dist/src/mcp/server.js.map +1 -0
  134. package/dist/src/mcp/tools/check-package.d.ts +30 -0
  135. package/dist/src/mcp/tools/check-package.d.ts.map +1 -0
  136. package/dist/src/mcp/tools/check-package.js +196 -0
  137. package/dist/src/mcp/tools/check-package.js.map +1 -0
  138. package/dist/src/mcp/tools/fix.d.ts +41 -0
  139. package/dist/src/mcp/tools/fix.d.ts.map +1 -0
  140. package/dist/src/mcp/tools/fix.js +98 -0
  141. package/dist/src/mcp/tools/fix.js.map +1 -0
  142. package/dist/src/mcp/tools/graph-query.d.ts +7 -0
  143. package/dist/src/mcp/tools/graph-query.d.ts.map +1 -0
  144. package/dist/src/mcp/tools/graph-query.js +139 -0
  145. package/dist/src/mcp/tools/graph-query.js.map +1 -0
  146. package/dist/src/mcp/tools/production-errors.d.ts +23 -0
  147. package/dist/src/mcp/tools/production-errors.d.ts.map +1 -0
  148. package/dist/src/mcp/tools/production-errors.js +46 -0
  149. package/dist/src/mcp/tools/production-errors.js.map +1 -0
  150. package/dist/src/mcp/tools/scan.d.ts +7 -0
  151. package/dist/src/mcp/tools/scan.d.ts.map +1 -0
  152. package/dist/src/mcp/tools/scan.js +9 -0
  153. package/dist/src/mcp/tools/scan.js.map +1 -0
  154. package/dist/src/mcp/tools/status.d.ts +9 -0
  155. package/dist/src/mcp/tools/status.d.ts.map +1 -0
  156. package/dist/src/mcp/tools/status.js +18 -0
  157. package/dist/src/mcp/tools/status.js.map +1 -0
  158. package/dist/src/mcp/tools/verify-resolution.d.ts +12 -0
  159. package/dist/src/mcp/tools/verify-resolution.d.ts.map +1 -0
  160. package/dist/src/mcp/tools/verify-resolution.js +45 -0
  161. package/dist/src/mcp/tools/verify-resolution.js.map +1 -0
  162. package/dist/src/types.d.ts +136 -0
  163. package/dist/src/types.d.ts.map +1 -0
  164. package/dist/src/types.js +2 -0
  165. package/dist/src/types.js.map +1 -0
  166. package/package.json +53 -0
@@ -0,0 +1,20 @@
1
+ import type { ScanResult } from '../types.js';
2
+ export interface PrScanOptions {
3
+ repoFullName: string;
4
+ prNumber: number;
5
+ headSha: string;
6
+ baseSha: string;
7
+ installationId: number;
8
+ }
9
+ /**
10
+ * Get changed files in a PR and scan them.
11
+ *
12
+ * 1. Fetches list of changed files via GitHub API
13
+ * 2. Downloads content of each changed file
14
+ * 3. Writes them to a temp directory
15
+ * 4. Runs pattern engine scan
16
+ * 5. Cleans up temp directory
17
+ * 6. Returns scan result
18
+ */
19
+ export declare function scanPullRequest(options: PrScanOptions): Promise<ScanResult>;
20
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/github/scanner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AASD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAkDjF"}
@@ -0,0 +1,78 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+ import { getInstallationToken, githubApi } from './api.js';
5
+ import { runPatternEngine } from '../engines/pattern/index.js';
6
+ /**
7
+ * Get changed files in a PR and scan them.
8
+ *
9
+ * 1. Fetches list of changed files via GitHub API
10
+ * 2. Downloads content of each changed file
11
+ * 3. Writes them to a temp directory
12
+ * 4. Runs pattern engine scan
13
+ * 5. Cleans up temp directory
14
+ * 6. Returns scan result
15
+ */
16
+ export async function scanPullRequest(options) {
17
+ const token = await getInstallationToken(options.installationId);
18
+ // 1. Fetch changed files
19
+ const files = await fetchChangedFiles(options.repoFullName, options.prNumber, token);
20
+ // Filter out deleted files — nothing to scan
21
+ const filesToScan = files.filter((f) => f.status !== 'removed');
22
+ if (filesToScan.length === 0) {
23
+ return {
24
+ status: 'pass',
25
+ score: 'A',
26
+ findings: [],
27
+ scan_duration_ms: 0,
28
+ };
29
+ }
30
+ // 2. Create temp directory
31
+ const tmpDir = await fs.mkdtemp(path.join(tmpdir(), 'shipsafe-pr-'));
32
+ try {
33
+ // 3. Download and write each file
34
+ const filePaths = [];
35
+ for (const file of filesToScan) {
36
+ const content = await fetchFileContent(options.repoFullName, file.filename, options.headSha, token);
37
+ const filePath = path.join(tmpDir, file.filename);
38
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
39
+ await fs.writeFile(filePath, content, 'utf-8');
40
+ filePaths.push(file.filename);
41
+ }
42
+ // 4. Run pattern engine scan on the temp directory
43
+ const result = await runPatternEngine({
44
+ targetPath: tmpDir,
45
+ scope: 'all',
46
+ stagedFiles: filePaths,
47
+ });
48
+ return result;
49
+ }
50
+ finally {
51
+ // 5. Clean up temp directory
52
+ await fs.rm(tmpDir, { recursive: true, force: true });
53
+ }
54
+ }
55
+ /**
56
+ * Fetch the list of files changed in a PR.
57
+ */
58
+ async function fetchChangedFiles(repoFullName, prNumber, token) {
59
+ const result = (await githubApi(`/repos/${repoFullName}/pulls/${prNumber}/files`, {
60
+ token,
61
+ }));
62
+ return result;
63
+ }
64
+ /**
65
+ * Fetch the raw content of a file at a specific commit SHA.
66
+ */
67
+ async function fetchFileContent(repoFullName, filePath, sha, token) {
68
+ const result = (await githubApi(`/repos/${repoFullName}/contents/${filePath}?ref=${sha}`, {
69
+ token,
70
+ }));
71
+ if (result.content && result.encoding === 'base64') {
72
+ return Buffer.from(result.content, 'base64').toString('utf-8');
73
+ }
74
+ // Fallback: try raw download
75
+ const rawResult = (await githubApi(`https://raw.githubusercontent.com/${repoFullName}/${sha}/${filePath}`, { token }));
76
+ return rawResult;
77
+ }
78
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../../src/github/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export interface WebhookEvent {
2
+ action: string;
3
+ pull_request: {
4
+ number: number;
5
+ head: {
6
+ sha: string;
7
+ ref: string;
8
+ };
9
+ base: {
10
+ sha: string;
11
+ ref: string;
12
+ };
13
+ };
14
+ repository: {
15
+ full_name: string;
16
+ clone_url: string;
17
+ };
18
+ installation: {
19
+ id: number;
20
+ };
21
+ }
22
+ /**
23
+ * Verify a GitHub webhook signature using HMAC-SHA256.
24
+ * Compares the computed signature against the provided one using timing-safe comparison.
25
+ */
26
+ export declare function verifyWebhookSignature(payload: string, signature: string, secret: string): boolean;
27
+ /**
28
+ * Process a GitHub webhook event.
29
+ *
30
+ * Flow:
31
+ * 1. Verify webhook signature
32
+ * 2. If action is 'opened' or 'synchronize':
33
+ * a. Create a pending check run via GitHub Checks API
34
+ * b. Scan the PR diff
35
+ * c. Post check run result (pass/fail with findings summary)
36
+ * 3. Ignore other actions
37
+ */
38
+ export declare function handleWebhook(event: WebhookEvent, signature: string, secret: string): Promise<void>;
39
+ //# sourceMappingURL=webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/github/webhook.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QACnC,IAAI,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;KACpC,CAAC;IACF,UAAU,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAaT;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAqDf"}
@@ -0,0 +1,80 @@
1
+ import { createHmac, timingSafeEqual } from 'node:crypto';
2
+ import { createCheckRun, completeCheckRun } from './checks.js';
3
+ import { scanPullRequest } from './scanner.js';
4
+ /**
5
+ * Verify a GitHub webhook signature using HMAC-SHA256.
6
+ * Compares the computed signature against the provided one using timing-safe comparison.
7
+ */
8
+ export function verifyWebhookSignature(payload, signature, secret) {
9
+ const computed = 'sha256=' + createHmac('sha256', secret).update(payload).digest('hex');
10
+ // Both must have the same length for timingSafeEqual
11
+ if (computed.length !== signature.length) {
12
+ return false;
13
+ }
14
+ try {
15
+ return timingSafeEqual(Buffer.from(computed), Buffer.from(signature));
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ /**
22
+ * Process a GitHub webhook event.
23
+ *
24
+ * Flow:
25
+ * 1. Verify webhook signature
26
+ * 2. If action is 'opened' or 'synchronize':
27
+ * a. Create a pending check run via GitHub Checks API
28
+ * b. Scan the PR diff
29
+ * c. Post check run result (pass/fail with findings summary)
30
+ * 3. Ignore other actions
31
+ */
32
+ export async function handleWebhook(event, signature, secret) {
33
+ // 1. Verify signature
34
+ const payload = JSON.stringify(event);
35
+ if (!verifyWebhookSignature(payload, signature, secret)) {
36
+ throw new Error('Invalid webhook signature');
37
+ }
38
+ // 2. Only process PR opened and synchronize events
39
+ if (event.action !== 'opened' && event.action !== 'synchronize') {
40
+ return;
41
+ }
42
+ const { pull_request: pr, repository, installation } = event;
43
+ // 2a. Create a pending check run
44
+ const checkRunId = await createCheckRun({
45
+ repoFullName: repository.full_name,
46
+ headSha: pr.head.sha,
47
+ installationId: installation.id,
48
+ });
49
+ try {
50
+ // 2b. Scan the PR diff
51
+ const scanResult = await scanPullRequest({
52
+ repoFullName: repository.full_name,
53
+ prNumber: pr.number,
54
+ headSha: pr.head.sha,
55
+ baseSha: pr.base.sha,
56
+ installationId: installation.id,
57
+ });
58
+ // 2c. Determine conclusion and post result
59
+ const conclusion = scanResult.status === 'fail' ? 'failure' : 'success';
60
+ await completeCheckRun({
61
+ repoFullName: repository.full_name,
62
+ checkRunId,
63
+ installationId: installation.id,
64
+ conclusion,
65
+ findings: scanResult.findings,
66
+ });
67
+ }
68
+ catch (err) {
69
+ // If scanning fails, mark the check as neutral with an error message
70
+ await completeCheckRun({
71
+ repoFullName: repository.full_name,
72
+ checkRunId,
73
+ installationId: installation.id,
74
+ conclusion: 'neutral',
75
+ findings: [],
76
+ });
77
+ throw err;
78
+ }
79
+ }
80
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../../src/github/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAgB/C;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAe,EACf,SAAiB,EACjB,MAAc;IAEd,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAExF,qDAAqD;IACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAmB,EACnB,SAAiB,EACjB,MAAc;IAEd,sBAAsB;IACtB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,mDAAmD;IACnD,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;QAChE,OAAO;IACT,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IAE7D,iCAAiC;IACjC,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC;QACtC,YAAY,EAAE,UAAU,CAAC,SAAS;QAClC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG;QACpB,cAAc,EAAE,YAAY,CAAC,EAAE;KAChC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,uBAAuB;QACvB,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC;YACvC,YAAY,EAAE,UAAU,CAAC,SAAS;YAClC,QAAQ,EAAE,EAAE,CAAC,MAAM;YACnB,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG;YACpB,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG;YACpB,cAAc,EAAE,YAAY,CAAC,EAAE;SAChC,CAAC,CAAC;QAEH,2CAA2C;QAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAExE,MAAM,gBAAgB,CAAC;YACrB,YAAY,EAAE,UAAU,CAAC,SAAS;YAClC,UAAU;YACV,cAAc,EAAE,YAAY,CAAC,EAAE;YAC/B,UAAU;YACV,QAAQ,EAAE,UAAU,CAAC,QAAQ;SAC9B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,qEAAqE;QACrE,MAAM,gBAAgB,CAAC;YACrB,YAAY,EAAE,UAAU,CAAC,SAAS;YAClC,UAAU;YACV,cAAc,EAAE,YAAY,CAAC,EAAE;YAC/B,UAAU,EAAE,SAAS;YACrB,QAAQ,EAAE,EAAE;SACb,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function installHooks(projectDir?: string): Promise<void>;
2
+ export declare function uninstallHooks(projectDir?: string): Promise<void>;
3
+ export declare function checkHooksInstalled(projectDir?: string): Promise<boolean>;
4
+ //# sourceMappingURL=installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../../src/hooks/installer.ts"],"names":[],"mappings":"AAuEA,wBAAsB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BrE;AAED,wBAAsB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCvE;AAED,wBAAsB,mBAAmB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB/E"}
@@ -0,0 +1,146 @@
1
+ import * as fs from 'node:fs/promises';
2
+ import * as path from 'node:path';
3
+ import { HOOK_MARKER } from '../constants.js';
4
+ const PRE_COMMIT_HOOK = `#!/bin/sh
5
+ ${HOOK_MARKER}
6
+ # ShipSafe pre-commit hook — scans staged files before commit
7
+
8
+ SHIPSAFE=\$(command -v shipsafe 2>/dev/null)
9
+ if [ -z "\$SHIPSAFE" ]; then
10
+ SHIPSAFE="npx shipsafe"
11
+ fi
12
+
13
+ echo "ShipSafe: Scanning staged files..."
14
+ \$SHIPSAFE scan --scope staged
15
+
16
+ EXIT_CODE=\$?
17
+ if [ \$EXIT_CODE -ne 0 ]; then
18
+ echo ""
19
+ echo "ShipSafe: Critical/high security issues found. Fix before committing."
20
+ echo "To bypass (not recommended): git commit --no-verify"
21
+ exit 1
22
+ fi
23
+
24
+ exit 0
25
+ `;
26
+ const PRE_PUSH_HOOK = `#!/bin/sh
27
+ ${HOOK_MARKER}
28
+ # ShipSafe pre-push hook — runs full scan before push
29
+
30
+ SHIPSAFE=\$(command -v shipsafe 2>/dev/null)
31
+ if [ -z "\$SHIPSAFE" ]; then
32
+ SHIPSAFE="npx shipsafe"
33
+ fi
34
+
35
+ echo "ShipSafe: Running full scan before push..."
36
+ \$SHIPSAFE scan --scope all
37
+
38
+ EXIT_CODE=\$?
39
+ if [ \$EXIT_CODE -ne 0 ]; then
40
+ echo ""
41
+ echo "ShipSafe: Critical/high security issues found. Fix before pushing."
42
+ echo "To bypass (not recommended): git push --no-verify"
43
+ exit 1
44
+ fi
45
+
46
+ exit 0
47
+ `;
48
+ const HOOKS = [
49
+ { name: 'pre-commit', content: PRE_COMMIT_HOOK },
50
+ { name: 'pre-push', content: PRE_PUSH_HOOK },
51
+ ];
52
+ async function getHooksDir(projectDir) {
53
+ const gitDir = path.join(projectDir, '.git');
54
+ try {
55
+ const stat = await fs.stat(gitDir);
56
+ if (!stat.isDirectory()) {
57
+ throw new Error('Not a git repository');
58
+ }
59
+ }
60
+ catch (err) {
61
+ if (err.code === 'ENOENT') {
62
+ throw new Error('Not a git repository');
63
+ }
64
+ throw err;
65
+ }
66
+ return path.join(gitDir, 'hooks');
67
+ }
68
+ export async function installHooks(projectDir) {
69
+ const dir = projectDir ?? process.cwd();
70
+ const hooksDir = await getHooksDir(dir);
71
+ await fs.mkdir(hooksDir, { recursive: true });
72
+ for (const hook of HOOKS) {
73
+ const hookPath = path.join(hooksDir, hook.name);
74
+ const backupPath = path.join(hooksDir, `${hook.name}.pre-shipsafe`);
75
+ // Check if hook file already exists
76
+ let existingContent = null;
77
+ try {
78
+ existingContent = await fs.readFile(hookPath, 'utf-8');
79
+ }
80
+ catch {
81
+ // File doesn't exist, that's fine
82
+ }
83
+ if (existingContent !== null && !existingContent.includes(HOOK_MARKER)) {
84
+ // Existing non-ShipSafe hook — back it up
85
+ await fs.writeFile(backupPath, existingContent);
86
+ }
87
+ // Write the ShipSafe hook
88
+ await fs.writeFile(hookPath, hook.content, { mode: 0o755 });
89
+ }
90
+ }
91
+ export async function uninstallHooks(projectDir) {
92
+ const dir = projectDir ?? process.cwd();
93
+ let hooksDir;
94
+ try {
95
+ hooksDir = await getHooksDir(dir);
96
+ }
97
+ catch {
98
+ // Not a git repo or no .git dir — nothing to uninstall
99
+ return;
100
+ }
101
+ for (const hook of HOOKS) {
102
+ const hookPath = path.join(hooksDir, hook.name);
103
+ const backupPath = path.join(hooksDir, `${hook.name}.pre-shipsafe`);
104
+ // Check if current hook is a ShipSafe hook
105
+ let content = null;
106
+ try {
107
+ content = await fs.readFile(hookPath, 'utf-8');
108
+ }
109
+ catch {
110
+ // Hook doesn't exist, skip
111
+ continue;
112
+ }
113
+ if (content !== null && content.includes(HOOK_MARKER)) {
114
+ // Remove the ShipSafe hook
115
+ await fs.unlink(hookPath);
116
+ // Restore backup if it exists
117
+ try {
118
+ const backup = await fs.readFile(backupPath, 'utf-8');
119
+ await fs.writeFile(hookPath, backup, { mode: 0o755 });
120
+ await fs.unlink(backupPath);
121
+ }
122
+ catch {
123
+ // No backup to restore, that's fine
124
+ }
125
+ }
126
+ }
127
+ }
128
+ export async function checkHooksInstalled(projectDir) {
129
+ const dir = projectDir ?? process.cwd();
130
+ let hooksDir;
131
+ try {
132
+ hooksDir = await getHooksDir(dir);
133
+ }
134
+ catch {
135
+ return false;
136
+ }
137
+ const preCommitPath = path.join(hooksDir, 'pre-commit');
138
+ try {
139
+ const content = await fs.readFile(preCommitPath, 'utf-8');
140
+ return content.includes(HOOK_MARKER);
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ }
146
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../../src/hooks/installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function startMcpServer(): Promise<void>;
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAWA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA8HpD"}
@@ -0,0 +1,96 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import { handleScan } from './tools/scan.js';
5
+ import { handleStatus } from './tools/status.js';
6
+ import { handleGraphQuery } from './tools/graph-query.js';
7
+ import { handleProductionErrors } from './tools/production-errors.js';
8
+ import { handleFix } from './tools/fix.js';
9
+ import { handleVerifyResolution } from './tools/verify-resolution.js';
10
+ import { handleCheckPackage } from './tools/check-package.js';
11
+ export async function startMcpServer() {
12
+ const server = new McpServer({
13
+ name: 'shipsafe',
14
+ version: '0.1.0',
15
+ });
16
+ // Register shipsafe_scan tool
17
+ server.tool('shipsafe_scan', 'Run security scan on the current project. Checks for vulnerabilities, hardcoded secrets, and dependency CVEs.', {
18
+ scope: z.string().optional().describe('Scan scope: staged (default), all, or file:<path>'),
19
+ fix: z.boolean().optional().describe('Attempt auto-fix (default: false)'),
20
+ }, async (params) => {
21
+ const result = await handleScan(params);
22
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
23
+ });
24
+ // Register shipsafe_status tool
25
+ server.tool('shipsafe_status', 'Get current project security status, hook state, and scanner availability.', async () => {
26
+ const result = await handleStatus();
27
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
28
+ });
29
+ // Register shipsafe_graph_query tool
30
+ server.tool('shipsafe_graph_query', 'Query the project knowledge graph for callers, callees, attack paths, blast radius, or missing auth chains.', {
31
+ query_type: z.enum(['callers', 'callees', 'data_flow', 'attack_paths', 'blast_radius', 'auth_chain'])
32
+ .describe('Type of graph query to run'),
33
+ target: z.string().optional()
34
+ .describe('Target function name (required for callers, callees, data_flow, blast_radius)'),
35
+ depth: z.number().optional()
36
+ .describe('Max traversal depth (default: 3 for callers/callees, 5 for data_flow)'),
37
+ }, async (params) => {
38
+ const result = await handleGraphQuery({
39
+ query_type: params.query_type,
40
+ target: params.target,
41
+ depth: params.depth,
42
+ });
43
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
44
+ });
45
+ // Register shipsafe_production_errors tool
46
+ server.tool('shipsafe_production_errors', 'Fetch queued production errors for this project. Returns errors with stack traces, root causes, and suggested fixes.', {
47
+ severity: z.enum(['all', 'critical', 'high', 'medium', 'low']).optional()
48
+ .describe('Filter by severity (default: all)'),
49
+ status: z.enum(['open', 'resolved', 'all']).optional()
50
+ .describe('Filter by status (default: open)'),
51
+ }, async (params) => {
52
+ const result = await handleProductionErrors({
53
+ severity: params.severity,
54
+ status: params.status,
55
+ });
56
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
57
+ });
58
+ // Register shipsafe_fix tool
59
+ server.tool('shipsafe_fix', 'Apply a fix for a scan finding. For hardcoded secrets, moves them to .env automatically. For other findings, returns the suggestion.', {
60
+ finding_id: z.string().describe('The ID of the finding to fix (from shipsafe_scan results)'),
61
+ strategy: z.enum(['suggested', 'custom']).optional()
62
+ .describe('Fix strategy: suggested (default) or custom'),
63
+ }, async (params) => {
64
+ const result = await handleFix({
65
+ finding_id: params.finding_id,
66
+ strategy: params.strategy,
67
+ });
68
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
69
+ });
70
+ // Register shipsafe_verify_resolution tool
71
+ server.tool('shipsafe_verify_resolution', 'Check if a production error has been resolved or is still recurring.', {
72
+ error_id: z.string().describe('The ID of the production error to check'),
73
+ }, async (params) => {
74
+ const result = await handleVerifyResolution({
75
+ error_id: params.error_id,
76
+ });
77
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
78
+ });
79
+ // Register shipsafe_check_package tool
80
+ server.tool('shipsafe_check_package', 'Vet an npm package before installing. Checks for typosquatting, maintenance status, license compatibility, and known vulnerabilities.', {
81
+ name: z.string().describe('Package name to check'),
82
+ version: z.string().optional().describe('Specific version to check (default: latest)'),
83
+ registry: z.enum(['npm', 'pip', 'cargo']).optional()
84
+ .describe('Package registry (default: npm, only npm currently supported)'),
85
+ }, async (params) => {
86
+ const result = await handleCheckPackage({
87
+ name: params.name,
88
+ version: params.version,
89
+ registry: params.registry,
90
+ });
91
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
92
+ });
93
+ const transport = new StdioServerTransport();
94
+ await server.connect(transport);
95
+ }
96
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export interface CheckPackageParams {
2
+ name: string;
3
+ version?: string;
4
+ registry?: 'npm' | 'pip' | 'cargo';
5
+ }
6
+ export interface CheckPackageResult {
7
+ name: string;
8
+ version: string;
9
+ safe: boolean;
10
+ cves: string[];
11
+ license: string;
12
+ license_compatible: boolean;
13
+ maintained: boolean;
14
+ last_publish: string;
15
+ typosquat_warning: boolean;
16
+ recommendation: string;
17
+ }
18
+ /**
19
+ * Compute Levenshtein edit distance between two strings.
20
+ */
21
+ export declare function editDistance(a: string, b: string): number;
22
+ /**
23
+ * Check if a package name looks like a typosquat of a popular package.
24
+ */
25
+ export declare function checkTyposquat(name: string): {
26
+ isTyposquat: boolean;
27
+ similarTo?: string;
28
+ };
29
+ export declare function handleCheckPackage(params: CheckPackageParams): Promise<CheckPackageResult>;
30
+ //# sourceMappingURL=check-package.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-package.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/check-package.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAoCD;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAuBzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAYzF;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,kBAAkB,CAAC,CAoJ7B"}