When managing server configurations in Git repositories, we need to ensure no unauthorized local modifications exist. While git status
shows changes, we need an automated way to detect and alert about any modifications.
The simplest approach checks git status --porcelain
output. The --porcelain
flag provides parseable output:
#!/bin/bash
REPO_PATH="/path/to/your/repo"
cd $REPO_PATH
if [[ $(git status --porcelain) ]]; then
echo "Changes detected in $REPO_PATH at $(date)" | mail -s "Git Changes Alert" admin@example.com
git status # Include full status in logs
fi
For multiple repositories, create a script like this:
#!/bin/bash
REPOS=(
"/etc/apache2"
"/var/www/configs"
"/opt/application/config"
)
for repo in "${REPOS[@]}"; do
cd "$repo" || continue
if [[ $(git status --porcelain) ]]; then
SUBJECT="Unauthorized changes in $repo"
BODY=$(git status)
echo "$BODY" | mail -s "$SUBJECT" sysadmin-team@example.com
logger -t git-monitor "$SUBJECT"
fi
done
Add this to crontab (run every 15 minutes):
*/15 * * * * /usr/local/bin/git-change-monitor.sh >/dev/null 2>&1
For files that should be ignored (like local config overrides), ensure they're properly listed in .gitignore
:
# Example .gitignore entries
/local-settings.ini
/temp/
*.swp
For more detailed tracking, use git diff
:
#!/bin/bash
REPO="/path/to/repo"
DIFF_FILE="/tmp/git-diff-$(date +%Y%m%d).log"
cd $REPO
git diff > $DIFF_FILE
if [ -s $DIFF_FILE ]; then
mail -s "Git Diff Report for $REPO" admin@example.com < $DIFF_FILE
fi
For Nagios/Icinga integration:
#!/bin/bash
REPO=$1
WARNING=1
CRITICAL=2
cd $REPO || exit $CRITICAL
CHANGES=$(git status --porcelain | wc -l)
if [ $CHANGES -ge $CRITICAL ]; then
echo "CRITICAL: $CHANGES uncommitted changes"
exit 2
elif [ $CHANGES -ge $WARNING ]; then
echo "WARNING: $CHANGES uncommitted changes"
exit 1
else
echo "OK: No uncommitted changes"
exit 0
fi
For better logging:
LOG_FILE="/var/log/git-monitor.log"
exec >> $LOG_FILE 2>&1
echo "=== Git Change Check $(date) ==="
git status --porcelain
echo "==============================="
Ensure the cron job runs with appropriate permissions and consider:
- Using a dedicated monitoring account
- Setting proper umask (0027 recommended)
- Storing logs securely
- Using GPG for email alerts containing sensitive data
When managing server configurations via Git repositories, unexpected local modifications can introduce configuration drift and deployment inconsistencies. The fundamental requirement is ensuring that no uncommitted changes exist in any repository directory, whether they're server configs, static websites, or web applications.
#!/bin/bash
REPO_PATH="/path/to/your/repo"
cd $REPO_PATH || exit 1
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
echo "Uncommitted changes detected in $REPO_PATH"
git status --porcelain
exit 1
fi
# Check for untracked files (excluding .gitignore patterns)
if [ -n "$(git status --porcelain)" ]; then
echo "Untracked files found in $REPO_PATH"
git status --porcelain
exit 1
fi
For environments with multiple repositories, we can create a wrapper script:
#!/bin/bash
REPO_LIST=(
"/etc/apache2"
"/var/www/html/config"
"/opt/wordpress/wp-content"
)
for repo in "${REPO_LIST[@]}"; do
if [ -d "$repo/.git" ]; then
output=$(git -C "$repo" status --porcelain)
if [ -n "$output" ]; then
echo "ALERT: Changes detected in $repo"
echo "$output"
# Additional notification logic here
fi
fi
done
To run this check hourly, add to crontab:
0 * * * * /usr/local/bin/git_repo_monitor.sh >> /var/log/git_monitor.log 2>&1
For immediate alerts, integrate with common notification systems:
# Slack notification example
if [ -n "$output" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"Git changes detected in $repo:\n$output\"}" \
https://hooks.slack.com/services/TOKEN
fi
- Add timestamp logging for audit trails
- Implement lock files to prevent concurrent execution
- Include proper error handling for non-Git directories
- Add whitelist capability for intentional local changes
For Puppet environments, consider complementing this solution with:
# Puppet snippet to ensure no manual changes
file { '/etc/apache2':
ensure => 'directory',
recurse => true,
source => 'puppet:///modules/apache/config',
replace => true,
force => true,
}