Public Access
223 lines
7.8 KiB
Bash
Executable File
223 lines
7.8 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Run from the deploy/ directory
|
|
cd "$(dirname "$0")"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${BLUE}"
|
|
cat << "EOF"
|
|
______ __ __ ___
|
|
/ ____// /_ ____ _ _____ __ __ / /_ ____/ (_)____
|
|
/ / / __ \ / __ `// ___// / / // __ \ / __ // // __ \
|
|
/ /___ / / / // /_/ // / / /_/ // /_/ // /_/ // // /_/ /
|
|
\____//_/ /_/ \__,_//_/ \__, //_.___/ \__,_//_/ \____/
|
|
/____/
|
|
EOF
|
|
echo -e "${NC}"
|
|
|
|
echo -e "${GREEN}Charybdis Demo${NC}\n"
|
|
|
|
# Detect gRPC client
|
|
GRPC_CMD=""
|
|
if command -v buf &> /dev/null; then
|
|
GRPC_CMD="buf"
|
|
elif command -v grpcurl &> /dev/null; then
|
|
GRPC_CMD="grpcurl"
|
|
else
|
|
echo -e "${RED}Error: Neither 'buf' nor 'grpcurl' found. Install one:${NC}"
|
|
echo -e " brew install bufbuild/buf/buf"
|
|
echo -e " brew install grpcurl"
|
|
exit 1
|
|
fi
|
|
echo -e "${BLUE}Using gRPC client: ${GRPC_CMD}${NC}\n"
|
|
|
|
# Helper function for gRPC calls
|
|
grpc_call() {
|
|
local service_method="$1"
|
|
local data="$2"
|
|
local host="${3:-localhost:50051}"
|
|
|
|
if [ "$GRPC_CMD" = "buf" ]; then
|
|
buf curl --protocol grpc --http2-prior-knowledge \
|
|
-d "$data" \
|
|
"http://${host}/${service_method}" 2>&1
|
|
else
|
|
grpcurl -plaintext -d "$data" "$host" "$service_method" 2>&1
|
|
fi
|
|
}
|
|
|
|
# Check if Docker is running
|
|
if ! docker info > /dev/null 2>&1; then
|
|
echo -e "${RED}Error: Docker is not running. Please start Docker first.${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${BLUE}Starting services...${NC}\n"
|
|
|
|
# Start core services (Charybdis + Postgres only for quick demo)
|
|
docker compose -f docker-compose.demo.yml up -d postgres-charybdis 2>/dev/null
|
|
echo -e "${GREEN} Postgres started${NC}"
|
|
|
|
# Wait for Postgres
|
|
for i in {1..15}; do
|
|
if docker compose -f docker-compose.demo.yml exec -T postgres-charybdis pg_isready -U charybdis > /dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
docker compose -f docker-compose.demo.yml up -d charybdis 2>/dev/null
|
|
echo -e "${GREEN} Charybdis started${NC}"
|
|
|
|
# Wait for Charybdis gRPC
|
|
echo -e "\n${BLUE}Waiting for Charybdis to be ready...${NC}"
|
|
for i in {1..30}; do
|
|
if timeout 2 bash -c "echo > /dev/tcp/localhost/50051" 2>/dev/null; then
|
|
echo -e "${GREEN} gRPC server ready on :50051${NC}"
|
|
break
|
|
fi
|
|
if [ $i -eq 30 ]; then
|
|
echo -e "${RED} Charybdis failed to start${NC}"
|
|
docker compose -f docker-compose.demo.yml logs charybdis | tail -10
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
sleep 2 # Allow service to fully initialize
|
|
|
|
# --- Demo: Entity Management ---
|
|
echo -e "\n${BLUE}=== Entity Management ===${NC}\n"
|
|
|
|
echo -e "${YELLOW}1. Creating a Component...${NC}"
|
|
RESULT=$(grpc_call "charybdis.entities.EntityService/CreateEntity" '{
|
|
"entity": {
|
|
"kind": "Component",
|
|
"component_metadata": {
|
|
"name": "payment-service",
|
|
"namespace": "default",
|
|
"description": "Payment processing microservice"
|
|
},
|
|
"component_spec": {
|
|
"type": "service",
|
|
"lifecycle": "production",
|
|
"owner": "team-payments"
|
|
}
|
|
}
|
|
}')
|
|
echo "$RESULT" | head -5
|
|
ENTITY_ID=$(echo "$RESULT" | grep '"id"' | head -1 | sed 's/.*"id": *"//;s/".*//')
|
|
echo -e "${GREEN} Created entity: ${ENTITY_ID}${NC}\n"
|
|
|
|
echo -e "${YELLOW}2. Listing entities...${NC}"
|
|
grpc_call "charybdis.entities.EntityService/ListEntities" '{}' | head -5
|
|
echo -e ""
|
|
|
|
# --- Demo: Vulnerability Ingestion ---
|
|
echo -e "\n${BLUE}=== Vulnerability Ingestion ===${NC}\n"
|
|
|
|
# Create a SARIF report
|
|
SARIF_REPORT=$(cat << 'SARIF'
|
|
{
|
|
"version": "2.1.0",
|
|
"runs": [{
|
|
"tool": {"driver": {"name": "semgrep", "version": "1.0.0", "rules": [
|
|
{"id": "sql-injection", "shortDescription": {"text": "SQL Injection"}, "defaultConfiguration": {"level": "error"}, "properties": {"tags": ["CWE-89"]}},
|
|
{"id": "xss-reflected", "shortDescription": {"text": "Reflected XSS"}, "defaultConfiguration": {"level": "warning"}, "properties": {"tags": ["CWE-79"]}},
|
|
{"id": "hardcoded-secret", "shortDescription": {"text": "Hardcoded Secret"}, "defaultConfiguration": {"level": "error"}}
|
|
]}},
|
|
"results": [
|
|
{"ruleId": "sql-injection", "level": "error", "message": {"text": "User input in SQL query without parameterization"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/db/queries.rs"}, "region": {"startLine": 42}}}], "partialFingerprints": {"primaryLocationLineHash": "fp-sql-001"}},
|
|
{"ruleId": "xss-reflected", "level": "warning", "message": {"text": "User input reflected in response without encoding"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/handlers/search.rs"}, "region": {"startLine": 18}}}]},
|
|
{"ruleId": "hardcoded-secret", "level": "error", "message": {"text": "AWS secret key found in source code"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/config.rs"}, "region": {"startLine": 7}}}]}
|
|
]
|
|
}]
|
|
}
|
|
SARIF
|
|
)
|
|
|
|
SARIF_B64=$(echo "$SARIF_REPORT" | base64)
|
|
|
|
echo -e "${YELLOW}3. Dry-run scan (preview without persisting)...${NC}"
|
|
grpc_call "charybdis.ingestion.IngestionService/DryRunScan" "{
|
|
\"component_ref\": \"payment-service\",
|
|
\"lifecycle\": \"production\",
|
|
\"format\": \"sarif\",
|
|
\"data\": \"${SARIF_B64}\"
|
|
}"
|
|
echo -e ""
|
|
|
|
echo -e "${YELLOW}4. Importing scan (persisting findings)...${NC}"
|
|
grpc_call "charybdis.ingestion.IngestionService/ImportScan" "{
|
|
\"component_ref\": \"payment-service\",
|
|
\"lifecycle\": \"production\",
|
|
\"format\": \"sarif\",
|
|
\"data\": \"${SARIF_B64}\"
|
|
}"
|
|
echo -e ""
|
|
|
|
echo -e "${YELLOW}5. Re-importing same scan (testing deduplication)...${NC}"
|
|
grpc_call "charybdis.ingestion.IngestionService/ImportScan" "{
|
|
\"component_ref\": \"payment-service\",
|
|
\"lifecycle\": \"production\",
|
|
\"format\": \"sarif\",
|
|
\"data\": \"${SARIF_B64}\"
|
|
}"
|
|
echo -e ""
|
|
|
|
# Simulate a fix: remove the SQL injection finding
|
|
SARIF_FIXED=$(cat << 'SARIF'
|
|
{
|
|
"version": "2.1.0",
|
|
"runs": [{
|
|
"tool": {"driver": {"name": "semgrep", "version": "1.0.0", "rules": [
|
|
{"id": "xss-reflected", "shortDescription": {"text": "Reflected XSS"}, "defaultConfiguration": {"level": "warning"}, "properties": {"tags": ["CWE-79"]}},
|
|
{"id": "hardcoded-secret", "shortDescription": {"text": "Hardcoded Secret"}, "defaultConfiguration": {"level": "error"}}
|
|
]}},
|
|
"results": [
|
|
{"ruleId": "xss-reflected", "level": "warning", "message": {"text": "User input reflected in response without encoding"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/handlers/search.rs"}, "region": {"startLine": 18}}}]},
|
|
{"ruleId": "hardcoded-secret", "level": "error", "message": {"text": "AWS secret key found in source code"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/config.rs"}, "region": {"startLine": 7}}}]}
|
|
]
|
|
}]
|
|
}
|
|
SARIF
|
|
)
|
|
|
|
SARIF_FIXED_B64=$(echo "$SARIF_FIXED" | base64)
|
|
|
|
echo -e "${YELLOW}6. Importing scan after fix (SQL injection resolved)...${NC}"
|
|
grpc_call "charybdis.ingestion.IngestionService/ImportScan" "{
|
|
\"component_ref\": \"payment-service\",
|
|
\"lifecycle\": \"production\",
|
|
\"format\": \"sarif\",
|
|
\"data\": \"${SARIF_FIXED_B64}\"
|
|
}"
|
|
echo -e ""
|
|
|
|
# --- Summary ---
|
|
echo -e "\n${GREEN}=== Demo Complete ===${NC}\n"
|
|
echo -e "${BLUE}What we demonstrated:${NC}"
|
|
echo -e " 1. Created a Component entity via gRPC"
|
|
echo -e " 2. Dry-run scan: preview findings without persisting"
|
|
echo -e " 3. Import scan: persist 3 findings (SQL injection, XSS, hardcoded secret)"
|
|
echo -e " 4. Deduplication: re-import same scan -> all unchanged"
|
|
echo -e " 5. Auto-resolution: import without SQL injection -> marked as resolved"
|
|
echo ""
|
|
echo -e "${BLUE}Access:${NC}"
|
|
echo -e " gRPC: localhost:50051"
|
|
echo -e " YAML Adapter: http://localhost:8081"
|
|
echo ""
|
|
echo -e "${BLUE}Stop:${NC}"
|
|
echo -e " docker compose -f docker-compose.demo.yml down"
|
|
echo ""
|
|
echo -e "${BLUE}Clean up:${NC}"
|
|
echo -e " docker compose -f docker-compose.demo.yml down -v"
|
|
echo ""
|