nomosguard 0.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.
- nomosguard-0.1.0/.github/workflows/ci.yml +42 -0
- nomosguard-0.1.0/.github/workflows/release-pypi.yml +77 -0
- nomosguard-0.1.0/.gitignore +10 -0
- nomosguard-0.1.0/LICENSE +202 -0
- nomosguard-0.1.0/PKG-INFO +152 -0
- nomosguard-0.1.0/PLAN.md +143 -0
- nomosguard-0.1.0/README.md +121 -0
- nomosguard-0.1.0/SKILL.md +116 -0
- nomosguard-0.1.0/VISION.md +121 -0
- nomosguard-0.1.0/examples/default_policy.json +37 -0
- nomosguard-0.1.0/examples/sample_toolcalls.jsonl +7 -0
- nomosguard-0.1.0/pyproject.toml +57 -0
- nomosguard-0.1.0/src/nomosguard/__init__.py +9 -0
- nomosguard-0.1.0/src/nomosguard/benchmark/__init__.py +12 -0
- nomosguard-0.1.0/src/nomosguard/benchmark/results/RESULTS.md +21 -0
- nomosguard-0.1.0/src/nomosguard/benchmark/results/results.json +81 -0
- nomosguard-0.1.0/src/nomosguard/benchmark/run_suite.py +185 -0
- nomosguard-0.1.0/src/nomosguard/benchmark/run_suite_main.py +37 -0
- nomosguard-0.1.0/src/nomosguard/benchmark/scenarios.py +129 -0
- nomosguard-0.1.0/src/nomosguard/demo.py +88 -0
- nomosguard-0.1.0/src/nomosguard/gate.py +147 -0
- nomosguard-0.1.0/src/nomosguard/ingest/__init__.py +16 -0
- nomosguard-0.1.0/src/nomosguard/ingest/cli.py +118 -0
- nomosguard-0.1.0/src/nomosguard/ingest/toolcall_jsonl.py +132 -0
- nomosguard-0.1.0/src/nomosguard/ledger.py +321 -0
- nomosguard-0.1.0/src/nomosguard/mcp_server.py +219 -0
- nomosguard-0.1.0/src/nomosguard/mcp_stdio.py +214 -0
- nomosguard-0.1.0/src/nomosguard/policy.py +178 -0
- nomosguard-0.1.0/src/nomosguard/rules.py +358 -0
- nomosguard-0.1.0/tests/test_core.py +362 -0
- nomosguard-0.1.0/tests/test_ingest.py +184 -0
- nomosguard-0.1.0/tests/test_mcp.py +254 -0
- nomosguard-0.1.0/tests/test_policy.py +153 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install package (zero runtime deps) and pytest
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e . pytest
|
|
28
|
+
|
|
29
|
+
- name: Verify zero runtime dependencies
|
|
30
|
+
run: |
|
|
31
|
+
# The core must run with ONLY the stdlib: install into a clean
|
|
32
|
+
# venv with no extra packages and run the demo.
|
|
33
|
+
python -m venv /tmp/clean-env
|
|
34
|
+
/tmp/clean-env/bin/pip install -q --no-deps -e .
|
|
35
|
+
/tmp/clean-env/bin/python -m nomosguard.demo | python -m json.tool > /dev/null
|
|
36
|
+
echo "zero-dependency demo OK"
|
|
37
|
+
|
|
38
|
+
- name: Run tests
|
|
39
|
+
run: pytest tests/ -v
|
|
40
|
+
|
|
41
|
+
- name: Run demo (smoke)
|
|
42
|
+
run: python -m nomosguard.demo
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
# Fires when a GitHub Release is published. The trusted OIDC publisher must
|
|
4
|
+
# be registered on PyPI (pypi.org/manage/account/publishing) for:
|
|
5
|
+
# project: nomosguard
|
|
6
|
+
# owner: Furox-Art
|
|
7
|
+
# repo: nomosguard
|
|
8
|
+
# workflow: release-pypi.yml
|
|
9
|
+
# environment: pypi
|
|
10
|
+
# Before that registration, the publish step fails with invalid-publisher —
|
|
11
|
+
# that is expected on the first run; register, then re-publish the release.
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
release:
|
|
15
|
+
types: [published]
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
permissions: {}
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
name: Build and verify distributions
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
with:
|
|
29
|
+
persist-credentials: false
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
- name: Install build tooling
|
|
34
|
+
run: python -m pip install --upgrade build twine
|
|
35
|
+
- name: Build sdist and wheel
|
|
36
|
+
run: python -m build
|
|
37
|
+
- name: Check package metadata
|
|
38
|
+
run: python -m twine check dist/*
|
|
39
|
+
- name: Verify the version matches the release tag
|
|
40
|
+
run: |
|
|
41
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
42
|
+
PKG_VER=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
|
|
43
|
+
echo "release tag: $TAG, package version: $PKG_VER"
|
|
44
|
+
test "$TAG" = "$PKG_VER"
|
|
45
|
+
- name: Install built wheel in a clean venv and run the full test suite
|
|
46
|
+
run: |
|
|
47
|
+
python -m venv /tmp/clean
|
|
48
|
+
/tmp/clean/bin/pip install --quiet --no-deps dist/*.whl pytest
|
|
49
|
+
# zero runtime dependencies: prove the installed package runs on stdlib alone
|
|
50
|
+
/tmp/clean/bin/python -c "import nomosguard; print('import OK', nomosguard.__version__)"
|
|
51
|
+
/tmp/clean/bin/python -m nomosguard.demo > /dev/null && echo "demo OK"
|
|
52
|
+
- uses: actions/upload-artifact@v4
|
|
53
|
+
with:
|
|
54
|
+
name: dist
|
|
55
|
+
path: dist/
|
|
56
|
+
|
|
57
|
+
publish:
|
|
58
|
+
name: Publish to PyPI via trusted OIDC
|
|
59
|
+
needs: build
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
environment: pypi
|
|
62
|
+
permissions:
|
|
63
|
+
contents: read
|
|
64
|
+
id-token: write # OIDC token for trusted publishing
|
|
65
|
+
steps:
|
|
66
|
+
- uses: actions/checkout@v4
|
|
67
|
+
with:
|
|
68
|
+
persist-credentials: false
|
|
69
|
+
- uses: actions/setup-python@v5
|
|
70
|
+
with:
|
|
71
|
+
python-version: "3.12"
|
|
72
|
+
- name: Install build tooling
|
|
73
|
+
run: python -m pip install --upgrade build
|
|
74
|
+
- name: Build distributions
|
|
75
|
+
run: python -m build
|
|
76
|
+
- name: Publish to PyPI
|
|
77
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
nomosguard-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: nomosguard
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Deterministic security reasoning core: hash-chained evidence ledger, attack-path rule engine, and a fail-closed policy gate. LLMs may produce evidence and explain decisions; they never cross the decision boundary.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Furox-Art/nomosguard
|
|
6
|
+
Project-URL: Documentation, https://github.com/Furox-Art/nomosguard/blob/main/README.md
|
|
7
|
+
Project-URL: Repository, https://github.com/Furox-Art/nomosguard
|
|
8
|
+
Author-email: Furox-Art <177975472+Furox-Art@users.noreply.github.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent-security,agent-skills,ai-security,attack-graph,audit-log,deterministic,evidence-ledger,fail-closed,hash-chain,llm,mcp-server,policy-gate,pure-python,reasoning,reproducible,rule-engine,security,tamper-evident,tool-call-guard,zero-dependencies
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Information Technology
|
|
15
|
+
Classifier: Intended Audience :: System Administrators
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Classifier: Natural Language :: English
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Topic :: Security
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# NomosGuard
|
|
33
|
+
|
|
34
|
+
**LLM produces evidence. Deterministic machinery decides.**
|
|
35
|
+
|
|
36
|
+
NomosGuard is a deterministic security reasoning core: an append-only
|
|
37
|
+
evidence ledger, a rule engine that derives threat/access paths from that
|
|
38
|
+
evidence, and a fail-closed policy gate. Language models may *read* events
|
|
39
|
+
and *write* structured claims with cited evidence, and may later *explain*
|
|
40
|
+
decisions in human language — but a model never crosses the decision
|
|
41
|
+
boundary. Every claim without reproducible evidence is discarded; every
|
|
42
|
+
decision is hash-chained; the gate defaults to deny.
|
|
43
|
+
|
|
44
|
+
The name: *nomos* (νόμος) — Greek for rational law, order derived from
|
|
45
|
+
reason rather than brute force (physis) — plus *guard*, the fail-closed
|
|
46
|
+
gate that enforces it. Together: reasoning that decides, evidence that
|
|
47
|
+
must prove itself.
|
|
48
|
+
|
|
49
|
+
## Why deterministic core + probabilistic edge
|
|
50
|
+
|
|
51
|
+
A language model's confidence is not evidence — it is an assertion. This
|
|
52
|
+
project treats it as such:
|
|
53
|
+
|
|
54
|
+
- **The LLM edge (top):** reads raw events, configuration, CVE records,
|
|
55
|
+
logs; emits *structured claims* (entities, relations, vulnerabilities,
|
|
56
|
+
tool calls), each citing the exact evidence fragment (log line hash,
|
|
57
|
+
config path, CVE ID) that supports it.
|
|
58
|
+
- **The deterministic core:** an append-only, SHA-256 hash-chained ledger
|
|
59
|
+
stores every claim; a rule engine derives attack/access paths
|
|
60
|
+
(MulVAL-style logical inference — pure logic, no randomness, no model);
|
|
61
|
+
a policy gate decides ALLOW / ALERT / BLOCK, fail-closed.
|
|
62
|
+
- **The LLM edge (bottom):** explains the decision, drafts remediation
|
|
63
|
+
suggestions, and proposes next analysis steps. It narrates; it never
|
|
64
|
+
decides. If the explanation contradicts the evidence chain, the chain
|
|
65
|
+
wins.
|
|
66
|
+
|
|
67
|
+
This is the same separation that makes a court work: a lawyer (the model)
|
|
68
|
+
presents evidence, but the verdict comes from the rules of law (the core),
|
|
69
|
+
and the transcript is tamper-evident.
|
|
70
|
+
|
|
71
|
+
## Status
|
|
72
|
+
|
|
73
|
+
Early development — see [VISION.md](VISION.md) for the architecture,
|
|
74
|
+
scope, and first-release boundary. The core (evidence ledger, rule
|
|
75
|
+
engine, policy gate) is implemented with 51 passing tests and a
|
|
76
|
+
reproducible demo scenario, real log ingestion, and a measured benchmark corpus.
|
|
77
|
+
|
|
78
|
+
### Components
|
|
79
|
+
|
|
80
|
+
| Module | What it does |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `nomosguard.ledger` | Append-only SHA-256 hash-chained evidence ledger; rejects unevidenced claims; persistent (atomic save, full-chain-verify load) |
|
|
83
|
+
| `nomosguard.rules` | Forward-chaining rule engine with unification; tool-call / CVE / policy extractors |
|
|
84
|
+
| `nomosguard.gate` | Fail-closed policy gate: ALLOW / ALERT / BLOCK with full derivation chains |
|
|
85
|
+
| `nomosguard.ingest.toolcall_jsonl` | Real tool-call JSONL ingestion: each claim cites sha256 of the raw source line |
|
|
86
|
+
| `nomosguard.mcp_server` | MCP session layer: 5 tools (`evidence_ingest`, `assert_claim`, `derive_paths`, `decide`, `explain`) |
|
|
87
|
+
| `nomosguard.mcp_stdio` | JSON-RPC stdio server (`python -m nomosguard.mcp_stdio`) |
|
|
88
|
+
| `nomosguard.benchmark` | Attack-scenario corpus with measured recall / false-positive / fail-closed results |
|
|
89
|
+
| `SKILL.md` | Agent behavioral contract: when to invoke the deterministic chain vs. narrate |
|
|
90
|
+
|
|
91
|
+
### Benchmark (measured, not asserted)
|
|
92
|
+
|
|
93
|
+
Run with `python -m nomosguard.benchmark.run_suite_main --output DIR`. The
|
|
94
|
+
corpus is committed and deterministic; the expected outcomes are
|
|
95
|
+
hand-derived from the facts, not produced by the engine. Latest run:
|
|
96
|
+
|
|
97
|
+
| metric | value |
|
|
98
|
+
|---|---|
|
|
99
|
+
| scenarios | 6 |
|
|
100
|
+
| recall | 2/2 = 100% |
|
|
101
|
+
| false positives | 0 |
|
|
102
|
+
| fail-closed on incomplete evidence | OK |
|
|
103
|
+
| all scenarios passed | yes |
|
|
104
|
+
|
|
105
|
+
What the corpus does NOT cover (stated honestly): real-world logs, evidence
|
|
106
|
+
tampering *inside* the ledger (that is the ledger's own test suite's job),
|
|
107
|
+
and any scenario requiring an LLM to judge.
|
|
108
|
+
|
|
109
|
+
### Ingestion
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
python -m nomosguard.ingest.cli examples/sample_toolcalls.jsonl [--ledger PATH]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Every accepted record becomes a claim whose evidence field is
|
|
116
|
+
`sha256:<hex>` of the raw log line — independently verifiable. Malformed
|
|
117
|
+
records are rejected with line number and reason; duplicate lines are
|
|
118
|
+
counted, never re-appended.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
| Module | What it does |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `nomosguard.ledger` | Append-only SHA-256 hash-chained evidence ledger; rejects unevidenced claims |
|
|
125
|
+
| `nomosguard.rules` | Forward-chaining rule engine (MulVAL-style) with tool-call / CVE / policy extractors |
|
|
126
|
+
| `nomosguard.gate` | Fail-closed policy gate: ALLOW / ALERT / BLOCK with full derivation chains |
|
|
127
|
+
| `nomosguard.mcp_server` | MCP session layer: 5 tools (`evidence_ingest`, `assert_claim`, `derive_paths`, `decide`, `explain`) |
|
|
128
|
+
| `nomosguard.mcp_stdio` | JSON-RPC stdio server (`python -m nomosguard.mcp_stdio`) |
|
|
129
|
+
| `SKILL.md` | Agent behavioral contract: when to invoke the deterministic chain vs. narrate |
|
|
130
|
+
|
|
131
|
+
### Run it
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pip install -e .
|
|
135
|
+
python -m nomosguard.demo # committed scenario: derivation + BLOCK
|
|
136
|
+
pytest tests/ # 51 tests incl. full stdio protocol
|
|
137
|
+
python -m nomosguard.benchmark.run_suite_main # measured recall / false-positive
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Use it from an MCP client
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{"command": "python", "args": ["-m", "nomosguard.mcp_stdio"]}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The server never calls a model. Agents load `SKILL.md` for the behavioral
|
|
147
|
+
contract: assert claims with evidence, derive paths, read the gate
|
|
148
|
+
decision, explain it — never decide it.
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
Apache-2.0
|
nomosguard-0.1.0/PLAN.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# NomosGuard — Development Plan (living document)
|
|
2
|
+
|
|
3
|
+
> Status line is updated as work lands. Every number in this file comes from
|
|
4
|
+
> an actual test run or CI run, never hand-computed.
|
|
5
|
+
|
|
6
|
+
## Current state (verified 2026-10-09)
|
|
7
|
+
|
|
8
|
+
**Repository:** https://github.com/Furox-Art/nomosguard (public, Apache-2.0)
|
|
9
|
+
**Version:** 0.1.0 (unreleased — not yet on PyPI)
|
|
10
|
+
**Tests:** 32 passed (core: 30, MCP: 32 incl. stdio protocol)
|
|
11
|
+
**CI:** green on Python 3.10 / 3.11 / 3.12 / 3.13 + zero-dependency check
|
|
12
|
+
**Commits:** f63547c (ledger persistence)
|
|
13
|
+
|
|
14
|
+
### What exists and is proven
|
|
15
|
+
|
|
16
|
+
| Component | Module | Proven by |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Evidence ledger (in-memory) | `ledger.py` | hash-chain link tests, tamper detection |
|
|
19
|
+
| Evidence ledger (persistent) | `ledger.py` | save/load round-trip, append-after-load, tamper rejection, idempotency (7 tests) |
|
|
20
|
+
| Rule engine (unification) | `rules.py` | variable consistency, head substitution, multi-match firing, unbound-head rejection (7 tests) |
|
|
21
|
+
| Fail-closed policy gate | `gate.py` | fallback BLOCK, block-on-derived-path with full chain |
|
|
22
|
+
| MCP server (5 tools + stdio) | `mcp_server.py`, `mcp_stdio.py` | full JSON-RPC protocol end-to-end test |
|
|
23
|
+
| Agent skill contract | `SKILL.md` | — (behavioral doc) |
|
|
24
|
+
| Vision + architecture doc | `VISION.md` | — |
|
|
25
|
+
|
|
26
|
+
### What was fixed in this session (both were real defects)
|
|
27
|
+
|
|
28
|
+
1. **Rule engine matching (commit 1dcb0a8).** The previous Cartesian-product
|
|
29
|
+
matcher had two correctness bugs: (a) body variables could bind different
|
|
30
|
+
values in different literals, producing derivations no single evidence
|
|
31
|
+
chain supports; (b) the head was a constant string, so derived facts lost
|
|
32
|
+
the component/CVE values (`vulnerable_component` instead of `orders_db`).
|
|
33
|
+
Rewritten with backtracking unification + head substitution. Demo now
|
|
34
|
+
derives `Fact(researcher -exposes-> orders_db)`.
|
|
35
|
+
2. **Ledger persistence (commit f63547c).** The chain was in-memory only —
|
|
36
|
+
it died with the process, defeating the tamper-evidence property it
|
|
37
|
+
exists for. Now: atomic save, full-chain-verify load, append-continues,
|
|
38
|
+
MCP `--ledger` flag.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## The plan (priority order)
|
|
43
|
+
|
|
44
|
+
The guiding principle from VISION.md: **one ingestion path done flawlessly
|
|
45
|
+
beats five shallow ones.** The tool-call path is the v1 path. Order is
|
|
46
|
+
correctness-first, then real data, then measurement.
|
|
47
|
+
|
|
48
|
+
### P1 — Real log ingestion (the promise the project makes)
|
|
49
|
+
|
|
50
|
+
**Why:** the value proposition is "read real tool-call logs, produce
|
|
51
|
+
evidence-citing claims." Today claims are synthetic in-memory dicts. Until
|
|
52
|
+
a real parser exists, the demo cannot leave the lab.
|
|
53
|
+
|
|
54
|
+
Deliverables:
|
|
55
|
+
- [ ] `ingest/toolcall_jsonl.py` — parse a JSONL file of MCP tool-call
|
|
56
|
+
records into ledger claims. Each claim's `evidence` field carries the
|
|
57
|
+
source line hash (SHA-256 of the raw line), not a paraphrase.
|
|
58
|
+
- [ ] Payload schema validation per claim kind (reject malformed records
|
|
59
|
+
with a per-record error, never silently skip — the gateway's
|
|
60
|
+
fail-closed discipline applies to ingestion too).
|
|
61
|
+
- [ ] Ingest demo: committed sample log (synthetic but *realistic* — the
|
|
62
|
+
same shapes real MCP gateways emit) → parsed → derived → decided.
|
|
63
|
+
- [ ] Tests: parser unit tests (well-formed, malformed, empty-line,
|
|
64
|
+
duplicate-record idempotency), and an end-to-end ingest→derive→gate test.
|
|
65
|
+
|
|
66
|
+
Exit criteria: `python -m nomosguard.ingest.toolcall_jsonl sample.jsonl`
|
|
67
|
+
produces a verified ledger; every claim cites a verifiable line hash.
|
|
68
|
+
|
|
69
|
+
### P2 — Benchmark: attack scenarios with measured catch/miss/false-positive
|
|
70
|
+
|
|
71
|
+
**Why:** the discipline this project follows (and that the five repos
|
|
72
|
+
released today all share) is: publish real measurements, including null
|
|
73
|
+
results. A security reasoning core with no corpus is unfalsifiable.
|
|
74
|
+
|
|
75
|
+
Deliverables:
|
|
76
|
+
- [ ] `benchmark/scenarios/` — a committed corpus of tool-call attack
|
|
77
|
+
scenarios with known ground truth (which paths should be derived,
|
|
78
|
+
which should not): at minimum (a) vulnerable-component exposure
|
|
79
|
+
(positive), (b) benign multi-tool workflow (negative — must NOT
|
|
80
|
+
fire), (c) chained access path 3+ hops deep (positive), (d)
|
|
81
|
+
incomplete evidence (fail-closed default must apply).
|
|
82
|
+
- [ ] `benchmark/run_suite.py` — measures recall (caught / total positive),
|
|
83
|
+
false-positive rate, and fail-closed correctness; writes committed
|
|
84
|
+
JSON + markdown results.
|
|
85
|
+
- [ ] Honesty gate: results page states what the corpus does NOT cover
|
|
86
|
+
(no real-world logs, no adversarial evidence tampering inside the
|
|
87
|
+
ledger — that is the ledger's own test's job).
|
|
88
|
+
- [ ] README gets a measured-results section ONLY if numbers support a
|
|
89
|
+
claim; otherwise the "not yet demonstrated" disclaimer stays.
|
|
90
|
+
|
|
91
|
+
Exit criteria: corpus runs green in CI; results committed from an actual
|
|
92
|
+
run; limitations stated.
|
|
93
|
+
|
|
94
|
+
### P3 — Declarative policy configuration
|
|
95
|
+
|
|
96
|
+
**Why:** `default_rules()` is hardcoded in `mcp_server.py`. A security
|
|
97
|
+
tool whose rules cannot be inspected or versioned outside the code is a
|
|
98
|
+
maintenance trap.
|
|
99
|
+
|
|
100
|
+
Deliverables:
|
|
101
|
+
- [ ] Policy file format (JSON): rules (Pattern triples) + gate decisions,
|
|
102
|
+
with a schema validator that rejects malformed rules at load.
|
|
103
|
+
- [ ] `NomosGuardSession.from_policy_file(path)`.
|
|
104
|
+
- [ ] Tests: valid config loads, malformed config rejected with precise
|
|
105
|
+
error, unknown decision rejected.
|
|
106
|
+
|
|
107
|
+
### P4 — Ledger hardening
|
|
108
|
+
|
|
109
|
+
- [ ] Concurrent-append safety note: current design is single-writer;
|
|
110
|
+
document it, or add file locking. Decide, don't leave ambiguous.
|
|
111
|
+
- [ ] `load` performance on large ledgers: streaming parse + verify
|
|
112
|
+
instead of read-all (the chain verify is O(n) either way, but memory
|
|
113
|
+
should be O(1) per entry).
|
|
114
|
+
|
|
115
|
+
### P5 — First release
|
|
116
|
+
|
|
117
|
+
- [ ] PyPI trusted publisher (`furox-nomosguard`? — name TBD) + PyPI
|
|
118
|
+
publish workflow. PyPI/npm release only AFTER P1+P2 land: a first
|
|
119
|
+
release should ship with the ingestion path and a measured corpus,
|
|
120
|
+
not before.
|
|
121
|
+
- [ ] GitHub Release notes linking VISION.md + benchmark results.
|
|
122
|
+
|
|
123
|
+
### Explicitly out of scope (guard against scope creep)
|
|
124
|
+
|
|
125
|
+
- Real-time network enforcement (batch/stream analysis only)
|
|
126
|
+
- Asset inventory / network topology ingestion (v1 is tool-call only)
|
|
127
|
+
- Any LLM inference inside the core (the whole design forbids it)
|
|
128
|
+
- Multi-writer concurrency (document single-writer instead)
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Standing rules for this project (learned the hard way)
|
|
133
|
+
|
|
134
|
+
1. **Every published number comes from a real run.** No hand-computed
|
|
135
|
+
figures. If a metric can't be measured, say so.
|
|
136
|
+
2. **The decision boundary is never crossed by a model.** Reviewers' first
|
|
137
|
+
question is "can an LLM influence the gate?" — the answer must stay no.
|
|
138
|
+
3. **Fail closed.** Missing evidence → BLOCK default. Reject unverifiable
|
|
139
|
+
chains. Refuse malformed input loudly.
|
|
140
|
+
4. **Zero runtime dependencies.** The core runs on stdlib only; CI checks it
|
|
141
|
+
in a clean venv. Optional extras (matplotlib-style) never enter the core.
|
|
142
|
+
5. **Honesty sections are mandatory** in any results/doc page: state what
|
|
143
|
+
was NOT measured and why.
|