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
10 changes: 10 additions & 0 deletions tests/samples/linux/ssh_bruteforce.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ cases:
- 'Sep 28 10:00:15 web1 sshd[811]: Failed password for root from 203.0.113.7 port 50004 ssh2'
- 'Sep 28 10:00:20 web1 sshd[811]: Failed password for root from 203.0.113.7 port 50005 ssh2'
- 'Sep 28 10:00:25 web1 sshd[811]: Failed password for root from 203.0.113.7 port 50006 ssh2'
- description: 6 failures from one IPv6 source in 25 seconds (IPv6 is grouped like IPv4)
expect: alert
groups: [["2001:db8::7"]]
raw:
- 'Sep 28 10:00:00 web1 sshd[811]: Failed password for root from 2001:db8::7 port 50010 ssh2'
- 'Sep 28 10:00:05 web1 sshd[811]: Failed password for root from 2001:db8::7 port 50011 ssh2'
- 'Sep 28 10:00:10 web1 sshd[811]: Failed password for root from 2001:db8::7 port 50012 ssh2'
- 'Sep 28 10:00:15 web1 sshd[811]: Failed password for root from 2001:db8::7 port 50013 ssh2'
- 'Sep 28 10:00:20 web1 sshd[811]: Failed password for root from 2001:db8::7 port 50014 ssh2'
- 'Sep 28 10:00:25 web1 sshd[811]: Failed password for root from 2001:db8::7 port 50015 ssh2'
- description: 5 failures spread over 4 minutes (slow guessing stays under the threshold)
wazuh_skip: "wazuh correlates on analysis time; logtest processes every line at once, so time gaps can't be reproduced (covered by the Python engine)"
expect: no_alert
Expand Down
3 changes: 3 additions & 0 deletions tests/samples/linux/ssh_failed_password.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ cases:
- description: failed password for a non-existent user
expect: match
raw: "Sep 28 10:00:01 web1 sshd[811]: Failed password for invalid user admin from 203.0.113.7 port 51240 ssh2"
- description: failed password from an IPv6 source
expect: match
raw: "Sep 28 10:00:01 web1 sshd[811]: Failed password for root from 2001:db8::7 port 51241 ssh2"
- description: successful login
expect: no_match
raw: "Sep 28 10:00:02 web1 sshd[812]: Accepted password for alice from 198.51.100.4 port 40022 ssh2"
Expand Down
36 changes: 36 additions & 0 deletions tests/test_scan_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""CLI entry point of detlab.scan (file, stdin, exit codes, --year)."""

import io

from detlab.scan import main

BURST = "".join(
f"Sep 28 10:00:0{i} web1 sshd[1]: Failed password for root from 2001:db8::7 port 5000{i} ssh2\n"
for i in range(6)
)


def test_main_reads_file_and_reports(tmp_path, capsys):
log = tmp_path / "auth.log"
log.write_text(BURST + "garbage line\n")
assert main([str(log), "--year", "2026"]) == 1
out, err = capsys.readouterr()
assert "SSH Brute Force From Single Source" in out
assert "2001:db8::7" in out and "2026-09-28" in out
assert "1 line(s) in unknown formats skipped" in err


def test_main_reads_stdin(monkeypatch, capsys):
monkeypatch.setattr("sys.stdin", io.StringIO(BURST))
assert main(["-"]) == 1
assert "SSH Brute Force" in capsys.readouterr().out


def test_main_quiet_input_exits_zero(tmp_path, capsys):
log = tmp_path / "auth.log"
log.write_text(
"Sep 28 10:00:00 web1 sshd[1]: Accepted password for alice from 198.51.100.4 port 1 ssh2\n"
)
assert main([str(log)]) == 0
_, err = capsys.readouterr()
assert "0 alert(s); 0 line(s) in unknown formats skipped" in err
Loading