ids2eval 0.2.2__py3-none-any.whl
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.
- ids2eval/__init__.py +0 -0
- ids2eval/__main__.py +4 -0
- ids2eval/_json_utils.py +24 -0
- ids2eval/audit/__init__.py +239 -0
- ids2eval/audit/_auc.py +48 -0
- ids2eval/audit/_by_class.py +29 -0
- ids2eval/audit/_checkpoint.py +74 -0
- ids2eval/audit/_fit_score.py +40 -0
- ids2eval/audit/_materiality.py +28 -0
- ids2eval/audit/_status.py +15 -0
- ids2eval/audit/_time.py +14 -0
- ids2eval/audit/artifact_sensitivity.py +88 -0
- ids2eval/audit/class_distribution.py +57 -0
- ids2eval/audit/cross_capture_matrix.py +115 -0
- ids2eval/audit/cross_dataset_drift.py +74 -0
- ids2eval/audit/data_integrity.py +67 -0
- ids2eval/audit/dedup.py +67 -0
- ids2eval/audit/feature_auc_ranking.py +125 -0
- ids2eval/audit/feature_category_ablation.py +98 -0
- ids2eval/audit/flow_group_leakage.py +66 -0
- ids2eval/audit/homogeneity.py +160 -0
- ids2eval/audit/identity_columns.py +171 -0
- ids2eval/audit/known_issues.py +144 -0
- ids2eval/audit/label_conflict.py +92 -0
- ids2eval/audit/leakage.py +99 -0
- ids2eval/audit/near_duplicate_class.py +87 -0
- ids2eval/audit/one_rule.py +82 -0
- ids2eval/audit/port_protocol_shortcut.py +75 -0
- ids2eval/audit/repeated_seed_falsification.py +182 -0
- ids2eval/audit/resplit.py +92 -0
- ids2eval/audit/result_robustness.py +154 -0
- ids2eval/audit/row_order_leakage.py +86 -0
- ids2eval/audit/scenario_holdout.py +115 -0
- ids2eval/audit/schema_fingerprint.py +52 -0
- ids2eval/audit/seed_sensitivity.py +69 -0
- ids2eval/audit/synthetic_realism.py +73 -0
- ids2eval/audit/temporal_leakage.py +58 -0
- ids2eval/audit/temporal_realism.py +81 -0
- ids2eval/cli.py +284 -0
- ids2eval/config.py +362 -0
- ids2eval/dashboard/__init__.py +1 -0
- ids2eval/dashboard/__main__.py +3 -0
- ids2eval/dashboard/server.py +527 -0
- ids2eval/dashboard/static/app.js +1064 -0
- ids2eval/dashboard/static/charts.js +366 -0
- ids2eval/dashboard/static/index.html +33 -0
- ids2eval/dashboard/static/style.css +293 -0
- ids2eval/data/__init__.py +3 -0
- ids2eval/data/cache.py +99 -0
- ids2eval/data/chunked_io.py +387 -0
- ids2eval/data/dataset.py +208 -0
- ids2eval/data/features.py +95 -0
- ids2eval/data/label_grouping.py +38 -0
- ids2eval/modeling/__init__.py +3 -0
- ids2eval/modeling/benchmark.py +360 -0
- ids2eval/modeling/classifiers.py +145 -0
- ids2eval/modeling/preprocessing.py +73 -0
- ids2eval/reporting/__init__.py +2 -0
- ids2eval/reporting/cite.py +57 -0
- ids2eval/reporting/compare_datasets.py +103 -0
- ids2eval/reporting/drift.py +80 -0
- ids2eval/reporting/intervention_manifest.py +83 -0
- ids2eval/reporting/recommend.py +402 -0
- ids2eval/reporting/run_manager.py +184 -0
- ids2eval/reporting/scorecard.py +875 -0
- ids2eval/reporting/scorecard_plot.py +162 -0
- ids2eval/version_info.py +36 -0
- ids2eval-0.2.2.dist-info/METADATA +119 -0
- ids2eval-0.2.2.dist-info/RECORD +73 -0
- ids2eval-0.2.2.dist-info/WHEEL +5 -0
- ids2eval-0.2.2.dist-info/entry_points.txt +4 -0
- ids2eval-0.2.2.dist-info/licenses/LICENSE +661 -0
- ids2eval-0.2.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Renders the scorecard as a figure (PDF + PNG): the verdict, the full
|
|
2
|
+
per-check breakdown (name, status, and *why* - the check's own summary
|
|
3
|
+
for this run), and diagnostic charts where applicable. A bare status-count
|
|
4
|
+
chart was tried first and dropped - "8 ok, 1 warning" means nothing
|
|
5
|
+
without seeing which checks and why, so the checks list is the main
|
|
6
|
+
content, not an afterthought.
|
|
7
|
+
|
|
8
|
+
PDF is the publication-grade vector figure meant to be cited/embedded
|
|
9
|
+
directly in a paper; PNG is a raster preview of the exact same figure,
|
|
10
|
+
embedded in SCORECARD.md so the chart shows up inline on GitHub (PDFs
|
|
11
|
+
don't render in Markdown previews) - SCORECARD.md constrains its display
|
|
12
|
+
width explicitly, since GitHub renders an embedded image at full native
|
|
13
|
+
size otherwise.
|
|
14
|
+
|
|
15
|
+
Requires matplotlib - an optional extra (`pip install "ids2eval[plots]"`),
|
|
16
|
+
not a core dependency, so importing ids2eval.scorecard never needs it.
|
|
17
|
+
config.py's validate_config() already confirms matplotlib is importable
|
|
18
|
+
before this module is ever touched, so no import-error handling here.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import textwrap
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
import matplotlib
|
|
27
|
+
|
|
28
|
+
matplotlib.use("Agg") # headless - never touches a display, safe in CI/servers
|
|
29
|
+
|
|
30
|
+
import matplotlib.pyplot as plt
|
|
31
|
+
|
|
32
|
+
_STATUS_COLOR = {"ok": "#1a7f4e", "warning": "#a15c00", "flag": "#b3261e", "not_applicable": "#8a8f99"}
|
|
33
|
+
_VERDICT_TEXT = {"passed": "PASSED", "passed_with_warnings": "PASSED WITH WARNINGS", "review_required": "REVIEW REQUIRED",
|
|
34
|
+
"not_evaluated": "NOT EVALUATED"}
|
|
35
|
+
_VERDICT_STATUS = {"passed": "ok", "passed_with_warnings": "warning", "review_required": "flag",
|
|
36
|
+
"not_evaluated": "not_applicable"}
|
|
37
|
+
_INK = "#16181c"
|
|
38
|
+
_MUTED = "#5b5f6a"
|
|
39
|
+
_ACCENT = "#0d8f82"
|
|
40
|
+
|
|
41
|
+
_SUMMARY_WRAP_WIDTH = 92
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _find(findings: list[dict], check: str) -> dict | None:
|
|
45
|
+
return next((f for f in findings if f["check"] == check), None)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def render(scorecard: dict, findings: list[dict], pdf_path: Path, png_path: Path) -> None:
|
|
49
|
+
class_dist = _find(findings, "class_distribution_report")
|
|
50
|
+
leakage = _find(findings, "leakage_screen")
|
|
51
|
+
has_leakage_panel = leakage is not None and "top_features" in leakage.get("details", {})
|
|
52
|
+
|
|
53
|
+
wrapped = [(f, textwrap.wrap(f["summary"], width=_SUMMARY_WRAP_WIDTH) or [""]) for f in findings]
|
|
54
|
+
checks_lines = sum(1 + len(lines) + 0.35 for _, lines in wrapped)
|
|
55
|
+
# Generous on purpose: this panel is raw ax.text(), not axes titles/ticks,
|
|
56
|
+
# so matplotlib's own layout engines can't see its content to avoid
|
|
57
|
+
# collisions with the panel below - the padding has to be manual.
|
|
58
|
+
checks_panel_height = 0.6 + checks_lines * 0.26
|
|
59
|
+
|
|
60
|
+
n_diagnostic_panels = (class_dist is not None) + has_leakage_panel
|
|
61
|
+
fig_height = 1.0 + checks_panel_height + n_diagnostic_panels * 2.6
|
|
62
|
+
fig = plt.figure(figsize=(7.5, fig_height))
|
|
63
|
+
height_ratios = [1.0, checks_panel_height, *([2.6] * n_diagnostic_panels)]
|
|
64
|
+
gs = fig.add_gridspec(nrows=2 + n_diagnostic_panels, ncols=1, height_ratios=height_ratios, hspace=0.55)
|
|
65
|
+
|
|
66
|
+
_draw_header(fig.add_subplot(gs[0]), scorecard)
|
|
67
|
+
_draw_checks_list(fig.add_subplot(gs[1]), wrapped)
|
|
68
|
+
|
|
69
|
+
row = 2
|
|
70
|
+
if class_dist is not None:
|
|
71
|
+
_draw_class_distribution(fig.add_subplot(gs[row]), class_dist)
|
|
72
|
+
row += 1
|
|
73
|
+
if has_leakage_panel:
|
|
74
|
+
_draw_feature_importance(fig.add_subplot(gs[row]), leakage)
|
|
75
|
+
row += 1
|
|
76
|
+
|
|
77
|
+
fig.text(
|
|
78
|
+
0.01, 0.005,
|
|
79
|
+
"Verdict rule: any flag -> review required · warnings only -> passed with warnings · all ok -> passed",
|
|
80
|
+
fontsize=7, color=_MUTED,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
fig.savefig(pdf_path, format="pdf", bbox_inches="tight")
|
|
84
|
+
fig.savefig(png_path, format="png", dpi=130, bbox_inches="tight")
|
|
85
|
+
plt.close(fig)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _draw_header(ax, scorecard: dict) -> None:
|
|
89
|
+
ax.axis("off")
|
|
90
|
+
verdict = scorecard["overall_status"]
|
|
91
|
+
counts = {"ok": 0, "warning": 0, "flag": 0, "not_applicable": 0}
|
|
92
|
+
for f in scorecard["findings"]:
|
|
93
|
+
counts[f["status"]] += 1
|
|
94
|
+
counts_text = (
|
|
95
|
+
f"{counts['ok']} ok · {counts['warning']} warning · {counts['flag']} flag · "
|
|
96
|
+
+ (f"{counts['not_applicable']} n/a · " if counts["not_applicable"] else "")
|
|
97
|
+
+ f"{sum(counts.values())} checks"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
ax.text(0, 0.8, "IDS2Eval Scorecard", fontsize=16, fontweight="bold", color=_INK, transform=ax.transAxes)
|
|
101
|
+
ax.text(0, 0.42, scorecard["dataset_name"], fontsize=11, color=_MUTED, transform=ax.transAxes)
|
|
102
|
+
ax.text(0, 0.08, counts_text, fontsize=9.5, color=_INK, transform=ax.transAxes)
|
|
103
|
+
ax.text(
|
|
104
|
+
1, 0.55, _VERDICT_TEXT[verdict], fontsize=13, fontweight="bold", color="white",
|
|
105
|
+
ha="right", va="center", transform=ax.transAxes,
|
|
106
|
+
bbox={"boxstyle": "round,pad=0.4", "facecolor": _STATUS_COLOR[_VERDICT_STATUS[verdict]], "edgecolor": "none"},
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _draw_checks_list(ax, wrapped: list[tuple[dict, list[str]]]) -> None:
|
|
111
|
+
total_lines = sum(1 + len(lines) + 0.35 for _, lines in wrapped)
|
|
112
|
+
ax.set_xlim(0, 1)
|
|
113
|
+
ax.set_ylim(0, max(total_lines, 1))
|
|
114
|
+
ax.axis("off")
|
|
115
|
+
|
|
116
|
+
y = total_lines
|
|
117
|
+
for f, lines in wrapped:
|
|
118
|
+
y -= 1
|
|
119
|
+
color = _STATUS_COLOR[f["status"]]
|
|
120
|
+
ax.text(0.0, y, "●", color=color, fontsize=11, va="top")
|
|
121
|
+
ax.text(0.028, y, f["check"], color=_INK, fontsize=9.3, fontweight="bold", family="monospace", va="top")
|
|
122
|
+
label = "n/a" if f["status"] == "not_applicable" else f["status"]
|
|
123
|
+
ax.text(0.99, y, label, color=color, fontsize=8.8, fontweight="bold", va="top", ha="right")
|
|
124
|
+
for line in lines:
|
|
125
|
+
y -= 1
|
|
126
|
+
ax.text(0.028, y, line, color=_MUTED, fontsize=8.3, va="top")
|
|
127
|
+
y -= 0.35
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _draw_class_distribution(ax, finding: dict) -> None:
|
|
131
|
+
details = finding["details"]
|
|
132
|
+
train_counts, test_counts = details["train"]["counts"], details["test"]["counts"]
|
|
133
|
+
classes = list(train_counts)
|
|
134
|
+
classes += [c for c in test_counts if c not in classes]
|
|
135
|
+
|
|
136
|
+
x = range(len(classes))
|
|
137
|
+
width = 0.35
|
|
138
|
+
ax.bar([i - width / 2 for i in x], [train_counts.get(c, 0) for c in classes], width, label="train", color=_ACCENT)
|
|
139
|
+
ax.bar([i + width / 2 for i in x], [test_counts.get(c, 0) for c in classes], width, label="test", color=_MUTED)
|
|
140
|
+
ax.set_yscale("log")
|
|
141
|
+
ax.set_xticks(list(x))
|
|
142
|
+
# Short labels (e.g. numeric 0/1 label columns) sit horizontally - no
|
|
143
|
+
# need to eat vertical space rotating something that already fits.
|
|
144
|
+
needs_rotation = max(len(str(c)) for c in classes) > 6
|
|
145
|
+
if needs_rotation:
|
|
146
|
+
ax.set_xticklabels(classes, rotation=20, ha="right", fontsize=9)
|
|
147
|
+
else:
|
|
148
|
+
ax.set_xticklabels(classes, fontsize=9)
|
|
149
|
+
ax.set_title("Class distribution (log scale)", fontsize=11, color=_INK, loc="left")
|
|
150
|
+
ax.legend(frameon=False, fontsize=9)
|
|
151
|
+
ax.spines[["top", "right"]].set_visible(False)
|
|
152
|
+
ax.tick_params(colors=_MUTED)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _draw_feature_importance(ax, finding: dict) -> None:
|
|
156
|
+
top_features = finding["details"]["top_features"]
|
|
157
|
+
names = list(top_features)[::-1]
|
|
158
|
+
values = [top_features[name] for name in names]
|
|
159
|
+
ax.barh(names, values, color=_STATUS_COLOR["flag"])
|
|
160
|
+
ax.set_title("Top feature importances (leakage_screen)", fontsize=11, color=_INK, loc="left")
|
|
161
|
+
ax.spines[["top", "right"]].set_visible(False)
|
|
162
|
+
ax.tick_params(colors=_MUTED)
|
ids2eval/version_info.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Best-effort software version info for cache invalidation and run provenance.
|
|
2
|
+
|
|
3
|
+
Used by cache.py's fingerprint (so a code change to loading/splitting
|
|
4
|
+
logic invalidates an existing cache even when the config and input
|
|
5
|
+
files haven't changed) and run_manager.py's environment.json.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import shutil
|
|
11
|
+
import subprocess
|
|
12
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_version_info() -> dict:
|
|
17
|
+
try:
|
|
18
|
+
pkg_version = version("ids2eval")
|
|
19
|
+
except PackageNotFoundError:
|
|
20
|
+
pkg_version = "unknown (not pip-installed)"
|
|
21
|
+
|
|
22
|
+
git_commit = None
|
|
23
|
+
git_path = shutil.which("git") # resolve full path, not a bare "git" off PATH
|
|
24
|
+
if git_path:
|
|
25
|
+
try:
|
|
26
|
+
result = subprocess.run( # noqa: S603 - fixed args, no untrusted input
|
|
27
|
+
[git_path, "rev-parse", "HEAD"],
|
|
28
|
+
cwd=Path(__file__).parent,
|
|
29
|
+
capture_output=True, text=True, timeout=5, check=False,
|
|
30
|
+
)
|
|
31
|
+
if result.returncode == 0:
|
|
32
|
+
git_commit = result.stdout.strip()
|
|
33
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
return {"version": pkg_version, "git_commit": git_commit}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ids2eval
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Config-driven data-quality-audit and benchmarking toolkit for NIDS datasets
|
|
5
|
+
License-Expression: AGPL-3.0-only
|
|
6
|
+
Project-URL: Homepage, https://hashtagRR.github.io/IDS2Eval
|
|
7
|
+
Project-URL: Source, https://github.com/hashtagRR/IDS2Eval
|
|
8
|
+
Project-URL: Issues, https://github.com/hashtagRR/IDS2Eval/issues
|
|
9
|
+
Project-URL: Documentation, https://github.com/hashtagRR/IDS2Eval/blob/main/guide/usage.md
|
|
10
|
+
Keywords: intrusion detection,NIDS,dataset audit,data quality,benchmarking,machine learning
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Requires-Python: <3.14,>=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: pyyaml
|
|
25
|
+
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: numpy
|
|
27
|
+
Requires-Dist: scikit-learn>=1.4
|
|
28
|
+
Requires-Dist: scipy
|
|
29
|
+
Requires-Dist: imbalanced-learn
|
|
30
|
+
Requires-Dist: xgboost
|
|
31
|
+
Requires-Dist: pyarrow
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff; extra == "dev"
|
|
35
|
+
Provides-Extra: plots
|
|
36
|
+
Requires-Dist: matplotlib; extra == "plots"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# IDS<sup>2</sup>Eval
|
|
40
|
+
|
|
41
|
+
**[hashtagRR.github.io/IDS2Eval](https://hashtagRR.github.io/IDS2Eval)**
|
|
42
|
+
|
|
43
|
+
[](https://pypi.org/project/ids2eval/)
|
|
44
|
+
[](https://doi.org/10.5281/zenodo.23217300)
|
|
45
|
+
|
|
46
|
+
<p align="center">
|
|
47
|
+
<img src="https://raw.githubusercontent.com/hashtagRR/IDS2Eval/main/docs/img/ids2eval-overview.svg" width="100%"
|
|
48
|
+
alt="IDS2Eval overview: a NIDS dataset and a YAML config go through four kinds of check (diagnose, 18 checks; control, 1; intervene, 8; look up known issues, 1), run on the raw data and again after removing duplicates, and every verdict lands in one scorecard. ids2eval recommend suggests config fixes for flagged checks.">
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
A config-driven toolkit that audits network intrusion detection (NIDS)
|
|
52
|
+
datasets before you trust a result on them. It runs 28 checks for
|
|
53
|
+
duplicated rows, label conflicts, one-column shortcuts and split
|
|
54
|
+
problems, tests whether a suspected problem actually changes the
|
|
55
|
+
accuracy, and records every verdict in a citable scorecard.
|
|
56
|
+
|
|
57
|
+
*IDS<sup>2</sup> reads both ways: **I**ntrusion **D**etection **S**ystems and
|
|
58
|
+
**I**ntrusion **D**ata **S**ets.*
|
|
59
|
+
|
|
60
|
+
## Quickstart
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python3 -m venv venv && venv/bin/pip install "ids2eval[plots]"
|
|
64
|
+
venv/bin/ids2eval-dashboard # web UI with a pre-filled config editor
|
|
65
|
+
venv/bin/ids2eval run --config my_config.yaml # or the CLI, with a config like the one below
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
# my_config.yaml: any NIDS dataset in CSV or Parquet form
|
|
70
|
+
dataset:
|
|
71
|
+
name: my-dataset
|
|
72
|
+
raw_files: ["data.csv"]
|
|
73
|
+
schema:
|
|
74
|
+
label_column: Label
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Windows, installing from the source code, and troubleshooting: [INSTALL.md](https://github.com/hashtagRR/IDS2Eval/blob/main/INSTALL.md).
|
|
78
|
+
|
|
79
|
+
## Documentation
|
|
80
|
+
|
|
81
|
+
| Guide | What it covers |
|
|
82
|
+
|---|---|
|
|
83
|
+
| [Usage](https://github.com/hashtagRR/IDS2Eval/blob/main/guide/usage.md) | the CLI, the dashboard, output files, caching, reproducing a run, and the Python API |
|
|
84
|
+
| [Config fields](https://github.com/hashtagRR/IDS2Eval/blob/main/configs/README.md) | every config field, with its default and an example |
|
|
85
|
+
| [Configuration notes](https://github.com/hashtagRR/IDS2Eval/blob/main/guide/configuration.md) | the reasoning behind non-obvious fields, and larger worked examples |
|
|
86
|
+
| [Checks](https://github.com/hashtagRR/IDS2Eval/blob/main/guide/checks.md) | what each of the 28 checks does, the research behind it, and the scorecard's verdict rule |
|
|
87
|
+
| [Example scorecards](https://github.com/hashtagRR/IDS2Eval/blob/main/examples/README.md) | the real audit runs behind the paper, on seven widely used NIDS benchmarks |
|
|
88
|
+
| [Paper results](https://github.com/hashtagRR/IDS2Eval/blob/main/results/README.md) | configurations, scorecards and analysis outputs behind the accompanying paper |
|
|
89
|
+
| [Known issues](https://github.com/hashtagRR/IDS2Eval/blob/main/guide/contributing-known-issues.md) | how to add a curated known issue or extractor fingerprint |
|
|
90
|
+
| [Install guide](https://github.com/hashtagRR/IDS2Eval/blob/main/INSTALL.md) | platform setup, extras, tests and lint, including Windows |
|
|
91
|
+
| [Contributing](https://github.com/hashtagRR/IDS2Eval/blob/main/CONTRIBUTING.md) | development setup and how releases are made |
|
|
92
|
+
| [Project site](https://hashtagRR.github.io/IDS2Eval) | the project's overview page |
|
|
93
|
+
|
|
94
|
+
## Versions
|
|
95
|
+
|
|
96
|
+
Every release and its changes are in the [changelog](https://github.com/hashtagRR/IDS2Eval/blob/main/CHANGELOG.md); each one is archived on Zenodo under the concept DOI above.
|
|
97
|
+
|
|
98
|
+
- **`v0.2.1`** ([10.5281/zenodo.23301210](https://doi.org/10.5281/zenodo.23301210)): a check with no input to test reports `not_applicable` instead of `ok`, an audit in which no check produced a result is `not_evaluated` instead of passed, scorecards list the checks a config left disabled (schema 1.4), and known-issue warnings name the release they document; no statistic or threshold changed. Also adds the validation scripts and results of the paper's revision (host-disjoint splits, workflow ablation, interval coverage, class-adjusted reuse, a comparison with Flood et al.'s released heuristics).
|
|
99
|
+
- **`v0.2.0`** ([10.5281/zenodo.23217301](https://doi.org/10.5281/zenodo.23217301)): the code, configurations and results behind the accompanying paper on auditing NIDS benchmarks (in preparation).
|
|
100
|
+
|
|
101
|
+
IDS<sup>2</sup>Eval grew out of the dataset-auditing code of research on
|
|
102
|
+
machine-learning-based network intrusion detection, generalized into a
|
|
103
|
+
dataset-independent toolkit.
|
|
104
|
+
|
|
105
|
+
## Citing
|
|
106
|
+
|
|
107
|
+
Cite the version you used. The concept DOI
|
|
108
|
+
[10.5281/zenodo.23217300](https://doi.org/10.5281/zenodo.23217300)
|
|
109
|
+
always resolves to the latest version.
|
|
110
|
+
|
|
111
|
+
> Relapanawa, R. (2026). *IDS2Eval 0.2.1* (Version v0.2.1) [Computer software]. Zenodo. https://doi.org/10.5281/zenodo.23301210
|
|
112
|
+
|
|
113
|
+
The results, configurations and analysis scripts behind the accompanying paper are archived separately:
|
|
114
|
+
|
|
115
|
+
> Relapanawa, R. (2026). *IDS2Eval paper: research artifacts (results, configurations and analysis scripts)* [Dataset]. Zenodo. https://doi.org/10.5281/zenodo.23301258
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
AGPL-3.0. See [LICENSE](https://github.com/hashtagRR/IDS2Eval/blob/main/LICENSE).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
ids2eval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
ids2eval/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
|
|
3
|
+
ids2eval/_json_utils.py,sha256=X9NMLhgR7M1e03eH6g1tsM8CupiekTzQursUXY-vuXw,817
|
|
4
|
+
ids2eval/cli.py,sha256=D7j4xqO3IIXaXQvgSO8jZu1bsdM7n3YABgpjxikHfOs,13642
|
|
5
|
+
ids2eval/config.py,sha256=frbQoFNYZTiQpBjwU_m2emDAwiojxR2_bkBeesvJL5M,17028
|
|
6
|
+
ids2eval/version_info.py,sha256=G3rxvo3zl5QPsxoaiaVS4OAnd7FM6DxC1zfTOoyUvbI,1230
|
|
7
|
+
ids2eval/audit/__init__.py,sha256=zfyAmTm33C0WA6eUTYdy4FMC35r2AjKZAx9rlX6ELh8,12534
|
|
8
|
+
ids2eval/audit/_auc.py,sha256=rv3nQ6eLXzbcvULvk8DJKalBOwoiUKkqKQbCQveZzvY,1990
|
|
9
|
+
ids2eval/audit/_by_class.py,sha256=kPFYZcL4WTtbNM7VEiOnnC3PBr8waMi3F-t-luLDS-Y,1013
|
|
10
|
+
ids2eval/audit/_checkpoint.py,sha256=vWHXHfYwBe-zoJxnETtD-qQ2mnBDowiSKkvgZFFd8sA,2548
|
|
11
|
+
ids2eval/audit/_fit_score.py,sha256=PhJZkBCeZc3i8aNOe-_IFo_YkzR4Zj3ZC5rKCC9FHvI,1737
|
|
12
|
+
ids2eval/audit/_materiality.py,sha256=hY6Tl9Ls5sb3RcQZUgTZppehEOMCBsM1FGotbrEARno,1339
|
|
13
|
+
ids2eval/audit/_status.py,sha256=qgWYYH-dkS-wF_HkmoIhQgDw3m1Ro6lSJ-nikFr2BNs,550
|
|
14
|
+
ids2eval/audit/_time.py,sha256=KfGxR8iGh9l_aYGTdYmVLNIvQdE64cwipczXg96YamM,395
|
|
15
|
+
ids2eval/audit/artifact_sensitivity.py,sha256=kmkr7O_dk_D7V7xcZozMlXZdT2m3wWOgf2yhiiZGRaE,3854
|
|
16
|
+
ids2eval/audit/class_distribution.py,sha256=fPr5EroRzkIJruRYu6ITNCe75M6LrgrK9VNAthR3kcc,2209
|
|
17
|
+
ids2eval/audit/cross_capture_matrix.py,sha256=HXPmWBsyg6btnfL7VcVjwpRUezYxQoGNc2f8cULX2w0,4686
|
|
18
|
+
ids2eval/audit/cross_dataset_drift.py,sha256=JnNOtEb--W_13LslIY6NSr9IYQs6JW4ivc6w4NO7k4M,3177
|
|
19
|
+
ids2eval/audit/data_integrity.py,sha256=A0MGDfhAwIVIKtOFSK8sWvdmpyYRtnkVuz9ocJdgxCo,2646
|
|
20
|
+
ids2eval/audit/dedup.py,sha256=QLvsmgY0uR-6uhvKWAKDqC9PfyPPLDWc6WiGRn5Rneo,2837
|
|
21
|
+
ids2eval/audit/feature_auc_ranking.py,sha256=HicQKuicfk1LJy4C3_1jhIwEVG0Y8ox9EyH7KDaDnlc,5156
|
|
22
|
+
ids2eval/audit/feature_category_ablation.py,sha256=A8watluBQhbh4UHMrKeibSrUwHc8D-A1M1U-ElqoWQA,4064
|
|
23
|
+
ids2eval/audit/flow_group_leakage.py,sha256=Sd-3W1mvqNrdLuGNsMZtjifBwH1EYWrLTrPUbX0lBQM,2937
|
|
24
|
+
ids2eval/audit/homogeneity.py,sha256=3-Ekl5WWSzAsixY006cttknlSqPVDToemBYteM0Kl3A,7369
|
|
25
|
+
ids2eval/audit/identity_columns.py,sha256=TxWy1R-Om8hwXQavd4_yStkxApHNAFaBKEPNkop7h3U,8274
|
|
26
|
+
ids2eval/audit/known_issues.py,sha256=uJ_ddVacwwGRrY-OkDthIQQnHFYjMRbxHKwUJkmwJ1g,7552
|
|
27
|
+
ids2eval/audit/label_conflict.py,sha256=bi25ieyk0n7Ql1lQZ7Wl10MiYE2s17kh8zV69iZIzlU,4293
|
|
28
|
+
ids2eval/audit/leakage.py,sha256=k9F3p7cQbQZ-Yp-3myF1dQZQiSWdv2C9ttht7o1mNIA,4501
|
|
29
|
+
ids2eval/audit/near_duplicate_class.py,sha256=Stiexlch-BLbp85-nAgPqK8yjxlB7zzf3EbJx9I-Iww,3541
|
|
30
|
+
ids2eval/audit/one_rule.py,sha256=Y9DP7qfutBZF-zMJED_PfvR3geXmqMqDEHER7pUGfhg,3846
|
|
31
|
+
ids2eval/audit/port_protocol_shortcut.py,sha256=ZrDVdMqvAeegtg7DkfhgAbgCT1FmU6-LK0A9qIUYtSk,3270
|
|
32
|
+
ids2eval/audit/repeated_seed_falsification.py,sha256=Xd1b-T31_QX72RkyR-laAAkVIcsmQAmwrRN4qSBz8Gk,8796
|
|
33
|
+
ids2eval/audit/resplit.py,sha256=GtG_ChHbrLtuOHawDrmd7IyQpZupbfmZS5GVLtIf2YI,4739
|
|
34
|
+
ids2eval/audit/result_robustness.py,sha256=QOprmMPO7TVZxPLEueHK8EYQ0gjbjMV5ls0nNI8g_90,7041
|
|
35
|
+
ids2eval/audit/row_order_leakage.py,sha256=GFc05TjY_1fIymDth7wyqjOijm9oQ_Ay5KrMB0e-YmY,3434
|
|
36
|
+
ids2eval/audit/scenario_holdout.py,sha256=4AaZ4RCQotsaMlL8XLjzn6sS81bMwt5XfUGbmeNz3xM,4902
|
|
37
|
+
ids2eval/audit/schema_fingerprint.py,sha256=yqS6b7jCiSnPHkEulqKxjzRG5pERn77wcGidoR42pEo,2033
|
|
38
|
+
ids2eval/audit/seed_sensitivity.py,sha256=QO5tRD-AlrXM9h1PNKaq7KGfJzuIczQCHMCogzitg10,2935
|
|
39
|
+
ids2eval/audit/synthetic_realism.py,sha256=lkF5C2iLYaKzaFQ2owSvlge_yLNlpijHj7-YlUW7bZg,3130
|
|
40
|
+
ids2eval/audit/temporal_leakage.py,sha256=E2IVS1wGKQ5tF0qFOpNthy_28mcKCdum7vOuZlBTTrQ,2554
|
|
41
|
+
ids2eval/audit/temporal_realism.py,sha256=mdmf7JDNA_JiFs8J038Bv3umdbxkv1A6APeQp0Fa2PE,3188
|
|
42
|
+
ids2eval/dashboard/__init__.py,sha256=qgB7NuQZzOoTLiPZYmdBL8Cv5TEg1n-bXSrYhm-U1Bg,88
|
|
43
|
+
ids2eval/dashboard/__main__.py,sha256=3dYKHfmWsrdExFlTFlcR5a_icR9fAkn06Yh14TQkEd8,33
|
|
44
|
+
ids2eval/dashboard/server.py,sha256=whBKSYeVrO0l36F1g5ZncRsg7WlcWcE4zli45c7CXsM,24936
|
|
45
|
+
ids2eval/dashboard/static/app.js,sha256=Mk5w5oAvoJKM-j2Eca5pIma3p5km4QeYtD_D5gNCbdI,61742
|
|
46
|
+
ids2eval/dashboard/static/charts.js,sha256=okUnQCamDkGlQpJ9Df3yaz6QIQ89soSahIOGp-QI02Y,21719
|
|
47
|
+
ids2eval/dashboard/static/index.html,sha256=St2kLtNGBQoHecozwmBmyI881N-ATTX4zKkHJygoY3E,1287
|
|
48
|
+
ids2eval/dashboard/static/style.css,sha256=OHolv5eJ9-L3gtAsGlERoMA6mlnTYp6hAEQdluq7_H0,19294
|
|
49
|
+
ids2eval/data/__init__.py,sha256=eF1sOPeC4XXjFEylQy_hLS7cI57rfuO3btaw3UUcado,108
|
|
50
|
+
ids2eval/data/cache.py,sha256=pAiPUbnZcfPBr94MHsKi-6xKiazAX_x3VheIB2rIZ0I,4046
|
|
51
|
+
ids2eval/data/chunked_io.py,sha256=cLvRm95tWirVcmky61KDnlsd3N0FqKcRBGjEPieklcw,19501
|
|
52
|
+
ids2eval/data/dataset.py,sha256=XxbmYRDOCvWFCYTPVLuDezgCN6gue2dablqAcSWxksY,8995
|
|
53
|
+
ids2eval/data/features.py,sha256=hSnZL1V6TBizSomoOa9jD9_n_aPbUZS9sDsa4-8iYtg,4359
|
|
54
|
+
ids2eval/data/label_grouping.py,sha256=UuCMGb4aS8N6yWUYK8jfXtS5O75FpSlE6S40-8YaZpk,1275
|
|
55
|
+
ids2eval/modeling/__init__.py,sha256=qf7pZjgt9OW_dmy_w_G7jOv8g6GyXB_SJNzI8l1Cs04,89
|
|
56
|
+
ids2eval/modeling/benchmark.py,sha256=kzdyRneKIjVAaVBvKKGg69rgJ_9PYQ3WbJSpFNDNs1U,17165
|
|
57
|
+
ids2eval/modeling/classifiers.py,sha256=WE2m1qDgL1tm2-07CkY1LYv7auHkONi84KoqcZYHvPE,6194
|
|
58
|
+
ids2eval/modeling/preprocessing.py,sha256=SNJGwvCQ7dAiuBstdp8p0iVsdqIF51FH8ZtvD3q8mCY,2724
|
|
59
|
+
ids2eval/reporting/__init__.py,sha256=rKnMrOQ0bbPZWqkBCkYHzGBDpLX_svX-RqWz_N0sPNk,77
|
|
60
|
+
ids2eval/reporting/cite.py,sha256=pGZSifgSfcCNDS9AIwRKK8eldw44NNU9CgEYUnVROmw,2191
|
|
61
|
+
ids2eval/reporting/compare_datasets.py,sha256=MnpZFreae3Wu448h37hl3p8_D9oqEB9xpmHk3278lSc,4727
|
|
62
|
+
ids2eval/reporting/drift.py,sha256=U2ecHWSXybaetLvAj7jKTuVcc9CH7ygbPDDnye1w3RY,3237
|
|
63
|
+
ids2eval/reporting/intervention_manifest.py,sha256=TOmto4UyRUCIkjg1579lNPTmi_E1i9IiLS3w97tj32Q,4827
|
|
64
|
+
ids2eval/reporting/recommend.py,sha256=Rwd1NvedMiVFbcmmQqRxw8IRiKjgw3POisHpiPILdxo,19516
|
|
65
|
+
ids2eval/reporting/run_manager.py,sha256=xutWFYaRvybpBqE7L7mGtlWwCJPI7aK5yAgx1lV0BgI,7826
|
|
66
|
+
ids2eval/reporting/scorecard.py,sha256=Lfr5QvWGpc1jxh_oU3Ft_YMi96cS9aiy3dGx0X88Pf4,45347
|
|
67
|
+
ids2eval/reporting/scorecard_plot.py,sha256=MUXz1Pk6TWB3Z-BClkcdihNjVMCwofu7S_PcYPy0JFc,7239
|
|
68
|
+
ids2eval-0.2.2.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
69
|
+
ids2eval-0.2.2.dist-info/METADATA,sha256=06DmpyuZd2NpNlQcXt0BT9Kr5FQYZ18cZ6EcVO7j6N8,6661
|
|
70
|
+
ids2eval-0.2.2.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
71
|
+
ids2eval-0.2.2.dist-info/entry_points.txt,sha256=q8WZWzs0tBuj__nI-WSiqMdvARdmZKBafRRysSVyNIY,144
|
|
72
|
+
ids2eval-0.2.2.dist-info/top_level.txt,sha256=Mo1n5SGhQw6FYJMTRXJQ-0n4Y6IY4ZGr1ahX5OKJg74,9
|
|
73
|
+
ids2eval-0.2.2.dist-info/RECORD,,
|