Skip to content

Commit 9579a5b

Browse files
committed
gitleaks
1 parent 5900777 commit 9579a5b

File tree

8 files changed

+193
-7
lines changed

8 files changed

+193
-7
lines changed

agents/gitleaks/.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# dependencies
2+
node_modules
3+
.pnp
4+
.pnp.js
5+
.yarn*
6+
pnpm-lock.yaml
7+
8+
# aixyz
9+
.aixyz
10+
11+
# local env files
12+
.env.local

agents/gitleaks/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM oven/bun:1 AS build
2+
WORKDIR /app
3+
COPY . .
4+
RUN bun install
5+
RUN bun run build
6+
7+
FROM oven/bun:1-slim
8+
WORKDIR /app
9+
COPY --from=build /app/agents/gitleaks/.aixyz/output .aixyz/output
10+
CMD ["bun", ".aixyz/output/server.js"]

agents/gitleaks/aixyz.config.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { AixyzConfig } from "aixyz/config";
2+
3+
const config: AixyzConfig = {
4+
name: "Gitleaks",
5+
description:
6+
"Scan code and text for exposed credentials, API keys, tokens, and other secrets. Get detailed findings with rule ID, redacted match, file location, and tags.",
7+
version: "1.1.0",
8+
url: process.env.RAILWAY_PUBLIC_DOMAIN ? `https://${process.env.RAILWAY_PUBLIC_DOMAIN}` : undefined,
9+
x402: {
10+
payTo: "0x0799872E07EA7a63c79357694504FE66EDfE4a0A",
11+
network: process.env.NODE_ENV === "production" ? "eip155:8453" : "eip155:84532",
12+
},
13+
skills: [
14+
{
15+
id: "scan",
16+
name: "Secret Scanner",
17+
description:
18+
"Scan code, configuration files, or text for exposed credentials such as API keys, tokens, private keys, and database connection strings.",
19+
tags: ["security", "secrets", "credentials", "scanning"],
20+
examples: [
21+
"Scan this code for leaked secrets: const apiKey = 'AKIAIOSFODNN7EXAMPLE'",
22+
"Check this config file for exposed credentials",
23+
"Analyze my .env file for any hardcoded secrets that should be rotated",
24+
],
25+
},
26+
],
27+
};
28+
29+
export default config;

agents/gitleaks/app/erc-8004.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { ERC8004Registration } from "aixyz/erc-8004";
2+
3+
const metadata: ERC8004Registration = {
4+
/**
5+
* `aixyz erc-8004 register` will write to this field.
6+
*/
7+
registrations: [],
8+
supportedTrust: ["reputation"],
9+
};
10+
11+
/**
12+
* Declaring `export default metadata` will expose ERC-8004 metadata at:
13+
*
14+
* GET /_aixyz/erc-8004.json
15+
*/
16+
export default metadata;

agents/gitleaks/app/tools/scan.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { tool } from "ai";
2+
import type { Accepts } from "aixyz/accepts";
3+
import { z } from "zod";
4+
5+
const GITLEAKS_BASE_URL = process.env.GITLEAKS_BASE_URL ?? "http://gitleaks.railway.internal:8080";
6+
7+
interface GitleaksFinding {
8+
Description: string;
9+
StartLine: number;
10+
EndLine: number;
11+
StartColumn: number;
12+
EndColumn: number;
13+
Match: string;
14+
Secret: string;
15+
File: string;
16+
SymlinkFile: string;
17+
Commit: string;
18+
Entropy: number;
19+
Author: string;
20+
Email: string;
21+
Date: string;
22+
Message: string;
23+
Tags: string[];
24+
RuleID: string;
25+
Fingerprint: string;
26+
}
27+
28+
function redact(value: string): string {
29+
if (value.length <= 8) {
30+
return value.slice(0, 2) + "*".repeat(value.length - 2);
31+
}
32+
const visibleStart = Math.min(4, Math.floor(value.length * 0.15));
33+
const visibleEnd = Math.min(4, Math.floor(value.length * 0.15));
34+
return value.slice(0, visibleStart) + "*".repeat(value.length - visibleStart - visibleEnd) + value.slice(-visibleEnd);
35+
}
36+
37+
export const accepts: Accepts = {
38+
scheme: "exact",
39+
price: "$0.01",
40+
};
41+
42+
export default tool({
43+
description:
44+
"Scan text or code for exposed credentials, API keys, tokens, private keys, and other secrets. Returns findings with rule ID, description, redacted secret, line number, and tags.",
45+
inputSchema: z.object({
46+
text: z.string().describe("The code or text content to scan for exposed secrets."),
47+
}),
48+
execute: async ({ text }) => {
49+
const response = await fetch(`${GITLEAKS_BASE_URL}/scan`, {
50+
method: "POST",
51+
headers: { "Content-Type": "application/json" },
52+
body: JSON.stringify({ content: text }),
53+
});
54+
55+
if (!response.ok) {
56+
const errorText = await response.text();
57+
throw new Error(`Scan service error (${response.status}): ${errorText}`);
58+
}
59+
60+
const raw: GitleaksFinding[] = await response.json();
61+
62+
const findings = raw.map((f) => ({
63+
ruleId: f.RuleID,
64+
description: f.Description,
65+
match: redact(f.Secret || f.Match),
66+
startLine: f.StartLine,
67+
endLine: f.EndLine,
68+
tags: f.Tags ?? [],
69+
}));
70+
71+
return {
72+
totalFindings: findings.length,
73+
findings,
74+
};
75+
},
76+
});

agents/gitleaks/package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "gitleaks",
3+
"private": true,
4+
"scripts": {
5+
"build": "aixyz build",
6+
"dev": "aixyz dev"
7+
},
8+
"dependencies": {
9+
"ai": "^6",
10+
"aixyz": "0.31.0",
11+
"zod": "^4"
12+
},
13+
"devDependencies": {
14+
"@types/bun": "^1",
15+
"typescript": "^5",
16+
"use-agently": "latest"
17+
}
18+
}

agents/gitleaks/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ESNext",
4+
"module": "NodeNext",
5+
"moduleResolution": "bundler",
6+
"strict": true,
7+
"skipLibCheck": true,
8+
"types": ["bun"]
9+
}
10+
}

bun.lock

Lines changed: 22 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)