243 lines
5.5 KiB
Bash
Executable File
243 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(
|
|
cd "$(dirname "${BASH_SOURCE[0]}")/.." &&
|
|
pwd
|
|
)"
|
|
|
|
cd "$ROOT"
|
|
|
|
echo "========================================"
|
|
echo " managed-container release test suite"
|
|
echo "========================================"
|
|
|
|
echo
|
|
echo ">>> Entrypoint / shell structure"
|
|
./tests/test-entrypoint-structure.sh
|
|
|
|
echo
|
|
echo ">>> Proxy protocol contract"
|
|
./tests/test-proxy-protocol.sh
|
|
|
|
echo
|
|
echo ">>> Generic proxy client actions"
|
|
python3 ./tests/test-proxy-client-actions.py
|
|
python3 ./tests/test-proxy-client-parameters.py
|
|
./tests/test-notify-daemon-shadow.sh
|
|
./tests/test-notify-target-shadow.sh
|
|
./tests/test-demote-database-shadow.sh
|
|
./tests/test-demote-database-gate.sh
|
|
|
|
echo
|
|
echo ">>> Python syntax"
|
|
|
|
while IFS= read -r -d '' file; do
|
|
python3 -m py_compile "$file"
|
|
done < <(
|
|
find ocf \
|
|
-type f \
|
|
-name '*.py' \
|
|
-print0
|
|
)
|
|
|
|
echo "PYTHON_SYNTAX_OK=1"
|
|
|
|
echo
|
|
echo ">>> Host helper shell syntax"
|
|
|
|
for file in postgres-host/*; do
|
|
[[ -f "$file" ]] || continue
|
|
|
|
case "$file" in
|
|
*.sh|*/postgres-ha-bootstrap)
|
|
bash -n "$file"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
echo "HOST_HELPER_SYNTAX_OK=1"
|
|
|
|
echo
|
|
echo ">>> Secret-content guard"
|
|
|
|
python3 - <<'PY_SECRET_GUARD'
|
|
from pathlib import Path
|
|
import re
|
|
import sys
|
|
|
|
roots = [Path("quadlet"), Path("postgres-host")]
|
|
|
|
credential_key = re.compile(
|
|
r'^[A-Z0-9_]*(?:PASSWORD|PASSWD|SECRET|TOKEN)[A-Z0-9_]*$'
|
|
)
|
|
|
|
private_key = re.compile(
|
|
r'-----BEGIN (?:OPENSSH|RSA|EC|DSA) PRIVATE KEY-----'
|
|
)
|
|
|
|
errors = []
|
|
|
|
for root in roots:
|
|
if not root.exists():
|
|
continue
|
|
|
|
for path in root.rglob("*"):
|
|
if not path.is_file():
|
|
continue
|
|
|
|
try:
|
|
text = path.read_text(errors="replace")
|
|
except Exception as exc:
|
|
errors.append(f"{path}: unable to read: {exc}")
|
|
continue
|
|
|
|
if private_key.search(text):
|
|
errors.append(f"{path}: contains private-key material")
|
|
|
|
for lineno, raw in enumerate(text.splitlines(), 1):
|
|
line = raw.strip()
|
|
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
|
|
# Only inspect configuration-style assignments whose KEY itself
|
|
# is uppercase and explicitly credential-related.
|
|
m = re.match(
|
|
r'^([A-Z][A-Z0-9_]*)\s*=\s*(.*)$',
|
|
line
|
|
)
|
|
|
|
if not m:
|
|
continue
|
|
|
|
key, value = m.groups()
|
|
|
|
if not credential_key.match(key):
|
|
continue
|
|
|
|
value = value.strip()
|
|
|
|
# Empty values are not embedded credentials.
|
|
if not value:
|
|
continue
|
|
|
|
# References, secret-file paths, templates and placeholders
|
|
# are acceptable.
|
|
safe_prefixes = (
|
|
"$",
|
|
"${",
|
|
"/run/secrets/",
|
|
"/etc/",
|
|
"<",
|
|
"CHANGE_ME",
|
|
)
|
|
|
|
unquoted = value.strip("'\"")
|
|
|
|
if value.startswith(safe_prefixes) or unquoted.startswith(safe_prefixes):
|
|
continue
|
|
|
|
errors.append(
|
|
f"{path}:{lineno}: possible literal credential assignment: {key}=..."
|
|
)
|
|
|
|
if errors:
|
|
for error in errors:
|
|
print(error, file=sys.stderr)
|
|
|
|
print(
|
|
"ERROR: possible embedded credential material found",
|
|
file=sys.stderr
|
|
)
|
|
sys.exit(1)
|
|
|
|
print("SECRET_GUARD_OK=1")
|
|
PY_SECRET_GUARD
|
|
|
|
echo
|
|
echo ">>> Checksum manifest"
|
|
|
|
if [[ ! -f checksums/SHA256SUMS ]]; then
|
|
echo "ERROR: checksums/SHA256SUMS is missing" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -Eq '\.pre-|\.new($|[[:space:]])' checksums/SHA256SUMS; then
|
|
echo "ERROR: checksum manifest contains development artifacts" >&2
|
|
exit 1
|
|
fi
|
|
|
|
while read -r expected file; do
|
|
[[ -n "${expected:-}" && -n "${file:-}" ]] || continue
|
|
|
|
if [[ ! -f "$file" ]]; then
|
|
echo "ERROR: checksum target is missing: $file" >&2
|
|
exit 1
|
|
fi
|
|
|
|
actual="$(sha256sum "$file" | awk '{print $1}')"
|
|
|
|
if [[ "$actual" != "$expected" ]]; then
|
|
echo "ERROR: checksum mismatch: $file" >&2
|
|
echo " expected=$expected" >&2
|
|
echo " actual=$actual" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! git ls-files --error-unmatch "$file" >/dev/null 2>&1; then
|
|
echo "ERROR: checksum manifest references untracked file: $file" >&2
|
|
exit 1
|
|
fi
|
|
done < checksums/SHA256SUMS
|
|
|
|
expected_release_files="$(
|
|
git ls-files \
|
|
ocf \
|
|
postgres-host \
|
|
quadlet \
|
|
tests \
|
|
pacemaker/README.md |
|
|
while IFS= read -r file; do
|
|
case "$file" in
|
|
checksums/SHA256SUMS|quadlet/postgres.env)
|
|
continue
|
|
;;
|
|
esac
|
|
printf '%s\n' "$file"
|
|
done |
|
|
LC_ALL=C sort
|
|
)"
|
|
|
|
manifest_release_files="$(
|
|
awk '{ $1=""; sub(/^[[:space:]]+/, ""); print }' \
|
|
checksums/SHA256SUMS |
|
|
LC_ALL=C sort
|
|
)"
|
|
|
|
if [[ "$manifest_release_files" != "$expected_release_files" ]]; then
|
|
echo "ERROR: checksum manifest is not a complete release inventory" >&2
|
|
|
|
echo >&2
|
|
echo "--- missing from manifest ---" >&2
|
|
comm -23 \
|
|
<(printf '%s\n' "$expected_release_files") \
|
|
<(printf '%s\n' "$manifest_release_files") \
|
|
>&2 || true
|
|
|
|
echo >&2
|
|
echo "--- unexpected in manifest ---" >&2
|
|
comm -13 \
|
|
<(printf '%s\n' "$expected_release_files") \
|
|
<(printf '%s\n' "$manifest_release_files") \
|
|
>&2 || true
|
|
|
|
exit 1
|
|
fi
|
|
|
|
echo "CHECKSUM_MANIFEST_COMPLETE=1"
|
|
echo "CHECKSUM_MANIFEST_OK=1"
|
|
|
|
echo
|
|
echo "ALL_TESTS_PASS=1"
|