Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 37 additions & 28 deletions .github/workflows/test-and-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ jobs:
run: |
mkdir -p data/openclaw/raw
mkdir -p data/openclaw/replay/labeled
# Materialize the benchmark corpus expected by regression tests.
if [ -f "data/fixtures/events.json" ]; then
cp data/fixtures/events.json data/events.json
fi
if [ -f "data/fixtures/events_unlabeled.json" ]; then
cp data/fixtures/events_unlabeled.json data/events_unlabeled.json
fi
# Copy fixture data
if [ -f "data/fixtures/openclaw/sample_audit.jsonl" ]; then
cp data/fixtures/openclaw/sample_audit.jsonl data/openclaw/raw/audit.jsonl
Expand All @@ -46,34 +53,36 @@ jobs:
fi
# Create mock schema file for tests (at parent directory level)
mkdir -p ../secopsai-dashboard/supabase_migrations
cat > ../secopsai-dashboard/supabase_migrations/2026-03-28_findings.sql << 'SCHEMA_EOF'
create table if not exists public.findings (
id uuid primary key default gen_random_uuid(),
external_finding_id text not null,
title text not null,
summary text,
severity text,
severity_score int,
status text,
disposition text,
confidence float,
source text,
source_name text,
detector text,
fingerprint text,
dedupe_key text,
detected_at timestamptz,
first_seen_at timestamptz,
last_seen_at timestamptz,
rule_id text,
rule_name text,
mitre text,
event_count int,
event_ids jsonb,
recommended_actions jsonb,
raw_payload jsonb
);
SCHEMA_EOF
cat > ../secopsai-dashboard/supabase_migrations/2026-03-28_findings.sql <<'SCHEMA_EOF'
create table if not exists public.findings (
id uuid primary key default gen_random_uuid(),
external_finding_id text not null,
title text not null,
summary text,
severity text,
severity_score int,
status text,
disposition text,
confidence text,
source text,
source_platform text,
correlation_type text,
detection_layer text,
detected_at timestamptz,
first_seen_at timestamptz,
last_seen_at timestamptz,
rule_id text,
rule_name text,
mitre text,
mitre_ids text[],
event_count int,
event_ids jsonb,
risk_tags text[],
recommended_actions jsonb,
raw_payload jsonb,
metadata jsonb
);
SCHEMA_EOF

- name: Lint with flake8
run: |
Expand Down
23 changes: 18 additions & 5 deletions correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,12 +629,25 @@ def correlate_by_file_hash(findings: List[Dict]) -> List[Dict]:
return correlations


def run_correlation(findings: List[Dict]) -> Dict[str, Any]:
"""Run all correlation rules."""
def run_correlation(
findings: List[Dict],
time_window_minutes: int = 60,
) -> Dict[str, Any]:
"""Run all correlation rules.

``time_window_minutes`` is accepted for backward compatibility with older
CLI callers that pass a configurable window.
"""
if not isinstance(time_window_minutes, int):
try:
time_window_minutes = int(time_window_minutes)
except (TypeError, ValueError):
time_window_minutes = 60

results = {
"cross_platform_ip": correlate_by_ip(findings),
"cross_platform_user": correlate_by_user(findings),
"time_cluster": correlate_by_time(findings),
"cross_platform_ip": correlate_by_ip(findings, time_window_minutes=time_window_minutes),
"cross_platform_user": correlate_by_user(findings, time_window_minutes=time_window_minutes),
"time_cluster": correlate_by_time(findings, time_window_minutes=time_window_minutes),
"cross_platform_file": correlate_by_file_hash(findings),
"total_correlations": 0
}
Expand Down
Loading