Skip to main content

asx_rs/
lib.rs

1/*!
2# asx-rs — AS2/AS4 EDI protocol library
3
4`asx-rs` is an async-native, memory-safe Rust library for the AS2 (RFC 4130) and
5AS4 (OASIS ebMS3 + eDelivery) EDI transport protocols. The crate is published as
6`asx-rs`; the library itself is imported as `asx_rs`.
7
8## Feature flags
9
10 The crate uses Cargo feature flags to limit the compiled surface and dependency
11 tree.  The **default** feature set is
12 `["interop-strict", "async-ocsp", "compression", "trace"]`.
13
14| Feature | Enables | Required by |
15|---|---|---|
16| `as2` | AS2 send/receive free functions (`as2::send_sync`, `as2::receive_sync`) and async wrappers (`as2::send_async`, `as2::receive_async`) | anything using AS2 |
17| `as4` | AS4 send/receive free functions (`as4::send_sync`, `as4::receive_push_with_dedup_sync`), receipt verification (`as4::verify_sync_response`), `As4PullStore`, and protocol configuration (`pmode`, `types`) | anything using AS4 |
18| `compression` | Zlib/GZIP payload compression via `flate2` | AS2/AS4 `policy.compress = true` (default) |
19| `async-ocsp` | Async OCSP responder fetching via `reqwest` | production OCSP validation |
20| `interop-strict` | **(default)** Strict interop mode as the default. Governs header/ambiguity handling only — **not** the security policy; see [`InteropMode`](core::InteropMode) | All profiles |
21| `interop-relaxed` | Relaxed mode helpers available alongside strict | Legacy partner interop |
22| `trace` | Experimental `tracing` instrumentation for selected protocol paths | Observability |
23| `prometheus` | Built-in Prometheus/OpenMetrics text `MetricsSink` adapter (`observability::PrometheusMetricsSink`) | Native metrics export |
24| `opentelemetry` | OpenTelemetry `MetricsSink` adapter (`observability::OtelMetricsSink`) | Native metrics export |
25| `dns` | Built-in BDXL resolver (`smp::HickoryBdxlResolver`) for Peppol/CEF participant discovery | `SmlDiscovery::Naptr` without a custom `BdxlResolver` |
26| `testing` | Exposes `fixtures` and `matrix` test-scaffold modules | Integration test harness |
27| `server` | Axum router integration (`as2_router`, `as4_router`, `As2AxumHandler`, `As4AxumHandler`) | HTTP receive |
28| `client` | Async HTTP egress transport via `reqwest` (`As2HttpTransport`, `As4HttpTransport`) | HTTP send |
29
30`reqwest` dependency note:
31- Enabling `async-ocsp` pulls `reqwest` for OCSP HTTP fetches.
32- Enabling `client` also pulls `reqwest` for protocol egress transports.
33- Enabling both features reuses the same crate dependency; there is no second HTTP stack.
34
35### Minimal feature combinations
36
37```toml
38# AS2 only (sign, encrypt, OCSP; compression is enabled by default):
39asx-rs = { version = "0.14", features = ["as2", "async-ocsp"] }
40
41# AS4 only (sign, encrypt; compression is enabled by default):
42asx-rs = { version = "0.14", features = ["as4", "async-ocsp"] }
43
44# Both protocols with compression:
45asx-rs = { version = "0.14", features = ["as2", "as4", "compression", "async-ocsp"] }
46
47# AS4 with Peppol/CEF dynamic discovery:
48asx-rs = { version = "0.14", features = ["as4", "client", "dns"] }
49
50# Both protocols, relaxed interop for legacy partners:
51asx-rs = { version = "0.14", features = ["as2", "as4", "interop-relaxed", "async-ocsp"] }
52
53```
54
55> **Note:** `as2` and `as4` are **not** in the default feature set.
56> Adding `asx-rs` without explicit features compiles only the shared
57> infrastructure (`core`, `crypto`, `reliability`, `observability`).
58
59## Security notes
60
61- AS2 trust-verifier traits are intentionally open so applications and tests can
62  supply their own verification backends. Prefer local deterministic test
63  verifiers over crate-exported bypass helpers.
64- PKIX chain validation requires at least one trust-anchor PEM in
65  `CertHandle::trust_anchor_pems` (fail-closed when empty).
66- OCSP freshness checking (thisUpdate/nextUpdate) is enforced automatically
67  when `OcspMode` is not `Disabled`.
68- HTTP egress transports are HTTPS-only.
69*/
70
71// The crate parses MIME, SOAP, XML and CMS straight off the network. Memory
72// safety there is the entire point, so `unsafe` is not merely absent — it
73// cannot be added.
74#![forbid(unsafe_code)]
75
76pub mod core;
77#[cfg(any(feature = "as2", feature = "as4"))]
78pub mod credentials;
79pub mod crypto;
80pub mod http;
81pub mod interop;
82pub mod lifecycle;
83pub mod observability;
84pub mod presets;
85#[cfg(feature = "as4")]
86pub(crate) mod time_utils;
87
88// Compile-time guards for invalid feature combinations.
89#[cfg(all(feature = "server", not(any(feature = "as2", feature = "as4"))))]
90compile_error!(
91    "the `server` feature requires at least one of `as2` or `as4` to be enabled alongside it; \
92     e.g. features = [\"server\", \"as2\"] or features = [\"server\", \"as4\"]"
93);
94
95// Block `testing` in release profile.  The guard uses the `cargo_release_profile`
96// cfg flag emitted by build.rs (derived from the `PROFILE` env var) rather than
97// `not(debug_assertions)`, which can be defeated by
98// `[profile.release] debug-assertions = true` in an embedder's Cargo.toml.
99#[cfg(all(feature = "testing", cargo_release_profile))]
100compile_error!(
101    "the `testing` feature must not be enabled in release builds; \
102     remove `testing` from your feature list for production or release workflows"
103);
104
105#[cfg(feature = "testing")]
106pub mod fixtures;
107#[cfg(feature = "testing")]
108pub mod matrix;
109pub mod reliability;
110#[cfg(feature = "as4")]
111pub mod sbdh;
112#[cfg(any(feature = "as2", feature = "as4"))]
113pub(crate) mod send_pipeline;
114pub mod storage;
115pub mod transport;
116#[cfg(any(feature = "as2", feature = "as4"))]
117pub mod wire;
118
119#[cfg(feature = "as2")]
120pub mod as2;
121
122#[cfg(feature = "as4")]
123pub mod as4;
124
125#[cfg(feature = "client")]
126#[cfg(feature = "as4")]
127pub mod smp;
128
129pub use core::{AsxError, CryptoAdmissionControl, ErrorCode, ErrorContext, Result};
130#[cfg(any(feature = "as2", feature = "as4"))]
131pub use credentials::PartnerCredentials;
132
133#[cfg(test)]
134mod tests {
135    use crate::core::InteropMode;
136
137    #[test]
138    fn default_interop_mode_is_strict() {
139        assert_eq!(InteropMode::default(), InteropMode::Strict);
140    }
141}