Files
2026-03-24 21:55:00 +01:00

26 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
02-lab-01-iam-sicurezza 01 execute 0
labs/lab-01-iam/tests/test-01-user-creation.sh
labs/lab-01-iam/tests/test-02-docker-access.sh
labs/lab-01-iam/tests/03-non-root-test.sh
labs/lab-01-iam/tests/99-final-verification.sh
labs/lab-01-iam/tests/run-all-tests.sh
true
TEST-01
TEST-05
INF-01
truths artifacts key_links
Test scripts exist and can validate user creation and Docker access
Test scripts verify non-root container execution (INF-01)
Final verification script runs all checks for student self-validation
Test harness can be executed with single command
path provides min_lines
labs/lab-01-iam/tests/test-01-user-creation.sh User and group creation validation 40
path provides min_lines
labs/lab-01-iam/tests/test-02-docker-access.sh Docker socket access control validation 30
path provides min_lines
labs/lab-01-iam/tests/03-non-root-test.sh Non-root container verification (INF-01) 35
path provides min_lines
labs/lab-01-iam/tests/99-final-verification.sh Final double-check command for students 25
path provides min_lines
labs/lab-01-iam/tests/run-all-tests.sh Test suite orchestration 15
from to via pattern
run-all-tests.sh test-01-user-creation.sh, test-02-docker-access.sh, 03-non-root-test.sh, 99-final-verification.sh Sequential execution with exit code handling bash.*tests/.*.sh
Create test infrastructure following TDD methodology (RED phase first). Test scripts validate user creation, Docker socket access control, and non-root container execution before any implementation exists.

Purpose: Enable Test-Driven Infrastructure (TDI) by writing failing tests first, then implementing infrastructure to make them pass. Output: Four test scripts (user creation, Docker access, non-root verification, final check) plus test orchestration script.

<execution_context> @/home/luca/.claude/get-shit-done/workflows/execute-plan.md @/home/luca/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-lab-01-iam-sicurezza/02-RESEARCH.md @.planning/phases/02-lab-01-iam-sicurezza/02-VALIDATION.md @CLAUDE.md

Key patterns from RESEARCH.md

TDD Methodology for Infrastructure

# RED Phase: Test should fail initially (no infrastructure exists)
# GREEN Phase: Implement minimum infrastructure to pass tests
# REFACTOR Phase: Optimize without breaking tests

# Example test structure from RESEARCH.md:
test_unauthorized_access() {
    sudo useradd -m -s /bin/bash test_user 2>/dev/null || true
    if sudo -u test_user docker ps &>/dev/null; then
        echo "FAIL: test_user can access docker without being in docker group"
        return 1
    else
        echo "PASS: test_user correctly denied access"
        return 0
    fi
}

INF-01 Verification Pattern

# From RESEARCH.md - Non-root container verification
for service in $(docker-compose ps --services); do
    container_name=$(docker-compose ps -q $service)
    actual_user=$(docker exec $container_name whoami 2>/dev/null)
    if [ "$actual_user" = "root" ]; then
        echo "FAIL: $service running as root"
        exit 1
    fi
done
echo "PASS: All containers running as non-root"

Common Pitfalls to Handle

  • Group membership requires re-login (use groups command for testing)
  • Test as non-privileged user (root bypasses Docker socket permissions)
  • Verify with multiple methods: docker exec whoami, docker inspect, docker top

Test Framework from RESEARCH.md

  • Framework: BASH (Bourne Again Shell) >= 4.0
  • No config file needed - inline test functions
  • Quick run: bash labs/lab-01-iam/tests/quick-test.sh
  • Full suite: bash labs/lab-01-iam/tests/run-all-tests.sh
Task 1: Create user creation test script labs/lab-01-iam/tests/test-01-user-creation.sh - Test 1: Non-existent user returns appropriate failure - Test 2: User not in docker group cannot access Docker socket - Test 3: User can be added to docker group - Test 4: Group membership verified with `groups` command Create test script for Linux user and group management:
#!/bin/bash
# Test: Linux user creation and Docker group membership
# Phase: RED - This test will fail initially (no users configured)

set -euo pipefail

# Color output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

pass_count=0
fail_count=0

test_user_not_exists() {
    local user="lab01_student"
    if id "$user" &>/dev/null; then
        echo -e "${YELLOW}SKIP${NC}: User $user already exists"
        return 0
    fi
    echo -e "${GREEN}PASS${NC}: User $user does not exist (test environment clean)"
    ((pass_count++))
    return 0
}

test_user_without_docker_group() {
    local user="lab01_student"
    # Create test user if doesn't exist
    if ! id "$user" &>/dev/null; then
        sudo useradd -m -s /bin/bash "$user" 2>/dev/null || true
    fi

    # Check if user is in docker group
    if groups "$user" 2>/dev/null | grep -q docker; then
        echo -e "${RED}FAIL${NC}: User $user is in docker group (should not be yet)"
        ((fail_count++))
        return 1
    fi

    echo -e "${GREEN}PASS${NC}: User $user is not in docker group"
    ((pass_count++))
    return 0
}

test_docker_access_denied() {
    local user="lab01_student"

    # Test that user cannot access docker socket
    if sudo -u "$user" docker ps &>/dev/null; then
        echo -e "${RED}FAIL${NC}: User $user can access docker without docker group membership"
        ((fail_count++))
        return 1
    fi

    echo -e "${GREEN}PASS${NC}: Docker access correctly denied for $user"
    ((pass_count++))
    return 0
}

# Run all tests
echo "Running user creation tests..."
echo "================================"
test_user_not_exists
test_user_without_docker_group
test_docker_access_denied
echo "================================"
echo "Tests passed: $pass_count"
echo "Tests failed: $fail_count"

if [ $fail_count -gt 0 ]; then
    exit 1
fi
exit 0

Key implementation points:

  • Use groups command to verify group membership (handles re-login issue)
  • Run Docker commands as test user with sudo -u
  • Test the negative case first (user without access)
  • Return proper exit codes (0=pass, 1=fail) chmod +x labs/lab-01-iam/tests/test-01-user-creation.sh && bash labs/lab-01-iam/tests/test-01-user-creation.sh Script exists, is executable, and tests user/group creation behavior
Task 2: Create Docker access control test script labs/lab-01-iam/tests/test-02-docker-access.sh - Test 1: User in docker group can execute docker ps - Test 2: User in docker group can run basic containers - Test 3: Socket permissions are correctly set (660 or stricter) - Test 4: Group membership propagation is verified Create test script for Docker socket access control:
#!/bin/bash
# Test: Docker socket access control via group membership
# Phase: RED - This test will fail initially (no users configured)

set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

pass_count=0
fail_count=0

test_socket_permissions() {
    local socket="/var/run/docker.sock"
    local perms=$(stat -c "%a" "$socket" 2>/dev/null || echo "000")

    # Socket should be 660 or stricter (no world-readable/writable)
    if [ "$perms" = "660" ] || [ "$perms" = "600" ]; then
        echo -e "${GREEN}PASS${NC}: Docker socket permissions are $perms"
        ((pass_count++))
        return 0
    else
        echo -e "${YELLOW}WARN${NC}: Docker socket permissions are $perms (expected 660)"
        ((pass_count++))
        return 0
    fi
}

test_docker_group_exists() {
    if getent group docker >/dev/null 2>&1; then
        echo -e "${GREEN}PASS${NC}: Docker group exists"
        ((pass_count++))
        return 0
    else
        echo -e "${RED}FAIL${NC}: Docker group does not exist"
        ((fail_count++))
        return 1
    fi
}

test_user_can_add_to_docker_group() {
    local user="lab01_student"

    # This test verifies the MECHANISM, not that it's done yet
    if command -v usermod >/dev/null 2>&1; then
        echo -e "${GREEN}PASS${NC}: usermod command available for group management"
        ((pass_count++))
        return 0
    else
        echo -e "${RED}FAIL${NC}: usermod command not available"
        ((fail_count++))
        return 1
    fi
}

test_docker_accessible_by_group() {
    # Check that docker group members can access the socket
    local socket_group=$(stat -c "%G" /var/run/docker.sock 2>/dev/null || echo "unknown")

    if [ "$socket_group" = "docker" ]; then
        echo -e "${GREEN}PASS${NC}: Docker socket owned by docker group"
        ((pass_count++))
        return 0
    else
        echo -e "${YELLOW}WARN${NC}: Docker socket owned by $socket_group (expected docker)"
        ((pass_count++))
        return 0
    fi
}

# Run all tests
echo "Running Docker access control tests..."
echo "======================================"
test_socket_permissions
test_docker_group_exists
test_user_can_add_to_docker_group
test_docker_accessible_by_group
echo "======================================"
echo "Tests passed: $pass_count"
echo "Tests failed: $fail_count"

if [ $fail_count -gt 0 ]; then
    exit 1
fi
exit 0

Key implementation points:

  • Verify socket ownership and permissions
  • Check docker group exists
  • Validate group management commands available
  • Test mechanism for adding users to docker group chmod +x labs/lab-01-iam/tests/test-02-docker-access.sh && bash labs/lab-01-iam/tests/test-02-docker-access.sh Script validates Docker socket access control mechanisms
Task 3: Create non-root container verification script (INF-01) labs/lab-01-iam/tests/03-non-root-test.sh - Test 1: Container configured with USER directive runs as non-root - Test 2: docker exec whoami returns non-root user - Test 3: docker inspect shows User field set - Test 4: docker top shows non-root UID (not 0) Create test script for non-root container verification (INF-01 requirement):
#!/bin/bash
# Test: Non-root container execution (INF-01 requirement)
# Phase: RED - This test will fail initially (no containers exist)

set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

pass_count=0
fail_count=0

# Container name to test
CONTAINER_NAME="lab01-test-container"

test_non_root_dockerfile_exists() {
    local dockerfile="labs/lab-01-iam/Dockerfile.test"

    if [ -f "$dockerfile" ]; then
        echo -e "${GREEN}PASS${NC}: Test Dockerfile exists"
        ((pass_count++))
        return 0
    else
        echo -e "${YELLOW}SKIP${NC}: Test Dockerfile not created yet (expected in RED phase)"
        ((pass_count++))
        return 0
    fi
}

test_container_runs_as_non_root() {
    # Check if container exists
    if ! docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
        echo -e "${YELLOW}SKIP${NC}: Container ${CONTAINER_NAME} does not exist yet (expected in RED phase)"
        ((pass_count++))
        return 0
    fi

    # Check if container is running
    if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
        echo -e "${YELLOW}SKIP${NC}: Container ${CONTAINER_NAME} not running"
        ((pass_count++))
        return 0
    fi

    # Method 1: docker exec whoami
    local actual_user=$(docker exec "${CONTAINER_NAME}" whoami 2>/dev/null || echo "unknown")

    if [ "$actual_user" = "root" ]; then
        echo -e "${RED}FAIL${NC}: Container running as root (whoami)"
        ((fail_count++))
        return 1
    elif [ "$actual_user" = "unknown" ]; then
        echo -e "${YELLOW}SKIP${NC}: Cannot determine user (container not running or no exec)"
        ((pass_count++))
        return 0
    else
        echo -e "${GREEN}PASS${NC}: Container running as non-root user: $actual_user"
        ((pass_count++))
        return 0
    fi
}

test_container_user_configured() {
    if ! docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
        echo -e "${YELLOW}SKIP${NC}: Container not created yet"
        ((pass_count++))
        return 0
    fi

    # Method 2: docker inspect for User field
    local user_config=$(docker inspect --format='{{.Config.User}}' "${CONTAINER_NAME}" 2>/dev/null || echo "")

    if [ -z "$user_config" ]; then
        # Check compose file for user directive (may override Dockerfile)
        if [ -f "labs/lab-01-iam/docker-compose.yml" ]; then
            if grep -q "user:" labs/lab-01-iam/docker-compose.yml; then
                echo -e "${GREEN}PASS${NC}: User directive found in docker-compose.yml"
                ((pass_count++))
                return 0
            fi
        fi

        echo -e "${YELLOW}WARN${NC}: No User directive found in Dockerfile or compose"
        ((pass_count++))
        return 0
    else
        echo -e "${GREEN}PASS${NC}: User configured in container: $user_config"
        ((pass_count++))
        return 0
    fi
}

test_no_container_runs_as_root() {
    # INF-01 requirement: NO container should run as root
    local compose_file="labs/lab-01-iam/docker-compose.yml"

    if [ ! -f "$compose_file" ]; then
        echo -e "${YELLOW}SKIP${NC}: docker-compose.yml not created yet"
        ((pass_count++))
        return 0
    fi

    # Get all services from compose file
    local services=$(docker-compose -f "$compose_file" ps --services 2>/dev/null || echo "")

    if [ -z "$services" ]; then
        echo -e "${YELLOW}SKIP${NC}: No services defined yet"
        ((pass_count++))
        return 0
    fi

    local root_containers=0
    while IFS= read -r service; do
        if [ -n "$service" ]; then
            local container_name=$(docker-compose -f "$compose_file" ps -q "$service" 2>/dev/null || echo "")
            if [ -n "$container_name" ]; then
                local user=$(docker exec "$container_name" whoami 2>/dev/null || echo "unknown")
                if [ "$user" = "root" ]; then
                    echo -e "${RED}FAIL${NC}: Service $service running as root"
                    ((root_containers++))
                fi
            fi
        fi
    done <<< "$services"

    if [ $root_containers -gt 0 ]; then
        echo -e "${RED}FAIL${NC}: $root_containers container(s) running as root (INF-01 violation)"
        ((fail_count++))
        return 1
    else
        echo -e "${GREEN}PASS${NC}: No containers running as root (INF-01 satisfied)"
        ((pass_count++))
        return 0
    fi
}

# Run all tests
echo "Running non-root container tests (INF-01)..."
echo "============================================"
test_non_root_dockerfile_exists
test_container_runs_as_non_root
test_container_user_configured
test_no_container_runs_as_root
echo "============================================"
echo "Tests passed: $pass_count"
echo "Tests failed: $fail_count"

if [ $fail_count -gt 0 ]; then
    exit 1
fi
exit 0

Key implementation points:

  • INF-01 requirement: NO container runs as root
  • Multiple verification methods (whoami, inspect, compose check)
  • Handle not-yet-created infrastructure gracefully (skip with warning)
  • Check all services in docker-compose.yml for compliance chmod +x labs/lab-01-iam/tests/03-non-root-test.sh && bash labs/lab-01-iam/tests/03-non-root-test.sh Script verifies INF-01: no container runs as root
Task 4: Create final verification script (double-check for students) labs/lab-01-iam/tests/99-final-verification.sh - Test 1: All previous tests can be run - Test 2: Student can verify their work end-to-end - Test 3: Clear PASS/FAIL report for all requirements - Test 4: Exit code indicates overall success/failure Create final verification script for student self-check:
#!/bin/bash
# Final Verification: Lab 01 - IAM & Sicurezza
# This is the "double check" command students run to verify their work
# Usage: bash tests/99-final-verification.sh

set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab 01 - IAM & Sicurezza${NC}"
echo -e "${BLUE}Final Verification (Double Check)${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""

# Track overall results
all_passed=true

# Test 1: User and group configuration
echo -e "${BLUE}[1/5] Checking user and group configuration...${NC}"
if id lab01_student &>/dev/null; then
    echo -e "  ${GREEN}${NC} User lab01_student exists"
    if groups lab01_student 2>/dev/null | grep -q docker; then
        echo -e "  ${GREEN}${NC} User lab01_student is in docker group"
    else
        echo -e "  ${RED}${NC} User lab01_student is NOT in docker group"
        all_passed=false
    fi
else
    echo -e "  ${YELLOW}${NC} User lab01_student does not exist (not created yet)"
    all_passed=false
fi
echo ""

# Test 2: Docker access control
echo -e "${BLUE}[2/5] Checking Docker access control...${NC}"
if sudo -u lab01_student docker ps &>/dev/null; then
    echo -e "  ${GREEN}${NC} lab01_student can access Docker socket"
else
    echo -e "  ${RED}${NC} lab01_student cannot access Docker socket"
    echo -e "  ${YELLOW}  Hint: User may need to re-login for group membership to take effect${NC}"
    all_passed=false
fi
echo ""

# Test 3: Non-root container execution (INF-01)
echo -e "${BLUE}[3/5] Checking non-root container execution (INF-01)...${NC}"
compose_file="labs/lab-01-iam/docker-compose.yml"
if [ ! -f "$compose_file" ]; then
    echo -e "  ${YELLOW}${NC} docker-compose.yml not found"
    all_passed=false
else
    echo -e "  ${GREEN}${NC} docker-compose.yml exists"

    # Check for user directive in services
    if grep -A 10 "services:" "$compose_file" | grep -q "user:"; then
        echo -e "  ${GREEN}${NC} Services configured with non-root user directive"
    else
        echo -e "  ${RED}${NC} No user directive found in docker-compose.yml"
        all_passed=false
    fi

    # If containers are running, verify they're not root
    if docker-compose -f "$compose_file" ps --services 2>/dev/null | grep -q .; then
        local root_count=0
        while IFS= read -r service; do
            [ -z "$service" ] && continue
            local container=$(docker-compose -f "$compose_file" ps -q "$service" 2>/dev/null || echo "")
            if [ -n "$container" ]; then
                local user=$(docker exec "$container" whoami 2>/dev/null || echo "unknown")
                if [ "$user" = "root" ]; then
                    echo -e "  ${RED}${NC} Service $service running as ROOT (INF-01 violation)"
                    ((root_count++))
                fi
            fi
        done <<< "$(docker-compose -f "$compose_file" ps --services 2>/dev/null)"

        if [ $root_count -eq 0 ]; then
            echo -e "  ${GREEN}${NC} All running containers are non-root"
        else
            all_passed=false
        fi
    else
        echo -e "  ${YELLOW}${NC} No containers running (start with docker-compose up)"
    fi
fi
echo ""

# Test 4: Documentation completeness (Diátaxis)
echo -e "${BLUE}[4/5] Checking documentation (Diátaxis framework)...${NC}"
doc_count=0
for doc_type in "tutorial" "how-to-guides" "reference" "explanation"; do
    if [ -d "labs/lab-01-iam/$doc_type" ]; then
        local md_files=$(find "labs/lab-01-iam/$doc_type" -name "*.md" 2>/dev/null | wc -l)
        if [ "$md_files" -gt 0 ]; then
            echo -e "  ${GREEN}${NC} $doc_type: $md_files document(s)"
            ((doc_count++))
        else
            echo -e "  ${YELLOW}${NC} $doc_type: directory exists but empty"
        fi
    else
        echo -e "  ${RED}${NC} $doc_type: missing"
    fi
done

if [ $doc_count -eq 4 ]; then
    echo -e "  ${GREEN}${NC} All 4 Diátaxis document types present"
else
    echo -e "  ${YELLOW}${NC} $doc_count/4 Diátaxis document types present"
    all_passed=false
fi
echo ""

# Test 5: IAM parallels documentation
echo -e "${BLUE}[5/5] Checking IAM parallels explanation...${NC}"
explanation_file="labs/lab-01-iam/explanation/docker-iam-parallels.md"
if [ -f "$explanation_file" ]; then
    if grep -qi "IAM.*Linux\|Linux.*IAM" "$explanation_file"; then
        echo -e "  ${GREEN}${NC} IAM parallels documented"
    else
        echo -e "  ${YELLOW}${NC} Explanation exists but IAM parallels unclear"
    fi

    if grep -qi "differenza\|difference" "$explanation_file"; then
        echo -e "  ${GREEN}${NC} Local vs cloud differences documented"
    else
        echo -e "  ${YELLOW}${NC} Local vs cloud differences not clearly documented"
    fi
else
    echo -e "  ${RED}${NC} IAM parallels explanation not found"
    all_passed=false
fi
echo ""

# Final summary
echo -e "${BLUE}========================================${NC}"
if [ "$all_passed" = true ]; then
    echo -e "${GREEN}ALL CHECKS PASSED${NC}"
    echo -e "${GREEN}Lab 01 is complete!${NC}"
    echo -e "${BLUE}========================================${NC}"
    exit 0
else
    echo -e "${RED}SOME CHECKS FAILED${NC}"
    echo -e "${YELLOW}Review the output above and complete the missing items${NC}"
    echo -e "${BLUE}========================================${NC}"
    exit 1
fi

Key implementation points:

  • Student-friendly double-check command
  • Clear visual indicators (✓ pass, ✗ fail, ○ skip)
  • Tests all phase requirements: LAB-01, INF-01, DOCT-01/02/03/04, PARA-01/03
  • Exit code 0 for all-pass, 1 for any failure
  • Helpful hints for common issues (re-login for group membership) chmod +x labs/lab-01-iam/tests/99-final-verification.sh && bash labs/lab-01-iam/tests/99-final-verification.sh Student can run single command to verify all lab requirements are met
Task 5: Create test orchestration script labs/lab-01-iam/tests/run-all-tests.sh - Test 1: Script executes all test files in sequence - Test 2: Script stops on first failure (fail-fast) - Test 3: Script aggregates results and provides summary - Test 4: Script can be run from project root Create test orchestration script:
#!/bin/bash
# Test Suite Runner: Lab 01 - IAM & Sicurezza
# Runs all tests in sequence and provides summary
# Usage: bash labs/lab-01-iam/tests/run-all-tests.sh

set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'

TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$TEST_DIR/../.." && pwd)"

cd "$PROJECT_ROOT"

echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab 01 Test Suite${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""

# Array of test files in order
declare -a tests=(
    "$TEST_DIR/test-01-user-creation.sh"
    "$TEST_DIR/test-02-docker-access.sh"
    "$TEST_DIR/03-non-root-test.sh"
)

total_tests=${#tests[@]}
passed_tests=0
failed_tests=0

for i in "${!tests[@]}"; do
    test_num=$((i + 1))
    test_file="${tests[$i]}"
    test_name=$(basename "$test_file")

    echo -e "${BLUE}[$test_num/$total_tests] Running $test_name...${NC}"

    if bash "$test_file"; then
        echo -e "${GREEN}✓ PASSED${NC}"
        echo ""
        ((passed_tests++))
    else
        echo -e "${RED}✗ FAILED${NC}"
        echo ""
        ((failed_tests++))
        # Fail-fast: stop on first failure
        break
    fi
done

# Summary
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Test Suite Summary${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Passed: $passed_tests/$total_tests"
echo "Failed: $failed_tests/$total_tests"
echo ""

if [ $failed_tests -eq 0 ]; then
    echo -e "${GREEN}All tests passed!${NC}"
    echo ""
    echo "Run final verification:"
    echo "  bash labs/lab-01-iam/tests/99-final-verification.sh"
    echo -e "${BLUE}========================================${NC}"
    exit 0
else
    echo -e "${RED}Some tests failed${NC}"
    echo -e "${BLUE}========================================${NC}"
    exit 1
fi

Key implementation points:

  • Fail-fast approach (stops on first failure for TDD RED phase)
  • Executes tests in dependency order
  • Provides summary and next steps
  • Can be run from any directory (uses absolute paths) chmod +x labs/lab-01-iam/tests/run-all-tests.sh && bash labs/lab-01-iam/tests/run-all-tests.sh Orchestration script runs all tests and provides summary
1. All test scripts are executable (chmod +x) 2. Test scripts can run individually and return proper exit codes 3. Test orchestration script executes all tests in sequence 4. Test scripts follow TDD RED phase (will fail before implementation exists) 5. All tests handle missing infrastructure gracefully (skip with warning)

<success_criteria>

  1. Test infrastructure is in place before any implementation (Wave 0 complete)
  2. All requirement IDs (TEST-01, TEST-05, INF-01) have test coverage
  3. Tests follow bash scripting best practices (set -euo pipefail, proper exit codes)
  4. Student can run individual tests or full suite
  5. Final verification script provides clear pass/fail report for all lab requirements </success_criteria>
After completion, create `.planning/phases/02-lab-01-iam-sicurezza/02-01-SUMMARY.md`