diff --git a/.husky/hooks/code-quality.sh b/.husky/hooks/code-quality.sh new file mode 100755 index 0000000..b556a90 --- /dev/null +++ b/.husky/hooks/code-quality.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +""" +Code quality checking hook for Husky-style pre-commit setup. +This hook runs Black, isort, flake8, and Bandit for code quality. +""" + +echo "๐Ÿ Running Python code quality checks..." + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check Black formatting +echo " - Checking code formatting with Black..." +if command_exists black; then + if black --check --diff .; then + echo " โœ… Black formatting check passed" + else + echo " โŒ Black formatting issues found" + echo " ๐Ÿ’ก Run 'black .' to fix formatting" + exit 1 + fi +else + echo " โš ๏ธ Black not installed, skipping formatting check" + echo " ๐Ÿ’ก Install with: pip install black" +fi + +# Check isort import sorting +echo " - Checking import sorting with isort..." +if command_exists isort; then + if isort --check-only --diff .; then + echo " โœ… isort import sorting check passed" + else + echo " โŒ isort import sorting issues found" + echo " ๐Ÿ’ก Run 'isort .' to fix import sorting" + exit 1 + fi +else + echo " โš ๏ธ isort not installed, skipping import sorting check" + echo " ๐Ÿ’ก Install with: pip install isort" +fi + +# Check flake8 linting +echo " - Running linting with flake8..." +if command_exists flake8; then + if flake8 --max-line-length=88 --extend-ignore=E203,W503 .; then + echo " โœ… flake8 linting check passed" + else + echo " โŒ flake8 linting issues found" + echo " ๐Ÿ’ก Fix the linting issues above" + exit 1 + fi +else + echo " โš ๏ธ flake8 not installed, skipping linting check" + echo " ๐Ÿ’ก Install with: pip install flake8" +fi + +# Check Bandit security linting +echo " - Running security linting with Bandit..." +if command_exists bandit; then + if bandit -r . -f json -o bandit-report.json; then + echo " โœ… Bandit security linting check passed" + else + echo " โŒ Bandit found security issues" + echo " ๐Ÿ’ก Review bandit-report.json for details" + exit 1 + fi +else + echo " โš ๏ธ Bandit not installed, skipping security linting" + echo " ๐Ÿ’ก Install with: pip install bandit" +fi + +echo "โœ… All code quality checks passed!" diff --git a/.husky/hooks/snyk-scan.py b/.husky/hooks/snyk-scan.py new file mode 100755 index 0000000..c7b4dc0 --- /dev/null +++ b/.husky/hooks/snyk-scan.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +""" +Snyk security scanning hook for Husky-style pre-commit setup. +This hook runs Snyk security scanning on Python dependencies. +""" + +import os +import sys +import subprocess +import json +from pathlib import Path + + +def run_snyk_scan(): + """Run Snyk security scan on Python dependencies.""" + + # Check if Snyk CLI is available + try: + subprocess.run(['snyk', '--version'], capture_output=True, check=True) + except (subprocess.CalledProcessError, FileNotFoundError): + print("โŒ Snyk CLI not found. Please install it first:") + print(" npm install -g snyk") + print(" or visit: https://snyk.io/docs/using-snyk/") + return 1 + + # Check if SNYK_TOKEN is set + if not os.getenv('SNYK_TOKEN'): + print("โš ๏ธ SNYK_TOKEN environment variable not set.") + print(" Please set it with: export SNYK_TOKEN=your_token") + print(" You can get a token from: https://app.snyk.io/account") + return 0 # Don't fail the commit, just warn + + # Check for requirements.txt + requirements_files = ['requirements.txt', 'setup.py'] + found_requirements = False + + for req_file in requirements_files: + if Path(req_file).exists(): + found_requirements = True + break + + if not found_requirements: + print("โš ๏ธ No requirements.txt or setup.py found. Skipping Snyk scan.") + return 0 + + print("๐Ÿ” Running Snyk security scan...") + + try: + # Run Snyk test on Python dependencies + result = subprocess.run([ + 'snyk', 'test', + '--severity-threshold=high', + '--json' + ], capture_output=True, text=True, check=False) + + if result.returncode == 0: + print("โœ… Snyk scan completed - no high severity vulnerabilities found") + return 0 + else: + # Parse JSON output to show vulnerabilities + try: + vulns = json.loads(result.stdout) + if 'vulnerabilities' in vulns: + print("โŒ High severity vulnerabilities found:") + for vuln in vulns['vulnerabilities']: + if vuln.get('severity') == 'high': + print(f" - {vuln.get('title', 'Unknown')} in {vuln.get('packageName', 'Unknown')}") + print(f" CVSS Score: {vuln.get('cvssScore', 'N/A')}") + print(f" More info: {vuln.get('url', 'N/A')}") + print() + + print("๐Ÿ’ก To fix vulnerabilities, run: snyk wizard") + return 1 + except json.JSONDecodeError: + print("โŒ Snyk scan failed with errors:") + print(result.stderr) + return 1 + + except Exception as e: + print(f"โŒ Error running Snyk scan: {e}") + return 1 + + +if __name__ == '__main__': + sys.exit(run_snyk_scan()) diff --git a/.husky/hooks/talisman-check.sh b/.husky/hooks/talisman-check.sh new file mode 100755 index 0000000..9e0fd06 --- /dev/null +++ b/.husky/hooks/talisman-check.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +""" +Talisman secrets detection hook for Husky-style pre-commit setup. +This hook runs Talisman to detect potential secrets in commits. +""" + +# Check if Talisman is available +if ! command -v talisman &> /dev/null; then + echo "โŒ Talisman not found. Please install it first:" + echo " # macOS" + echo " brew install talisman" + echo " # Linux" + echo " curl -sL https://github.com/thoughtworks/talisman/releases/latest/download/talisman_linux_amd64 -o talisman" + echo " chmod +x talisman" + echo " sudo mv talisman /usr/local/bin/" + exit 1 +fi + +echo "๐Ÿ” Running Talisman secrets detection..." + +# Run Talisman with pre-commit hook +if talisman --githook pre-commit; then + echo "โœ… Talisman check passed - no secrets detected" + exit 0 +else + echo "โŒ Talisman found potential secrets in your changes" + echo "" + echo "๐Ÿ’ก To fix this:" + echo "1. Review the files mentioned above" + echo "2. Remove any actual secrets from your code" + echo "3. If the file contains legitimate test data, add it to .talismanrc:" + echo " talisman --checksum path/to/file" + echo " # Then add the checksum to .talismanrc" + exit 1 +fi diff --git a/.husky/hooks/test-runner.sh b/.husky/hooks/test-runner.sh new file mode 100755 index 0000000..4dcfe11 --- /dev/null +++ b/.husky/hooks/test-runner.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +""" +Test runner hook for Husky-style pre-push setup. +This hook runs tests and coverage checks before pushing. +""" + +echo "๐Ÿงช Running tests and coverage checks..." + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check if pytest is available +if ! command_exists pytest; then + echo "โŒ pytest not found. Please install it first:" + echo " pip install pytest pytest-cov" + exit 1 +fi + +# Run tests +echo " - Running tests..." +if pytest --html=tests/test-report/test-report.html; then + echo " โœ… All tests passed" +else + echo " โŒ Tests failed. Please fix before pushing." + exit 1 +fi + +# Run coverage check +echo " - Checking test coverage..." +if command_exists pytest; then + if pytest --cov=contentstack_utils --cov-report=term-missing; then + echo " โœ… Coverage check completed" + else + echo " โŒ Coverage check failed. Please improve test coverage." + exit 1 + fi +else + echo " โš ๏ธ pytest-cov not installed, skipping coverage check" + echo " ๐Ÿ’ก Install with: pip install pytest-cov" +fi + +echo "โœ… All test checks passed!" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..da3763f --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,69 @@ +#!/usr/bin/env sh +# Pre-commit hook to run Talisman and Snyk scans, completing both before deciding to commit + +# Function to check if a command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check if Talisman is installed +if ! command_exists talisman; then + echo "Error: Talisman is not installed. Please install it and try again." + exit 1 +fi + +# Check if Snyk is installed +if ! command_exists snyk; then + echo "Error: Snyk is not installed. Please install it and try again." + exit 1 +fi + +# Allow bypassing the hook with an environment variable +if [ "$SKIP_HOOK" = "1" ]; then + echo "Skipping Talisman and Snyk scans (SKIP_HOOK=1)." + exit 0 +fi + +# Initialize variables to track scan results +talisman_failed=false +snyk_failed=false + +# Run Talisman secret scan +echo "Running Talisman secret scan..." +talisman --githook pre-commit > talisman_output.log 2>&1 +talisman_exit_code=$? + +if [ $talisman_exit_code -eq 0 ]; then + echo "Talisman scan passed: No secrets found." +else + echo "Talisman scan failed (exit code $talisman_exit_code). See talisman_output.log for details." + talisman_failed=true +fi + +# Run Snyk vulnerability scan (continues even if Talisman failed) +echo "Running Snyk vulnerability scan..." +snyk test --all-projects --fail-on=all > snyk_output.log 2>&1 +snyk_exit_code=$? + +if [ $snyk_exit_code -eq 0 ]; then + echo "Snyk scan passed: No vulnerabilities found." +elif [ $snyk_exit_code -eq 1 ]; then + echo "Snyk found vulnerabilities. See snyk_output.log for details." + snyk_failed=true +else + echo "Snyk scan failed with error (exit code $snyk_exit_code). See snyk_output.log for details." + snyk_failed=true +fi + +# Evaluate results after both scans +if [ "$talisman_failed" = true ] || [ "$snyk_failed" = true ]; then + echo "Commit aborted due to issues found in one or both scans." + [ "$talisman_failed" = true ] && echo "- Talisman issues: Check talisman_output.log" + [ "$snyk_failed" = true ] && echo "- Snyk issues: Check snyk_output.log" + exit 1 +fi + +# If both scans pass, allow the commit +echo "All scans passed. Proceeding with commit." +rm -f talisman_output.log snyk_output.log +exit 0 diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..55f5168 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,34 @@ +#!/usr/bin/env sh + +echo "๐Ÿš€ Running pre-push checks..." + +# Activate virtual environment if it exists +if [ -d "venv" ]; then + echo "๐Ÿ”ง Activating virtual environment..." + source venv/bin/activate +fi + +# Run tests to ensure code quality +echo "๐Ÿงช Running tests..." +if ! pytest --html=tests/test-report/test-report.html; then + echo "โŒ Tests failed. Please fix before pushing." + exit 1 +fi + +# Run coverage check +echo "๐Ÿ“Š Checking test coverage..." +if ! pytest --cov=contentstack_utils --cov-report=term-missing; then + echo "โŒ Coverage check failed. Please improve test coverage." + exit 1 +fi + +# Run security scan on dependencies (optional) +if [ -n "$SNYK_TOKEN" ]; then + echo "๐Ÿ” Running comprehensive Snyk scan..." + if ! snyk test --severity-threshold=high; then + echo "โŒ High severity vulnerabilities found. Please fix before pushing." + exit 1 + fi +fi + +echo "โœ… All pre-push checks passed!" diff --git a/LICENSE b/LICENSE index f6d74aa..becb635 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2021-2025 Contentstack +Copyright 2021-2026 Contentstack 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: diff --git a/requirements.txt b/requirements.txt index d83dc9f..8516149 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,10 @@ -pip~=25.1.1 +pip~=26.0 setuptools==80.3.1 lxml~=5.4.0 -ruff==0.11.5 \ No newline at end of file +ruff==0.11.5 +pytest>=7.0.0 +pytest-cov>=4.0.0 +pytest-html>=4.2.0 +black>=23.0.0 +flake8>=6.0.0 +isort>=5.0.0