fix(ci): make the hardcoded-secret scan blocking and close the .gitignore/.sops.yaml gaps that let a plaintext deploy key through — also untracks tfplan binaries and skills-lock.json

This commit is contained in:
Story Crater Bot
2026-08-18 15:08:04 -07:00
parent 5f16f16f0f
commit 0fe3d25936
3 changed files with 49 additions and 16 deletions
+35 -13
View File
@@ -156,22 +156,44 @@ jobs:
- name: Check for Secrets in Code - name: Check for Secrets in Code
run: | run: |
echo "=== Scanning for hardcoded secrets ===" echo "=== Scanning for hardcoded secrets ==="
SECRETS_FOUND=0 # BLOCKING. This step used to only count findings and then exit 0, so a
# plaintext deploy key rode through it into a public remote. Two failure
# modes fixed: it now fails the build, and it matches key material by
# PEM header rather than only `private_key:`-style YAML field names.
# Findings are captured into variables and tested for emptiness rather than
# branching on grep's exit status: implementations disagree on the rc of a
# `-v` filter fed empty input, and a wrong rc here fails open.
# NOTE: --include must precede `--`; after `--` grep treats it as a filename
# and silently scans nothing.
FAILED=0
for pattern in "password:" "secret:" "token:" "api_key:" "apikey:" "private_key:" "privatekey:"; do # Any private key block is fatal, regardless of the field name carrying it.
if grep -r "$pattern" k8s/ --include="*.yaml" --include="*.yml" | grep -v "^Binary"; then KEYS=$(grep -rIE --include="*.yaml" --include="*.yml" \
echo "⚠️ Found potential secret pattern: $pattern" -- "-----BEGIN ([A-Z]+ )?PRIVATE KEY-----" k8s/ \
SECRETS_FOUND=$((SECRETS_FOUND + 1)) | grep -v "\.enc\.yaml" || true)
fi if [ -n "$KEYS" ]; then
done echo "❌ Unencrypted private key material found:"
echo "$KEYS"
if [ $SECRETS_FOUND -gt 0 ]; then FAILED=1
echo "⚠️ Warning: Found $SECRETS_FOUND potential secrets"
echo "Secrets should be encrypted with SOPS or stored in ArgoCD Sealed Secrets"
else
echo "✓ No hardcoded secrets found"
fi fi
# Plaintext values in secret-ish YAML fields. SOPS output is ENC[...],
# so encrypted files never trip this.
VALS=$(grep -rInE --include="*.yaml" --include="*.yml" \
-- "^[[:space:]]*(password|token|apiKey|api_key|sshPrivateKey|client_secret):[[:space:]]*[\"']?[^\"'[:space:]{\$]{8,}" k8s/ \
| grep -v "ENC\[" | grep -v "\.enc\.yaml" || true)
if [ -n "$VALS" ]; then
echo "❌ Plaintext secret value found:"
echo "$VALS"
FAILED=1
fi
if [ "$FAILED" -ne 0 ]; then
echo "Encrypt with SOPS (see .sops.yaml) — *.enc.yaml files are exempt."
exit 1
fi
echo "✓ No hardcoded secrets found"
# === Check K8s Security Best Practices === # === Check K8s Security Best Practices ===
- name: Check K8s Security Best Practices - name: Check K8s Security Best Practices
run: | run: |
+11 -2
View File
@@ -50,10 +50,19 @@ terraform/*.tfstate.*
terraform.tfvars.local terraform.tfvars.local
skills-lock.json skills-lock.json
secrets-plaintext.yaml secrets-plaintext.yaml
skills-lock.json
# Saved plan files — binary, environment-specific, may embed resource attributes
terraform/tfplan
terraform/tfplan-*
.DS_Store .DS_Store
CLAUDE.md CLAUDE.md
docs/ docs/
k8s/argocd/seed-repo-secret.yamlbootstrap-argocd.log bootstrap-argocd.log
# Any plaintext (non-SOPS) secret manifest. Encrypted ones are *.enc.yaml and
# ARE committed — see .sops.yaml. A missing newline once merged two patterns on
# one line here, which is how a plaintext deploy key reached a public remote.
k8s/**/*-secret.yaml
!k8s/**/*.enc.yaml
+3 -1
View File
@@ -1,3 +1,5 @@
creation_rules: creation_rules:
- path_regex: k8s/.*secrets.*\.ya?ml # `secrets?` — singular too. A `seed-repo-secret.yaml` once slipped this regex
# and was committed in plaintext to a public remote.
- path_regex: k8s/.*secrets?.*\.ya?ml
age: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla age: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla