Spaces:
Sleeping
Sleeping
nr-bundle-classifier — initial release (V8 binary + multiclass-folded, 2026-05-13)
Browse files- LICENSE +191 -0
- README.md +71 -8
- app.py +282 -0
- release-cert.json +137 -0
- requirements.txt +7 -0
LICENSE
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of tracking or improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for describing the origin of the Work and
|
| 141 |
+
reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Support. While redistributing the Work or
|
| 166 |
+
Derivative Works thereof, You may accept upon your own behalf the
|
| 167 |
+
responsibility to provide, and accept charging a fee for, accepting
|
| 168 |
+
warranty, support, indemnity, or other liability obligations and/or
|
| 169 |
+
rights consistent with this License. However, in accepting such
|
| 170 |
+
obligations, You may act only on Your own behalf and on Your sole
|
| 171 |
+
responsibility, not on behalf of any other Contributor, and only
|
| 172 |
+
if You agree to indemnify, defend, and hold each Contributor
|
| 173 |
+
harmless for any liability incurred by, or claims asserted against,
|
| 174 |
+
such Contributor by reason of your accepting any such warranty
|
| 175 |
+
or support.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
Copyright 2026 NullRabbit Labs Ltd
|
| 180 |
+
|
| 181 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 182 |
+
you may not use this file except in compliance with the License.
|
| 183 |
+
You may obtain a copy of the License at
|
| 184 |
+
|
| 185 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 186 |
+
|
| 187 |
+
Unless required by applicable law or agreed to in writing, software
|
| 188 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 189 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 190 |
+
implied. See the License for the specific language governing
|
| 191 |
+
permissions and limitations under the License.
|
README.md
CHANGED
|
@@ -1,13 +1,76 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version: '3.13'
|
| 9 |
app_file: app.py
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: nr-bundle-classifier
|
| 3 |
+
emoji: 🛡️
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 4.44.0
|
|
|
|
| 8 |
app_file: app.py
|
| 9 |
+
license: apache-2.0
|
| 10 |
+
short_description: Bundle v1 classifier — V8 + multi-class folded
|
| 11 |
+
tags:
|
| 12 |
+
- cybersecurity
|
| 13 |
+
- blockchain
|
| 14 |
+
- network-security
|
| 15 |
+
- validator-security
|
| 16 |
+
- sui
|
| 17 |
+
- solana
|
| 18 |
---
|
| 19 |
|
| 20 |
+
# nr-bundle-classifier
|
| 21 |
+
|
| 22 |
+
Interactive Gradio Space for NullRabbit's published bundle v1 classifiers. Accepts a user-uploaded bundle (zip or directory), validates against the open [bundle v1 spec](https://github.com/NullRabbitLabs/nr-bundle-spec), and runs both the V8 cipher-agnostic byte-amplification binary detector and the multi-class softmax folded 9-class unified detector. Returns per-class probabilities + scoreability + feature-coverage flags.
|
| 23 |
+
|
| 24 |
+
This is the data-layer artefact of NullRabbit Labs' research on **autonomous defence for decentralised networks**. The methodology is the contribution; the Space is a worked demonstration of the spec → corpus → model → unified-detector path end-to-end on user-supplied data.
|
| 25 |
+
|
| 26 |
+
## What it shows
|
| 27 |
+
|
| 28 |
+
For each uploaded bundle, the Space displays:
|
| 29 |
+
|
| 30 |
+
1. **Bundle metadata** parsed from `manifest.json` (corpus_id, primitive_id, family, chain, fidelity_class, ground_truth_label).
|
| 31 |
+
2. **Modality state** (`responses_rows`, `packets_pcap_present`).
|
| 32 |
+
3. **V8 binary verdict** — attack/benign + calibrated P(attack).
|
| 33 |
+
4. **Multi-class folded verdict** — 9-class softmax (benign + V8/V9/V10/V11/V12/V13/V14/V16) with per-class P + feature_coverage flag + coverage_warning when the predicted class is sensitive to missing modalities.
|
| 34 |
+
|
| 35 |
+
## How to try it
|
| 36 |
+
|
| 37 |
+
- Upload a bundle directory or `.zip` of one. Sample bundles are available at [NullRabbit/nr-bundles-public](https://huggingface.co/datasets/NullRabbit/nr-bundles-public) (CC-BY-4.0).
|
| 38 |
+
- Quickest path: download one bundle from the public dataset (e.g. `crp_1ef98f1fc0644369`, a `sui_F14` compute-amp attack) and upload the directory zipped.
|
| 39 |
+
|
| 40 |
+
## Backing models
|
| 41 |
+
|
| 42 |
+
- **V8 cipher-agnostic byte-amplification detector** (Apache-2.0): [NullRabbit/v8-cipher-agnostic](https://huggingface.co/NullRabbit/v8-cipher-agnostic). Binary classifier over 7 cipher-agnostic features. Reference detector for byte-amplification attacks against validator JSON-RPC.
|
| 43 |
+
- **Multi-class softmax folded detector** (Apache-2.0): [NullRabbit/multiclass-folded](https://huggingface.co/NullRabbit/multiclass-folded). 9-class joint classifier over 107 features. Unified detector for the V8-V14 + V16 attack-family taxonomy.
|
| 44 |
+
|
| 45 |
+
Both models are products of NullRabbit's pre-registration discipline applied to network-layer attack detection. The iterative leak-surface peeling pattern is documented in their model cards.
|
| 46 |
+
|
| 47 |
+
## Honest limitations
|
| 48 |
+
|
| 49 |
+
- **Public dataset bundles have raw `packets.pcap` dropped** per their safety policy. Some class manifolds (V8 response_amp, V13 service_misconfig, V14 compute_amp) survive this and produce correct verdicts; others (V11 rate_limiter_bypass, benign-with-traffic, V16 gossip-abuse) are load-bearing on `pcap.*` features and skew accordingly. Coverage warnings emit when the predicted class is sensitive to the missing modality.
|
| 50 |
+
- **n=1 OOF fragility** on the V16 load-bearing benign (SOL_BG01). Documented in the multiclass-folded model card. The fitted model routes SOL_BG01 to benign correctly; OOF held-out is fragile. Production V16 deployment requires corpus scale-up.
|
| 51 |
+
- **No streaming detection**: this Space scores single bundles, not live packet streams. Production deployment uses IBSR (an eBPF-based extractor) feeding the same models in a real-time loop; that's the operator-side runbook, not this Space.
|
| 52 |
+
|
| 53 |
+
## Methodology
|
| 54 |
+
|
| 55 |
+
NullRabbit's training cycles follow pre-registration discipline. Each detector cycle has a design document committed before the trainer runs. Audits run on close against sanity floors, per-feature ablation trails, and falsification holdouts. Where an audit fires, training halts, the design is re-registered, and the prior version is retracted in writing.
|
| 56 |
+
|
| 57 |
+
The **iterative leak-surface peeling pattern** is the methodology contribution. The current model cycle (V16 → multi-class folded v2, 2026-05-13) is the worked example at the unified-detector layer: V15 binary pre-registered a leak caveat (manifest may learn protocol shape, not attack shape); cycle2 corpus expansion provided the load-bearing UDP benign that made the caveat empirically testable; V15 evaluation confirmed the caveat; V16 binary retrained with corpus augmentation closed the caveat at the n=1 fragile level; multi-class folded v2 absorbed V16 into the unified detector with the load-bearing benign test passing at training-set scale and the OOF fragility surfaced honestly.
|
| 58 |
+
|
| 59 |
+
The corpus format and family taxonomy are open at `nr-bundle-spec`. The methodology is open (in preparation as the substrate paper). The specific corpus contents beyond `nr-bundles-public` are proprietary.
|
| 60 |
+
|
| 61 |
+
## Related
|
| 62 |
+
|
| 63 |
+
- **Bundle format spec**: [`nr-bundle-spec`](https://github.com/NullRabbitLabs/nr-bundle-spec) (MIT)
|
| 64 |
+
- **Reference public bundles**: [NullRabbit/nr-bundles-public](https://huggingface.co/datasets/NullRabbit/nr-bundles-public) (CC-BY-4.0)
|
| 65 |
+
- **V8 binary detector**: [NullRabbit/v8-cipher-agnostic](https://huggingface.co/NullRabbit/v8-cipher-agnostic) (Apache-2.0)
|
| 66 |
+
- **Multi-class folded detector**: [NullRabbit/multiclass-folded](https://huggingface.co/NullRabbit/multiclass-folded) (Apache-2.0)
|
| 67 |
+
- **Earned-autonomy paper** (governance layer): [Zenodo DOI 10.5281/zenodo.18406828](https://doi.org/10.5281/zenodo.18406828)
|
| 68 |
+
- **Substrate paper** (data-layer methodology, in preparation)
|
| 69 |
+
- **NullRabbit Labs**: [huggingface.co/NullRabbit](https://huggingface.co/NullRabbit)
|
| 70 |
+
- **Website**: [nullrabbit.ai](https://nullrabbit.ai)
|
| 71 |
+
|
| 72 |
+
## Contact
|
| 73 |
+
|
| 74 |
+
Research enquiries: simon@nullrabbit.ai
|
| 75 |
+
|
| 76 |
+
Spec compliance or format questions — open an issue at [`nr-bundle-spec`](https://github.com/NullRabbitLabs/nr-bundle-spec).
|
app.py
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""nr-bundle-classifier — Gradio Space for the NullRabbit bundle v1 classifier.
|
| 2 |
+
|
| 3 |
+
Accepts a user-uploaded bundle directory (zip or extracted), validates it
|
| 4 |
+
against the open bundle v1 spec (nr-bundle-spec), runs both V8 (cipher-
|
| 5 |
+
agnostic byte-amplification binary detector) and multiclass-folded (9-class
|
| 6 |
+
V8-V14+V16 unified detector) inference, and displays:
|
| 7 |
+
|
| 8 |
+
- bundle metadata (corpus_id, primitive_id if labelled, fidelity_class)
|
| 9 |
+
- V8 binary verdict + score
|
| 10 |
+
- multiclass-folded 9-class softmax with per-class probabilities
|
| 11 |
+
- scoreability + feature-coverage flags
|
| 12 |
+
- any coverage warnings (e.g. pcap-sensitive misclassification risk)
|
| 13 |
+
|
| 14 |
+
Demonstrates the spec → corpus → model → unified-detector path end-to-end
|
| 15 |
+
on user-supplied data. The Space is a hosted variant of the operator-
|
| 16 |
+
internal demo at github.com/NullRabbitLabs/nr-substrate.
|
| 17 |
+
|
| 18 |
+
License: Apache-2.0. SDK: Gradio.
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
from __future__ import annotations
|
| 22 |
+
|
| 23 |
+
import json
|
| 24 |
+
import shutil
|
| 25 |
+
import tempfile
|
| 26 |
+
import zipfile
|
| 27 |
+
from pathlib import Path
|
| 28 |
+
from typing import Any
|
| 29 |
+
|
| 30 |
+
import gradio as gr
|
| 31 |
+
import joblib
|
| 32 |
+
import numpy as np
|
| 33 |
+
import pyarrow.parquet as pq
|
| 34 |
+
from bundle_spec import BundleManifest
|
| 35 |
+
from huggingface_hub import hf_hub_download
|
| 36 |
+
|
| 37 |
+
V8_REPO = "NullRabbit/v8-cipher-agnostic"
|
| 38 |
+
MULTICLASS_REPO = "NullRabbit/multiclass-folded"
|
| 39 |
+
DATASET_REPO = "NullRabbit/nr-bundles-public"
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
_models_cache: dict[str, Any] = {}
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def _load_models() -> tuple[dict, dict]:
|
| 46 |
+
"""Lazy-load both models on first inference call."""
|
| 47 |
+
if "v8" not in _models_cache:
|
| 48 |
+
v8_path = hf_hub_download(repo_id=V8_REPO, filename="model.joblib")
|
| 49 |
+
_models_cache["v8"] = joblib.load(v8_path)
|
| 50 |
+
if "multiclass" not in _models_cache:
|
| 51 |
+
mc_path = hf_hub_download(repo_id=MULTICLASS_REPO, filename="model.joblib")
|
| 52 |
+
_models_cache["multiclass"] = joblib.load(mc_path)
|
| 53 |
+
return _models_cache["v8"], _models_cache["multiclass"]
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def _modality_state(bundle_dir: Path) -> tuple[bool, int, bool]:
|
| 57 |
+
responses_path = bundle_dir / "responses.parquet"
|
| 58 |
+
n_resp = 0
|
| 59 |
+
has_resp = False
|
| 60 |
+
if responses_path.is_file():
|
| 61 |
+
table = pq.read_table(responses_path)
|
| 62 |
+
n_resp = table.num_rows
|
| 63 |
+
has_resp = n_resp > 0
|
| 64 |
+
has_pcap = (bundle_dir / "packets.pcap").is_file()
|
| 65 |
+
return has_resp, n_resp, has_pcap
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def _extract_v8_features(bundle_dir: Path) -> dict[str, float]:
|
| 69 |
+
features = {n: 0.0 for n in [
|
| 70 |
+
"pcap.unique_dst_ports", "pcap.unique_src_ports",
|
| 71 |
+
"resp.amp_ratio_max", "resp.amp_ratio_mean", "resp.amp_ratio_median",
|
| 72 |
+
"resp.req_bytes_max", "resp.resp_bytes_max",
|
| 73 |
+
]}
|
| 74 |
+
rp = bundle_dir / "responses.parquet"
|
| 75 |
+
if rp.is_file():
|
| 76 |
+
table = pq.read_table(rp)
|
| 77 |
+
if table.num_rows > 0:
|
| 78 |
+
req = table.column("request_size_bytes").to_numpy()
|
| 79 |
+
resp = table.column("response_size_bytes").to_numpy()
|
| 80 |
+
features["resp.req_bytes_max"] = float(req.max())
|
| 81 |
+
features["resp.resp_bytes_max"] = float(resp.max())
|
| 82 |
+
with np.errstate(divide="ignore", invalid="ignore"):
|
| 83 |
+
ratios = np.where(req > 0, resp / req, 0.0)
|
| 84 |
+
features["resp.amp_ratio_max"] = float(ratios.max())
|
| 85 |
+
features["resp.amp_ratio_mean"] = float(ratios.mean())
|
| 86 |
+
features["resp.amp_ratio_median"] = float(np.median(ratios))
|
| 87 |
+
return features
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def _extract_multiclass_features(bundle_dir: Path, feature_names: list[str]) -> np.ndarray:
|
| 91 |
+
"""Minimal fallback feature extractor for the multi-class model.
|
| 92 |
+
|
| 93 |
+
Only populates resp.* features (the rest default to 0). The model's
|
| 94 |
+
OOD-by-construction behaviour on partial-coverage inputs is surfaced
|
| 95 |
+
via the coverage_warning in the inference output.
|
| 96 |
+
"""
|
| 97 |
+
features = {n: 0.0 for n in feature_names}
|
| 98 |
+
rp = bundle_dir / "responses.parquet"
|
| 99 |
+
if rp.is_file():
|
| 100 |
+
table = pq.read_table(rp)
|
| 101 |
+
if table.num_rows > 0:
|
| 102 |
+
req = table.column("request_size_bytes").to_numpy()
|
| 103 |
+
resp = table.column("response_size_bytes").to_numpy()
|
| 104 |
+
with np.errstate(divide="ignore", invalid="ignore"):
|
| 105 |
+
ratios = np.where(req > 0, resp / req, 0.0)
|
| 106 |
+
for name, value in [
|
| 107 |
+
("resp.req_bytes_max", float(req.max())),
|
| 108 |
+
("resp.resp_bytes_max", float(resp.max())),
|
| 109 |
+
("resp.amp_ratio_max", float(ratios.max())),
|
| 110 |
+
("resp.amp_ratio_mean", float(ratios.mean())),
|
| 111 |
+
("resp.amp_ratio_median", float(np.median(ratios))),
|
| 112 |
+
]:
|
| 113 |
+
if name in features:
|
| 114 |
+
features[name] = value
|
| 115 |
+
return np.array([[features[n] for n in feature_names]], dtype=float)
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def classify_bundle(uploaded_path: str | None) -> dict[str, Any]:
|
| 119 |
+
"""Main entrypoint. Accepts a bundle directory (zip or extracted)
|
| 120 |
+
and returns a verdict dict suitable for Gradio JSON display."""
|
| 121 |
+
if not uploaded_path:
|
| 122 |
+
return {"error": "Please upload a bundle (.zip or extracted directory)."}
|
| 123 |
+
|
| 124 |
+
upload = Path(uploaded_path)
|
| 125 |
+
workdir = Path(tempfile.mkdtemp(prefix="nr-bundle-"))
|
| 126 |
+
|
| 127 |
+
try:
|
| 128 |
+
# Handle zip vs directory uploads.
|
| 129 |
+
if upload.is_file() and upload.suffix == ".zip":
|
| 130 |
+
with zipfile.ZipFile(upload, "r") as zf:
|
| 131 |
+
zf.extractall(workdir)
|
| 132 |
+
bundle_root = workdir
|
| 133 |
+
# If the zip contains a single top-level directory, descend.
|
| 134 |
+
entries = [p for p in workdir.iterdir() if p.is_dir()]
|
| 135 |
+
if len(entries) == 1 and not (workdir / "manifest.json").is_file():
|
| 136 |
+
bundle_root = entries[0]
|
| 137 |
+
elif upload.is_dir():
|
| 138 |
+
bundle_root = upload
|
| 139 |
+
else:
|
| 140 |
+
return {"error": "Unsupported upload: provide a .zip or directory."}
|
| 141 |
+
|
| 142 |
+
mf_path = bundle_root / "manifest.json"
|
| 143 |
+
if not mf_path.is_file():
|
| 144 |
+
return {"error": f"No manifest.json found in upload (looked at {bundle_root})."}
|
| 145 |
+
|
| 146 |
+
# Validate against bundle v1 spec.
|
| 147 |
+
try:
|
| 148 |
+
manifest = BundleManifest.model_validate_json(mf_path.read_text())
|
| 149 |
+
except Exception as exc:
|
| 150 |
+
return {
|
| 151 |
+
"error": "Bundle does not validate against nr-bundle-spec v0.1.0.",
|
| 152 |
+
"detail": str(exc)[:400],
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
has_resp, n_resp, has_pcap = _modality_state(bundle_root)
|
| 156 |
+
|
| 157 |
+
v8_payload, mc_payload = _load_models()
|
| 158 |
+
|
| 159 |
+
# V8 binary inference.
|
| 160 |
+
v8_features = _extract_v8_features(bundle_root)
|
| 161 |
+
X_v8 = np.array([[v8_features[n] for n in v8_payload["feature_names"]]], dtype=float)
|
| 162 |
+
v8_score = float(v8_payload["model"].predict_proba(X_v8)[0, 1])
|
| 163 |
+
v8_verdict = "attack" if v8_score >= 0.5 else "benign"
|
| 164 |
+
|
| 165 |
+
# Multi-class inference.
|
| 166 |
+
if not (has_resp or has_pcap):
|
| 167 |
+
mc_block = {
|
| 168 |
+
"verdict": "unscoreable",
|
| 169 |
+
"reason": "No responses.parquet (with rows) and no packets.pcap present.",
|
| 170 |
+
}
|
| 171 |
+
else:
|
| 172 |
+
X_mc = _extract_multiclass_features(bundle_root, mc_payload["feature_names"])
|
| 173 |
+
proba = mc_payload["model"].predict_proba(X_mc)[0]
|
| 174 |
+
class_order = mc_payload["class_order"]
|
| 175 |
+
argmax = int(np.argmax(proba))
|
| 176 |
+
argmax_class = class_order[argmax]
|
| 177 |
+
argmax_p = float(proba[argmax])
|
| 178 |
+
coverage = ("full" if has_resp and has_pcap
|
| 179 |
+
else "resp_only" if has_resp
|
| 180 |
+
else "pcap_only" if has_pcap
|
| 181 |
+
else "none")
|
| 182 |
+
|
| 183 |
+
warning = None
|
| 184 |
+
if coverage == "resp_only" and argmax_class != "V16" and argmax_p < 0.8:
|
| 185 |
+
warning = (
|
| 186 |
+
f"argmax={argmax_class} with P={argmax_p:.3f} on resp_only "
|
| 187 |
+
"coverage; multiclass-folded was trained on full-modality "
|
| 188 |
+
"bundles. For reliable V8-V14 inference provide bundles "
|
| 189 |
+
"with raw packets.pcap present."
|
| 190 |
+
)
|
| 191 |
+
elif coverage == "resp_only" and argmax_class == "V16":
|
| 192 |
+
warning = (
|
| 193 |
+
"argmax=V16 with resp_only coverage. V16 is load-bearing "
|
| 194 |
+
"on pcap.* features; this is likely a missing-modality "
|
| 195 |
+
"artefact, not a true gossip-abuse detection. Provide "
|
| 196 |
+
"bundles with raw packets.pcap for V16 inference."
|
| 197 |
+
)
|
| 198 |
+
|
| 199 |
+
mc_block = {
|
| 200 |
+
"verdict": argmax_class,
|
| 201 |
+
"argmax_p": round(argmax_p, 4),
|
| 202 |
+
"class_probs": {c: round(float(proba[i]), 4)
|
| 203 |
+
for i, c in enumerate(class_order)},
|
| 204 |
+
"feature_coverage": coverage,
|
| 205 |
+
"coverage_warning": warning,
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
return {
|
| 209 |
+
"bundle_manifest": {
|
| 210 |
+
"corpus_id": manifest.corpus_id,
|
| 211 |
+
"primitive_id": manifest.primitive_id,
|
| 212 |
+
"family_id": manifest.family_id,
|
| 213 |
+
"chain": manifest.chain,
|
| 214 |
+
"fidelity_class": (
|
| 215 |
+
manifest.provenance.fidelity_class.value
|
| 216 |
+
if hasattr(manifest.provenance.fidelity_class, "value")
|
| 217 |
+
else str(manifest.provenance.fidelity_class)
|
| 218 |
+
),
|
| 219 |
+
"ground_truth_label": (
|
| 220 |
+
manifest.ground_truth_label.value
|
| 221 |
+
if hasattr(manifest.ground_truth_label, "value")
|
| 222 |
+
else str(manifest.ground_truth_label)
|
| 223 |
+
),
|
| 224 |
+
},
|
| 225 |
+
"modality_state": {
|
| 226 |
+
"responses_rows": n_resp,
|
| 227 |
+
"packets_pcap_present": has_pcap,
|
| 228 |
+
},
|
| 229 |
+
"v8_binary": {
|
| 230 |
+
"score": round(v8_score, 4),
|
| 231 |
+
"verdict": v8_verdict,
|
| 232 |
+
},
|
| 233 |
+
"multiclass_folded": mc_block,
|
| 234 |
+
}
|
| 235 |
+
finally:
|
| 236 |
+
shutil.rmtree(workdir, ignore_errors=True)
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
# ── Gradio interface ──────────────────────────────────────────────
|
| 240 |
+
|
| 241 |
+
DESCRIPTION = """
|
| 242 |
+
# nr-bundle-classifier
|
| 243 |
+
|
| 244 |
+
Run a bundle (in the open [bundle v1 format](https://github.com/NullRabbitLabs/nr-bundle-spec)) through NullRabbit's published detectors:
|
| 245 |
+
|
| 246 |
+
- **[V8 cipher-agnostic byte-amplification detector](https://huggingface.co/NullRabbit/v8-cipher-agnostic)** — binary attack/benign classification for byte-amplification family
|
| 247 |
+
- **[Multi-class softmax folded detector](https://huggingface.co/NullRabbit/multiclass-folded)** — 9-class unified detector (benign + V8/V9/V10/V11/V12/V13/V14/V16)
|
| 248 |
+
|
| 249 |
+
Upload a bundle directory (zip or extracted) — the Space validates against bundle v1 spec, runs both detectors, and returns per-class probabilities plus scoreability + coverage flags. Sample bundles available at [NullRabbit/nr-bundles-public](https://huggingface.co/datasets/NullRabbit/nr-bundles-public).
|
| 250 |
+
|
| 251 |
+
This is the data-layer artefact of NullRabbit Labs' research on **autonomous defence for decentralised networks**. The methodology is documented in the [substrate paper](https://github.com/NullRabbitLabs/nr-bundle-spec) (in preparation); the governance layer is published separately as the [earned-autonomy paper](https://doi.org/10.5281/zenodo.18406828).
|
| 252 |
+
|
| 253 |
+
**Note**: bundles in `nr-bundles-public` have raw `packets.pcap` dropped per the dataset's safety policy. Some class manifolds (V8/V13/V14) survive this and produce correct verdicts; others (V11, benign-with-traffic, V16) are load-bearing on pcap features and skew accordingly. Coverage warnings emit when the predicted class is sensitive to the missing modality. For reliable inference on V11/benign-with-traffic/V16, provide bundles with raw pcap retained.
|
| 254 |
+
"""
|
| 255 |
+
|
| 256 |
+
with gr.Blocks(title="nr-bundle-classifier") as demo:
|
| 257 |
+
gr.Markdown(DESCRIPTION)
|
| 258 |
+
with gr.Row():
|
| 259 |
+
with gr.Column():
|
| 260 |
+
upload = gr.File(label="Bundle (.zip or extracted dir)",
|
| 261 |
+
file_count="single")
|
| 262 |
+
run_btn = gr.Button("Classify", variant="primary")
|
| 263 |
+
with gr.Column():
|
| 264 |
+
output = gr.JSON(label="Verdict")
|
| 265 |
+
|
| 266 |
+
run_btn.click(fn=classify_bundle, inputs=upload, outputs=output)
|
| 267 |
+
|
| 268 |
+
gr.Markdown("""
|
| 269 |
+
---
|
| 270 |
+
|
| 271 |
+
**Related**:
|
| 272 |
+
|
| 273 |
+
- [`nr-bundle-spec`](https://github.com/NullRabbitLabs/nr-bundle-spec) — open bundle v1 format (MIT)
|
| 274 |
+
- [`nr-bundles-public`](https://huggingface.co/datasets/NullRabbit/nr-bundles-public) — curated public sample (CC-BY-4.0)
|
| 275 |
+
- [`v8-cipher-agnostic`](https://huggingface.co/NullRabbit/v8-cipher-agnostic) — binary detector (Apache-2.0)
|
| 276 |
+
- [`multiclass-folded`](https://huggingface.co/NullRabbit/multiclass-folded) — unified detector (Apache-2.0)
|
| 277 |
+
- [NullRabbit Labs](https://huggingface.co/NullRabbit) · [nullrabbit.ai](https://nullrabbit.ai)
|
| 278 |
+
""")
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
if __name__ == "__main__":
|
| 282 |
+
demo.launch()
|
release-cert.json
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"audited_at": "2026-05-13T18:29:02Z",
|
| 3 |
+
"space_repo": "NullRabbit/nr-bundle-classifier",
|
| 4 |
+
"checks": [
|
| 5 |
+
{
|
| 6 |
+
"check": "app.py_exists",
|
| 7 |
+
"ok": true
|
| 8 |
+
},
|
| 9 |
+
{
|
| 10 |
+
"check": "README.md_exists",
|
| 11 |
+
"ok": true
|
| 12 |
+
},
|
| 13 |
+
{
|
| 14 |
+
"check": "requirements.txt_exists",
|
| 15 |
+
"ok": true
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"check": "LICENSE_exists",
|
| 19 |
+
"ok": true
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"check": "app_py_compiles",
|
| 23 |
+
"ok": true
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"check": "readme_yaml_frontmatter",
|
| 27 |
+
"ok": true
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
"check": "readme_sdk_gradio",
|
| 31 |
+
"ok": true
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
"check": "readme_app_file_app_py",
|
| 35 |
+
"ok": true
|
| 36 |
+
},
|
| 37 |
+
{
|
| 38 |
+
"check": "readme_license_apache",
|
| 39 |
+
"ok": true
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"check": "readme_anchor_autonomous_defence",
|
| 43 |
+
"ok": true
|
| 44 |
+
},
|
| 45 |
+
{
|
| 46 |
+
"check": "readme_anchor_iterative_leak_surface_peeling",
|
| 47 |
+
"ok": true
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"check": "readme_methodology_is_the_contribution",
|
| 51 |
+
"ok": true
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"check": "readme_substrate_paper_in_preparation",
|
| 55 |
+
"ok": true
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"check": "readme_zenodo_doi_present",
|
| 59 |
+
"ok": true
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"check": "readme_cross_links_nr_bundles_public",
|
| 63 |
+
"ok": true
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"check": "readme_cross_links_v8",
|
| 67 |
+
"ok": true
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"check": "readme_cross_links_multiclass",
|
| 71 |
+
"ok": true
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"check": "readme_cross_links_nr_bundle_spec",
|
| 75 |
+
"ok": true
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"check": "readme_has_honest_limitations",
|
| 79 |
+
"ok": true
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"check": "readme_has_pcap_caveat",
|
| 83 |
+
"ok": true
|
| 84 |
+
},
|
| 85 |
+
{
|
| 86 |
+
"check": "readme_has_n1_bg01_caveat",
|
| 87 |
+
"ok": true
|
| 88 |
+
},
|
| 89 |
+
{
|
| 90 |
+
"check": "readme_no_embargo_language",
|
| 91 |
+
"ok": true
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"check": "requirements_includes_gradio",
|
| 95 |
+
"ok": true
|
| 96 |
+
},
|
| 97 |
+
{
|
| 98 |
+
"check": "requirements_includes_huggingface_hub",
|
| 99 |
+
"ok": true
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"check": "requirements_includes_scikit-learn",
|
| 103 |
+
"ok": true
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"check": "requirements_includes_joblib",
|
| 107 |
+
"ok": true
|
| 108 |
+
},
|
| 109 |
+
{
|
| 110 |
+
"check": "requirements_includes_numpy",
|
| 111 |
+
"ok": true
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"check": "requirements_includes_pyarrow",
|
| 115 |
+
"ok": true
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"check": "requirements_includes_nr-bundle-spec",
|
| 119 |
+
"ok": true
|
| 120 |
+
},
|
| 121 |
+
{
|
| 122 |
+
"check": "app_imports_clean",
|
| 123 |
+
"ok": true
|
| 124 |
+
},
|
| 125 |
+
{
|
| 126 |
+
"check": "smoke_test_classify_bundle_returns_dict",
|
| 127 |
+
"ok": true,
|
| 128 |
+
"v8_verdict": "attack",
|
| 129 |
+
"v8_score": 0.9874,
|
| 130 |
+
"mc_verdict": "V14",
|
| 131 |
+
"mc_argmax_p": 0.4629
|
| 132 |
+
}
|
| 133 |
+
],
|
| 134 |
+
"n_checks": 31,
|
| 135 |
+
"n_ok": 31,
|
| 136 |
+
"release_ok": true
|
| 137 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0
|
| 2 |
+
huggingface_hub>=1.0
|
| 3 |
+
scikit-learn>=1.5
|
| 4 |
+
joblib>=1.3
|
| 5 |
+
numpy>=1.26
|
| 6 |
+
pyarrow>=17
|
| 7 |
+
git+https://github.com/NullRabbitLabs/nr-bundle-spec.git
|