release: dorian v1.0.1 — hardening, DX, interop + first real cross-PR catch#8
Conversation
…ASK-001)
dorian-vwp 1.0.0 is live on PyPI, but several user-facing docs still denied
the shipped release (pre-PyPI 'install from source until...' framing, an rc2
latest stamp, a PARTIAL pypi-trusted-publishing backlog item). For a tool
whose brand is verification, docs that refute their own release are
self-refuting. This corrects every live version/PyPI surface and adds a guard
test that scans them so the drift cannot regress.
- README.md: lead with 'pip install dorian-vwp'; source install demoted to a
secondary 'unreleased changes' option; roadmap line now says v1.0.0 is live.
- action/action.yml: stale install-input comment now states PyPI is the default.
- action/README.md: pre-PyPI wording replaced with live-PyPI reality; usage
example no longer overrides install: to a git spec (uses the dorian-vwp default).
- docs/ROADMAP_BACKLOG.md: pypi-trusted-publishing marked DONE.
- docs/BENCHMARK_CURRENT.md: version stamp rc2 -> 1.0.0; honesty disclaimer
('not a fresh benchmark claim') preserved, no fresh run fabricated.
- tests/test_version_sync.py: new test_no_stale_prepypi_or_rc_vocabulary_in_live_docs
scoped to the five live surfaces (archive/CHANGELOG provenance excluded).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the copy-paste "Try it in 30 seconds" block above the fold as the hero, point the Demo badge anchor at it, and label the illustrative /login "60-second aha" clearly. Add a black-box test asserting the Demo badge resolves to the runnable heading (not the illustrative one) so the first-click demo path can't silently rot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A C4 program `pytest:-pevil` / `pytest:--collect-only` reached pytest as an OPTION (-p/-c/--collect-only), not a file, because the file part was only checked for emptiness and repo-containment. Reject any nodeid whose file part is empty or starts with '-' as ERROR(bad_program) before .resolve() and before any subprocess spawn. Red-green test asserts the three option-like nodeids ERROR with zero subprocess spawns; legitimate nodeids are unaffected (file parts never start with '-'). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One documented, independently-reproduced cross-PR catch on a public repo (encode/httpx, BSD-3): a load-bearing config-value claim sealed at commit A (requires-python ">=3.8") is flipped WARRANTED->REVOKED (exit 4) by a real later upstream PR (#3592 "Drop Python 3.8 support", >=3.8 -> >=3.9) while httpx's own test suite stays green (no test references requires-python; the PR diff touches no test file) and no stateless per-PR bot would re-open commit A's claim. Fills the previously-empty Entries section of the ledger template; honest-scope caveats and full reproduction included. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cmd_verify rebuilt the whole-repo Python symbol-definer index 2x and the config-key index 3x per run, each a full git ls-files + AST/TOML/JSON walk. Both are pure functions of the repo tree, so build each ONCE at the top of cmd_verify and thread the precomputed copy through claim_watch_paths, ambiguous_symbol_mentions and ambiguous_config_mentions (extending the existing optional-`definers` pattern with a None sentinel for the non-git degrade path). Output is byte-identical: a call-count spy test pins each builder to <=1x per verify, and the existing watch/read-set/exit-code assertions (Tests A-D, test_verify) prove the verify result is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…TASK-014) Typed C5 reads are deliberately not deny-exec-gated (only shell: is), so a pathological reconcile query the read-only authorizer permits — e.g. an infinite recursive CTE (SQLITE_RECURSIVE is a read op) — could hang the process even under --deny-exec. Install a progress handler with a monotonic wall-clock deadline (_SQLITE_QUERY_TIMEOUT_S, 5s) that interrupts the query; a deadline interrupt is distinguished from a genuine bad query via a timed_out flag and surfaces as ERROR(query_timeout), never FAIL/PASS. The read-only authorizer is preserved. Red-green test: a recursive CTE ERRORs in well under the bound with the cap patched tiny. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Pin all 22 third-party `uses:` across the 5 workflows to immutable 40-char commit SHAs (each verified live via git ls-remote; none guessed), with a `# vX` comment so Dependabot can still bump them. - Add .github/workflows/security.yml: pip-audit (SCA, currently clean) + bandit (SAST). bandit is configured in [tool.bandit] to exclude exactly dorian's documented, policy-gated execution primitives (subprocess for C4/git, the gated C5 shell: path, read-only data-check SQL) with a reason per check; it still gates every other vulnerability class. - Add .github/dependabot.yml (github-actions + pip, weekly). - action/README.md: change the self-reference examples from the mutable `@main` to the released `@v1.0.0` tag so copy-pasting users get an immutable ref. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…K-017) Add `dorian export --in-toto <artifact>`: a pure, deterministic projection of a sealed .warrant into an in-toto v1 Statement carrying an experimental ClaimVerification predicate (warrant id, git ref, sealed-at, dorian version, claims + checker programs). No signing/DSSE, no network, no model, zero new deps. New module src/dorian/intoto.py; black-box tests pin the shape and byte-determinism. Documented as experimental interop in docs/ATTESTATION_INTEROP.md. Also corrects docs/REAL_CATCH_LOG.md: the warrant id is content-addressed and TAMPER-EVIDENT, but the body includes the seal timestamp, so a fresh seal of identical inputs yields a different id — what reproduces is the OUTCOME (exit 0 seal -> exit 4 REVOKED), not the id. (Caught by the docs dogfood; honesty fix.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WRITING_GOOD_CLAIMS.md: a claim is only as strong as its checker. Three worked good/bad pairs (string->py-const, symbol->py-signature, regex-> config-value), the gutted-body ceiling (a symbol:/py-signature: existence check stays VERIFIED when a body is gutted; only a C4 pytest:/C5 check flips it — trigger != truth), an authoring checklist, and a real `dorian bindings` adequacy-mismatch diagnostic. All program strings validated by running them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a prominent propose-vs-verify callout (the agent only PROPOSES claims; dorian verifies with deterministic checkers, no model at check time, and a failing checker refuses the seal), a runnable end-to-end example walkthrough with corrected real CLI output, and the bindings adequacy-mismatch teaching point. Example under examples/claude-code/ confirmed runnable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SECURITY_AND_SAFE_RUNNERS.md: one copy-paste recipe for untrusted fork PRs (pull_request + contents:read/pull-requests:write + checker_trust:base + deny_exec:true + fail_on:never), a prominent "this is policy, not a sandbox" section (checker_trust:base is a trust-ROOT control, not execution isolation), why never pull_request_target, a separate trusted-repo recipe, and the SHA-pin + pip-audit/bandit supply-chain note. Verified against action.yml/policy.py. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The protocol docs named candidate repos (httpx/click) and hand-authored claims, but the shipped run executed humanize + python-dotenv with a machine-derived (Chain-of-Verification) ground truth. Add an "Amendment (shipped)" banner + section recording the actually-executed repos/method (keeping the pre-registration text as the audit trail, since a guard test pins the candidate names), and rewrite bench/public/README.md to match. Honesty framing preserved: reproducibility/determinism on frozen SHAs, not validation; circular-ground-truth caveat kept. No benchmark numbers altered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`dorian suggest-claims <file.py>`: a zero-model C3 counterpart to
suggest-data-checks. Proposes symbol: claims for non-private top-level
defs/classes (ambiguous names skipped loudly) and py-const: claims for
module-level literal constants, RUNS each candidate against current source,
and emits only the ones that PASS — so the {"claims": [...]} fragment seals
unmodified (born-verifiable; pinned by a test that feeds the output to
`verify`). load_bearing defaults to false. Suggestions check existence/value,
not behavior (gutted-body ceiling documented). New module suggestclaims.py;
black-box tests; design note docs/design/SUGGEST_CLAIMS.md scopes the shipped
core and the deferred breadth (--since diff, py-signature/config-value/path)
gated on adoption demand per the launch plan.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surgical README pass around the hero loop + proof (no new headings, so the TOC/doc-sync guards stay green): - Upgrade the "We ran this on dorian itself" proof from a throwaway dogfood to the documented, reproducible public-repo cross-PR catch (encode/httpx #3592), linking docs/REAL_CATCH_LOG.md with honest scope. - Link docs/WRITING_GOOD_CLAIMS.md from the claim-authoring section and docs/SECURITY_AND_SAFE_RUNNERS.md from the executable-checker safety callout. - Add the two new commands to the command surface: `suggest-claims` (with docs/design/SUGGEST_CLAIMS.md) and `export --in-toto` (with docs/ATTESTATION_INTEROP.md). - Refresh the roadmap "real catches" item to reflect the first recorded catch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…015) The shipped public benchmark executes structural C3 only and is byte-deterministic on frozen SHAs. Document the plan to add executed C5 (deterministic, needs a data-bearing subject) and C4 (pytest subprocess, environment-dependent) cases, and why C4-in-a-public-benchmark is deferred: folding an environment-dependent verdict into a benchmark advertised as byte-deterministic would weaken the exact honesty property it exists to show. Deferred with evidence, not built flaky. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump dorian-vwp 1.0.0 -> 1.0.1 (pyproject + package __version__; CLI and the version-sync guard agree). Add release notes docs/releases/v1.0.1.md. A hardening/DX/interop patch on top of 1.0.0 — no breaking changes: - security: C4 leading-dash nodeid rejection; C5 sqlite reconcile per-query timeout; Actions pinned to SHAs + pip-audit/bandit + Dependabot - perf: build symbol/config indexes once per verify (byte-identical output) - features (additive, opt-in): `suggest-claims`, `export --in-toto` - docs: runnable hero demo + Demo badge; WRITING_GOOD_CLAIMS; safe-runners; Claude Code recipe; benchmark protocol reconciled - proof: docs/REAL_CATCH_LOG.md — one documented, reproducible cross-PR catch on encode/httpx (#3592) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 38 minutes and 10 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR releases dorian v1.0.1, adding two new CLI commands ( Changesdorian v1.0.1 Release
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as dorian CLI
participant suggestclaims as suggestclaims.suggest()
participant ast_parser as ast (Python file parser)
participant symbol_index as symbol_index (ambiguity filter)
participant c3_checker as C3 checker
User->>CLI: dorian suggest-claims app.py
CLI->>suggestclaims: repo, normalized URI
suggestclaims->>ast_parser: parse app.py for defs/literals
ast_parser-->>suggestclaims: candidate symbols and constants
suggestclaims->>symbol_index: filter ambiguous cross-file symbols
symbol_index-->>suggestclaims: unambiguous candidates
loop each candidate
suggestclaims->>c3_checker: probe candidate
c3_checker-->>suggestclaims: PASS or skip
end
suggestclaims-->>CLI: {claims: [...], skipped: [...]}
CLI-->>User: JSON fragment (+ optional --out file)
sequenceDiagram
participant User
participant CLI as dorian CLI
participant cmd_export
participant warrantio as warrant sidecar loader
participant intoto as intoto.warrant_to_statement()
User->>CLI: dorian export app.py --in-toto
CLI->>cmd_export: args (artifact, --in-toto)
cmd_export->>warrantio: verify sidecar exists, load warrant
warrantio-->>cmd_export: Warrant object
cmd_export->>intoto: warrant + dorian_version
intoto-->>cmd_export: in-toto v1 Statement dict
cmd_export-->>User: deterministic JSON (stdout)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (5)
.github/workflows/security.yml (2)
14-14: ⚡ Quick winDisable credential persistence for checkout in this PR-triggered workflow.
Line 14 uses default
persist-credentials: true; set it tofalseto avoid leavingGITHUB_TOKENin local git config for later steps.Suggested patch
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/security.yml at line 14, The actions/checkout action on line 14 is using the default persist-credentials setting which leaves the GITHUB_TOKEN in the local git config. Add the persist-credentials input parameter set to false to the checkout action step to disable credential persistence and prevent the GITHUB_TOKEN from being stored in git config for subsequent steps in the workflow.Source: Linters/SAST tools
21-21: ⚡ Quick winVerify
uvx pip-auditis auditing the project dependency set.Line 21 may run
pip-auditin an isolated tool environment. Please verify it is auditing the dependencies resolved byuv sync --all-extras; otherwise switch to a project-env invocation (e.g.,uv run ...) so SCA coverage matches the workflow intent.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/security.yml at line 21, The `uvx pip-audit` command on line 21 runs pip-audit in an isolated tool environment, which means it is not auditing the actual project dependencies resolved by `uv sync --all-extras`. Replace the `uvx pip-audit` invocation with `uv run pip-audit` to ensure that the security audit covers the project's dependency set as intended by the workflow..github/workflows/ci.yml (1)
16-16: ⚡ Quick winHarden checkout by disabling persisted credentials.
Line 16 should set
persist-credentials: falseto avoid persistingGITHUB_TOKENinto repo git config during CI.Suggested patch
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/ci.yml at line 16, The actions/checkout action on line 16 is missing the persist-credentials configuration option, which allows the GITHUB_TOKEN to be persisted in the git config during CI. Add a with section to the actions/checkout action and configure persist-credentials to false to prevent the GITHUB_TOKEN from being stored in the repository's git configuration.Source: Linters/SAST tools
.github/workflows/release-gate.yml (2)
34-37: Setpersist-credentials: falseon both checkout steps.Lines 34 and 53 currently persist the repository token for Git operations. Since this workflow executes project code (
pytest,python -m build), disabling credential persistence follows the principle of least privilege and prevents potential unauthorized Git operations by other steps.In actions/checkout v6, credentials are stored in a separate file rather than in
.git/config, butpersist-credentials: falseremains the recommended approach for workflows that don't require authenticated Git operations.Suggested hardening diff
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: ref: ${{ inputs.ref || github.ref }} fetch-depth: 0 + persist-credentials: falseAlso applies to: 53-56
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release-gate.yml around lines 34 - 37, Add persist-credentials: false to the with section of both checkout steps in the workflow (the actions/checkout step around line 34 and the one around line 53). This disables repository token persistence and follows the principle of least privilege since the workflow executes project code like pytest and python build commands that don't require authenticated Git operations.Source: Linters/SAST tools
38-39: Explicitly configuresetup-uvcache behavior for release gate determinism.Since this job validates releases destined for publication and attestation, relying on implicit cache defaults introduces unnecessary ambiguity. The default
enable-cache: autoenables caching on GitHub-hosted runners, which could interfere with reproducibility. Addenable-cache: "false"to ensure deterministic verification.Suggested change
- uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 - with: { python-version: "${{ matrix.python }}" } + with: + python-version: "${{ matrix.python }}" + enable-cache: "false"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release-gate.yml around lines 38 - 39, The setup-uv action in the release-gate workflow currently relies on implicit cache defaults which can compromise reproducibility. Add the explicit configuration enable-cache: "false" to the with block of the astral-sh/setup-uv action to ensure deterministic verification behavior and prevent cache-related interference with release validation and attestation processes.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/ATTESTATION_INTEROP.md`:
- Line 37: The dorianVersion field in the example JSON object is set to an
outdated version string. Update the dorianVersion value from "1.0.0" to "1.0.1"
to reflect the current patch release being documented.
In `@src/dorian/commands.py`:
- Around line 404-416: The issue is that removesuffix(".warrant") is applied
unconditionally to args.artifact before determining whether the user provided an
artifact name or a sidecar path. For an artifact named foo.warrant, this
incorrectly strips it to foo, resulting in a wrong sidecar lookup. Instead, only
apply removesuffix(".warrant") when the provided path is actually a sidecar file
(check if it ends in .warrant and corresponds to an actual file), otherwise use
args.artifact as-is for the artifact name. This way the correct sidecar path
artifact_uri + ".warrant" will be derived properly for all artifact names
including those that naturally end in .warrant.
In `@src/dorian/suggestclaims.py`:
- Around line 63-65: The current code uses read_text(encoding="utf-8") which
forces UTF-8 decoding and ignores PEP 263 encoding cookies in Python files.
Replace read_text(encoding="utf-8") with read_bytes() and pass the bytes
directly to ast.parse(). Since read_bytes() is used instead of read_text(),
UnicodeDecodeError will no longer be raised and should be removed from the
exception handler tuple, leaving only OSError and SyntaxError to catch.
In `@src/dorian/symbol_index.py`:
- Around line 204-210: The code has a vulnerability where when a precomputed
index is provided (definers is not None), it bypasses the error handling and
calls pyproject_script_definers on line 210, which internally calls
gitio.ls_files and can raise a GitError for non-git repos. Even though the
caller supplied a fallback value to avoid errors, the function still fails. Wrap
the pyproject_script_definers call in a try-except block to catch gitio.GitError
and return an empty dict on failure, ensuring both the python_symbol_definers
and pyproject_script_definers paths handle non-git repos gracefully.
In `@tests/test_intoto_export.py`:
- Around line 70-74: The determinism test calls cli.main() twice on lines 70 and
72 without checking if the commands succeeded, so two failed runs could still
produce identical output and pass the assertion. Add assertions to verify that
both cli.main() calls return a success indicator (typically exit code 0 or a
truthy value) before comparing the out1 and out2 outputs. This ensures the
export operations actually succeeded before validating byte-identical output.
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Line 16: The actions/checkout action on line 16 is missing the
persist-credentials configuration option, which allows the GITHUB_TOKEN to be
persisted in the git config during CI. Add a with section to the
actions/checkout action and configure persist-credentials to false to prevent
the GITHUB_TOKEN from being stored in the repository's git configuration.
In @.github/workflows/release-gate.yml:
- Around line 34-37: Add persist-credentials: false to the with section of both
checkout steps in the workflow (the actions/checkout step around line 34 and the
one around line 53). This disables repository token persistence and follows the
principle of least privilege since the workflow executes project code like
pytest and python build commands that don't require authenticated Git
operations.
- Around line 38-39: The setup-uv action in the release-gate workflow currently
relies on implicit cache defaults which can compromise reproducibility. Add the
explicit configuration enable-cache: "false" to the with block of the
astral-sh/setup-uv action to ensure deterministic verification behavior and
prevent cache-related interference with release validation and attestation
processes.
In @.github/workflows/security.yml:
- Line 14: The actions/checkout action on line 14 is using the default
persist-credentials setting which leaves the GITHUB_TOKEN in the local git
config. Add the persist-credentials input parameter set to false to the checkout
action step to disable credential persistence and prevent the GITHUB_TOKEN from
being stored in git config for subsequent steps in the workflow.
- Line 21: The `uvx pip-audit` command on line 21 runs pip-audit in an isolated
tool environment, which means it is not auditing the actual project dependencies
resolved by `uv sync --all-extras`. Replace the `uvx pip-audit` invocation with
`uv run pip-audit` to ensure that the security audit covers the project's
dependency set as intended by the workflow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 61f843d5-d350-45df-83db-59b69fa7a9a1
📒 Files selected for processing (38)
.github/dependabot.yml.github/workflows/ci.yml.github/workflows/public-microbench.yml.github/workflows/publish-testpypi.yml.github/workflows/publish.yml.github/workflows/release-gate.yml.github/workflows/security.ymlREADME.mdaction/README.mdaction/action.ymlbench/public/README.mddocs/ATTESTATION_INTEROP.mddocs/BENCHMARK_CURRENT.mddocs/PUBLIC_BENCHMARK_PROTOCOL.mddocs/REAL_CATCH_LOG.mddocs/ROADMAP_BACKLOG.mddocs/SECURITY_AND_SAFE_RUNNERS.mddocs/USE_WITH_CLAUDE_CODE.mddocs/WRITING_GOOD_CLAIMS.mddocs/design/BENCHMARK_C4_C5.mddocs/design/SUGGEST_CLAIMS.mddocs/releases/v1.0.1.mdpyproject.tomlsrc/dorian/__init__.pysrc/dorian/checkers/c4_test.pysrc/dorian/checkers/c5_data.pysrc/dorian/cli.pysrc/dorian/commands.pysrc/dorian/intoto.pysrc/dorian/suggestclaims.pysrc/dorian/symbol_index.pytests/test_c4.pytests/test_c5.pytests/test_intoto_export.pytests/test_readme_example.pytests/test_suggest_claims.pytests/test_symbol_index.pytests/test_version_sync.py
| "predicate": { | ||
| "warrantId": "sha256:...", | ||
| "specVersion": "...", | ||
| "dorianVersion": "1.0.0", |
There was a problem hiding this comment.
Update the example dorianVersion to match this release.
Line 37 still shows 1.0.0; this patch release is 1.0.1, so the sample is stale.
Suggested fix
- "dorianVersion": "1.0.0",
+ "dorianVersion": "1.0.1",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "dorianVersion": "1.0.0", | |
| "dorianVersion": "1.0.1", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/ATTESTATION_INTEROP.md` at line 37, The dorianVersion field in the
example JSON object is set to an outdated version string. Update the
dorianVersion value from "1.0.0" to "1.0.1" to reflect the current patch release
being documented.
| raw = args.artifact.removesuffix(".warrant") # accept the artifact or its sidecar path | ||
| try: | ||
| artifact_uri = _artifact_uri(repo, raw) | ||
| except ValueError as exc: | ||
| print(f"dorian export: {exc}", file=sys.stderr) | ||
| return EXIT_USAGE | ||
| sidecar = repo / (artifact_uri + ".warrant") | ||
| if not sidecar.is_file(): | ||
| print( | ||
| f"dorian export: no warrant for {artifact_uri!r} (expected {sidecar.name})", | ||
| file=sys.stderr, | ||
| ) | ||
| return EXIT_USAGE |
There was a problem hiding this comment.
Don’t strip .warrant before checking the artifact sidecar.
Line 404 treats any artifact whose real filename ends in .warrant as if the user supplied its sidecar. For an artifact like foo.warrant, the valid sidecar is foo.warrant.warrant, but this code looks for or loads foo.warrant instead.
🐛 Suggested fix
- raw = args.artifact.removesuffix(".warrant") # accept the artifact or its sidecar path
try:
- artifact_uri = _artifact_uri(repo, raw)
+ input_uri = _artifact_uri(repo, args.artifact)
except ValueError as exc:
print(f"dorian export: {exc}", file=sys.stderr)
return EXIT_USAGE
- sidecar = repo / (artifact_uri + ".warrant")
+ artifact_sidecar = repo / (input_uri + ".warrant")
+ if artifact_sidecar.is_file():
+ artifact_uri = input_uri
+ sidecar = artifact_sidecar
+ else:
+ artifact_uri = input_uri.removesuffix(".warrant")
+ sidecar = repo / (artifact_uri + ".warrant")
if not sidecar.is_file():🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/dorian/commands.py` around lines 404 - 416, The issue is that
removesuffix(".warrant") is applied unconditionally to args.artifact before
determining whether the user provided an artifact name or a sidecar path. For an
artifact named foo.warrant, this incorrectly strips it to foo, resulting in a
wrong sidecar lookup. Instead, only apply removesuffix(".warrant") when the
provided path is actually a sidecar file (check if it ends in .warrant and
corresponds to an actual file), otherwise use args.artifact as-is for the
artifact name. This way the correct sidecar path artifact_uri + ".warrant" will
be derived properly for all artifact names including those that naturally end in
.warrant.
| tree = ast.parse(p.read_text(encoding="utf-8")) | ||
| except (OSError, UnicodeDecodeError, SyntaxError) as exc: | ||
| raise ValueError(f"unparseable python: {path}: {exc}") from None |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether the repo contains .py files with non-UTF8 declared encodings.
python - <<'PY'
import pathlib, tokenize
for p in pathlib.Path('.').rglob('*.py'):
try:
with p.open('rb') as f:
enc, _ = tokenize.detect_encoding(f.readline)
if enc.lower() not in ('utf-8', 'utf8'):
print(f"{p}\t{enc}")
except Exception:
pass
PYRepository: ajaysurya1221/dorian
Length of output: 46
🏁 Script executed:
cat -n src/dorian/suggestclaims.py | sed -n '55,75p'Repository: ajaysurya1221/dorian
Length of output: 1107
🏁 Script executed:
python - <<'PY'
import ast
import tempfile
import pathlib
# Test 1: Verify ast.parse handles PEP 263 with bytes
test_code_with_encoding = b"""# -*- coding: iso-8859-1 -*-
print('hello')
"""
try:
tree = ast.parse(test_code_with_encoding)
print("✓ ast.parse(bytes) with PEP 263 cookie: SUCCESS")
except Exception as e:
print(f"✗ ast.parse(bytes) with PEP 263 cookie: {type(e).__name__}: {e}")
# Test 2: Verify what exceptions are raised with invalid encoding
test_code_invalid = b"""# -*- coding: invalid-encoding -*-
print('hello')
"""
try:
tree = ast.parse(test_code_invalid)
print("✓ ast.parse(bytes) with invalid encoding: SUCCESS")
except Exception as e:
print(f"✗ ast.parse(bytes) with invalid encoding: {type(e).__name__}: {e}")
# Test 3: Verify UnicodeDecodeError with read_text(encoding='utf-8') on non-UTF8 content
try:
# Simulate ISO-8859-1 encoded file
iso_content = "café".encode('iso-8859-1')
iso_content.decode('utf-8')
except UnicodeDecodeError as e:
print(f"✓ UnicodeDecodeError occurs with mismatched encoding: {type(e).__name__}")
PYRepository: ajaysurya1221/dorian
Length of output: 295
Use bytes input to ast.parse() for proper PEP 263 encoding cookie handling.
The current code forces UTF-8 decoding via read_text(encoding="utf-8"), which rejects valid .py files declaring other encodings via PEP 263 cookies. Passing bytes directly to ast.parse() respects encoding declarations, making the code more robust. Additionally, UnicodeDecodeError becomes unreachable when using read_bytes().
Suggested fix
- try:
- tree = ast.parse(p.read_text(encoding="utf-8"))
- except (OSError, UnicodeDecodeError, SyntaxError) as exc:
+ try:
+ tree = ast.parse(p.read_bytes())
+ except (OSError, SyntaxError) as exc:
raise ValueError(f"unparseable python: {path}: {exc}") from None🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/dorian/suggestclaims.py` around lines 63 - 65, The current code uses
read_text(encoding="utf-8") which forces UTF-8 decoding and ignores PEP 263
encoding cookies in Python files. Replace read_text(encoding="utf-8") with
read_bytes() and pass the bytes directly to ast.parse(). Since read_bytes() is
used instead of read_text(), UnicodeDecodeError will no longer be raised and
should be removed from the exception handler tuple, leaving only OSError and
SyntaxError to catch.
| if definers is None: | ||
| try: | ||
| definers = python_symbol_definers(repo) | ||
| except gitio.GitError: | ||
| return {} | ||
| index = definers | ||
| scripts = pyproject_script_definers(repo, index) # console-script name -> target file |
There was a problem hiding this comment.
Keep the optional-index path non-fatal for non-git repos.
Line 210 still calls pyproject_script_definers, which calls gitio.ls_files. If a caller supplies a precomputed fallback like {} after python_symbol_definers failed, the new definers is not None path bypasses the guard on Lines 204-208 and can raise instead of returning {}.
🛡️ Suggested fix
- scripts = pyproject_script_definers(repo, index) # console-script name -> target file
+ try:
+ scripts = pyproject_script_definers(repo, index) # console-script name -> target file
+ except gitio.GitError:
+ scripts = {}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if definers is None: | |
| try: | |
| definers = python_symbol_definers(repo) | |
| except gitio.GitError: | |
| return {} | |
| index = definers | |
| scripts = pyproject_script_definers(repo, index) # console-script name -> target file | |
| if definers is None: | |
| try: | |
| definers = python_symbol_definers(repo) | |
| except gitio.GitError: | |
| return {} | |
| index = definers | |
| try: | |
| scripts = pyproject_script_definers(repo, index) # console-script name -> target file | |
| except gitio.GitError: | |
| scripts = {} |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/dorian/symbol_index.py` around lines 204 - 210, The code has a
vulnerability where when a precomputed index is provided (definers is not None),
it bypasses the error handling and calls pyproject_script_definers on line 210,
which internally calls gitio.ls_files and can raise a GitError for non-git
repos. Even though the caller supplied a fallback value to avoid errors, the
function still fails. Wrap the pyproject_script_definers call in a try-except
block to catch gitio.GitError and return an empty dict on failure, ensuring both
the python_symbol_definers and pyproject_script_definers paths handle non-git
repos gracefully.
| cli.main(["--repo", str(repo), "export", "note.md", "--in-toto"]) | ||
| out1 = capsys.readouterr().out | ||
| cli.main(["--repo", str(repo), "export", "note.md", "--in-toto"]) | ||
| out2 = capsys.readouterr().out | ||
| assert out1 == out2 # same warrant -> byte-identical statement |
There was a problem hiding this comment.
Assert export succeeds in the determinism test before comparing bytes.
Lines 70 and 72 currently ignore the CLI exit code, so two failed runs can still satisfy out1 == out2.
Suggested fix
- cli.main(["--repo", str(repo), "export", "note.md", "--in-toto"])
+ assert cli.main(["--repo", str(repo), "export", "note.md", "--in-toto"]) == 0
out1 = capsys.readouterr().out
- cli.main(["--repo", str(repo), "export", "note.md", "--in-toto"])
+ assert cli.main(["--repo", str(repo), "export", "note.md", "--in-toto"]) == 0
out2 = capsys.readouterr().out🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/test_intoto_export.py` around lines 70 - 74, The determinism test calls
cli.main() twice on lines 70 and 72 without checking if the commands succeeded,
so two failed runs could still produce identical output and pass the assertion.
Add assertions to verify that both cli.main() calls return a success indicator
(typically exit code 0 or a truthy value) before comparing the out1 and out2
outputs. This ensures the export operations actually succeeded before validating
byte-identical output.
…anged) The version-coupled guard (test_benchmark_evidence) requires the current- benchmark doc to stamp the live package version. Bumping to 1.0.1 added real checker-source changes (C4 leading-dash rejection, C5 reconcile timeout, the byte-identical index-once verify refactor) plus two additive commands, so the stamp could not just be bumped: both headline suites were RE-RUN at 1.0.1 and reproduce the metric-commit figures exactly — large-mutation P=R=0.93 / FP reduction 11.6x, and binding-lifecycle to the same content-derived run_id 168b50d9aa631d52 (byte-identical). Doc updated to disclose the 1.0.1 checker changes and the re-confirmation; the historical 0.9.0 binding-lifecycle doc was regenerated by the rerun and restored from git as it instructs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Patch release on top of v1.0.0 (origin/main's tree == v1.0.0; this branch adds 16 commits). No breaking changes — additive only.
Headline: first documented real catch
docs/REAL_CATCH_LOG.md— one reproducible cross-PR catch on a public repo (encode/httpx, BSD-3): a load-bearing claim sealed whenrequires-pythonwas">=3.8"flipsWARRANTED → REVOKED(exit 4) under a real later upstream PR (#3592, "Drop Python 3.8 support") while httpx's own tests stay green and no stateless per-PR review would re-open the claim. One documented catch, honest scope — not a validation claim.Security
pytest:nodeids (-pevil/--collect-only) before any spawn (red/green).reconcile:by a per-query timeout →ERROR(query_timeout), closing a DoS that survived--deny-exec(red/green).security.yml(pip-audit + bandit) and Dependabot.Performance
verify(byte-identical output, spy-tested).Features (additive, opt-in)
dorian suggest-claims <file.py>— deterministic, born-verifiable C3 claim scaffolding.dorian export --in-toto <artifact>— experimental in-totoClaimVerificationpredicate.Docs / DX
WRITING_GOOD_CLAIMS.md(gutted-body ceiling);SECURITY_AND_SAFE_RUNNERS.md; sharpened Claude Code recipe; public benchmark protocol reconciled with what shipped.Gates
ruff check+ruff format --checkclean; 867 tests pass (full suite, exit 0).Honesty notes preserved throughout: reproducibility on frozen SHAs ≠ validation; trigger ≠ truth; ERROR ≠ BROKEN;
--deny-exec/checker_trust: baseare policies, not sandboxes; the warrant id is tamper-evident but timestamped (not reproducible). PyPI publishing is a separate step.🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes: v1.0.1
New Features
dorian suggest-claimscommand to generate deterministic C3 claim suggestions from Python files.dorian export --in-totocommand for experimental in-toto Statement interoperability.Bug Fixes
Documentation
Chores