Skip to content

Commit 28eabd4

Browse files
committed
fixup! Implement drift-detection module
1 parent fb93c0b commit 28eabd4

3 files changed

Lines changed: 166 additions & 156 deletions

File tree

infra/modules/drift-detection/buildspec/buildspec.yml

Lines changed: 0 additions & 155 deletions
This file was deleted.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# shellcheck shell=bash
2+
# shellcheck disable=SC2148
3+
4+
set -euo pipefail
5+
6+
echo "=== Drift Detection for ${DEPLOYMENT_NAME} ==="
7+
echo "Timestamp: $(date -Iseconds)"
8+
echo "Region: ${AWS_DEFAULT_REGION}"
9+
echo ""
10+
11+
# Clone repository (full history needed to compare against stored SHAs)
12+
echo "Cloning repository: ${GIT_REPOSITORY_URL}"
13+
git clone --single-branch --branch "${GIT_BRANCH}" "${GIT_REPOSITORY_URL}" /tmp/repo
14+
cd /tmp/repo || exit
15+
16+
CURRENT_SHA=$(git rev-parse HEAD)
17+
echo "Current HEAD: ${CURRENT_SHA}"
18+
echo ""
19+
20+
# Get list of all roots for this deployment
21+
echo "=== Querying SSM parameters for ${DEPLOYMENT_NAME} roots ==="
22+
SSM_PREFIX="/terraform/last_applied/${DEPLOYMENT_NAME}/"
23+
24+
PARAMETERS=$(aws ssm describe-parameters \
25+
--parameter-filters "Key=Name,Option=BeginsWith,Values=${SSM_PREFIX}" \
26+
--query 'Parameters[].Name' \
27+
--output text)
28+
29+
if [ -z "$PARAMETERS" ]; then
30+
echo "ERROR: No SSM parameters found for deployment: ${DEPLOYMENT_NAME}"
31+
exit 1
32+
fi
33+
34+
echo "Found $(echo "$PARAMETERS" | wc -w) root(s) to check"
35+
echo ""
36+
37+
# Track results
38+
TOTAL_ROOTS=0
39+
UP_TO_DATE_COUNT=0
40+
DRIFT_DETECTED_COUNT=0
41+
MISSING_SHA_COUNT=0
42+
DRIFTED_ROOTS=()
43+
44+
# Check each root
45+
for PARAM_NAME in $PARAMETERS; do
46+
TOTAL_ROOTS=$((TOTAL_ROOTS + 1))
47+
48+
# Extract root path from parameter name
49+
# /terraform/last_applied/deploy/account -> deploy/account
50+
ROOT_PATH="${PARAM_NAME#/terraform/last_applied/}"
51+
52+
echo "--- Checking: ${ROOT_PATH} ---"
53+
54+
# Get stored SHA from SSM
55+
STORED_SHA=$(aws ssm get-parameter --name "${PARAM_NAME}" --query 'Parameter.Value' --output text 2>/dev/null || echo "")
56+
57+
if [ -z "$STORED_SHA" ]; then
58+
echo " ❌ MISSING: No SHA stored in SSM"
59+
MISSING_SHA_COUNT=$((MISSING_SHA_COUNT + 1))
60+
DRIFTED_ROOTS+=("${ROOT_PATH} (no SHA)")
61+
echo ""
62+
continue
63+
fi
64+
65+
echo " Stored SHA: ${STORED_SHA}"
66+
67+
# Check if SHA exists in repo
68+
if ! git cat-file -e "${STORED_SHA}" 2>/dev/null; then
69+
echo " ⚠️ WARNING: Stored SHA not found in repository"
70+
DRIFT_DETECTED_COUNT=$((DRIFT_DETECTED_COUNT + 1))
71+
DRIFTED_ROOTS+=("${ROOT_PATH} (SHA not in repo)")
72+
echo ""
73+
continue
74+
fi
75+
76+
# Check if directory has changed since stored SHA
77+
ROOT_DIR="infra/deployments/${ROOT_PATH}"
78+
79+
if [ ! -d "${ROOT_DIR}" ]; then
80+
echo " ⚠️ WARNING: Directory does not exist: ${ROOT_DIR}"
81+
DRIFT_DETECTED_COUNT=$((DRIFT_DETECTED_COUNT + 1))
82+
DRIFTED_ROOTS+=("${ROOT_PATH} (dir missing)")
83+
echo ""
84+
continue
85+
fi
86+
87+
# Check for changes between stored SHA and current HEAD
88+
# Includes both the root directory AND all modules (with exclusions)
89+
90+
# Build git pathspec with exclusions
91+
PATHSPEC="${ROOT_DIR} infra/modules/"
92+
if [ -n "${EXCLUDED_MODULE_PATHS}" ]; then
93+
IFS=',' read -ra EXCLUDED <<<"${EXCLUDED_MODULE_PATHS}"
94+
for EXCLUDED_PATH in "${EXCLUDED[@]}"; do
95+
PATHSPEC="${PATHSPEC} :(exclude)${EXCLUDED_PATH}"
96+
done
97+
fi
98+
99+
if git diff --quiet "${STORED_SHA}..HEAD" -- "${PATHSPEC}"; then
100+
echo " ✅ UP TO DATE: No changes detected"
101+
UP_TO_DATE_COUNT=$((UP_TO_DATE_COUNT + 1))
102+
else
103+
echo " ⚠️ DRIFT DETECTED: Changes found since last apply"
104+
105+
# Show changed files in root
106+
ROOT_CHANGES=$(git diff --name-only "${STORED_SHA}..HEAD" -- "${ROOT_DIR}")
107+
if [ -n "$ROOT_CHANGES" ]; then
108+
echo " Changed files in root:"
109+
echo "$ROOT_CHANGES" | sed 's/^/ - /'
110+
fi
111+
112+
# Show changed modules (excluding specified paths)
113+
MODULE_CHANGES=$(git diff --name-only "${STORED_SHA}..HEAD" -- "${PATHSPEC}" | grep "^infra/modules/" || true)
114+
if [ -n "$MODULE_CHANGES" ]; then
115+
echo " Changed modules:"
116+
echo "$MODULE_CHANGES" | sed 's/^/ - /'
117+
fi
118+
119+
DRIFT_DETECTED_COUNT=$((DRIFT_DETECTED_COUNT + 1))
120+
DRIFTED_ROOTS+=("${ROOT_PATH}")
121+
fi
122+
123+
echo ""
124+
done
125+
126+
# Print summary
127+
echo "==================================================================="
128+
echo "=== DRIFT DETECTION SUMMARY ==="
129+
echo "==================================================================="
130+
echo "Deployment: ${DEPLOYMENT_NAME}"
131+
echo "Total roots: ${TOTAL_ROOTS}"
132+
echo "Up to date: ${UP_TO_DATE_COUNT}"
133+
echo "Drift detected: ${DRIFT_DETECTED_COUNT}"
134+
echo "Missing SHA: ${MISSING_SHA_COUNT}"
135+
echo ""
136+
137+
if [ ${DRIFT_DETECTED_COUNT} -gt 0 ] || [ ${MISSING_SHA_COUNT} -gt 0 ]; then
138+
echo "⚠️ ATTENTION REQUIRED: ${#DRIFTED_ROOTS[@]} root(s) need review:"
139+
for ROOT in "${DRIFTED_ROOTS[@]}"; do
140+
echo " - ${ROOT}"
141+
done
142+
echo ""
143+
echo "These roots may need to be reapplied to match the current codebase."
144+
exit 0
145+
else
146+
echo "✅ All roots are up to date!"
147+
exit 0
148+
fi

infra/modules/drift-detection/main.tf

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,23 @@ resource "aws_cloudwatch_log_group" "drift_check" {
1111
retention_in_days = 30
1212
}
1313

14+
locals {
15+
buildspec = {
16+
version = "0.2"
17+
env = {
18+
shell = "bash"
19+
}
20+
21+
phases = {
22+
build = {
23+
commands = [
24+
file("${path.module}/drift-detection.sh")
25+
]
26+
}
27+
}
28+
}
29+
}
30+
1431
resource "aws_codebuild_project" "drift_check" {
1532
#checkov:skip=CKV_AWS_147:Amazon Managed SSE is sufficient
1633
name = "drift-check-${var.deployment_name}"
@@ -20,7 +37,7 @@ resource "aws_codebuild_project" "drift_check" {
2037

2138
source {
2239
type = "NO_SOURCE"
23-
buildspec = file("${path.module}/buildspec/buildspec.yml")
40+
buildspec = jsonencode(local.buildspec)
2441
}
2542

2643
logs_config {

0 commit comments

Comments
 (0)