euthyna 0.1.0
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.
- package/LICENSE +202 -0
- package/NOTICE.md +119 -0
- package/README.md +246 -0
- package/assets/euthyna.png +0 -0
- package/bin/euthyna.js +25 -0
- package/package.json +40 -0
- package/src/cli.js +238 -0
- package/src/contract.js +249 -0
- package/src/facts/coverage.js +338 -0
- package/src/facts/history.js +399 -0
- package/src/git.js +107 -0
package/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 2026 euthyna contributors
|
|
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.
|
package/NOTICE.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# 第三方来源与许可
|
|
2
|
+
|
|
3
|
+
## 本项目许可
|
|
4
|
+
|
|
5
|
+
**Apache License 2.0**,全文见 `LICENSE`。
|
|
6
|
+
Copyright 2026 euthyna contributors。
|
|
7
|
+
|
|
8
|
+
## 本仓库**不分发**任何第三方文件
|
|
9
|
+
|
|
10
|
+
这是有意设计的,不是遗漏。
|
|
11
|
+
|
|
12
|
+
本项目的调研需要反复阅读上游原文。但把上游原文**拷进仓库**会带来两个问题:
|
|
13
|
+
它让本仓库的许可证变得含糊(上游中有一份是 CC-BY-SA-4.0),
|
|
14
|
+
而且那份快照会悄悄与上游脱节。
|
|
15
|
+
|
|
16
|
+
所以原文改为**按需拉取**:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
node tools/fetch-references.js # 全部拉取
|
|
20
|
+
node tools/fetch-references.js --list # 只看清单,不下载
|
|
21
|
+
node tools/fetch-references.js competitors # 只拉某一份
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
文件落到 `.refs/`(已 gitignore),并在同目录生成 `PROVENANCE.txt` 记录来源、分支、许可与拉取时间。
|
|
25
|
+
**这些文件不属于本项目,也不受本项目许可覆盖。**
|
|
26
|
+
|
|
27
|
+
已验证:拉取回来的 30 个文件与原先入库的副本**逐字节一致**(SHA-256 比对)。
|
|
28
|
+
|
|
29
|
+
## 上游来源与致谢
|
|
30
|
+
|
|
31
|
+
本项目的**方法论**主要借鉴以下两处公开工作。思想与方法不受版权保护,
|
|
32
|
+
本项目据此**自行实现**(包括代码与技能文本),并按学术惯例署名。
|
|
33
|
+
|
|
34
|
+
### Trail of Bits — `skills`
|
|
35
|
+
|
|
36
|
+
- 仓库:https://github.com/trailofbits/skills
|
|
37
|
+
- 许可:**CC-BY-SA-4.0**,Copyright Trail of Bits
|
|
38
|
+
- 借鉴内容:变更面安全审查(`differential-review`)、误报验证(`fp-check`,
|
|
39
|
+
含 6 门禁、误报清单、恶魔代言人提问)、依赖供应链审计(`supply-chain-risk-auditor`)
|
|
40
|
+
|
|
41
|
+
他们选择 CC-BY-SA 而不是「保留所有权利」,本身就是一份**允许他人复用**的邀请。
|
|
42
|
+
本项目感谢这份公开工作,并**不把他们的文本重新授权**。
|
|
43
|
+
|
|
44
|
+
### dsh-skill-pack-security
|
|
45
|
+
|
|
46
|
+
- 仓库:https://github.com/PerryLink/dsh-skill-pack-security
|
|
47
|
+
- 许可:**Apache-2.0**,dsh-skill-pack-security contributors
|
|
48
|
+
- 借鉴内容:竞品能力边界分析;技能包型插件的 provider 骨架结构
|
|
49
|
+
|
|
50
|
+
## 上游原文**没有被改写进本仓库**
|
|
51
|
+
|
|
52
|
+
本仓库中的方法论与技能文本是**自行撰写的表述**,不是上游文档的翻译或逐句改写。
|
|
53
|
+
判断依据见下节。
|
|
54
|
+
|
|
55
|
+
### 为什么这一点需要单独说明
|
|
56
|
+
|
|
57
|
+
CC BY-SA 4.0 对 `Adapted Material` 的定义**明确包含 "translated"**
|
|
58
|
+
(CC 官方 legalcode 原文):
|
|
59
|
+
|
|
60
|
+
> …material … derived from or based upon the Licensed Material and in which the
|
|
61
|
+
> Licensed Material is **translated**, altered, arranged, transformed, or otherwise modified…
|
|
62
|
+
|
|
63
|
+
也就是说:**翻译或逐句改写会构成改编物**,而 ShareAlike(§3(b))要求改编物以相同许可分发。
|
|
64
|
+
本项目希望整体采用 Apache-2.0,因此**不能**包含对上游文本的改编。
|
|
65
|
+
|
|
66
|
+
同行的两种做法都印证了这条边界:
|
|
67
|
+
|
|
68
|
+
- `solanabr/auditor-skill`(MIT)在 `ATTRIBUTION.md` 中写明:上游以 git submodule 方式引用,
|
|
69
|
+
「**A submodule is a reference (gitlink), not a copy, so no CC-BY-SA ShareAlike obligation
|
|
70
|
+
attaches**」,方法论则「**re-implemented natively, in our own words (not copied)**」
|
|
71
|
+
- `dsh-skill-pack-security`(Apache-2.0)在 `THIRD_PARTY_NOTICES.md` 中声明技能与引擎
|
|
72
|
+
**全部为原创**,未移植第三方代码
|
|
73
|
+
|
|
74
|
+
### ✅ 已解决:仓库内不含任何改编物
|
|
75
|
+
|
|
76
|
+
早期有一份 `docs/methodology-zh.md` 是按「逐条对照改写」写的,属于上述改编物候选。
|
|
77
|
+
它**已从仓库移除**。其中的内容改为**用自己的结构重新撰写**,落在技能里:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
.agents/skills/euthyna/references/
|
|
81
|
+
├── meta-mechanisms.md 让流程不退化成走过场的机制
|
|
82
|
+
├── change-audit.md 变更面审计
|
|
83
|
+
├── dependency-audit.md 依赖面审计
|
|
84
|
+
├── bug-classes.md 缺陷类别与默认假设方向
|
|
85
|
+
├── verification-gates.md 结论面验证
|
|
86
|
+
├── fact-producers.md 两个确定性测量的操作手册
|
|
87
|
+
└── fact-contract.md 事实的读法
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
这些文件是**原创表述**,不是上游文档的翻译。**本仓库现在整体适用 Apache-2.0,无例外。**
|
|
91
|
+
|
|
92
|
+
### 边界在哪
|
|
93
|
+
|
|
94
|
+
判据不是「有没有改代码」,而是**「你的文字是不是从人家的文字长出来的」**:
|
|
95
|
+
|
|
96
|
+
| 做了什么 | 是否需要相同许可 |
|
|
97
|
+
|---|---|
|
|
98
|
+
| 读它、理解方法、**用自己的结构重新表述** | ❌ 不需要 |
|
|
99
|
+
| **翻译它**,或照着它的段落逐句改写 | ✅ 需要 |
|
|
100
|
+
| 把原文件拷进仓库 | ✅ 需要 |
|
|
101
|
+
|
|
102
|
+
上表第二行是本项目早期踩到的点——**它和「改代码」无关**。
|
|
103
|
+
|
|
104
|
+
## DSH 插件目录快照
|
|
105
|
+
|
|
106
|
+
`data/dsh-plugins.json` 是公开插件目录 https://awesome-dsh-plugin.com/plugins.json 的快照
|
|
107
|
+
(`updated` 字段:2026-09-18,共 3931 条),仅用于生态调研。
|
|
108
|
+
其中各插件的名称、描述与链接归各自作者所有。
|
|
109
|
+
|
|
110
|
+
## DeepSeek Harness
|
|
111
|
+
|
|
112
|
+
本仓库中关于宿主能力的描述(技能 frontmatter 契约、hook 协议、技能发现路径等)
|
|
113
|
+
来自对本机安装的 DeepSeek Harness 源码的阅读与**运行验证**,属于对软件行为的**事实性描述**,
|
|
114
|
+
不复制其代码。
|
|
115
|
+
|
|
116
|
+
`tools/check-stop-gate.mjs` 会 `import` 本机 DSH 安装中的两个包
|
|
117
|
+
(`dsh-hook-protocol`、`dsh-hooks-claude-code`)以验证协议行为——它**引用**而非**分发**这些包。
|
|
118
|
+
|
|
119
|
+
DeepSeek Harness 及其相关包归其各自权利人所有。本项目与 DeepSeek 官方无隶属关系。
|
package/README.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/euthyna.png" width="150" alt="euthyna logo">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">euthyna</h1>
|
|
6
|
+
|
|
7
|
+
> **εὔθυνα** — in classical Athens, the audit every outgoing official had to submit.
|
|
8
|
+
> You did not get to simply walk away from office. You handed over your accounts and they
|
|
9
|
+
> were examined. Pass, and you left with your standing intact. Fail, and you faced trial.
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/slow-stack/euthyna/actions/workflows/ci.yml"><img src="https://github.com/slow-stack/euthyna/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
**euthyna is a code security audit framework for AI coding agents.** It is not another
|
|
16
|
+
scanner. It does two things: it **produces the facts an agent cannot compute by reading
|
|
17
|
+
code**, and it **forces every security claim the agent makes through gates before it
|
|
18
|
+
counts as a finding**.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 📖 The problem, in plain words
|
|
23
|
+
|
|
24
|
+
When an AI coding agent touches security, it fails in two specific ways:
|
|
25
|
+
|
|
26
|
+
1. **It reports things that are not real.** Code that *looks* dangerous gets called a
|
|
27
|
+
vulnerability, without tracing the data. In validation runs on real codebases — a
|
|
28
|
+
JavaScript one and a Python one — the pattern-matched "vulnerabilities" were mostly
|
|
29
|
+
false: **5 out of 5** refuted at the gates on the first run; **2 out of 3** refuted,
|
|
30
|
+
the third unresolved (INCONCLUSIVE, supply-chain-dependent) on the second. See the
|
|
31
|
+
[case studies](https://github.com/slow-stack/euthyna/blob/main/docs/case-study-crewai.md)
|
|
32
|
+
([Python/crewAI](https://github.com/slow-stack/euthyna/blob/main/docs/case-study-crewai.md),
|
|
33
|
+
[JavaScript/axe-core](https://github.com/slow-stack/euthyna/blob/main/docs/case-study-axe-core.md)).
|
|
34
|
+
2. **Its reassurances cannot be checked.** "I'm done." "The tests cover this." "It's
|
|
35
|
+
safe now." These are assertions. You cannot tell a done-claim from a done-deal.
|
|
36
|
+
|
|
37
|
+
Neither is fixed by telling the agent to be more careful. euthyna changes the handshake
|
|
38
|
+
between you and the agent:
|
|
39
|
+
|
|
40
|
+
> **The agent saying "I'm done" does not count. The accounts get handed over, and the
|
|
41
|
+
> gates decide.**
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ⚖️ The two things it does
|
|
46
|
+
|
|
47
|
+
### 1. It measures what a model cannot
|
|
48
|
+
|
|
49
|
+
Two fact producers — a zero-dependency Node CLI:
|
|
50
|
+
|
|
51
|
+
- **`history`** — for every line a change deletes, it finds the commit that introduced
|
|
52
|
+
that line and classifies that commit from its own message. If the deleted code came
|
|
53
|
+
from a security fix, that is flagged. This is git archaeology no model can do from
|
|
54
|
+
reading a diff.
|
|
55
|
+
- **`coverage`** — was this symbol *ever actually invoked* by a test? It has exactly two
|
|
56
|
+
answers: never invoked (established), or entered but that proves nothing about any
|
|
57
|
+
specific call site (unknown). **It never reports "executed"** — V8 coverage marks
|
|
58
|
+
unreachable code as covered, and "line covered → call ran" is wrong in exactly the
|
|
59
|
+
direction an audit cannot afford. The reasoning is in
|
|
60
|
+
[`docs/fact-contract.md`](https://github.com/slow-stack/euthyna/blob/main/docs/fact-contract.md) §6.2.
|
|
61
|
+
|
|
62
|
+
### 2. It gates what the agent claims
|
|
63
|
+
|
|
64
|
+
The [skill](https://github.com/slow-stack/euthyna/tree/main/.agents/skills/euthyna/) is the audit discipline itself, as loadable
|
|
65
|
+
Markdown. Every security claim must pass six gates — reachability, trust boundary, real
|
|
66
|
+
impact, and their counterparts. A claim that cannot produce evidence is **downgraded to
|
|
67
|
+
an observation**, not reported as a finding. "I'm done" becomes a package: claims,
|
|
68
|
+
evidence, and the commands that reproduce both.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 🖥️ Which tools it works in, and how to install
|
|
73
|
+
|
|
74
|
+
**Prerequisite for everything**: Node >= 20 and git. There is nothing else to install —
|
|
75
|
+
the project is deliberately zero-dependency.
|
|
76
|
+
|
|
77
|
+
| Host | The skill (audit discipline) | The CLI (fact producers) |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| **DSH** | Copy `.agents/skills/euthyna/` into `~/.agents/skills/` (user-wide) or `<project>/.agents/skills/`. Markdown hot-reloads; no restart needed. | `npm install -g euthyna` — runs in any terminal |
|
|
80
|
+
| **Claude Code** | Copy the same folder into `~/.claude/skills/` | Same |
|
|
81
|
+
| **Codex** | The same Markdown layer works; packaging goes through Codex's plugin/marketplace format | Same |
|
|
82
|
+
| **Any terminal** | — | `npm install -g euthyna`, then `euthyna …` |
|
|
83
|
+
|
|
84
|
+
Two honest notes:
|
|
85
|
+
|
|
86
|
+
- **The skill is the instructions; the CLI is the measurement.** The skill directory
|
|
87
|
+
does **not** contain the CLI. Install the CLI from npm (`npm install -g euthyna`) or
|
|
88
|
+
keep this repository checked out; on a host without the CLI, the skill requires the
|
|
89
|
+
unmeasurable criteria to be recorded as *not evaluated* rather than guessed at — that
|
|
90
|
+
fallback is the design, not a gap.
|
|
91
|
+
- **The skill text and the CLI's reports are currently written in Chinese.** The
|
|
92
|
+
discipline is host-agnostic Markdown, but an English reader should expect Chinese
|
|
93
|
+
output from the tool itself.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 🚀 Quick start
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
npm install -g euthyna
|
|
101
|
+
euthyna history --repo <path> --base main --head HEAD
|
|
102
|
+
euthyna coverage --coverage coverage/coverage-final.json --symbol <name>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or without a global install: `npx euthyna history --repo <path> --base main`.
|
|
106
|
+
|
|
107
|
+
From a checkout instead (development):
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
git clone https://github.com/slow-stack/euthyna
|
|
111
|
+
cd euthyna && npm test # 92 tests; no install step exists
|
|
112
|
+
node bin/euthyna.js history --repo <path> --base main --head HEAD
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
What `history` reports looks like this:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
已确证 (7)
|
|
119
|
+
• 本次变更删除了 4 行来自提交 ab877f9d70 的代码,分布在 2 个文件。
|
|
120
|
+
提交信息:"fix(link-in-text-block): don't match style or script text (#3775)",分类:fix
|
|
121
|
+
证据: lib/checks/color/link-in-text-block-evaluate.js (ab877f9d70)
|
|
122
|
+
复现: git blame --porcelain -L 104,104 -L 114,114 <base> -- lib/checks/.../evaluate.js
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Every deleted line is blamed back to the commit that introduced it, and the `复现`
|
|
126
|
+
(Reproduce) command lets you re-derive the claim yourself without trusting the report.
|
|
127
|
+
Add `--json` for the structured fact report, and `--pickaxe` to detect lines that were
|
|
128
|
+
removed and are now being added back.
|
|
129
|
+
|
|
130
|
+
### Exit codes are part of the contract
|
|
131
|
+
|
|
132
|
+
Surveying eight measurement plugins in this ecosystem found **none of them publishes a
|
|
133
|
+
process exit code**, which makes their output unusable as a CI gate. This one does:
|
|
134
|
+
|
|
135
|
+
| Code | Meaning |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `0` | Measured; nothing security-classified found |
|
|
138
|
+
| `10` | Measured; at least one `security`-classified fact exists |
|
|
139
|
+
| `1` | Usage error |
|
|
140
|
+
| `2` | **Could not measure at all** — must not be read as clean |
|
|
141
|
+
|
|
142
|
+
`2` being distinct from `0` is the whole point: *failing to measure* and *measuring and
|
|
143
|
+
finding nothing* are different things.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 🧱 What is actually built
|
|
148
|
+
|
|
149
|
+
| Piece | What it is | Status |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| **Fact producers** | A zero-dependency Node CLI that answers two questions deterministically | Working, tested |
|
|
152
|
+
| **The skill** | The audit discipline itself, as loadable Markdown | Working, loadable |
|
|
153
|
+
| **The benchmark** | A blind recall measurement for the adjudication layer | Four rounds complete |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## ✅ What has been verified, and what has not
|
|
158
|
+
|
|
159
|
+
This project tries to be explicit about the difference. Current state:
|
|
160
|
+
|
|
161
|
+
### Verified
|
|
162
|
+
|
|
163
|
+
- **`history` attribution against real repositories — in two languages.** Run against
|
|
164
|
+
[axe-core](https://github.com/dequelabs/axe-core) (JavaScript) and
|
|
165
|
+
[crewAI](https://github.com/crewAIInc/crewAI) (Python); deleted lines attributed to the
|
|
166
|
+
commits that introduced them, then checked **by hand** against `git blame`. The checks
|
|
167
|
+
developed for that comparison now run as regression tests in the suite.
|
|
168
|
+
- **`coverage` on real output in two formats** — c8/V8 JSON and coverage.py JSON (format 3) —
|
|
169
|
+
distinguishing all three states correctly.
|
|
170
|
+
- **Adjudication recall and specificity**, measured blind: **10/10 cases**, 4 real
|
|
171
|
+
vulnerabilities all caught, 6 non-vulnerabilities all correctly cleared, no abstentions.
|
|
172
|
+
Round 2 repeated every case three times — **30 adjudications, zero flips**, four of them
|
|
173
|
+
on a different model. Round 3 expanded the set to **18 cases** (8 real, 10 not) and
|
|
174
|
+
reshuffled the blind ids every round: **54 adjudications**, 24/24 real-bug claims caught
|
|
175
|
+
with no misses and no abstentions, 29/30 non-vulnerabilities correctly cleared — and the
|
|
176
|
+
single "false alarm" was the round's finding, not noise: the adjudicator caught a defect
|
|
177
|
+
in a fixture's guard, confirmed by reproduction and fixed. Every case is a *near-neighbour
|
|
178
|
+
pair* — same pattern, one guard apart — so the verdicts had to come from reading the guard
|
|
179
|
+
rather than recognising the shape. Round 4 re-ran the full set under fresh id shuffles, with
|
|
180
|
+
the twice-defeated guard — rebuilt as a bare-name allow-list — facing its first blind
|
|
181
|
+
adjudication: **54/54 correct**, all 8 pairs separated, and a third run on a second model
|
|
182
|
+
family agreed with the first two on every case.
|
|
183
|
+
See [`bench/RESULTS.md`](https://github.com/slow-stack/euthyna/blob/main/bench/RESULTS.md),
|
|
184
|
+
[`bench/RESULTS-round2.md`](https://github.com/slow-stack/euthyna/blob/main/bench/RESULTS-round2.md),
|
|
185
|
+
[`bench/RESULTS-round3.md`](https://github.com/slow-stack/euthyna/blob/main/bench/RESULTS-round3.md),
|
|
186
|
+
and [`bench/RESULTS-round4.md`](https://github.com/slow-stack/euthyna/blob/main/bench/RESULTS-round4.md).
|
|
187
|
+
- **The delivery-gate mechanism**, by running the real host plugin: blocking works, and the two
|
|
188
|
+
documented ways of getting it wrong do not. See [`docs/dsh-stop-gate.md`](https://github.com/slow-stack/euthyna/blob/main/docs/dsh-stop-gate.md).
|
|
189
|
+
|
|
190
|
+
### Not verified
|
|
191
|
+
|
|
192
|
+
- **Whether the method finds vulnerabilities in real code.** The benchmark measures whether the
|
|
193
|
+
discipline reaches the right verdict *on a claim*. It does not measure whether the claims would
|
|
194
|
+
be found in the first place. The cases are deliberately constructed. The crewAI case study
|
|
195
|
+
surfaced one INCONCLUSIVE (pickle deserialization, supply-chain-dependent) and refuted the
|
|
196
|
+
rest — a directional signal, not a rate.
|
|
197
|
+
- **Recall in the field.** The benchmark's real-bug cases are constructed; whether the
|
|
198
|
+
discipline helps on code nobody staged for it is unmeasured.
|
|
199
|
+
- **Source maps, bundlers, monorepos** for the coverage producer. Untested.
|
|
200
|
+
- **Anything about the case-study targets' security** — the runs found nothing to endorse or
|
|
201
|
+
condemn; that is not a statement about either project. See
|
|
202
|
+
[`docs/case-study-crewai.md`](https://github.com/slow-stack/euthyna/blob/main/docs/case-study-crewai.md) and
|
|
203
|
+
[`docs/case-study-axe-core.md`](https://github.com/slow-stack/euthyna/blob/main/docs/case-study-axe-core.md).
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 📂 Repository layout
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
euthyna/
|
|
211
|
+
├── bin/ src/ test/ Fact producers (zero dependencies, Node >= 20)
|
|
212
|
+
├── .agents/skills/euthyna/ The audit discipline, as a portable skill
|
|
213
|
+
├── bench/ Blind recall benchmark + results
|
|
214
|
+
├── docs/ Design notes and case studies (English and Chinese)
|
|
215
|
+
├── tools/ Research and verification scripts
|
|
216
|
+
└── data/ DSH plugin catalog snapshot
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`tools/fetch-references.js` downloads the upstream sources this project reads into `.refs/`
|
|
220
|
+
(gitignored). **No third-party files are distributed in this repository** — see
|
|
221
|
+
[`NOTICE.md`](NOTICE.md) for why, and for what is owed to whom.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 🧭 Status
|
|
226
|
+
|
|
227
|
+
Early, and honest about it. Working: the two fact producers, the skill, the benchmark harness.
|
|
228
|
+
Not yet built: wiring the skill to the CLI so an agent uses them without being told, and the
|
|
229
|
+
git-history / coverage work needed to close the remaining recall gap.
|
|
230
|
+
|
|
231
|
+
The design notes are available in English and Chinese; the `-zh` files are the originals.
|
|
232
|
+
|
|
233
|
+
## 🤝 Contributing
|
|
234
|
+
|
|
235
|
+
Read [`CONTRIBUTING.md`](CONTRIBUTING.md). The short version: no AI attribution in commits,
|
|
236
|
+
one change per commit, and do not claim something works until you have run it.
|
|
237
|
+
|
|
238
|
+
## 🔒 Security
|
|
239
|
+
|
|
240
|
+
The fact producers execute `git` and parse coverage output; their integrity is the product.
|
|
241
|
+
What is in scope, and how to report privately: [`SECURITY.md`](SECURITY.md). Note that the
|
|
242
|
+
benchmark fixtures in `bench/cases/` are vulnerable by construction and are not vulnerabilities.
|
|
243
|
+
|
|
244
|
+
## 📜 License
|
|
245
|
+
|
|
246
|
+
**Apache License 2.0** — see [`LICENSE`](LICENSE).
|
|
Binary file
|
package/bin/euthyna.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* euthyna CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Kept trivial on purpose: argument handling and exit codes live in src/cli.js
|
|
6
|
+
* so they can be exercised by tests without spawning a process.
|
|
7
|
+
*/
|
|
8
|
+
import process from 'node:process';
|
|
9
|
+
import { main } from '../src/cli.js';
|
|
10
|
+
import { safeTextLines } from '../src/contract.js';
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
14
|
+
} catch (error) {
|
|
15
|
+
// An unexpected throw is a measurement failure, not a clean result. Saying so
|
|
16
|
+
// is the whole point of having a distinct exit code for it.
|
|
17
|
+
//
|
|
18
|
+
// stderr boundary: an error message inherits repo-controlled text (git embeds
|
|
19
|
+
// filenames and refs in its stderr), so the stack is made terminal-safe at
|
|
20
|
+
// this write, exactly once, like the report channel at its render boundary.
|
|
21
|
+
process.stderr.write(
|
|
22
|
+
safeTextLines(`euthyna: 测量过程抛出异常,结果不可用\n${error?.stack ?? error}\n`)
|
|
23
|
+
);
|
|
24
|
+
process.exitCode = 2;
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "euthyna",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Deterministic fact producers for security auditing: which deleted code came from a security fix, and which changed symbols no test ever executed.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"euthyna": "./bin/euthyna.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"assets/euthyna.png",
|
|
13
|
+
"NOTICE.md"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "node --test",
|
|
20
|
+
"check:license": "node tools/check-license-text.mjs"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"security-audit",
|
|
24
|
+
"git",
|
|
25
|
+
"code-review",
|
|
26
|
+
"coverage",
|
|
27
|
+
"ai-agents",
|
|
28
|
+
"ai-coding-agents"
|
|
29
|
+
],
|
|
30
|
+
"author": "modusensus",
|
|
31
|
+
"license": "Apache-2.0",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/slow-stack/euthyna.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/slow-stack/euthyna/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/slow-stack/euthyna#readme"
|
|
40
|
+
}
|