confium 0.3.2 → 0.3.4

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: c8445c7b4b7f4fdea4740a5f22874c5a97eda59e75ebe5cf327dbc84b67ff6f2
4
- data.tar.gz: 68381a40a3a7f21b5f4330611bbe86e7abbf9223602288f105f611553e86cd21
3
+ metadata.gz: fdc8059371955b1e4ee89982856fb39a1fb758c9d1b3264bb2f3bd21fe77c028
4
+ data.tar.gz: a392f2b3d8b87e4d296f5f68dec94e61ae3e2263eea032f12240b2f625b7ba56
5
5
  SHA512:
6
- metadata.gz: 00cf2dd64ba0bce3897db2d5f026818ccc5f90cc1ad1f27a65869827f530811df1a60c50e6fefeb9c83183859bccce81194b0e031e2fbff5b8213d53bb3cb4cb
7
- data.tar.gz: a2f6509125418022a2aa3d98d86b724cc841f7f3067884c482d345f2f3b28a0adb63b51dbba34d48dd5d64aa1c827a42d8bf86be273160feb631d5e8a68b72b9
6
+ metadata.gz: ccdae726768ecf965b3f21f000b42bbc7c67a01b31d7715a2f23f0e243873453da7539ae57fbfb0ffda185d3ea572b74d0f3c033518e1e154fdc0b739db0b1b1
7
+ data.tar.gz: db63f19d08cf86076df52ec0f583493019e03a1512268aa1d83b56edce182d42c18120369e46ca054e66dfdf79619b04fdfe91175607845260cc668894fa680d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.4] — 2026-08-23
4
+
5
+ ### Fixed
6
+
7
+ - **Typed-error sweep completed.** Crypto operation failures
8
+ (FrostP256 sign, ElGamal encapsulate/decrypt/aggregate, composite
9
+ sign) raise `Confium::CryptoError` with the primitive in `details`;
10
+ `PathValidator` DER extraction failures raise `Confium::ParseError`;
11
+ `Manifest#tier_name_at` and `SignedData#certificate_at` out-of-range
12
+ raise the typed `Confium::IndexError` (unifying with the
13
+ transparency proofs — they previously raised Ruby's core
14
+ `IndexError`).
15
+ - **Zero compiler warnings.** All 80 direct
16
+ `magnus::exception::*` constructor sites are centralized into
17
+ `util::runtime`/`util::arg_error` (the deprecated API survives in
18
+ exactly one module whose job is wrapping it); the remaining magnus
19
+ deprecations (`RString::buf_new`, `RArray::each`) and dead imports
20
+ are fixed.
21
+ - **DoS guard now covers every byte input**: the duplicate local
22
+ `bytes_from_value` copies in tc/transparency — one of which
23
+ skipped the 1 MiB size cap — are consolidated onto the util
24
+ version that enforces it.
25
+
26
+ ## [0.3.3] — 2026-08-23
27
+
28
+ ### Added
29
+
30
+ - **Typed native errors everywhere**: PEM/DER, JSON, TOML, DSL, and
31
+ XML parse failures raise `Confium::ParseError`; out-of-range
32
+ sequence indexes raise `Confium::IndexError`; consistency-proof
33
+ failures raise `Confium::VerificationError` — each with a
34
+ structured `details` Hash (format, operation, index, ...).
35
+ Previously these surfaced as bare `RuntimeError`.
36
+
37
+ ### Added
38
+
39
+ - `Confium::Composite::Signature.components_to_json` /
40
+ `.from_json` — JSON transport for composite signatures with the
41
+ binary fields hex-encoded on the wire (fixes the Sinatra example's
42
+ happy path, which called a `from_json` that did not exist).
43
+ - Steep type checking in CI: the Steepfile never loaded before
44
+ (it used a `configure_code_diagnostics` API that does not exist in
45
+ steep 1.10). `sig/confium.rbs` now covers every pure-Ruby
46
+ subsystem — including the TC session machinery — and
47
+ `bundle exec steep check` is green and enforced. Only the FFI
48
+ layer is excluded (the ffi gem has no RBS signatures).
49
+
50
+ ### Fixed
51
+
52
+ - `Confium::PKI::CMS::SignedDataBuilder#build` raised KeyError on
53
+ the ECDSA-P256 path (`FrostP256.sign` returns `der`/`fixed`, not
54
+ `signature`); it now uses the DER form, which is what CMS carries.
55
+ - `Confium::PKI::CertificateBuilder`, `Confium::PKI::CNML`, and
56
+ `Confium::Transparency::OTS` were unreachable after
57
+ `require "confium"` (missing autoload wiring); the PKI namespace
58
+ file is now eager-required and registers them.
59
+ - All five `hello_*` quickstart examples, the Sinatra example's
60
+ happy path, and every page under `docs/` were rewritten against
61
+ the real APIs (see the docs audit), and CI now runs every example
62
+ on every push.
63
+
3
64
  ## [0.3.2] — 2026-08-22
4
65
 
5
66
  Native platform gems (linux x86_64/aarch64, macOS x86_64/arm64) ship
data/README.adoc CHANGED
@@ -10,7 +10,7 @@ Confium supports three deployment modes:
10
10
  * **Mode 2 — TC PKI replacement**: drop-in for existing PKI consumers (PKCS#11 server, OpenSSL 3.0 provider, JCE)
11
11
  * **Mode 3 — TC Certificate PKI**: institutional deployments with custom certificate formats (OIML CNML, BIPM, pharma, accreditation)
12
12
 
13
- This gem wraps the high-value Confium subsystems via a Rust native extension (built at `gem install` time with `rb_sys` + `magnus`). No separate C ABI library to install; everything is statically linked into the extension.
13
+ This gem wraps the high-value Confium subsystems via a Rust native extension. Pre-compiled platform gems are published for Linux and macOS, so `gem install` needs no Rust toolchain there; other platforms build from source at install time with `rb_sys` + `magnus`. No separate C ABI library to install; everything is statically linked into the extension.
14
14
 
15
15
  == Installation
16
16
 
@@ -18,7 +18,7 @@ Add to your Gemfile:
18
18
 
19
19
  [source,ruby]
20
20
  ----
21
- gem "confium", "~> 0.1"
21
+ gem "confium", "~> 0.3"
22
22
  ----
23
23
 
24
24
  Or install directly:
@@ -31,10 +31,18 @@ $ gem install confium
31
31
  === Prerequisites
32
32
 
33
33
  * Ruby ≥ 3.1
34
+ * Nothing else on the pre-compiled platforms: `x86_64-linux`,
35
+ `aarch64-linux`, `x86_64-darwin`, `arm64-darwin` (each gem carries
36
+ one extension per Ruby C-ABI window)
37
+
38
+ Source builds (other platforms, or installing from the repo) also
39
+ need:
40
+
34
41
  * Rust stable toolchain (`rustup default stable`)
35
42
  * C toolchain (clang/gcc/Xcode CLT)
36
43
 
37
- The gem compiles a Rust cdylib at install time and links it into Ruby as a native extension. There is no separate `libconfium` to install.
44
+ There is no separate `libconfium` to install — the extension
45
+ statically links everything.
38
46
 
39
47
  == Quick start
40
48
 
@@ -76,7 +84,7 @@ recovered = Confium::TC::FrostP256.recover_secret(shares.first(3).map { |s| { "x
76
84
  recovered == kp["private_key"] # => true
77
85
  ----
78
86
 
79
- == API surface (v0.1.0)
87
+ == API surface (v0.3)
80
88
 
81
89
  === `Confium::Transparency`
82
90
  - `MerkleTree.new` / `#append(artifact_hash)` / `#root` / `#length` / `#empty?` / `#inclusion_proof(seq)`
@@ -127,7 +135,7 @@ After checking out the repo:
127
135
  ----
128
136
  $ bundle install
129
137
  $ bundle exec rake compile # build the Rust extension
130
- $ bundle exec rspec # 75+ specs
138
+ $ bundle exec rspec # 226 specs
131
139
  ----
132
140
 
133
141
  == Architecture
data/confium.gemspec CHANGED
@@ -49,7 +49,6 @@ Gem::Specification.new do |spec|
49
49
 
50
50
  spec.add_development_dependency 'rake', '~> 13.0'
51
51
  spec.add_development_dependency 'rake-compiler', '~> 1.3.0'
52
- spec.add_development_dependency 'rake-compiler-dock', '~> 1.3'
53
52
  spec.add_development_dependency 'rspec', '~> 3.0'
54
53
  spec.add_development_dependency 'rubocop', '~> 1.0'
55
54
  spec.add_development_dependency 'steep', '~> 1.5'
@@ -12,7 +12,7 @@
12
12
 
13
13
  use confium_attributes::{evaluate, parse as dsl_parse, Predicate, SignerAttributes};
14
14
  use magnus::{
15
- exception, function, method, typed_data::Obj, DataTypeFunctions, Error, Module,
15
+ function, method, typed_data::Obj, DataTypeFunctions, Error, Module,
16
16
  Object, Ruby, TryConvert, TypedData, Value,
17
17
  };
18
18
 
@@ -26,8 +26,8 @@ impl PredicateWrap {
26
26
  fn satisfied_by(&self, signers_value: Value) -> Result<bool, Error> {
27
27
  let arr = magnus::RArray::try_convert(signers_value)?;
28
28
  let mut owned: Vec<SignerAttributes> = Vec::with_capacity(arr.len());
29
- for v in arr.each() {
30
- let signer_wrap = Obj::<SignerWrap>::try_convert(v?)?;
29
+ for v in arr.into_iter() {
30
+ let signer_wrap = Obj::<SignerWrap>::try_convert(v)?;
31
31
  owned.push(signer_wrap.inner.borrow().clone());
32
32
  }
33
33
  let refs: Vec<&SignerAttributes> = owned.iter().collect();
@@ -63,8 +63,8 @@ impl SignerWrap {
63
63
 
64
64
  fn parse(expr: String) -> Result<Obj<PredicateWrap>, Error> {
65
65
  let predicate = dsl_parse(&expr)
66
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
67
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
66
+ .map_err(|e| crate::util::parse_error(e.to_string(), "Attributes.parse", Some("dsl"), None))?;
67
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
68
68
  Ok(ruby.obj_wrap(PredicateWrap { inner: predicate }))
69
69
  }
70
70
 
@@ -11,7 +11,7 @@
11
11
  //! sink raises, the calling operation still succeeds. Audit
12
12
  //! failures must never break a signing ceremony.
13
13
 
14
- use magnus::{exception, function, prelude::*, Error, Module, Ruby, Value};
14
+ use magnus::{function, prelude::*, Error, Module, Ruby, Value};
15
15
  use sha2::{Digest, Sha256};
16
16
 
17
17
  const SINK_IVAR: &str = "@sink";
@@ -94,12 +94,12 @@ fn record(
94
94
  algorithm: Option<String>,
95
95
  error: Option<String>,
96
96
  ) -> Result<(), Error> {
97
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
97
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
98
98
  let audit_mod: magnus::RModule = ruby
99
99
  .class_object()
100
100
  .const_get("Confium")
101
101
  .and_then(|m: magnus::RModule| m.const_get("Audit"))
102
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
102
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
103
103
 
104
104
  let sink: Value = audit_mod.ivar_get(SINK_IVAR)?;
105
105
  if sink.is_nil() {
@@ -123,31 +123,31 @@ fn record(
123
123
 
124
124
  let _: Value = sink
125
125
  .funcall("call", (h,))
126
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
126
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
127
127
  Ok(())
128
128
  }
129
129
 
130
130
  /// Set the global audit sink. `callback` is a Proc that receives a Hash
131
131
  /// or nil to disable auditing.
132
132
  fn set_sink(callback: Value) -> Result<(), Error> {
133
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
133
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
134
134
  let audit_mod: magnus::RModule = ruby
135
135
  .class_object()
136
136
  .const_get("Confium")
137
137
  .and_then(|m: magnus::RModule| m.const_get("Audit"))
138
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
138
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
139
139
  audit_mod.ivar_set(SINK_IVAR, callback)?;
140
140
  Ok(())
141
141
  }
142
142
 
143
143
  /// Get the current audit sink (or nil if not set).
144
144
  fn get_sink() -> Result<Value, Error> {
145
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
145
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
146
146
  let audit_mod: magnus::RModule = ruby
147
147
  .class_object()
148
148
  .const_get("Confium")
149
149
  .and_then(|m: magnus::RModule| m.const_get("Audit"))
150
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
150
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
151
151
  audit_mod.ivar_get(SINK_IVAR)
152
152
  }
153
153
 
@@ -14,7 +14,7 @@
14
14
  use confium_composite::{CompositeSignature, ComponentSignature, VerificationResult};
15
15
  use ed25519_dalek::SigningKey;
16
16
  use magnus::{
17
- exception, function, method, prelude::*, scan_args,
17
+ function, method, prelude::*, scan_args,
18
18
  typed_data::Obj, DataTypeFunctions, Error, IntoValue,
19
19
  Module, Object, RHash, Ruby, TryConvert, TypedData, Value,
20
20
  };
@@ -79,7 +79,7 @@ impl CompositeSig {
79
79
  let details = new_details(&ruby);
80
80
  confium_error(e.to_string(), "VerificationError", details)
81
81
  })?;
82
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
82
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
83
83
  Ok(ruby.obj_wrap(VerificationResultWrap { inner: result }))
84
84
  }
85
85
  }
@@ -133,7 +133,7 @@ impl VerificationResultWrap {
133
133
  }
134
134
 
135
135
  fn per_component(&self) -> Result<Value, Error> {
136
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
136
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
137
137
  let result = ruby.hash_new();
138
138
  for c in &self.inner.per_component {
139
139
  let entry = ruby.hash_new();
@@ -156,9 +156,7 @@ fn sign_ed25519(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash
156
156
  let pk_bytes = bytes_from_value(private_key)?;
157
157
  let msg = bytes_from_value(message)?;
158
158
  if pk_bytes.len() != 32 {
159
- return Err(Error::new(
160
- exception::arg_error(),
161
- format!("Ed25519 private key must be 32 bytes, got {}", pk_bytes.len()),
159
+ return Err(crate::util::arg_error(format!("Ed25519 private key must be 32 bytes, got {}", pk_bytes.len()),
162
160
  ));
163
161
  }
164
162
  let mut pk_arr = [0u8; 32];
@@ -174,7 +172,7 @@ fn sign_ed25519(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash
174
172
  Some(&msg),
175
173
  Some(&e.to_string()),
176
174
  );
177
- return Err(Error::new(exception::runtime_error(), e.to_string()));
175
+ return Err(crate::util::crypto_error(e.to_string(), "Composite.sign_ed25519", "ed25519"));
178
176
  }
179
177
  };
180
178
 
@@ -204,16 +202,14 @@ fn sign_p256(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash, E
204
202
  let pk_bytes = bytes_from_value(private_key)?;
205
203
  let msg = bytes_from_value(message)?;
206
204
  if pk_bytes.len() != 32 {
207
- return Err(Error::new(
208
- exception::arg_error(),
209
- format!("P-256 private key must be 32 bytes, got {}", pk_bytes.len()),
205
+ return Err(crate::util::arg_error(format!("P-256 private key must be 32 bytes, got {}", pk_bytes.len()),
210
206
  ));
211
207
  }
212
208
  let mut arr = [0u8; 32];
213
209
  arr.copy_from_slice(&pk_bytes);
214
210
  use p256::ecdsa::{Signature, SigningKey, signature::Signer};
215
211
  let signing = SigningKey::from_bytes(&arr.into())
216
- .map_err(|e| Error::new(exception::arg_error(), format!("invalid P-256 private key: {e}")))?;
212
+ .map_err(|e| crate::util::arg_error(format!("invalid P-256 private key: {e}")))?;
217
213
  let sig: Signature = match signing.try_sign(msg.as_slice()) {
218
214
  Ok(s) => s,
219
215
  Err(e) => {
@@ -224,7 +220,7 @@ fn sign_p256(ruby: &Ruby, private_key: Value, message: Value) -> Result<RHash, E
224
220
  Some(&msg),
225
221
  Some(&format!("sign error: {e}")),
226
222
  );
227
- return Err(Error::new(exception::runtime_error(), format!("sign error: {e}")));
223
+ return Err(crate::util::crypto_error(format!("sign error: {e}"), "Composite.sign_p256", "ecdsa-p256"));
228
224
  }
229
225
  };
230
226
  let verifying = signing.verifying_key();
@@ -259,8 +255,8 @@ fn generate_ed25519_keypair(ruby: &Ruby) -> Result<RHash, Error> {
259
255
  fn parse_components(value: Value) -> Result<Vec<ComponentSignature>, Error> {
260
256
  let arr = magnus::RArray::try_convert(value)?;
261
257
  let mut out = Vec::with_capacity(arr.len());
262
- for v in arr.each() {
263
- let h: RHash = RHash::try_convert(v?)?;
258
+ for v in arr.into_iter() {
259
+ let h: RHash = RHash::try_convert(v)?;
264
260
  let algorithm: String = h.fetch::<_, String>("algorithm")?;
265
261
  let public_key: Value = h.fetch::<_, Value>("public_key")?;
266
262
  let signature: Value = h.fetch::<_, Value>("signature")?;
@@ -11,8 +11,8 @@ use confium_deployment::{
11
11
  manifest::{parse_manifest, Manifest as RustManifest},
12
12
  validate::validate_manifest,
13
13
  };
14
- use crate::util::enforce_size;
15
- use magnus::{exception, function, method, typed_data::Obj, DataTypeFunctions, Error, Module, Object, Ruby, TypedData};
14
+ use crate::util::{enforce_size, parse_error};
15
+ use magnus::{function, method, typed_data::Obj, DataTypeFunctions, Error, Module, Object, Ruby, TypedData};
16
16
 
17
17
  #[derive(TypedData, DataTypeFunctions)]
18
18
  #[magnus(class = "Confium::Identity::Actor", size)]
@@ -24,8 +24,8 @@ impl Actor {
24
24
  fn from_json(json: String) -> Result<Obj<Self>, Error> {
25
25
  enforce_size(json.len())?;
26
26
  let actor: ActorIdentity = serde_json::from_str(&json)
27
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
28
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
27
+ .map_err(|e| parse_error(e.to_string(), "Actor.from_json", Some("json"), None))?;
28
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
29
29
  Ok(ruby.obj_wrap(Self {
30
30
  inner: std::cell::RefCell::new(actor),
31
31
  }))
@@ -33,7 +33,7 @@ impl Actor {
33
33
 
34
34
  fn to_json(&self) -> Result<String, Error> {
35
35
  serde_json::to_string(&*self.inner.borrow())
36
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))
36
+ .map_err(|e| crate::util::runtime(e.to_string()))
37
37
  }
38
38
 
39
39
  fn actor_id(&self) -> String {
@@ -93,8 +93,8 @@ impl Manifest {
93
93
  fn from_toml(toml_str: String) -> Result<Obj<Self>, Error> {
94
94
  enforce_size(toml_str.len())?;
95
95
  let manifest = parse_manifest(&toml_str)
96
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
97
- let ruby = Ruby::get().map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
96
+ .map_err(|e| parse_error(e.to_string(), "Manifest.from_toml", Some("toml"), None))?;
97
+ let ruby = Ruby::get().map_err(|e| crate::util::runtime(e.to_string()))?;
98
98
  Ok(ruby.obj_wrap(Self {
99
99
  inner: std::cell::RefCell::new(manifest),
100
100
  }))
@@ -123,9 +123,10 @@ impl Manifest {
123
123
  .get(index)
124
124
  .map(|t| t.name.clone())
125
125
  .ok_or_else(|| {
126
- Error::new(
127
- exception::index_error(),
126
+ crate::util::index_error(
128
127
  format!("tier index {index} out of range"),
128
+ "Manifest.tier_name_at",
129
+ Some(index as u64),
129
130
  )
130
131
  })
131
132
  }
@@ -5,7 +5,7 @@ use confium_transparency::ers::{
5
5
  EvidenceRecord, HashAlgorithm,
6
6
  };
7
7
  use magnus::{
8
- exception, function, method, typed_data::Obj,
8
+ function, method, typed_data::Obj,
9
9
  DataTypeFunctions, Error, Module, Object, Ruby, TryConvert, TypedData, Value,
10
10
  };
11
11
 
@@ -20,13 +20,11 @@ pub struct ErsRecord {
20
20
  impl ErsRecord {
21
21
  fn build_initial(args: &[Value]) -> Result<Obj<Self>, Error> {
22
22
  let first = args.first().ok_or_else(|| {
23
- Error::new(exception::arg_error(), "data_hash required")
23
+ crate::util::arg_error("data_hash required")
24
24
  })?;
25
25
  let data_hash = bytes_from_value(*first)?;
26
26
  if data_hash.len() != 32 {
27
- return Err(Error::new(
28
- exception::arg_error(),
29
- format!("data_hash must be 32 bytes, got {}", data_hash.len()),
27
+ return Err(crate::util::arg_error(format!("data_hash must be 32 bytes, got {}", data_hash.len()),
30
28
  ));
31
29
  }
32
30
  let mut hash = [0u8; 32];
@@ -42,7 +40,7 @@ impl ErsRecord {
42
40
  let record =
43
41
  build_initial_evidence_record(hash, HashAlgorithm::Sha256, tsa_id, token_bytes);
44
42
  let ruby = Ruby::get()
45
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
43
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
46
44
  Ok(ruby.obj_wrap(Self {
47
45
  inner: std::cell::RefCell::new(record),
48
46
  }))
@@ -50,13 +48,11 @@ impl ErsRecord {
50
48
 
51
49
  fn renew(&self, args: &[Value]) -> Result<Obj<Self>, Error> {
52
50
  let first = args.first().ok_or_else(|| {
53
- Error::new(exception::arg_error(), "new_hash required")
51
+ crate::util::arg_error("new_hash required")
54
52
  })?;
55
53
  let new_hash_bytes = bytes_from_value(*first)?;
56
54
  if new_hash_bytes.len() != 32 {
57
- return Err(Error::new(
58
- exception::arg_error(),
59
- format!("new_hash must be 32 bytes, got {}", new_hash_bytes.len()),
55
+ return Err(crate::util::arg_error(format!("new_hash must be 32 bytes, got {}", new_hash_bytes.len()),
60
56
  ));
61
57
  }
62
58
  let mut hash = [0u8; 32];
@@ -72,7 +68,7 @@ impl ErsRecord {
72
68
  let mut cloned = self.inner.borrow().clone();
73
69
  renew_evidence_record(&mut cloned, HashAlgorithm::Sha256, hash, tsa_id, token_bytes);
74
70
  let ruby = Ruby::get()
75
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
71
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
76
72
  Ok(ruby.obj_wrap(Self {
77
73
  inner: std::cell::RefCell::new(cloned),
78
74
  }))
@@ -2,7 +2,7 @@
2
2
  //!
3
3
  //! Confium ships RNP functionality baked into the native extension.
4
4
 
5
- use magnus::{exception, function, prelude::*, Error, Module, RModule, Ruby, TryConvert, Value};
5
+ use magnus::{function, prelude::*, Error, Module, RModule, Ruby, TryConvert, Value};
6
6
  use rnp::ops::ArmorType;
7
7
  use rnp::{armor_bytes, dearmor_bytes};
8
8
 
@@ -26,7 +26,7 @@ fn native_armor(ruby: &Ruby, data: Value, type_str: Value) -> Result<magnus::RSt
26
26
  }
27
27
  };
28
28
  let armored = armor_bytes(&bytes, ty)
29
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
29
+ .map_err(|e| crate::util::parse_error(e.to_string(), "OpenPGP.armor", Some("openpgp"), None))?;
30
30
  Ok(bytes_to_rstring(ruby, &armored))
31
31
  }
32
32
 
@@ -34,7 +34,7 @@ fn native_armor(ruby: &Ruby, data: Value, type_str: Value) -> Result<magnus::RSt
34
34
  fn native_dearmor(ruby: &Ruby, data: Value) -> Result<magnus::RString, Error> {
35
35
  let bytes = bytes_from_value(data)?;
36
36
  let raw = dearmor_bytes(&bytes)
37
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
37
+ .map_err(|e| crate::util::parse_error(e.to_string(), "OpenPGP.dearmor", Some("openpgp"), None))?;
38
38
  Ok(bytes_to_rstring(ruby, &raw))
39
39
  }
40
40
 
@@ -10,7 +10,7 @@ use confium_pki::{
10
10
  path::{validate_path, CertPath},
11
11
  result::VerificationResult as PathVerificationResult,
12
12
  };
13
- use magnus::{exception, function, method, prelude::*, DataTypeFunctions, Error, Module, Ruby, TypedData, Value};
13
+ use magnus::{function, method, prelude::*, DataTypeFunctions, Error, Module, Ruby, TypedData, Value};
14
14
 
15
15
  /// Wraps a confium_pki::path::VerificationResult.
16
16
  #[derive(TypedData, DataTypeFunctions)]
@@ -63,17 +63,17 @@ fn validate(args: &[Value]) -> Result<magnus::typed_data::Obj<PathResult>, Error
63
63
  Vec::new()
64
64
  } else {
65
65
  let arr = magnus::RArray::try_convert(intermediates_value)
66
- .map_err(|e| Error::new(exception::arg_error(), e.to_string()))?;
66
+ .map_err(|e| crate::util::arg_error(e.to_string()))?;
67
67
  let mut out = Vec::with_capacity(arr.len());
68
- for v in arr.each() {
69
- out.push(extract_cert(v?, "intermediate")?);
68
+ for v in arr.into_iter() {
69
+ out.push(extract_cert(v, "intermediate")?);
70
70
  }
71
71
  out
72
72
  };
73
73
 
74
74
  let now = match now_iso8601 {
75
75
  Some(s) => chrono::DateTime::parse_from_rfc3339(&s)
76
- .map_err(|e| Error::new(exception::arg_error(), format!("invalid time: {e}")))?
76
+ .map_err(|e| crate::util::arg_error(format!("invalid time: {e}")))?
77
77
  .with_timezone(&Utc),
78
78
  None => Utc::now(),
79
79
  };
@@ -86,7 +86,7 @@ fn validate(args: &[Value]) -> Result<magnus::typed_data::Obj<PathResult>, Error
86
86
  let result = validate_path(&path, now);
87
87
 
88
88
  let ruby = Ruby::get()
89
- .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?;
89
+ .map_err(|e| crate::util::runtime(e.to_string()))?;
90
90
  Ok(ruby.obj_wrap(PathResult { inner: result }))
91
91
  }
92
92
 
@@ -98,10 +98,10 @@ fn extract_cert(value: Value, label: &str) -> Result<RustCert, Error> {
98
98
  // We re-parse those bytes into a fresh RustCert.
99
99
  let der_value: Value = value
100
100
  .funcall("to_der", ())
101
- .map_err(|e| Error::new(exception::runtime_error(), format!("{}: cannot get DER: {e}", label)))?;
101
+ .map_err(|e| crate::util::parse_error(format!("{label}: cannot get DER: {e}"), "PathValidator.validate", Some("der"), None))?;
102
102
  let der = crate::util::bytes_from_value(der_value)?;
103
103
  RustCert::from_der(&der)
104
- .map_err(|e| Error::new(exception::runtime_error(), format!("{}: invalid DER: {e}", label)))
104
+ .map_err(|e| crate::util::parse_error(format!("{label}: invalid DER: {e}"), "PathValidator.validate", Some("der"), None))
105
105
  }
106
106
 
107
107
  pub fn init(ruby: &Ruby, parent: magnus::RModule) -> Result<(), Error> {