Last active
March 12, 2025 11:12
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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