@cognium/mcp-server 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 (88) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/dist/cache.d.ts +46 -0
  5. package/dist/cache.d.ts.map +1 -0
  6. package/dist/cache.js +106 -0
  7. package/dist/cache.js.map +1 -0
  8. package/dist/index.d.ts +12 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +24 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/resources/catalogs.d.ts +63 -0
  13. package/dist/resources/catalogs.d.ts.map +1 -0
  14. package/dist/resources/catalogs.js +92 -0
  15. package/dist/resources/catalogs.js.map +1 -0
  16. package/dist/resources/index.d.ts +13 -0
  17. package/dist/resources/index.d.ts.map +1 -0
  18. package/dist/resources/index.js +94 -0
  19. package/dist/resources/index.js.map +1 -0
  20. package/dist/resources/schema.d.ts +81 -0
  21. package/dist/resources/schema.d.ts.map +1 -0
  22. package/dist/resources/schema.js +63 -0
  23. package/dist/resources/schema.js.map +1 -0
  24. package/dist/server.d.ts +12 -0
  25. package/dist/server.d.ts.map +1 -0
  26. package/dist/server.js +41 -0
  27. package/dist/server.js.map +1 -0
  28. package/dist/tools/attack-surface-summary.d.ts +24 -0
  29. package/dist/tools/attack-surface-summary.d.ts.map +1 -0
  30. package/dist/tools/attack-surface-summary.js +116 -0
  31. package/dist/tools/attack-surface-summary.js.map +1 -0
  32. package/dist/tools/check-sanitizer.d.ts +29 -0
  33. package/dist/tools/check-sanitizer.d.ts.map +1 -0
  34. package/dist/tools/check-sanitizer.js +82 -0
  35. package/dist/tools/check-sanitizer.js.map +1 -0
  36. package/dist/tools/describe-sink.d.ts +22 -0
  37. package/dist/tools/describe-sink.d.ts.map +1 -0
  38. package/dist/tools/describe-sink.js +47 -0
  39. package/dist/tools/describe-sink.js.map +1 -0
  40. package/dist/tools/describe-source.d.ts +27 -0
  41. package/dist/tools/describe-source.d.ts.map +1 -0
  42. package/dist/tools/describe-source.js +64 -0
  43. package/dist/tools/describe-source.js.map +1 -0
  44. package/dist/tools/explain-finding.d.ts +23 -0
  45. package/dist/tools/explain-finding.d.ts.map +1 -0
  46. package/dist/tools/explain-finding.js +65 -0
  47. package/dist/tools/explain-finding.js.map +1 -0
  48. package/dist/tools/find-similar.d.ts +34 -0
  49. package/dist/tools/find-similar.d.ts.map +1 -0
  50. package/dist/tools/find-similar.js +107 -0
  51. package/dist/tools/find-similar.js.map +1 -0
  52. package/dist/tools/list-entry-points.d.ts +22 -0
  53. package/dist/tools/list-entry-points.d.ts.map +1 -0
  54. package/dist/tools/list-entry-points.js +71 -0
  55. package/dist/tools/list-entry-points.js.map +1 -0
  56. package/dist/tools/list-reachable-sinks.d.ts +33 -0
  57. package/dist/tools/list-reachable-sinks.d.ts.map +1 -0
  58. package/dist/tools/list-reachable-sinks.js +116 -0
  59. package/dist/tools/list-reachable-sinks.js.map +1 -0
  60. package/dist/tools/refresh.d.ts +21 -0
  61. package/dist/tools/refresh.d.ts.map +1 -0
  62. package/dist/tools/refresh.js +39 -0
  63. package/dist/tools/refresh.js.map +1 -0
  64. package/dist/tools/scan.d.ts +42 -0
  65. package/dist/tools/scan.d.ts.map +1 -0
  66. package/dist/tools/scan.js +197 -0
  67. package/dist/tools/scan.js.map +1 -0
  68. package/dist/tools/taint-paths.d.ts +31 -0
  69. package/dist/tools/taint-paths.d.ts.map +1 -0
  70. package/dist/tools/taint-paths.js +55 -0
  71. package/dist/tools/taint-paths.js.map +1 -0
  72. package/dist/tools/types.d.ts +22 -0
  73. package/dist/tools/types.d.ts.map +1 -0
  74. package/dist/tools/types.js +17 -0
  75. package/dist/tools/types.js.map +1 -0
  76. package/dist/util/files.d.ts +33 -0
  77. package/dist/util/files.d.ts.map +1 -0
  78. package/dist/util/files.js +184 -0
  79. package/dist/util/files.js.map +1 -0
  80. package/dist/util/serialize.d.ts +29 -0
  81. package/dist/util/serialize.d.ts.map +1 -0
  82. package/dist/util/serialize.js +42 -0
  83. package/dist/util/serialize.js.map +1 -0
  84. package/dist/util/wasm.d.ts +9 -0
  85. package/dist/util/wasm.d.ts.map +1 -0
  86. package/dist/util/wasm.js +37 -0
  87. package/dist/util/wasm.js.map +1 -0
  88. package/package.json +75 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * `cognium://sast-finding-schema` resource — the canonical shape of a
3
+ * `SastFinding` object as produced by circle-ir. Callers can consume
4
+ * this at prompt-construction time to know which fields to expect.
5
+ *
6
+ * We hand-write the schema here (rather than reflecting one from the
7
+ * TypeScript type) so it remains stable and hand-tuned for LLM
8
+ * consumption.
9
+ */
10
+ export declare const SAST_FINDING_SCHEMA: {
11
+ readonly $schema: "http://json-schema.org/draft-07/schema#";
12
+ readonly $id: "cognium://sast-finding-schema";
13
+ readonly title: "SastFinding";
14
+ readonly description: string;
15
+ readonly type: "object";
16
+ readonly required: readonly ["id", "pass", "category", "rule_id", "cwe", "severity", "level", "message", "file", "line"];
17
+ readonly properties: {
18
+ readonly id: {
19
+ readonly type: "string";
20
+ readonly description: "Stable per-run id, formed as `<pass>-<file>-<line>` (or with a discriminator suffix when multiple findings collide).";
21
+ };
22
+ readonly pass: {
23
+ readonly type: "string";
24
+ readonly description: "Name of the AnalysisPass that emitted the finding.";
25
+ };
26
+ readonly category: {
27
+ readonly type: "string";
28
+ readonly enum: readonly ["security", "reliability", "performance", "maintainability", "architecture"];
29
+ readonly description: "High-level PassCategory. Filters use this axis first.";
30
+ };
31
+ readonly rule_id: {
32
+ readonly type: "string";
33
+ readonly description: "Canonical rule identifier — matches `docs/PASSES.md rule_id` column.";
34
+ };
35
+ readonly cwe: {
36
+ readonly type: "string";
37
+ readonly description: "CWE identifier (e.g. `CWE-89`) for security findings; empty for quality findings.";
38
+ };
39
+ readonly severity: {
40
+ readonly type: "string";
41
+ readonly enum: readonly ["critical", "high", "medium", "low"];
42
+ readonly description: "Coarse severity bucket. Not linear — critical is >2x high in practice.";
43
+ };
44
+ readonly level: {
45
+ readonly type: "string";
46
+ readonly enum: readonly ["error", "warning", "note", "none"];
47
+ readonly description: "SARIF level for the finding. Maps into SARIF `result.level`.";
48
+ };
49
+ readonly message: {
50
+ readonly type: "string";
51
+ readonly description: "Human-readable one-line description.";
52
+ };
53
+ readonly file: {
54
+ readonly type: "string";
55
+ readonly description: "Repository-relative path (may be absolute when scanned outside a repo).";
56
+ };
57
+ readonly line: {
58
+ readonly type: "integer";
59
+ readonly description: "1-indexed line number.";
60
+ };
61
+ readonly column: {
62
+ readonly type: "integer";
63
+ readonly description: "1-indexed column, when available.";
64
+ };
65
+ readonly snippet: {
66
+ readonly type: "string";
67
+ readonly description: "Short source excerpt (may be truncated to 2KB by this server).";
68
+ };
69
+ readonly fix: {
70
+ readonly type: "string";
71
+ readonly description: "Suggested remediation code / instruction.";
72
+ };
73
+ readonly metadata: {
74
+ readonly type: "object";
75
+ readonly description: "Free-form per-rule metadata (e.g. sink type, confidence, taint path id).";
76
+ readonly additionalProperties: true;
77
+ };
78
+ };
79
+ readonly additionalProperties: true;
80
+ };
81
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/resources/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDtB,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `cognium://sast-finding-schema` resource — the canonical shape of a
3
+ * `SastFinding` object as produced by circle-ir. Callers can consume
4
+ * this at prompt-construction time to know which fields to expect.
5
+ *
6
+ * We hand-write the schema here (rather than reflecting one from the
7
+ * TypeScript type) so it remains stable and hand-tuned for LLM
8
+ * consumption.
9
+ */
10
+ export const SAST_FINDING_SCHEMA = {
11
+ $schema: 'http://json-schema.org/draft-07/schema#',
12
+ $id: 'cognium://sast-finding-schema',
13
+ title: 'SastFinding',
14
+ description: 'Deterministic security or quality finding emitted by circle-ir. Every field is populated by ' +
15
+ 'static analysis; there is no LLM in the emission path.',
16
+ type: 'object',
17
+ required: [
18
+ 'id',
19
+ 'pass',
20
+ 'category',
21
+ 'rule_id',
22
+ 'cwe',
23
+ 'severity',
24
+ 'level',
25
+ 'message',
26
+ 'file',
27
+ 'line',
28
+ ],
29
+ properties: {
30
+ id: { type: 'string', description: 'Stable per-run id, formed as `<pass>-<file>-<line>` (or with a discriminator suffix when multiple findings collide).' },
31
+ pass: { type: 'string', description: 'Name of the AnalysisPass that emitted the finding.' },
32
+ category: {
33
+ type: 'string',
34
+ enum: ['security', 'reliability', 'performance', 'maintainability', 'architecture'],
35
+ description: 'High-level PassCategory. Filters use this axis first.',
36
+ },
37
+ rule_id: { type: 'string', description: 'Canonical rule identifier — matches `docs/PASSES.md rule_id` column.' },
38
+ cwe: { type: 'string', description: 'CWE identifier (e.g. `CWE-89`) for security findings; empty for quality findings.' },
39
+ severity: {
40
+ type: 'string',
41
+ enum: ['critical', 'high', 'medium', 'low'],
42
+ description: 'Coarse severity bucket. Not linear — critical is >2x high in practice.',
43
+ },
44
+ level: {
45
+ type: 'string',
46
+ enum: ['error', 'warning', 'note', 'none'],
47
+ description: 'SARIF level for the finding. Maps into SARIF `result.level`.',
48
+ },
49
+ message: { type: 'string', description: 'Human-readable one-line description.' },
50
+ file: { type: 'string', description: 'Repository-relative path (may be absolute when scanned outside a repo).' },
51
+ line: { type: 'integer', description: '1-indexed line number.' },
52
+ column: { type: 'integer', description: '1-indexed column, when available.' },
53
+ snippet: { type: 'string', description: 'Short source excerpt (may be truncated to 2KB by this server).' },
54
+ fix: { type: 'string', description: 'Suggested remediation code / instruction.' },
55
+ metadata: {
56
+ type: 'object',
57
+ description: 'Free-form per-rule metadata (e.g. sink type, confidence, taint path id).',
58
+ additionalProperties: true,
59
+ },
60
+ },
61
+ additionalProperties: true,
62
+ };
63
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/resources/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,OAAO,EAAE,yCAAyC;IAClD,GAAG,EAAE,+BAA+B;IACpC,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,8FAA8F;QAC9F,wDAAwD;IAC1D,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE;QACR,IAAI;QACJ,MAAM;QACN,UAAU;QACV,SAAS;QACT,KAAK;QACL,UAAU;QACV,OAAO;QACP,SAAS;QACT,MAAM;QACN,MAAM;KACP;IACD,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sHAAsH,EAAE;QAC3J,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oDAAoD,EAAE;QAC3F,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,CAAC;YACnF,WAAW,EAAE,uDAAuD;SACrE;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sEAAsE,EAAE;QAChH,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mFAAmF,EAAE;QACzH,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;YAC3C,WAAW,EAAE,wEAAwE;SACtF;QACD,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC;YAC1C,WAAW,EAAE,8DAA8D;SAC5E;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sCAAsC,EAAE;QAChF,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yEAAyE,EAAE;QAChH,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,wBAAwB,EAAE;QAChE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,mCAAmC,EAAE;QAC7E,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gEAAgE,EAAE;QAC1G,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2CAA2C,EAAE;QACjF,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,0EAA0E;YACvF,oBAAoB,EAAE,IAAI;SAC3B;KACF;IACD,oBAAoB,EAAE,IAAI;CAClB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * MCP server assembly — register every tool + resource on a fresh
3
+ * `McpServer` instance. Transport wiring lives in `index.ts` so this
4
+ * module stays transport-agnostic and testable.
5
+ */
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ export interface BuildServerOptions {
8
+ /** Override the default cache capacity (3 projects). */
9
+ cacheCapacity?: number;
10
+ }
11
+ export declare function buildServer(opts?: BuildServerOptions): McpServer;
12
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiBpE,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,SAAS,CAwBpE"}
package/dist/server.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * MCP server assembly — register every tool + resource on a fresh
3
+ * `McpServer` instance. Transport wiring lives in `index.ts` so this
4
+ * module stays transport-agnostic and testable.
5
+ */
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { ProjectCache } from './cache.js';
8
+ import { registerResources } from './resources/index.js';
9
+ import { scanConfig, makeScanHandler } from './tools/scan.js';
10
+ import { explainFindingConfig, makeExplainFindingHandler } from './tools/explain-finding.js';
11
+ import { taintPathsConfig, makeTaintPathsHandler } from './tools/taint-paths.js';
12
+ import { listEntryPointsConfig, makeListEntryPointsHandler } from './tools/list-entry-points.js';
13
+ import { checkSanitizerConfig, makeCheckSanitizerHandler } from './tools/check-sanitizer.js';
14
+ import { describeSinkConfig, makeDescribeSinkHandler } from './tools/describe-sink.js';
15
+ import { describeSourceConfig, makeDescribeSourceHandler } from './tools/describe-source.js';
16
+ import { attackSurfaceSummaryConfig, makeAttackSurfaceSummaryHandler } from './tools/attack-surface-summary.js';
17
+ import { listReachableSinksConfig, makeListReachableSinksHandler } from './tools/list-reachable-sinks.js';
18
+ import { findSimilarConfig, makeFindSimilarHandler } from './tools/find-similar.js';
19
+ import { refreshConfig, makeRefreshHandler } from './tools/refresh.js';
20
+ export function buildServer(opts = {}) {
21
+ const cache = new ProjectCache(opts.cacheCapacity ?? 3);
22
+ const ctx = { cache };
23
+ const server = new McpServer({
24
+ name: 'cognium-mcp-server',
25
+ version: '0.1.0',
26
+ });
27
+ server.registerTool('scan', scanConfig, makeScanHandler(ctx));
28
+ server.registerTool('explain_finding', explainFindingConfig, makeExplainFindingHandler(ctx));
29
+ server.registerTool('taint_paths', taintPathsConfig, makeTaintPathsHandler(ctx));
30
+ server.registerTool('list_entry_points', listEntryPointsConfig, makeListEntryPointsHandler(ctx));
31
+ server.registerTool('check_sanitizer', checkSanitizerConfig, makeCheckSanitizerHandler(ctx));
32
+ server.registerTool('describe_sink', describeSinkConfig, makeDescribeSinkHandler(ctx));
33
+ server.registerTool('describe_source', describeSourceConfig, makeDescribeSourceHandler(ctx));
34
+ server.registerTool('attack_surface_summary', attackSurfaceSummaryConfig, makeAttackSurfaceSummaryHandler(ctx));
35
+ server.registerTool('list_reachable_sinks', listReachableSinksConfig, makeListReachableSinksHandler(ctx));
36
+ server.registerTool('find_similar', findSimilarConfig, makeFindSimilarHandler(ctx));
37
+ server.registerTool('refresh', refreshConfig, makeRefreshHandler(ctx));
38
+ registerResources(server);
39
+ return server;
40
+ }
41
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACjG,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC7F,OAAO,EAAE,0BAA0B,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AAChH,OAAO,EAAE,wBAAwB,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAC1G,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAOvE,MAAM,UAAU,WAAW,CAAC,OAA2B,EAAE;IACvD,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,GAAG,GAAgB,EAAE,KAAK,EAAE,CAAC;IAEnC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,GAAG,CAAU,CAAC,CAAC;IACvE,MAAM,CAAC,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,yBAAyB,CAAC,GAAG,CAAU,CAAC,CAAC;IACtG,MAAM,CAAC,YAAY,CAAC,aAAa,EAAE,gBAAgB,EAAE,qBAAqB,CAAC,GAAG,CAAU,CAAC,CAAC;IAC1F,MAAM,CAAC,YAAY,CAAC,mBAAmB,EAAE,qBAAqB,EAAE,0BAA0B,CAAC,GAAG,CAAU,CAAC,CAAC;IAC1G,MAAM,CAAC,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,yBAAyB,CAAC,GAAG,CAAU,CAAC,CAAC;IACtG,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,kBAAkB,EAAE,uBAAuB,CAAC,GAAG,CAAU,CAAC,CAAC;IAChG,MAAM,CAAC,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,yBAAyB,CAAC,GAAG,CAAU,CAAC,CAAC;IACtG,MAAM,CAAC,YAAY,CAAC,wBAAwB,EAAE,0BAA0B,EAAE,+BAA+B,CAAC,GAAG,CAAU,CAAC,CAAC;IACzH,MAAM,CAAC,YAAY,CAAC,sBAAsB,EAAE,wBAAwB,EAAE,6BAA6B,CAAC,GAAG,CAAU,CAAC,CAAC;IACnH,MAAM,CAAC,YAAY,CAAC,cAAc,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,GAAG,CAAU,CAAC,CAAC;IAC7F,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,kBAAkB,CAAC,GAAG,CAAU,CAAC,CAAC;IAEhF,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE1B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `attack_surface_summary` tool — high-level roll-up of a project's
3
+ * attack surface: entry points × sinks × cross-file taint paths, grouped
4
+ * by language / framework / vulnerability category.
5
+ *
6
+ * Designed as the first tool an LLM calls when a user asks
7
+ * "give me a security posture summary of this codebase".
8
+ */
9
+ import { z } from 'zod';
10
+ import type { ToolContext, ToolResult } from './types.js';
11
+ export declare const attackSurfaceSummaryInputShape: {
12
+ readonly project_root: z.ZodString;
13
+ };
14
+ export declare const attackSurfaceSummaryConfig: {
15
+ readonly title: "Attack surface summary";
16
+ readonly description: string;
17
+ readonly inputSchema: {
18
+ readonly project_root: z.ZodString;
19
+ };
20
+ };
21
+ export declare function makeAttackSurfaceSummaryHandler(ctx: ToolContext): (args: {
22
+ project_root: string;
23
+ }) => Promise<ToolResult>;
24
+ //# sourceMappingURL=attack-surface-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attack-surface-summary.d.ts","sourceRoot":"","sources":["../../src/tools/attack-surface-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG1D,eAAO,MAAM,8BAA8B;;CAEjC,CAAC;AAEX,eAAO,MAAM,0BAA0B;;;;;;CAO7B,CAAC;AAEX,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,WAAW,IAChD,MAAM;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,UAAU,CAAC,CAkGnE"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * `attack_surface_summary` tool — high-level roll-up of a project's
3
+ * attack surface: entry points × sinks × cross-file taint paths, grouped
4
+ * by language / framework / vulnerability category.
5
+ *
6
+ * Designed as the first tool an LLM calls when a user asks
7
+ * "give me a security posture summary of this codebase".
8
+ */
9
+ import { z } from 'zod';
10
+ import { resolve } from 'path';
11
+ import { RULE_DEFINITIONS } from 'circle-ir';
12
+ import { textResult } from './types.js';
13
+ export const attackSurfaceSummaryInputShape = {
14
+ project_root: z.string().describe('Absolute path to the project root.'),
15
+ };
16
+ export const attackSurfaceSummaryConfig = {
17
+ title: 'Attack surface summary',
18
+ description: 'Compute a security-posture roll-up for a previously-scanned project: total entry points by framework, ' +
19
+ 'total sinks by category, cross-file taint-path totals per sink type, and the top 10 files by finding ' +
20
+ 'count. Use as the entry-level tool for "what does this codebase look like from a security angle?"',
21
+ inputSchema: attackSurfaceSummaryInputShape,
22
+ };
23
+ export function makeAttackSurfaceSummaryHandler(ctx) {
24
+ return async (args) => {
25
+ const root = resolve(args.project_root);
26
+ const { analysis, cacheHit } = await ctx.cache.getOrCompute(root, {});
27
+ const entryPointsByFramework = {};
28
+ const entryPointsByLanguage = {};
29
+ const entryPointsByKind = {};
30
+ const sinksByType = {};
31
+ const sinksByLanguage = {};
32
+ const findingsBySeverity = {};
33
+ const findingsByCategory = {};
34
+ const findingsByRule = {};
35
+ const findingsPerFile = {};
36
+ let totalEntryPoints = 0;
37
+ let totalSinks = 0;
38
+ let totalSources = 0;
39
+ let totalFindings = 0;
40
+ for (const fa of analysis.files) {
41
+ const lang = fa.analysis.meta.language;
42
+ for (const reg of fa.analysis.runtime_registrations ?? []) {
43
+ totalEntryPoints++;
44
+ const fw = reg.framework ?? 'unknown';
45
+ entryPointsByFramework[fw] = (entryPointsByFramework[fw] ?? 0) + 1;
46
+ entryPointsByLanguage[lang] = (entryPointsByLanguage[lang] ?? 0) + 1;
47
+ entryPointsByKind[reg.kind] = (entryPointsByKind[reg.kind] ?? 0) + 1;
48
+ }
49
+ for (const s of fa.analysis.taint?.sinks ?? []) {
50
+ totalSinks++;
51
+ sinksByType[s.type] = (sinksByType[s.type] ?? 0) + 1;
52
+ sinksByLanguage[lang] = (sinksByLanguage[lang] ?? 0) + 1;
53
+ }
54
+ totalSources += fa.analysis.taint?.sources?.length ?? 0;
55
+ for (const f of fa.analysis.findings ?? []) {
56
+ totalFindings++;
57
+ findingsBySeverity[f.severity] = (findingsBySeverity[f.severity] ?? 0) + 1;
58
+ findingsByCategory[f.category] = (findingsByCategory[f.category] ?? 0) + 1;
59
+ findingsByRule[f.rule_id] = (findingsByRule[f.rule_id] ?? 0) + 1;
60
+ findingsPerFile[fa.file] = (findingsPerFile[fa.file] ?? 0) + 1;
61
+ }
62
+ }
63
+ const crossFilePathsBySinkType = {};
64
+ for (const p of analysis.taint_paths) {
65
+ const t = p.sink.type ?? 'unknown';
66
+ crossFilePathsBySinkType[t] = (crossFilePathsBySinkType[t] ?? 0) + 1;
67
+ }
68
+ const topFiles = Object.entries(findingsPerFile)
69
+ .sort((a, b) => b[1] - a[1])
70
+ .slice(0, 10)
71
+ .map(([file, count]) => ({ file, findings: count }));
72
+ const criticalCategories = Object.entries(sinksByType)
73
+ .map(([type, count]) => ({
74
+ type,
75
+ count,
76
+ cwe: RULE_DEFINITIONS[type]?.cwe,
77
+ severity: RULE_DEFINITIONS[type]?.severityLevel,
78
+ }))
79
+ .sort((a, b) => b.count - a.count);
80
+ return textResult({
81
+ projectRoot: root,
82
+ cacheHit,
83
+ totals: {
84
+ files: analysis.files.length,
85
+ entryPoints: totalEntryPoints,
86
+ sources: totalSources,
87
+ sinks: totalSinks,
88
+ findings: totalFindings,
89
+ crossFileTaintPaths: analysis.taint_paths.length,
90
+ },
91
+ entryPoints: {
92
+ byFramework: entryPointsByFramework,
93
+ byLanguage: entryPointsByLanguage,
94
+ byKind: entryPointsByKind,
95
+ },
96
+ sinks: {
97
+ byLanguage: sinksByLanguage,
98
+ byCategory: criticalCategories,
99
+ },
100
+ findings: {
101
+ bySeverity: findingsBySeverity,
102
+ byCategory: findingsByCategory,
103
+ topRules: Object.entries(findingsByRule)
104
+ .sort((a, b) => b[1] - a[1])
105
+ .slice(0, 10)
106
+ .map(([rule_id, count]) => ({ rule_id, count })),
107
+ },
108
+ crossFileTaintPaths: {
109
+ bySinkType: crossFilePathsBySinkType,
110
+ budgetExceeded: analysis.cross_file_budget_exceeded === true,
111
+ },
112
+ topFiles,
113
+ });
114
+ };
115
+ }
116
+ //# sourceMappingURL=attack-surface-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attack-surface-summary.js","sourceRoot":"","sources":["../../src/tools/attack-surface-summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `check_sanitizer` tool — deterministic yes/no on whether a function
3
+ * qualifies as a sanitizer for a given sink type.
4
+ *
5
+ * Grounds LLM claims like "this is escaped by DOMPurify.sanitize" —
6
+ * replaces guesswork with a lookup against circle-ir's YAML catalog.
7
+ */
8
+ import { z } from 'zod';
9
+ import type { ToolContext, ToolResult } from './types.js';
10
+ export declare const checkSanitizerInputShape: {
11
+ readonly function_qualified_name: z.ZodString;
12
+ readonly sink_type: z.ZodString;
13
+ readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
14
+ };
15
+ export declare const checkSanitizerConfig: {
16
+ readonly title: "Check sanitizer validity";
17
+ readonly description: string;
18
+ readonly inputSchema: {
19
+ readonly function_qualified_name: z.ZodString;
20
+ readonly sink_type: z.ZodString;
21
+ readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
22
+ };
23
+ };
24
+ export declare function makeCheckSanitizerHandler(_ctx: ToolContext): (args: {
25
+ function_qualified_name: string;
26
+ sink_type: string;
27
+ language?: string;
28
+ }) => Promise<ToolResult>;
29
+ //# sourceMappingURL=check-sanitizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-sanitizer.d.ts","sourceRoot":"","sources":["../../src/tools/check-sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,wBAAwB;;;;CAQ3B,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;;;CAOvB,CAAC;AAEX,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,WAAW,IAC3C,MAAM;IAClB,uBAAuB,EAAE,MAAM,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAG,OAAO,CAAC,UAAU,CAAC,CA0DxB"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * `check_sanitizer` tool — deterministic yes/no on whether a function
3
+ * qualifies as a sanitizer for a given sink type.
4
+ *
5
+ * Grounds LLM claims like "this is escaped by DOMPurify.sanitize" —
6
+ * replaces guesswork with a lookup against circle-ir's YAML catalog.
7
+ */
8
+ import { z } from 'zod';
9
+ import { textResult } from './types.js';
10
+ import { loadSanitizerCatalog } from '../resources/catalogs.js';
11
+ export const checkSanitizerInputShape = {
12
+ function_qualified_name: z.string()
13
+ .describe('Fully-qualified function name to check, e.g. "org.owasp.esapi.Encoder.encodeForHTML" or "DOMPurify.sanitize".'),
14
+ sink_type: z.string()
15
+ .describe('Sink category to check against, e.g. "xss", "sql_injection", "command_injection".'),
16
+ language: z.enum(['java', 'javascript', 'typescript', 'python', 'go', 'rust', 'bash', 'html'])
17
+ .optional()
18
+ .describe('Language of the function under check. When omitted, all languages are searched.'),
19
+ };
20
+ export const checkSanitizerConfig = {
21
+ title: 'Check sanitizer validity',
22
+ description: 'Verify that a function is a recognized sanitizer for a specific sink type in circle-ir\'s YAML ' +
23
+ 'catalog. Returns { isValidSanitizer, matchedRule, notes, alternatives } so an LLM can ground its ' +
24
+ '"this input is safe because it was escaped" reasoning.',
25
+ inputSchema: checkSanitizerInputShape,
26
+ };
27
+ export function makeCheckSanitizerHandler(_ctx) {
28
+ return async (args) => {
29
+ const catalog = loadSanitizerCatalog();
30
+ const fq = args.function_qualified_name;
31
+ const fqLower = fq.toLowerCase();
32
+ const fqLast = fq.split(/[.:]/).pop() ?? fq;
33
+ const sinkType = args.sink_type;
34
+ const matches = catalog.filter(entry => {
35
+ // Sink type must match or entry must be typeless (applies to all).
36
+ if (entry.sinkType && entry.sinkType !== sinkType)
37
+ return false;
38
+ if (args.language && entry.language && entry.language !== args.language)
39
+ return false;
40
+ const patternMatches = entry.patterns.some(pat => {
41
+ const p = pat.toLowerCase();
42
+ return p === fqLower
43
+ || fqLower.endsWith('.' + p)
44
+ || fqLower.endsWith(':' + p)
45
+ || fqLast.toLowerCase() === p;
46
+ });
47
+ return patternMatches;
48
+ });
49
+ if (matches.length === 0) {
50
+ // Suggest alternatives from the catalog for this sink.
51
+ const alternatives = catalog
52
+ .filter(e => (!args.language || !e.language || e.language === args.language) && (!e.sinkType || e.sinkType === sinkType))
53
+ .flatMap(e => e.patterns)
54
+ .slice(0, 20);
55
+ return textResult({
56
+ isValidSanitizer: false,
57
+ function: fq,
58
+ sink_type: sinkType,
59
+ language: args.language ?? 'any',
60
+ notes: `No sanitizer entry matches "${fq}" for sink_type "${sinkType}". This does NOT mean the function ` +
61
+ `is unsafe — it may be a project-specific wrapper. But circle-ir will not treat it as a sanitizer ` +
62
+ `during taint analysis, so a source→sink flow through it will be flagged.`,
63
+ alternatives,
64
+ });
65
+ }
66
+ return textResult({
67
+ isValidSanitizer: true,
68
+ function: fq,
69
+ sink_type: sinkType,
70
+ language: args.language ?? 'any',
71
+ matchedRules: matches.map(m => ({
72
+ pattern: m.patterns,
73
+ sinkType: m.sinkType ?? 'any',
74
+ language: m.language ?? 'any',
75
+ source: m.source,
76
+ })),
77
+ notes: 'circle-ir will treat any taint flowing through this function as sanitized for the given sink ' +
78
+ 'type. A downstream sink call will not fire.',
79
+ });
80
+ };
81
+ }
82
+ //# sourceMappingURL=check-sanitizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-sanitizer.js","sourceRoot":"","sources":["../../src/tools/check-sanitizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `describe_sink` tool — sink category metadata (CWE, remediation, sanitizers).
3
+ */
4
+ import { z } from 'zod';
5
+ import type { ToolContext, ToolResult } from './types.js';
6
+ export declare const describeSinkInputShape: {
7
+ readonly sink_type: z.ZodString;
8
+ readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
9
+ };
10
+ export declare const describeSinkConfig: {
11
+ readonly title: "Describe sink category";
12
+ readonly description: string;
13
+ readonly inputSchema: {
14
+ readonly sink_type: z.ZodString;
15
+ readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
16
+ };
17
+ };
18
+ export declare function makeDescribeSinkHandler(_ctx: ToolContext): (args: {
19
+ sink_type: string;
20
+ language?: string;
21
+ }) => Promise<ToolResult>;
22
+ //# sourceMappingURL=describe-sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-sink.d.ts","sourceRoot":"","sources":["../../src/tools/describe-sink.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,sBAAsB;;;CAMzB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;;;;;;CAOrB,CAAC;AAEX,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,WAAW,IACzC,MAAM;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,UAAU,CAAC,CA0BnF"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * `describe_sink` tool — sink category metadata (CWE, remediation, sanitizers).
3
+ */
4
+ import { z } from 'zod';
5
+ import { RULE_DEFINITIONS } from 'circle-ir';
6
+ import { textResult, errorResult } from './types.js';
7
+ import { loadSanitizerCatalog } from '../resources/catalogs.js';
8
+ export const describeSinkInputShape = {
9
+ sink_type: z.string()
10
+ .describe('Sink category, e.g. "sql_injection", "command_injection", "xss", "path_traversal".'),
11
+ language: z.enum(['java', 'javascript', 'typescript', 'python', 'go', 'rust', 'bash', 'html'])
12
+ .optional()
13
+ .describe('Restrict sanitizer suggestions to this language.'),
14
+ };
15
+ export const describeSinkConfig = {
16
+ title: 'Describe sink category',
17
+ description: 'Return canonical metadata for a taint sink category: CWE identifier, short + full description, ' +
18
+ 'recommended remediation, CVSS-like severity score, and the list of sanitizer functions that would ' +
19
+ 'neutralize the sink. Use when the LLM needs authoritative information about a vulnerability class.',
20
+ inputSchema: describeSinkInputShape,
21
+ };
22
+ export function makeDescribeSinkHandler(_ctx) {
23
+ return async (args) => {
24
+ const rule = RULE_DEFINITIONS[args.sink_type];
25
+ if (!rule) {
26
+ return errorResult(`Unknown sink_type "${args.sink_type}". Known types: ${Object.keys(RULE_DEFINITIONS).join(', ')}`);
27
+ }
28
+ const sanitizers = loadSanitizerCatalog()
29
+ .filter(e => (!e.sinkType || e.sinkType === args.sink_type)
30
+ && (!args.language || !e.language || e.language === args.language))
31
+ .flatMap(e => e.patterns);
32
+ return textResult({
33
+ sink_type: args.sink_type,
34
+ cwe: rule.cwe,
35
+ name: rule.name,
36
+ shortDescription: rule.shortDescription,
37
+ fullDescription: rule.fullDescription,
38
+ remediation: rule.remediation,
39
+ cvssScore: rule.cvssScore,
40
+ severityLevel: rule.severityLevel,
41
+ language: args.language ?? 'any',
42
+ sanitizers: [...new Set(sanitizers)].slice(0, 50),
43
+ sanitizerCount: sanitizers.length,
44
+ });
45
+ };
46
+ }
47
+ //# sourceMappingURL=describe-sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-sink.js","sourceRoot":"","sources":["../../src/tools/describe-sink.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAiB,MAAM,WAAW,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;SAClB,QAAQ,CAAC,oFAAoF,CAAC;IACjG,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;SAC3F,QAAQ,EAAE;SACV,QAAQ,CAAC,kDAAkD,CAAC;CACvD,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,KAAK,EAAE,wBAAwB;IAC/B,WAAW,EACT,iGAAiG;QACjG,oGAAoG;QACpG,oGAAoG;IACtG,WAAW,EAAE,sBAAsB;CAC3B,CAAC;AAEX,MAAM,UAAU,uBAAuB,CAAC,IAAiB;IACvD,OAAO,KAAK,EAAE,IAA8C,EAAuB,EAAE;QACnF,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,SAAqB,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,WAAW,CAChB,sBAAsB,IAAI,CAAC,SAAS,mBAAmB,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClG,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,oBAAoB,EAAE;aACtC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,SAAS,CAAC;eACtD,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,CAAC,CAAC;aACpE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAE5B,OAAO,UAAU,CAAC;YAChB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK;YAChC,UAAU,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YACjD,cAAc,EAAE,UAAU,CAAC,MAAM;SAClC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `describe_source` tool — enumerate taint-source patterns known to
3
+ * circle-ir for a given source category (e.g. `http_param`, `http_header`,
4
+ * `db_result`, `env`, `file`).
5
+ *
6
+ * Used by an LLM to answer "where would attacker-controlled data enter
7
+ * this codebase from `http_body`?" without guessing framework APIs.
8
+ */
9
+ import { z } from 'zod';
10
+ import type { ToolContext, ToolResult } from './types.js';
11
+ export declare const describeSourceInputShape: {
12
+ readonly source_type: z.ZodString;
13
+ readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
14
+ };
15
+ export declare const describeSourceConfig: {
16
+ readonly title: "Describe taint source category";
17
+ readonly description: string;
18
+ readonly inputSchema: {
19
+ readonly source_type: z.ZodString;
20
+ readonly language: z.ZodOptional<z.ZodEnum<["java", "javascript", "typescript", "python", "go", "rust", "bash", "html"]>>;
21
+ };
22
+ };
23
+ export declare function makeDescribeSourceHandler(_ctx: ToolContext): (args: {
24
+ source_type: string;
25
+ language?: string;
26
+ }) => Promise<ToolResult>;
27
+ //# sourceMappingURL=describe-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-source.d.ts","sourceRoot":"","sources":["../../src/tools/describe-source.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI1D,eAAO,MAAM,wBAAwB;;;CAM3B,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;;CAOvB,CAAC;AAEX,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,WAAW,IAC3C,MAAM;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,UAAU,CAAC,CAsCrF"}