hermia 0.1.1__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.
Files changed (86) hide show
  1. hermia-0.1.1/.github/ISSUE_TEMPLATE/bug_report.md +49 -0
  2. hermia-0.1.1/.github/ISSUE_TEMPLATE/feature_request.md +36 -0
  3. hermia-0.1.1/.github/dependabot.yml +13 -0
  4. hermia-0.1.1/.github/pull_request_template.md +19 -0
  5. hermia-0.1.1/.github/workflows/ci.yml +34 -0
  6. hermia-0.1.1/.github/workflows/publish.yml +55 -0
  7. hermia-0.1.1/.github/workflows/security.yml +171 -0
  8. hermia-0.1.1/.gitignore +38 -0
  9. hermia-0.1.1/.gitleaks.toml +100 -0
  10. hermia-0.1.1/.pre-commit-config.yaml +18 -0
  11. hermia-0.1.1/.secrets.baseline +171 -0
  12. hermia-0.1.1/AGENTS.md +214 -0
  13. hermia-0.1.1/CHANGELOG.md +63 -0
  14. hermia-0.1.1/CLAUDE.md +64 -0
  15. hermia-0.1.1/CODE_OF_CONDUCT.md +58 -0
  16. hermia-0.1.1/CONTRIBUTING.md +122 -0
  17. hermia-0.1.1/LICENSE +21 -0
  18. hermia-0.1.1/PKG-INFO +278 -0
  19. hermia-0.1.1/README.md +236 -0
  20. hermia-0.1.1/SECURITY.md +76 -0
  21. hermia-0.1.1/assets/demo.mp4 +0 -0
  22. hermia-0.1.1/assets/goldilocks.cast +2841 -0
  23. hermia-0.1.1/assets/goldilocks.mp4 +0 -0
  24. hermia-0.1.1/docs/demo-reference-2026-05-21.md +111 -0
  25. hermia-0.1.1/docs/llm-benchmark-landscape-2026.md +330 -0
  26. hermia-0.1.1/docs/roadmap.md +554 -0
  27. hermia-0.1.1/docs/security-framework-research.md +281 -0
  28. hermia-0.1.1/docs/specs/hermia-0ws-spec.md +232 -0
  29. hermia-0.1.1/docs/specs/hermia-gx8-spec.md +149 -0
  30. hermia-0.1.1/docs/specs/hermia-tun-spec.md +353 -0
  31. hermia-0.1.1/docs/specs/hermia-w59-spec.md +222 -0
  32. hermia-0.1.1/docs/usage.md +300 -0
  33. hermia-0.1.1/hermia-fleet.yaml +27 -0
  34. hermia-0.1.1/pyproject.toml +87 -0
  35. hermia-0.1.1/scripts/add_audit_columns.sql +3 -0
  36. hermia-0.1.1/scripts/add_findings_table.sql +48 -0
  37. hermia-0.1.1/scripts/add_framework_columns.sql +19 -0
  38. hermia-0.1.1/scripts/add_judge_columns.sql +8 -0
  39. hermia-0.1.1/scripts/add_mode_columns.sql +2 -0
  40. hermia-0.1.1/scripts/create_table.sql +37 -0
  41. hermia-0.1.1/scripts/hermia +10 -0
  42. hermia-0.1.1/src/hermia/__init__.py +3 -0
  43. hermia-0.1.1/src/hermia/analyze.py +484 -0
  44. hermia-0.1.1/src/hermia/app.py +107 -0
  45. hermia-0.1.1/src/hermia/audit.py +235 -0
  46. hermia-0.1.1/src/hermia/export.py +232 -0
  47. hermia-0.1.1/src/hermia/fleet.py +121 -0
  48. hermia-0.1.1/src/hermia/metrics.py +462 -0
  49. hermia-0.1.1/src/hermia/preflight.py +209 -0
  50. hermia-0.1.1/src/hermia/regression.py +270 -0
  51. hermia-0.1.1/src/hermia/results.py +72 -0
  52. hermia-0.1.1/src/hermia/robustness.py +123 -0
  53. hermia-0.1.1/src/hermia/runner.py +250 -0
  54. hermia-0.1.1/src/hermia/schemas.py +332 -0
  55. hermia-0.1.1/src/hermia/screens.py +418 -0
  56. hermia-0.1.1/test-datasets/agentic-tasks.json +455 -0
  57. hermia-0.1.1/tests/__init__.py +0 -0
  58. hermia-0.1.1/tests/integration/__init__.py +0 -0
  59. hermia-0.1.1/tests/integration/conftest.py +87 -0
  60. hermia-0.1.1/tests/integration/test_determinism.py +93 -0
  61. hermia-0.1.1/tests/integration/test_fake_ollama.py +110 -0
  62. hermia-0.1.1/tests/security/__init__.py +0 -0
  63. hermia-0.1.1/tests/security/test_adversarial_input_robustness.py +131 -0
  64. hermia-0.1.1/tests/security/test_prompt_injection.py +69 -0
  65. hermia-0.1.1/tests/security/test_robustness.py +187 -0
  66. hermia-0.1.1/tests/security/test_scope_escalation.py +51 -0
  67. hermia-0.1.1/tests/security/test_security_boundary.py +28 -0
  68. hermia-0.1.1/tests/security/test_structured_field_injection.py +103 -0
  69. hermia-0.1.1/tests/test_regression.py +454 -0
  70. hermia-0.1.1/tests/unit/__init__.py +0 -0
  71. hermia-0.1.1/tests/unit/test_analyze.py +434 -0
  72. hermia-0.1.1/tests/unit/test_app.py +160 -0
  73. hermia-0.1.1/tests/unit/test_audit.py +342 -0
  74. hermia-0.1.1/tests/unit/test_export.py +553 -0
  75. hermia-0.1.1/tests/unit/test_fleet.py +374 -0
  76. hermia-0.1.1/tests/unit/test_metrics.py +711 -0
  77. hermia-0.1.1/tests/unit/test_preflight.py +171 -0
  78. hermia-0.1.1/tests/unit/test_regression.py +366 -0
  79. hermia-0.1.1/tests/unit/test_results.py +147 -0
  80. hermia-0.1.1/tests/unit/test_robustness.py +191 -0
  81. hermia-0.1.1/tests/unit/test_runner.py +667 -0
  82. hermia-0.1.1/tests/unit/test_schemas.py +323 -0
  83. hermia-0.1.1/tests/unit/test_schemas_properties.py +362 -0
  84. hermia-0.1.1/tests/unit/test_screens.py +156 -0
  85. hermia-0.1.1/tests/unit/test_screens_aggregates.py +95 -0
  86. hermia-0.1.1/tests/unit/test_screens_pilot.py +556 -0
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something isn't working correctly
4
+ title: 'bug: '
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## What happened
10
+
11
+ <!-- Clear description of the bug. -->
12
+
13
+ ## Expected behavior
14
+
15
+ <!-- What should have happened instead. -->
16
+
17
+ ## Steps to reproduce
18
+
19
+ ```
20
+ 1.
21
+ 2.
22
+ 3.
23
+ ```
24
+
25
+ ## Environment
26
+
27
+ - OS:
28
+ - Python version:
29
+ - Ollama version:
30
+ - Model(s) under test:
31
+ - Hermia version / commit:
32
+
33
+ ## Eval context (if applicable)
34
+
35
+ <!-- Which dimension or test ID is affected? Which model(s)? -->
36
+
37
+ - Test ID:
38
+ - Model:
39
+ - Dimension:
40
+
41
+ ## Relevant output
42
+
43
+ ```
44
+ paste terminal output here
45
+ ```
46
+
47
+ ## Additional context
48
+
49
+ <!-- Anything else that might be relevant. -->
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: Feature request
3
+ about: Propose a new eval test, dimension, or capability
4
+ title: 'feat: '
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## What problem does this solve
10
+
11
+ <!-- Why does this need to exist? What gap does it fill? -->
12
+
13
+ ## Proposed solution
14
+
15
+ <!-- What would you build? Keep it specific. -->
16
+
17
+ ## Framework mapping (for new eval tests)
18
+
19
+ <!-- If proposing a new eval test or dimension, which framework(s) does it map to?
20
+ OWASP LLM Top 10, MITRE ATLAS, CSA MAESTRO, NIST AI RMF — or a gap none of them cover. -->
21
+
22
+ - Framework:
23
+ - Reference (e.g. OWASP LLM01, ATLAS AML.T0054):
24
+
25
+ ## Alternatives considered
26
+
27
+ <!-- What else could solve this problem? Why is your proposal better? -->
28
+
29
+ ## Scope estimate
30
+
31
+ <!-- How much of the codebase does this touch?
32
+ New eval test only / schema changes / runner changes / TUI changes / CI changes -->
33
+
34
+ ## Additional context
35
+
36
+ <!-- Links, prior art, related issues. -->
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ open-pull-requests-limit: 5
8
+
9
+ - package-ecosystem: github-actions
10
+ directory: "/"
11
+ schedule:
12
+ interval: quarterly
13
+ open-pull-requests-limit: 5
@@ -0,0 +1,19 @@
1
+ ## What
2
+ <!-- One sentence: what does this change do? -->
3
+
4
+ ## Why
5
+ <!-- Why is this change needed? Link to issue or framework gap if applicable (e.g., OWASP LLM01, ATLAS AML.T0054). -->
6
+
7
+ ## Test coverage
8
+ <!-- What tests cover this? New tests added? Existing tests affected? -->
9
+ - [ ] New eval test cases added to `agentic-tasks.json`
10
+ - [ ] Unit tests added/updated in `tests/`
11
+ - [ ] Manually verified against local Ollama endpoint
12
+
13
+ ## Security checklist
14
+ - [ ] No secrets, credentials, or API keys in diff
15
+ - [ ] No new dependencies without justification
16
+ - [ ] Bandit/pip-audit clean (CI will verify)
17
+
18
+ ## Notes for reviewer
19
+ <!-- Anything Gemini Code Assist or a human reviewer should pay particular attention to. -->
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - "feature/**"
7
+ - "fix/**"
8
+ - "chore/**"
9
+ - "dev"
10
+ pull_request:
11
+ branches:
12
+ - dev
13
+ - main
14
+
15
+ jobs:
16
+ lint-and-test:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
20
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
21
+ with:
22
+ python-version: "3.11"
23
+
24
+ - name: Install dependencies
25
+ run: pip install -e ".[dev]"
26
+
27
+ - name: Lint (ruff)
28
+ run: ruff check src/ tests/
29
+
30
+ - name: Type check (mypy)
31
+ run: mypy src/
32
+
33
+ - name: Test (pytest)
34
+ run: pytest tests/
@@ -0,0 +1,55 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+
14
+ steps:
15
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
16
+
17
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
18
+ with:
19
+ python-version: "3.11"
20
+
21
+ - name: Install dependencies
22
+ run: pip install -e ".[dev]"
23
+
24
+ - name: Lint (ruff)
25
+ run: ruff check src/ tests/
26
+
27
+ - name: Type check (mypy)
28
+ run: mypy src/
29
+
30
+ - name: Test (pytest)
31
+ run: pytest tests/
32
+
33
+ build-and-publish:
34
+ needs: test
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ contents: read
39
+ id-token: write
40
+
41
+ steps:
42
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
43
+
44
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
45
+ with:
46
+ python-version: "3.11"
47
+
48
+ - name: Install build
49
+ run: pip install build==1.5.0
50
+
51
+ - name: Build
52
+ run: python -m build
53
+
54
+ - name: Publish to PyPI
55
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,171 @@
1
+ name: Security
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main # full security gate before anything hits main
7
+ - dev # catch issues before promotion, not after
8
+ schedule:
9
+ - cron: "0 6 * * 1" # weekly Monday 06:00 UTC — scans main regardless of activity
10
+
11
+ jobs:
12
+ gitleaks:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ contents: read
16
+ pull-requests: read
17
+ steps:
18
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
19
+ with:
20
+ fetch-depth: 0
21
+ - uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2
22
+ env:
23
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24
+ GITLEAKS_CONFIG: .gitleaks.toml
25
+
26
+ trufflehog:
27
+ runs-on: ubuntu-latest
28
+ permissions:
29
+ contents: read
30
+ pull-requests: read
31
+ steps:
32
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
33
+ with:
34
+ fetch-depth: 0
35
+ - name: TruffleHog — entropy + credential scan
36
+ uses: trufflesecurity/trufflehog@0fa069c12f0c7baf431041cd1e564a9c5058846c # main 2026-05-16
37
+
38
+ trivy:
39
+ runs-on: ubuntu-latest
40
+ steps:
41
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
42
+ - name: Trivy dependency scan
43
+ uses: aquasecurity/trivy-action@314ff8b43182423b84c50b1670b0e10f858f2d98 # master 2026-05-16
44
+ with:
45
+ scan-type: fs
46
+ scan-ref: "."
47
+ exit-code: "1"
48
+ severity: HIGH,CRITICAL
49
+
50
+ bandit:
51
+ runs-on: ubuntu-latest
52
+ steps:
53
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
54
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
55
+ with:
56
+ python-version: "3.11"
57
+ - name: Install bandit
58
+ run: pip install bandit
59
+ - name: Bandit SAST
60
+ run: bandit -r src/ -ll
61
+
62
+ pip-audit:
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
66
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
67
+ with:
68
+ python-version: "3.11"
69
+ - name: Audit hermia dependencies in isolated venv
70
+ run: |
71
+ python -m venv /tmp/audit-env
72
+ /tmp/audit-env/bin/pip install --quiet --upgrade pip
73
+ /tmp/audit-env/bin/pip install --quiet pip-audit
74
+ /tmp/audit-env/bin/pip install --quiet -e .
75
+ # CVE-2026-3219 affects pip itself (no fix available yet); all hermia deps are clean
76
+ /tmp/audit-env/bin/pip-audit --skip-editable --ignore-vuln CVE-2026-3219
77
+
78
+ guarddog-changes:
79
+ runs-on: ubuntu-latest
80
+ outputs:
81
+ relevant: ${{ steps.filter.outputs.relevant }}
82
+ steps:
83
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
84
+ with:
85
+ fetch-depth: 0
86
+ - id: filter
87
+ run: |
88
+ if [[ "${{ github.event_name }}" == "schedule" ]]; then
89
+ echo "relevant=true" >> "$GITHUB_OUTPUT"
90
+ elif git diff --name-only "origin/${{ github.base_ref }}...HEAD" \
91
+ | grep -qE '^(pyproject\.toml|\.github/workflows/security\.yml)$'; then
92
+ echo "relevant=true" >> "$GITHUB_OUTPUT"
93
+ else
94
+ echo "relevant=false" >> "$GITHUB_OUTPUT"
95
+ echo "No dep or workflow changes — skipping guarddog"
96
+ fi
97
+
98
+ guarddog:
99
+ needs: guarddog-changes
100
+ if: needs.guarddog-changes.outputs.relevant == 'true'
101
+ runs-on: ubuntu-latest
102
+ timeout-minutes: 10
103
+ steps:
104
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
105
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
106
+ with:
107
+ python-version: "3.11"
108
+ - name: Install guarddog
109
+ # pinned to avoid silent rule/CLI changes; bump quarterly and re-validate rule names
110
+ run: pip install "guarddog==2.10.0"
111
+ - name: GuardDog — typosquatting (hard fail)
112
+ run: |
113
+ python3 - <<'EOF'
114
+ import tomllib, subprocess, sys
115
+ from packaging.requirements import Requirement
116
+ from packaging.utils import canonicalize_name
117
+ with open("pyproject.toml", "rb") as f:
118
+ data = tomllib.load(f)
119
+ project = data.get("project", {})
120
+ all_deps = list(project.get("dependencies", []))
121
+ for group in project.get("optional-dependencies", {}).values():
122
+ all_deps += group
123
+ pkgs = sorted({canonicalize_name(Requirement(d).name) for d in all_deps})
124
+ failed = False
125
+ for pkg in pkgs:
126
+ print(f"Scanning {pkg}...")
127
+ r = subprocess.run(
128
+ ["guarddog", "pypi", "scan", pkg,
129
+ "--exit-non-zero-on-finding",
130
+ "--rules", "typosquatting"],
131
+ check=False,
132
+ )
133
+ if r.returncode != 0:
134
+ failed = True
135
+ if failed:
136
+ sys.exit(1)
137
+ EOF
138
+ - name: GuardDog — heuristic rules (warn only)
139
+ continue-on-error: true
140
+ run: |
141
+ python3 - <<'EOF'
142
+ import tomllib, subprocess, os
143
+ from packaging.requirements import Requirement
144
+ from packaging.utils import canonicalize_name
145
+ with open("pyproject.toml", "rb") as f:
146
+ data = tomllib.load(f)
147
+ project = data.get("project", {})
148
+ all_deps = list(project.get("dependencies", []))
149
+ for group in project.get("optional-dependencies", {}).values():
150
+ all_deps += group
151
+ pkgs = sorted({canonicalize_name(Requirement(d).name) for d in all_deps})
152
+ findings = []
153
+ for pkg in pkgs:
154
+ print(f"Scanning {pkg}...")
155
+ r = subprocess.run(
156
+ ["guarddog", "pypi", "scan", pkg,
157
+ "--exit-non-zero-on-finding",
158
+ "--rules", "potentially_compromised_email_domain",
159
+ "--rules", "obfuscation"],
160
+ check=False, capture_output=True, text=True,
161
+ )
162
+ print(r.stdout)
163
+ if r.returncode != 0:
164
+ findings.append((pkg, r.stdout))
165
+ summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
166
+ if summary_path and findings:
167
+ with open(summary_path, "a") as f:
168
+ f.write("## :warning: GuardDog heuristic findings (warn only)\n\n")
169
+ for pkg, output in findings:
170
+ f.write(f"### `{pkg}`\n```\n{output.strip()}\n```\n\n")
171
+ EOF
@@ -0,0 +1,38 @@
1
+ .venv/
2
+ venv/
3
+ __pycache__/
4
+ ._*
5
+ .coverage
6
+ uv.lock
7
+ *.pyc
8
+ *.pyo
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .pytest_cache/
12
+ dist/
13
+ *.egg-info/
14
+ results/
15
+ .env
16
+ .env.*
17
+ !.env.template
18
+ session-notes/
19
+ prompt.txt
20
+ docs/talk-*.md
21
+ docs/talk-*.js
22
+ docs/*.pptx
23
+ docs/*.pdf
24
+ docs/slide-*.jpg
25
+ docs/~$*
26
+ logs/
27
+ analysis/*.jsonl
28
+ scripts/collect_and_push.sh
29
+ scripts/run_analyze.sh
30
+ scripts/seed_findings.py
31
+ .claude/
32
+ analysis/*.md
33
+ analysis/*.html
34
+ docs/*.docx
35
+
36
+ # Secret scanning
37
+ # .secrets.baseline is intentionally tracked (audited false-positive list)
38
+ # .gitleaks.toml is intentionally tracked (custom rules)
@@ -0,0 +1,100 @@
1
+ # Hermia — Gitleaks configuration
2
+ # Extends the default ruleset with custom rules for internal infrastructure strings.
3
+ # Run: gitleaks detect --config .gitleaks.toml
4
+ # Docs: https://github.com/zricethezav/gitleaks/tree/master#configuration
5
+
6
+ title = "hermia-gitleaks"
7
+
8
+ [extend]
9
+ # Inherit the full upstream default ruleset, then layer our rules on top.
10
+ useDefault = true
11
+
12
+ # ── Custom rules ─────────────────────────────────────────────────────────────
13
+
14
+ [[rules]]
15
+ id = "tailscale-ip"
16
+ description = "Tailscale CGNAT IP (100.64.0.0/10) — covers all fleet nodes past and future"
17
+ regex = '''(?i)(tailscale|ts[_\-]?ip|node[_\-]?ip|host)[^\n]{0,40}100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.\d{1,3}\.\d{1,3}\b'''
18
+ tags = ["tailscale", "internal-ip"]
19
+
20
+ [[rules]]
21
+ id = "tailscale-ip-bare"
22
+ description = "Bare Tailscale CGNAT IP with no keyword context — belt-and-suspenders"
23
+ regex = '''\b100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.\d{1,3}\.\d{1,3}\b'''
24
+ tags = ["tailscale", "internal-ip"]
25
+
26
+ [[rules]]
27
+ id = "tailscale-hostname"
28
+ description = "Any *.tailXXXX.ts.net hostname — catches all tailnets including future ones"
29
+ regex = '''\b[a-z0-9][a-z0-9\-]*\.tail[a-z0-9]+\.ts\.net\b'''
30
+ tags = ["tailscale", "internal-hostname"]
31
+
32
+ [[rules]]
33
+ id = "rfc1918-172-16"
34
+ description = "RFC 1918 172.16–31.x.x (Docker bridge, internal subnets)"
35
+ regex = '''\b172\.(1[6-9]|2[0-9]|3[01])\.\d{1,3}\.\d{1,3}\b'''
36
+ tags = ["internal-ip", "docker"]
37
+
38
+ [[rules]]
39
+ id = "internal-ssh-alias"
40
+ description = "Original internal SSH host aliases — catch if accidentally re-introduced"
41
+ regex = '''\b(m3pro-work|m3pro|m1pro-personal|m1pro|openclaw-linux|openclaw)\b'''
42
+ tags = ["internal-hostname", "ssh"]
43
+
44
+ [[rules]]
45
+ id = "internal-path-home-scott"
46
+ description = "/home/scott/* paths — personal home directory leakage"
47
+ regex = '''/home/scott/[^\s"'`]+'''
48
+ tags = ["internal-path"]
49
+
50
+ [[rules]]
51
+ id = "grafana-dashboard-uid"
52
+ description = "Grafana dashboard UID — full UUID or short UID (default 9-char) in URL or config"
53
+ # Grafana native UIDs are typically 9-char alphanumeric (/d/<uid>/); full UUIDs also used
54
+ regex = '''grafana[^\n]{0,80}(/d/[A-Za-z0-9_-]{8,40}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})'''
55
+ tags = ["grafana", "internal-id"]
56
+
57
+ [[rules]]
58
+ id = "litellm-dispatch-key"
59
+ description = "LiteLLM dispatch/master key"
60
+ # Bridge pattern covers: env var assignments, Python dict literals, YAML config values
61
+ regex = '''(?i)(litellm[_\-]?(dispatch|master|api)[_\-]?key|LITELLM_[A-Z_]*KEY)[^\n]{0,40}["']?[A-Za-z0-9\-_]{20,}'''
62
+ tags = ["api-key", "litellm"]
63
+
64
+ [[rules]]
65
+ id = "postgres-dsn"
66
+ description = "PostgreSQL DSN with embedded credentials"
67
+ # Known gap: passwords containing raw '@' are missed; %40 (URL-encoded) is matched correctly
68
+ regex = '''postgresql://[^:/?#\s]+:(?:[^@\s"'`\\]|%40){6,}@\S+'''
69
+ tags = ["database", "credentials"]
70
+
71
+ # ── Allowlist ─────────────────────────────────────────────────────────────────
72
+
73
+ [allowlist]
74
+ description = "Safe strings that match rules but are intentionally present"
75
+ regexes = [
76
+ # RFC 5737 documentation addresses — used as replacements after purge
77
+ '''192\.0\.2\.\d+''',
78
+ # RFC 2606 documentation domains
79
+ '''hermia\.example\.com''',
80
+ # Placeholder tokens in docs/tests
81
+ '''YOUR-DASHBOARD-ID''',
82
+ '''YOUR-TAILSCALE-IP''',
83
+ '''YOUR-TAILNET''',
84
+ # Literal regex patterns in this config file itself
85
+ '''100\\\.\(6\[4-9\]''',
86
+ ]
87
+
88
+ paths = [
89
+ # Test fixtures that intentionally contain RFC-reserved example addresses
90
+ "tests/",
91
+ # Lock file — no secrets, just hashes
92
+ "uv.lock",
93
+ # detect-secrets baseline records false-positives as JSON — not real secrets
94
+ ".secrets.baseline",
95
+ # Fleet configs — intentionally contain fleet node hostnames and example labels
96
+ "hermia-fleet.yaml",
97
+ "fleet-.*\\.yaml",
98
+ "marcus-only.yaml",
99
+ "overnight.sh",
100
+ ]
@@ -0,0 +1,18 @@
1
+ repos:
2
+ - repo: https://github.com/gitleaks/gitleaks
3
+ rev: c2afd56bbe7ab11564107d34efac4bfde3e3c78d # v8.24.0
4
+ hooks:
5
+ - id: gitleaks
6
+ args: ["--config", ".gitleaks.toml"]
7
+
8
+ - repo: https://github.com/Yelp/detect-secrets
9
+ rev: 01886c8a910c64595c47f186ca1ffc0b77fa5458 # v1.5.0
10
+ hooks:
11
+ - id: detect-secrets
12
+ args: ["--baseline", ".secrets.baseline"]
13
+ exclude: uv\.lock
14
+
15
+ - repo: https://github.com/pre-commit/pre-commit-hooks
16
+ rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # v5.0.0
17
+ hooks:
18
+ - id: detect-private-key