From e943c2cc3974f2f4c19eb2a40a67a4761a711b17 Mon Sep 17 00:00:00 2001 From: Artem Zahumonnyi Date: Wed, 25 Mar 2026 16:50:32 +0200 Subject: [PATCH 1/2] refactor(security): extract secrets detection into dedicated shell script Move Docker/Podman secrets detection logic from pre-commit hook into scripts/secrets-check.sh, simplify pre-commit hook, and wire license-check script to the new shell script. --- .husky/pre-commit | 27 +------------------------ package.json | 2 +- scripts/secrets-check.sh | 43 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-) create mode 100755 scripts/secrets-check.sh diff --git a/.husky/pre-commit b/.husky/pre-commit index 8af5aa08..2af5759b 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,28 +1,3 @@ # Run lint-staged (lint + test changed files) npx lint-staged - -# Check for secrets (only if Docker daemon is running) -if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then - echo "🔍 Checking for secrets with Gitleaks..." - npm run validate:secrets || { - echo "⚠️ Secrets detected! Please remove sensitive data before committing." - exit 1 - } -else - # Docker not available - provide helpful hints based on installed alternatives - if command -v colima >/dev/null 2>&1; then - echo "⚠️ Docker daemon not running - Colima is installed" - echo "💡 Run 'colima start' to enable secrets detection locally" - elif command -v podman >/dev/null 2>&1; then - echo "⚠️ Docker daemon not running - Podman is installed" - echo "💡 Run 'podman machine start' to enable secrets detection locally" - elif command -v orbstack >/dev/null 2>&1; then - echo "⚠️ Docker daemon not running - OrbStack is installed" - echo "💡 Start OrbStack to enable secrets detection locally" - elif command -v docker >/dev/null 2>&1; then - echo "⚠️ Docker installed but daemon not running" - echo "💡 Start Docker Desktop to enable secrets detection locally" - else - echo "⚠️ Docker not available - skipping secrets detection (will run in CI)" - fi -fi +npm run validate:secrets diff --git a/package.json b/package.json index 6fc4175c..2d83e055 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "commitlint": "commitlint --edit", "commitlint:last": "commitlint --from HEAD~1 --to HEAD --verbose", "validate:secrets": "node scripts/validate-secrets.js", - "license-check": "node scripts/license-check.js", + "license-check": "sh scripts/secrets-check.sh", "ci": "npm run license-check && npm run lint && npm run build && npm run test:unit && npm run test:integration", "ci:full": "npm run commitlint:last && npm run ci", "prepare": "husky", diff --git a/scripts/secrets-check.sh b/scripts/secrets-check.sh new file mode 100755 index 00000000..152aee3a --- /dev/null +++ b/scripts/secrets-check.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# Secrets detection using Gitleaks via Docker or Podman. +# Usage: +# scripts/secrets-check.sh # scan staged files +# scripts/secrets-check.sh --git # scan full git history + +GITLEAKS_IMAGE="ghcr.io/gitleaks/gitleaks:v8.30.1" +CONTAINER_ENGINE=$(command -v docker 2>/dev/null || command -v podman 2>/dev/null) + +if [ -z "$CONTAINER_ENGINE" ]; then + echo "No suitable container engine found - skipping secrets detection" + echo "Install Docker to enable local secrets scanning" + exit 1 +fi + +if ! $CONTAINER_ENGINE info >/dev/null 2>&1; then + if command -v colima >/dev/null 2>&1; then + echo "Docker daemon not running - Colima is installed" + echo "Run 'colima start' to enable secrets detection locally" + elif command -v podman >/dev/null 2>&1; then + echo "Docker daemon not running - Podman is installed" + echo "Run 'podman machine start' to enable secrets detection locally" + elif command -v orbstack >/dev/null 2>&1; then + echo "Docker daemon not running - OrbStack is installed" + echo "Start OrbStack to enable secrets detection locally" + else + echo "Container engine found but daemon is not running" + fi + exit 1 +fi + +echo "Checking for secrets with Gitleaks..." + +if [ "$1" = "--git" ]; then + $CONTAINER_ENGINE run --rm -v "$(pwd):/path" "$GITLEAKS_IMAGE" git --no-banner --verbose /path +else + $CONTAINER_ENGINE run --rm -v "$(pwd):/path" "$GITLEAKS_IMAGE" dir --no-banner --verbose /path +fi + +if [ $? -ne 0 ]; then + echo "Secrets detected! Please remove sensitive data before committing." + exit 1 +fi From af33f0918003312cc350c9c026c4d02c00c3f310 Mon Sep 17 00:00:00 2001 From: Artem Zahumonnyi Date: Wed, 25 Mar 2026 17:55:51 +0200 Subject: [PATCH 2/2] refactor(ci): extract secrets detection into dedicated shell script --- package.json | 2 +- scripts/secrets-check.sh | 43 ------------------ scripts/validate-secrets.js | 90 ++++++++++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 64 deletions(-) delete mode 100755 scripts/secrets-check.sh diff --git a/package.json b/package.json index 2d83e055..6fc4175c 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "commitlint": "commitlint --edit", "commitlint:last": "commitlint --from HEAD~1 --to HEAD --verbose", "validate:secrets": "node scripts/validate-secrets.js", - "license-check": "sh scripts/secrets-check.sh", + "license-check": "node scripts/license-check.js", "ci": "npm run license-check && npm run lint && npm run build && npm run test:unit && npm run test:integration", "ci:full": "npm run commitlint:last && npm run ci", "prepare": "husky", diff --git a/scripts/secrets-check.sh b/scripts/secrets-check.sh deleted file mode 100755 index 152aee3a..00000000 --- a/scripts/secrets-check.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# Secrets detection using Gitleaks via Docker or Podman. -# Usage: -# scripts/secrets-check.sh # scan staged files -# scripts/secrets-check.sh --git # scan full git history - -GITLEAKS_IMAGE="ghcr.io/gitleaks/gitleaks:v8.30.1" -CONTAINER_ENGINE=$(command -v docker 2>/dev/null || command -v podman 2>/dev/null) - -if [ -z "$CONTAINER_ENGINE" ]; then - echo "No suitable container engine found - skipping secrets detection" - echo "Install Docker to enable local secrets scanning" - exit 1 -fi - -if ! $CONTAINER_ENGINE info >/dev/null 2>&1; then - if command -v colima >/dev/null 2>&1; then - echo "Docker daemon not running - Colima is installed" - echo "Run 'colima start' to enable secrets detection locally" - elif command -v podman >/dev/null 2>&1; then - echo "Docker daemon not running - Podman is installed" - echo "Run 'podman machine start' to enable secrets detection locally" - elif command -v orbstack >/dev/null 2>&1; then - echo "Docker daemon not running - OrbStack is installed" - echo "Start OrbStack to enable secrets detection locally" - else - echo "Container engine found but daemon is not running" - fi - exit 1 -fi - -echo "Checking for secrets with Gitleaks..." - -if [ "$1" = "--git" ]; then - $CONTAINER_ENGINE run --rm -v "$(pwd):/path" "$GITLEAKS_IMAGE" git --no-banner --verbose /path -else - $CONTAINER_ENGINE run --rm -v "$(pwd):/path" "$GITLEAKS_IMAGE" dir --no-banner --verbose /path -fi - -if [ $? -ne 0 ]; then - echo "Secrets detected! Please remove sensitive data before committing." - exit 1 -fi diff --git a/scripts/validate-secrets.js b/scripts/validate-secrets.js index 82be1ffa7..102e7127 100755 --- a/scripts/validate-secrets.js +++ b/scripts/validate-secrets.js @@ -1,54 +1,104 @@ #!/usr/bin/env node /** - * Cross-platform secrets detection using Gitleaks - * Works on Windows, macOS, and Linux + * Cross-platform secrets detection using Gitleaks. + * Supports Docker and Podman (including Colima, OrbStack, Podman Machine). + * Works on Windows, macOS, and Linux. * - * This script runs Gitleaks in a Docker container for local validation. - * CI uses the official gitleaks-action@v2 for better GitHub integration. - * Both share the same .gitleaks.toml configuration. + * Usage: + * node scripts/validate-secrets.js # scan working directory */ -import { spawn } from 'child_process'; +import { spawn, execSync } from 'child_process'; import { platform } from 'os'; import { resolve } from 'path'; import { existsSync } from 'fs'; +const GITLEAKS_IMAGE = 'ghcr.io/gitleaks/gitleaks:v8.30.1'; const isWindows = platform() === 'win32'; const projectPath = resolve(process.cwd()); - -// Check if .gitleaks.toml exists const configPath = resolve(projectPath, '.gitleaks.toml'); const hasConfig = existsSync(configPath); +function commandExists(cmd) { + try { + execSync(isWindows ? `where ${cmd}` : `which ${cmd}`, { stdio: 'ignore' }); + return true; + } catch { + return false; + } +} + +function daemonRunning(engine) { + try { + execSync(`${engine} info`, { stdio: 'ignore' }); + return true; + } catch { + return false; + } +} + +function detectEngine() { + for (const engine of ['docker', 'podman']) { + if (commandExists(engine)) return engine; + } + return null; +} + +function hintForStoppedDaemon(engine) { + if (engine === 'docker') { + if (commandExists('colima')) return "Run 'colima start' to enable secrets detection locally"; + if (commandExists('orbstack')) return 'Start OrbStack to enable secrets detection locally'; + } + if (engine === 'podman') { + return "Run 'podman machine start' to enable secrets detection locally"; + } + return 'Start your container engine to enable secrets detection locally'; +} + +const engine = detectEngine(); + +if (!engine) { + console.log('No container engine found (docker/podman) - skipping secrets detection'); + console.log('Install Docker or Podman to enable local secrets scanning'); + process.exit(1); +} + +if (!daemonRunning(engine)) { + const engineLabel = engine.charAt(0).toUpperCase() + engine.slice(1); + console.error(`${engineLabel} daemon is not running`); + console.error(hintForStoppedDaemon(engine)); + process.exit(1); +} + const args = [ - 'run', - '--rm', - '-v', - `${projectPath}:/path`, - 'ghcr.io/gitleaks/gitleaks:v8.30.1', - 'detect', - '--source=/path', + 'run', '--rm', + '-v', `${projectPath}:/path`, + GITLEAKS_IMAGE, + 'dir', + '--no-banner', '--verbose', - '--no-git' + '/path' ]; -// Add config file if it exists if (hasConfig) { args.push('--config=/path/.gitleaks.toml'); } -console.log('Running Gitleaks secrets detection...'); +console.log('Checking for secrets with Gitleaks...'); -const gitleaks = spawn('docker', args, { +const gitleaks = spawn(engine, args, { stdio: 'inherit', shell: isWindows }); gitleaks.on('close', (code) => { + if (code !== 0) { + console.error('Secrets detected! Please remove sensitive data before committing.'); + } process.exit(code); }); gitleaks.on('error', (err) => { - console.error('Failed to run Gitleaks:', err.message); + console.error(`Failed to run Gitleaks via ${engine}:`, err.message); process.exit(1); });