docs(02): create phase 2 plans (3 plans)

This commit is contained in:
Luca Sacchi Ricciardi
2026-03-24 21:55:00 +01:00
parent 385f854581
commit 87dbdb4f93
4 changed files with 3161 additions and 2 deletions

View File

@@ -12,7 +12,7 @@
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Setup & Git Foundation | 0/2 | Planning complete | - |
| 2. Lab 01 - IAM & Sicurezza | 0/3 | Not started | - |
| 2. Lab 01 - IAM & Sicurezza | 0/3 | Planning complete | - |
| 3. Lab 02 - Network & VPC | 0/3 | Not started | - |
| 4. Lab 03 - Compute & EC2 | 0/3 | Not started | - |
| 5. Lab 04 - Storage & S3 | 0/3 | Not started | - |
@@ -80,7 +80,11 @@
4. Lab include Tutorial passo-passo, How-to Guides, Reference, e Explanation (Framework Diátaxis completo)
5. Studente può eseguire comando di verifica finale ("double check") per validare il lavoro svolto
**Plans:** TBD
**Plans:** 3
- [ ] [02-01-PLAN.md](.planning/phases/02-lab-01-iam-sicurezza/02-01-PLAN.md) — Create test infrastructure (Wave 0: test-01-user-creation.sh, test-02-docker-access.sh, 03-non-root-test.sh, 99-final-verification.sh, run-all-tests.sh)
- [ ] [02-02-PLAN.md](.planning/phases/02-lab-01-iam-sicurezza/02-02-PLAN.md) — Create Diátaxis documentation (Tutorial: 3 parts, How-to Guides: 3 guides, Reference: 3 documents, Explanation: IAM parallels)
- [ ] [02-03-PLAN.md](.planning/phases/02-lab-01-iam-sicurezza/02-03-PLAN.md) — Create infrastructure (Dockerfile with non-root user, docker-compose.yml with user directive, infrastructure verification)
---

View File

@@ -0,0 +1,808 @@
---
phase: 02-lab-01-iam-sicurezza
plan: 01
type: execute
wave: 0
depends_on: []
files_modified:
- 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
autonomous: true
requirements: [TEST-01, TEST-05, INF-01]
user_setup: []
must_haves:
truths:
- "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"
artifacts:
- path: "labs/lab-01-iam/tests/test-01-user-creation.sh"
provides: "User and group creation validation"
min_lines: 40
- path: "labs/lab-01-iam/tests/test-02-docker-access.sh"
provides: "Docker socket access control validation"
min_lines: 30
- path: "labs/lab-01-iam/tests/03-non-root-test.sh"
provides: "Non-root container verification (INF-01)"
min_lines: 35
- path: "labs/lab-01-iam/tests/99-final-verification.sh"
provides: "Final double-check command for students"
min_lines: 25
- path: "labs/lab-01-iam/tests/run-all-tests.sh"
provides: "Test suite orchestration"
min_lines: 15
key_links:
- from: "run-all-tests.sh"
to: "test-01-user-creation.sh, test-02-docker-access.sh, 03-non-root-test.sh, 99-final-verification.sh"
via: "Sequential execution with exit code handling"
pattern: "bash.*tests/.*\\.sh"
---
<objective>
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.
</objective>
<execution_context>
@/home/luca/.claude/get-shit-done/workflows/execute-plan.md
@/home/luca/.claude/get-shit-done/templates/summary.md
</execution_context>
<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
```bash
# 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
```bash
# 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`
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Create user creation test script</name>
<files>labs/lab-01-iam/tests/test-01-user-creation.sh</files>
<behavior>
- 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
</behavior>
<action>
Create test script for Linux user and group management:
```bash
#!/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)
</action>
<verify>
<automated>chmod +x labs/lab-01-iam/tests/test-01-user-creation.sh && bash labs/lab-01-iam/tests/test-01-user-creation.sh</automated>
</verify>
<done>Script exists, is executable, and tests user/group creation behavior</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Create Docker access control test script</name>
<files>labs/lab-01-iam/tests/test-02-docker-access.sh</files>
<behavior>
- 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
</behavior>
<action>
Create test script for Docker socket access control:
```bash
#!/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
</action>
<verify>
<automated>chmod +x labs/lab-01-iam/tests/test-02-docker-access.sh && bash labs/lab-01-iam/tests/test-02-docker-access.sh</automated>
</verify>
<done>Script validates Docker socket access control mechanisms</done>
</task>
<task type="auto" tdd="true">
<name>Task 3: Create non-root container verification script (INF-01)</name>
<files>labs/lab-01-iam/tests/03-non-root-test.sh</files>
<behavior>
- 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)
</behavior>
<action>
Create test script for non-root container verification (INF-01 requirement):
```bash
#!/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
</action>
<verify>
<automated>chmod +x labs/lab-01-iam/tests/03-non-root-test.sh && bash labs/lab-01-iam/tests/03-non-root-test.sh</automated>
</verify>
<done>Script verifies INF-01: no container runs as root</done>
</task>
<task type="auto" tdd="true">
<name>Task 4: Create final verification script (double-check for students)</name>
<files>labs/lab-01-iam/tests/99-final-verification.sh</files>
<behavior>
- 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
</behavior>
<action>
Create final verification script for student self-check:
```bash
#!/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)
</action>
<verify>
<automated>chmod +x labs/lab-01-iam/tests/99-final-verification.sh && bash labs/lab-01-iam/tests/99-final-verification.sh</automated>
</verify>
<done>Student can run single command to verify all lab requirements are met</done>
</task>
<task type="auto" tdd="true">
<name>Task 5: Create test orchestration script</name>
<files>labs/lab-01-iam/tests/run-all-tests.sh</files>
<behavior>
- 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
</behavior>
<action>
Create test orchestration script:
```bash
#!/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)
</action>
<verify>
<automated>chmod +x labs/lab-01-iam/tests/run-all-tests.sh && bash labs/lab-01-iam/tests/run-all-tests.sh</automated>
</verify>
<done>Orchestration script runs all tests and provides summary</done>
</task>
</tasks>
<verification>
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)
</verification>
<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>
<output>
After completion, create `.planning/phases/02-lab-01-iam-sicurezza/02-01-SUMMARY.md`
</output>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,504 @@
---
phase: 02-lab-01-iam-sicurezza
plan: 03
type: execute
wave: 2
depends_on: [02-01, 02-02]
files_modified:
- labs/lab-01-iam/Dockerfile
- labs/lab-01-iam/docker-compose.yml
- labs/lab-01-iam/tests/04-verify-infrastructure.sh
autonomous: true
requirements: [LAB-01, INF-01, TEST-01]
user_setup: []
must_haves:
truths:
- "docker-compose.yml defines services with non-root user directive (INF-01)"
- "Dockerfile creates non-root user and switches before CMD (INF-01)"
- "Test scripts validate non-root execution (INF-01)"
- "Infrastructure follows test-driven approach (GREEN phase of TDI)"
artifacts:
- path: "labs/lab-01-iam/Dockerfile"
provides: "Non-root container image definition"
min_lines: 15
- path: "labs/lab-01-iam/docker-compose.yml"
provides: "Service orchestration with user directive"
min_lines: 20
- path: "labs/lab-01-iam/tests/04-verify-infrastructure.sh"
provides: "Infrastructure verification script"
min_lines: 25
key_links:
- from: "docker-compose.yml"
to: "Dockerfile"
via: "build context and image reference"
pattern: "build:.*\\..*Dockerfile"
- from: "tests/04-verify-infrastructure.sh"
to: "docker-compose.yml, Dockerfile"
via: "Infrastructure validation"
pattern: "docker-compose.*-f.*docker-compose.yml"
---
<objective>
Create Docker infrastructure (Dockerfile and docker-compose.yml) that implements non-root container execution (INF-01). Following TDD methodology, infrastructure is created AFTER tests exist, and tests should now pass (GREEN phase).
Purpose: Implement minimum infrastructure to satisfy LAB-01 and INF-01 requirements while ensuring all containers run as non-root.
Output: Dockerfile with non-root user, docker-compose.yml with user directive, and infrastructure verification test.
</objective>
<execution_context>
@/home/luca/.claude/get-shit-done/workflows/execute-plan.md
@/home/luca/.claude/get-shit-done/templates/summary.md
</execution_context>
<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
# From RESEARCH.md - Non-Root Container Pattern
```dockerfile
# Source: Docker security best practices
FROM alpine:3.19
# Create non-root user with specific UID/GID for consistency
RUN addgroup -g 1000 appgroup && \
adduser -D -u 1000 -G appgroup appuser
# Switch to non-root user BEFORE any operations
USER appuser
# Verify non-root execution
CMD ["sh", "-c", "echo 'Running as:' && whoami"]
```
```yaml
# docker-compose.yml with user directive
services:
test-container:
image: alpine:3.19
user: "1000:1000" # UID:GID for non-root
command: ["sh", "-c", "whoami && sleep 3600"]
```
# From RESEARCH.md - Verification Methods
```bash
# Method 1: Execute whoami inside container
docker exec <container_name> whoami
# Expected output: appuser (NOT root)
# Method 2: Inspect container configuration
docker inspect <container_name> --format='{{.State.User}}'
# Method 3: Check process on host
docker top <container_name>
# Look at USER column - should show UID (e.g., 1000), NOT 0 (root)
```
# Common Pitfalls to Avoid
- Running containers as root (violates INF-01)
- Using `--privileged` flag (defeats container isolation)
- Skipping verification of non-root execution
- Forgetting `user:` directive in docker-compose.yml
# TDD Methodology - GREEN Phase
Now that tests exist (Wave 0), implement MINIMUM infrastructure to make them pass:
1. docker-compose.yml with `user:` directive
2. Dockerfile with `USER` directive
3. Run tests to verify GREEN phase
4. Do NOT over-engineer - minimum to pass tests is sufficient
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Create Dockerfile with non-root user</name>
<files>labs/lab-01-iam/Dockerfile</files>
<behavior>
- Base image: alpine:3.19 (small, secure)
- Creates non-root user with UID/GID 1000
- Switches to non-root user with USER directive
- CMD demonstrates non-root execution with whoami
- Follows INF-01 requirement (no root execution)
</behavior>
<action>
Create Dockerfile that implements non-root container execution:
```dockerfile
# Lab 01 - IAM & Sicurezza
# Dockerfile per container non-root (INF-01 requirement)
#
# Questo Dockerfile dimostra come creare un container che gira
# come utente non-root, seguendo il principio del minimo privilegio.
FROM alpine:3.19
# Label per metadata
LABEL maintainer="Lab 01 - IAM & Sicurezza"
LABEL description="Container non-root per dimostrare permessi IAM"
LABEL version="1.0"
# Crea utente non-root con UID/GID specifici per consistenza
# UID 1000 e GID 1000 sono comuni per utenti non-root
RUN addgroup -g 1000 labuser && \
adduser -D -u 1000 -G labuser labuser
# Imposta la working directory (creata con adduser -D)
WORKDIR /home/labuser
# Crea un file semplice per verificare i permessi di scrittura
RUN echo "Questo file e stato creato durante la build" > /home/labuser/test.txt && \
chown labuser:labuser /home/labuser/test.txt
# PASSA A UTENTE NON-ROOT PRIMA DI QUALSIASI OPERAZIONE
# Questo e il punto chiave per INF-01: nessun processo gira come root
USER labuser
# Verifica che il container gira come utente non-root
CMD ["sh", "-c", "\
echo '========================================' && \
echo 'Lab 01 - IAM & Sicurezza' && \
echo 'Container non-root verification (INF-01)' && \
echo '========================================' && \
echo '' && \
echo 'Utente corrente:' && \
whoami && \
echo '' && \
echo 'UID:' && \
id -u && \
echo '' && \
echo 'GID:' && \
id -g && \
echo '' && \
echo 'Gruppi:' && \
groups && \
echo '' && \
echo 'Home directory:' && \
pwd && \
echo '' && \
echo 'Contenuto di test.txt (permessi scrittura):' && \
cat test.txt && \
echo '' && \
echo '========================================' && \
echo 'Se vedi \"labuser\" sopra, INF-01 e soddisfatto!' && \
echo '========================================' && \
echo '' && \
echo 'Container in esecuzione. Premi Ctrl-C per uscire.' && \
sleep 3600 \
"]
```
Key implementation points:
- Base image Alpine 3.19 (minimal, secure)
- Creates `labuser` with UID/GID 1000
- USER directive switches to non-root BEFORE CMD
- CMD demonstrates and verifies non-root execution
- Follows INF-01 requirement strictly
- Labels for metadata and documentation
- Working directory set to user's home
- Test file to verify write permissions
TDD Context: This is the GREEN phase - tests already exist (from Wave 0), this Dockerfile should make those tests pass.
</action>
<verify>
<automated>cd labs/lab-01-iam && docker build -t lab01-non-root . && docker run --rm lab01-non-root | grep -q "labuser" && echo "PASS: Container runs as non-root" || echo "FAIL: Container not running as labuser"</automated>
</verify>
<done>Dockerfile creates non-root container verified by whoami output</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Create docker-compose.yml with user directive</name>
<files>labs/lab-01-iam/docker-compose.yml</files>
<behavior>
- Defines service with local image build
- Specifies user directive (1000:1000) for non-root execution
- Includes container_name for easy reference
- Follows INF-01 requirement (no root)
- Enables test scripts to verify configuration
</behavior>
<action>
Create docker-compose.yml that enforces non-root execution:
```yaml
# Lab 01 - IAM & Sicurezza
# Docker Compose configuration per container non-root
#
# Questo file definisce i servizi per il lab, assicurandosi che
# TUTTI i container girino come utente non-root (INF-01).
version: "3.8"
services:
# Container di test per verificare l'esecuzione non-root
lab01-test:
build:
context: .
dockerfile: Dockerfile
image: lab01-non-root:latest
container_name: lab01-iam-test
# CRITICO: user directive assicura esecuzione non-root (INF-01)
# Format: UID:GID
# 1000:1000 corrisponde all'utente labuser creato nel Dockerfile
user: "1000:1000"
# Non esponiamo porte (non necessario per questo lab)
# Le porte private non devono essere esposte sull'host (best practice)
restart: unless-stopped
# Nessun volume mount necessario per questo lab semplice
# I volumi saranno introdotti nei lab successivi
healthcheck:
# Healthcheck per verificare che il container sia sano
test: ["CMD", "sh", "-c", "whoami | grep -q labuser"]
interval: 30s
timeout: 5s
retries: 3
start_period: 5s
# Nessuna rete definita - useremo la default bridge network
# Le reti custom isolate saranno introdotte nel Lab 02 (Network & VPC)
# Nessun volume definito - i volumi saranno introdotti nel Lab 04 (Storage & S3)
```
Key implementation points:
- Service definition with local build context
- `user: "1000:1000"` directive enforces non-root execution
- Container name matches test expectations
- Healthcheck verifies non-root user
- Comments explain why no volumes/networks (future labs)
- Follows docker-compose V3.8 syntax
- No ports exposed (security best practice)
TDD Context: Tests from Wave 0 check for user directive - this configuration should satisfy those tests.
INF-01 Compliance:
- User directive explicitly set
- Healthcheck verifies non-root execution
- No possibility of root execution
</action>
<verify>
<automated>cd labs/lab-01-iam && docker-compose config > /dev/null 2>&1 && echo "PASS: docker-compose.yml is valid" || echo "FAIL: docker-compose.yml has errors"</automated>
</verify>
<done>docker-compose.yml defines service with non-root user directive</done>
</task>
<task type="auto" tdd="true">
<name>Task 3: Create infrastructure verification script</name>
<files>labs/lab-01-iam/tests/04-verify-infrastructure.sh</files>
<behavior>
- Test 1: docker-compose.yml is valid YAML
- Test 2: Dockerfile builds successfully
- Test 3: Service has user directive set
- Test 4: Built container runs as non-root
- Test 5: All INF-01 requirements satisfied
</behavior>
<action>
Create infrastructure verification script (TDD GREEN phase verification):
```bash
#!/bin/bash
# Infrastructure Verification: Lab 01
# Verifies that docker-compose.yml and Dockerfile satisfy all requirements
# This is the GREEN phase check - tests should pass after infrastructure implementation
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$TEST_DIR/../.." && pwd)"
LAB_DIR="$PROJECT_ROOT/labs/lab-01-iam"
cd "$LAB_DIR"
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Lab 01 Infrastructure Verification${NC}"
echo -e "${BLUE}GREEN Phase Check${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
pass_count=0
fail_count=0
# Test 1: docker-compose.yml is valid
echo -e "${BLUE}[1/6] Checking docker-compose.yml syntax...${NC}"
if docker-compose config >/dev/null 2>&1; then
echo -e " ${GREEN}${NC} docker-compose.yml is valid YAML"
((pass_count++))
else
echo -e " ${RED}${NC} docker-compose.yml has syntax errors"
((fail_count++))
fi
echo ""
# Test 2: Dockerfile exists and is readable
echo -e "${BLUE}[2/6] Checking Dockerfile...${NC}"
if [ -f "Dockerfile" ]; then
echo -e " ${GREEN}${NC} Dockerfile exists"
# Check for USER directive
if grep -q "^USER" Dockerfile; then
user_line=$(grep "^USER" Dockerfile)
echo -e " ${GREEN}${NC} USER directive found: $user_line"
((pass_count++))
else
echo -e " ${RED}${NC} No USER directive found in Dockerfile"
((fail_count++))
fi
else
echo -e " ${RED}${NC} Dockerfile not found"
((fail_count++))
fi
echo ""
# Test 3: docker-compose.yml has user directive
echo -e "${BLUE}[3/6] Checking docker-compose.yml user directive...${NC}"
if grep -q "user:" docker-compose.yml; then
user_value=$(grep "user:" docker-compose.yml | head -1 | sed 's/.*user: *//' | tr -d '"')
echo -e " ${GREEN}${NC} user directive found: $user_value"
# Verify it's not root (0:0)
if [[ "$user_value" != *"0:0"* ]] && [[ "$user_value" != *"root"* ]]; then
echo -e " ${GREEN}${NC} User is not root (INF-01 compliant)"
((pass_count++))
else
echo -e " ${RED}${NC} User is root (INF-01 violation)"
((fail_count++))
fi
else
echo -e " ${RED}${NC} No user directive in docker-compose.yml"
((fail_count++))
fi
echo ""
# Test 4: Build Docker image
echo -e "${BLUE}[4/6] Building Docker image...${NC}"
if docker build -t lab01-non-root -q Dockerfile >/dev/null 2>&1; then
echo -e " ${GREEN}${NC} Docker image built successfully"
((pass_count++))
else
echo -e " ${RED}${NC} Docker image build failed"
((fail_count++))
fi
echo ""
# Test 5: Verify container runs as non-root
echo -e "${BLUE}[5/6] Verifying non-root execution...${NC}"
if docker run --rm lab01-non-root whoami 2>/dev/null | grep -q "labuser"; then
echo -e " ${GREEN}${NC} Container runs as non-root user (labuser)"
((pass_count++))
else
echo -e " ${RED}${NC} Container not running as labuser"
((fail_count++))
fi
echo ""
# Test 6: Verify docker-compose service
echo -e "${BLUE}[6/6] Verifying docker-compose service...${NC}"
# Start container in detached mode
if docker-compose up -d >/dev/null 2>&1; then
echo -e " ${GREEN}${NC} docker-compose service started"
# Wait for container to be ready
sleep 3
# Check container is running
if docker ps --format "{{.Names}}" | grep -q "^lab01-iam-test$"; then
echo -e " ${GREEN}${NC} Container is running"
# Verify user
actual_user=$(docker exec lab01-iam-test whoami 2>/dev/null || echo "unknown")
if [ "$actual_user" = "labuser" ]; then
echo -e " ${GREEN}${NC} docker-compose container runs as non-root"
((pass_count++))
else
echo -e " ${RED}${NC} docker-compose container running as $actual_user (expected labuser)"
((fail_count++))
fi
else
echo -e " ${RED}${NC} Container not running"
((fail_count++))
fi
# Cleanup
docker-compose down --volumes >/dev/null 2>&1
else
echo -e " ${RED}${NC} Failed to start docker-compose service"
((fail_count++))
fi
echo ""
# Summary
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Verification Summary${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Passed: $pass_count/6"
echo "Failed: $fail_count/6"
echo ""
if [ $fail_count -eq 0 ]; then
echo -e "${GREEN}All checks passed!${NC}"
echo -e "${GREEN}GREEN phase complete - infrastructure satisfies tests${NC}"
echo ""
echo "Next: Run full test suite"
echo " bash labs/lab-01-iam/tests/run-all-tests.sh"
echo -e "${BLUE}========================================${NC}"
exit 0
else
echo -e "${RED}Some checks failed${NC}"
echo -e "${RED}Infrastructure needs fixes before tests will pass${NC}"
echo -e "${BLUE}========================================${NC}"
exit 1
fi
```
Key implementation points:
- Validates docker-compose.yml syntax
- Verifies USER directive in Dockerfile
- Verifies user directive in docker-compose.yml
- Builds and tests Docker image
- Starts container with docker-compose and verifies execution
- Proper cleanup after testing
- Clear pass/fail indicators
TDD Context: This script confirms the GREEN phase - infrastructure implementation makes tests pass.
</action>
<verify>
<automated>chmod +x labs/lab-01-iam/tests/04-verify-infrastructure.sh && cd labs/lab-01-iam && bash ../tests/04-verify-infrastructure.sh</automated>
</verify>
<done>Infrastructure verification script confirms all requirements satisfied</done>
</task>
</tasks>
<verification>
1. Dockerfile creates non-root user with USER directive
2. docker-compose.yml specifies user directive for service
3. docker-compose config validates without errors
4. Docker build succeeds without warnings
5. Container execution verified as non-root (whoami, docker inspect, docker top)
6. All Wave 0 tests now pass (GREEN phase of TDD)
7. INF-01 requirement satisfied: no container runs as root
</verification>
<success_criteria>
1. Dockerfile follows non-root best practices from RESEARCH.md
2. docker-compose.yml enforces non-root execution via user directive
3. Infrastructure verification confirms all requirements met
4. Tests from Wave 0 (02-01-PLAN.md) now pass
5. LAB-01 requirement satisfied: students can configure users and Docker permissions
6. INF-01 requirement satisfied: no container runs as root
</success_criteria>
<output>
After completion, create `.planning/phases/02-lab-01-iam-sicurezza/02-03-SUMMARY.md`
</output>