diff --git a/README.md b/README.md
index 4c5fbd4..6658e3a 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,22 @@ secretsecurity install
This writes a `pre-commit` hook to `.git/hooks/` that runs `secretsecurity scan` automatically on every commit.
+### Uninstall the pre-commit hook
+
+```bash
+secretsecurity uninstall
+```
+
+Removes the hook if it was installed by SecretSecurity. If the hook was created by something else, it is left untouched.
+
+### Update
+
+```bash
+secretsecurity update
+```
+
+Updates the tool to the latest version via `dotnet tool update --global`.
+
### Scan manually
```bash
diff --git a/SecretSecurity/Program.cs b/SecretSecurity/Program.cs
index dec2505..1fbb77d 100644
--- a/SecretSecurity/Program.cs
+++ b/SecretSecurity/Program.cs
@@ -27,6 +27,12 @@ class Program
case "install":
InstallCommand();
break;
+ case "uninstall":
+ UninstallCommand();
+ break;
+ case "update":
+ UpdateCommand();
+ break;
default:
PrintHelp();
break;
@@ -59,7 +65,45 @@ fi
File.WriteAllText(hookPath, script);
- Console.WriteLine("✅ SecretSecurity installed successfully");
+ // make the hook executable on Unix
+ if (!OperatingSystem.IsWindows())
+ RunProcess("chmod", $"+x \"{hookPath}\"");
+
+ AnsiConsole.MarkupLine("[green]✅ SecretSecurity hook installed successfully[/]");
+ }
+
+ static void UninstallCommand()
+ {
+ var root = RunGit("rev-parse --show-toplevel").Trim();
+ var hookPath = Path.Combine(root, ".git", "hooks", "pre-commit");
+
+ if (!File.Exists(hookPath))
+ {
+ AnsiConsole.MarkupLine("[yellow]No pre-commit hook found — nothing to uninstall.[/]");
+ return;
+ }
+
+ var content = File.ReadAllText(hookPath);
+ if (!content.Contains("SecretSecurity"))
+ {
+ AnsiConsole.MarkupLine("[yellow]Pre-commit hook exists but was not installed by SecretSecurity — leaving it untouched.[/]");
+ return;
+ }
+
+ File.Delete(hookPath);
+ AnsiConsole.MarkupLine("[green]✅ SecretSecurity hook removed successfully[/]");
+ }
+
+ static void UpdateCommand()
+ {
+ AnsiConsole.MarkupLine("[cyan]Updating SecretSecurity...[/]");
+
+ var exitCode = RunProcess("dotnet", "tool update --global SecretSecurity");
+
+ if (exitCode == 0)
+ AnsiConsole.MarkupLine("[green]✅ SecretSecurity updated successfully[/]");
+ else
+ AnsiConsole.MarkupLine("[red]Update failed. Try running: dotnet tool update --global SecretSecurity[/]");
}
static void PrintHelp()
@@ -68,9 +112,10 @@ fi
SecretSecurity CLI
Commands:
- scan Scan staged git changes
- install Install git pre-commit hook
- ignore Add ignore-rule
+ scan Scan staged git changes
+ install Install git pre-commit hook
+ uninstall Remove the git pre-commit hook
+ update Update SecretSecurity to the latest version
");
}
@@ -101,7 +146,7 @@ Commands:
foreach (var f in critical)
{
- AnsiConsole.MarkupLine($"[red]• {f.Type}[/] in [grey]{f.File}:{f.Line}[/]");
+ AnsiConsole.MarkupLine($"[red]• {f.Type}[/] in [grey]{Markup.Escape(f.File)}:{f.Line}[/]");
}
Environment.Exit(1);
@@ -134,8 +179,8 @@ Commands:
AnsiConsole.MarkupLine($"""
[{color}]{f.Severity}[/]
-📄 [bold]{f.File}:{f.Line}[/]
-🔎 {f.ValuePreview}
+📄 [bold]{Markup.Escape(f.File)}:{f.Line}[/]
+🔎 {Markup.Escape(f.ValuePreview)}
────────────────────────────
""");
@@ -225,18 +270,30 @@ Commands:
return results;
}
- public static string RunGit(string args)
+ public static string RunGit(string args) => RunProcessOutput("git", args);
+
+ static string RunProcessOutput(string fileName, string args)
{
var process = new Process();
- process.StartInfo.FileName = "git";
+ process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = args;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.Start();
-
return process.StandardOutput.ReadToEnd();
}
+ static int RunProcess(string fileName, string args)
+ {
+ var process = new Process();
+ process.StartInfo.FileName = fileName;
+ process.StartInfo.Arguments = args;
+ process.StartInfo.UseShellExecute = false;
+ process.Start();
+ process.WaitForExit();
+ return process.ExitCode;
+ }
+
static bool IsIgnored(string file)
{
return _ignorePatterns.Any(p =>
diff --git a/SecretSecurity/SecretSecurity.csproj b/SecretSecurity/SecretSecurity.csproj
index e58df46..e7a1783 100644
--- a/SecretSecurity/SecretSecurity.csproj
+++ b/SecretSecurity/SecretSecurity.csproj
@@ -12,8 +12,20 @@