zerodds-coap-bridge v1.0 — Spec Coverage

Source: docs/specs/zerodds-coap-bridge-1.0.md

Implementation:

§1 Conformance levels

§1 L1-L6 conformance matrix

Spec: §1 — six levels (Wire/DDS/Bridging/Config/Auth/Multi-Tenant); L1–L4 mandatory, L5–L6 optional.

Repo: —

Tests: —

Status: n/a (informative) — assignment of the levels; the requirements are the items §2 to §12.

§2 CLI surface

§2 zerodds-coap-bridged CLI

Spec: §2 — options --config/--bind/--domain/--dtls-*/--topic/--log-level/--metrics/--version/--help; exit codes 0/1/2/3/4.

Repo: crates/coap-bridge/src/bin/zerodds-coap-bridged.rs, crates/coap-bridge/src/daemon/cli.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed, ::well_known_core_returns_link_format_catalog, ::observe_register_returns_initial_content_with_observe_option, ::unknown_path_returns_bad_request.

Status: done

§3 Config-file format

§3 YAML loader with ENV substitution

Spec: §3 — top-level domain/coap/oscore/topics/content_format/acl/metrics; ENV substitution.

Repo: crates/coap-bridge/src/daemon/config.rs, crates/config/src/parse.rs (the shared parser), crates/coap-bridge/src/daemon/mod.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::make_test_config (config construction). Inline tests in crates/coap-bridge/src/daemon/config.rs::tests.

Status: done

§4 CoAP wire protocol

§4.1 RFC-7252 header + token + options

Spec: §4.1 — a 4-byte header (Ver/T/TKL/Code/Message-ID), token, options, payload marker 0xFF.

Repo: crates/coap-bridge/src/codec.rs, crates/coap-bridge/src/message.rs, crates/coap-bridge/src/option.rs, crates/coap-bridge/src/method_props.rs.

Tests: crates/coap-bridge/src/codec.rs::tests (19 Tests): encodes_minimum_get_request_to_4_byte_header, encode_decode_round_trip_preserves_header_fields, token_length_above_8_is_rejected_on_encode, header_too_short_decode_fails, unsupported_version_decode_fails, reserved_token_length_9_through_15_decode_fails, token_truncated_decode_fails, single_short_option_encodes_in_one_byte_header, option_delta_extended_13_uses_one_extra_byte, option_delta_extended_14_uses_two_extra_bytes, option_length_extended_13_uses_one_extra_byte, delta_encoding_sums_across_multiple_options, payload_marker_separates_options_from_payload, payload_marker_without_payload_is_format_error, options_are_sorted_on_encode, empty_message_round_trip; crates/coap-bridge/src/message.rs::tests (message_type_round_trips_via_bits, code_byte_round_trip, well_known_codes_match_spec_values, code_display_uses_dotted_format); crates/coap-bridge/src/option.rs::tests (critical_unsafe_nocachekey_bits_per_spec_5_4_6, repeatable_options_match_spec_table_4, uint_strips_leading_zero_bytes); crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed.

Status: done

§4.2 POST/PUT/DELETE → DDS write/dispose

Spec: §4.2 — POST → DDS write (2.04 Changed), PUT idempotent, DELETE → dispose; 4.00/4.13/5.00 error mapping.

Repo: crates/coap-bridge/src/daemon/server.rs, crates/coap-bridge/src/bridge.rs, crates/coap-bridge/src/method_props.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed, ::unknown_path_returns_bad_request.

Status: done

§4.3 GET + Observe (RFC 7641) → DDS→CoAP push

Spec: §4.3 — GET with Observe:0 registers, notify per sample with Observe:<seq>; cancel via Observe:1 or RST.

Repo: crates/coap-bridge/src/observe.rs, crates/coap-bridge/src/daemon/server.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::observe_register_returns_initial_content_with_observe_option.

Status: done

§4.4 Block-wise transfer (RFC 7959)

Spec: §4.4 — Block1 (POST) + Block2 (notify); block_size (SZX 16..1024); defragmentation cap.

Repo: crates/coap-bridge/src/blockwise.rs, crates/coap-bridge/src/reliability.rs, crates/coap-bridge/src/option.rs (Block1/Block2 options), crates/coap-bridge/src/daemon/server.rs (block wire-up).

Tests: crates/coap-bridge/src/blockwise.rs::tests (10 tests): block_size_matches_spec_szx_table, szx_7_rejected, round_trip_small_block_value, round_trip_large_block_value, num_too_large_rejected, decode_rejects_bad_length, reassembler_combines_blocks_in_order, out_of_order_block_rejected, intermediate_block_size_must_match, final_block_can_be_smaller; crates/coap-bridge/tests/daemon_e2e.rs::block1_chunked_post_completes_with_2_04_changed, crates/coap-bridge/tests/daemon_e2e.rs::block1_out_of_order_returns_2_31_continue_only_in_order.

Status: done

§4.5 Content-format registry 65000/65001/65002/50/60

Spec: §4.5 — vendor range 65000-65535 for CDR2-LE/BE + CDR1-LE; 50=application/json, 60=application/cbor.

Repo: crates/coap-bridge/src/option.rs (content-format tags), crates/coap-bridge/src/bridge.rs (CDR decoder).

Tests: crates/coap-bridge/src/option.rs::tests::content_format_uses_number_12, crates/coap-bridge/src/codec.rs::tests::representation_carries_content_format_per_spec_5_5, crates/coap-bridge/src/codec.rs::tests::diagnostic_payload_of_error_response_carries_no_content_format; the value 65000 is set by crates/coap-bridge/src/daemon/server.rs and read back by crates/coap-bridge/tests/daemon_e2e.rs::observe_register_returns_initial_content_with_observe_option. 65001, 65002, 50 and 60 do not exist as a registry — see §4.5a.

Status: partial — the option itself and the CDR2-LE value 65000 are covered; the four other values are carried as §4.5a open. ## §5 Topic mapping

§4.5a Content-format values 65001/65002/50/60

Spec: §4.5 — CDR2-BE (65001), CDR1-LE (65002), 50=application/json, 60=application/cbor.

Repo: —

Tests: —

Status: open — the part of §4.5 beyond 65000. The tree carries no registry type and no test for the four values.

§5.1 Slug algorithm DDS → CoAP URI

Spec: §5.1 — lowercase, ::→/, non-[a-z0-9/_-]→_; override per coap_uri_path.

Repo: crates/coap-bridge/src/uri.rs, crates/coap-bridge/src/daemon/config.rs.

Tests: crates/coap-bridge/src/uri.rs::tests (11 tests): parses_basic_coap_uri, parses_coaps_default_port, parses_explicit_port, parses_query_params, parses_empty_path_when_no_slash, rejects_unknown_scheme, rejects_missing_host, rejects_invalid_port, rejects_fragment, default_port_returns_5684_for_coaps, round_trip_path_filtering_strips_empty_segments; the override path crates/coap-bridge/src/daemon/config.rs::tests and crates/coap-bridge/tests/example_yaml_loadback.rs::example_yaml_topics_reach_the_daemon.

Status: done

§5.2 /.well-known/core (RFC 6690) catalog

Spec: §5.2 — /.well-known/core returns a link-format resource list with rt="dds.topic", ct=65000, type="...".

Repo: crates/coap-bridge/src/core_link.rs, crates/coap-bridge/src/daemon/server.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::well_known_core_returns_link_format_catalog.

Status: done

§6 QoS translation

§6 DDS-QoS → CoAP-behavior map

Spec: §6 — Reliable→CON, BestEffort→NON, Volatile/TransientLocal, Lifespan→Max-Age, Deadline→5.03, Liveliness→ping, Partition→filter.

Repo: crates/coap-bridge/src/reliability.rs, crates/coap-bridge/src/observe.rs, crates/coap-bridge/src/bridge.rs, crates/coap-bridge/src/daemon/qos_translation.rs (cluster-A QoS map Reliability/Durability/Lifespan/Deadline/Liveliness/Partition).

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed (reliable POST→write); a QoS matrix in crates/coap-bridge/src/daemon/qos_translation.rs::tests.

Status: done

§7 Security

§7.1 DTLS coaps:// + cipher suites

Spec: §7.1 — “coaps:// mode is enabled via coap.dtls.enabled: true”; the cipher suites §7.1 recommends are TLS_PSK_WITH_AES_128_CCM_8 (PSK mode, RFC 7252 §9.1.3), TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (cert mode) and TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 (hybrid); “Cert rotation via SIGHUP (the daemon re-reads cert/key, sessions are kept)”. The config schema (§3) names coap.dtls.cert_file/key_file/ca_file and the psk list of identity + secret_hex, the CLI (§3) --dtls-psk-id/--dtls-psk/--dtls-cert/ --dtls-key. Auth+ACL run over vendor option 65000 (CoAP application auth token).

Repo: crates/coap-bridge/src/dtls.rs — DtlsMode (RFC 7252 §9.1), DtlsCipherSuite with the three §7.1 suites and their IANA code points, PskStore/PskEntry (lookup per identity, identity hint per RFC 4279 §5.2), parse_secret_hex and DtlsCredentials with effective_cipher_suites/uses_psk. crates/coap-bridge/src/dtls_transport.rs (feature dtls) — load_certificate reads cert_file+key_file as PEM (PKCS#8; a SEC1/PKCS#1 file is refused with the conversion named), load_client_cas turns ca_file into a trust store and switches on RequireAndVerifyClientCert, server_config builds either the PSK or the cert handshake through supported_cipher_suites, DtlsCoapServer::bind_with keeps the UDP listener and the DTLS configuration apart, rotate swaps the configuration used by the next handshake on the same socket, DtlsCoapClient::connect / connect_psk. crates/coap-bridge/src/daemon/config.rs reads the coap.dtls block (cert_file, key_file, ca_file, cipher_suites, psk) and rejects unknown suite names, missing secret_hex fields and a cert_file without its key_file; crates/coap-bridge/src/daemon/cli.rs + crates/coap-bridge/src/bin/zerodds-coap-bridged.rs wire up the four DTLS flags; crates/coap-bridge/src/daemon/server.rs (spawn_dtls_server/dtls_accept_loop) hands the credentials to the listener and performs the rotation on the SIGHUP reload_flag; crates/coap-bridge/src/daemon/security.rs (option-65000 auth wire-up).

Tests: inline in crates/coap-bridge/src/dtls.rs — cipher_suite_names_and_code_points_match_iana, psk_store_looks_up_by_identity_and_refuses_short_secrets, secret_hex_round_trips_and_rejects_garbage, credentials_pick_the_mode_they_were_configured_for plus the validate_dtls_mode cases; crates/coap-bridge/tests/dtls_coap_e2e.rs (feature dtls) — dtls_coap_get_content_roundtrip (handshake + CoAP-GET → 2.05 Content), dtls_psk_handshake_carries_coap (PSK mode, no certificate), dtls_psk_unknown_identity_is_refused, dtls_certificate_files_and_rotation_keep_sessions_alive (cert/key from disk, SIGHUP rotation: a new client handshakes against the new certificate while the session opened before the rotation keeps carrying CoAP), dtls_rejects_a_non_pkcs8_key_file; crates/coap-bridge/tests/security_e2e.rs (option-65000 auth).

Status: done — PSK and cert mode including ca_file client verification, the config and CLI path and the SIGHUP cert rotation are implemented and measured. Of the three suites §7.1 recommends, the endpoint offers TLS_PSK_WITH_AES_128_CCM_8 and TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 (0xc037) is not in webrtc-dtls 0.12’s CipherSuiteId, and supported_cipher_suites refuses to start naming the suite rather than quietly negotiating a different one.

§7.2 OSCORE (RFC 8613)

Spec: §7.2 — master-secret/salt/ID-context, per-kid HKDF sender/ recipient context, replay window 32; daemon refuses unprotected requests with 4.01, protects responses (§8.3) and Observe notifications with its own Partial IV (§4.1.3.5.2); fail-closed without the oscore feature.

Repo: crates/coap-bridge/src/oscore/ — crates/coap-bridge/src/oscore/mod.rs (security context + HKDF key derivation, RFC 8613 §3.2 / RFC 5869), crates/coap-bridge/src/oscore/aead.rs (AES-CCM-16-64- 128, nonce §5.2, AAD §5.4), crates/coap-bridge/src/oscore/message.rs (protect/unprotect for requests §8.1/§8.2 and responses §8.3/§8.4, option class split §4.1.2), crates/coap-bridge/src/oscore/wire.rs (OSCORE option codec §6.1 + anti-replay window §3.2.2, default width 32); crates/coap-bridge/src/daemon/config.rs (oscore: block, spec schema), crates/coap-bridge/src/daemon/oscore_gateway.rs (per-kid server state), crates/coap-bridge/src/daemon/server.rs (unprotect/protect in dispatch + protected notify path).

Tests: crates/coap-bridge/tests/oscore_rfc8613_vectors.rs: c4_protected_request_is_byte_exact, c5_protected_request_is_byte_exact, c6_protected_request_with_kid_context_is_byte_exact, c7_protected_response_is_byte_exact, c8_protected_response_with_partial_iv_is_byte_exact; crates/coap-bridge/tests/daemon_oscore_e2e.rs: protected_post_round_trips_and_replay_is_refused, unprotected_request_is_refused_with_4_01, well_known_core_stays_reachable_in_the_clear, notify_to_protected_observer_arrives_protected, protected_observe_register_is_answered_protected; inline crates/coap-bridge/src/oscore/mod.rs::tests (7), crates/coap-bridge/src/oscore/aead.rs::tests (4), crates/coap-bridge/src/oscore/wire.rs::tests (9), crates/coap-bridge/src/oscore/message.rs::tests (6), crates/coap-bridge/src/daemon/oscore_gateway.rs::tests (6).

Status: done — full OSCORE implementation including the daemon wiring (ADR 0010); correctness anchored byte-exact to the RFC 8613 Appendix C vectors C.1-C.8.

§7.3 ACL per topic

Spec: §7.3 — subject = vendor-auth-token ID (CoAP option 65000) or a cert subject DN.

Repo: crates/coap-bridge/src/daemon/config.rs (ACL fields), crates/coap-bridge/src/daemon/security.rs, crates/bridge-security/src/acl.rs; crates/coap-bridge/src/dtls_transport.rs::DtlsCoapSession::peer_identity (the DTLS identity for auth.mode: mtls: the client certificate’s subject DN per RFC 4514 — a rule may name the fingerprint mtls:<SHA-256> too — or psk:<identity>). Before, the DTLS identity did not reach the request path; mtls answered every request 4.01 (from the code). auth.jwt as in the WS bridge.

Tests: crates/coap-bridge/tests/daemon_dtls_e2e.rs::mtls_takes_the_psk_identity_as_the_acl_subject, crates/coap-bridge/tests/daemon_dtls_e2e.rs::mtls_without_dtls_is_a_config_error, crates/coap-bridge/tests/daemon_dtls_e2e.rs::mtls_takes_the_certificate_dn_as_the_acl_subject (CN=sensor-9 2.04, CN=other of the same CA 4.03), crates/coap-bridge/src/daemon/security.rs::tests::jwt_without_a_public_key_is_a_config_error, crates/coap-bridge/tests/security_e2e.rs::acl_write_deny_yields_4_03_forbidden, crates/coap-bridge/tests/security_e2e.rs::acl_observe_register_deny_yields_4_03, crates/coap-bridge/tests/security_e2e.rs::auth_bearer_token_in_option_is_accepted, crates/coap-bridge/tests/security_e2e.rs::auth_missing_bearer_token_yields_4_01_unauthorized; crates/coap-bridge/src/daemon/security.rs::tests::coap_acl_subscribe_check, ::coap_bearer_in_option_accepted, ::coap_missing_option_with_bearer_rejected; crates/coap-bridge/tests/example_yaml_loadback.rs::example_yaml_acl_reaches_the_daemon.

Status: done

§8 Operations + observability

§8.1 Structured JSON logging

Spec: §8.1 — JSON log + a --log-level switch.

Repo: —

Tests: —

Status: open — crates/coap-bridge/src/daemon/cli.rs::tests covers the flag splitting, but nothing tests the JSON log form or the effect of --log-level. ### §8.2 Prometheus metrics

Spec: §8.2 — --metrics CLI + 10 counter/gauge families.

Repo: crates/coap-bridge/src/daemon/server.rs, crates/coap-bridge/src/daemon/config.rs, crates/coap-bridge/src/daemon/runtime_common.rs (counter/gauge families cluster-A wire-up).

Tests: crates/coap-bridge/src/daemon/runtime_common.rs::tests::metrics_register_idempotent, crates/coap-bridge/src/daemon/runtime_common.rs::tests::admin_endpoint_serves_metrics, crates/coap-bridge/src/daemon/runtime_common.rs::tests::catalog_render_contains_topic_fields.

Status: done

§8.3 OTLP spans

Spec: §8.3 — OTEL_EXPORTER_OTLP_ENDPOINT enables span emission.

Repo: —

Tests: —

Status: open — crates/coap-bridge/src/daemon/runtime_common.rs builds the OtlpConfig, but nothing tests that OTEL_EXPORTER_OTLP_ENDPOINT is read or that a span is emitted per CoAP exchange. ## §9 Lifecycle

§9.1 Startup sequence

Spec: §9.1 — config → DTLS → DCPS → reader/writer → UDP bind 5683/5684 → signal handler.

Repo: crates/coap-bridge/src/daemon/mod.rs, crates/coap-bridge/src/bin/zerodds-coap-bridged.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed.

Status: done

§9.2 Shutdown SIGTERM/SIGINT/SIGHUP

Spec: §9.2 — graceful drain max 30 s, observer deregister, cleanup; SIGHUP TLS+ACL reload.

Repo: crates/coap-bridge/src/daemon/server.rs::DaemonHandle::shutdown, ::end_observations (the pumps first, then every observer gets a notification 5.03 without Observe option with its token, RFC 7641 §4.2; before, the shutdown dropped the registry without a message), crates/coap-bridge/src/bin/zerodds-coap-bridged.rs (waits for the stop flag; the binary was still running 3 s after SIGTERM before, measured), ::reload (ACL and auth, DTLS material through the DTLS reload).

Tests: crates/coap-bridge/tests/daemon_e2e.rs::the_shutdown_ends_every_observation_with_5_03, ::the_binary_exits_0_on_sigterm; crates/coap-bridge/tests/security_e2e.rs::sighup_applies_the_reloaded_acl.

Status: done

§10 Cross-vendor

§10 RTPS peer + libcoap/californium/aiocoap

Spec: §10 — the daemon is a normal RTPS peer; the CoAP side against libcoap/californium/aiocoap/Eclipse-Wakaama.

Repo: crates/coap-bridge/src/daemon/server.rs.

Tests: crates/coap-bridge/tests/cross_vendor.rs::libcoap_post_to_zerodds_daemon_returns_2_04_changed, crates/coap-bridge/tests/cross_vendor.rs::libcoap_get_well_known_core_returns_catalog, crates/coap-bridge/tests/cross_vendor.rs::libcoap_observe_receives_notification (all #[ignore], feature cross-vendor-tests); the RTPS side crates/coap-bridge/src/bridge.rs::tests::bridge_apply_write_then_read_round_trip. Californium and aiocoap have not been run against the daemon — see §10a.

Status: partial — libcoap is measured, Californium and aiocoap are not; the missing part is carried as §10a open. ### §10a Client matrix Californium/aiocoap

Spec: §10 — the CoAP side runs against Californium and aiocoap.

Repo: —

Tests: —

Status: open — the part of §10 and §12.3 beyond libcoap. crates/coap-bridge/tests/cross_vendor.rs knows only libcoap.


§11 Packaging

§11 Linux/macOS/Windows/Docker layout

Spec: §11 — binary zerodds-coap-bridged; configs/services/Docker; manuals.

Repo: packaging/linux/systemd/zerodds-coap-bridged.service, packaging/macos/launchd/org.zerodds.coap-bridged.plist, packaging/macos/homebrew/zerodds-coap-bridge.rb, packaging/windows/services/Install-Services.ps1, packaging/docker/coap-bridged/, packaging/linux/configs/coap-bridged.yaml.example, man/man1/zerodds-coap-bridged.1, man/man5/zerodds-coap-bridged.yaml.5.

Tests: crates/coap-bridge/tests/example_yaml_loadback.rs::{example_yaml_parses_without_error, example_yaml_key_fields_match_intent, example_yaml_topics_reach_the_daemon, example_yaml_acl_reaches_the_daemon, example_yaml_has_no_unknown_top_level_keys} (the shipped example configuration through the real parser, with the values it states); tools/traceability/tests/bridge_config_manpages.rs::{every_example_key_is_documented_in_the_man_page, the_man_page_names_no_key_the_example_does_not_declare, the_pre_spec_vocabulary_is_gone_from_pages_and_examples, every_man_page_names_its_parser_and_what_an_unknown_key_does} (the manual page and the example file name the same keys).

Status: done

§12 Testing

§12.1 Unit tests per module

Spec: §12.1 — config/coap_codec/block_assembler/observe_table/dtls/oscore/dds_pump, ≥ 5 tests each.

Repo: crates/coap-bridge/src/{daemon/config.rs,codec.rs,message.rs,option.rs,blockwise.rs,observe.rs,reliability.rs,uri.rs,core_link.rs,bridge.rs,dtls.rs,multicast.rs,matching.rs,caching_proxy.rs,method_props.rs}.

Tests: Inline #[cfg(test)] mod tests per module: crates/coap-bridge/src/codec.rs::tests::empty_message_round_trip (19), crates/coap-bridge/src/option.rs::tests::repeatable_options_match_spec_table_4 (12), crates/coap-bridge/src/message.rs::tests::code_byte_round_trip (7), crates/coap-bridge/src/blockwise.rs::tests::round_trip_large_block_value (10), crates/coap-bridge/src/bridge.rs::tests::bridge_discover_lists_keys (16), crates/coap-bridge/src/observe.rs::tests (11), crates/coap-bridge/src/reliability.rs::tests (16), crates/coap-bridge/src/caching_proxy.rs::tests (15), crates/coap-bridge/src/dtls.rs::tests (15), crates/coap-bridge/src/multicast.rs::tests (9), crates/coap-bridge/src/uri.rs::tests::parses_basic_coap_uri (11), crates/coap-bridge/src/matching.rs::tests (7), crates/coap-bridge/src/core_link.rs::tests (8), crates/coap-bridge/src/method_props.rs::tests (5); plus crates/coap-bridge/tests/fuzz_smoke.rs::fuzz_coap_decode_no_panic, ::empty_input_returns_err_not_panic, ::single_byte_inputs_no_panic.

Status: done

§12.2 Integration tests bridge_e2e

Spec: §12.2 — spawn the daemon, libcoap client, POST/Observe/Block round-trip.

Repo: crates/coap-bridge/src/bin/zerodds-coap-bridged.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed, ::well_known_core_returns_link_format_catalog, ::observe_register_returns_initial_content_with_observe_option, ::unknown_path_returns_bad_request.

Status: done

§12.3 Multi-vendor cross_vendor.rs

Spec: §12.3 — a Cyclone-DDS subscriber + libcoap/californium client in compose.

Repo: crates/coap-bridge/tests/cross_vendor.rs (cluster-C cross-vendor harness).

Tests: crates/coap-bridge/tests/cross_vendor.rs::libcoap_post_to_zerodds_daemon_returns_2_04_changed, crates/coap-bridge/tests/cross_vendor.rs::libcoap_get_well_known_core_returns_catalog, crates/coap-bridge/tests/cross_vendor.rs::libcoap_observe_receives_notification; the DDS side crates/coap-bridge/src/bridge.rs::tests::bridge_apply_write_then_read_round_trip. The client matrix beyond libcoap is not measured — see §10a.

Status: partial — libcoap and the DDS side are covered, the rest of the client matrix is not. ## §13 Cross-references

Spec: §13 — library crates/coap-bridge/, RFC 7252/7641/7959/8613, wire format, deployment, sister daemons.

Repo: —

Tests: —

Status: n/a (informative) — reference list.

§14 Versioning

§14 SemVer bump rules

Spec: §14 — patch=bugfixes, minor=additive config (e.g. content-format IDs), major=wire-protocol change.

Repo: —

Tests: —

Status: n/a (informative) — rule for assigning the version number of a release, not a property of the daemon.


Audit status

18 done / 3 partial / 4 open / 0 blocked / 3 n/a (informative).

Test run: cargo test -p zerodds-coap-bridge --features daemon,dtls,oscore — 251 tests green, 0 failed (218 unit tests plus the daemon, DTLS, OSCORE and security end-to-end suites).

Open items: zerodds-coap-bridge-1.0.open.en.md.

zerodds-coap-bridge v1.0 — Spec-Coverage

Quelle: docs/specs/zerodds-coap-bridge-1.0.md

Implementation:

§1 Conformance-Levels

§1 L1-L6 Conformance-Matrix

Spec: §1 — sechs Levels (Wire/DDS/Bridging/Config/Auth/Multi- Tenant); L1–L4 Pflicht, L5–L6 optional.

Repo: —

Tests: —

Status: n/a (informative) — Zuordnung der Levels; die Anforderungen sind die Items §2 bis §12.

§2 CLI-Surface

§2 zerodds-coap-bridged CLI

Spec: §2 — Optionen --config/--bind/--domain/--dtls-*/ --topic/--log-level/--metrics/--version/--help; Exit-Codes 0/1/2/3/4.

Repo: crates/coap-bridge/src/bin/zerodds-coap-bridged.rs, crates/coap-bridge/src/daemon/cli.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed, ::well_known_core_returns_link_format_catalog, ::observe_register_returns_initial_content_with_observe_option, ::unknown_path_returns_bad_request.

Status: done

§3 Config-File-Format

§3 YAML-Loader mit ENV-Substitution

Spec: §3 — Top-Level domain/coap/oscore/topics/ content_format/acl/metrics; ENV-Substitution.

Repo: crates/coap-bridge/src/daemon/config.rs, crates/config/src/parse.rs (the shared parser), crates/coap-bridge/src/daemon/mod.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::make_test_config (Config-Construction). Inline-Tests in crates/coap-bridge/src/daemon/config.rs::tests.

Status: done

§4 CoAP-Wire-Protocol

§4.1 RFC-7252 Header + Token + Options

Spec: §4.1 — 4-Byte-Header (Ver/T/TKL/Code/Message-ID), Token, Options, Payload-Marker 0xFF.

Repo: crates/coap-bridge/src/codec.rs, crates/coap-bridge/src/message.rs, crates/coap-bridge/src/option.rs, crates/coap-bridge/src/method_props.rs.

Tests: crates/coap-bridge/src/codec.rs::tests (19 Tests): encodes_minimum_get_request_to_4_byte_header, encode_decode_round_trip_preserves_header_fields, token_length_above_8_is_rejected_on_encode, header_too_short_decode_fails, unsupported_version_decode_fails, reserved_token_length_9_through_15_decode_fails, token_truncated_decode_fails, single_short_option_encodes_in_one_byte_header, option_delta_extended_13_uses_one_extra_byte, option_delta_extended_14_uses_two_extra_bytes, option_length_extended_13_uses_one_extra_byte, delta_encoding_sums_across_multiple_options, payload_marker_separates_options_from_payload, payload_marker_without_payload_is_format_error, options_are_sorted_on_encode, empty_message_round_trip; crates/coap-bridge/src/message.rs::tests (message_type_round_trips_via_bits, code_byte_round_trip, well_known_codes_match_spec_values, code_display_uses_dotted_format); crates/coap-bridge/src/option.rs::tests (critical_unsafe_nocachekey_bits_per_spec_5_4_6, repeatable_options_match_spec_table_4, uint_strips_leading_zero_bytes); crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed.

Status: done

§4.2 POST/PUT/DELETE → DDS-Write/Dispose

Spec: §4.2 — POST → DDS-Write (2.04 Changed), PUT idempotent, DELETE → Dispose; 4.00/4.13/5.00 Error-Mapping.

Repo: crates/coap-bridge/src/daemon/server.rs, crates/coap-bridge/src/bridge.rs, crates/coap-bridge/src/method_props.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed, ::unknown_path_returns_bad_request.

Status: done

§4.3 GET + Observe (RFC 7641) → DDS→CoAP-Push

Spec: §4.3 — GET mit Observe:0 registriert, Notify pro Sample mit Observe:<seq>; Cancel via Observe:1 oder RST.

Repo: crates/coap-bridge/src/observe.rs, crates/coap-bridge/src/daemon/server.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::observe_register_returns_initial_content_with_observe_option.

Status: done

§4.4 Block-Wise-Transfer (RFC 7959)

Spec: §4.4 — Block1 (POST) + Block2 (Notify); block_size (SZX 16..1024); Defragmentation-Cap.

Repo: crates/coap-bridge/src/blockwise.rs, crates/coap-bridge/src/reliability.rs, crates/coap-bridge/src/option.rs (Block1/Block2-Options), crates/coap-bridge/src/daemon/server.rs (Block-Wireup).

Tests: crates/coap-bridge/src/blockwise.rs::tests (10 Tests): block_size_matches_spec_szx_table, szx_7_rejected, round_trip_small_block_value, round_trip_large_block_value, num_too_large_rejected, decode_rejects_bad_length, reassembler_combines_blocks_in_order, out_of_order_block_rejected, intermediate_block_size_must_match, final_block_can_be_smaller; crates/coap-bridge/tests/daemon_e2e.rs::block1_chunked_post_completes_with_2_04_changed, crates/coap-bridge/tests/daemon_e2e.rs::block1_out_of_order_returns_2_31_continue_only_in_order.

Status: done

§4.5 Content-Format-Registry 65000/65001/65002/50/60

Spec: §4.5 — Vendor-Range 65000-65535 für CDR2-LE/BE + CDR1-LE; 50=application/json, 60=application/cbor.

Repo: crates/coap-bridge/src/option.rs (Content-Format-Tags), crates/coap-bridge/src/bridge.rs (CDR-Decoder).

Tests: crates/coap-bridge/src/option.rs::tests::content_format_uses_number_12, crates/coap-bridge/src/codec.rs::tests::representation_carries_content_format_per_spec_5_5, crates/coap-bridge/src/codec.rs::tests::diagnostic_payload_of_error_response_carries_no_content_format; den Wert 65000 setzt crates/coap-bridge/src/daemon/server.rs und crates/coap-bridge/tests/daemon_e2e.rs::observe_register_returns_initial_content_with_observe_option liest ihn zurück. 65001, 65002, 50 und 60 gibt es als Registry nicht — siehe §4.5a.

Status: partial — die Option selbst und der CDR2-LE-Wert 65000 sind geprüft; die vier weiteren Werte werden als §4.5a open geführt. ## §5 Topic-Mapping

§4.5a Content-Format-Werte 65001/65002/50/60

Spec: §4.5 — CDR2-BE (65001), CDR1-LE (65002), 50=application/json, 60=application/cbor.

Repo: —

Tests: —

Status: open — der Teil von §4.5 jenseits 65000. Im Baum steht kein Registry-Typ und kein Test für die vier Werte.

§5.1 Slug-Algorithmus DDS → CoAP-URI

Spec: §5.1 — Lowercase, ::→/, non-[a-z0-9/_-]→_; Override per coap_uri_path.

Repo: crates/coap-bridge/src/uri.rs, crates/coap-bridge/src/daemon/config.rs.

Tests: crates/coap-bridge/src/uri.rs::tests (11 Tests): parses_basic_coap_uri, parses_coaps_default_port, parses_explicit_port, parses_query_params, parses_empty_path_when_no_slash, rejects_unknown_scheme, rejects_missing_host, rejects_invalid_port, rejects_fragment, default_port_returns_5684_for_coaps, round_trip_path_filtering_strips_empty_segments; den Override-Pfad crates/coap-bridge/src/daemon/config.rs::tests und crates/coap-bridge/tests/example_yaml_loadback.rs::example_yaml_topics_reach_the_daemon.

Status: done

§5.2 /.well-known/core (RFC 6690) Catalog

Spec: §5.2 — /.well-known/core liefert Link-Format-Resource-List mit rt="dds.topic", ct=65000, type="...".

Repo: crates/coap-bridge/src/core_link.rs, crates/coap-bridge/src/daemon/server.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::well_known_core_returns_link_format_catalog.

Status: done

§6 QoS-Translation

§6 DDS-QoS → CoAP-Behavior Map

Spec: §6 — Reliable→CON, BestEffort→NON, Volatile/TransientLocal, Lifespan→Max-Age, Deadline→5.03, Liveliness→Ping, Partition→Filter.

Repo: crates/coap-bridge/src/reliability.rs, crates/coap-bridge/src/observe.rs, crates/coap-bridge/src/bridge.rs, crates/coap-bridge/src/daemon/qos_translation.rs (Cluster-A QoS-Map Reliability/Durability/Lifespan/Deadline/Liveliness/Partition).

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed (reliable POST→Write); QoS-Matrix in crates/coap-bridge/src/daemon/qos_translation.rs::tests.

Status: done

§7 Security

§7.1 DTLS coaps:// + Cipher-Suites

Spec: §7.1 — „coaps://-Mode aktiviert über coap.dtls.enabled: true“; die Cipher-Suites, die §7.1 empfiehlt, sind TLS_PSK_WITH_AES_128_CCM_8 (PSK-Mode, RFC 7252 §9.1.3), TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (Cert-Mode) und TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 (Hybrid); „Cert-Rotation via SIGHUP (Daemon liest cert/key neu, Sessions halten)”. Das Config-Schema (§3) nennt coap.dtls.cert_file/key_file/ca_file und die psk-Liste aus identity + secret_hex, die CLI (§3) --dtls-psk-id/--dtls-psk/ --dtls-cert/--dtls-key. Auth+ACL laufen über Vendor-Option 65000 (CoAP-Application-Auth-Token).

Repo: crates/coap-bridge/src/dtls.rs — DtlsMode (RFC 7252 §9.1), DtlsCipherSuite mit den drei §7.1-Suiten samt IANA-Code-Points, PskStore/PskEntry (Lookup je Identity, Identity-Hint nach RFC 4279 §5.2), parse_secret_hex und DtlsCredentials mit effective_cipher_suites/uses_psk. crates/coap-bridge/src/dtls_transport.rs (Feature dtls) — load_certificate liest cert_file+key_file als PEM (PKCS#8; eine SEC1/PKCS#1-Datei wird mit dem Konvertierungshinweis abgewiesen), load_client_cas legt ca_file als Trust-Store an und schaltet RequireAndVerifyClientCert, server_config baut daraus den PSK- oder den Cert-Handshake mit supported_cipher_suites, DtlsCoapServer::bind_with trennt UDP-Listener und DTLS-Konfiguration, rotate tauscht die Konfiguration für den nächsten Handshake auf demselben Socket, DtlsCoapClient::connect / connect_psk. crates/coap-bridge/src/daemon/config.rs liest den coap.dtls-Block (cert_file, key_file, ca_file, cipher_suites, psk) und weist unbekannte Suite-Namen, fehlende secret_hex-Felder und eine cert_file-ohne-key_file-Konfiguration ab; crates/coap-bridge/src/daemon/cli.rs + crates/coap-bridge/src/bin/zerodds-coap-bridged.rs verdrahten die vier DTLS-Flags; crates/coap-bridge/src/daemon/server.rs (spawn_dtls_server/dtls_accept_loop) gibt die Credentials an den Listener und führt beim SIGHUP-reload_flag die Rotation aus; crates/coap-bridge/src/daemon/security.rs (Option-65000-Auth-Wireup).

Tests: crates/coap-bridge/src/dtls.rs inline — cipher_suite_names_and_code_points_match_iana, psk_store_looks_up_by_identity_and_refuses_short_secrets, secret_hex_round_trips_and_rejects_garbage, credentials_pick_the_mode_they_were_configured_for plus die validate_dtls_mode-Fälle; crates/coap-bridge/tests/dtls_coap_e2e.rs (Feature dtls) — dtls_coap_get_content_roundtrip (Handshake + CoAP-GET → 2.05 Content), dtls_psk_handshake_carries_coap (PSK-Mode ohne Zertifikat), dtls_psk_unknown_identity_is_refused, dtls_certificate_files_and_rotation_keep_sessions_alive (Cert/Key von Platte, SIGHUP-Rotation: der neue Client handshaked gegen das neue Zertifikat, die vor der Rotation geöffnete Session trägt weiter CoAP), dtls_rejects_a_non_pkcs8_key_file; crates/coap-bridge/tests/security_e2e.rs (Option-65000-Auth).

Status: done — PSK- und Cert-Mode inklusive ca_file-Client-Verifikation, Config- und CLI-Pfad und SIGHUP-Cert-Rotation sind implementiert und gemessen. Von den drei Suiten, die §7.1 empfiehlt, bietet der Endpoint TLS_PSK_WITH_AES_128_CCM_8 und TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 an; TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 (0xc037) führt webrtc-dtls 0.12 in CipherSuiteId nicht, und supported_cipher_suites verweigert den Start mit Nennung der Suite, statt still auf eine andere auszuweichen.

§7.2 OSCORE (RFC 8613)

Spec: §7.2 — Master-Secret/Salt/ID-Context, HKDF-Sender/Recipient- Context pro kid, Replay-Window 32; der Daemon weist ungeschützte Requests mit 4.01 ab, schützt Responses (§8.3) und Observe- Notifications mit eigener Partial IV (§4.1.3.5.2); fail-closed ohne oscore-Feature.

Repo: crates/coap-bridge/src/oscore/ — crates/coap-bridge/src/oscore/mod.rs (Security-Context + HKDF-Key-Derivation, RFC 8613 §3.2 / RFC 5869), crates/coap-bridge/src/oscore/aead.rs (AES-CCM-16-64- 128, Nonce §5.2, AAD §5.4), crates/coap-bridge/src/oscore/message.rs (Protect/Unprotect für Requests §8.1/§8.2 und Responses §8.3/§8.4, Option-Klassen-Split §4.1.2), crates/coap-bridge/src/oscore/wire.rs (OSCORE-Option-Codec §6.1 + Anti-Replay-Window §3.2.2, Default- Breite 32); crates/coap-bridge/src/daemon/config.rs (oscore:-Block, Spec-Schema), crates/coap-bridge/src/daemon/oscore_gateway.rs (Server- State pro kid), crates/coap-bridge/src/daemon/server.rs (Unprotect/Protect in dispatch + geschützter Notify-Pfad).

Tests: crates/coap-bridge/tests/oscore_rfc8613_vectors.rs: c4_protected_request_is_byte_exact, c5_protected_request_is_byte_exact, c6_protected_request_with_kid_context_is_byte_exact, c7_protected_response_is_byte_exact, c8_protected_response_with_partial_iv_is_byte_exact; crates/coap-bridge/tests/daemon_oscore_e2e.rs: protected_post_round_trips_and_replay_is_refused, unprotected_request_is_refused_with_4_01, well_known_core_stays_reachable_in_the_clear, notify_to_protected_observer_arrives_protected, protected_observe_register_is_answered_protected; inline crates/coap-bridge/src/oscore/mod.rs::tests (7), crates/coap-bridge/src/oscore/aead.rs::tests (4), crates/coap-bridge/src/oscore/wire.rs::tests (9), crates/coap-bridge/src/oscore/message.rs::tests (6), crates/coap-bridge/src/daemon/oscore_gateway.rs::tests (6).

Status: done — volle OSCORE-Implementation inklusive Daemon- Verdrahtung (ADR 0010); Korrektheit byte-exakt gegen die RFC-8613- Appendix-C-Vektoren C.1-C.8 verankert.

§7.3 ACL pro Topic

Spec: §7.3 — Subject = Vendor-Auth-Token-ID (CoAP-Option-65000) oder Cert-Subject-DN.

Repo: crates/coap-bridge/src/daemon/config.rs (ACL-Felder), crates/coap-bridge/src/daemon/security.rs, crates/bridge-security/src/acl.rs; crates/coap-bridge/src/dtls_transport.rs::DtlsCoapSession::peer_identity (die DTLS-Identität für auth.mode: mtls: der Subject-DN des Client-Zertifikats nach RFC 4514 — eine Regel darf auch den Fingerprint mtls:<SHA-256> nennen — oder psk:<Identität>). Vorher erreichte die DTLS-Identität den Request-Pfad nicht; mtls beantwortete jede Anfrage mit 4.01 (aus dem Code). auth.jwt wie in der WS-Bridge.

Tests: crates/coap-bridge/tests/daemon_dtls_e2e.rs::mtls_takes_the_psk_identity_as_the_acl_subject, crates/coap-bridge/tests/daemon_dtls_e2e.rs::mtls_without_dtls_is_a_config_error, crates/coap-bridge/tests/daemon_dtls_e2e.rs::mtls_takes_the_certificate_dn_as_the_acl_subject (CN=sensor-9 2.04, CN=other derselben CA 4.03), crates/coap-bridge/src/daemon/security.rs::tests::jwt_without_a_public_key_is_a_config_error, crates/coap-bridge/tests/security_e2e.rs::acl_write_deny_yields_4_03_forbidden, crates/coap-bridge/tests/security_e2e.rs::acl_observe_register_deny_yields_4_03, crates/coap-bridge/tests/security_e2e.rs::auth_bearer_token_in_option_is_accepted, crates/coap-bridge/tests/security_e2e.rs::auth_missing_bearer_token_yields_4_01_unauthorized; crates/coap-bridge/src/daemon/security.rs::tests::coap_acl_subscribe_check, ::coap_bearer_in_option_accepted, ::coap_missing_option_with_bearer_rejected; crates/coap-bridge/tests/example_yaml_loadback.rs::example_yaml_acl_reaches_the_daemon.

Status: done

§8 Operations + Observability

§8.1 Strukturiertes JSON-Logging

Spec: §8.1 — JSON-Log + --log-level-Switch.

Repo: —

Tests: —

Status: open — crates/coap-bridge/src/daemon/cli.rs::tests prüft die Flag-Zerlegung, aber kein Test prüft die JSON-Log-Form oder die Wirkung von --log-level. ### §8.2 Prometheus-Metrics

Spec: §8.2 — --metrics-CLI + 10 Counter/Gauge-Familien.

Repo: crates/coap-bridge/src/daemon/server.rs, crates/coap-bridge/src/daemon/config.rs, crates/coap-bridge/src/daemon/runtime_common.rs (Counter/Gauge- Familien Cluster-A-Wireup).

Tests: crates/coap-bridge/src/daemon/runtime_common.rs::tests::metrics_register_idempotent, crates/coap-bridge/src/daemon/runtime_common.rs::tests::admin_endpoint_serves_metrics, crates/coap-bridge/src/daemon/runtime_common.rs::tests::catalog_render_contains_topic_fields.

Status: done

§8.3 OTLP-Spans

Spec: §8.3 — OTEL_EXPORTER_OTLP_ENDPOINT aktiviert Span-Emission.

Repo: —

Tests: —

Status: open — crates/coap-bridge/src/daemon/runtime_common.rs baut die OtlpConfig, aber kein Test prüft, dass OTEL_EXPORTER_OTLP_ENDPOINT gelesen wird oder dass pro CoAP-Exchange ein Span entsteht. ## §9 Lifecycle

§9.1 Startup-Sequence

Spec: §9.1 — Config → DTLS → DCPS → Reader/Writer → UDP-Bind 5683/ 5684 → Signal-Handler.

Repo: crates/coap-bridge/src/daemon/mod.rs, crates/coap-bridge/src/bin/zerodds-coap-bridged.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed.

Status: done

§9.2 Shutdown SIGTERM/SIGINT/SIGHUP

Spec: §9.2 — Graceful Drain max 30 s, Observer-Deregister, Cleanup; SIGHUP TLS+ACL-Reload.

Repo: crates/coap-bridge/src/daemon/server.rs::DaemonHandle::shutdown, ::end_observations (Pumps zuerst, dann an jeden Observer eine Notification 5.03 ohne Observe-Option mit seinem Token, RFC 7641 §4.2; vorher verwarf der Shutdown die Registry ohne Nachricht), crates/coap-bridge/src/bin/zerodds-coap-bridged.rs (wartet auf das Stop-Flag; das Binary lief vorher 3 s nach SIGTERM weiter, gemessen), ::reload (ACL und Auth, DTLS-Material über den DTLS-Reload).

Tests: crates/coap-bridge/tests/daemon_e2e.rs::the_shutdown_ends_every_observation_with_5_03, ::the_binary_exits_0_on_sigterm; crates/coap-bridge/tests/security_e2e.rs::sighup_applies_the_reloaded_acl.

Status: done

§10 Cross-Vendor

§10 RTPS-Peer + libcoap/californium/aiocoap

Spec: §10 — Daemon ist normaler RTPS-Peer; CoAP-Seite gegen libcoap/californium/aiocoap/Eclipse-Wakaama.

Repo: crates/coap-bridge/src/daemon/server.rs.

Tests: crates/coap-bridge/tests/cross_vendor.rs::libcoap_post_to_zerodds_daemon_returns_2_04_changed, crates/coap-bridge/tests/cross_vendor.rs::libcoap_get_well_known_core_returns_catalog, crates/coap-bridge/tests/cross_vendor.rs::libcoap_observe_receives_notification (alle #[ignore], Feature cross-vendor-tests); die RTPS-Seite crates/coap-bridge/src/bridge.rs::tests::bridge_apply_write_then_read_round_trip. Californium und aiocoap hat niemand gegen den Daemon laufen lassen — siehe §10a.

Status: partial — libcoap ist gemessen, Californium und aiocoap nicht; der fehlende Teil wird als §10a open geführt. ### §10a Client-Matrix Californium/aiocoap

Spec: §10 — die CoAP-Seite läuft gegen Californium und aiocoap.

Repo: —

Tests: —

Status: open — der Teil von §10 und §12.3 jenseits libcoap. crates/coap-bridge/tests/cross_vendor.rs kennt nur libcoap.


§11 Packaging

§11 Linux/macOS/Windows/Docker Layout

Spec: §11 — Binary zerodds-coap-bridged; Configs/Services/Docker; Manuals.

Repo: packaging/linux/systemd/zerodds-coap-bridged.service, packaging/macos/launchd/org.zerodds.coap-bridged.plist, packaging/macos/homebrew/zerodds-coap-bridge.rb, packaging/windows/services/Install-Services.ps1, packaging/docker/coap-bridged/, packaging/linux/configs/coap-bridged.yaml.example, man/man1/zerodds-coap-bridged.1, man/man5/zerodds-coap-bridged.yaml.5.

Tests: crates/coap-bridge/tests/example_yaml_loadback.rs::{example_yaml_parses_without_error, example_yaml_key_fields_match_intent, example_yaml_topics_reach_the_daemon, example_yaml_acl_reaches_the_daemon, example_yaml_has_no_unknown_top_level_keys} (die ausgelieferte Beispiel-Konfiguration durch den echten Parser, mit den Werten, die sie nennt); tools/traceability/tests/bridge_config_manpages.rs::{every_example_key_is_documented_in_the_man_page, the_man_page_names_no_key_the_example_does_not_declare, the_pre_spec_vocabulary_is_gone_from_pages_and_examples, every_man_page_names_its_parser_and_what_an_unknown_key_does} (die Handbuchseite und die Beispieldatei nennen dieselben Schlüssel).

Status: done

§12 Testing

§12.1 Unit-Tests pro Modul

Spec: §12.1 — config/coap_codec/block_assembler/observe_table/dtls/ oscore/dds_pump je ≥ 5 Tests.

Repo: crates/coap-bridge/src/{daemon/config.rs,codec.rs,message.rs,option.rs,blockwise.rs,observe.rs,reliability.rs,uri.rs,core_link.rs,bridge.rs,dtls.rs,multicast.rs,matching.rs,caching_proxy.rs,method_props.rs}.

Tests: Inline #[cfg(test)] mod tests pro Modul: crates/coap-bridge/src/codec.rs::tests::empty_message_round_trip (19), crates/coap-bridge/src/option.rs::tests::repeatable_options_match_spec_table_4 (12), crates/coap-bridge/src/message.rs::tests::code_byte_round_trip (7), crates/coap-bridge/src/blockwise.rs::tests::round_trip_large_block_value (10), crates/coap-bridge/src/bridge.rs::tests::bridge_discover_lists_keys (16), crates/coap-bridge/src/observe.rs::tests (11), crates/coap-bridge/src/reliability.rs::tests (16), crates/coap-bridge/src/caching_proxy.rs::tests (15), crates/coap-bridge/src/dtls.rs::tests (15), crates/coap-bridge/src/multicast.rs::tests (9), crates/coap-bridge/src/uri.rs::tests::parses_basic_coap_uri (11), crates/coap-bridge/src/matching.rs::tests (7), crates/coap-bridge/src/core_link.rs::tests (8), crates/coap-bridge/src/method_props.rs::tests (5); dazu crates/coap-bridge/tests/fuzz_smoke.rs::fuzz_coap_decode_no_panic, ::empty_input_returns_err_not_panic, ::single_byte_inputs_no_panic.

Status: done

§12.2 Integration-Tests bridge_e2e

Spec: §12.2 — Spawn Daemon, libcoap-Client, POST/Observe/Block Roundtrip.

Repo: crates/coap-bridge/src/bin/zerodds-coap-bridged.rs.

Tests: crates/coap-bridge/tests/daemon_e2e.rs::post_to_configured_path_returns_2_04_changed, ::well_known_core_returns_link_format_catalog, ::observe_register_returns_initial_content_with_observe_option, ::unknown_path_returns_bad_request.

Status: done

§12.3 Multi-Vendor cross_vendor.rs

Spec: §12.3 — Cyclone-DDS-Subscriber + libcoap/californium-Client im Compose.

Repo: crates/coap-bridge/tests/cross_vendor.rs (Cluster-C Cross-Vendor-Harness).

Tests: crates/coap-bridge/tests/cross_vendor.rs::libcoap_post_to_zerodds_daemon_returns_2_04_changed, crates/coap-bridge/tests/cross_vendor.rs::libcoap_get_well_known_core_returns_catalog, crates/coap-bridge/tests/cross_vendor.rs::libcoap_observe_receives_notification; die DDS-Seite crates/coap-bridge/src/bridge.rs::tests::bridge_apply_write_then_read_round_trip. Die Client-Matrix jenseits libcoap ist nicht gemessen — siehe §10a.

Status: partial — libcoap und die DDS-Seite sind geprüft, die restliche Client-Matrix nicht. ## §13 Cross-References

§13 Verwandte Library + RFCs + Daemons

Spec: §13 — Library crates/coap-bridge/, RFC 7252/7641/7959/8613, Wire-Format, Deployment, Sister-Daemons.

Repo: —

Tests: —

Status: n/a (informative) — Verweisliste.

§14 Versioning

§14 SemVer-Bump-Regeln

Spec: §14 — Patch=Bugfixes, Minor=additive Config (z.B. Content-Format-IDs), Major=Wire-Protocol-Change.

Repo: —

Tests: —

Status: n/a (informative) — Regel für die Vergabe der Versionsnummer eines Release, keine Eigenschaft des Daemons.


Audit-Status

18 done / 3 partial / 4 open / 0 blocked / 3 n/a (informative).

Test-Lauf: cargo test -p zerodds-coap-bridge --features daemon,dtls,oscore — 251 Tests grün, 0 failed (218 Unit-Tests plus die End-to-End-Suiten für Daemon, DTLS, OSCORE und Security).

Offene Punkte: zerodds-coap-bridge-1.0.open.md.