Skip to content

Commit 666ccea

Browse files
committed
Science Commit 5.
1 parent 9f84859 commit 666ccea

7 files changed

Lines changed: 198 additions & 0 deletions

.idea/easycode.ignore

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/easycode/codebase-v2.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bash/Config.Password.Scan.sh

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Config.Password.Scan.sh
4+
# =========================
5+
# MEARVK LLC — NitroWebExpress™
6+
#
7+
# Scans all configuration-style files in the project (*.xml, *.properties,
8+
# *.conf, *.cfg, *.ini, *.yml, *.yaml, *.json, *.env) for password / secret /
9+
# credential fields that contain a *non-default* value — i.e. a real,
10+
# hardcoded secret rather than a placeholder, empty value, or an indirection
11+
# (password-env, credentials-file, etc.) that points elsewhere for the
12+
# real secret.
13+
#
14+
# Usage:
15+
# bash/Config.Password.Scan.sh # scan and print report only
16+
# bash/Config.Password.Scan.sh --update-gitignore # also add flagged files
17+
# to .gitignore
18+
#
19+
# Exit codes:
20+
# 0 = no non-default passwords found
21+
# 1 = one or more non-default passwords found (see report)
22+
#
23+
set -uo pipefail
24+
25+
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
26+
cd "$PROJECT_ROOT" || exit 2
27+
28+
GITIGNORE="$PROJECT_ROOT/.gitignore"
29+
UPDATE_GITIGNORE=false
30+
[[ "${1:-}" == "--update-gitignore" ]] && UPDATE_GITIGNORE=true
31+
32+
# ─────────────────────────────────────────────────────────────────────────
33+
# Directories to skip entirely (build output, VCS internals, IDE metadata)
34+
# ─────────────────────────────────────────────────────────────────────────
35+
PRUNE_DIRS=(
36+
"*/target/*"
37+
"*/build/*"
38+
"*/out/*"
39+
"*/.git/*"
40+
"*/.idea/*"
41+
"*/.vscode/*"
42+
"*/node_modules/*"
43+
)
44+
45+
# ─────────────────────────────────────────────────────────────────────────
46+
# File extensions considered "configuration" files
47+
# ─────────────────────────────────────────────────────────────────────────
48+
CONFIG_GLOBS=(
49+
"*.xml" "*.properties" "*.conf" "*.cfg" "*.ini"
50+
"*.yml" "*.yaml" "*.json" "*.env"
51+
)
52+
53+
# ─────────────────────────────────────────────────────────────────────────
54+
# Keys that indicate a credential field
55+
# ─────────────────────────────────────────────────────────────────────────
56+
KEY_PATTERN='(password|passwd|pwd|secret|api[_-]?key|access[_-]?key|private[_-]?key|auth[_-]?token|client[_-]?secret)'
57+
58+
# ─────────────────────────────────────────────────────────────────────────
59+
# Values considered "default" / safe / not a real leaked secret.
60+
# Matched case-insensitively against the captured value.
61+
# ─────────────────────────────────────────────────────────────────────────
62+
DEFAULT_VALUE_PATTERN='^(|changeit|change_me|changeme|replace_me|your_api_key_here|your_cx_here|xxxxx*|password|secret|todo|n\/a|none)$'
63+
64+
# Keys that are *indirections* to a real secret stored elsewhere
65+
# (env var name, path to a credentials file, etc.) — not the secret itself.
66+
INDIRECTION_KEY_PATTERN='(password-env|credentials-file|secret-file|password-file)'
67+
68+
echo "══════════════════════════════════════════════════════════════════════"
69+
echo " Config Password Scan — MEARVK LLC NitroWebExpress™"
70+
echo " Root: $PROJECT_ROOT"
71+
echo "══════════════════════════════════════════════════════════════════════"
72+
73+
# Build the prune expression for `find`
74+
find_prune_expr=()
75+
for d in "${PRUNE_DIRS[@]}"; do
76+
find_prune_expr+=( -path "$d" -o )
77+
done
78+
unset 'find_prune_expr[${#find_prune_expr[@]}-1]' # drop trailing -o
79+
80+
# Build the name expression for `find`
81+
find_name_expr=()
82+
for g in "${CONFIG_GLOBS[@]}"; do
83+
find_name_expr+=( -name "$g" -o )
84+
done
85+
unset 'find_name_expr[${#find_name_expr[@]}-1]' # drop trailing -o
86+
87+
mapfile -d '' -t FILES < <(
88+
find "$PROJECT_ROOT" \
89+
\( "${find_prune_expr[@]}" \) -prune -o \
90+
\( "${find_name_expr[@]}" \) -type f -print0 2>/dev/null
91+
)
92+
93+
declare -a FLAGGED_FILES=()
94+
TOTAL_HITS=0
95+
96+
for f in "${FILES[@]}"; do
97+
rel="${f#"$PROJECT_ROOT"/}"
98+
99+
# Read line by line looking for key/value pairs in XML, properties, JSON, etc.
100+
while IFS= read -r line_no_and_content; do
101+
line_no="${line_no_and_content%%:*}"
102+
content="${line_no_and_content#*:}"
103+
104+
# Skip indirection keys (password-env, credentials-file, ...)
105+
if echo "$content" | grep -qiE "$INDIRECTION_KEY_PATTERN"; then
106+
continue
107+
fi
108+
109+
# Extract candidate value depending on format:
110+
# XML: <password>VALUE</password>
111+
# properties: key.password=VALUE
112+
# JSON/YAML: "password": "VALUE" or password: VALUE
113+
value=""
114+
115+
if [[ "$content" =~ \<[A-Za-z0-9_-]*($KEY_PATTERN)[A-Za-z0-9_-]*\>([^\<]*)\< ]]; then
116+
value="${BASH_REMATCH[3]}"
117+
elif [[ "$content" =~ [\"\']?[A-Za-z0-9_.-]*($KEY_PATTERN)[A-Za-z0-9_.-]*[\"\']?[[:space:]]*[:=][[:space:]]*[\"\']?([^\"\',}]*) ]]; then
118+
value="${BASH_REMATCH[3]}"
119+
else
120+
continue
121+
fi
122+
123+
# Trim whitespace
124+
value="$(echo -n "$value" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
125+
126+
# Skip if value matches a known default/placeholder pattern
127+
if echo "$value" | grep -qiE "$DEFAULT_VALUE_PATTERN"; then
128+
continue
129+
fi
130+
131+
# Skip empty values (already covered above but double-guard)
132+
[[ -z "$value" ]] && continue
133+
134+
echo " [FOUND] $rel:$line_no -> ${content#"${content%%[![:space:]]*}"}"
135+
FLAGGED_FILES+=("$rel")
136+
TOTAL_HITS=$((TOTAL_HITS + 1))
137+
138+
done < <(grep -nEi "$KEY_PATTERN" "$f" 2>/dev/null)
139+
done
140+
141+
echo "──────────────────────────────────────────────────────────────────────"
142+
echo " Total non-default password/secret hits: $TOTAL_HITS"
143+
echo " Distinct files flagged: $(printf '%s\n' "${FLAGGED_FILES[@]}" | sort -u | wc -l)"
144+
echo "══════════════════════════════════════════════════════════════════════"
145+
146+
if [[ "$TOTAL_HITS" -eq 0 ]]; then
147+
echo "No non-default passwords found. Nothing to do."
148+
exit 0
149+
fi
150+
151+
# De-duplicate flagged files
152+
mapfile -t UNIQUE_FLAGGED < <(printf '%s\n' "${FLAGGED_FILES[@]}" | sort -u)
153+
154+
if [[ "$UPDATE_GITIGNORE" == true ]]; then
155+
echo
156+
echo "Updating .gitignore with flagged files..."
157+
158+
{
159+
echo ""
160+
echo "### Config files with non-default passwords (auto-detected by bash/Config.Password.Scan.sh) ###"
161+
for rel in "${UNIQUE_FLAGGED[@]}"; do
162+
if ! grep -qxF "$rel" "$GITIGNORE" 2>/dev/null; then
163+
echo "$rel"
164+
fi
165+
done
166+
} >> "$GITIGNORE"
167+
168+
echo "Done. .gitignore updated with $(echo "${#UNIQUE_FLAGGED[@]}") candidate file(s)."
169+
echo "NOTE: Files already tracked by git must also be removed from the index:"
170+
echo " git rm --cached <file>"
171+
else
172+
echo
173+
echo "Flagged files (not yet added to .gitignore — rerun with --update-gitignore):"
174+
for rel in "${UNIQUE_FLAGGED[@]}"; do
175+
echo " $rel"
176+
done
177+
fi
178+
179+
exit 1
3.39 MB
Loading
3.19 MB
Loading
3.48 MB
Loading
2.95 MB
Loading

0 commit comments

Comments
 (0)