Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ out/
report.md
report.json
*.exe
!tests/fixtures/report_contracts/**/report.md
!tests/fixtures/report_contracts/**/report.json
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ All notable user-visible changes should be recorded here.

### Added

- None yet.
- Added sanitized golden `report.md` / `report.json` regression fixtures to lock report contracts.

### Changed

Expand Down
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,12 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/assets/sample_config.json
${CMAKE_CURRENT_BINARY_DIR}/cli_test_output
)

add_executable(test_report_contracts tests/test_report_contracts.cpp)
add_test(
NAME report_contracts
COMMAND test_report_contracts
$<TARGET_FILE:loglens>
${CMAKE_CURRENT_BINARY_DIR}/report_contract_output
)
endif()
16 changes: 16 additions & 0 deletions tests/fixtures/report_contracts/journalctl_short_full/input.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Tue 2026-03-10 08:11:22 UTC example-host sshd[2234]: Failed password for invalid user admin from 203.0.113.10 port 51022 ssh2
Tue 2026-03-10 08:12:05 UTC example-host sshd[2235]: Failed password for root from 203.0.113.10 port 51030 ssh2
Tue 2026-03-10 08:13:10 UTC example-host sshd[2236]: Failed password for test from 203.0.113.10 port 51040 ssh
Tue 2026-03-10 08:14:44 UTC example-host sshd[2237]: Failed password for guest from 203.0.113.10 port 51050 ssh2
Tue 2026-03-10 08:18:05 UTC example-host sshd[2238]: Failed publickey for invalid user deploy from 203.0.113.10 port 51060 ssh2
Tue 2026-03-10 08:20:10 UTC example-host sshd[2240]: Accepted password for alice from 203.0.113.20 port 51111 ssh2
Tue 2026-03-10 08:21:00 UTC example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl restart ssh
Tue 2026-03-10 08:22:10 UTC example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/journalctl -xe
Tue 2026-03-10 08:24:15 UTC example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/vi /etc/ssh/sshd_config
Tue 2026-03-10 08:25:30 UTC example-host sshd[2241]: Failed password for bob from 203.0.113.30 port 51234 ssh2
Tue 2026-03-10 08:26:02 UTC example-host sshd[2242]: Invalid user backup from 203.0.113.31 port 51236
Tue 2026-03-10 08:28:33 UTC example-host pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=203.0.113.41 user=alice
Tue 2026-03-10 08:29:50 UTC example-host pam_unix(sudo:session): session opened for user root by alice(uid=0)
Tue 2026-03-10 08:30:12 UTC example-host sshd[2244]: Failed password for invalid user qauser from 203.0.113.50 port 51290 ssh2
Tue 2026-03-10 08:31:18 UTC example-host sshd[2245]: Connection closed by authenticating user alice 203.0.113.51 port 51291 [preauth]
Tue 2026-03-10 08:32:26 UTC example-host sshd[2246]: Timeout, client not responding from 203.0.113.52 port 51292
64 changes: 64 additions & 0 deletions tests/fixtures/report_contracts/journalctl_short_full/report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"tool": "LogLens",
"input": "tests/fixtures/report_contracts/journalctl_short_full/input.log",
"input_mode": "journalctl_short_full",
"timezone_present": true,
"parser_quality": {
"total_lines": 16,
"parsed_lines": 14,
"unparsed_lines": 2,
"parse_success_rate": 0.8750,
"top_unknown_patterns": [
{"pattern": "sshd_connection_closed_preauth", "count": 1},
{"pattern": "sshd_timeout_or_disconnection", "count": 1}
]
},
"parsed_event_count": 14,
"warning_count": 2,
"finding_count": 3,
"event_counts": [
{"event_type": "ssh_failed_password", "count": 4},
{"event_type": "ssh_accepted_password", "count": 1},
{"event_type": "ssh_invalid_user", "count": 3},
{"event_type": "ssh_failed_publickey", "count": 1},
{"event_type": "pam_auth_failure", "count": 1},
{"event_type": "session_opened", "count": 1},
{"event_type": "sudo_command", "count": 3}
],
"findings": [
{
"rule": "brute_force",
"subject_kind": "source_ip",
"subject": "203.0.113.10",
"event_count": 5,
"window_start": "2026-03-10 08:11:22",
"window_end": "2026-03-10 08:18:05",
"usernames": [],
"summary": "5 failed SSH attempts from 203.0.113.10 within 10 minutes."
},
{
"rule": "multi_user_probing",
"subject_kind": "source_ip",
"subject": "203.0.113.10",
"event_count": 5,
"window_start": "2026-03-10 08:11:22",
"window_end": "2026-03-10 08:18:05",
"usernames": ["admin", "deploy", "guest", "root", "test"],
"summary": "203.0.113.10 targeted 5 usernames within 15 minutes."
},
{
"rule": "sudo_burst",
"subject_kind": "username",
"subject": "alice",
"event_count": 3,
"window_start": "2026-03-10 08:21:00",
"window_end": "2026-03-10 08:24:15",
"usernames": [],
"summary": "alice ran 3 sudo commands within 5 minutes."
}
],
"warnings": [
{"line_number": 15, "reason": "unrecognized auth pattern: sshd_connection_closed_preauth"},
{"line_number": 16, "reason": "unrecognized auth pattern: sshd_timeout_or_disconnection"}
]
}
48 changes: 48 additions & 0 deletions tests/fixtures/report_contracts/journalctl_short_full/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# LogLens Report

## Summary

- Input: `tests/fixtures/report_contracts/journalctl_short_full/input.log`
- Input mode: journalctl_short_full
- Timezone present: true
- Total lines: 16
- Parsed lines: 14
- Unparsed lines: 2
- Parse success rate: 87.50%
- Parsed events: 14
- Findings: 3
- Parser warnings: 2

## Findings

| Rule | Subject | Count | Window | Notes |
| --- | --- | ---: | --- | --- |
| brute_force | 203.0.113.10 | 5 | 2026-03-10 08:11:22 -> 2026-03-10 08:18:05 | 5 failed SSH attempts from 203.0.113.10 within 10 minutes. |
| multi_user_probing | 203.0.113.10 | 5 | 2026-03-10 08:11:22 -> 2026-03-10 08:18:05 | 203.0.113.10 targeted 5 usernames within 15 minutes. Usernames: admin, deploy, guest, root, test |
| sudo_burst | alice | 3 | 2026-03-10 08:21:00 -> 2026-03-10 08:24:15 | alice ran 3 sudo commands within 5 minutes. |

## Event Counts

| Event Type | Count |
| --- | ---: |
| ssh_failed_password | 4 |
| ssh_accepted_password | 1 |
| ssh_invalid_user | 3 |
| ssh_failed_publickey | 1 |
| pam_auth_failure | 1 |
| session_opened | 1 |
| sudo_command | 3 |

## Parser Quality

| Unknown Pattern | Count |
| --- | ---: |
| sshd_connection_closed_preauth | 1 |
| sshd_timeout_or_disconnection | 1 |

## Parser Warnings

| Line | Reason |
| ---: | --- |
| 15 | unrecognized auth pattern: sshd_connection_closed_preauth |
| 16 | unrecognized auth pattern: sshd_timeout_or_disconnection |
16 changes: 16 additions & 0 deletions tests/fixtures/report_contracts/syslog_legacy/input.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Mar 10 08:11:22 example-host sshd[1234]: Failed password for invalid user admin from 203.0.113.10 port 51022 ssh2
Mar 10 08:12:05 example-host sshd[1235]: Failed password for root from 203.0.113.10 port 51030 ssh2
Mar 10 08:13:10 example-host sshd[1236]: Failed password for test from 203.0.113.10 port 51040 ssh2
Mar 10 08:14:44 example-host sshd[1237]: Failed password for guest from 203.0.113.10 port 51050 ssh2
Mar 10 08:18:05 example-host sshd[1238]: Failed password for invalid user deploy from 203.0.113.10 port 51060 ssh2
Mar 10 08:20:10 example-host sshd[1240]: Accepted password for alice from 203.0.113.20 port 51111 ssh2
Mar 10 08:21:00 example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/systemctl restart ssh
Mar 10 08:22:10 example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/journalctl -xe
Mar 10 08:24:15 example-host sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/vi /etc/ssh/sshd_config
Mar 10 08:25:30 example-host sshd[1241]: Failed password for bob from 203.0.113.30 port 51234 ssh2
Mar 10 08:26:02 example-host sshd[1242]: Invalid user backup from 203.0.113.31 port 51236
Mar 10 08:27:10 example-host sshd[1243]: Failed publickey for invalid user svc-backup from 203.0.113.40 port 51240 ssh2
Mar 10 08:28:33 example-host pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=203.0.113.41 user=alice
Mar 10 08:29:50 example-host pam_unix(sudo:session): session opened for user root by alice(uid=0)
Mar 10 08:30:12 example-host sshd[1244]: Connection closed by authenticating user alice 203.0.113.50 port 51290 [preauth]
Mar 10 08:31:18 example-host sshd[1245]: Timeout, client not responding from 203.0.113.51 port 51291
65 changes: 65 additions & 0 deletions tests/fixtures/report_contracts/syslog_legacy/report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"tool": "LogLens",
"input": "tests/fixtures/report_contracts/syslog_legacy/input.log",
"input_mode": "syslog_legacy",
"assume_year": 2026,
"timezone_present": false,
"parser_quality": {
"total_lines": 16,
"parsed_lines": 14,
"unparsed_lines": 2,
"parse_success_rate": 0.8750,
"top_unknown_patterns": [
{"pattern": "sshd_connection_closed_preauth", "count": 1},
{"pattern": "sshd_timeout_or_disconnection", "count": 1}
]
},
"parsed_event_count": 14,
"warning_count": 2,
"finding_count": 3,
"event_counts": [
{"event_type": "ssh_failed_password", "count": 4},
{"event_type": "ssh_accepted_password", "count": 1},
{"event_type": "ssh_invalid_user", "count": 3},
{"event_type": "ssh_failed_publickey", "count": 1},
{"event_type": "pam_auth_failure", "count": 1},
{"event_type": "session_opened", "count": 1},
{"event_type": "sudo_command", "count": 3}
],
"findings": [
{
"rule": "brute_force",
"subject_kind": "source_ip",
"subject": "203.0.113.10",
"event_count": 5,
"window_start": "2026-03-10 08:11:22",
"window_end": "2026-03-10 08:18:05",
"usernames": [],
"summary": "5 failed SSH attempts from 203.0.113.10 within 10 minutes."
},
{
"rule": "multi_user_probing",
"subject_kind": "source_ip",
"subject": "203.0.113.10",
"event_count": 5,
"window_start": "2026-03-10 08:11:22",
"window_end": "2026-03-10 08:18:05",
"usernames": ["admin", "deploy", "guest", "root", "test"],
"summary": "203.0.113.10 targeted 5 usernames within 15 minutes."
},
{
"rule": "sudo_burst",
"subject_kind": "username",
"subject": "alice",
"event_count": 3,
"window_start": "2026-03-10 08:21:00",
"window_end": "2026-03-10 08:24:15",
"usernames": [],
"summary": "alice ran 3 sudo commands within 5 minutes."
}
],
"warnings": [
{"line_number": 15, "reason": "unrecognized auth pattern: sshd_connection_closed_preauth"},
{"line_number": 16, "reason": "unrecognized auth pattern: sshd_timeout_or_disconnection"}
]
}
49 changes: 49 additions & 0 deletions tests/fixtures/report_contracts/syslog_legacy/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# LogLens Report

## Summary

- Input: `tests/fixtures/report_contracts/syslog_legacy/input.log`
- Input mode: syslog_legacy
- Assume year: 2026
- Timezone present: false
- Total lines: 16
- Parsed lines: 14
- Unparsed lines: 2
- Parse success rate: 87.50%
- Parsed events: 14
- Findings: 3
- Parser warnings: 2

## Findings

| Rule | Subject | Count | Window | Notes |
| --- | --- | ---: | --- | --- |
| brute_force | 203.0.113.10 | 5 | 2026-03-10 08:11:22 -> 2026-03-10 08:18:05 | 5 failed SSH attempts from 203.0.113.10 within 10 minutes. |
| multi_user_probing | 203.0.113.10 | 5 | 2026-03-10 08:11:22 -> 2026-03-10 08:18:05 | 203.0.113.10 targeted 5 usernames within 15 minutes. Usernames: admin, deploy, guest, root, test |
| sudo_burst | alice | 3 | 2026-03-10 08:21:00 -> 2026-03-10 08:24:15 | alice ran 3 sudo commands within 5 minutes. |

## Event Counts

| Event Type | Count |
| --- | ---: |
| ssh_failed_password | 4 |
| ssh_accepted_password | 1 |
| ssh_invalid_user | 3 |
| ssh_failed_publickey | 1 |
| pam_auth_failure | 1 |
| session_opened | 1 |
| sudo_command | 3 |

## Parser Quality

| Unknown Pattern | Count |
| --- | ---: |
| sshd_connection_closed_preauth | 1 |
| sshd_timeout_or_disconnection | 1 |

## Parser Warnings

| Line | Reason |
| ---: | --- |
| 15 | unrecognized auth pattern: sshd_connection_closed_preauth |
| 16 | unrecognized auth pattern: sshd_timeout_or_disconnection |
Loading
Loading