Skip to content

Instantly share code, notes, and snippets.

@xoelop
Last active March 12, 2025 11:12
Show Gist options
  • Save xoelop/67b42c905f1f8b43a1127f143ba0a28f to your computer and use it in GitHub Desktop.
Save xoelop/67b42c905f1f8b43a1127f143ba0a28f to your computer and use it in GitHub Desktop.
script to replace secrets from one or multiple files, given a .env file where they're stored and pre-commit hook to run it before each commit
repos:
# Local hooks
- repo: local
hooks:
- id: env-var-replacer
name: Replace sensitive values with env variables
description: Replace actual values from .env with their variable names
entry: scripts/env_var_replacer.sh .env blur
language: script
pass_filenames: true
# Only run on specific file types that might contain sensitive data
# Adjust these file types based on your project needs
files: \.(sql|py|js|ts|json|yaml|yml|sh|conf)$
# Optional: exclude certain directories if needed
# exclude: ^(node_modules/|venv/|\.venv/)
#!/bin/bash
# env_var_replacer.sh
# This script can either:
# - Replace values from a .env file with their corresponding variable names (blur mode)
# - Replace variable placeholders with their actual values using envsubst (show mode)
# Usage: ./env_var_replacer.sh path/to/.env blur|show file1 file2 file3...
set -e
# Check if at least three arguments are provided
if [ $# -lt 3 ]; then
echo "Usage: $0 path/to/.env blur|show file1 [file2 file3...]"
echo " - path/to/.env: Path to the .env file containing variable definitions"
echo " - blur|show: Mode of operation"
echo " - blur: Replace values with variable names (${VAR_NAME})"
echo " - show: Replace variable placeholders with their actual values"
echo " - file1, file2, etc.: Files to process"
exit 1
fi
# Define list of env vars that should not be replaced
WORDS_TO_SKIP=(
"default"
"postgres"
"localhost"
"root"
"admin"
"user"
"password"
"username"
"host"
"port"
"database"
"schema"
"table"
)
ENV_FILE="$1"
MODE="$2"
shift 2 # Remove the first two arguments (env file and mode) from the arguments list
# Check if the .env file exists
if [ ! -f "$ENV_FILE" ]; then
echo "Error: .env file '$ENV_FILE' not found"
exit 1
fi
# Check if mode is valid
if [ "$MODE" != "blur" ] && [ "$MODE" != "show" ]; then
echo "Error: Mode must be either 'blur' or 'show'"
exit 1
fi
echo "Using environment file: $ENV_FILE"
echo "Mode: $MODE"
if [ "$MODE" = "show" ]; then
# SHOW MODE: Replace variable placeholders with their actual values
# Create a temporary environment file for envsubst
TMP_ENV_FILE=$(mktemp)
# Process the .env file line by line to handle complex values properly
while IFS= read -r line || [ -n "$line" ]; do
# Skip comments and empty lines
if [[ "$line" =~ ^[[:space:]]*# || -z "$line" ]]; then
continue
fi
# Extract variable name (everything before the first =)
if [[ "$line" =~ ^([^=]+)= ]]; then
VAR_NAME="${BASH_REMATCH[1]}"
# Get the value (everything after the first =)
VAR_VALUE="${line#*=}"
# Export the variable for envsubst
export "$VAR_NAME"="$VAR_VALUE"
# Add to our list of variables for envsubst
echo "$VAR_NAME" >> "$TMP_ENV_FILE"
fi
done < "$ENV_FILE"
# Create a list of variables in the format that envsubst expects
VARS_LIST=$(sed 's/^/${/' "$TMP_ENV_FILE" | sed 's/$/}/' | tr '\n' ' ')
# Process each file
for file in "$@"; do
if [ ! -f "$file" ]; then
echo "Warning: File '$file' not found, skipping"
continue
fi
echo "Replacing variables with values in: $file"
# Create a temporary file
TMP_FILE=$(mktemp)
# Use envsubst with our specific list of variables to replace
envsubst "$VARS_LIST" < "$file" > "$TMP_FILE"
# Move the temporary file to the original
mv "$TMP_FILE" "$file"
done
# Clean up
rm -f "$TMP_ENV_FILE"
echo "Replacement complete!"
else
# BLUR MODE: Replace values with variable names
# Process each variable in the .env file
while IFS= read -r line || [ -n "$line" ]; do
# Skip comments and empty lines
if [[ "$line" =~ ^[[:space:]]*# || -z "$line" ]]; then
continue
fi
# Extract variable name (everything before the first =)
if [[ "$line" =~ ^([^=]+)= ]]; then
VAR_NAME="${BASH_REMATCH[1]}"
# Get the value (everything after the first =)
VAR_VALUE="${line#*=}"
# Remove quotes if present
VAR_VALUE=$(echo "$VAR_VALUE" | sed -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//")
# Skip empty values
if [ -z "$VAR_VALUE" ]; then
continue
fi
# Check if the value is in our list of words to skip
SKIP_THIS_VALUE=0
for word in "${WORDS_TO_SKIP[@]}"; do
if [ "$VAR_VALUE" = "$word" ]; then
echo "Skipping common word: $VAR_VALUE"
SKIP_THIS_VALUE=1
break
fi
done
# Continue to next iteration if we should skip this value
if [ $SKIP_THIS_VALUE -eq 1 ]; then
continue
fi
# Skip if the value is too short (less than 4 characters)
if [ ${#VAR_VALUE} -lt 4 ]; then
echo "Skipping short value: $VAR_VALUE (too short, might cause false positives)"
continue
fi
echo "Processing variable: $VAR_NAME"
# Process each file
for file in "$@"; do
if [ ! -f "$file" ]; then
echo "Warning: File '$file' not found, skipping"
continue
fi
# Check if the value exists in the file
if grep -q "$VAR_VALUE" "$file"; then
echo " - Replacing value of '$VAR_NAME' in $file"
# Use sed to replace the value with the variable name
# We need to escape special characters in the value for sed
ESCAPED_VALUE=$(echo "$VAR_VALUE" | sed 's/[\/&]/\\&/g')
sed -i.bak "s/$ESCAPED_VALUE/\${$VAR_NAME}/g" "$file"
rm -f "$file.bak" # Remove backup file
fi
done
fi
done < "$ENV_FILE"
echo "Replacement complete!"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment