Skip to content

Instantly share code, notes, and snippets.

@EtherZa
Last active December 15, 2023 14:25
Show Gist options
  • Save EtherZa/5be6dee35219525cc9b305e86143ea69 to your computer and use it in GitHub Desktop.
Save EtherZa/5be6dee35219525cc9b305e86143ea69 to your computer and use it in GitHub Desktop.
git filter to smudge/clean secrets stored in .ini
#!/bin/bash
# README
# Swap secrets for placeholders on commit/restore
#
# Copy this file to ~/scipts/git-redact-filter.sh
# chmod +x ~/scripts/git-redact-filter.sh
#
# Create ~/scripts/secret.ini
# populate with key=value
# ensure last key/value pair has a line break.
# empty lines, section headings and lines starting with # or ; are excluded
#
# Add fiters to git (drop --global for a single repo)
# git config --global filter.redact.smudge "~/scripts/git-redact-filter.sh smudge ~/scripts/secrets.ini"
# git config --global filter.redact.clean "~/scripts/git-redact-filter.sh clean ~/scripts/secrets.ini"
#
# Add files to process to .gitattributes
# *.json filter=redact
# *.env filter=redact
# *.yml filter=redact
#
# To remove filters
# git config --global --unset filter.redact.smudge
# git config --global --unset filter.redact.clean
# Check if the correct number of arguments is provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <clean/smudge> <config_file>"
exit 1
fi
config_file="$2"
# Exist if the file does not exist
if [ ! -e "$config_file" ]; then
echo "$config_file not found"
exit 2
fi
sedcmd="sed"
# mac - use gsed instead of sed
# if [[ "$(uname)" == "Darwin" ]]; then
# sedcmd="gsed"
# fi
declare -A mapArr
# Use process substitution to avoid subshell
while read -r bash_code; do
eval "$bash_code"
done < <(
awk -F '=' '/^[[:space:]]*[^#\[;[:space:]].*[[:space:]]*=[[:space:]]*[^[:space:]]+[[:space:]]*/ {
key = $1
value = $2
# Trim leading and trailing whitespace
gsub(/^[[:space:]]+|[[:space:]]+$/, "", key)
gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
# Escape quote for print
gsub(/"/, "\\\"", key)
gsub(/"/, "\\\"", value)
# Escaoe / for sed replacement
gsub(/\//, "\\/", key)
gsub(/\//, "\\/", value)
# Use print to generate Bash code for populating mapArr
print "mapArr[\"" key "\"]=" "\"" value "\""
}' "$config_file"
)
if [[ "$1" == "smudge" ]]; then
# For smudge, sort by descending value length to avoid clashes
# Create an mapArray of keys
keys=("${!mapArr[@]}")
# Sort the keys based on the corresponding values' lengths
IFS=$'\n' sorted_keys=($(
for key in "${keys[@]}"; do
echo "${#mapArr[$key]} $key"
done | sort -k1,1nr | cut -d ' ' -f 2-
))
for key in "${sorted_keys[@]}"; do
value=${mapArr[${key}]}
sedcmd+=" -e \"s/\[${key}\]/${value}/g\""
done
elif [[ "$1" == "clean" ]]; then
for key in "${!mapArr[@]}"; do
value=${key}
key=${mapArr[${key}]}
sedcmd+=" -e \"s/${key}/\[${value}\]/g\""
done
else
echo "Usage: $0 <clean/smudge> <config_file>"
exit 1
fi
eval "$sedcmd"
@EtherZa
Copy link
Author

EtherZa commented Dec 1, 2023

Clean/smudge configurations can also be applied to a collection of repositories separated by folder.

~/.gitconfig - apply config per parent path

[includeIf "gitdir/i:c:/Git/aa/"]
    path = c:/Git/aa/.gitconfig

c:/git - common redact script

git-redact-filter.sh

c:/git/aa

.gitattributes - which files to apply redact to

*.json text filter=redact
*.env text filter=redact
*.yml text filter=redact

.gitconfig - override global .gitattributes location and add filter

[core]
    attributesFile = c:/Git/aa/.gitattributes

[filter "redact"]
    clean = c:/Git/aa/git-redact-filter.sh clean c:/Git/aa/redact.ini
    smudge = c:/Git/aa/git-redact-filter.sh smudge c:/Git/aa/redact.ini

.redact.ini - secrets to smudge/clean

[Service Bus]
azure_svb_namespace=[add secret here]
azure_svb_sharedAccessKeyName=[add secret here]
azure_svb_sharedAccessKey=[add secret here]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment