xml-audit-viewer 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ümit Özdemir
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.4
2
+ Name: xml-audit-viewer
3
+ Version: 1.1.0
4
+ Summary: Python GUI viewer and live-tail tool for NetApp ONTAP and Huawei OceanStor CIFS Security Audit XML logs — stdlib only, no install.
5
+ Author-email: Umit Ozdemir <umitozdemir@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Ümit Özdemir
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/ozdemirumit/XMLAuditViewer
29
+ Project-URL: Repository, https://github.com/ozdemirumit/XMLAuditViewer
30
+ Project-URL: Issues, https://github.com/ozdemirumit/XMLAuditViewer/issues
31
+ Project-URL: Changelog, https://github.com/ozdemirumit/XMLAuditViewer/blob/main/CHANGELOG.md
32
+ Keywords: netapp,huawei,oceanstor,ontap,audit,xml,cifs,smb,security,tkinter,gui,live-tail
33
+ Classifier: Development Status :: 5 - Production/Stable
34
+ Classifier: Environment :: X11 Applications
35
+ Classifier: Environment :: Win32 (MS Windows)
36
+ Classifier: Environment :: MacOS X
37
+ Classifier: Intended Audience :: System Administrators
38
+ Classifier: Intended Audience :: Information Technology
39
+ Classifier: License :: OSI Approved :: MIT License
40
+ Classifier: Operating System :: OS Independent
41
+ Classifier: Programming Language :: Python :: 3
42
+ Classifier: Programming Language :: Python :: 3.10
43
+ Classifier: Programming Language :: Python :: 3.11
44
+ Classifier: Programming Language :: Python :: 3.12
45
+ Classifier: Programming Language :: Python :: 3.13
46
+ Classifier: Programming Language :: Python :: 3.14
47
+ Classifier: Topic :: System :: Logging
48
+ Classifier: Topic :: System :: Monitoring
49
+ Classifier: Topic :: System :: Systems Administration
50
+ Classifier: Topic :: Security
51
+ Requires-Python: >=3.10
52
+ Description-Content-Type: text/markdown
53
+ License-File: LICENSE
54
+ Dynamic: license-file
55
+
56
+ # XML Audit Viewer
57
+
58
+ A single-file Python GUI for browsing **NetApp ONTAP** and **Huawei OceanStor (e.g. 5510) CIFS Security Audit XML** logs. Opens large files instantly, follows them like `tail -f` as new events are written, and lets you slice the data by user, IP, time range, and event type — with no external dependencies beyond Python's standard library.
59
+
60
+ Built for storage and infrastructure engineers who need to triage `audit_*.xml` output without spinning up Splunk/ELK.
61
+
62
+ [![PyPI](https://img.shields.io/pypi/v/xml-audit-viewer.svg)](https://pypi.org/project/xml-audit-viewer/) [![Python versions](https://img.shields.io/pypi/pyversions/xml-audit-viewer.svg)](https://pypi.org/project/xml-audit-viewer/) ![status: working](https://img.shields.io/badge/status-working-brightgreen) ![deps: stdlib only](https://img.shields.io/badge/deps-stdlib%20only-success) ![license: MIT](https://img.shields.io/badge/license-MIT-lightgrey)
63
+
64
+ ---
65
+
66
+ ## Features
67
+
68
+ - **Separate Open File / Start Tail buttons** — *Open File* loads the file once (no following); *Start Tail* follows it for new events, continuing right after the loaded content if you opened it first.
69
+ - **Live tail** — watches the XML file and streams new events to the table as they're written, with proper handling of partial events that get split across writes.
70
+ - **Rotated file support** — point it at a folder and it loads `audit.xml`, `audit.xml-1`, `audit.xml.0` etc. in chronological order, then tails the newest one.
71
+ - **Huawei OceanStor support** — auto-detects Huawei audit XML (`Huawei-Security-Auditing`, namespaced `<Event>`, `<Events>` wrapper). Adds a `Share` column and a Vendor selector in the top bar (Auto / NetApp / Huawei; Auto detects the vendor from the file and shows it in the status bar; CLI: `--vendor huawei`), decodes `%%4416`-style `AccessList` codes, and file-access statistics tabs (Shares, Top objects, File access users, Access types).
72
+ - **Unified columns for both event families** — logon events (4624/4625/4634) and file-operation events (4656/4663/4670/4907) share a single `User` / `IP` / `Object` / `Action` view, so you don't have to know which schema applies.
73
+ - **Filters** — Event ID, Result, User, IP, time range (with `Last 1 hour` / `Last 24 hours` shortcuts), and a free-text search across all fields. Filters apply as you type (debounced).
74
+ - **Right-click drill-in** — right-click any row to instantly filter by that IP/user, or run a combined "this IP + this user, failures only" pivot. Also copies values to clipboard.
75
+ - **Statistics window** — top failure IPs, top failure users, hourly distribution as ASCII bar chart, double-click to filter the main table.
76
+ - **CSV export** — UTF-8 with BOM and `;` delimiter, opens cleanly in Excel with a Turkish or other non-ASCII locale.
77
+ - **CLI flags** — pre-load filters from the command line, e.g. for shortcut-driven workflows.
78
+ - **No installation, no dependencies** — single `.py` file, only Python stdlib (`tkinter` ships with Python on Windows by default).
79
+
80
+ ---
81
+
82
+ ## Install
83
+
84
+ From PyPI:
85
+
86
+ ```bash
87
+ pip install xml-audit-viewer
88
+ xml-audit-viewer
89
+ ```
90
+
91
+ Or run directly from source — no install needed since the only dependency is the Python stdlib:
92
+
93
+ ```bash
94
+ git clone https://github.com/ozdemirumit/XMLAuditViewer.git
95
+ cd XMLAuditViewer
96
+ python xml_audit_viewer.py
97
+ ```
98
+
99
+ Works on Windows, Linux and macOS.
100
+
101
+ ---
102
+
103
+ ## Quick start
104
+
105
+ ```bash
106
+ xml-audit-viewer
107
+ xml-audit-viewer /path/to/audit_log.xml
108
+ xml-audit-viewer /path/to/audit_log.xml --tail
109
+ xml-audit-viewer /path/to/audit_log.xml --filter-ip 10.0.0.5 --only-failures --tail
110
+ ```
111
+
112
+ (If running from source, substitute `python xml_audit_viewer.py` for `xml-audit-viewer`.)
113
+
114
+ ### CLI options
115
+
116
+ | Flag | Description |
117
+ |---|---|
118
+ | `path` (positional) | XML file to open on startup. |
119
+ | `--tail`, `-t` | Auto-open the file and start tailing immediately. |
120
+ | `--filter-ip IP` | Pre-fill the IP-contains filter. |
121
+ | `--filter-user USER` | Pre-fill the user-contains filter. |
122
+ | `--filter-eventid ID` | Pre-filter by a specific Event ID (e.g. `4625`). |
123
+ | `--vendor V` | Vendor label: `auto` (default), `netapp` or `huawei`. |
124
+ | `--only-failures` | Show only `Audit Failure` events on startup. |
125
+
126
+ ---
127
+
128
+ ## Supported events
129
+
130
+ The parser recognises two families of NetApp CIFS audit events and exposes them through unified columns:
131
+
132
+ | Event ID | Name | Family | Key fields |
133
+ |---|---|---|---|
134
+ | 4624 | Logon Attempt | Logon | `TargetUserName`, `IpAddress` |
135
+ | 4625 | Logon Failure | Logon | `TargetUserName`, `IpAddress`, `FailureReasonString` |
136
+ | 4634 | Logoff | Logon | `TargetUserName`, `IpAddress` |
137
+ | 4656 | Open Object | File-op | `SubjectUserName`, `SubjectIP`, `ObjectName`, `DesiredAccess` |
138
+ | 4663 | Get Object Attributes | File-op | `SubjectUserName`, `SubjectIP`, `ObjectName`, `InformationRequested` |
139
+ | 4670 | Permissions Changed | File-op | `SubjectUserName`, `ObjectName`, `OldSD`, `NewSD` |
140
+ | 4907 | Auditing Settings Changed | File-op | `SubjectUserName`, `ObjectName`, `OldSD`, `NewSD` |
141
+
142
+ Other event types are still parsed and shown — only the unified `User`/`IP`/`Object`/`Action` columns may be empty for unrecognised IDs.
143
+
144
+ ---
145
+
146
+ ## Real-world example
147
+
148
+ Here's a quick triage on a 54 MB / 54,806-event audit file from a production CIFS share:
149
+
150
+ ```
151
+ Event distribution
152
+ 4625 Logon Failure 49,839
153
+ 4624 Logon Attempt 3,003
154
+ 4634 Logoff 1,841
155
+ 4656 Open Object 54
156
+ 4663 Get Object Attributes 52
157
+ 4907 Auditing Settings 9
158
+ 4670 Permissions Changed 8
159
+
160
+ Top failure IPs
161
+ 172.17.10.165 37,350 (74.9%) <- single host, almost the whole file
162
+ 172.17.10.150 3,625 (7.3%)
163
+ 172.17.9.9 2,047 (4.1%)
164
+
165
+ Top failure usernames
166
+ tb2783 37,350 (74.9%) <- repeating against the same SVM
167
+ tb1386 3,675 (7.4%)
168
+
169
+ Top failure reasons
170
+ No such user account 44,186 (88.7%)
171
+ User name is correct but the password is wrong 3,858 (7.7%)
172
+ Unknown user name or bad password 1,780 (3.6%)
173
+ ```
174
+
175
+ A single host hammering one username with `No such user account` failures over multiple days — classic credential-stuffing pattern. From the GUI, this is two clicks: open the Statistics window → double-click `172.17.10.165` in the Failure IPs tab → main table is filtered to that IP for further review or CSV export to the SOC team.
176
+
177
+ ---
178
+
179
+ ## Build a Windows `.exe`
180
+
181
+ Ship the viewer to colleagues who don't have Python installed. The build produces a **single, self-contained `XMLAuditViewer.exe`** — the Python runtime, Tcl/Tk and every required DLL are packed inside it, so **no external DLLs, no Python install and no extra files** are needed on the target machine. Copy the one file anywhere and run it.
182
+
183
+ ### Using `build.bat` (recommended)
184
+
185
+ `build.bat` is included in the repo. On a Windows machine with Python 3.10+ installed:
186
+
187
+ 1. Open the repo folder.
188
+ 2. Double-click `build.bat` (or run it from `cmd`).
189
+ 3. Take the result from `dist\XMLAuditViewer.exe`.
190
+
191
+ What the script does:
192
+
193
+ - Removes previous `build\` and `dist\` folders.
194
+ - Installs [PyInstaller](https://pyinstaller.org) with `pip` if it is missing.
195
+ - Runs PyInstaller with `--onefile --windowed --clean`, which gives one exe and no console window.
196
+ - Stops with an error message if the build fails.
197
+
198
+ ### Manual build
199
+
200
+ ```cmd
201
+ pip install pyinstaller
202
+ pyinstaller --noconfirm --onefile --windowed --name "XMLAuditViewer" --clean xml_audit_viewer.py
203
+ ```
204
+
205
+ :**
206
+ - A `--onefile` exe unpacks itself to a temporary folder on every start, so launch takes a second or two longer. Corporate antivirus sometimes flags PyInstaller's onefile bootloader — whitelist the exe if that happens. If it keeps being quarantined, build without `--onefile` (folder build in `dist\XMLAuditViewer\`, more AV-friendly, but you must ship the whole folder).
207
+ - The exe must be built on Windows; PyInstaller cannot cross-compile from Linux/macOS.
208
+ - Add `--icon=audit.ico` if you want a custom icon.
209
+ - For a tiny portable alternative when target machines have Python: `python -m zipapp . -m "xml_audit_viewer:main" -o XMLAuditViewer.pyz` produces a ~40 KB single-file zipapp.
210
+
211
+ ---
212
+
213
+ ## How tail works (technical note)
214
+
215
+ The tail thread reads the file in chunks starting from the last position, keeps a buffer of unparsed bytes, and emits parsed events to the GUI thread via a `queue.Queue`. If a write happens mid-event, the partial bytes stay in the buffer until the closing `</Event>` arrives — no malformed records ever reach the table. File rotation/truncation is detected by comparing on-disk size to the last read position.
216
+
217
+ The GUI never blocks on disk I/O. Filtering is debounced (250 ms) so you can type freely without freezing the UI on a 100k-event dataset.
218
+
219
+ ---
220
+
221
+ ## Limitations
222
+
223
+ - The Treeview shows at most 10,000 rows at a time (configurable via `MAX_DISPLAY_ROWS` at the top of the file). All events are kept in memory; only the displayed slice is capped for rendering performance.
224
+ - Memory footprint is roughly 1.5 KB per event, so 1M events ≈ 1.5 GB RAM. For larger datasets, filter on import or split the file first.
225
+ - Dates and times are interpreted as the literal string in `TimeCreated/@SystemTime` (UTC in NetApp's output). No timezone conversion.
226
+
227
+ ---
228
+
229
+ ## License
230
+
231
+ MIT — see [LICENSE](LICENSE).
232
+
233
+ ## Contributing
234
+
235
+ Issues and PRs welcome. Particularly interested in:
236
+ - Coverage of additional NetApp event IDs (NFS audit, anti-virus events, etc.)
237
+ - Performance improvements for very large files (memory-mapped reading?)
238
+ - Optional Splunk/ELK forwarder mode
@@ -0,0 +1,183 @@
1
+ # XML Audit Viewer
2
+
3
+ A single-file Python GUI for browsing **NetApp ONTAP** and **Huawei OceanStor (e.g. 5510) CIFS Security Audit XML** logs. Opens large files instantly, follows them like `tail -f` as new events are written, and lets you slice the data by user, IP, time range, and event type — with no external dependencies beyond Python's standard library.
4
+
5
+ Built for storage and infrastructure engineers who need to triage `audit_*.xml` output without spinning up Splunk/ELK.
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/xml-audit-viewer.svg)](https://pypi.org/project/xml-audit-viewer/) [![Python versions](https://img.shields.io/pypi/pyversions/xml-audit-viewer.svg)](https://pypi.org/project/xml-audit-viewer/) ![status: working](https://img.shields.io/badge/status-working-brightgreen) ![deps: stdlib only](https://img.shields.io/badge/deps-stdlib%20only-success) ![license: MIT](https://img.shields.io/badge/license-MIT-lightgrey)
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **Separate Open File / Start Tail buttons** — *Open File* loads the file once (no following); *Start Tail* follows it for new events, continuing right after the loaded content if you opened it first.
14
+ - **Live tail** — watches the XML file and streams new events to the table as they're written, with proper handling of partial events that get split across writes.
15
+ - **Rotated file support** — point it at a folder and it loads `audit.xml`, `audit.xml-1`, `audit.xml.0` etc. in chronological order, then tails the newest one.
16
+ - **Huawei OceanStor support** — auto-detects Huawei audit XML (`Huawei-Security-Auditing`, namespaced `<Event>`, `<Events>` wrapper). Adds a `Share` column and a Vendor selector in the top bar (Auto / NetApp / Huawei; Auto detects the vendor from the file and shows it in the status bar; CLI: `--vendor huawei`), decodes `%%4416`-style `AccessList` codes, and file-access statistics tabs (Shares, Top objects, File access users, Access types).
17
+ - **Unified columns for both event families** — logon events (4624/4625/4634) and file-operation events (4656/4663/4670/4907) share a single `User` / `IP` / `Object` / `Action` view, so you don't have to know which schema applies.
18
+ - **Filters** — Event ID, Result, User, IP, time range (with `Last 1 hour` / `Last 24 hours` shortcuts), and a free-text search across all fields. Filters apply as you type (debounced).
19
+ - **Right-click drill-in** — right-click any row to instantly filter by that IP/user, or run a combined "this IP + this user, failures only" pivot. Also copies values to clipboard.
20
+ - **Statistics window** — top failure IPs, top failure users, hourly distribution as ASCII bar chart, double-click to filter the main table.
21
+ - **CSV export** — UTF-8 with BOM and `;` delimiter, opens cleanly in Excel with a Turkish or other non-ASCII locale.
22
+ - **CLI flags** — pre-load filters from the command line, e.g. for shortcut-driven workflows.
23
+ - **No installation, no dependencies** — single `.py` file, only Python stdlib (`tkinter` ships with Python on Windows by default).
24
+
25
+ ---
26
+
27
+ ## Install
28
+
29
+ From PyPI:
30
+
31
+ ```bash
32
+ pip install xml-audit-viewer
33
+ xml-audit-viewer
34
+ ```
35
+
36
+ Or run directly from source — no install needed since the only dependency is the Python stdlib:
37
+
38
+ ```bash
39
+ git clone https://github.com/ozdemirumit/XMLAuditViewer.git
40
+ cd XMLAuditViewer
41
+ python xml_audit_viewer.py
42
+ ```
43
+
44
+ Works on Windows, Linux and macOS.
45
+
46
+ ---
47
+
48
+ ## Quick start
49
+
50
+ ```bash
51
+ xml-audit-viewer
52
+ xml-audit-viewer /path/to/audit_log.xml
53
+ xml-audit-viewer /path/to/audit_log.xml --tail
54
+ xml-audit-viewer /path/to/audit_log.xml --filter-ip 10.0.0.5 --only-failures --tail
55
+ ```
56
+
57
+ (If running from source, substitute `python xml_audit_viewer.py` for `xml-audit-viewer`.)
58
+
59
+ ### CLI options
60
+
61
+ | Flag | Description |
62
+ |---|---|
63
+ | `path` (positional) | XML file to open on startup. |
64
+ | `--tail`, `-t` | Auto-open the file and start tailing immediately. |
65
+ | `--filter-ip IP` | Pre-fill the IP-contains filter. |
66
+ | `--filter-user USER` | Pre-fill the user-contains filter. |
67
+ | `--filter-eventid ID` | Pre-filter by a specific Event ID (e.g. `4625`). |
68
+ | `--vendor V` | Vendor label: `auto` (default), `netapp` or `huawei`. |
69
+ | `--only-failures` | Show only `Audit Failure` events on startup. |
70
+
71
+ ---
72
+
73
+ ## Supported events
74
+
75
+ The parser recognises two families of NetApp CIFS audit events and exposes them through unified columns:
76
+
77
+ | Event ID | Name | Family | Key fields |
78
+ |---|---|---|---|
79
+ | 4624 | Logon Attempt | Logon | `TargetUserName`, `IpAddress` |
80
+ | 4625 | Logon Failure | Logon | `TargetUserName`, `IpAddress`, `FailureReasonString` |
81
+ | 4634 | Logoff | Logon | `TargetUserName`, `IpAddress` |
82
+ | 4656 | Open Object | File-op | `SubjectUserName`, `SubjectIP`, `ObjectName`, `DesiredAccess` |
83
+ | 4663 | Get Object Attributes | File-op | `SubjectUserName`, `SubjectIP`, `ObjectName`, `InformationRequested` |
84
+ | 4670 | Permissions Changed | File-op | `SubjectUserName`, `ObjectName`, `OldSD`, `NewSD` |
85
+ | 4907 | Auditing Settings Changed | File-op | `SubjectUserName`, `ObjectName`, `OldSD`, `NewSD` |
86
+
87
+ Other event types are still parsed and shown — only the unified `User`/`IP`/`Object`/`Action` columns may be empty for unrecognised IDs.
88
+
89
+ ---
90
+
91
+ ## Real-world example
92
+
93
+ Here's a quick triage on a 54 MB / 54,806-event audit file from a production CIFS share:
94
+
95
+ ```
96
+ Event distribution
97
+ 4625 Logon Failure 49,839
98
+ 4624 Logon Attempt 3,003
99
+ 4634 Logoff 1,841
100
+ 4656 Open Object 54
101
+ 4663 Get Object Attributes 52
102
+ 4907 Auditing Settings 9
103
+ 4670 Permissions Changed 8
104
+
105
+ Top failure IPs
106
+ 172.17.10.165 37,350 (74.9%) <- single host, almost the whole file
107
+ 172.17.10.150 3,625 (7.3%)
108
+ 172.17.9.9 2,047 (4.1%)
109
+
110
+ Top failure usernames
111
+ tb2783 37,350 (74.9%) <- repeating against the same SVM
112
+ tb1386 3,675 (7.4%)
113
+
114
+ Top failure reasons
115
+ No such user account 44,186 (88.7%)
116
+ User name is correct but the password is wrong 3,858 (7.7%)
117
+ Unknown user name or bad password 1,780 (3.6%)
118
+ ```
119
+
120
+ A single host hammering one username with `No such user account` failures over multiple days — classic credential-stuffing pattern. From the GUI, this is two clicks: open the Statistics window → double-click `172.17.10.165` in the Failure IPs tab → main table is filtered to that IP for further review or CSV export to the SOC team.
121
+
122
+ ---
123
+
124
+ ## Build a Windows `.exe`
125
+
126
+ Ship the viewer to colleagues who don't have Python installed. The build produces a **single, self-contained `XMLAuditViewer.exe`** — the Python runtime, Tcl/Tk and every required DLL are packed inside it, so **no external DLLs, no Python install and no extra files** are needed on the target machine. Copy the one file anywhere and run it.
127
+
128
+ ### Using `build.bat` (recommended)
129
+
130
+ `build.bat` is included in the repo. On a Windows machine with Python 3.10+ installed:
131
+
132
+ 1. Open the repo folder.
133
+ 2. Double-click `build.bat` (or run it from `cmd`).
134
+ 3. Take the result from `dist\XMLAuditViewer.exe`.
135
+
136
+ What the script does:
137
+
138
+ - Removes previous `build\` and `dist\` folders.
139
+ - Installs [PyInstaller](https://pyinstaller.org) with `pip` if it is missing.
140
+ - Runs PyInstaller with `--onefile --windowed --clean`, which gives one exe and no console window.
141
+ - Stops with an error message if the build fails.
142
+
143
+ ### Manual build
144
+
145
+ ```cmd
146
+ pip install pyinstaller
147
+ pyinstaller --noconfirm --onefile --windowed --name "XMLAuditViewer" --clean xml_audit_viewer.py
148
+ ```
149
+
150
+ :**
151
+ - A `--onefile` exe unpacks itself to a temporary folder on every start, so launch takes a second or two longer. Corporate antivirus sometimes flags PyInstaller's onefile bootloader — whitelist the exe if that happens. If it keeps being quarantined, build without `--onefile` (folder build in `dist\XMLAuditViewer\`, more AV-friendly, but you must ship the whole folder).
152
+ - The exe must be built on Windows; PyInstaller cannot cross-compile from Linux/macOS.
153
+ - Add `--icon=audit.ico` if you want a custom icon.
154
+ - For a tiny portable alternative when target machines have Python: `python -m zipapp . -m "xml_audit_viewer:main" -o XMLAuditViewer.pyz` produces a ~40 KB single-file zipapp.
155
+
156
+ ---
157
+
158
+ ## How tail works (technical note)
159
+
160
+ The tail thread reads the file in chunks starting from the last position, keeps a buffer of unparsed bytes, and emits parsed events to the GUI thread via a `queue.Queue`. If a write happens mid-event, the partial bytes stay in the buffer until the closing `</Event>` arrives — no malformed records ever reach the table. File rotation/truncation is detected by comparing on-disk size to the last read position.
161
+
162
+ The GUI never blocks on disk I/O. Filtering is debounced (250 ms) so you can type freely without freezing the UI on a 100k-event dataset.
163
+
164
+ ---
165
+
166
+ ## Limitations
167
+
168
+ - The Treeview shows at most 10,000 rows at a time (configurable via `MAX_DISPLAY_ROWS` at the top of the file). All events are kept in memory; only the displayed slice is capped for rendering performance.
169
+ - Memory footprint is roughly 1.5 KB per event, so 1M events ≈ 1.5 GB RAM. For larger datasets, filter on import or split the file first.
170
+ - Dates and times are interpreted as the literal string in `TimeCreated/@SystemTime` (UTC in NetApp's output). No timezone conversion.
171
+
172
+ ---
173
+
174
+ ## License
175
+
176
+ MIT — see [LICENSE](LICENSE).
177
+
178
+ ## Contributing
179
+
180
+ Issues and PRs welcome. Particularly interested in:
181
+ - Coverage of additional NetApp event IDs (NFS audit, anti-virus events, etc.)
182
+ - Performance improvements for very large files (memory-mapped reading?)
183
+ - Optional Splunk/ELK forwarder mode
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "xml-audit-viewer"
7
+ version = "1.1.0"
8
+ description = "Python GUI viewer and live-tail tool for NetApp ONTAP and Huawei OceanStor CIFS Security Audit XML logs — stdlib only, no install."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Umit Ozdemir", email = "umitozdemir@gmail.com" }]
13
+ keywords = ["netapp", "huawei", "oceanstor", "ontap", "audit", "xml", "cifs", "smb", "security", "tkinter", "gui", "live-tail"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Environment :: X11 Applications",
17
+ "Environment :: Win32 (MS Windows)",
18
+ "Environment :: MacOS X",
19
+ "Intended Audience :: System Administrators",
20
+ "Intended Audience :: Information Technology",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
+ "Topic :: System :: Logging",
30
+ "Topic :: System :: Monitoring",
31
+ "Topic :: System :: Systems Administration",
32
+ "Topic :: Security",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/ozdemirumit/XMLAuditViewer"
37
+ Repository = "https://github.com/ozdemirumit/XMLAuditViewer"
38
+ Issues = "https://github.com/ozdemirumit/XMLAuditViewer/issues"
39
+ Changelog = "https://github.com/ozdemirumit/XMLAuditViewer/blob/main/CHANGELOG.md"
40
+
41
+ [project.scripts]
42
+ xml-audit-viewer = "xml_audit_viewer:main"
43
+
44
+ [tool.setuptools]
45
+ py-modules = ["xml_audit_viewer"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+