commit c681cef2b12c1ac7533c5331e6d46b7152871e93 Author: Omega Leo Date: Wed Jun 17 16:44:04 2026 +0100 Initial implementation diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..81b856a --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: omegaleo +ko_fi: omegaleo diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..00d92bc --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,48 @@ +name: Build and Release + +on: + push: + tags: + - 'v*' + +jobs: + build-and-publish: + runs-on: ubuntu-latest + permissions: + contents: write + packages: write + + steps: + - uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Extract version from tag + id: version + run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT + + - name: Build + run: dotnet build SecretSecurity/SecretSecurity.csproj --configuration Release + + - name: Pack NuGet tool + run: > + dotnet pack SecretSecurity/SecretSecurity.csproj + --configuration Release + --no-build + -p:Version=${{ steps.version.outputs.VERSION }} + --output ./nupkg + + - name: Push to GitHub Packages + run: > + dotnet nuget push ./nupkg/*.nupkg + --api-key ${{ secrets.GITHUB_TOKEN }} + --source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: ./nupkg/*.nupkg + generate_release_notes: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e75d1d --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.svclog +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +![Ss]tyle[Cc]op.targets +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml + +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +_NCrunch* + +.vs +.vscode +.rider + +test-files/ \ No newline at end of file diff --git a/.secretsecurityignore b/.secretsecurityignore new file mode 100644 index 0000000..8abbe37 --- /dev/null +++ b/.secretsecurityignore @@ -0,0 +1,6 @@ +node_modules/ +bin/ +obj/ +*.min.js +*.lock +testfiles/ \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3a6bfbc --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Omega Leo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9dd2043 --- /dev/null +++ b/README.md @@ -0,0 +1,96 @@ +# SecretSecurity + +[![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) +[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-%E2%9D%A4-pink?logo=github)](https://github.com/sponsors/omegaleo) +[![Ko-fi](https://img.shields.io/badge/Ko--fi-Support%20me-FF5E5B?logo=ko-fi&logoColor=white)](https://ko-fi.com/omegaleo) + +A .NET CLI tool that scans staged git changes for secrets, API keys, tokens, and sensitive credentials — and blocks commits when critical findings are detected. + +## What it detects + +| Type | Examples | Severity | +|------|----------|----------| +| Provider tokens | AWS access keys (`AKIA…`), Stripe live keys (`sk_live_…`), GitHub PATs (`ghp_…`), Slack tokens | Critical | +| Private keys | RSA, EC, OpenSSH private key blocks | Critical | +| Azure connection strings | `DefaultEndpointsProtocol`, `AccountKey` | Critical | +| Explicit secret assignments | `api_key=`, `token=`, `secret:` with a value | High | +| Database connection strings | General ADO.NET, Postgres/MySQL/MongoDB/Redis URLs | High | +| Suspicious blobs | High-entropy strings in suspicious context | Warning | + +Dev-safe connections (localhost, 127.0.0.1, integrated security) are automatically ignored. + +## Installation + +Requires [.NET 10 SDK](https://dotnet.microsoft.com/download) or later. + +```bash +dotnet tool install --global SecretSecurity --add-source https://nuget.pkg.github.com/omegaleo/index.json +``` + +## Usage + +### Install the pre-commit hook + +Run once inside your repository: + +```bash +secretsecurity install +``` + +This writes a `pre-commit` hook to `.git/hooks/` that runs `secretsecurity scan` automatically on every commit. + +### Scan manually + +```bash +secretsecurity scan +``` + +Scans all currently staged changes (`git diff --cached`). Exits with code `1` if any High or Critical findings are found, blocking the commit. + +### Ignore files + +Create a `.secretsecurityignore` file in your repo root with one pattern per line: + +``` +tests/fixtures/ +mock_secrets.json +``` + +Any staged file whose path contains a listed pattern is skipped. + +## How it works + +1. Runs `git diff --cached -U0` to get only the lines you are about to commit. +2. Each added line is checked against a set of compiled regex patterns ordered by confidence. +3. Matched values are partially masked in the output (e.g. `ghp_****Ab`). +4. If any finding is High or Critical, the scan exits with code `1`, preventing the commit. + +## Building from source + +```bash +git clone https://github.com/omegaleo/SecretSecurity.git +cd SecretSecurity +dotnet build +dotnet run --project SecretSecurity -- scan +``` + +## Contributing + +Contributions are welcome! To get started: + +1. Fork the repository and create a branch from `main`. +2. Make your changes and ensure the project builds (`dotnet build`). +3. Open a pull request describing what you changed and why. + +Please open an issue first for any significant change so we can discuss the approach before you invest time in it. + +## Support + +If SecretSecurity saves you from an accidental secret leak, consider supporting its development: + +- [GitHub Sponsors](https://github.com/sponsors/omegaleo) — sponsor directly on GitHub +- [Ko-fi](https://ko-fi.com/omegaleo) — buy me a coffee + +## License + +MIT — see [LICENSE.md](LICENSE) for details. diff --git a/SecretSecurity.slnx b/SecretSecurity.slnx new file mode 100644 index 0000000..12fc75b --- /dev/null +++ b/SecretSecurity.slnx @@ -0,0 +1,3 @@ + + + diff --git a/SecretSecurity/MethodExtensions/ListExtensions.cs b/SecretSecurity/MethodExtensions/ListExtensions.cs new file mode 100644 index 0000000..8486301 --- /dev/null +++ b/SecretSecurity/MethodExtensions/ListExtensions.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace SecretSecurity.MethodExtensions +{ + public static class ListExtensions + { + public static ReadOnlySpan AsReadOnlySpan(this IEnumerable strings) + { + return new ReadOnlySpan(strings.ToArray()); + } + } +} diff --git a/SecretSecurity/Models/DiffEntry.cs b/SecretSecurity/Models/DiffEntry.cs new file mode 100644 index 0000000..6d62eba --- /dev/null +++ b/SecretSecurity/Models/DiffEntry.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SecretSecurity.Models +{ + public class DiffEntry + { + public string File { get; set; } + public int Line { get; set; } + public string Content { get; set; } + } +} diff --git a/SecretSecurity/Models/FindingResult.cs b/SecretSecurity/Models/FindingResult.cs new file mode 100644 index 0000000..fa60aa2 --- /dev/null +++ b/SecretSecurity/Models/FindingResult.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SecretSecurity.Models +{ + public enum FindingType + { + ApiKey, + Token, + PrivateKey, + ConnectionString, + CloudCredential, + SuspiciousBlob + } + + public enum Severity + { + Info, + Warning, + High, + Critical + } + + public class SecretFinding + { + public string File { get; set; } + public int Line { get; set; } + public FindingType Type { get; set; } // "API Key", "Connection String" + public string ValuePreview { get; set; } // partially masked + public Severity Severity { get; set; } + } +} diff --git a/SecretSecurity/Program.cs b/SecretSecurity/Program.cs new file mode 100644 index 0000000..dec2505 --- /dev/null +++ b/SecretSecurity/Program.cs @@ -0,0 +1,255 @@ +using SecretSecurity; +using SecretSecurity.MethodExtensions; +using SecretSecurity.Models; +using Spectre.Console; +using System.Buffers; +using System.Diagnostics; + +class Program +{ + static List _ignorePatterns = new(); + + static void Main(string[] args) + { + if (args.Length == 0) + { + PrintHelp(); + return; + } + + var arg = args[0].ToLower(); + + switch (arg) + { + case "scan": + PerformScan(); + break; + case "install": + InstallCommand(); + break; + default: + PrintHelp(); + break; + } + } + + static void LoadIgnoreFile() + { + if (!File.Exists(".secretsecurityignore")) + return; + + _ignorePatterns = File.ReadAllLines(".secretsecurityignore") + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToList(); + } + + static void InstallCommand() + { + var root = RunGit("rev-parse --show-toplevel").Trim(); + var hookPath = Path.Combine(root, ".git", "hooks", "pre-commit"); + + var script = """ +#!/bin/sh +SecretSecurity scan +if [ $? -ne 0 ]; then + echo "❌ SecretSecurity blocked commit" + exit 1 +fi +"""; + + File.WriteAllText(hookPath, script); + + Console.WriteLine("✅ SecretSecurity installed successfully"); + } + + static void PrintHelp() + { + Console.WriteLine(@" +SecretSecurity CLI + +Commands: + scan Scan staged git changes + install Install git pre-commit hook + ignore Add ignore-rule +"); + } + + static void PerformScan() + { + LoadIgnoreFile(); + + AnsiConsole.MarkupLine("[cyan]🔍 SecretSecurity scanning...[/]\n"); + var findings = GetFindings(); + + PrintFindings(findings); + + bool shouldBlockCommit = findings.Any(f => + f.Severity == Severity.High || + f.Severity == Severity.Critical); + + if (shouldBlockCommit) + { + AnsiConsole.Write( + new Panel("[red]Commit blocked: High/Critical secrets detected[/]") + .Header("SecretSecurity") + .Border(BoxBorder.Double) + ); + + var critical = findings + .Where(f => f.Severity is Severity.High or Severity.Critical) + .ToList(); + + foreach (var f in critical) + { + AnsiConsole.MarkupLine($"[red]• {f.Type}[/] in [grey]{f.File}:{f.Line}[/]"); + } + + Environment.Exit(1); + } + } + + public static void PrintFindings(IEnumerable findings) + { + if (findings.Count() == 0) + { + AnsiConsole.MarkupLine("[green]✅ SecretSecurity: No secrets detected.[/]"); + return; + } + + AnsiConsole.Write( + new Panel($"[red]❌ {findings.Count()} issue(s) detected[/]") + .Border(BoxBorder.Rounded) + .Header("SecretSecurity Report") + ); + + foreach (var f in findings) + { + var color = f.Severity switch + { + Severity.Critical => "red", + Severity.High => "darkred", + Severity.Warning => "yellow", + _ => "grey" + }; + + AnsiConsole.MarkupLine($""" +[{color}]{f.Severity}[/] +📄 [bold]{f.File}:{f.Line}[/] +🔎 {f.ValuePreview} + +──────────────────────────── +"""); + } + } + + public static void PrintSeverity(Severity severity) + { + switch (severity) + { + case Severity.Critical: + Console.ForegroundColor = ConsoleColor.Red; + break; + case Severity.High: + Console.ForegroundColor = ConsoleColor.DarkRed; + break; + case Severity.Warning: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + default: + Console.ForegroundColor = ConsoleColor.Gray; + break; + } + } + + public static IEnumerable GetFindings() + { + var findings = new List(); + + var diffLines = GetStagedDiffWithContext(); + + foreach (var entry in diffLines) + { + var result = Validator.FindSecret(entry.Content); + + if (result != null) + { + if (IsIgnored(entry.File)) + continue; + + if (IsDocumentationFile(entry.File)) + continue; + + result.File = entry.File; + result.Line = entry.Line; + findings.Add(result); + } + } + + return findings; + } + + public static List GetStagedDiffWithContext() + { + var output = RunGit("diff --cached -U0"); + + var lines = output.Split('\n'); + + var results = new List(); + + string currentFile = null; + int lineNumber = 0; + + foreach (var line in lines) + { + // detect file + if (line.StartsWith("+++ b/")) + { + currentFile = line.Substring(6); + lineNumber = 0; + } + + // detect added line + else if (line.StartsWith("+") && !line.StartsWith("+++")) + { + lineNumber++; + + results.Add(new DiffEntry + { + File = currentFile ?? "unknown", + Line = lineNumber, + Content = line.Substring(1) // remove "+" + }); + } + } + + return results; + } + + public static string RunGit(string args) + { + var process = new Process(); + process.StartInfo.FileName = "git"; + process.StartInfo.Arguments = args; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.Start(); + + return process.StandardOutput.ReadToEnd(); + } + + static bool IsIgnored(string file) + { + return _ignorePatterns.Any(p => + file.Contains(p.Replace("*", ""))); + } + + static bool IsDocumentationFile(string file) + { + file = file.ToLowerInvariant(); + + return file.EndsWith(".md") || + file.EndsWith(".txt") || + file.Contains("readme") || + file.Contains("docs"); + } +} \ No newline at end of file diff --git a/SecretSecurity/Properties/launchSettings.json b/SecretSecurity/Properties/launchSettings.json new file mode 100644 index 0000000..f179c08 --- /dev/null +++ b/SecretSecurity/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "SecretSecurity": { + "commandName": "Project", + "commandLineArgs": "scan" + } + } +} \ No newline at end of file diff --git a/SecretSecurity/SecretSecurity.csproj b/SecretSecurity/SecretSecurity.csproj new file mode 100644 index 0000000..e58df46 --- /dev/null +++ b/SecretSecurity/SecretSecurity.csproj @@ -0,0 +1,21 @@ + + + + Exe + net10.0 + enable + enable + true + secretsecurity + SecretSecurity + 1.0.0 + Omega Leo + CLI tool for scanning secrets and sensitive data in files. + https://github.com/omegaleo/SecretSecurity + + + + + + + diff --git a/SecretSecurity/Validator.cs b/SecretSecurity/Validator.cs new file mode 100644 index 0000000..2c9b2f8 --- /dev/null +++ b/SecretSecurity/Validator.cs @@ -0,0 +1,173 @@ +using SecretSecurity.Models; +using System.Text.RegularExpressions; + +namespace SecretSecurity +{ + public static class Validator + { + // 1. Explicit secret assignments (HIGH confidence) + static Regex _explicitSecret = new Regex( + @"(?i)(api[_-]?key|secret|token|access[_-]?key|auth[_-]?token)\s*[:=]\s*[\""']?(?[a-z0-9_\-]{16,})[\""']?", + RegexOptions.Compiled); + + // 2. Provider-specific tokens (VERY high confidence) + static Regex _providerSecrets = new Regex( + @"(AKIA[0-9A-Z]{16}|sk_live_[0-9a-zA-Z]{24,}|ghp_[0-9a-zA-Z]{36}|xox[baprs]-[0-9a-zA-Z-]{10,})", + RegexOptions.Compiled); + + // 3. Private key blocks + static Regex _privateKey = new Regex( + @"-----BEGIN (RSA|EC|OPENSSH) PRIVATE KEY-----", + RegexOptions.Compiled); + + // 4. High entropy fallback (LIMITED usage only) + static Regex _randomBlob = new Regex( + @"\b[a-zA-Z0-9_\-]{40,}\b", + RegexOptions.Compiled); + + // 5. General Connection Strings + static Regex _generalConnString = new Regex( + "(?i)\\b(server|data source|database|uid|user id|pwd|password)\\s*=\\s*[^;]+", + RegexOptions.Compiled); + + // 6. Postgres Connection Strings + static Regex _postgres = new Regex( + "(?i)(postgres|mysql|mongodb|redis):\\/\\/[^\\\\s\\\"']+", + RegexOptions.Compiled); + + // 7. Azure Connection Strings + static Regex _azureConnString = new Regex( + "(?i)(DefaultEndpointsProtocol|AccountName|AccountKey)=", + RegexOptions.Compiled); + + public static SecretFinding? FindSecret(string line) + { + if (string.IsNullOrWhiteSpace(line)) + return null; + + // 1. Provider secrets (highest confidence) + if (_providerSecrets.IsMatch(line)) + { + return new SecretFinding + { + Type = FindingType.Token, + Severity = Severity.Critical, + ValuePreview = Mask(line) + }; + } + + // 2. Private keys + if (_privateKey.IsMatch(line)) + { + return new SecretFinding + { + Type = FindingType.ApiKey, + Severity = Severity.Critical, + ValuePreview = "-----BEGIN **** KEY-----" + }; + } + + // 3. Explicit assignment secrets + var explicitMatch = _explicitSecret.Match(line); + if (explicitMatch.Success) + { + return new SecretFinding + { + Type = FindingType.ApiKey | FindingType.Token, + Severity = Severity.High, + ValuePreview = Mask(explicitMatch.Value) + }; + } + + // 4. Connection strings (general) + if (_generalConnString.IsMatch(line)) + { + if (IsSafeDevConnection(line)) + { + return null; + } + + return new SecretFinding + { + Type = FindingType.ConnectionString, + Severity = Severity.High, + ValuePreview = MaskConnection(line) + }; + } + + // 5. Postgres / DB URLs + if (_postgres.IsMatch(line)) + { + return new SecretFinding + { + Type = FindingType.ConnectionString, + Severity = Severity.High, + ValuePreview = Mask(line) + }; + } + + // 6. Azure connection strings + if (_azureConnString.IsMatch(line)) + { + return new SecretFinding + { + Type = FindingType.ConnectionString, + Severity = Severity.Critical, + ValuePreview = Mask(line) + }; + } + + // 7. Fallback entropy check (low confidence) + if (_randomBlob.IsMatch(line) && LooksSuspicious(line)) + { + return new SecretFinding + { + Type = FindingType.SuspiciousBlob, + Severity = Severity.Warning, + ValuePreview = Mask(line) + }; + } + + return null; + } + + static string Mask(string value) + { + if (string.IsNullOrEmpty(value)) + return value; + + if (value.Length <= 10) + return "****"; + + return value.Substring(0, 4) + "****" + value[^2..]; + } + + static string MaskConnection(string conn) + { + return Regex.Replace(conn, + "(?i)(password|pwd|user id|uid|key)=([^;]+)", + "$1=****"); + } + + static bool LooksSuspicious(string line) + { + // reduce false positives + return line.Contains("=") || + line.Contains(":") || + line.Contains("token") || + line.Contains("key") || + line.Contains("secret"); + } + + static bool IsSafeDevConnection(string line) + { + line = line.ToLowerInvariant(); + + return line.Contains("localhost") || + line.Contains("127.0.0.1") || + line.Contains("::1") || + line.Contains("database=mydb") && line.Contains("trusted_connection=true") || + line.Contains("integrated security=true"); + } + } +} \ No newline at end of file diff --git a/testfiles/.env b/testfiles/.env new file mode 100644 index 0000000..b437207 --- /dev/null +++ b/testfiles/.env @@ -0,0 +1,8 @@ +AWS_KEY=AKIAIOSFODNN7EXAMPLE +AWS_SECRET=abcd1234abcd1234abcd1234abcd1234 + +GITHUB_TOKEN=ghp_ABCDEF1234567890ABCDEF1234567890AB + +SLACK_TOKEN=xoxb-1234567890-abcdefghij + +DATABASE_URL=postgres://admin:SuperSecret@localhost:5432/prod \ No newline at end of file diff --git a/testfiles/appSettings.dev.json b/testfiles/appSettings.dev.json new file mode 100644 index 0000000..57786df --- /dev/null +++ b/testfiles/appSettings.dev.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information" + } + }, + "ConnectionStrings": { + "DefaultConnection": "Server=localhost;Database=GameDb;Trusted_Connection=true;" + } +} \ No newline at end of file diff --git a/testfiles/appsettings.json b/testfiles/appsettings.json new file mode 100644 index 0000000..ec8ab9c --- /dev/null +++ b/testfiles/appsettings.json @@ -0,0 +1,8 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=mydb;Database=Prod;User Id=admin;Password=SuperSecret123;" + }, + "Stripe": { + "SecretKey": "sk_live_9x8y7z6w5v4u3t2s" + } +} \ No newline at end of file diff --git a/testfiles/clean_code.cs b/testfiles/clean_code.cs new file mode 100644 index 0000000..f70dd81 --- /dev/null +++ b/testfiles/clean_code.cs @@ -0,0 +1,5 @@ +public class Config +{ + public string ApiKeyName = "access_key"; + public string TokenDescription = "used for authentication flow"; +} \ No newline at end of file diff --git a/testfiles/mixed.cs b/testfiles/mixed.cs new file mode 100644 index 0000000..3d435cb --- /dev/null +++ b/testfiles/mixed.cs @@ -0,0 +1,14 @@ +public class Startup +{ + // safe config name + public const string ApiKeyName = "access_key"; + + // suspicious placeholder + private string tokenExample = "your_token_here_1234567890abcdef"; + + // real secret + private string stripeKey = "sk_live_1234567890abcdef"; + + // connection string + private string db = "Server=prod;Database=Main;User Id=admin;Password=SuperSecret;"; +} \ No newline at end of file diff --git a/testfiles/mixed.json b/testfiles/mixed.json new file mode 100644 index 0000000..cd2c85d --- /dev/null +++ b/testfiles/mixed.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "Level": "Debug" + }, + "ApiKeyHint": "use environment variable API_KEY", + + "Stripe": { + "Secret": "sk_live_1234567890abcdef" + }, + + "ConnectionStrings": { + "Default": "postgres://user:pass@localhost/db" + } +} \ No newline at end of file diff --git a/testfiles/mixed.txt b/testfiles/mixed.txt new file mode 100644 index 0000000..3a93d27 --- /dev/null +++ b/testfiles/mixed.txt @@ -0,0 +1,9 @@ +This file contains notes about API keys and tokens. + +DO NOT COMMIT REAL VALUES. + +Example: +API_KEY=example_value_1234567890 + +Actual production key: +ghp_ABCDEF1234567890ABCDEF1234567890AB \ No newline at end of file diff --git a/testfiles/private.pem b/testfiles/private.pem new file mode 100644 index 0000000..e47e154 --- /dev/null +++ b/testfiles/private.pem @@ -0,0 +1,4 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA7examplefakekeydataaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/testfiles/secrets.cs b/testfiles/secrets.cs new file mode 100644 index 0000000..662ef09 --- /dev/null +++ b/testfiles/secrets.cs @@ -0,0 +1,7 @@ +public class Config +{ + public string ApiKey = "sk_live_1234567890abcdef"; + public string Secret = "ghp_ABCDEF1234567890ABCDEF1234567890AB"; + + string conn = "Server=db;User Id=admin;Password=123456;"; +} \ No newline at end of file diff --git a/testfiles/suspicious_config.cs b/testfiles/suspicious_config.cs new file mode 100644 index 0000000..789d2a1 --- /dev/null +++ b/testfiles/suspicious_config.cs @@ -0,0 +1,5 @@ +public class Settings +{ + public string ApiKeyPlaceholder = "your_api_key_here_123456789"; + public string TokenExample = "example_token_value_1234567890abcdef"; +} \ No newline at end of file diff --git a/testfiles/suspicious_env.txt b/testfiles/suspicious_env.txt new file mode 100644 index 0000000..1fab59a --- /dev/null +++ b/testfiles/suspicious_env.txt @@ -0,0 +1,5 @@ +# development environment + +DATABASE_URL=postgres://user:password@localhost:5432/db +API_KEY=replace_this_value +SECRET_TOKEN=example_only_but_long_enough_1234567890 \ No newline at end of file diff --git a/testfiles/suspicious_log.txt b/testfiles/suspicious_log.txt new file mode 100644 index 0000000..8af7748 --- /dev/null +++ b/testfiles/suspicious_log.txt @@ -0,0 +1,4 @@ + +User login failed +Auth token received: abcdef1234567890abcdef1234567890abcdef +Request processed successfully \ No newline at end of file