161ef94b4f
Sirius CI/CD Pipeline / Merge API Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge UI Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Integration Test (push) Blocked by required conditions
Sirius CI/CD Pipeline / Public Stack Contract (push) Blocked by required conditions
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Blocked by required conditions
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Waiting to run
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
568 lines
16 KiB
Bash
Executable File
568 lines
16 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Phase 2 Integration Test Suite
|
|
# Tests source attribution functionality across all scanner types
|
|
# Validates multi-source scenarios and data integrity
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Test configuration
|
|
API_BASE_URL="http://localhost:9001"
|
|
TEST_HOST_IP="192.168.1.100"
|
|
TEST_CVE_1="CVE-2017-0144" # EternalBlue
|
|
TEST_CVE_2="CVE-2019-0708" # BlueKeep
|
|
TEST_CVE_3="CVE-2021-34527" # PrintNightmare
|
|
|
|
# Test counters
|
|
TOTAL_TESTS=0
|
|
PASSED_TESTS=0
|
|
FAILED_TESTS=0
|
|
|
|
# Logging functions
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
((PASSED_TESTS++))
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
((FAILED_TESTS++))
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
# Test helper functions
|
|
run_test() {
|
|
local test_name="$1"
|
|
local test_function="$2"
|
|
|
|
((TOTAL_TESTS++))
|
|
log_info "Running test: $test_name"
|
|
|
|
if $test_function; then
|
|
log_success "$test_name"
|
|
else
|
|
log_error "$test_name"
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
# API helper functions
|
|
api_post() {
|
|
local endpoint="$1"
|
|
local data="$2"
|
|
local expected_status="${3:-200}"
|
|
|
|
response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
|
|
-X POST \
|
|
-H "Content-Type: application/json" \
|
|
-d "$data" \
|
|
"$API_BASE_URL$endpoint")
|
|
|
|
http_code=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
|
body=$(echo "$response" | sed -e 's/HTTPSTATUS:.*//g')
|
|
|
|
if [[ "$http_code" -eq "$expected_status" ]]; then
|
|
echo "$body"
|
|
return 0
|
|
else
|
|
log_error "API call failed. Expected: $expected_status, Got: $http_code"
|
|
echo "$body"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
api_get() {
|
|
local endpoint="$1"
|
|
local expected_status="${2:-200}"
|
|
|
|
response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
|
|
-X GET \
|
|
-H "Content-Type: application/json" \
|
|
"$API_BASE_URL$endpoint")
|
|
|
|
http_code=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
|
body=$(echo "$response" | sed -e 's/HTTPSTATUS:.*//g')
|
|
|
|
if [[ "$http_code" -eq "$expected_status" ]]; then
|
|
echo "$body"
|
|
return 0
|
|
else
|
|
log_error "API call failed. Expected: $expected_status, Got: $http_code"
|
|
echo "$body"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Test functions
|
|
test_api_connectivity() {
|
|
log_info "Testing API connectivity..."
|
|
if api_get "/host" >/dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
log_error "Cannot connect to API at $API_BASE_URL"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_legacy_host_submission() {
|
|
log_info "Testing legacy host submission (backward compatibility)..."
|
|
|
|
local host_data='{
|
|
"ip": "'$TEST_HOST_IP'",
|
|
"hostname": "test-legacy-host",
|
|
"os": "Linux",
|
|
"ports": [
|
|
{
|
|
"port": 22,
|
|
"protocol": "tcp",
|
|
"state": "open",
|
|
"service": "ssh"
|
|
}
|
|
],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_1'",
|
|
"title": "EternalBlue SMB Vulnerability",
|
|
"description": "Legacy submission test",
|
|
"severity": "critical",
|
|
"cvss_score": 9.3,
|
|
"port": 445
|
|
}
|
|
]
|
|
}'
|
|
|
|
if api_post "/host" "$host_data" 200 >/dev/null; then
|
|
# Verify the host was created with legacy source
|
|
local host_response
|
|
host_response=$(api_get "/host/$TEST_HOST_IP")
|
|
if echo "$host_response" | grep -q "$TEST_HOST_IP"; then
|
|
return 0
|
|
else
|
|
log_error "Legacy host not found after submission"
|
|
return 1
|
|
fi
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_source_aware_nmap_submission() {
|
|
log_info "Testing source-aware nmap submission..."
|
|
|
|
local host_data='{
|
|
"host": {
|
|
"ip": "192.168.1.101",
|
|
"hostname": "test-nmap-host",
|
|
"os": "Linux",
|
|
"ports": [
|
|
{
|
|
"port": 80,
|
|
"protocol": "tcp",
|
|
"state": "open",
|
|
"service": "http"
|
|
}
|
|
],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_2'",
|
|
"title": "BlueKeep RDP Vulnerability",
|
|
"description": "Nmap source test",
|
|
"severity": "critical",
|
|
"cvss_score": 9.8,
|
|
"port": 3389
|
|
}
|
|
]
|
|
},
|
|
"source": {
|
|
"name": "nmap",
|
|
"version": "7.94",
|
|
"config": "ports:1-1000;aggressive:true;template:comprehensive"
|
|
}
|
|
}'
|
|
|
|
if api_post "/host/with-source" "$host_data" 200 >/dev/null; then
|
|
# Verify source attribution
|
|
local host_response
|
|
host_response=$(api_get "/host/192.168.1.101/sources")
|
|
if echo "$host_response" | grep -q "nmap" && echo "$host_response" | grep -q "7.94"; then
|
|
return 0
|
|
else
|
|
log_error "Nmap source attribution not found"
|
|
return 1
|
|
fi
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_source_aware_agent_submission() {
|
|
log_info "Testing source-aware agent submission..."
|
|
|
|
local host_data='{
|
|
"host": {
|
|
"ip": "192.168.1.102",
|
|
"hostname": "test-agent-host",
|
|
"os": "Ubuntu 20.04",
|
|
"ports": [
|
|
{
|
|
"port": 443,
|
|
"protocol": "tcp",
|
|
"state": "open",
|
|
"service": "https"
|
|
}
|
|
],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_3'",
|
|
"title": "PrintNightmare Vulnerability",
|
|
"description": "Agent source test",
|
|
"severity": "high",
|
|
"cvss_score": 8.8,
|
|
"port": 445
|
|
}
|
|
]
|
|
},
|
|
"source": {
|
|
"name": "sirius-agent",
|
|
"version": "1.0.0",
|
|
"config": "os:linux;arch:amd64;go:go1.21.0;host:test-agent"
|
|
}
|
|
}'
|
|
|
|
if api_post "/host/with-source" "$host_data" 200 >/dev/null; then
|
|
# Verify source attribution
|
|
local host_response
|
|
host_response=$(api_get "/host/192.168.1.102/sources")
|
|
if echo "$host_response" | grep -q "sirius-agent" && echo "$host_response" | grep -q "1.0.0"; then
|
|
return 0
|
|
else
|
|
log_error "Agent source attribution not found"
|
|
return 1
|
|
fi
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_multi_source_same_host() {
|
|
log_info "Testing multiple sources for same host..."
|
|
|
|
local test_ip="192.168.1.103"
|
|
|
|
# Submit from nmap source
|
|
local nmap_data='{
|
|
"host": {
|
|
"ip": "'$test_ip'",
|
|
"hostname": "multi-source-host",
|
|
"os": "Linux",
|
|
"ports": [
|
|
{
|
|
"port": 22,
|
|
"protocol": "tcp",
|
|
"state": "open",
|
|
"service": "ssh"
|
|
}
|
|
],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_1'",
|
|
"title": "EternalBlue from Nmap",
|
|
"description": "Multi-source test - nmap",
|
|
"severity": "critical",
|
|
"cvss_score": 9.3,
|
|
"port": 445
|
|
}
|
|
]
|
|
},
|
|
"source": {
|
|
"name": "nmap",
|
|
"version": "7.94",
|
|
"config": "multi-source-test"
|
|
}
|
|
}'
|
|
|
|
# Submit from agent source
|
|
local agent_data='{
|
|
"host": {
|
|
"ip": "'$test_ip'",
|
|
"hostname": "multi-source-host",
|
|
"os": "Linux",
|
|
"ports": [
|
|
{
|
|
"port": 80,
|
|
"protocol": "tcp",
|
|
"state": "open",
|
|
"service": "http"
|
|
}
|
|
],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_2'",
|
|
"title": "BlueKeep from Agent",
|
|
"description": "Multi-source test - agent",
|
|
"severity": "critical",
|
|
"cvss_score": 9.8,
|
|
"port": 3389
|
|
}
|
|
]
|
|
},
|
|
"source": {
|
|
"name": "sirius-agent",
|
|
"version": "1.0.0",
|
|
"config": "multi-source-test"
|
|
}
|
|
}'
|
|
|
|
# Submit both sources
|
|
if api_post "/host/with-source" "$nmap_data" 200 >/dev/null && \
|
|
api_post "/host/with-source" "$agent_data" 200 >/dev/null; then
|
|
|
|
# Verify both sources are present
|
|
local sources_response
|
|
sources_response=$(api_get "/host/$test_ip/sources")
|
|
if echo "$sources_response" | grep -q "nmap" && echo "$sources_response" | grep -q "sirius-agent"; then
|
|
# Verify both vulnerabilities are present
|
|
local host_response
|
|
host_response=$(api_get "/host/$test_ip")
|
|
if echo "$host_response" | grep -q "$TEST_CVE_1" && echo "$host_response" | grep -q "$TEST_CVE_2"; then
|
|
return 0
|
|
else
|
|
log_error "Not all vulnerabilities found from multiple sources"
|
|
return 1
|
|
fi
|
|
else
|
|
log_error "Not all sources found for multi-source host"
|
|
return 1
|
|
fi
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_source_detection_headers() {
|
|
log_info "Testing automatic source detection from headers..."
|
|
|
|
local host_data='{
|
|
"ip": "192.168.1.104",
|
|
"hostname": "header-detection-host",
|
|
"os": "Linux",
|
|
"ports": [
|
|
{
|
|
"port": 8080,
|
|
"protocol": "tcp",
|
|
"state": "open",
|
|
"service": "http-proxy"
|
|
}
|
|
],
|
|
"vulnerabilities": []
|
|
}'
|
|
|
|
# Submit with custom headers that should be detected
|
|
response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
|
|
-X POST \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Scanner-Name: rustscan" \
|
|
-H "X-Scanner-Version: 2.1.1" \
|
|
-H "X-Scanner-Config: fast-scan" \
|
|
-d "$host_data" \
|
|
"$API_BASE_URL/host")
|
|
|
|
http_code=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
|
|
|
|
if [[ "$http_code" -eq 200 ]]; then
|
|
# Check if source was detected and attributed
|
|
local host_response
|
|
host_response=$(api_get "/host/192.168.1.104?include_source=true")
|
|
if echo "$host_response" | grep -q "rustscan" && echo "$host_response" | grep -q "2.1.1"; then
|
|
return 0
|
|
else
|
|
log_error "Source detection from headers failed"
|
|
return 1
|
|
fi
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_backward_compatibility_response_format() {
|
|
log_info "Testing backward compatibility response formats..."
|
|
|
|
# Test legacy client detection
|
|
local host_data='{
|
|
"ip": "192.168.1.105",
|
|
"hostname": "legacy-client-host",
|
|
"os": "Windows",
|
|
"ports": [],
|
|
"vulnerabilities": []
|
|
}'
|
|
|
|
# Submit with legacy User-Agent
|
|
response=$(curl -s \
|
|
-X POST \
|
|
-H "Content-Type: application/json" \
|
|
-H "User-Agent: legacy-client/1.0" \
|
|
-H "X-API-Version: 1.0" \
|
|
-d "$host_data" \
|
|
"$API_BASE_URL/host")
|
|
|
|
# Check response format (should be legacy format)
|
|
if echo "$response" | grep -q "Host added successfully" && ! echo "$response" | grep -q "source"; then
|
|
return 0
|
|
else
|
|
log_error "Legacy response format not maintained"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_data_integrity_across_sources() {
|
|
log_info "Testing data integrity across multiple sources..."
|
|
|
|
local test_ip="192.168.1.106"
|
|
|
|
# Submit same vulnerability from different sources
|
|
local source1_data='{
|
|
"host": {
|
|
"ip": "'$test_ip'",
|
|
"hostname": "integrity-test-host",
|
|
"os": "Linux",
|
|
"ports": [],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_1'",
|
|
"title": "EternalBlue",
|
|
"description": "From source 1",
|
|
"severity": "critical",
|
|
"cvss_score": 9.3,
|
|
"port": 445
|
|
}
|
|
]
|
|
},
|
|
"source": {
|
|
"name": "nmap",
|
|
"version": "7.94",
|
|
"config": "integrity-test-1"
|
|
}
|
|
}'
|
|
|
|
local source2_data='{
|
|
"host": {
|
|
"ip": "'$test_ip'",
|
|
"hostname": "integrity-test-host",
|
|
"os": "Linux",
|
|
"ports": [],
|
|
"vulnerabilities": [
|
|
{
|
|
"vid": "'$TEST_CVE_1'",
|
|
"title": "EternalBlue",
|
|
"description": "From source 2",
|
|
"severity": "critical",
|
|
"cvss_score": 9.3,
|
|
"port": 445
|
|
}
|
|
]
|
|
},
|
|
"source": {
|
|
"name": "rustscan",
|
|
"version": "2.1.1",
|
|
"config": "integrity-test-2"
|
|
}
|
|
}'
|
|
|
|
# Submit from both sources
|
|
if api_post "/host/with-source" "$source1_data" 200 >/dev/null && \
|
|
api_post "/host/with-source" "$source2_data" 200 >/dev/null; then
|
|
|
|
# Verify both source records exist for the same vulnerability
|
|
local sources_response
|
|
sources_response=$(api_get "/host/$test_ip/sources")
|
|
|
|
# Count occurrences of the CVE (should be 2 - one from each source)
|
|
local cve_count
|
|
cve_count=$(echo "$sources_response" | grep -o "$TEST_CVE_1" | wc -l)
|
|
|
|
if [[ "$cve_count" -ge 2 ]]; then
|
|
return 0
|
|
else
|
|
log_error "Data integrity test failed - CVE not preserved across sources"
|
|
return 1
|
|
fi
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Cleanup function
|
|
cleanup_test_data() {
|
|
log_info "Cleaning up test data..."
|
|
|
|
# Delete test hosts (if delete endpoint exists)
|
|
local test_ips=("192.168.1.100" "192.168.1.101" "192.168.1.102" "192.168.1.103" "192.168.1.104" "192.168.1.105" "192.168.1.106")
|
|
|
|
for ip in "${test_ips[@]}"; do
|
|
curl -s -X POST \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"ip": "'$ip'"}' \
|
|
"$API_BASE_URL/host/delete" >/dev/null 2>&1 || true
|
|
done
|
|
|
|
log_info "Cleanup completed"
|
|
}
|
|
|
|
# Main test execution
|
|
main() {
|
|
echo "=========================================="
|
|
echo "Phase 2 Integration Test Suite"
|
|
echo "Testing Source Attribution Functionality"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
# Pre-test cleanup
|
|
cleanup_test_data
|
|
|
|
# Run all tests
|
|
run_test "API Connectivity" test_api_connectivity
|
|
run_test "Legacy Host Submission" test_legacy_host_submission
|
|
run_test "Source-Aware Nmap Submission" test_source_aware_nmap_submission
|
|
run_test "Source-Aware Agent Submission" test_source_aware_agent_submission
|
|
run_test "Multi-Source Same Host" test_multi_source_same_host
|
|
run_test "Source Detection from Headers" test_source_detection_headers
|
|
run_test "Backward Compatibility Response Format" test_backward_compatibility_response_format
|
|
run_test "Data Integrity Across Sources" test_data_integrity_across_sources
|
|
|
|
# Post-test cleanup
|
|
cleanup_test_data
|
|
|
|
# Test summary
|
|
echo "=========================================="
|
|
echo "Test Summary"
|
|
echo "=========================================="
|
|
echo "Total Tests: $TOTAL_TESTS"
|
|
echo -e "Passed: ${GREEN}$PASSED_TESTS${NC}"
|
|
echo -e "Failed: ${RED}$FAILED_TESTS${NC}"
|
|
echo ""
|
|
|
|
if [[ $FAILED_TESTS -eq 0 ]]; then
|
|
echo -e "${GREEN}🎉 All tests passed! Phase 2 integration is working correctly.${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}❌ Some tests failed. Please review the errors above.${NC}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Run main function
|
|
main "$@" |