ci: cargo deny workflow#775
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds cargo-deny as a CI workflow to audit dependencies for vulnerabilities and license compliance, addressing issue #761. The goal is to help identify vulnerable dependencies and maintain security best practices by adding automated dependency auditing to the continuous integration pipeline.
Changes:
- Added a new GitHub Actions workflow file for running cargo-deny security audits
- Added a cargo-deny configuration file (deny.toml) to control the audit behavior
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| .github/workflows/audit.yaml | New GitHub Actions workflow to run cargo-deny checks in CI |
| deny.toml | Configuration file for cargo-deny specifying rules for advisories, licenses, bans, and sources |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
2ae7415 to
28d9313
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a GitHub Actions "Security Audit" workflow to run cargo-deny on pushes/PRs to Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer
participant GH as GitHub Actions
participant Repo as Repository
participant Action as EmbarkStudios/cargo-deny-action
participant Tool as cargo-deny
Dev->>GH: Push / PR / Manual trigger / Cron
GH->>Repo: checkout repository
GH->>Action: execute with "check all"
Action->>Tool: run cargo-deny using `deny.toml`
Tool->>Action: return audit results
Action->>GH: report status and logs
GH->>Dev: surface status / logs
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan for PR comments
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 |
cf0d52a to
17e081d
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #775 +/- ##
===========================================
+ Coverage 68.87% 83.19% +14.32%
===========================================
Files 35 52 +17
Lines 4932 15153 +10221
===========================================
+ Hits 3397 12607 +9210
- Misses 1535 2546 +1011 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@deny.toml`:
- Around line 42-45: The deny.toml currently sets the audit metadata flag
all-features = false which skips feature-gated dependencies from being audited;
change the setting to all-features = true so Deny collects metadata with
--all-features and includes feature-gated/optional dependencies in vulnerability
scans (update the all-features key value from false to true).
- Around line 220-231: The lint settings currently set unknown-registry = "warn"
and unknown-git = "warn", which permits unknown sources to pass CI; change these
to "deny" to enforce stricter supply-chain security so builds fail on unapproved
registries or git repos, and verify allow-registry and allow-git contain the
intended approved entries (symbols: unknown-registry, unknown-git,
allow-registry, allow-git).
- Around line 136-138: The commented example in the registries array has a
missing closing quote in the URL string; update the registries example (the
registries = [...] line) so the commented URL is properly quoted (e.g., ensure
"https://sekretz.com/registry" is enclosed in both opening and closing quotes)
and keep it commented as shown.
- Around line 88-107: Add "CC0-1.0" to the allow list in deny.toml so cargo-deny
won’t fail for the bitcoin v0.32 dependency; locate the allow = [...] array (the
explicit allow list near the top of the file) and insert "CC0-1.0" alongside
"MIT" and "Apache-2.0" entries, keeping the existing formatting and commas.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/audit.yaml:
- Around line 14-25: The cargo-deny job should be hardened by pinning the used
actions to immutable commit SHAs and restricting job token permissions: replace
uses: actions/checkout@v4 and uses: EmbarkStudios/cargo-deny-action@v2 with
their corresponding commit SHA references, and add a permissions block under the
cargo-deny job (e.g., permissions: contents: read) to limit the GITHUB_TOKEN
scope to the minimum required for these steps; update the job definition named
cargo-deny and the two step entries (Checkout repository and Run cargo-deny)
accordingly.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Cargo.toml`:
- Line 22: Update the wallet recovery logic and add tests to guard against
serde_cbor_2 formatting changes: replace the fragile string check
format!("{e:?}").contains("code: TrailingData") in src/utill.rs (around the
wallet recovery path) with a robust match against the CBOR error type or variant
provided by serde_cbor_2 (e.g., inspect the error kind/variant instead of Debug
text) so detection does not depend on Debug formatting; then add regression
tests that simulate the trailing-data scenario for wallet deserialization (unit
tests near utill.rs or integration tests) to assert recovery still triggers with
serde_cbor_2, and run/verify that behavior with the updated dependency in
Cargo.toml.
| serde = { version = "1.0", features = ["derive"] } | ||
| serde_json = "1.0" | ||
| serde_cbor = "0.11.2" | ||
| serde_cbor = { package = "serde_cbor_2", version = "0.13" } |
There was a problem hiding this comment.
❓ Verification inconclusive
Script executed:
#!/bin/bash
set -euo pipefail
echo "== Cargo.toml context (lines around 22) =="
sed -n '15,30p' Cargo.toml
echo -e "\n== serde_cbor usage in runtime paths =="
rg -n 'serde_cbor::(Error|from_slice|to_writer|ser::to_vec)' src/ --no-heading -A2 -B2 || echo "No matches found"
echo -e "\n== TrailingData string matching =="
rg -n 'TrailingData|format!\("\{e:\?\}"\)|contains.*code.*TrailingData' src/ --no-heading -A3 -B1 || echo "No matches found"
echo -e "\n== All serde_cbor references =="
rg -n 'serde_cbor' src/ --no-heading -A1 || echo "No matches found"
echo -e "\n== Wallet-related test files =="
fd -t f 'test|spec' tests/ 2>/dev/null | head -20 || echo "No tests dir found"
echo -e "\n== utill.rs around the claimed lines 724-750 =="
wc -l src/utill.rs
if [ $(wc -l < src/utill.rs) -ge 750 ]; then
sed -n '720,760p' src/utill.rs
else
echo "File is smaller than 750 lines; showing full file"
wc -l src/utill.rs
fi
echo -e "\n== Check for Cargo.lock =="
if [ -f Cargo.lock ]; then
grep -A2 'name = "serde_cbor' Cargo.lock | head -20
fiRepository: citadel-tech/coinswap
Repository: citadel-tech/coinswap
Exit code: 0
stdout:
== Cargo.toml context (lines around 22) ==
keywords = ["bitcoin", "HTLC", "coinswap"]
[dependencies]
bip39 = { version = "2.1.0", features = ["rand"] }
bitcoin = "0.32"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_cbor = { package = "serde_cbor_2", version = "0.13" }
log = "^0.4"
dirs = "3.0.1"
socks = "0.3.4"
clap = { version = "4.5", features = ["derive"] }
bitcoind = "0.36"
log4rs = "1.3.0"
secp256k1 = {git = "https://github.com/jlest01/rust-secp256k1.git", branch = "musig2-module", features = ["rand", "global-context"]}
minreq = { version = "2.12.0", features = ["https"] }
== serde_cbor usage in runtime paths ==
src/watch_tower/watcher_error.rs-21- RPCError(bitcoind::bitcoincore_rpc::Error),
src/watch_tower/watcher_error.rs-22- /// Serialization/deserialization error for CBOR.
src/watch_tower/watcher_error.rs:23: SerdeCbor(serde_cbor::Error),
src/watch_tower/watcher_error.rs-24- /// WebSocket error from tungstenite
src/watch_tower/watcher_error.rs-25- WebSocket(tungstenite::Error),
--
src/watch_tower/watcher_error.rs-50-}
src/watch_tower/watcher_error.rs-51-
src/watch_tower/watcher_error.rs:52:impl From<serde_cbor::Error> for WatcherError {
src/watch_tower/watcher_error.rs:53: fn from(value: serde_cbor::Error) -> Self {
src/watch_tower/watcher_error.rs-54- Self::SerdeCbor(value)
src/watch_tower/watcher_error.rs-55- }
--
src/watch_tower/registry_storage.rs-64- match std::fs::read(&path) {
src/watch_tower/registry_storage.rs-65- Ok(bytes) => Arc::new(Mutex::new(
src/watch_tower/registry_storage.rs:66: serde_cbor::from_slice(&bytes).unwrap_or_default(),
src/watch_tower/registry_storage.rs-67- )),
src/watch_tower/registry_storage.rs-68- Err(e) => {
--
src/wallet/storage.rs-129-
src/wallet/storage.rs-130- // Write encrypted wallet data to disk.
src/wallet/storage.rs:131: serde_cbor::to_writer(writer, &encrypted)?;
src/wallet/storage.rs-132- }
src/wallet/storage.rs-133- None => {
src/wallet/storage.rs-134- // No encryption: serialize and write the wallet directly.
src/wallet/storage.rs:135: serde_cbor::to_writer(writer, &self)?;
src/wallet/storage.rs-136- }
src/wallet/storage.rs-137- }
--
src/utill.rs-208-) -> Result<(), NetError> {
src/utill.rs-209- let mut writer = BufWriter::new(socket_writer);
src/utill.rs:210: let msg_bytes = serde_cbor::ser::to_vec(message)?;
src/utill.rs-211- let msg_len = (msg_bytes.len() as u32).to_be_bytes();
src/utill.rs-212- let mut to_send = Vec::with_capacity(msg_bytes.len() + msg_len.len());
--
src/utill.rs-483- General(String),
src/utill.rs-484- /// Cbor error
src/utill.rs:485: Serde(serde_cbor::Error),
src/utill.rs-486-}
src/utill.rs-487-
--
src/utill.rs-492-}
src/utill.rs-493-
src/utill.rs:494:impl From<serde_cbor::Error> for TorError {
src/utill.rs:495: fn from(value: serde_cbor::Error) -> Self {
src/utill.rs-496- TorError::Serde(value)
src/utill.rs-497- }
--
src/utill.rs-713- fs::write(
src/utill.rs-714- &tor_config_path,
src/utill.rs:715: serde_cbor::ser::to_vec(&[private_key, hostname.clone()])?,
src/utill.rs-716- )?;
src/utill.rs-717-
--
src/utill.rs-722-
src/utill.rs-723-/// Deserialize any generic type from a CBOR file. The type should impl [serde::de::Deserialize].
src/utill.rs:724:pub fn deserialize_from_cbor<T>(mut reader: Vec<u8>) -> Result<T, serde_cbor::Error>
src/utill.rs-725-where
src/utill.rs-726- T: serde::de::DeserializeOwned,
src/utill.rs-727-{
src/utill.rs:728: match serde_cbor::from_slice::<T>(&reader) {
src/utill.rs-729- Ok(store) => Ok(store),
src/utill.rs-730- Err(e) => {
--
src/utill.rs-735- loop {
src/utill.rs-736- reader.pop();
src/utill.rs:737: match serde_cbor::from_slice::<T>(&reader) {
src/utill.rs-738- Ok(store) => break Ok(store),
src/utill.rs-739- Err(_) => continue,
--
src/utill.rs-1001- let (mut socket, _) = listener.accept().unwrap();
src/utill.rs-1002- let msg_bytes = read_message(&mut socket).unwrap();
src/utill.rs:1003: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes).unwrap();
src/utill.rs-1004-
src/utill.rs-1005- if let MakerToTakerMessage::MakerHello(hello) = msg {
--
src/wallet/error.rs-19- ///
src/wallet/error.rs-20- /// This is used for encoding/decoding data structures.
src/wallet/error.rs:21: Cbor(serde_cbor::Error),
src/wallet/error.rs-22-
src/wallet/error.rs-23- /// Represents an error during JSON serialization or deserialization.
--
src/wallet/error.rs-115- }
src/wallet/error.rs-116-}
src/wallet/error.rs:117:impl From<serde_cbor::Error> for WalletError {
src/wallet/error.rs:118: fn from(value: serde_cbor::Error) -> Self {
src/wallet/error.rs-119- Self::Cbor(value)
src/wallet/error.rs-120- }
--
src/security.rs-26-pub enum EncryptError {
src/security.rs-27- /// Error occurred during CBOR serialization of the input struct.
src/security.rs:28: Serialization(serde_cbor::Error),
src/security.rs-29- /// Error occurred during AES-GCM encryption.
src/security.rs-30- ///
--
src/security.rs-34-}
src/security.rs-35-
src/security.rs:36:impl From<serde_cbor::Error> for EncryptError {
src/security.rs:37: fn from(err: serde_cbor::Error) -> Self {
src/security.rs-38- EncryptError::Serialization(err)
src/security.rs-39- }
--
src/security.rs-90-
src/security.rs-91-impl SerdeFormat for SerdeCbor {
src/security.rs:92: type Error = serde_cbor::Error;
src/security.rs-93- fn from_slice<T: DeserializeOwned>(input: &[u8]) -> Result<T, Self::Error> {
src/security.rs-94- utill::deserialize_from_cbor::<T>(input.to_vec())
--
src/security.rs-222-///
src/security.rs-223-/// This function applies the following transformation pipeline:
src/security.rs:224:/// `Struct -> serde_cbor::ser::to_vec(Struct) -> AES-GCM(encrypted_bytes) = encrypted_payload -> EncryptedData { encrypted_payload, nonce }`
src/security.rs-225-///
src/security.rs-226-///
--
src/security.rs-236-) -> Result<EncryptedData, EncryptError> {
src/security.rs-237- // Serialize wallet data to bytes.
src/security.rs:238: let packed_store = serde_cbor::ser::to_vec(&plain_struct)?;
src/security.rs-239-
src/security.rs-240- // Extract nonce and key for AES-GCM.
--
src/security.rs-268- encrypted_struct: EncryptedData,
src/security.rs-269- enc_material: &KeyMaterial,
src/security.rs:270:) -> Result<T, serde_cbor::Error> {
src/security.rs-271- // Deserialize the outer EncryptedWalletStore wrapper.
src/security.rs-272-
--
src/taker/routines.rs-45- )?;
src/taker/routines.rs-46- let msg_bytes = read_message(socket)?;
src/taker/routines.rs:47: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-48-
src/taker/routines.rs-49- // Check that protocol version is always 1.
--
src/taker/routines.rs-108-
src/taker/routines.rs-109- let msg_bytes = read_message(socket)?;
src/taker/routines.rs:110: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-111- let contract_sigs_for_sender = match msg {
src/taker/routines.rs-112- MakerToTakerMessage::RespContractSigsForSender(m) => {
--
src/taker/routines.rs-163-
src/taker/routines.rs-164- let msg_bytes = read_message(socket)?;
src/taker/routines.rs:165: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-166- let contract_sigs_for_recvr = match msg {
src/taker/routines.rs-167- MakerToTakerMessage::RespContractSigsForRecvr(m) => {
--
src/taker/routines.rs-245- // Recv ContractSigsAsRecvrAndSender.
src/taker/routines.rs-246- let msg_bytes = read_message(socket)?;
src/taker/routines.rs:247: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-248- let contract_sigs_as_recvr_and_sender = match msg {
src/taker/routines.rs-249- MakerToTakerMessage::ReqContractSigsAsRecvrAndSender(m) => {
--
src/taker/routines.rs-383-
src/taker/routines.rs-384- let msg_bytes = read_message(socket)?;
src/taker/routines.rs:385: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-386- let privkey_handover = match msg {
src/taker/routines.rs-387- MakerToTakerMessage::RespPrivKeyHandover(m) => {
--
src/taker/offers.rs-742-
src/taker/offers.rs-743- let msg_bytes = read_message(&mut socket)?;
src/taker/offers.rs:744: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/offers.rs-745- let offer = match msg {
src/taker/offers.rs-746- MakerToTakerMessage::RespOffer(offer) => offer,
--
src/taker/offers.rs-776- let response_bytes = read_message(&mut socket)?;
src/taker/offers.rs-777-
src/taker/offers.rs:778: let response: messages2::MakerToTakerMessage = serde_cbor::from_slice(&response_bytes)?;
src/taker/offers.rs-779-
src/taker/offers.rs-780- let taproot_offer = match response {
--
src/taker/error.rs-49-}
src/taker/error.rs-50-
src/taker/error.rs:51:impl From<serde_cbor::Error> for TakerError {
src/taker/error.rs:52: fn from(value: serde_cbor::Error) -> Self {
src/taker/error.rs-53- Self::Deserialize(value.to_string())
src/taker/error.rs-54- }
--
src/error.rs-22- /// Error related to CBOR (Concise Binary Object Representation) serialization or deserialization.
src/error.rs-23- ///
src/error.rs:24: /// This variant wraps a [`serde_cbor::Error`] to provide details about the issue.
src/error.rs:25: Cbor(serde_cbor::Error),
src/error.rs-26-
src/error.rs-27- /// Error indicating an invalid CLI application network.
--
src/error.rs-47-}
src/error.rs-48-
src/error.rs:49:impl From<serde_cbor::Error> for NetError {
src/error.rs:50: fn from(value: serde_cbor::Error) -> Self {
src/error.rs-51- Self::Cbor(value)
src/error.rs-52- }
--
src/maker/server.rs-373- }
src/maker/server.rs-374- }
src/maker/server.rs:375: let taker_msg = serde_cbor::from_slice::<TakerToMakerMessage>(&bytes)?;
src/maker/server.rs-376-
src/maker/server.rs-377- log::info!("[{}] <=== {}", maker.config.network_port, taker_msg);
--
src/taker/api2.rs-829- // Read response
src/taker/api2.rs-830- let response_bytes = read_message(&mut socket)?;
src/taker/api2.rs:831: let response: MakerToTakerMessage = serde_cbor::from_slice(&response_bytes)?;
src/taker/api2.rs-832- log::info!("<=== {} | {maker_addr}", response);
src/taker/api2.rs-833-
--
src/maker/server2.rs-436- ip
src/maker/server2.rs-437- );
src/maker/server2.rs:438: let message = match serde_cbor::from_slice::<TakerToMakerMessage>(&message_bytes) {
src/maker/server2.rs-439- Ok(msg) => {
src/maker/server2.rs-440- log::info!("[{}] <=== {}", maker.config.network_port, msg);
--
src/maker/error.rs-60-}
src/maker/error.rs-61-
src/maker/error.rs:62:impl From<serde_cbor::Error> for MakerError {
src/maker/error.rs:63: fn from(value: serde_cbor::Error) -> Self {
src/maker/error.rs-64- Self::Net(NetError::Cbor(value))
src/maker/error.rs-65- }
--
src/maker/rpc/server.rs-29-fn handle_request<M: MakerRpc>(maker: &Arc<M>, socket: &mut TcpStream) -> Result<(), MakerError> {
src/maker/rpc/server.rs-30- let msg_bytes = read_message(socket)?;
src/maker/rpc/server.rs:31: let rpc_request: RpcMsgReq = serde_cbor::from_slice(&msg_bytes)?;
src/maker/rpc/server.rs-32- log::info!("RPC request received: {rpc_request:?}");
src/maker/rpc/server.rs-33-
--
src/wallet/ffi.rs-116- // If it succeeds, the wallet is encrypted
src/wallet/ffi.rs-117- // If it fails, the wallet is plaintext
src/wallet/ffi.rs:118: match serde_cbor::from_slice::<crate::security::EncryptedData>(&content) {
src/wallet/ffi.rs-119- Ok(_) => Ok(true), // Successfully parsed as EncryptedData = encrypted
src/wallet/ffi.rs-120- Err(_) => Ok(false), // Failed to parse as EncryptedData = plaintext
== TrailingData string matching ==
src/utill.rs-730- Err(e) => {
src/utill.rs:731: let err_string = format!("{e:?}");
src/utill.rs:732: if err_string.contains("code: TrailingData") {
src/utill.rs-733- // Defensive error handling - monitor logs to confirm wallet files stay clean.
src/utill.rs-734- log::info!("Wallet file has trailing data, trying to restore");
src/utill.rs-735- loop {
--
src/maker/rpc/server.rs-182- if let Err(e) =
src/maker/rpc/server.rs:183: send_message(&mut stream, &RpcMsgResp::ServerError(format!("{e:?}")))
src/maker/rpc/server.rs-184- {
src/maker/rpc/server.rs-185- log::error!("Error sending RPC response {e:?}");
src/maker/rpc/server.rs-186- };
== All serde_cbor references ==
src/watch_tower/watcher_error.rs:23: SerdeCbor(serde_cbor::Error),
src/watch_tower/watcher_error.rs-24- /// WebSocket error from tungstenite
--
src/watch_tower/watcher_error.rs:52:impl From<serde_cbor::Error> for WatcherError {
src/watch_tower/watcher_error.rs:53: fn from(value: serde_cbor::Error) -> Self {
src/watch_tower/watcher_error.rs-54- Self::SerdeCbor(value)
--
src/watch_tower/registry_storage.rs:66: serde_cbor::from_slice(&bytes).unwrap_or_default(),
src/watch_tower/registry_storage.rs-67- )),
--
src/watch_tower/registry_storage.rs:82: match serde_cbor::to_vec(&RegistryData::default()) {
src/watch_tower/registry_storage.rs-83- Ok(bytes) => {
--
src/watch_tower/registry_storage.rs:115: let bytes = match serde_cbor::to_vec(&*data) {
src/watch_tower/registry_storage.rs-116- Ok(bytes) => bytes,
--
src/wallet/storage.rs:131: serde_cbor::to_writer(writer, &encrypted)?;
src/wallet/storage.rs-132- }
--
src/wallet/storage.rs:135: serde_cbor::to_writer(writer, &self)?;
src/wallet/storage.rs-136- }
--
src/wallet/error.rs:21: Cbor(serde_cbor::Error),
src/wallet/error.rs-22-
--
src/wallet/error.rs:117:impl From<serde_cbor::Error> for WalletError {
src/wallet/error.rs:118: fn from(value: serde_cbor::Error) -> Self {
src/wallet/error.rs-119- Self::Cbor(value)
--
src/wallet/ffi.rs:118: match serde_cbor::from_slice::<crate::security::EncryptedData>(&content) {
src/wallet/ffi.rs-119- Ok(_) => Ok(true), // Successfully parsed as EncryptedData = encrypted
--
src/utill.rs:210: let msg_bytes = serde_cbor::ser::to_vec(message)?;
src/utill.rs-211- let msg_len = (msg_bytes.len() as u32).to_be_bytes();
--
src/utill.rs:485: Serde(serde_cbor::Error),
src/utill.rs-486-}
--
src/utill.rs:494:impl From<serde_cbor::Error> for TorError {
src/utill.rs:495: fn from(value: serde_cbor::Error) -> Self {
src/utill.rs-496- TorError::Serde(value)
--
src/utill.rs:684: let data: [&str; 2] = serde_cbor::de::from_slice(&tor_metadata)?;
src/utill.rs-685-
--
src/utill.rs:715: serde_cbor::ser::to_vec(&[private_key, hostname.clone()])?,
src/utill.rs-716- )?;
--
src/utill.rs:724:pub fn deserialize_from_cbor<T>(mut reader: Vec<u8>) -> Result<T, serde_cbor::Error>
src/utill.rs-725-where
--
src/utill.rs:728: match serde_cbor::from_slice::<T>(&reader) {
src/utill.rs-729- Ok(store) => Ok(store),
--
src/utill.rs:737: match serde_cbor::from_slice::<T>(&reader) {
src/utill.rs-738- Ok(store) => break Ok(store),
--
src/utill.rs:1003: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes).unwrap();
src/utill.rs-1004-
--
src/taker/routines.rs:47: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-48-
--
src/taker/routines.rs:110: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-111- let contract_sigs_for_sender = match msg {
--
src/taker/routines.rs:165: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-166- let contract_sigs_for_recvr = match msg {
--
src/taker/routines.rs:247: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-248- let contract_sigs_as_recvr_and_sender = match msg {
--
src/taker/routines.rs:385: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/routines.rs-386- let privkey_handover = match msg {
--
src/taker/offers.rs:744: let msg: MakerToTakerMessage = serde_cbor::from_slice(&msg_bytes)?;
src/taker/offers.rs-745- let offer = match msg {
--
src/taker/offers.rs:778: let response: messages2::MakerToTakerMessage = serde_cbor::from_slice(&response_bytes)?;
src/taker/offers.rs-779-
--
src/taker/error.rs:51:impl From<serde_cbor::Error> for TakerError {
src/taker/error.rs:52: fn from(value: serde_cbor::Error) -> Self {
src/taker/error.rs-53- Self::Deserialize(value.to_string())
--
src/security.rs:28: Serialization(serde_cbor::Error),
src/security.rs-29- /// Error occurred during AES-GCM encryption.
--
src/security.rs:36:impl From<serde_cbor::Error> for EncryptError {
src/security.rs:37: fn from(err: serde_cbor::Error) -> Self {
src/security.rs-38- EncryptError::Serialization(err)
--
src/security.rs:57:/// Due to potential trailing bytes left by `serde_cbor`, the CBOR variant delegates
src/security.rs-58-/// parsing to [`utill::deserialize_from_cbor`] that strips extra data before deserialization.
--
src/security.rs:86:/// `serde_cbor` may leave trailing data behind, which can cause
src/security.rs-87-/// parsing errors.
--
src/security.rs:92: type Error = serde_cbor::Error;
src/security.rs-93- fn from_slice<T: DeserializeOwned>(input: &[u8]) -> Result<T, Self::Error> {
--
src/security.rs:224:/// `Struct -> serde_cbor::ser::to_vec(Struct) -> AES-GCM(encrypted_bytes) = encrypted_payload -> EncryptedData { encrypted_payload, nonce }`
src/security.rs-225-///
--
src/security.rs:238: let packed_store = serde_cbor::ser::to_vec(&plain_struct)?;
src/security.rs-239-
--
src/security.rs:270:) -> Result<T, serde_cbor::Error> {
src/security.rs-271- // Deserialize the outer EncryptedWalletStore wrapper.
--
src/taker/api2.rs:831: let response: MakerToTakerMessage = serde_cbor::from_slice(&response_bytes)?;
src/taker/api2.rs-832- log::info!("<=== {} | {maker_addr}", response);
--
src/error.rs:24: /// This variant wraps a [`serde_cbor::Error`] to provide details about the issue.
src/error.rs:25: Cbor(serde_cbor::Error),
src/error.rs-26-
--
src/error.rs:49:impl From<serde_cbor::Error> for NetError {
src/error.rs:50: fn from(value: serde_cbor::Error) -> Self {
src/error.rs-51- Self::Cbor(value)
--
src/maker/server.rs:375: let taker_msg = serde_cbor::from_slice::<TakerToMakerMessage>(&bytes)?;
src/maker/server.rs-376-
--
src/maker/server2.rs:438: let message = match serde_cbor::from_slice::<TakerToMakerMessage>(&message_bytes) {
src/maker/server2.rs-439- Ok(msg) => {
--
src/maker/rpc/server.rs:31: let rpc_request: RpcMsgReq = serde_cbor::from_slice(&msg_bytes)?;
src/maker/rpc/server.rs-32- log::info!("RPC request received: {rpc_request:?}");
--
src/maker/error.rs:62:impl From<serde_cbor::Error> for MakerError {
src/maker/error.rs:63: fn from(value: serde_cbor::Error) -> Self {
src/maker/error.rs-64- Self::Net(NetError::Cbor(value))
== Wallet-related test files ==
tests/liquidity_test.rs
== utill.rs around the claimed lines 724-750 ==
1152 src/utill.rs
Ok(hostname)
}
/// Deserialize any generic type from a CBOR file. The type should impl [serde::de::Deserialize].
pub fn deserialize_from_cbor<T>(mut reader: Vec<u8>) -> Result<T, serde_cbor::Error>
where
T: serde::de::DeserializeOwned,
{
match serde_cbor::from_slice::<T>(&reader) {
Ok(store) => Ok(store),
Err(e) => {
let err_string = format!("{e:?}");
if err_string.contains("code: TrailingData") {
// Defensive error handling - monitor logs to confirm wallet files stay clean.
log::info!("Wallet file has trailing data, trying to restore");
loop {
reader.pop();
match serde_cbor::from_slice::<T>(&reader) {
Ok(store) => break Ok(store),
Err(_) => continue,
}
}
} else {
Err(e)
}
}
}
}
/// Interactive Selection by User for Utxos
pub fn interactive_select(
mut choices: Vec<(ListUnspentResultEntry, UTXOSpendInfo)>,
required_amount: Amount,
) -> Result<Vec<(ListUnspentResultEntry, UTXOSpendInfo)>, WalletError> {
if choices.is_empty() {
return Err(WalletError::General("No UTXOs available".to_string()));
}
let total_available: Amount = choices.iter().map(|(utxo, _)| utxo.amount).sum();
if total_available < required_amount {
return Err(WalletError::General(format!(
== Check for Cargo.lock ==
Script executed:
#!/bin/bash
set -euo pipefail
echo "== Searching for serde_cbor_2 references in repo =="
rg -n 'serde_cbor_2' . --type-list 2>/dev/null | head -30 || echo "No additional refs found"
echo -e "\n== Check for wallet tests and CBOR deserialization tests =="
find tests -name "*.rs" -type f 2>/dev/null | while read f; do
echo "--- $f ---"
wc -l "$f"
done
echo -e "\n== Look for wallet fixture or deserialization tests =="
rg -n 'deserialize.*cbor|wallet.*fixture|TrailingData|deserialize_from_cbor' tests/ --type rust -A3 -B1 2>/dev/null || echo "No test coverage found"
echo -e "\n== Cargo.toml context for dependencies and versions =="
cat Cargo.toml | head -40Repository: citadel-tech/coinswap
Repository: citadel-tech/coinswap
Exit code: 0
stdout:
== Searching for serde_cbor_2 references in repo ==
No additional refs found
== Check for wallet tests and CBOR deserialization tests ==
--- tests/abort1.rs ---
255 tests/abort1.rs
--- tests/abort2_case1.rs ---
340 tests/abort2_case1.rs
--- tests/abort2_case2.rs ---
290 tests/abort2_case2.rs
--- tests/abort2_case3.rs ---
304 tests/abort2_case3.rs
--- tests/abort3_case1.rs ---
313 tests/abort3_case1.rs
--- tests/abort3_case2.rs ---
291 tests/abort3_case2.rs
--- tests/abort3_case3.rs ---
262 tests/abort3_case3.rs
--- tests/fidelity.rs ---
489 tests/fidelity.rs
--- tests/fidelity_renewal.rs ---
336 tests/fidelity_renewal.rs
--- tests/fidelity_timelock_violation.rs ---
127 tests/fidelity_timelock_violation.rs
--- tests/funding_dynamic_splits.rs ---
152 tests/funding_dynamic_splits.rs
--- tests/liquidity_test.rs ---
145 tests/liquidity_test.rs
--- tests/malice1.rs ---
260 tests/malice1.rs
--- tests/malice2.rs ---
267 tests/malice2.rs
--- tests/multi-taker.rs ---
223 tests/multi-taker.rs
--- tests/standard_swap.rs ---
279 tests/standard_swap.rs
--- tests/taker_cli.rs ---
180 tests/taker_cli.rs
--- tests/taproot_hashlock_recovery.rs ---
252 tests/taproot_hashlock_recovery.rs
--- tests/taproot_maker_abort1.rs ---
188 tests/taproot_maker_abort1.rs
--- tests/taproot_maker_abort2.rs ---
231 tests/taproot_maker_abort2.rs
--- tests/taproot_maker_abort3.rs ---
204 tests/taproot_maker_abort3.rs
--- tests/taproot_multi_maker.rs ---
200 tests/taproot_multi_maker.rs
--- tests/taproot_multi_taker.rs ---
223 tests/taproot_multi_taker.rs
--- tests/taproot_swap.rs ---
204 tests/taproot_swap.rs
--- tests/taproot_taker_abort1.rs ---
192 tests/taproot_taker_abort1.rs
--- tests/taproot_taker_abort2.rs ---
218 tests/taproot_taker_abort2.rs
--- tests/taproot_taker_abort3.rs ---
237 tests/taproot_taker_abort3.rs
--- tests/taproot_timelock_recovery.rs ---
256 tests/taproot_timelock_recovery.rs
--- tests/test_framework/mod.rs ---
866 tests/test_framework/mod.rs
--- tests/utxo_behavior.rs ---
701 tests/utxo_behavior.rs
--- tests/wallet_backup.rs ---
144 tests/wallet_backup.rs
== Look for wallet fixture or deserialization tests ==
No test coverage found
== Cargo.toml context for dependencies and versions ==
[package]
name = "coinswap"
version = "0.2.0"
authors = ["Developers at Citadel-Tech"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
description = "Functioning, minimal-viable binaries and libraries to perform a trustless, p2p Maxwell-Belcher Coinswap Protocol"
license = "MIT OR Apache-2.0"
documentation = "https://docs.rs/coinswap"
homepage = "https://github.com/citadel-tech/coinswap"
repository = "https://github.com/citadel-tech/coinswap"
categories = ["Bitcoin", "Atomic Swap", "HTLC"]
keywords = ["bitcoin", "HTLC", "coinswap"]
[dependencies]
bip39 = { version = "2.1.0", features = ["rand"] }
bitcoin = "0.32"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_cbor = { package = "serde_cbor_2", version = "0.13" }
log = "^0.4"
dirs = "3.0.1"
socks = "0.3.4"
clap = { version = "4.5", features = ["derive"] }
bitcoind = "0.36"
log4rs = "1.3.0"
secp256k1 = {git = "https://github.com/jlest01/rust-secp256k1.git", branch = "musig2-module", features = ["rand", "global-context"]}
minreq = { version = "2.12.0", features = ["https"] }
pbkdf2 = { version = "0.12", features = ["simple"] }
aes-gcm = "0.10.3"
sha2 = "0.10.9"
rust-coinselect = "0.1.6"
crossterm = "0.29.0"
zmq = "0.10.0"
tungstenite = { version = "0.28.0", features = ["native-tls"]}
nostr = "0.44.2"
crossbeam-channel = "0.5.15"
serde_cbor_2 rust crate
serde_cbor_2 is a Rust crate that provides CBOR (Concise Binary Object Representation) serialization/deserialization via Serde, intended as a drop-in replacement for serde_cbor. (docs.rs)
Add it to Cargo.toml:
[dependencies]
serde_cbor_2 = "0.13"(Docs.rs shows serde_cbor_2 0.13.0 as the latest.) (docs.rs)
Drop-in replacement pattern (keep importing serde_cbor in code):
[dependencies]
serde_cbor = { version = "0.12", package = "serde_cbor_2" }(docs.rs)
Docs / repo:
- Documentation is on docs.rs. (docs.rs)
- Repository is
kanidm/cboron GitHub. (github.com)
Citations:
- 1: https://docs.rs/serde_cbor_2
- 2: https://docs.rs/serde_cbor_2
- 3: https://docs.rs/serde_cbor_2
- 4: https://docs.rs/serde_cbor_2
- 5: https://github.com/kanidm/cbor
Script executed:
#!/bin/bash
set -euo pipefail
echo "== Check git history or comments near Cargo.toml change =="
git log --oneline -n 20 -- Cargo.toml 2>/dev/null || echo "Git log not available"
echo -e "\n== Search for comments about serde_cbor_2 in codebase =="
rg -n 'serde_cbor_2|serde.cbor.*2|cbor.*fork|cbor.*compatible' . --type rust --type toml -B2 -A2 2>/dev/null || echo "No explanatory comments found"
echo -e "\n== Check if there's a comment in Cargo.toml itself =="
cat Cargo.toml | grep -A5 -B5 'serde_cbor'
echo -e "\n== Look for error format testing or TrailingData handling docs =="
rg -n 'TrailingData|trailing.*data' src/ --type rust -B3 -A3 2>/dev/nullRepository: citadel-tech/coinswap
Repository: citadel-tech/coinswap
Exit code: 0
stdout:
== Check git history or comments near Cargo.toml change ==
a8f8fe7 replace serde_cbor with serde_cbor_2 (close `#782`)
== Search for comments about serde_cbor_2 in codebase ==
./Cargo.toml-20-serde = { version = "1.0", features = ["derive"] }
./Cargo.toml-21-serde_json = "1.0"
./Cargo.toml:22:serde_cbor = { package = "serde_cbor_2", version = "0.13" }
./Cargo.toml-23-log = "^0.4"
./Cargo.toml-24-dirs = "3.0.1"
== Check if there's a comment in Cargo.toml itself ==
[dependencies]
bip39 = { version = "2.1.0", features = ["rand"] }
bitcoin = "0.32"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_cbor = { package = "serde_cbor_2", version = "0.13" }
log = "^0.4"
dirs = "3.0.1"
socks = "0.3.4"
clap = { version = "4.5", features = ["derive"] }
bitcoind = "0.36"
== Look for error format testing or TrailingData handling docs ==
src/security.rs-81- }
src/security.rs-82-}
src/security.rs-83-/// CBOR implementation of `SerdeFormat`, using a utility wrapper
src/security.rs:84:/// that handles CBOR trailing data properly.
src/security.rs-85-///
src/security.rs:86:/// `serde_cbor` may leave trailing data behind, which can cause
src/security.rs-87-/// parsing errors.
src/security.rs-88-/// This wrapper [`utill::deserialize_from_cbor`] utility method to cleanly deserialize.
src/security.rs-89-pub struct SerdeCbor;
--
src/utill.rs-729- Ok(store) => Ok(store),
src/utill.rs-730- Err(e) => {
src/utill.rs-731- let err_string = format!("{e:?}");
src/utill.rs:732: if err_string.contains("code: TrailingData") {
src/utill.rs-733- // Defensive error handling - monitor logs to confirm wallet files stay clean.
src/utill.rs:734: log::info!("Wallet file has trailing data, trying to restore");
src/utill.rs-735- loop {
src/utill.rs-736- reader.pop();
src/utill.rs-737- match serde_cbor::from_slice::<T>(&reader) {
Script executed:
#!/bin/bash
set -euo pipefail
echo "== Check for issue `#782` reference in code or git =="
git log --all --grep="782" --oneline 2>/dev/null || echo "Git grep not available"
echo -e "\n== Search for any test with trailing data or wallet recovery =="
rg -n 'trailing|TrailingData|pop.*reader|wallet.*recover' tests/ --type rust -B2 -A4 || echo "No tests found"
echo -e "\n== Check if serde_cbor_2 error type is documented in code =="
rg -n 'serde_cbor::Error|TrailingData' src/ --type rust -B1 -A3 2>/dev/null | head -60
echo -e "\n== Look for version info in Cargo.lock or documented compatibility =="
if [ -f Cargo.lock ]; then
grep -A5 'serde_cbor' Cargo.lock | head -30
fi
echo -e "\n== Check if there's any documentation about the serde_cbor_2 swap =="
rg -n 'serde.cbor.*2|drop.in|compatible|replacement' . --type rust --type md --type toml -B2 -A2 2>/dev/null || echo "No docs found"Repository: citadel-tech/coinswap
Repository: citadel-tech/coinswap
Exit code: 0
stdout:
== Check for issue `#782` reference in code or git ==
a8f8fe7 replace serde_cbor with serde_cbor_2 (close `#782`)
== Search for any test with trailing data or wallet recovery ==
No tests found
== Check if serde_cbor_2 error type is documented in code ==
src/watch_tower/watcher_error.rs-22- /// Serialization/deserialization error for CBOR.
src/watch_tower/watcher_error.rs:23: SerdeCbor(serde_cbor::Error),
src/watch_tower/watcher_error.rs-24- /// WebSocket error from tungstenite
src/watch_tower/watcher_error.rs-25- WebSocket(tungstenite::Error),
src/watch_tower/watcher_error.rs-26- /// Nostr message parsing error
--
src/watch_tower/watcher_error.rs-51-
src/watch_tower/watcher_error.rs:52:impl From<serde_cbor::Error> for WatcherError {
src/watch_tower/watcher_error.rs:53: fn from(value: serde_cbor::Error) -> Self {
src/watch_tower/watcher_error.rs-54- Self::SerdeCbor(value)
src/watch_tower/watcher_error.rs-55- }
src/watch_tower/watcher_error.rs-56-}
--
src/taker/error.rs-50-
src/taker/error.rs:51:impl From<serde_cbor::Error> for TakerError {
src/taker/error.rs:52: fn from(value: serde_cbor::Error) -> Self {
src/taker/error.rs-53- Self::Deserialize(value.to_string())
src/taker/error.rs-54- }
src/taker/error.rs-55-}
--
src/wallet/error.rs-20- /// This is used for encoding/decoding data structures.
src/wallet/error.rs:21: Cbor(serde_cbor::Error),
src/wallet/error.rs-22-
src/wallet/error.rs-23- /// Represents an error during JSON serialization or deserialization.
src/wallet/error.rs-24- ///
--
src/wallet/error.rs-116-}
src/wallet/error.rs:117:impl From<serde_cbor::Error> for WalletError {
src/wallet/error.rs:118: fn from(value: serde_cbor::Error) -> Self {
src/wallet/error.rs-119- Self::Cbor(value)
src/wallet/error.rs-120- }
src/wallet/error.rs-121-}
--
src/security.rs-27- /// Error occurred during CBOR serialization of the input struct.
src/security.rs:28: Serialization(serde_cbor::Error),
src/security.rs-29- /// Error occurred during AES-GCM encryption.
src/security.rs-30- ///
src/security.rs-31- /// Note: This error type carries no additional information because
--
src/security.rs-35-
src/security.rs:36:impl From<serde_cbor::Error> for EncryptError {
src/security.rs:37: fn from(err: serde_cbor::Error) -> Self {
src/security.rs-38- EncryptError::Serialization(err)
src/security.rs-39- }
src/security.rs-40-}
--
src/security.rs-91-impl SerdeFormat for SerdeCbor {
src/security.rs:92: type Error = serde_cbor::Error;
src/security.rs-93- fn from_slice<T: DeserializeOwned>(input: &[u8]) -> Result<T, Self::Error> {
src/security.rs-94- utill::deserialize_from_cbor::<T>(input.to_vec())
src/security.rs-95- }
--
src/security.rs-269- enc_material: &KeyMaterial,
src/security.rs:270:) -> Result<T, serde_cbor::Error> {
src/security.rs-271- // Deserialize the outer EncryptedWalletStore wrapper.
src/security.rs-272-
src/security.rs-273- let nonce_vec = encrypted_struct.nonce;
--
src/error.rs-23- ///
src/error.rs:24: /// This variant wraps a [`serde_cbor::Error`] to provide details about the issue.
== Look for version info in Cargo.lock or documented compatibility ==
== Check if there's any documentation about the serde_cbor_2 swap ==
./src/wallet/ffi.rs:1://! FFI-compatible types for the Taker module.
./src/wallet/ffi.rs-2-//!
./src/wallet/ffi.rs:3://! This module provides Foreign Function Interface (FFI) compatible data structures
./src/wallet/ffi.rs-4-//! for exposing swap functionality and reporting to other languages.
./src/wallet/ffi.rs-5-
--
./Cargo.toml-20-serde = { version = "1.0", features = ["derive"] }
./Cargo.toml-21-serde_json = "1.0"
./Cargo.toml:22:serde_cbor = { package = "serde_cbor_2", version = "0.13" }
./Cargo.toml-23-log = "^0.4"
./Cargo.toml-24-dirs = "3.0.1"
--
./src/taker/api2.rs-1069- log::error!("Dropping connection after sending SendersContract to Maker");
./src/taker/api2.rs-1070- return Err(TakerError::General(
./src/taker/api2.rs:1071: "Taker dropping of after sending Senders Contract to Maker (test behavior) "
./src/taker/api2.rs-1072- .to_string(),
./src/taker/api2.rs-1073- ));
--
./src/taker/api2.rs-1161- );
./src/taker/api2.rs-1162- return Err(TakerError::General(
./src/taker/api2.rs:1163: "Taker dropping of after receiving Senders Contract from Maker (test behavior) ".to_string(),));
./src/taker/api2.rs-1164- }
./src/taker/api2.rs-1165- }
serde_cbor_2 TrailingData error format compatibility
In serde_cbor_2, TrailingData (displayed as “trailing data”) means the deserializer successfully decoded one CBOR value, but there were still unread bytes left in the input—i.e., your input is not exactly one standalone CBOR item. [1]
Common causes:
- You’re feeding a CBOR “sequence” (multiple CBOR values concatenated) to
from_slice/from_reader(which expect one value). - Your transport/storage adds framing bytes (length prefixes, checksums, padding, etc.) after the CBOR payload.
- You’re decoding from the middle of a buffer that contains more than one message.
What to do:
- If you expect multiple CBOR values: use
StreamDeserializer(iterator over consecutive CBOR values) instead offrom_slice/from_reader. [2] - If you expect one value inside a larger buffer: use a
Deserializerand then checkbyte_offset()to find where the decoded value ended (the docs show this pattern and how to get the “rest”). [2]
Format compatibility note:
serde_cbor_2aims to be a drop-in replacement forserde_cborand uses standard CBOR, but you must keep encoder/decoder settings aligned—e.g., if you enable packed encoding /legacy_enums(), the consumer must decode accordingly. Otherwise you can hit decode errors (including leftover bytes depending on framing). [2]
Sources
[1] https://docs.rs/serde_cbor_2/latest/src/serde_cbor_2/error.rs.html
[2] https://docs.rs/serde_cbor_2/latest/serde_cbor_2/
Verify error format compatibility and add wallet CBOR regression tests before merging.
The swap to serde_cbor_2 (v0.13) on line 22 is intentional (commit a8f8fe7 closed issue #782), but introduces a compatibility risk because the wallet recovery code at src/utill.rs:732 depends on CBOR error formatting stability. The code checks format!("{e:?}").contains("code: TrailingData") to detect and recover from trailing-data errors—if serde_cbor_2's Debug representation differs, this recovery will silently break for existing wallet files.
Confirm:
- Error format equivalence between
serde_cborandserde_cbor_2forTrailingDataerrors - Regression coverage for wallet deserialization with trailing-data scenarios (currently missing)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Cargo.toml` at line 22, Update the wallet recovery logic and add tests to
guard against serde_cbor_2 formatting changes: replace the fragile string check
format!("{e:?}").contains("code: TrailingData") in src/utill.rs (around the
wallet recovery path) with a robust match against the CBOR error type or variant
provided by serde_cbor_2 (e.g., inspect the error kind/variant instead of Debug
text) so detection does not depend on Debug formatting; then add regression
tests that simulate the trailing-data scenario for wallet deserialization (unit
tests near utill.rs or integration tests) to assert recovery still triggers with
serde_cbor_2, and run/verify that behavior with the updated dependency in
Cargo.toml.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
Cargo.toml (1)
22-22:⚠️ Potential issue | 🟠 MajorHarden trailing-data recovery before merging this crate swap.
At Line 22, moving to
serde_cbor_2is fine in principle, but current recovery insrc/utill.rsdepends onDebugstring matching ("code: TrailingData"). That is brittle across crate/version changes and can silently disable wallet recovery behavior.#!/bin/bash set -euo pipefail echo "== Find fragile TrailingData detection ==" rg -nP 'format!\("\{e:\?\}"\)\.contains\("code: TrailingData"\)' src/ -C2 echo -e "\n== Locate deserialization helper and call sites ==" rg -nP '\bdeserialize_from_cbor\s*\(' src/ tests/ -C2 echo -e "\n== Check for regression tests covering trailing-data recovery ==" rg -nP 'TrailingData|trailing data|deserialize_from_cbor' tests/ -C2 || true🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Cargo.toml` at line 22, The current trailing-data detection in src/utill.rs (used by deserialize_from_cbor and its call sites) relies on matching the Debug string "code: TrailingData", which is brittle across serde_cbor crate swaps; replace the string-match with a proper error-type check: update the deserialize_from_cbor error handling to match against the serde_cbor_2 trailing-data error variant (e.g., pattern-match the error enum or use the crate's API like Error::TrailingData / an is_trailing_data/is_eof-like accessor) instead of using format!(..).contains(...), update all call sites that expect the old string, and add/adjust tests under tests/ to cover the trailing-data recovery path so the behavior is verified after the serde_cbor -> serde_cbor_2 swap.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@Cargo.toml`:
- Line 22: The current trailing-data detection in src/utill.rs (used by
deserialize_from_cbor and its call sites) relies on matching the Debug string
"code: TrailingData", which is brittle across serde_cbor crate swaps; replace
the string-match with a proper error-type check: update the
deserialize_from_cbor error handling to match against the serde_cbor_2
trailing-data error variant (e.g., pattern-match the error enum or use the
crate's API like Error::TrailingData / an is_trailing_data/is_eof-like accessor)
instead of using format!(..).contains(...), update all call sites that expect
the old string, and add/adjust tests under tests/ to cover the trailing-data
recovery path so the behavior is verified after the serde_cbor -> serde_cbor_2
swap.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@deny.toml`:
- Around line 221-232: The deny.toml currently sets unknown-git = "deny" while
allow-git = [] (and no allow-org entries), which will block the git-sourced
dependency secp256k1 referenced in Cargo.toml; to fix, add the git repository
URL ("https://github.com/jlest01/rust-secp256k1.git") to the allow-git list or
add the owning org/URL under the [sources.allow-org] configuration (so the
secp256k1 git dependency is permitted), ensuring the change is made in deny.toml
and references the existing unknown-git / allow-git / allow-org settings.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9cf9fa9a-a3f3-42e4-99dd-89ef13c9cc52
📒 Files selected for processing (3)
.github/workflows/audit.yamlCargo.tomldeny.toml
| [sources] | ||
| # Lint level for what to happen when a crate from a crate registry that is not | ||
| # in the allow list is encountered | ||
| unknown-registry = "deny" | ||
| # Lint level for what to happen when a crate from a git repository that is not | ||
| # in the allow list is encountered | ||
| unknown-git = "deny" | ||
| # List of URLs for allowed crate registries. Defaults to the crates.io index | ||
| # if not specified. If it is specified but empty, no registries are allowed. | ||
| allow-registry = ["https://github.com/rust-lang/crates.io-index"] | ||
| # List of URLs for allowed Git repositories | ||
| allow-git = [] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find Cargo.toml and deny.toml files
echo "== Finding relevant files =="
find . -name "Cargo.toml" -o -name "deny.toml" | head -20
echo -e "\n== Checking Cargo.toml for git dependencies =="
if [ -f "Cargo.toml" ]; then
echo "Contents of Cargo.toml (git-related lines):"
grep -n -E 'git\s*=' Cargo.toml || echo "No git dependencies found"
echo -e "\nFull dependencies section:"
sed -n '/^\[dependencies\]/,/^\[/p' Cargo.toml | head -40
else
echo "Cargo.toml not found in root"
fi
echo -e "\n== Checking deny.toml sources section =="
if [ -f "deny.toml" ]; then
echo "Lines 220-235 of deny.toml:"
sed -n '220,235p' deny.toml
echo -e "\nSearching for allow-git in deny.toml:"
grep -n "allow-git" deny.toml
else
echo "deny.toml not found in root"
fiRepository: citadel-tech/coinswap
Length of output: 2117
🏁 Script executed:
#!/bin/bash
echo "== Full [sources.allow-org] section =="
grep -A 5 '\[sources.allow-org\]' deny.toml
echo -e "\n== Checking if github value exists in allow-org =="
awk '/\[sources.allow-org\]/,/^\[/' deny.toml | grep -E '^\s*github\s*='Repository: citadel-tech/coinswap
Length of output: 358
Git dependency will fail: allow-git is empty but secp256k1 uses a git source.
The configuration sets unknown-git = "deny" with an empty allow-git = [] and empty github = [] in [sources.allow-org], but Cargo.toml declares a git dependency:
secp256k1 = {git = "https://github.com/jlest01/rust-secp256k1.git", branch = "musig2-module", ...}This will cause cargo deny check sources to fail in CI.
🔧 Proposed fix to allow the git dependency
# List of URLs for allowed Git repositories
-allow-git = []
+allow-git = ["https://github.com/jlest01/rust-secp256k1.git"]Or use the allow-org section:
[sources.allow-org]
# github.com organizations to allow git sources for
-github = []
+github = ["jlest01"]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@deny.toml` around lines 221 - 232, The deny.toml currently sets unknown-git =
"deny" while allow-git = [] (and no allow-org entries), which will block the
git-sourced dependency secp256k1 referenced in Cargo.toml; to fix, add the git
repository URL ("https://github.com/jlest01/rust-secp256k1.git") to the
allow-git list or add the owning org/URL under the [sources.allow-org]
configuration (so the secp256k1 git dependency is permitted), ensuring the
change is made in deny.toml and references the existing unknown-git / allow-git
/ allow-org settings.
Close #761
Summary by CodeRabbit