confium 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 604e0df1709827705bdca8fabd5ac2c5bdb70eb1e32b550e7ad7bfca143d7dcc
4
- data.tar.gz: b1d4eea58189c4e1acf7613c27efc23ea7a76ea6afb9a32b911f27d56dc45a7c
3
+ metadata.gz: 80f1cc9387a28284e32d2c8b92fbdb5555f675f05e2ec8e6c38cd213a65e215f
4
+ data.tar.gz: d9ccaaf8e4297e8a731be6e19be9a5ee6566d3aa24d8398598f48fd6b2cf50fa
5
5
  SHA512:
6
- metadata.gz: e07456a3f0a1c4499290372d238fd15e173e578deabb01de7bea5c5b6c014495eab86b962c71f33fb3f21c9d2f9124dd982373c5e7df404c011955180d136b1f
7
- data.tar.gz: 2ee41a6707200f709086c9ae63d73554f2aa8836abf06c732a1ac904fded30baece97813b50a8229c2a351ea3cf0430d2265d3f93b06aa49daa4f8447c67e037
6
+ metadata.gz: b0fe995dbf54fcbc0b8fe57d815eedcba6abb10f8c4b26cd1713b62042798390861eb6faaf96168dcfcc8baa03dd54dd1d5c89d0f826f3d68f1a2bfb60416096
7
+ data.tar.gz: 4dde75f2b6d9c9143c546facb59bd249a1d87b6451d18a6036c1deec428773a553e2aedb8f9047465c4d0933e9f502d9d63341b74dac34ddfab3b31abafbd572
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.1] — UNRELEASED (code on main; release on the owner's tag)
4
+
5
+ ### Added
6
+
7
+ - `Confium::Transparency::OTS` is now the real OpenTimestamps
8
+ wire-protocol binding (confium-transparency 0.9): `OTS::Client#stamp`
9
+ POSTs the 32-byte digest to the calendar pool and returns a `Proof`
10
+ carrying the parsed partial proof; `#upgrade` polls for a confirmed
11
+ one; `Proof#verify` replays the op tree and classifies attestations
12
+ (pending URIs, Bitcoin/Litecoin heights, `anchored`). Module-level
13
+ `OTS.stamp`/`verify`/`upgrade` over the default calendar pool.
14
+ Network failures raise (`IOError`/`ParseError`) — the stub-era
15
+ silent nil is gone.
16
+ - The calendar round trip releases the GVL (direct
17
+ `rb_thread_call_without_gvl` trampoline — magnus 0.8 does not wrap
18
+ it), so a slow calendar never freezes the VM.
19
+
20
+ ### Fixed
21
+
22
+ - The workspace's OTS file magic was missing its final two salt bytes
23
+ (29 vs 31; shifted every parse offset for real .ots files) — caught
24
+ by this binding's cross-checked specs, fixed in confium-transparency
25
+ v0.9.1.
26
+
3
27
  ## [0.7.0] — 2026-09-07
4
28
 
5
29
  ### Added
data/Cargo.lock CHANGED
@@ -775,17 +775,18 @@ dependencies = [
775
775
 
776
776
  [[package]]
777
777
  name = "confium-transparency"
778
- version = "0.4.0"
778
+ version = "0.9.1"
779
779
  source = "registry+https://github.com/rust-lang/crates.io-index"
780
- checksum = "874cdab3dded22c22980d3a5b1f802301739368a32e9196bc645600329c07dcf"
780
+ checksum = "b4ec484381b582f508f774babbc1bf1b4a98c6aadd43cde806952c6e416b62ca"
781
781
  dependencies = [
782
782
  "chrono",
783
- "data-encoding",
783
+ "hex",
784
784
  "serde",
785
785
  "serde_json",
786
- "sha2 0.10.9",
787
- "snafu 0.8.9",
788
- "thiserror 1.0.69",
786
+ "sha2 0.11.0",
787
+ "subtle",
788
+ "thiserror 2.0.20",
789
+ "ureq",
789
790
  ]
790
791
 
791
792
  [[package]]
data/README.adoc CHANGED
@@ -103,7 +103,7 @@ end
103
103
  === `Confium::Transparency`
104
104
  - `MerkleTree.new` / `#append(artifact_hash)` / `#root` / `#length` / `#empty?` / `#inclusion_proof(seq)`
105
105
  - `InclusionProof#sequence` / `#steps` / `#verify(root)`
106
- - `Ots.stamp(hash)` / `Ots.verify(receipt, hash)` — OpenTimestamps anchoring interface (pure-Ruby stub; calendar-server wiring lands with the Rust client)
106
+ - `Ots.stamp(hash)` / `Ots.verify(proof)` / `Ots.upgrade(proof)` — real OpenTimestamps anchoring over the wire protocol (calendar HTTP, servers tried in order; the network round trip releases the GVL). `Ots::Client.new(servers)` for a custom pool; `Ots::Proof#verify` replays the op tree and classifies attestations. Network failures raise — there is no silent nil
107
107
 
108
108
  === `Confium::Composite` — PQ migration
109
109
  - `.generate_ed25519_keypair` → `{ private_key:, public_key: }`
@@ -36,7 +36,7 @@ magnus = { version = "0.8", features = ["bytes"] }
36
36
 
37
37
  # Confium crates — all from crates.io so gem install works without workspace checkout.
38
38
  confium-core = "0.2"
39
- confium-transparency = "0.4"
39
+ confium-transparency = { version = "0.9", features = ["calendar"] }
40
40
  confium-composite = "0.3.1"
41
41
  confium-attributes = "0.3.1"
42
42
  confium-pki = "0.5.6"
@@ -0,0 +1,56 @@
1
+ //! GVL release for long blocking calls.
2
+ //!
3
+ //! magnus 0.8 does not wrap `rb_thread_call_without_gvl`, so the OTS
4
+ //! calendar round trip (up to 30s) would hold the GVL and freeze the
5
+ //! entire Ruby VM — including any Ruby thread serving as the peer.
6
+ //! This is the standard MRI mechanism: release the GVL for the
7
+ //! duration of a blocking FFI call, reacquire before touching Ruby
8
+ //! objects again. The closure must not touch the Ruby API.
9
+
10
+ use std::ffi::c_void;
11
+
12
+ unsafe extern "C" {
13
+ fn rb_thread_call_without_gvl(
14
+ func: extern "C" fn(*mut c_void) -> *mut c_void,
15
+ data1: *mut c_void,
16
+ ubf: Option<extern "C" fn(*mut c_void) -> *mut c_void>,
17
+ data2: *mut c_void,
18
+ ) -> *mut c_void;
19
+ }
20
+
21
+ struct CallBox<F: FnOnce() -> T, T> {
22
+ func: Option<F>,
23
+ out: Option<T>,
24
+ }
25
+
26
+ extern "C" fn trampoline<F: FnOnce() -> T, T>(data: *mut c_void) -> *mut c_void {
27
+ // SAFETY: data points at the CallBox constructed by without_gvl,
28
+ // live for the duration of the call, on this same thread.
29
+ let box_ = unsafe { &mut *(data as *mut CallBox<F, T>) };
30
+ let func = box_.func.take().expect("trampoline runs once");
31
+ box_.out = Some(func());
32
+ std::ptr::null_mut()
33
+ }
34
+
35
+ /// Run `func` with the GVL released. Reacquires before returning.
36
+ ///
37
+ /// # Safety (caller obligations)
38
+ ///
39
+ /// `func` must not call the Ruby C API (no Ruby objects) and must be
40
+ /// callable from this thread while the GVL is released.
41
+ pub unsafe fn without_gvl<F: FnOnce() -> T, T>(func: F) -> T {
42
+ let mut call = CallBox {
43
+ func: Some(func),
44
+ out: None,
45
+ };
46
+ // SAFETY: the trampoline and box are used per the contract above.
47
+ unsafe {
48
+ rb_thread_call_without_gvl(
49
+ trampoline::<F, T>,
50
+ &mut call as *mut CallBox<F, T> as *mut c_void,
51
+ None,
52
+ std::ptr::null_mut(),
53
+ );
54
+ }
55
+ call.out.take().expect("trampoline stored the result")
56
+ }
@@ -9,12 +9,14 @@ mod attributes;
9
9
  mod composite;
10
10
  mod deployment;
11
11
  mod ers;
12
+ mod gvl;
12
13
  mod openpgp_verify;
13
14
  mod path;
14
15
  mod pki;
15
16
  mod store;
16
17
  mod tc;
17
18
  mod net;
19
+ mod ots;
18
20
  mod tc_session;
19
21
  mod transparency;
20
22
  mod util;
@@ -66,6 +68,8 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
66
68
  native.define_module_function("winsock_probe", function!(winsock_probe_fn, 1))?;
67
69
 
68
70
  transparency::init(ruby, confium)?;
71
+ let transparency = confium.define_module("Transparency")?;
72
+ ots::init(ruby, transparency)?;
69
73
  openpgp_verify::init(ruby, confium)?;
70
74
  #[cfg(feature = "pgp")]
71
75
  openpgp_verify::init_pgp(ruby, &confium)?;
@@ -0,0 +1,183 @@
1
+ //! Confium::Transparency::OTS — OpenTimestamps calendar client.
2
+ //!
3
+ //! Binds confium-transparency's real wire-protocol client (0.9):
4
+ //! `stamp` POSTs the 32-byte digest to a calendar server and parses
5
+ //! the returned partial proof (op stream + pending attestation);
6
+ //! `upgrade` fetches a more complete proof; `verify` replays the op
7
+ //! tree from the digest and classifies the attestations. Network
8
+ //! errors surface as Ruby exceptions — there is no silent nil.
9
+
10
+ use std::cell::RefCell;
11
+
12
+ use confium_transparency::ots::OtsClient;
13
+ use confium_transparency::ots::wire;
14
+ use magnus::prelude::*;
15
+ use magnus::Error;
16
+ use magnus::RHash;
17
+ use magnus::RString;
18
+ use magnus::Ruby;
19
+ use magnus::TypedData;
20
+ use magnus::DataTypeFunctions;
21
+
22
+ /// An OTS proof: the raw .ots file bytes plus the digest it anchors.
23
+ #[derive(TypedData, DataTypeFunctions)]
24
+ #[magnus(class = "Confium::Transparency::OTS::Proof", size)]
25
+ pub struct OtsProof {
26
+ digest: Vec<u8>,
27
+ bytes: Vec<u8>,
28
+ }
29
+
30
+ fn digest_arg_error() -> Error {
31
+ Error::new(magnus::exception::arg_error(), "digest must be exactly 32 bytes")
32
+ }
33
+
34
+ impl OtsProof {
35
+ fn initialize(_ruby: &Ruby, digest: RString, bytes: RString) -> Result<Self, Error> {
36
+ let digest = digest.to_bytes().to_vec();
37
+ if digest.len() != 32 {
38
+ return Err(digest_arg_error());
39
+ }
40
+ Ok(Self {
41
+ digest,
42
+ bytes: bytes.to_bytes().to_vec(),
43
+ })
44
+ }
45
+
46
+ fn digest(&self) -> RString {
47
+ RString::from_slice(&self.digest)
48
+ }
49
+
50
+ fn to_bytes(&self) -> RString {
51
+ RString::from_slice(&self.bytes)
52
+ }
53
+
54
+ /// Replay the proof tree and classify attestations. Returns a Hash:
55
+ /// { pending: [uri, ...], bitcoin: [height, ...],
56
+ /// litecoin: [height, ...], anchored: bool }
57
+ fn verify(&self) -> Result<RHash, Error> {
58
+ let ruby = Ruby::get().map_err(|_| Error::new(magnus::exception::runtime_error(), "not on Ruby thread"))?;
59
+ let file = wire::parse(&self.digest, &self.bytes)
60
+ .map_err(|e| Error::new(parse_error_class(&ruby), format!("invalid OTS proof: {e}")))?;
61
+ let summary = wire::verify(&file)
62
+ .map_err(|e| Error::new(ruby.exception_runtime_error(), format!("replay failed: {e}")))?;
63
+
64
+ let out = RHash::new();
65
+ let pending: Vec<String> = summary
66
+ .pending
67
+ .iter()
68
+ .map(|(_, uri)| uri.clone())
69
+ .collect();
70
+ out.aset(
71
+ "pending",
72
+ ruby.into_value(ruby.ary_from_vec(pending)),
73
+ )?;
74
+ let bitcoin: Vec<i64> = summary.bitcoin.iter().map(|(_, h)| i64::from(*h)).collect();
75
+ out.aset(
76
+ "bitcoin",
77
+ ruby.into_value(ruby.ary_from_vec(bitcoin)),
78
+ )?;
79
+ let litecoin: Vec<i64> = summary.litecoin.iter().map(|(_, h)| i64::from(*h)).collect();
80
+ out.aset(
81
+ "litecoin",
82
+ ruby.into_value(ruby.ary_from_vec(litecoin)),
83
+ )?;
84
+ // Bitcoin/Litecoin attestations are on-chain anchors; pending
85
+ // means recorded at a calendar awaiting confirmation.
86
+ let anchored = !summary.bitcoin.is_empty() || !summary.litecoin.is_empty();
87
+ out.aset("anchored", ruby.into_value(anchored))?;
88
+ Ok(out)
89
+ }
90
+ }
91
+
92
+ /// A calendar client bound to a server pool.
93
+ #[derive(TypedData, DataTypeFunctions)]
94
+ #[magnus(class = "Confium::Transparency::OTS::Client", size)]
95
+ pub struct Client {
96
+ inner: RefCell<OtsClient>,
97
+ }
98
+
99
+ impl Client {
100
+ fn initialize(_ruby: &Ruby, servers: Vec<String>) -> Result<Self, Error> {
101
+ Ok(Self {
102
+ inner: RefCell::new(OtsClient::with_servers(servers)),
103
+ })
104
+ }
105
+
106
+ /// Submit a 32-byte digest to the calendar pool. Returns a Proof
107
+ /// carrying the returned partial proof (pending attestation).
108
+ fn stamp(&self, digest: RString) -> Result<OtsProof, Error> {
109
+ let ruby = Ruby::get().map_err(|_| Error::new(magnus::exception::runtime_error(), "not on Ruby thread"))?;
110
+ let digest = digest.to_bytes().to_vec();
111
+ if digest.len() != 32 {
112
+ return Err(digest_arg_error());
113
+ }
114
+ let arr: [u8; 32] = digest.as_slice().try_into().map_err(|_| digest_arg_error())?;
115
+ let mut inner = self.inner.borrow_mut();
116
+ // Release the GVL for the network round trip: calendars take
117
+ // seconds-to-tens-of-seconds, and holding the VM would freeze
118
+ // every Ruby thread (including any in-process peer).
119
+ let stamped = unsafe {
120
+ crate::gvl::without_gvl(|| inner.stamp_wire(arr))
121
+ };
122
+ let file = stamped
123
+ .map_err(|e| Error::new(ruby.exception_io_error(), format!("calendar stamp failed: {e}")))?;
124
+ let bytes = wire::serialize(&file).map_err(|e| {
125
+ Error::new(
126
+ ruby.exception_runtime_error(),
127
+ format!("calendar returned an unserializable proof: {e}"),
128
+ )
129
+ })?;
130
+ Ok(OtsProof { digest, bytes })
131
+ }
132
+
133
+ /// Fetch a more complete proof for a pending attestation. Returns
134
+ /// the upgraded Proof (replaces the pending one).
135
+ fn upgrade(&self, proof: &OtsProof) -> Result<OtsProof, Error> {
136
+ let ruby = Ruby::get().map_err(|_| Error::new(magnus::exception::runtime_error(), "not on Ruby thread"))?;
137
+ let file = wire::parse(&proof.digest, &proof.bytes)
138
+ .map_err(|e| Error::new(parse_error_class(&ruby), format!("invalid OTS proof: {e}")))?;
139
+ let mut inner = self.inner.borrow_mut();
140
+ let upgraded_result = unsafe { crate::gvl::without_gvl(|| inner.upgrade(&file)) };
141
+ let upgraded = upgraded_result
142
+ .map_err(|e| Error::new(ruby.exception_io_error(), format!("calendar upgrade failed: {e}")))?;
143
+ let bytes = wire::serialize(&upgraded).map_err(|e| {
144
+ Error::new(
145
+ ruby.exception_runtime_error(),
146
+ format!("calendar returned an unserializable proof: {e}"),
147
+ )
148
+ })?;
149
+ Ok(OtsProof {
150
+ digest: proof.digest.clone(),
151
+ bytes,
152
+ })
153
+ }
154
+ }
155
+
156
+ pub fn init(ruby: &Ruby, parent: magnus::RModule) -> Result<(), Error> {
157
+ let ots = parent.define_module("OTS")?;
158
+ let parse_error = ots.define_error("ParseError", ruby.exception_standard_error())?;
159
+ ots.const_set("PARSE_ERROR", parse_error)?;
160
+
161
+ let proof = ots.define_class("Proof", ruby.class_object())?;
162
+ proof.define_singleton_method("new", magnus::function!(OtsProof::initialize, 2))?;
163
+ proof.define_method("digest", magnus::method!(OtsProof::digest, 0))?;
164
+ proof.define_method("to_bytes", magnus::method!(OtsProof::to_bytes, 0))?;
165
+ proof.define_method("verify", magnus::method!(OtsProof::verify, 0))?;
166
+
167
+ let client = ots.define_class("Client", ruby.class_object())?;
168
+ client.define_singleton_method("new", magnus::function!(Client::initialize, 1))?;
169
+ client.define_method("stamp", magnus::method!(Client::stamp, 1))?;
170
+ client.define_method("upgrade", magnus::method!(Client::upgrade, 1))?;
171
+
172
+ Ok(())
173
+ }
174
+
175
+ fn parse_error_class(ruby: &Ruby) -> magnus::ExceptionClass {
176
+ ruby
177
+ .class_object()
178
+ .const_get::<_, magnus::RModule>("Confium")
179
+ .and_then(|m| m.const_get::<_, magnus::RModule>("Transparency"))
180
+ .and_then(|m| m.const_get::<_, magnus::RModule>("OTS"))
181
+ .and_then(|m| m.const_get::<_, magnus::ExceptionClass>("PARSE_ERROR"))
182
+ .unwrap_or_else(|_| ruby.exception_runtime_error())
183
+ }
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Confium::Transparency::OTS — OpenTimestamps client interface.
3
+ # Confium::Transparency::OTS — OpenTimestamps calendar client.
4
4
  #
5
- # Wraps confium-transparency::ots::Client for anchoring Merkle tree
6
- # roots in the Bitcoin blockchain via OTS calendar servers.
7
- #
8
- # This is a pure-Ruby stub that defines the interface. The actual
9
- # OTS stamping requires network access to calendar servers and
10
- # will be wired through the Rust extension in a future PR
11
- # (TODO.completion/011-ots-ers-exposure.md).
5
+ # Real wire-protocol implementation over the native extension
6
+ # (confium-transparency 0.8.5+): stamps POST the 32-byte digest to a
7
+ # calendar server and parse the returned partial proof; verification
8
+ # replays the op tree from the digest and classifies attestations.
9
+ # Network failures raise (Confium::Transparency::OTS is backed by a
10
+ # real HTTP client) there is no silent nil.
12
11
 
13
12
  module Confium
14
13
  module Transparency
@@ -20,44 +19,48 @@ module Confium
20
19
  https://a.pool.eternitywall.com
21
20
  ].freeze
22
21
 
23
- # An OTS receipt proving that a hash was anchored in Bitcoin
24
- # at a specific block height.
25
- class Receipt
26
- attr_reader :bytes, :block_height
22
+ class << self
23
+ # Stamp a 32-byte digest via the default calendar pool.
24
+ # Returns a Proof (pending attestation — Bitcoin confirmation
25
+ # arrives later; poll with #upgrade).
26
+ #
27
+ # @param hash [String] 32-byte SHA-256 digest to anchor
28
+ # @return [Confium::Transparency::OTS::Proof]
29
+ # @raise [IOError, ArgumentError]
30
+ def stamp(hash)
31
+ default_client.stamp(hash)
32
+ end
27
33
 
28
- def initialize(bytes:, block_height: nil)
29
- @bytes = bytes
30
- @block_height = block_height
34
+ # Verify a proof: replay its op tree from the digest and
35
+ # classify the attestations.
36
+ #
37
+ # @param proof [Proof, String] the proof (or raw .ots bytes —
38
+ # pass the digest alongside for the String form)
39
+ # @param digest [String, nil] required when proof is bytes
40
+ # @return [Hash] { pending: [uri], bitcoin: [height],
41
+ # litecoin: [height], anchored: bool }
42
+ def verify(proof, digest = nil)
43
+ proof = Proof.new(digest, proof) if digest && proof.is_a?(String)
44
+ proof.verify
31
45
  end
32
46
 
33
- def to_bytes
34
- @bytes
47
+ # Upgrade a pending proof (fetch a more complete one).
48
+ #
49
+ # @return [Proof]
50
+ def upgrade(proof)
51
+ default_client.upgrade(proof)
35
52
  end
36
- end
37
53
 
38
- # Stamp a 32-byte hash via OTS calendar servers.
39
- # Returns a Receipt (stub: returns nil — requires network).
40
- #
41
- # @param hash [String] 32-byte SHA-256 hash to anchor
42
- # @return [Receipt, nil]
43
- def self.stamp(_hash)
44
- # Real implementation: calls the Rust OTS client which
45
- # submits the hash to calendar servers and returns a
46
- # merged proof. Requires network access.
47
- nil
48
- end
54
+ private
49
55
 
50
- # Verify an OTS receipt against a hash.
51
- # Returns true if the receipt proves the hash was anchored.
52
- #
53
- # @param receipt [Receipt, String] the OTS proof
54
- # @param hash [String] the 32-byte hash
55
- # @return [Boolean]
56
- def self.verify(_receipt, _hash)
57
- # Real implementation: calls the Rust OTS verifier which
58
- # walks the Bitcoin blockchain proof.
59
- false
56
+ def default_client
57
+ @default_client ||= Client.new(DEFAULT_CALENDARS)
58
+ end
60
59
  end
60
+
61
+ # The native Client is defined by the extension
62
+ # (Confium::Transparency::OTS::Client) with #stamp / #upgrade;
63
+ # the Proof class carries #digest / #to_bytes / #verify.
61
64
  end
62
65
  end
63
66
  end
@@ -5,8 +5,8 @@
5
5
  # The Transparency module itself is defined by the native Rust
6
6
  # extension via magnus at require time. This file registers
7
7
  # pure-Ruby autoloads for the Transparency submodules.
8
- module Confium
9
- module Transparency
10
- autoload :OTS, 'confium/transparency/ots'
11
- end
12
- end
8
+ # `require`, not `autoload`: the native extension defines the OTS
9
+ # constant at load time, which would shadow the autoload entry and
10
+ # keep this file from ever running — the Ruby-level convenience
11
+ # methods would silently vanish.
12
+ require 'confium/transparency/ots'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Confium
4
- VERSION = '0.7.0'
4
+ VERSION = '0.7.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: confium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Open
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-07 00:00:00.000000000 Z
11
+ date: 2026-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys
@@ -120,9 +120,11 @@ files:
120
120
  - ext/confium_native/src/composite.rs
121
121
  - ext/confium_native/src/deployment.rs
122
122
  - ext/confium_native/src/ers.rs
123
+ - ext/confium_native/src/gvl.rs
123
124
  - ext/confium_native/src/lib.rs
124
125
  - ext/confium_native/src/net.rs
125
126
  - ext/confium_native/src/openpgp_verify.rs
127
+ - ext/confium_native/src/ots.rs
126
128
  - ext/confium_native/src/path.rs
127
129
  - ext/confium_native/src/pki.rs
128
130
  - ext/confium_native/src/store.rs