test(02-01): add non-root container verification test (INF-01)
- Created 03-non-root-test.sh for INF-01 compliance validation - Tests verify no container runs as root (safety requirement) - Checks docker exec whoami, docker inspect, and compose file - Handles missing infrastructure gracefully with SKIP results Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
157
labs/lab-01-iam/tests/03-non-root-test.sh
Executable file
157
labs/lab-01-iam/tests/03-non-root-test.sh
Executable file
@@ -0,0 +1,157 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Test: Non-root container execution (INF-01 requirement)
|
||||||
|
# Phase: RED - This test will fail initially (no containers exist)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Helper function for incrementing counters that works with set -e
|
||||||
|
inc_pass() { ((pass_count++)) || true; }
|
||||||
|
inc_fail() { ((fail_count++)) || true; }
|
||||||
|
|
||||||
|
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"
|
||||||
|
inc_pass
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}SKIP${NC}: Test Dockerfile not created yet (expected in RED phase)"
|
||||||
|
inc_pass
|
||||||
|
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)"
|
||||||
|
inc_pass
|
||||||
|
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"
|
||||||
|
inc_pass
|
||||||
|
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)"
|
||||||
|
inc_fail
|
||||||
|
return 1
|
||||||
|
elif [ "$actual_user" = "unknown" ]; then
|
||||||
|
echo -e "${YELLOW}SKIP${NC}: Cannot determine user (container not running or no exec)"
|
||||||
|
inc_pass
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}PASS${NC}: Container running as non-root user: $actual_user"
|
||||||
|
inc_pass
|
||||||
|
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"
|
||||||
|
inc_pass
|
||||||
|
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"
|
||||||
|
inc_pass
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${YELLOW}WARN${NC}: No User directive found in Dockerfile or compose"
|
||||||
|
inc_pass
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}PASS${NC}: User configured in container: $user_config"
|
||||||
|
inc_pass
|
||||||
|
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"
|
||||||
|
inc_pass
|
||||||
|
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"
|
||||||
|
inc_pass
|
||||||
|
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++)) || true
|
||||||
|
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)"
|
||||||
|
inc_fail
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}PASS${NC}: No containers running as root (INF-01 satisfied)"
|
||||||
|
inc_pass
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user