diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..e76ed59 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,39 @@ + +title = "Custom GitHub Agent Security Scan" + +[extend] +useDefault = true + +[[rules]] +id = "company-api-key" +description = "Company API Key" +regex = '''COMP_[A-Z0-9]{40}''' +keywords = ["COMP_"] +tags = ["company", "api"] + +[[rules]] +id = "slack-token" +description = "Slack API Token" +regex = '''xox[baprs]-[0-9]{10,12}-[0-9]{10,12}-[a-zA-Z0-9]{24}''' +keywords = ["xoxb", "xoxp", "xoxa", "xoxr", "xoxs"] +tags = ["slack", "token"] + +[[rules]] +id = "stripe-secret" +description = "Stripe Secret Key" +regex = '''sk_(test|live)_[0-9a-zA-Z]{24}''' +keywords = ["sk_test", "sk_live"] +tags = ["stripe", "secret"] + +[[rules]] +id = "supabase-key" +description = "Supabase API Key" +regex = '''[a-zA-Z0-9_-]{20,200}''' +path = '''.*supabase.*''' +keywords = ["supabase"] +tags = ["supabase", "api"] + +# Allowlist for false positives +[[rules.allowlists]] +description = "Allow test files" +path = '''.*test.*''' diff --git a/README.md b/README.md new file mode 100644 index 0000000..50ba435 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# cost-crawler + +Codebase analyzer for identifying model/provider selection mechanisms and cost implications in LLM-integrated projects. + +## Stack + +- TypeScript (Node.js) +- `@babel/parser` + `@babel/traverse` for AST analysis +- `commander` for CLI +- Jest for tests + +## Install + +```bash +npm install +``` + +## Build + +```bash +npm run build +``` + +## Test + +```bash +npm test +``` + +## CLI Usage + +```bash +# Analyze a codebase using default patterns (src/**/*.ts, src/**/*.js) +node bin/cost-crawler.js analyze + +# Specify custom glob patterns +node bin/cost-crawler.js analyze -p "**/*.ts" "**/*.js" + +# Output as JSON +node bin/cost-crawler.js analyze -o json + +# Write report to file +node bin/cost-crawler.js analyze -f report.json +``` + +### Example + +```bash +node bin/cost-crawler.js analyze /path/to/project -o json -f results.json +``` diff --git a/jest-setup.js b/jest-setup.js new file mode 100644 index 0000000..7aca48f --- /dev/null +++ b/jest-setup.js @@ -0,0 +1,11 @@ +// Suppress localStorage initialization in jest-environment-node +Object.defineProperty(global, 'localStorage', { + value: { + getItem: () => null, + setItem: () => {}, + removeItem: () => {}, + clear: () => {}, + }, + writable: true, + configurable: true, +}); diff --git a/jest.config.js b/jest.config.js index 7349239..e1f6355 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,13 +6,8 @@ module.exports = { testMatch: ['**/tests/**/*.test.ts'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts'], + setupFiles: ['/jest-setup.js'], testEnvironmentOptions: { - autoUseFakeTimers: false, - localstoragePath: path.join(__dirname, '.jest-localStorage'), - }, - globals: { - 'ts-jest': { - isolatedModules: true, - }, + localstoragePath: path.join(__dirname, '.jest-tmp-localStorage'), }, }; diff --git a/package-lock.json b/package-lock.json index 18b7202..495dd42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,9 @@ "dotenv": "^16.0.0", "glob": "^10.3.0" }, + "bin": { + "cost-crawler": "bin/cost-crawler.js" + }, "devDependencies": { "@types/jest": "^29.5.0", "@types/node": "^20.0.0",