notari 0.3.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.
Files changed (180) hide show
  1. notari-0.3.0/.github/ISSUE_TEMPLATE/bug_report.md +51 -0
  2. notari-0.3.0/.github/ISSUE_TEMPLATE/config.yml +11 -0
  3. notari-0.3.0/.github/ISSUE_TEMPLATE/feature_request.md +32 -0
  4. notari-0.3.0/.github/ISSUE_TEMPLATE/missed_dangerous_action.md +50 -0
  5. notari-0.3.0/.github/dependabot.yml +52 -0
  6. notari-0.3.0/.github/pull_request_template.md +37 -0
  7. notari-0.3.0/.github/workflows/ci.yml +66 -0
  8. notari-0.3.0/.github/workflows/notari-check.yml +57 -0
  9. notari-0.3.0/.github/workflows/release.yml +71 -0
  10. notari-0.3.0/.gitignore +104 -0
  11. notari-0.3.0/CHANGELOG.md +415 -0
  12. notari-0.3.0/CITATION.cff +24 -0
  13. notari-0.3.0/CONTRIBUTING.md +58 -0
  14. notari-0.3.0/LICENSE +21 -0
  15. notari-0.3.0/NOTICE +41 -0
  16. notari-0.3.0/PKG-INFO +513 -0
  17. notari-0.3.0/README.md +447 -0
  18. notari-0.3.0/SECURITY.md +85 -0
  19. notari-0.3.0/action.yml +174 -0
  20. notari-0.3.0/docs/LAUNCH-DRY-RUN-0.3.0.md +104 -0
  21. notari-0.3.0/docs/LEARNING-LOOP.md +97 -0
  22. notari-0.3.0/docs/PRODUCT.md +106 -0
  23. notari-0.3.0/docs/QUICKSTART.md +162 -0
  24. notari-0.3.0/docs/SECURITY-MODEL.md +530 -0
  25. notari-0.3.0/docs/assets/notari-flow-dark.svg +71 -0
  26. notari-0.3.0/docs/assets/notari-flow-light.svg +71 -0
  27. notari-0.3.0/docs/assets/notari-trust-dark.svg +61 -0
  28. notari-0.3.0/docs/assets/notari-trust-light.svg +61 -0
  29. notari-0.3.0/docs/secure-workflow.yml +53 -0
  30. notari-0.3.0/examples/change_control_demo.sh +113 -0
  31. notari-0.3.0/pyproject.toml +248 -0
  32. notari-0.3.0/scripts/notari-passport.sh +296 -0
  33. notari-0.3.0/scripts/verify_launch_readiness.py +350 -0
  34. notari-0.3.0/src/notari/__init__.py +50 -0
  35. notari-0.3.0/src/notari/__main__.py +13 -0
  36. notari-0.3.0/src/notari/_version.py +1 -0
  37. notari-0.3.0/src/notari/adapters/__init__.py +7 -0
  38. notari-0.3.0/src/notari/adapters/claude_code.py +1523 -0
  39. notari-0.3.0/src/notari/adapters/cursor.py +530 -0
  40. notari-0.3.0/src/notari/approvals.py +258 -0
  41. notari-0.3.0/src/notari/attest.py +197 -0
  42. notari-0.3.0/src/notari/audit.py +349 -0
  43. notari-0.3.0/src/notari/audit_summary.py +674 -0
  44. notari-0.3.0/src/notari/bridge.py +83 -0
  45. notari-0.3.0/src/notari/cli.py +5041 -0
  46. notari-0.3.0/src/notari/code_scan.py +242 -0
  47. notari-0.3.0/src/notari/config.py +303 -0
  48. notari-0.3.0/src/notari/contract.py +264 -0
  49. notari-0.3.0/src/notari/controls.toml +430 -0
  50. notari-0.3.0/src/notari/decay.py +307 -0
  51. notari-0.3.0/src/notari/doctor.py +531 -0
  52. notari-0.3.0/src/notari/errors.py +43 -0
  53. notari-0.3.0/src/notari/events.py +100 -0
  54. notari-0.3.0/src/notari/explain.py +353 -0
  55. notari-0.3.0/src/notari/explain_html.py +111 -0
  56. notari-0.3.0/src/notari/exports.py +563 -0
  57. notari-0.3.0/src/notari/githook.py +283 -0
  58. notari-0.3.0/src/notari/github_review.py +130 -0
  59. notari-0.3.0/src/notari/hints.py +187 -0
  60. notari-0.3.0/src/notari/hints.toml +99 -0
  61. notari-0.3.0/src/notari/insights.py +364 -0
  62. notari-0.3.0/src/notari/integrate.py +288 -0
  63. notari-0.3.0/src/notari/journal.py +435 -0
  64. notari-0.3.0/src/notari/learn.py +516 -0
  65. notari-0.3.0/src/notari/learning.py +893 -0
  66. notari-0.3.0/src/notari/lessons.py +360 -0
  67. notari-0.3.0/src/notari/onboard.py +456 -0
  68. notari-0.3.0/src/notari/otel.py +195 -0
  69. notari-0.3.0/src/notari/overnight.py +304 -0
  70. notari-0.3.0/src/notari/passport.py +331 -0
  71. notari-0.3.0/src/notari/paths.py +67 -0
  72. notari-0.3.0/src/notari/pause.py +215 -0
  73. notari-0.3.0/src/notari/perimeter.py +266 -0
  74. notari-0.3.0/src/notari/pinning.py +258 -0
  75. notari-0.3.0/src/notari/policy.py +1724 -0
  76. notari-0.3.0/src/notari/prompt.py +270 -0
  77. notari-0.3.0/src/notari/prompt_injection.py +317 -0
  78. notari-0.3.0/src/notari/provenance.py +237 -0
  79. notari-0.3.0/src/notari/py.typed +0 -0
  80. notari-0.3.0/src/notari/readiness.py +247 -0
  81. notari-0.3.0/src/notari/receipt.py +318 -0
  82. notari-0.3.0/src/notari/roster.py +139 -0
  83. notari-0.3.0/src/notari/saves.py +456 -0
  84. notari-0.3.0/src/notari/secrets.py +405 -0
  85. notari-0.3.0/src/notari/session.py +294 -0
  86. notari-0.3.0/src/notari/session_approvals.py +147 -0
  87. notari-0.3.0/src/notari/severity.py +151 -0
  88. notari-0.3.0/src/notari/taint.py +250 -0
  89. notari-0.3.0/src/notari/teach.py +164 -0
  90. notari-0.3.0/src/notari/telemetry.py +279 -0
  91. notari-0.3.0/src/notari/tool_scan.py +269 -0
  92. notari-0.3.0/src/notari/touchid.py +187 -0
  93. notari-0.3.0/src/notari/transparency.py +246 -0
  94. notari-0.3.0/src/notari/verify.py +1173 -0
  95. notari-0.3.0/tests/conftest.py +46 -0
  96. notari-0.3.0/tests/test_action_wrapper.py +287 -0
  97. notari-0.3.0/tests/test_adapter_imports.py +57 -0
  98. notari-0.3.0/tests/test_approvals.py +248 -0
  99. notari-0.3.0/tests/test_attest.py +97 -0
  100. notari-0.3.0/tests/test_audit.py +298 -0
  101. notari-0.3.0/tests/test_audit_fixes_tier0.py +142 -0
  102. notari-0.3.0/tests/test_audit_fixes_tier1.py +138 -0
  103. notari-0.3.0/tests/test_audit_fixes_tier2.py +198 -0
  104. notari-0.3.0/tests/test_audit_summary.py +797 -0
  105. notari-0.3.0/tests/test_auto_promote.py +85 -0
  106. notari-0.3.0/tests/test_bench_hot_path.py +192 -0
  107. notari-0.3.0/tests/test_block_secrets_config.py +70 -0
  108. notari-0.3.0/tests/test_bypass_mode.py +131 -0
  109. notari-0.3.0/tests/test_change_control.py +308 -0
  110. notari-0.3.0/tests/test_classified_by.py +53 -0
  111. notari-0.3.0/tests/test_classify_command.py +193 -0
  112. notari-0.3.0/tests/test_claude_hook.py +795 -0
  113. notari-0.3.0/tests/test_cli_integration.py +488 -0
  114. notari-0.3.0/tests/test_code_scan.py +103 -0
  115. notari-0.3.0/tests/test_contract_expiry.py +161 -0
  116. notari-0.3.0/tests/test_cursor_hook.py +236 -0
  117. notari-0.3.0/tests/test_decay.py +146 -0
  118. notari-0.3.0/tests/test_determinism.py +195 -0
  119. notari-0.3.0/tests/test_diff_binary_rename.py +88 -0
  120. notari-0.3.0/tests/test_diff_quoted_paths.py +51 -0
  121. notari-0.3.0/tests/test_disable_auth.py +181 -0
  122. notari-0.3.0/tests/test_doc_counts.py +45 -0
  123. notari-0.3.0/tests/test_explain.py +301 -0
  124. notari-0.3.0/tests/test_exports.py +228 -0
  125. notari-0.3.0/tests/test_false_positives_2026_06.py +128 -0
  126. notari-0.3.0/tests/test_gitattributes_secret.py +62 -0
  127. notari-0.3.0/tests/test_gitattributes_surface.py +71 -0
  128. notari-0.3.0/tests/test_githook.py +289 -0
  129. notari-0.3.0/tests/test_github_review.py +93 -0
  130. notari-0.3.0/tests/test_init_readiness.py +102 -0
  131. notari-0.3.0/tests/test_insights.py +292 -0
  132. notari-0.3.0/tests/test_integrate.py +264 -0
  133. notari-0.3.0/tests/test_journal.py +178 -0
  134. notari-0.3.0/tests/test_kill_test_2026_06.py +259 -0
  135. notari-0.3.0/tests/test_launch_smoke.py +138 -0
  136. notari-0.3.0/tests/test_learn.py +257 -0
  137. notari-0.3.0/tests/test_learning_cleanup.py +342 -0
  138. notari-0.3.0/tests/test_learning_cli.py +271 -0
  139. notari-0.3.0/tests/test_learning_concurrency.py +213 -0
  140. notari-0.3.0/tests/test_learning_core.py +262 -0
  141. notari-0.3.0/tests/test_learning_drift.py +163 -0
  142. notari-0.3.0/tests/test_learning_hook_integration.py +284 -0
  143. notari-0.3.0/tests/test_learning_overrides.py +344 -0
  144. notari-0.3.0/tests/test_learning_real_log_replay.py +179 -0
  145. notari-0.3.0/tests/test_learning_self_test.py +149 -0
  146. notari-0.3.0/tests/test_lessons.py +312 -0
  147. notari-0.3.0/tests/test_onboard.py +217 -0
  148. notari-0.3.0/tests/test_otel.py +164 -0
  149. notari-0.3.0/tests/test_overnight.py +520 -0
  150. notari-0.3.0/tests/test_pause.py +142 -0
  151. notari-0.3.0/tests/test_perimeter_casefold.py +75 -0
  152. notari-0.3.0/tests/test_pinning.py +140 -0
  153. notari-0.3.0/tests/test_policy.py +216 -0
  154. notari-0.3.0/tests/test_prompt_injection.py +268 -0
  155. notari-0.3.0/tests/test_readiness.py +82 -0
  156. notari-0.3.0/tests/test_receipt_narrate.py +225 -0
  157. notari-0.3.0/tests/test_rename_and_inventory.py +196 -0
  158. notari-0.3.0/tests/test_resource_limits.py +130 -0
  159. notari-0.3.0/tests/test_roster.py +67 -0
  160. notari-0.3.0/tests/test_saves.py +428 -0
  161. notari-0.3.0/tests/test_secrets.py +366 -0
  162. notari-0.3.0/tests/test_secure_workflow_isolation.py +158 -0
  163. notari-0.3.0/tests/test_security_gates_2026_05.py +329 -0
  164. notari-0.3.0/tests/test_security_regressions.py +515 -0
  165. notari-0.3.0/tests/test_self_disable_classifier.py +96 -0
  166. notari-0.3.0/tests/test_sensitive_surfaces_agent.py +144 -0
  167. notari-0.3.0/tests/test_session_approvals.py +94 -0
  168. notari-0.3.0/tests/test_severity.py +124 -0
  169. notari-0.3.0/tests/test_submodule_policy.py +106 -0
  170. notari-0.3.0/tests/test_symlink_policy.py +79 -0
  171. notari-0.3.0/tests/test_telemetry.py +197 -0
  172. notari-0.3.0/tests/test_touchid.py +234 -0
  173. notari-0.3.0/tests/test_transparency.py +109 -0
  174. notari-0.3.0/tests/test_trust_layer.py +288 -0
  175. notari-0.3.0/tests/test_trust_root_path.py +47 -0
  176. notari-0.3.0/tests/test_trust_spine.py +433 -0
  177. notari-0.3.0/tests/test_verify_passport_validity.py +114 -0
  178. notari-0.3.0/uv.lock +2044 -0
  179. notari-0.3.0/web/logo_1024x1024.png +0 -0
  180. notari-0.3.0/web/logo_400x400.png +0 -0
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something Notari should do but doesn't, or shouldn't do but does
4
+ title: "bug: "
5
+ labels: ["bug"]
6
+ ---
7
+
8
+ <!--
9
+ Before filing: please confirm the bug reproduces on the latest released
10
+ version. `notari version` to check.
11
+ -->
12
+
13
+ ## What happened
14
+
15
+ A clear description of the bug. Include the exact command or tool call
16
+ that triggered it.
17
+
18
+ ## What you expected
19
+
20
+ A description of what Notari should have done instead.
21
+
22
+ ## Steps to reproduce
23
+
24
+ 1.
25
+ 2.
26
+ 3.
27
+
28
+ ## Environment
29
+
30
+ - OS: <!-- macOS / Linux / Windows + version -->
31
+ - Notari version: <!-- output of `notari version` -->
32
+ - Python version: <!-- output of `python --version` -->
33
+ - Coding agent: <!-- Claude Code / Cursor / Cline / etc. and version -->
34
+
35
+ ## Relevant audit log entries
36
+
37
+ If the bug involves a gate decision, paste the relevant `~/.notari/audit.log.jsonl`
38
+ lines. Strip any sensitive args before pasting; Notari's redaction normally
39
+ keeps these out but verify.
40
+
41
+ ```json
42
+
43
+ ```
44
+
45
+ ## `notari doctor` output
46
+
47
+ ```
48
+
49
+ ```
50
+
51
+ ## Anything else
@@ -0,0 +1,11 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security disclosure
4
+ url: https://github.com/manumarri-sudo/notari/security/advisories/new
5
+ about: Report a vulnerability privately (preferred over filing a public issue)
6
+ - name: Threat-model review
7
+ url: https://github.com/manumarri-sudo/notari/blob/main/SECURITY.md
8
+ about: Read SECURITY.md first if your question is about the threat model
9
+ - name: How to integrate with my coding agent
10
+ url: https://github.com/manumarri-sudo/notari/blob/main/docs/clients.md
11
+ about: Per-client integration recipes (Claude Code, Cursor, Cline, Aider, Continue, Windsurf, Zed)
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: Feature request
3
+ about: A capability Notari should have
4
+ title: "feat: "
5
+ labels: ["enhancement"]
6
+ ---
7
+
8
+ ## The problem this solves
9
+
10
+ Describe the situation where Notari falls short today. Focus on the
11
+ workflow, not the implementation.
12
+
13
+ ## The proposed feature
14
+
15
+ What should Notari do? Be specific about the user-facing surface (new
16
+ CLI command, new policy override, new event type, etc.).
17
+
18
+ ## Why this matters
19
+
20
+ Who benefits? Roughly how many users / customer accounts? Any compliance
21
+ or insurance angle?
22
+
23
+ ## Alternatives considered
24
+
25
+ What else could solve this? Why is the proposed feature better?
26
+
27
+ ## Sketch
28
+
29
+ If you have a sketch of the API / TOML / event-type shape, paste it here.
30
+ Not required.
31
+
32
+ ## Anything else
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: Missed dangerous action
3
+ about: An agent ran a command Notari should have refused
4
+ title: "missed-action: "
5
+ labels: ["missed-dangerous-action", "policy"]
6
+ ---
7
+
8
+ <!--
9
+ This is the highest-signal issue type for Notari. Every accepted issue
10
+ ships as a new pattern in src/notari/policy.py or src/notari/secrets.py
11
+ in the next release. Reproducibility matters more than narrative.
12
+ -->
13
+
14
+ ## The action Notari let through
15
+
16
+ Exact command, tool name, and args (redact secrets):
17
+
18
+ ```
19
+
20
+ ```
21
+
22
+ ## Why this is dangerous
23
+
24
+ One or two sentences. If it's a well-known CVE class, link the CVE.
25
+
26
+ ## What Notari should have done
27
+
28
+ `Risk.CRITICAL` (block + type-to-confirm) / `Risk.HIGH` (ask y/N) / other?
29
+
30
+ ## Synthetic reproduction
31
+
32
+ A safe test command that exercises the same pattern Notari should match
33
+ against. Doesn't have to actually be destructive; the regex must catch it.
34
+
35
+ ```
36
+
37
+ ```
38
+
39
+ ## Relevant policy section
40
+
41
+ If you've already located the regex set that should have fired, link
42
+ the relevant constant in [`src/notari/policy.py`](../../src/notari/policy.py).
43
+
44
+ ## Environment
45
+
46
+ - Notari version:
47
+ - Coding agent + version:
48
+ - OS:
49
+
50
+ ## Anything else
@@ -0,0 +1,52 @@
1
+ # Dependabot keeps Notari's deps current with weekly PRs.
2
+ # Three ecosystems matter here: the Python runtime deps, the GitHub Actions
3
+ # we run on every CI / release, and the optional extras (weasyprint,
4
+ # pyobjc-LocalAuthentication, asyncpg, opentelemetry) shipped under
5
+ # `[pdf]`, `[touchid]`, `[postgres]`, and `[otel]`.
6
+ #
7
+ # Security updates ship immediately regardless of the weekly cadence.
8
+
9
+ version: 2
10
+
11
+ updates:
12
+ # Python deps (project + dev + optional extras).
13
+ - package-ecosystem: "pip"
14
+ directory: "/"
15
+ schedule:
16
+ interval: "weekly"
17
+ day: "monday"
18
+ time: "07:00"
19
+ timezone: "America/Chicago"
20
+ open-pull-requests-limit: 5
21
+ groups:
22
+ # Pin all dev-tooling bumps into a single PR per week so the noise
23
+ # stays low. ruff / mypy / pyright / pytest move together anyway.
24
+ dev-tooling:
25
+ patterns:
26
+ - "ruff"
27
+ - "mypy"
28
+ - "pyright"
29
+ - "pytest*"
30
+ - "hypothesis"
31
+ - "syrupy"
32
+ - "pip-audit"
33
+ labels:
34
+ - "dependencies"
35
+ - "python"
36
+ commit-message:
37
+ prefix: "deps"
38
+ include: "scope"
39
+
40
+ # GitHub Actions versions used in ci.yml and release.yml.
41
+ - package-ecosystem: "github-actions"
42
+ directory: "/"
43
+ schedule:
44
+ interval: "weekly"
45
+ day: "monday"
46
+ open-pull-requests-limit: 3
47
+ labels:
48
+ - "dependencies"
49
+ - "github-actions"
50
+ commit-message:
51
+ prefix: "ci"
52
+ include: "scope"
@@ -0,0 +1,37 @@
1
+ <!--
2
+ Thanks for opening a PR.
3
+
4
+ Before submitting, please run:
5
+ pytest --no-cov
6
+ ruff check src tests
7
+ ruff format --check src tests
8
+
9
+ If the change touches the gate (policy.py, classify_command, secrets.py,
10
+ adapters/), add a test that exercises the new behavior. The audit-log
11
+ chain is the deliverable; if your change can break the chain shape,
12
+ mention it explicitly here.
13
+ -->
14
+
15
+ ## What this changes
16
+
17
+ A short description of what's different after this PR. The "why" matters
18
+ more than the "what"; the diff shows the what.
19
+
20
+ ## How it was tested
21
+
22
+ - [ ] `pytest --no-cov` passes locally
23
+ - [ ] `ruff check src tests` passes
24
+ - [ ] If you added a new tool-call risk pattern: a unit test in `test_classify_command.py` or `test_secrets.py` exercises it
25
+ - [ ] If you changed the audit-log event taxonomy: a test in `test_audit.py` exercises chain integrity across the new event type
26
+
27
+ ## Anything reviewers should know
28
+
29
+ Edge cases, dependencies on other in-flight PRs, things you're explicitly
30
+ not addressing in this PR but plan to follow up on.
31
+
32
+ ## Checklist
33
+
34
+ - [ ] Tests pass locally
35
+ - [ ] CHANGELOG.md `[Unreleased]` section updated if the change is user-facing
36
+ - [ ] README.md updated if the change adds a new CLI command or changes an existing one
37
+ - [ ] No em dashes in user-facing text
@@ -0,0 +1,66 @@
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
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install -e ".[dev]"
28
+
29
+ - name: Lint
30
+ run: ruff check src tests
31
+
32
+ - name: Format check
33
+ run: ruff format --check src tests
34
+
35
+ - name: Type-check (mypy)
36
+ run: mypy src/notari # blocking: strict is green and the py.typed marker promises it
37
+
38
+ - name: Test
39
+ run: pytest tests/ # enforces --cov-fail-under=75 from pyproject (currently ~82%)
40
+
41
+ - name: Audit dependencies
42
+ # Audit a frozen list that excludes the editable notari itself: its
43
+ # working version may not exist on PyPI yet (e.g. unreleased 0.3.0),
44
+ # which --strict treats as a hard error whether skipped or not.
45
+ # Every real dependency stays under --strict: a CVE fails the build.
46
+ run: |
47
+ pip freeze --exclude-editable > /tmp/audit-requirements.txt
48
+ pip-audit --strict --no-deps -r /tmp/audit-requirements.txt
49
+
50
+ build:
51
+ runs-on: ubuntu-latest
52
+ needs: test
53
+ steps:
54
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
55
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
56
+ with:
57
+ python-version: "3.12"
58
+ - name: Build sdist + wheel
59
+ run: |
60
+ pip install build
61
+ python -m build
62
+ - name: Upload artifacts
63
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
64
+ with:
65
+ name: dist
66
+ path: dist/
@@ -0,0 +1,57 @@
1
+ name: notari-change-control
2
+
3
+ # Gate every pull request: verify the diff against the human-approved contract
4
+ # (.notari/contract.json) and publish a Change Passport as a Status Check.
5
+ #
6
+ # ⚠ DOGFOOD CONFIGURATION: This workflow uses `uses: ./` and `install-from-source`
7
+ # because this repo IS the Notari source — we verify with HEAD's own code. A
8
+ # CONSUMER of Notari should NEVER do this; pin the release commit SHA instead
9
+ # (docs/secure-workflow.yml carries the current pin):
10
+ #
11
+ # uses: manumarri-sudo/notari@<full-release-commit-sha> # vX.Y.Z
12
+ #
13
+ # See README.md and docs/SECURITY-MODEL.md for the secure deployment checklist.
14
+ on:
15
+ pull_request:
16
+ branches: [main]
17
+
18
+ permissions:
19
+ contents: read
20
+ statuses: write # publish the commit Status Check
21
+ pull-requests: write # (reserved) post the passport as a PR comment
22
+
23
+ jobs:
24
+ change-control:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - name: Checkout (full history so the base commit is available)
28
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
29
+ with:
30
+ fetch-depth: 0
31
+
32
+ # No skip-on-missing-contract: the Action itself fails closed (exit 2)
33
+ # when no contract exists. Skipping was a fail-open: GitHub reports
34
+ # skipped jobs as successful, so a PR that deletes the contract would
35
+ # pass the required check.
36
+ - name: Notari Change Control
37
+ id: notari
38
+ # install-from-source: ONLY safe for the repo that owns the Action.
39
+ # Consumers pin a published tag so a PR cannot modify the gate.
40
+ uses: ./
41
+ with:
42
+ install-from-source: "true"
43
+ head: ${{ github.event.pull_request.head.sha }}
44
+ head-sha: ${{ github.event.pull_request.head.sha }}
45
+ fail-on-block: "true"
46
+ strict: "true"
47
+ gate-key: ${{ secrets.NOTARI_GATE_KEY }}
48
+ gate-pubkeys: ${{ vars.NOTARI_GATE_PUBKEYS }}
49
+ approver-pubkeys: ${{ secrets.NOTARI_APPROVER_PUBKEYS }}
50
+ # Dogfood without a gate key: accept report-grade unsigned evidence.
51
+ allow-unsigned-evidence: "true"
52
+ # Dogfood: this repo uses pull_request + install-from-source because it
53
+ # IS the Notari source. Consumers MUST use pull_request_target instead.
54
+ allow-pull-request-trigger: "true"
55
+
56
+ - name: Report verdict
57
+ run: echo "Notari verdict was ${{ steps.notari.outputs.verdict }}"
@@ -0,0 +1,71 @@
1
+ name: release
2
+
3
+ # Auto-publishes to PyPI when a GitHub release is published. Uses PyPI
4
+ # Trusted Publishing (OIDC) so no API token lives in repo secrets. One-time
5
+ # setup required on the PyPI side: register manumarri-sudo/notari as a
6
+ # trusted publisher for the `notari` project with workflow `release.yml`
7
+ # and environment `pypi`. The PyPI dist is `notari` because `notari` was
8
+ # taken; the package, CLI binary, and config dir all remain `notari`. See:
9
+ # https://docs.pypi.org/trusted-publishers/
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ jobs:
16
+ build-and-publish:
17
+ runs-on: ubuntu-latest
18
+ environment:
19
+ name: pypi
20
+ url: https://pypi.org/p/notari
21
+ permissions:
22
+ # Required for Trusted Publishing OIDC token exchange.
23
+ id-token: write
24
+ # Required to attach SBOM / attestations to the release.
25
+ contents: write
26
+ attestations: write
27
+
28
+ steps:
29
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
30
+ with:
31
+ fetch-depth: 0
32
+
33
+ - name: Set up Python
34
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
35
+ with:
36
+ python-version: "3.12"
37
+
38
+ - name: Install build deps
39
+ run: |
40
+ python -m pip install --upgrade pip build twine
41
+
42
+ - name: Verify tag matches pyproject version
43
+ run: |
44
+ tag="${GITHUB_REF_NAME#v}"
45
+ pkg=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
46
+ if [ "$tag" != "$pkg" ]; then
47
+ echo "::error::tag $tag != pyproject version $pkg"
48
+ exit 1
49
+ fi
50
+ echo "tag and pyproject agree on version: $pkg"
51
+
52
+ - name: Build sdist + wheel
53
+ run: python -m build
54
+
55
+ - name: Twine check
56
+ run: twine check dist/*
57
+
58
+ - name: Publish to PyPI via Trusted Publishing
59
+ # Tolerated until PyPI Trusted Publishing is registered for `notari`.
60
+ # Without TP the OIDC handshake fails; once TP is in place this step
61
+ # publishes cleanly and `skip-existing: true` keeps re-runs idempotent.
62
+ continue-on-error: true
63
+ uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
64
+ with:
65
+ packages-dir: dist/
66
+ skip-existing: true
67
+
68
+ - name: Generate attestations
69
+ uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1
70
+ with:
71
+ subject-path: "dist/*"
@@ -0,0 +1,104 @@
1
+ # --- Python ---
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ *.egg
8
+ *.egg-info/
9
+ build/
10
+ dist/
11
+ wheels/
12
+ .eggs/
13
+ MANIFEST
14
+
15
+ # --- Virtualenvs ---
16
+ .venv/
17
+ venv/
18
+ env/
19
+ ENV/
20
+
21
+ # --- Tooling caches ---
22
+ .pytest_cache/
23
+ .ruff_cache/
24
+ .mypy_cache/
25
+ .pyright/
26
+ .tox/
27
+ .cache/
28
+ pytest-cache-files-*/
29
+
30
+ # --- Coverage ---
31
+ .coverage
32
+ .coverage.*
33
+ htmlcov/
34
+ coverage.xml
35
+ *.cover
36
+
37
+ # --- IDE / editor ---
38
+ .vscode/
39
+ .idea/
40
+ *.swp
41
+ *.swo
42
+ .DS_Store
43
+
44
+ # --- Notari runtime artifacts (NEVER commit) ---
45
+ # The signing key is per-installation and must never be checked in.
46
+ .notari/
47
+ ~/.notari/
48
+
49
+ # Audit logs are user data with timestamps; keep out of source control.
50
+ *.audit.log.jsonl
51
+ audit.log.jsonl
52
+
53
+ # Claude Code session logs - may contain transcripts / tokens; never commit.
54
+ .claude-logs/
55
+
56
+ # --- Local secrets ---
57
+ .env
58
+ .env.local
59
+ .env.*.local
60
+ *.key
61
+ *.pem
62
+ secrets.json
63
+
64
+ # --- Generated experiment artifacts ---
65
+ # The harness scripts are committed; the generated runs are not.
66
+ experiments/results/
67
+ experiments/results.zip
68
+
69
+ # --- OS ---
70
+ Thumbs.db
71
+ .DS_Store
72
+
73
+ # Local-only PDF renders of markdown launch material
74
+ web/pdfs/
75
+
76
+ # Internal strategy / research / critique drafts and their binary renders.
77
+ # Keep local; the public threat model lives at docs/SECURITY-MODEL.md.
78
+ docs/research/
79
+
80
+ # Internal launch / go-to-market / business material. Kept local, not public.
81
+ LAUNCH.md
82
+ docs/distribution.md
83
+ docs/marketing/messaging-guide.md
84
+ docs/marketing/coding-agent-incident-recovery.md
85
+ docs/marketing/engagement-terms-template.md
86
+ docs/marketing/substack-draft-disaster-to-deadline.md
87
+ docs/marketing/future-loomiq-saas/
88
+ docs/marketing/outreach/
89
+
90
+ # Internal experiment harness and backend infra (telemetry/analysis).
91
+ # The client-side telemetry code stays public at src/notari/telemetry.py.
92
+ experiments/
93
+ infra/
94
+
95
+ # marketing drafts: pre-pivot product positioning + compliance claims; kept
96
+ # local until a Change-Control-aligned rewrite (see FINISH-STATUS.md). Not shipped.
97
+ docs/marketing/
98
+
99
+ # Manus private research cache (screenshots + competitor notes); not shipped
100
+ research-screenshots/
101
+
102
+ # internal worklists (security findings + triage); kept local, not public
103
+ AUDIT-FIX-PLAN.md
104
+ FINISH-STATUS.md