Repository navigation
feat(antd, sdks): SHA-256 on uploads and manifests; ant-core 0.14.0 - #347
Conversation
…ies (V2-1564) WIP: SDK stubs and docs follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…them (V2-1564) Swift, Elixir, Python, Dart and Ruby stubs regenerated on Linux with each script's pinned tools; only data/files/upload change. Kotlin proto copies synced. OpenAPI and llms docs gain the sha256 fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…6 work This keeps the SHA-256 work stacked on V2-1570, which now sits on the pointer API (#326). The merge had no conflicts. The ant-core dev pin below still applies to the whole tree, so the pointer code is built against it here as well. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ds (V2-1564) The sha256 fields added to data.proto, files.proto and upload.proto were regenerated for the other SDKs, but not in antd-rust's committed generated code, so its proto drift test failed (Check (antd-rust)). Regenerated with `ANTD_REGEN_PROTO=1 cargo test --test proto_drift`, using protoc 25.3. The only change is the `sha256` field on PutPublicDataResponse, PutDataResponse, FinalizeUploadResponse, PutFileResponse and PutFilePublicResponse. The gRPC mock server in grpc_tests.rs builds those responses as struct literals, so they now set `sha256: String::new()`. antd-rust's models don't expose sha256 yet. That's part of the open "other SDKs read sha256" follow-up. fmt, clippy -D warnings, cargo doc and cargo test (154 lib tests plus the drift test) are clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings up #325's final ant-cli-v0.3.11 repin via #326 and #346. antd/Cargo.toml and antd/Cargo.lock conflicted on the ant-core and ant-protocol pins; both keep this branch's side, the DEV PIN on WithAutonomi/ant-client#229 with its ant-protocol [patch], because the SHA-256 change needs #229 and ships with it. No other conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hermes review handoff — ant-sdk #347Review record: Linked Linear ticket: V2-1564. The PR head was read again before posting and still matches the reviewed revision. Required whole-PR panel coverage remains incomplete; this post is not approval. Posting-time upstream check: ant-client#229 is OPEN at WithAutonomi/ant-sdk #347 — bounded reviewRecommendation: HOLD — DO NOT MERGE; disclosed release gates and incomplete panel. This is an advisory review comment, not a formal GitHub APPROVE/REQUEST_CHANGES review or permission to merge.
Feature reviewAt the reviewed development pin, the SHA-256 value is propagated through the daemon's upload responses over REST/gRPC and the Go typed client, and recorded/reported on manifest entries. Local tests pass, including manifest and hash round-trips. No new blocking implementation defect was confirmed in this delta. This is not a whole-SDK feature-parity claim: the PR explicitly excludes non-Go hand-written REST client models; generated fields do not establish that Rust/Python or other typed clients return the new value. Hard release gates
Source: Lines 1 to 35 in 10dc29b Explicit limits
Execution and CI evidence
Actual original panel participationThe design was two independent roles (correctness and adversarial) for each of GLM 5.3/OpenRouter, local Qwen 3.8 27B, and local DS4 Flash. Production evidence was split into complete named scopes, so a role/model required multiple receipts to cover a whole PR. A receipt is not an extra independent model.
UNCERTAIN is unresolved, not approval. Missing, truncated and timed-out seats do not agree. These counts include complete UNCERTAIN opinions and therefore do not mean complete substantive sign-off. No whole-PR six-seat consensus exists. Recommendations without a verified defect remain provisional. Scope-by-scope receipts
Changed-file scope and classification manifest{
"pr": 347,
"head": "10dc29b4f0eba65273f99cb75e4e95b818024498",
"base": "4cf292a4761fe07e0db82ba270c177382a4ef7b5",
"changed_file_count": 52,
"files": [
{
"path": "antd-dart/lib/src/generated/antd/v1/data.pb.dart",
"classification": "generated",
"scope": null
},
{
"path": "antd-dart/lib/src/generated/antd/v1/data.pbjson.dart",
"classification": "generated",
"scope": null
},
{
"path": "antd-dart/lib/src/generated/antd/v1/files.pb.dart",
"classification": "generated",
"scope": null
},
{
"path": "antd-dart/lib/src/generated/antd/v1/files.pbjson.dart",
"classification": "generated",
"scope": null
},
{
"path": "antd-dart/lib/src/generated/antd/v1/upload.pb.dart",
"classification": "generated",
"scope": null
},
{
"path": "antd-dart/lib/src/generated/antd/v1/upload.pbjson.dart",
"classification": "generated",
"scope": null
},
{
"path": "antd-elixir/lib/antd/v1/data.pb.ex",
"classification": "generated",
"scope": null
},
{
"path": "antd-elixir/lib/antd/v1/files.pb.ex",
"classification": "generated",
"scope": null
},
{
"path": "antd-elixir/lib/antd/v1/upload.pb.ex",
"classification": "generated",
"scope": null
},
{
"path": "antd-go/client.go",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-go/client_test.go",
"classification": "tests",
"scope": null
},
{
"path": "antd-go/grpc_client.go",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-go/grpc_client_test.go",
"classification": "tests",
"scope": null
},
{
"path": "antd-go/manifest.go",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-go/manifest_test.go",
"classification": "tests",
"scope": null
},
{
"path": "antd-go/models.go",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-go/proto/antd/v1/data.pb.go",
"classification": "generated",
"scope": null
},
{
"path": "antd-go/proto/antd/v1/files.pb.go",
"classification": "generated",
"scope": null
},
{
"path": "antd-go/proto/antd/v1/manifests.pb.go",
"classification": "generated",
"scope": null
},
{
"path": "antd-go/proto/antd/v1/upload.pb.go",
"classification": "generated",
"scope": null
},
{
"path": "antd-kotlin/lib/src/main/proto/antd/v1/data.proto",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-kotlin/lib/src/main/proto/antd/v1/files.proto",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-kotlin/lib/src/main/proto/antd/v1/upload.proto",
"classification": "production",
"scope": "sha-go"
},
{
"path": "antd-py/src/antd/_proto/antd/v1/data_pb2.py",
"classification": "generated",
"scope": null
},
{
"path": "antd-py/src/antd/_proto/antd/v1/data_pb2.pyi",
"classification": "generated",
"scope": null
},
{
"path": "antd-py/src/antd/_proto/antd/v1/files_pb2.py",
"classification": "generated",
"scope": null
},
{
"path": "antd-py/src/antd/_proto/antd/v1/files_pb2.pyi",
"classification": "generated",
"scope": null
},
{
"path": "antd-py/src/antd/_proto/antd/v1/upload_pb2.py",
"classification": "generated",
"scope": null
},
{
"path": "antd-py/src/antd/_proto/antd/v1/upload_pb2.pyi",
"classification": "generated",
"scope": null
},
{
"path": "antd-ruby/lib/antd/v1/data_pb.rb",
"classification": "generated",
"scope": null
},
{
"path": "antd-ruby/lib/antd/v1/files_pb.rb",
"classification": "generated",
"scope": null
},
{
"path": "antd-ruby/lib/antd/v1/upload_pb.rb",
"classification": "generated",
"scope": null
},
{
"path": "antd-rust/src/generated/antd.v1.rs",
"classification": "generated",
"scope": null
},
{
"path": "antd-rust/src/grpc_tests.rs",
"classification": "tests",
"scope": null
},
{
"path": "antd-swift/Sources/AntdSdk/Proto/antd/v1/data.pb.swift",
"classification": "generated",
"scope": null
},
{
"path": "antd-swift/Sources/AntdSdk/Proto/antd/v1/files.pb.swift",
"classification": "generated",
"scope": null
},
{
"path": "antd-swift/Sources/AntdSdk/Proto/antd/v1/upload.pb.swift",
"classification": "generated",
"scope": null
},
{
"path": "antd/Cargo.lock",
"classification": "lock",
"scope": null
},
{
"path": "antd/Cargo.toml",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/openapi.yaml",
"classification": "docs",
"scope": null
},
{
"path": "antd/proto/antd/v1/data.proto",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/proto/antd/v1/files.proto",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/proto/antd/v1/manifests.proto",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/proto/antd/v1/upload.proto",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/grpc/service.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/manifests.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/rest/data.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/rest/files.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/rest/manifests.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/rest/upload.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "antd/src/types.rs",
"classification": "production",
"scope": "sha-server"
},
{
"path": "llms-full.txt",
"classification": "docs",
"scope": null
}
],
"scopes": [
{
"pr": 347,
"scope": "sha-server",
"head": "10dc29b4f0eba65273f99cb75e4e95b818024498",
"base": "4cf292a4761fe07e0db82ba270c177382a4ef7b5",
"evidence": "/Users/studio1/.hermes/cache/scratch/ant-sdk-review-evidence/347/panel-evidence/sha-server.txt",
"bytes": 34463,
"files": [
"antd/Cargo.toml",
"antd/proto/antd/v1/data.proto",
"antd/proto/antd/v1/files.proto",
"antd/proto/antd/v1/manifests.proto",
"antd/proto/antd/v1/upload.proto",
"antd/src/grpc/service.rs",
"antd/src/manifests.rs",
"antd/src/rest/data.rs",
"antd/src/rest/files.rs",
"antd/src/rest/manifests.rs",
"antd/src/rest/upload.rs",
"antd/src/types.rs"
]
},
{
"pr": 347,
"scope": "sha-go",
"head": "10dc29b4f0eba65273f99cb75e4e95b818024498",
"base": "4cf292a4761fe07e0db82ba270c177382a4ef7b5",
"evidence": "/Users/studio1/.hermes/cache/scratch/ant-sdk-review-evidence/347/panel-evidence/sha-go.txt",
"bytes": 14476,
"files": [
"antd-go/client.go",
"antd-go/grpc_client.go",
"antd-go/manifest.go",
"antd-go/models.go",
"antd-kotlin/lib/src/main/proto/antd/v1/data.proto",
"antd-kotlin/lib/src/main/proto/antd/v1/files.proto",
"antd-kotlin/lib/src/main/proto/antd/v1/upload.proto"
]
}
]
}Linear review comment: https://linear.app/autonominetwork/issue/V2-1564/ant-core-antd-sha-256-of-uploaded-content-computed-during-encryption#comment-e90784b9 |
# Conflicts: # llms-full.txt
ant-cli-v0.3.12 is the first ant-client release with the SHA-256 work (ant-client#229), so the dev pin on 2eace73 and the ant-protocol [patch.crates-io] go. ant-protocol moves to =5.0.1, ant-core's transitive version. Against main the lock changes only ant-core 0.13.0 -> 0.14.0, ant-protocol 5.0.0 -> 5.0.1, saorsa-core 0.29.1 -> 0.29.2, saorsa-transport 0.38.1 -> 0.38.2 and annotate-snippets 0.12.16 -> 0.12.17. The sha256 fields first ship in antd 0.17.0, not 0.16.0, so the antd-go and OpenAPI notes now say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…code The committed gRPC code missed the manifests.proto sha256 fields (ManifestEntryInput.sha256, ManifestEntryInfo.sha256), so proto_drift failed and the build broke on the new field. Regenerate it and carry sha256 through ManifestEntryInput (with_sha256) and ManifestEntryInfo over both REST and gRPC, unset on the wire when not given and None when the daemon sends none. The mock REST and gRPC build tests now cover it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Python, Ruby, Dart and Elixir via each SDK's regen script at its pinned generator versions; nothing outside manifests changes. Swift via the package's protoc-gen-swift, with the `nonisolated` modifiers that dev2's older plugin drops restored, so only the sha256 code changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaidSafe-Hermes
left a comment
There was a problem hiding this comment.
Review — APPROVE
No actionable defects found in the SHA-256 upload-response and manifest changes at this revision. The REST and gRPC upload/finalize handlers forward the hash returned by ant-core; manifest claims are validated, preserved as optional metadata, and exposed on decode. The source protobuf changes are additive, and the pinned ant-core uses named manifest serialization and verifies the recorded hash on extraction.
Coverage
2/2 seats reviewed (sol-1 gpt-6.1-sol xhigh; glm-1 z-ai/glm-5.3). sol-1 returned APPROVE. glm-1 returned UNCERTAIN; I checked its remaining concerns against the exact source and execution evidence rather than treating that as agreement. In particular, the suspected Rust serde-attribute placement is correct: each attribute precedes its sha256 field in antd-rust/src/manifests.rs:241-246,284-289; the SDK tests also compile and pass. The shared finalize path carries the result hash to both transports.
Validation and limits
- GitHub CI: applicable daemon, SDK, generated-proto drift and security checks completed successfully. Go race detection and Go security scanning were skipped.
cargo test --locked --manifest-path antd-rust/Cargo.toml: 170 unit tests and two live-manifest/pointer tests passed. The full command exited 101 becausetests/proto_drift.rscould not run withoutprotoc.cargo test --locked --manifest-path antd/Cargo.tomlcould not reach compilation/tests because the build script could not findprotoc.git diff --checkpassed.
This is a code-review verdict only; it does not authorize merge.
Ready for review. WithAutonomi/ant-client#229, which adds the SHA-256 in ant-core, shipped in ant-cli-v0.3.12 / ant-core 0.14.0 (2026-10-23). This PR now pins that release, and is the main content of antd 0.17.0; the version bump follows in a separate PR stacked on this one. Linear: V2-1564.
What
antd: repinned to
ant-cli-v0.3.12(ant-core 0.14.0), with ant-protocol=5.0.1. The dev pin on2eace73and the ant-protocol[patch.crates-io]are gone. Compared with main, the lock changes only:The repin also brings in ant-core 0.14's hot-record read spreading (ADR-0023, ant-client#225) and rustls 0.23.46 (ant-client#232).
antd, sha256 on uploads:
sha256(hex) is returned on the data, file and finalize upload responses, over REST and gRPC.antd, sha256 on manifests:
/v1/manifests/buildtakes an optionalsha256on each entry, and/v1/manifests/decodereturns it. The ADR-0006 owner approved it as an optional field within format version 1. A non-hex value, or one that isn't 32 bytes, is a 400.antd-go: the matching fields (
antd >= 0.17.0).antd-rust:
ManifestEntryInput::sha256/with_sha256andManifestEntryInfo::sha256, over REST and gRPC.proto_driftwas failing.Stubs:
nonisolated, so those modifiers are restored by hand.Docs: OpenAPI and the llms docs gain the
sha256fields.Not in this PR
sha256yet. Their generated gRPC stubs already carry it. This is a follow-up fan-out.Verified
Live devnet on dev2: an ant-node v0.23.1 devnet (small preset), with antd release-built from this branch.
POST /v1/dataand/v1/data/public(300 KB and 700 B), and/v1/filesand/v1/files/public(5 MB). Each returnedsha256equalssha256sumof the input.DataService.Put/PutPublicandFileService.Put, through the branch's Python stubs. Each hash matcheshashlib.sha256.resolve: trueand from its link. sha256 came back on the right entries and stayed absent on the no-hash one.antv0.3.12 binary:ant manifest downloadof the built manifest wrote all three files, and their hashes match.Local runs:
cargo fmt --check, clippy with-D warnings,cargo doc, andcargo test --locked(155 passed).-D warnings, andcargo test --locked --all-features, includingproto_drift.go vetandgo test.dev2, on the regenerated stubs: Python 584 passed, Ruby 212 runs with 0 failures, Dart 248 passed. Elixir's tests didn't run on dev2: OTP 25 there can't compile the locked cowlib. CI's proto-drift job checks the Elixir stubs.
🤖 Generated with Claude Code