@bouncesecurity/aghast 0.0.13
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/LICENSE +661 -0
- package/README.md +111 -0
- package/config/prompts/generic-instructions.md +56 -0
- package/config/prompts/test-cheaper-instructions.md +57 -0
- package/dist/check-library.d.ts +87 -0
- package/dist/check-library.d.ts.map +1 -0
- package/dist/check-library.js +374 -0
- package/dist/check-library.js.map +1 -0
- package/dist/claude-code-provider.d.ts +26 -0
- package/dist/claude-code-provider.d.ts.map +1 -0
- package/dist/claude-code-provider.js +247 -0
- package/dist/claude-code-provider.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -0
- package/dist/colors.d.ts +7 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +18 -0
- package/dist/colors.js.map +1 -0
- package/dist/error-codes.d.ts +42 -0
- package/dist/error-codes.d.ts.map +1 -0
- package/dist/error-codes.js +60 -0
- package/dist/error-codes.js.map +1 -0
- package/dist/formatters/index.d.ts +10 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +23 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/json-formatter.d.ts +11 -0
- package/dist/formatters/json-formatter.d.ts.map +1 -0
- package/dist/formatters/json-formatter.js +11 -0
- package/dist/formatters/json-formatter.js.map +1 -0
- package/dist/formatters/sarif-formatter.d.ts +18 -0
- package/dist/formatters/sarif-formatter.d.ts.map +1 -0
- package/dist/formatters/sarif-formatter.js +103 -0
- package/dist/formatters/sarif-formatter.js.map +1 -0
- package/dist/formatters/types.d.ts +11 -0
- package/dist/formatters/types.d.ts.map +1 -0
- package/dist/formatters/types.js +6 -0
- package/dist/formatters/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +406 -0
- package/dist/index.js.map +1 -0
- package/dist/logging.d.ts +26 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +79 -0
- package/dist/logging.js.map +1 -0
- package/dist/mock-ai-provider.d.ts +18 -0
- package/dist/mock-ai-provider.d.ts.map +1 -0
- package/dist/mock-ai-provider.js +28 -0
- package/dist/mock-ai-provider.js.map +1 -0
- package/dist/new-check.d.ts +13 -0
- package/dist/new-check.d.ts.map +1 -0
- package/dist/new-check.js +405 -0
- package/dist/new-check.js.map +1 -0
- package/dist/prompt-template.d.ts +12 -0
- package/dist/prompt-template.d.ts.map +1 -0
- package/dist/prompt-template.js +35 -0
- package/dist/prompt-template.js.map +1 -0
- package/dist/provider-registry.d.ts +15 -0
- package/dist/provider-registry.d.ts.map +1 -0
- package/dist/provider-registry.js +27 -0
- package/dist/provider-registry.js.map +1 -0
- package/dist/repository-analyzer.d.ts +68 -0
- package/dist/repository-analyzer.d.ts.map +1 -0
- package/dist/repository-analyzer.js +230 -0
- package/dist/repository-analyzer.js.map +1 -0
- package/dist/response-parser.d.ts +12 -0
- package/dist/response-parser.d.ts.map +1 -0
- package/dist/response-parser.js +109 -0
- package/dist/response-parser.js.map +1 -0
- package/dist/runtime-config.d.ts +15 -0
- package/dist/runtime-config.d.ts.map +1 -0
- package/dist/runtime-config.js +73 -0
- package/dist/runtime-config.js.map +1 -0
- package/dist/sarif-parser.d.ts +20 -0
- package/dist/sarif-parser.d.ts.map +1 -0
- package/dist/sarif-parser.js +76 -0
- package/dist/sarif-parser.js.map +1 -0
- package/dist/scan-runner.d.ts +29 -0
- package/dist/scan-runner.d.ts.map +1 -0
- package/dist/scan-runner.js +559 -0
- package/dist/scan-runner.js.map +1 -0
- package/dist/semgrep-runner.d.ts +25 -0
- package/dist/semgrep-runner.d.ts.map +1 -0
- package/dist/semgrep-runner.js +100 -0
- package/dist/semgrep-runner.js.map +1 -0
- package/dist/snippet-extractor.d.ts +25 -0
- package/dist/snippet-extractor.d.ts.map +1 -0
- package/dist/snippet-extractor.js +56 -0
- package/dist/snippet-extractor.js.map +1 -0
- package/dist/types.d.ts +206 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider Registry.
|
|
3
|
+
*
|
|
4
|
+
* Allows providers to be registered by name and resolved at runtime.
|
|
5
|
+
* Adding a new provider requires only implementing the AIProvider interface
|
|
6
|
+
* and calling registerProvider.
|
|
7
|
+
*/
|
|
8
|
+
import type { AIProvider } from './types.js';
|
|
9
|
+
export type ProviderFactory = () => AIProvider;
|
|
10
|
+
export declare function registerProvider(name: string, factory: ProviderFactory): void;
|
|
11
|
+
export declare function createProviderByName(name: string): AIProvider;
|
|
12
|
+
export declare function getProviderNames(): string[];
|
|
13
|
+
/** Default provider name — used as fallback in CLI when AI_PROVIDER / runtime config not set. */
|
|
14
|
+
export declare const DEFAULT_PROVIDER_NAME = "claude-code";
|
|
15
|
+
//# sourceMappingURL=provider-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.d.ts","sourceRoot":"","sources":["../src/provider-registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC;AAI/C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAE7E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAQ7D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,iGAAiG;AACjG,eAAO,MAAM,qBAAqB,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider Registry.
|
|
3
|
+
*
|
|
4
|
+
* Allows providers to be registered by name and resolved at runtime.
|
|
5
|
+
* Adding a new provider requires only implementing the AIProvider interface
|
|
6
|
+
* and calling registerProvider.
|
|
7
|
+
*/
|
|
8
|
+
import { ClaudeCodeProvider } from './claude-code-provider.js';
|
|
9
|
+
const registry = new Map();
|
|
10
|
+
export function registerProvider(name, factory) {
|
|
11
|
+
registry.set(name, factory);
|
|
12
|
+
}
|
|
13
|
+
export function createProviderByName(name) {
|
|
14
|
+
const factory = registry.get(name);
|
|
15
|
+
if (!factory) {
|
|
16
|
+
throw new Error(`Unknown AI provider "${name}". Supported providers: ${[...registry.keys()].join(', ')}`);
|
|
17
|
+
}
|
|
18
|
+
return factory();
|
|
19
|
+
}
|
|
20
|
+
export function getProviderNames() {
|
|
21
|
+
return [...registry.keys()];
|
|
22
|
+
}
|
|
23
|
+
/** Default provider name — used as fallback in CLI when AI_PROVIDER / runtime config not set. */
|
|
24
|
+
export const DEFAULT_PROVIDER_NAME = 'claude-code';
|
|
25
|
+
// Register built-in providers
|
|
26
|
+
registerProvider(DEFAULT_PROVIDER_NAME, () => new ClaudeCodeProvider());
|
|
27
|
+
//# sourceMappingURL=provider-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../src/provider-registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAI/D,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEpD,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAAwB;IACrE,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,wBAAwB,IAAI,2BAA2B,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC;AAEnD,8BAA8B;AAC9B,gBAAgB,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Analyzer component.
|
|
3
|
+
* Extracts Git metadata from target repositories.
|
|
4
|
+
* Implements spec Appendix B.4.
|
|
5
|
+
*/
|
|
6
|
+
import type { RepositoryInfo } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Result of repository analysis including branch and commit.
|
|
9
|
+
*/
|
|
10
|
+
export interface RepositoryAnalysis {
|
|
11
|
+
repository: RepositoryInfo;
|
|
12
|
+
branch?: string;
|
|
13
|
+
commit?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Check if a directory is a Git repository.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isGitRepository(path: string): Promise<boolean>;
|
|
19
|
+
/**
|
|
20
|
+
* Get the Git remote URL for 'origin'.
|
|
21
|
+
* Returns undefined if no origin remote is configured.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getRemoteUrl(path: string): Promise<string | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* Get the current Git branch name.
|
|
26
|
+
* Returns undefined if HEAD is detached or not on a branch.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getCurrentBranch(path: string): Promise<string | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Get the current commit hash (full SHA).
|
|
31
|
+
*/
|
|
32
|
+
export declare function getCommitHash(path: string): Promise<string | undefined>;
|
|
33
|
+
/**
|
|
34
|
+
* Sanitize a Git URL by removing embedded credentials.
|
|
35
|
+
* Handles URLs like:
|
|
36
|
+
* - https://user:pass@github.com/org/repo
|
|
37
|
+
* - ssh://user:pass@github.com/org/repo
|
|
38
|
+
*/
|
|
39
|
+
export declare function sanitizeUrl(url: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Normalize a Git URL by removing the .git suffix and cleaning up the URL.
|
|
42
|
+
* Extracts org/repo path for common providers.
|
|
43
|
+
*/
|
|
44
|
+
export declare function normalizeUrl(url: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Parse a Git URL and extract the organization and repository name.
|
|
47
|
+
* Returns { org, repo } or undefined if parsing fails.
|
|
48
|
+
*
|
|
49
|
+
* For URLs with nested paths (e.g., org/suborg/repo), returns the last
|
|
50
|
+
* two path segments as org and repo respectively.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseGitUrl(url: string): {
|
|
53
|
+
org: string;
|
|
54
|
+
repo: string;
|
|
55
|
+
} | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Normalize a repository path/URL for matching purposes.
|
|
58
|
+
* 1. Remove .git suffix (via normalizeUrl)
|
|
59
|
+
* 2. Replace backslashes with forward slashes
|
|
60
|
+
* 3. Convert to lowercase
|
|
61
|
+
*/
|
|
62
|
+
export declare function normalizeRepoPath(repoPathOrUrl: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Analyze a repository and extract all Git metadata.
|
|
65
|
+
* For non-Git directories, returns a RepositoryInfo with isGitRepository: false.
|
|
66
|
+
*/
|
|
67
|
+
export declare function analyzeRepository(path: string): Promise<RepositoryAnalysis>;
|
|
68
|
+
//# sourceMappingURL=repository-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-analyzer.d.ts","sourceRoot":"","sources":["../src/repository-analyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,cAAc,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQpE;AA8BD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO5E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO7B;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmC/C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAchD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CA6BlF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,kBAAkB,CAAC,CAqD7B"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Analyzer component.
|
|
3
|
+
* Extracts Git metadata from target repositories.
|
|
4
|
+
* Implements spec Appendix B.4.
|
|
5
|
+
*/
|
|
6
|
+
import { execFile } from 'node:child_process';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
import { access, constants } from 'node:fs/promises';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { logDebug, logProgress } from './logging.js';
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
const TAG = 'repo-analyzer';
|
|
13
|
+
/**
|
|
14
|
+
* Check if a directory is a Git repository.
|
|
15
|
+
*/
|
|
16
|
+
export async function isGitRepository(path) {
|
|
17
|
+
try {
|
|
18
|
+
const gitDir = join(path, '.git');
|
|
19
|
+
await access(gitDir, constants.F_OK);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Execute a git command in the specified directory.
|
|
28
|
+
* Returns the trimmed stdout, or undefined if the command fails.
|
|
29
|
+
*
|
|
30
|
+
* Note: 10 second timeout is sufficient for most git metadata commands.
|
|
31
|
+
* Commands like rev-parse are fast even on large repositories.
|
|
32
|
+
*
|
|
33
|
+
* Security: Uses execFile with argument array to prevent command injection.
|
|
34
|
+
* The args parameter is split on whitespace and passed as separate arguments.
|
|
35
|
+
*/
|
|
36
|
+
async function gitCommand(path, args) {
|
|
37
|
+
try {
|
|
38
|
+
const argArray = args.split(/\s+/).filter(Boolean);
|
|
39
|
+
const { stdout } = await execFileAsync('git', argArray, {
|
|
40
|
+
cwd: path,
|
|
41
|
+
timeout: 10000,
|
|
42
|
+
});
|
|
43
|
+
return stdout.trim();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
47
|
+
logDebug(TAG, `Git command failed (git ${args}): ${message}`);
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the Git remote URL for 'origin'.
|
|
53
|
+
* Returns undefined if no origin remote is configured.
|
|
54
|
+
*/
|
|
55
|
+
export async function getRemoteUrl(path) {
|
|
56
|
+
const url = await gitCommand(path, 'config --get remote.origin.url');
|
|
57
|
+
if (!url) {
|
|
58
|
+
logDebug(TAG, 'No origin remote configured');
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return url;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get the current Git branch name.
|
|
65
|
+
* Returns undefined if HEAD is detached or not on a branch.
|
|
66
|
+
*/
|
|
67
|
+
export async function getCurrentBranch(path) {
|
|
68
|
+
const branch = await gitCommand(path, 'rev-parse --abbrev-ref HEAD');
|
|
69
|
+
if (!branch || branch === 'HEAD') {
|
|
70
|
+
logDebug(TAG, 'Detached HEAD or no branch');
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
return branch;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get the current commit hash (full SHA).
|
|
77
|
+
*/
|
|
78
|
+
export async function getCommitHash(path) {
|
|
79
|
+
return gitCommand(path, 'rev-parse HEAD');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Sanitize a Git URL by removing embedded credentials.
|
|
83
|
+
* Handles URLs like:
|
|
84
|
+
* - https://user:pass@github.com/org/repo
|
|
85
|
+
* - ssh://user:pass@github.com/org/repo
|
|
86
|
+
*/
|
|
87
|
+
export function sanitizeUrl(url) {
|
|
88
|
+
try {
|
|
89
|
+
// Handle standard SSH URLs (git@github.com:org/repo.git)
|
|
90
|
+
// These use key-based auth, not embedded credentials
|
|
91
|
+
if (url.startsWith('git@') && !url.includes('://')) {
|
|
92
|
+
return url;
|
|
93
|
+
}
|
|
94
|
+
// Handle other non-URL SSH formats (user@host:path without protocol)
|
|
95
|
+
// But only if there's no colon before the @ (which would indicate credentials)
|
|
96
|
+
if (url.includes('@') && !url.includes('://')) {
|
|
97
|
+
const atIndex = url.indexOf('@');
|
|
98
|
+
const colonBeforeAt = url.lastIndexOf(':', atIndex);
|
|
99
|
+
// If there's a colon before @, it's likely credentials (user:pass@host)
|
|
100
|
+
// Standard SSH format is user@host:path (colon after @)
|
|
101
|
+
if (colonBeforeAt === -1) {
|
|
102
|
+
return url;
|
|
103
|
+
}
|
|
104
|
+
// Has credentials in SSH-style URL, strip them
|
|
105
|
+
return url.slice(atIndex + 1);
|
|
106
|
+
}
|
|
107
|
+
// Handle URLs with protocol (https://, ssh://, etc.)
|
|
108
|
+
const parsed = new URL(url);
|
|
109
|
+
if (parsed.username || parsed.password) {
|
|
110
|
+
parsed.username = '';
|
|
111
|
+
parsed.password = '';
|
|
112
|
+
return parsed.toString();
|
|
113
|
+
}
|
|
114
|
+
return url;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// If URL parsing fails, try a regex-based approach
|
|
118
|
+
// Matches protocol://user:pass@host or protocol://user@host
|
|
119
|
+
return url.replace(/^([a-z]+:\/\/)[^@]+@/, '$1');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Normalize a Git URL by removing the .git suffix and cleaning up the URL.
|
|
124
|
+
* Extracts org/repo path for common providers.
|
|
125
|
+
*/
|
|
126
|
+
export function normalizeUrl(url) {
|
|
127
|
+
let normalized = url;
|
|
128
|
+
// Remove trailing .git suffix
|
|
129
|
+
if (normalized.endsWith('.git')) {
|
|
130
|
+
normalized = normalized.slice(0, -4);
|
|
131
|
+
}
|
|
132
|
+
// Remove trailing slashes
|
|
133
|
+
while (normalized.endsWith('/')) {
|
|
134
|
+
normalized = normalized.slice(0, -1);
|
|
135
|
+
}
|
|
136
|
+
return normalized;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Parse a Git URL and extract the organization and repository name.
|
|
140
|
+
* Returns { org, repo } or undefined if parsing fails.
|
|
141
|
+
*
|
|
142
|
+
* For URLs with nested paths (e.g., org/suborg/repo), returns the last
|
|
143
|
+
* two path segments as org and repo respectively.
|
|
144
|
+
*/
|
|
145
|
+
export function parseGitUrl(url) {
|
|
146
|
+
const normalized = normalizeUrl(sanitizeUrl(url));
|
|
147
|
+
// SSH format: git@github.com:org/repo or git@github.com:org/suborg/repo
|
|
148
|
+
// Match host:path where path contains at least one slash
|
|
149
|
+
const sshMatch = normalized.match(/^git@[^:]+:(.+)$/);
|
|
150
|
+
if (sshMatch) {
|
|
151
|
+
const pathPart = sshMatch[1];
|
|
152
|
+
const segments = pathPart.split('/').filter(Boolean);
|
|
153
|
+
if (segments.length >= 2) {
|
|
154
|
+
// Take last segment as repo, second-to-last as org
|
|
155
|
+
return { org: segments[segments.length - 2], repo: segments[segments.length - 1] };
|
|
156
|
+
}
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
// HTTPS format: https://github.com/org/repo
|
|
160
|
+
try {
|
|
161
|
+
const parsed = new URL(normalized);
|
|
162
|
+
const pathParts = parsed.pathname.split('/').filter(Boolean);
|
|
163
|
+
if (pathParts.length >= 2) {
|
|
164
|
+
// Take last segment as repo, second-to-last as org
|
|
165
|
+
return { org: pathParts[pathParts.length - 2], repo: pathParts[pathParts.length - 1] };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Not a valid URL
|
|
170
|
+
}
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Normalize a repository path/URL for matching purposes.
|
|
175
|
+
* 1. Remove .git suffix (via normalizeUrl)
|
|
176
|
+
* 2. Replace backslashes with forward slashes
|
|
177
|
+
* 3. Convert to lowercase
|
|
178
|
+
*/
|
|
179
|
+
export function normalizeRepoPath(repoPathOrUrl) {
|
|
180
|
+
let normalized = normalizeUrl(repoPathOrUrl);
|
|
181
|
+
normalized = normalized.replace(/\\/g, '/');
|
|
182
|
+
normalized = normalized.toLowerCase();
|
|
183
|
+
return normalized;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Analyze a repository and extract all Git metadata.
|
|
187
|
+
* For non-Git directories, returns a RepositoryInfo with isGitRepository: false.
|
|
188
|
+
*/
|
|
189
|
+
export async function analyzeRepository(path) {
|
|
190
|
+
const isGit = await isGitRepository(path);
|
|
191
|
+
if (!isGit) {
|
|
192
|
+
logProgress(TAG, `Warning: ${path} is not a Git repository`);
|
|
193
|
+
return {
|
|
194
|
+
repository: {
|
|
195
|
+
path,
|
|
196
|
+
isGitRepository: false,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
logDebug(TAG, `Analyzing Git repository: ${path}`);
|
|
201
|
+
const [rawRemoteUrl, branch, commit] = await Promise.all([
|
|
202
|
+
getRemoteUrl(path),
|
|
203
|
+
getCurrentBranch(path),
|
|
204
|
+
getCommitHash(path),
|
|
205
|
+
]);
|
|
206
|
+
// Sanitize and normalize the remote URL
|
|
207
|
+
const remoteUrl = rawRemoteUrl
|
|
208
|
+
? normalizeUrl(sanitizeUrl(rawRemoteUrl))
|
|
209
|
+
: undefined;
|
|
210
|
+
const repository = {
|
|
211
|
+
path,
|
|
212
|
+
isGitRepository: true,
|
|
213
|
+
};
|
|
214
|
+
if (remoteUrl) {
|
|
215
|
+
repository.remoteUrl = remoteUrl;
|
|
216
|
+
}
|
|
217
|
+
if (branch) {
|
|
218
|
+
repository.branch = branch;
|
|
219
|
+
}
|
|
220
|
+
if (commit) {
|
|
221
|
+
repository.commit = commit;
|
|
222
|
+
}
|
|
223
|
+
logDebug(TAG, `Repository analysis complete: branch=${branch ?? 'none'}, commit=${commit?.slice(0, 7) ?? 'none'}`);
|
|
224
|
+
return {
|
|
225
|
+
repository,
|
|
226
|
+
branch,
|
|
227
|
+
commit,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=repository-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-analyzer.js","sourceRoot":"","sources":["../src/repository-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI response parser.
|
|
3
|
+
* Parses raw AI responses into CheckResponse format (spec Appendix A.3b).
|
|
4
|
+
* Handles malformed JSON, missing fields, and edge cases.
|
|
5
|
+
*/
|
|
6
|
+
import type { CheckResponse } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Attempt to parse a raw AI response string into a CheckResponse.
|
|
9
|
+
* Returns undefined if the response is not valid JSON or lacks the expected structure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseAIResponse(raw: string): CheckResponse | undefined;
|
|
12
|
+
//# sourceMappingURL=response-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-parser.d.ts","sourceRoot":"","sources":["../src/response-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAyB,MAAM,YAAY,CAAC;AAKvE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAgHtE"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI response parser.
|
|
3
|
+
* Parses raw AI responses into CheckResponse format (spec Appendix A.3b).
|
|
4
|
+
* Handles malformed JSON, missing fields, and edge cases.
|
|
5
|
+
*/
|
|
6
|
+
import { logDebug } from './logging.js';
|
|
7
|
+
const TAG = 'parser';
|
|
8
|
+
/**
|
|
9
|
+
* Attempt to parse a raw AI response string into a CheckResponse.
|
|
10
|
+
* Returns undefined if the response is not valid JSON or lacks the expected structure.
|
|
11
|
+
*/
|
|
12
|
+
export function parseAIResponse(raw) {
|
|
13
|
+
logDebug(TAG, `Parsing response: ${raw.length} chars`);
|
|
14
|
+
const tryParse = (text) => {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(text);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
// 1) Direct parse
|
|
23
|
+
let parsed = tryParse(raw);
|
|
24
|
+
// 2) If that fails, look for a fenced code block (```json ... ```)
|
|
25
|
+
if (parsed === undefined) {
|
|
26
|
+
const fence = raw.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
27
|
+
if (fence?.[1]) {
|
|
28
|
+
logDebug(TAG, 'Trying fenced code block extraction');
|
|
29
|
+
parsed = tryParse(fence[1]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// 3) If still failing, grab the first balanced-looking JSON object
|
|
33
|
+
if (parsed === undefined) {
|
|
34
|
+
const firstBrace = raw.indexOf('{');
|
|
35
|
+
const lastBrace = raw.lastIndexOf('}');
|
|
36
|
+
if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
|
|
37
|
+
logDebug(TAG, 'Trying brace extraction');
|
|
38
|
+
const slice = raw.slice(firstBrace, lastBrace + 1);
|
|
39
|
+
parsed = tryParse(slice);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (parsed === undefined) {
|
|
43
|
+
logDebug(TAG, 'All parse strategies failed');
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const obj = parsed;
|
|
50
|
+
if (!Array.isArray(obj.issues)) {
|
|
51
|
+
logDebug(TAG, `Missing issues array, keys: ${Object.keys(obj).join(', ')}`);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const issues = [];
|
|
55
|
+
for (const item of obj.issues) {
|
|
56
|
+
if (typeof item !== 'object' || item === null) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const issue = item;
|
|
60
|
+
// Required fields: file, description, startLine, endLine (per spec A.3)
|
|
61
|
+
if (typeof issue.file !== 'string' || typeof issue.description !== 'string') {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Line numbers are required - skip issues without valid line numbers
|
|
65
|
+
if (typeof issue.startLine !== 'number' || typeof issue.endLine !== 'number') {
|
|
66
|
+
logDebug(TAG, `Skipping issue missing required line numbers: ${issue.file}`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const aiIssue = {
|
|
70
|
+
file: issue.file,
|
|
71
|
+
startLine: issue.startLine,
|
|
72
|
+
endLine: issue.endLine,
|
|
73
|
+
description: issue.description,
|
|
74
|
+
};
|
|
75
|
+
// Parse optional dataFlow array
|
|
76
|
+
if (Array.isArray(issue.dataFlow)) {
|
|
77
|
+
const validSteps = [];
|
|
78
|
+
for (const step of issue.dataFlow) {
|
|
79
|
+
if (typeof step === 'object' && step !== null &&
|
|
80
|
+
typeof step.file === 'string' &&
|
|
81
|
+
typeof step.lineNumber === 'number' &&
|
|
82
|
+
typeof step.label === 'string') {
|
|
83
|
+
validSteps.push({
|
|
84
|
+
file: step.file,
|
|
85
|
+
lineNumber: step.lineNumber,
|
|
86
|
+
label: step.label,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (validSteps.length > 0) {
|
|
91
|
+
aiIssue.dataFlow = validSteps;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
issues.push(aiIssue);
|
|
95
|
+
}
|
|
96
|
+
logDebug(TAG, `Parsed ${issues.length} issues`);
|
|
97
|
+
const response = { issues };
|
|
98
|
+
if (obj.flagged === true) {
|
|
99
|
+
response.flagged = true;
|
|
100
|
+
}
|
|
101
|
+
if (typeof obj.summary === 'string') {
|
|
102
|
+
response.summary = obj.summary;
|
|
103
|
+
}
|
|
104
|
+
if (typeof obj.analysisNotes === 'string') {
|
|
105
|
+
response.analysisNotes = obj.analysisNotes;
|
|
106
|
+
}
|
|
107
|
+
return response;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=response-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-parser.js","sourceRoot":"","sources":["../src/response-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration loader.
|
|
3
|
+
* Loads runtime-config.json from the config directory to override AI provider and reporting settings.
|
|
4
|
+
* Spec Section 8.1 & Appendix C.10.
|
|
5
|
+
*/
|
|
6
|
+
import type { RuntimeConfig } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Load runtime configuration from file.
|
|
9
|
+
* @param configDir - Directory containing runtime-config.json.
|
|
10
|
+
* @param explicitPath - Explicit path to the runtime config file (from --runtime-config CLI flag).
|
|
11
|
+
* @returns Parsed RuntimeConfig object, or empty object if file absent
|
|
12
|
+
* @throws Error if file exists but contains invalid JSON
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadRuntimeConfig(configDir: string, explicitPath?: string): Promise<RuntimeConfig>;
|
|
15
|
+
//# sourceMappingURL=runtime-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-config.d.ts","sourceRoot":"","sources":["../src/runtime-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA2DxG"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime configuration loader.
|
|
3
|
+
* Loads runtime-config.json from the config directory to override AI provider and reporting settings.
|
|
4
|
+
* Spec Section 8.1 & Appendix C.10.
|
|
5
|
+
*/
|
|
6
|
+
import { readFile } from 'node:fs/promises';
|
|
7
|
+
import { resolve } from 'node:path';
|
|
8
|
+
/**
|
|
9
|
+
* Load runtime configuration from file.
|
|
10
|
+
* @param configDir - Directory containing runtime-config.json.
|
|
11
|
+
* @param explicitPath - Explicit path to the runtime config file (from --runtime-config CLI flag).
|
|
12
|
+
* @returns Parsed RuntimeConfig object, or empty object if file absent
|
|
13
|
+
* @throws Error if file exists but contains invalid JSON
|
|
14
|
+
*/
|
|
15
|
+
export async function loadRuntimeConfig(configDir, explicitPath) {
|
|
16
|
+
const pathToLoad = explicitPath ?? resolve(configDir, 'runtime-config.json');
|
|
17
|
+
let content;
|
|
18
|
+
try {
|
|
19
|
+
content = await readFile(pathToLoad, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
// File absent: silently return defaults
|
|
23
|
+
if (err.code === 'ENOENT') {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
// File exists but may have invalid JSON
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = JSON.parse(content);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new Error(`Invalid JSON in runtime config file: ${pathToLoad}`);
|
|
35
|
+
}
|
|
36
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
37
|
+
throw new Error(`Runtime config file "${pathToLoad}" must contain a JSON object`);
|
|
38
|
+
}
|
|
39
|
+
// Validate field types
|
|
40
|
+
const obj = parsed;
|
|
41
|
+
if (obj.aiProvider !== undefined) {
|
|
42
|
+
if (typeof obj.aiProvider !== 'object' || obj.aiProvider === null || Array.isArray(obj.aiProvider)) {
|
|
43
|
+
throw new Error(`Runtime config "${pathToLoad}": "aiProvider" must be an object`);
|
|
44
|
+
}
|
|
45
|
+
const ap = obj.aiProvider;
|
|
46
|
+
if (ap.name !== undefined && typeof ap.name !== 'string') {
|
|
47
|
+
throw new Error(`Runtime config "${pathToLoad}": "aiProvider.name" must be a string`);
|
|
48
|
+
}
|
|
49
|
+
if (ap.model !== undefined && typeof ap.model !== 'string') {
|
|
50
|
+
throw new Error(`Runtime config "${pathToLoad}": "aiProvider.model" must be a string`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (obj.reporting !== undefined) {
|
|
54
|
+
if (typeof obj.reporting !== 'object' || obj.reporting === null || Array.isArray(obj.reporting)) {
|
|
55
|
+
throw new Error(`Runtime config "${pathToLoad}": "reporting" must be an object`);
|
|
56
|
+
}
|
|
57
|
+
const rpt = obj.reporting;
|
|
58
|
+
if (rpt.outputDirectory !== undefined && typeof rpt.outputDirectory !== 'string') {
|
|
59
|
+
throw new Error(`Runtime config "${pathToLoad}": "reporting.outputDirectory" must be a string`);
|
|
60
|
+
}
|
|
61
|
+
if (rpt.outputFormat !== undefined && typeof rpt.outputFormat !== 'string') {
|
|
62
|
+
throw new Error(`Runtime config "${pathToLoad}": "reporting.outputFormat" must be a string`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (obj.genericPrompt !== undefined && typeof obj.genericPrompt !== 'string') {
|
|
66
|
+
throw new Error(`Runtime config "${pathToLoad}": "genericPrompt" must be a string`);
|
|
67
|
+
}
|
|
68
|
+
if (obj.failOnCheckFailure !== undefined && typeof obj.failOnCheckFailure !== 'boolean') {
|
|
69
|
+
throw new Error(`Runtime config "${pathToLoad}": "failOnCheckFailure" must be a boolean`);
|
|
70
|
+
}
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=runtime-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-config.js","sourceRoot":"","sources":["../src/runtime-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SARIF 2.1.0 parser for Semgrep output.
|
|
3
|
+
* Extracts CheckTarget[] from SARIF results.
|
|
4
|
+
*/
|
|
5
|
+
import type { CheckTarget } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Parse SARIF 2.1.0 JSON content into CheckTarget[].
|
|
8
|
+
* Skips results with missing location fields.
|
|
9
|
+
* Throws on invalid JSON or missing SARIF structure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseSARIF(sarifContent: string): CheckTarget[];
|
|
12
|
+
/**
|
|
13
|
+
* Deduplicate targets by file:startLine:endLine key.
|
|
14
|
+
*/
|
|
15
|
+
export declare function deduplicateTargets(targets: CheckTarget[]): CheckTarget[];
|
|
16
|
+
/**
|
|
17
|
+
* Limit the number of targets to a maximum.
|
|
18
|
+
*/
|
|
19
|
+
export declare function limitTargets(targets: CheckTarget[], maxTargets: number): CheckTarget[];
|
|
20
|
+
//# sourceMappingURL=sarif-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif-parser.d.ts","sourceRoot":"","sources":["../src/sarif-parser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAyB9C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,WAAW,EAAE,CAsD9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAaxE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE,CAEtF"}
|