#!/bin/bash # Final Verification: Lab 02 - Network & VPC # Comprehensive end-to-end verification for students (double-check command) # Usage: bash labs/lab-02-network/tests/99-final-verification.sh set -euo pipefail # Color definitions RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # Get script directory TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$TEST_DIR/../.." && pwd)" LAB_DIR="$PROJECT_ROOT/labs/lab-02-network" # Counter helpers pass_count=0 fail_count=0 warn_count=0 inc_pass() { ((pass_count++)) || true; } inc_fail() { ((fail_count++)) || true; } inc_warn() { ((warn_count++)) || true; } # Helper functions print_header() { echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║${NC} ${BOLD}$1${NC}" echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}" } print_section() { echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" } print_pass() { echo -e " ${GREEN}[✓]${NC} $1" inc_pass } print_fail() { echo -e " ${RED}[✗]${NC} $1" inc_fail } print_warn() { echo -e " ${YELLOW}[!]${NC} $1" inc_warn } print_info() { echo -e " ${BLUE}[i]${NC} $1" } # Main header clear print_header "Lab 02: Network & VPC - Final Verification" echo "" echo -e "This script verifies your entire Lab 02 implementation." echo -e "Run this after completing all tutorials to double-check your work." echo "" # Verify Docker is available print_section "0. Environment Check" if ! command -v docker &> /dev/null; then echo -e "${RED}ERROR: Docker is not installed or not in PATH${NC}" exit 1 fi echo -e "Docker version: $(docker --version | cut -d' ' -f3)" echo -e "Docker Compose version: $(docker compose version | grep 'Docker Compose' | cut -d' ' -f4)" # Test 1: Network Creation print_section "1. Network Creation Verification" COMPOSE_FILE="$LAB_DIR/docker-compose.yml" if [[ ! -f "$COMPOSE_FILE" ]]; then print_fail "docker-compose.yml not found at $COMPOSE_FILE" print_info "Expected output of Tutorial 1" FAIL_REASON="compose_missing" else print_pass "docker-compose.yml exists" # Validate compose syntax if docker compose -f "$COMPOSE_FILE" config &> /dev/null; then print_pass "docker-compose.yml has valid syntax" else print_fail "docker-compose.yml has syntax errors" print_info "Run: docker compose -f docker-compose.yml config" FAIL_REASON="compose_invalid" fi fi # Test 2: Network Topology print_section "2. Network Topology Verification" if [[ "${FAIL_REASON:-}" == "compose_missing" ]]; then print_warn "Skipping network tests - compose file missing" else # Check for custom networks NETWORKS=$(docker compose -f "$COMPOSE_FILE" config --format json 2>/dev/null | grep -o '"networks"' | wc -l || echo "0") if [[ $NETWORKS -gt 0 ]]; then print_pass "Custom networks defined in docker-compose.yml" # List networks echo "" print_info "Networks defined:" docker compose -f "$COMPOSE_FILE" config --format json 2>/dev/null | \ grep -A 3 '"networks"' | grep -E '^\s+"[a-z]+"' | sed 's/.*"\([^"]*\)".*/ \1/' || echo " (unable to list)" else print_warn "No custom networks found - using default bridge" fi # Check for VPC-style naming (PARA-02 requirement) VPC_NAMES=$(grep -E 'vpc-|subnet-|network-' "$COMPOSE_FILE" 2>/dev/null | wc -l || echo "0") if [[ $VPC_NAMES -gt 0 ]]; then print_pass "Uses VPC-style naming convention (PARA-02 compliant)" else print_warn "VPC-style naming not found (recommended: vpc-main, subnet-public, etc.)" fi fi # Test 3: INF-02 Compliance print_section "3. INF-02 Security Compliance" if [[ -f "$COMPOSE_FILE" ]]; then # Check for 0.0.0.0 bindings ZERO_BINDINGS=$(grep -c -E '0\.0\.0\.0:[0-9]+' "$COMPOSE_FILE" 2>/dev/null || echo "0") if [[ $ZERO_BINDINGS -eq 0 ]]; then print_pass "No 0.0.0.0 port bindings found (INF-02 compliant)" else print_fail "Found $ZERO_BINDINGS 0.0.0.0 port bindings - VIOLATES INF-02" print_info "Private networks must not expose ports on 0.0.0.0" FAIL_REASON="inf02_violation" fi # Check for localhost bindings LOCALHOST_BINDINGS=$(grep -c -E '127\.0\.0\.1:[0-9]+' "$COMPOSE_FILE" 2>/dev/null || echo "0") if [[ $LOCALHOST_BINDINGS -gt 0 ]]; then print_pass "Found $LOCALHOST_BINDINGS service(s) with 127.0.0.1 binding (secure)" else print_info "No 127.0.0.1 bindings - services may have no published ports" fi # Check for host networking HOST_NET=$(grep -c -E 'network_mode:\s*host' "$COMPOSE_FILE" 2>/dev/null || echo "0") if [[ $HOST_NET -eq 0 ]]; then print_pass "No services using host networking mode" else print_fail "Found services using 'network_mode: host' - security risk" FAIL_REASON="host_networking" fi else print_warn "Skipping INF-02 tests - compose file missing" fi # Test 4: Service Startup print_section "4. Service Startup Verification" if [[ -f "$COMPOSE_FILE" && "${FAIL_REASON:-}" != "compose_invalid" ]]; then print_info "Attempting to start services..." if docker compose -f "$COMPOSE_FILE" up -d &> /dev/null; then print_pass "Services started successfully" # List running services echo "" print_info "Running services:" docker compose -f "$COMPOSE_FILE" ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null || \ docker compose -f "$COMPOSE_FILE" ps # Cleanup print_info "Stopping services..." docker compose -f "$COMPOSE_FILE" down &> /dev/null else print_fail "Services failed to start" print_info "Run: docker compose -f docker-compose.yml up" print_info "Check logs: docker compose -f docker-compose.yml logs" FAIL_REASON="services_failed" fi else print_warn "Skipping service tests - compose file missing or invalid" fi # Test 5: Documentation Completeness print_section "5. Documentation Completeness (Diátxis Framework)" DOC_COUNT=0 DOC_FILES=( "$LAB_DIR/tutorial/01-create-networks.md" "$LAB_DIR/tutorial/02-deploy-containers.md" "$LAB_DIR/tutorial/03-verify-isolation.md" "$LAB_DIR/how-to-guides/*.md" "$LAB_DIR/reference/*.md" "$LAB_DIR/explanation/*.md" ) for file_pattern in "${DOC_FILES[@]}"; do count=$(ls $file_pattern 2>/dev/null | wc -l) DOC_COUNT=$((DOC_COUNT + count)) done if [[ $DOC_COUNT -ge 10 ]]; then print_pass "Documentation complete: $DOC_COUNT files found (Framework Diátaxis)" echo "" print_info "Documentation breakdown:" echo -e " Tutorials: $(ls "$LAB_DIR/tutorial"/*.md 2>/dev/null | wc -l)" echo -e " How-to Guides: $(ls "$LAB_DIR/how-to-guides"/*.md 2>/dev/null | wc -l)" echo -e " Reference: $(ls "$LAB_DIR/reference"/*.md 2>/dev/null | wc -l)" echo -e " Explanation: $(ls "$LAB_DIR/explanation"/*.md 2>/dev/null | wc -l)" else print_warn "Documentation incomplete: $DOC_COUNT files found (expected 10+)" print_info "Complete all tutorials and documentation" fi # Test 6: Test Infrastructure print_section "6. Test Infrastructure Verification" TEST_FILES=( "$TEST_DIR/01-network-creation-test.sh" "$TEST_DIR/02-isolation-verification-test.sh" "$TEST_DIR/03-inf02-compliance-test.sh" "$TEST_DIR/run-all-tests.sh" ) TESTS_FOUND=0 for test_file in "${TEST_FILES[@]}"; do if [[ -f "$test_file" && -x "$test_file" ]]; then ((TESTS_FOUND++)) || true fi done if [[ $TESTS_FOUND -eq ${#TEST_FILES[@]} ]]; then print_pass "All test scripts present and executable" elif [[ $TESTS_FOUND -gt 0 ]]; then print_warn "Some test scripts missing: $TESTS_FOUND/${#TEST_FILES[@]} found" else print_fail "Test infrastructure not found" fi # Final Summary print_section "Final Summary" echo "" echo -e " ${BOLD}Results:${NC}" echo -e " ${GREEN}✓ Passed:${NC} $pass_count" if [[ $fail_count -gt 0 ]]; then echo -e " ${RED}✗ Failed:${NC} $fail_count" fi if [[ $warn_count -gt 0 ]]; then echo -e " ${YELLOW}! Warnings:${NC} $warn_count" fi echo "" # Overall verdict if [[ $fail_count -eq 0 && $warn_count -eq 0 ]]; then echo -e "${GREEN}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}${BOLD}║ ✓ ALL CHECKS PASSED ║${NC}" echo -e "${GREEN}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "${GREEN}Your Lab 02 implementation is complete and compliant!${NC}" echo "" echo -e "Next steps:" echo -e " 1. Review the Explanation document to understand VPC parallels" echo -e " 2. Proceed to Phase 4: Lab 03 - Compute & EC2" echo "" exit 0 elif [[ $fail_count -eq 0 ]]; then echo -e "${YELLOW}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${YELLOW}${BOLD}║ ! PASSED WITH WARNINGS ║${NC}" echo -e "${YELLOW}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "${YELLOW}Implementation is functional but has warnings.${NC}" echo "" echo -e "Recommendations:" if [[ $VPC_NAMES -eq 0 ]]; then echo -e " - Consider using VPC-style naming (vpc-main, subnet-public, subnet-private)" fi if [[ $DOC_COUNT -lt 10 ]]; then echo -e " - Complete all documentation files (Diátxis Framework)" fi echo "" exit 0 else echo -e "${RED}${BOLD}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${RED}${BOLD}║ ✗ VERIFICATION FAILED ║${NC}" echo -e "${RED}${BOLD}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "${RED}Some checks failed. Please review the issues above.${NC}" echo "" # Provide specific guidance case "${FAIL_REASON:-}" in compose_missing) echo -e "${YELLOW}To fix:${NC} Complete Tutorial 1 to create docker-compose.yml" ;; compose_invalid) echo -e "${YELLOW}To fix:${NC} Validate and fix docker-compose.yml syntax" echo -e " Run: docker compose -f docker-compose.yml config" ;; inf02_violation) echo -e "${YELLOW}To fix:${NC} Replace 0.0.0.0 bindings with 127.0.0.1" echo -e " Change: '8080:80' → '127.0.0.1:8080:80'" ;; services_failed) echo -e "${YELLOW}To fix:${NC} Check service logs for errors" echo -e " Run: docker compose -f docker-compose.yml logs" ;; *) echo -e "${YELLOW}To fix:${NC} Review the failed items above and complete the tutorials" ;; esac echo "" echo -e "After fixing, run this verification again:" echo -e " ${CYAN}bash labs/lab-02-network/tests/99-final-verification.sh${NC}" echo "" exit 1 fi