zerodds-corba-bridge v1.0 — Spec Coverage

Source: docs/specs/zerodds-corba-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-corba-bridged CLI

Spec: §2 — --config/--set/--check-config, the short forms --iiop-bind/--ssliop-bind/--domain/--naming-service/--orb-id/ --tls-cert+--tls-key/--topic/--log-level/--metrics as --set of their file key; exit codes 0–5.

Repo: crates/corba-dds-bridge/src/bin/zerodds-corba-bridged.rs (thin CLI), crates/corba-dds-bridge/src/bridge_daemon.rs::run (exit codes 2 bind, 3 DDS, 4 TLS), man/man1/zerodds-corba-bridged.1.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::{version_flag_emits_one_line, unknown_arg_yields_exit_1, dump_iors_writes_stringified_ior, a_certificate_that_does_not_load_is_exit_4}.

Status: partial — exit code 5 (NameService) does not occur while the NameService registration is not built (§4.1); exit codes 2 and 3 are set in the code but have no test of their own.

§3 Config-file format

§3 YAML loader with ENV substitution

Spec: §3 — top level domain/log_level/corba/mappings/acl/ metrics; zerodds-config subset with include:, drop-ins and ${VAR}; unknown keys and wrong types prevent the start; what is not built is refused.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (DaemonConfig::from_config, read_mapping, is_key), crates/config/ (parser, layering, ${VAR}), packaging/linux/configs/corba-bridged.yaml.example, man/man5/zerodds-corba-bridged.yaml.5.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{the_shipped_example_reads_as_it_says, what_the_daemon_does_not_build_is_refused}, crates/config/tests/layering.rs::environment_references_expand_before_the_parse.

Status: done

§4 GIOP/IIOP wire protocol

§4.1 IOR generation IIOP/SSLIOP/Components

Spec: §4.1 — one IOR per mapping with type_id = repo_id, an IIOP profile (host/port/object_key) and components; SSL component for SSLIOP; ior_file; NameService bind.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (build_ior, ior_lines, corba.iiop.advertise_host).

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::dump_iors_writes_stringified_ior, crates/corba-dds-bridge/tests/cross_vendor.rs::catior_reads_the_ior_the_daemon_prints (omniORB catior reads the IOR the daemon prints; behind --features cross-vendor-tests and #[ignore], measured on the Linux test host), crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (omniORB calls through the IOR from ior_file).

crates/corba-dds-bridge/src/bridge_daemon.rs::tests::the_ior_carries_code_sets_and_the_ssl_component, crates/corba-ior/src/components.rs::tests::a_code_sets_encapsulation_pads_after_the_byte_order_octet (the encapsulation aligns from its byte-order octet; catior called the unpadded form “Broken component with tag 1”).

Status: partial — TAG_CODE_SETS and TAG_SSL_SEC_TRANS built, catior reads both; no TAG_ORB_TYPE (no OMG-assigned ORB type); publish_to_naming: true is refused (NameService not built).

§4.2 GIOP frame format header + body

Spec: §4.2 — 12-byte header (GIOP/major/minor/flags/msg_type) + message_size + CDR body; msg_type 0–7.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::serve_connection (header read, max_message_size, MessageError), codec in crates/corba-giop/.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::a_request_to_an_unknown_object_is_object_not_exist, crates/corba-giop/src/header.rs::{magic_bytes_match_spec, header_size_is_12_bytes, round_trip_big_endian_request_header}, crates/corba-giop/src/message_type.rs::message_type_values_match_spec_table_15_1, crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant.

Status: done

§4.3 Request-reply mapping CORBA→DDS

Spec: §4.3 — GIOP request → mapping lookup → DDS request sample (u64 request_id + arguments, XCDR1 in the GIOP byte order) → correlated reply sample (request_id, reply_status, reserved, body) → GIOP reply; TIMEOUT, OBJECT_NOT_EXIST, BAD_OPERATION, NO_PERMISSION, NO_IMPLEMENT (GIOP < 1.2), TRANSIENT, MARSHAL; CancelRequest.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (on_request, on_reply, timeout_loop, system_exception_body).

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (omniORB 4.3.3 on the Linux test host: add → 42 through a DDS backend, never → TIMEOUT, wrong operation → BAD_OPERATION), crates/corba-dds-bridge/tests/bridge_e2e.rs::a_request_to_an_unknown_object_is_object_not_exist, crates/corba-dds-bridge/src/bridge_daemon.rs::tests::a_system_exception_body_is_the_giop_layout.

Status: partial — NO_PERMISSION, NO_IMPLEMENT, TRANSIENT on a DDS write error, MARSHAL and CancelRequest are built but have no test of their own; a correlation_id other than request_id is refused.

§4.4 Notify mapping DDS→CORBA

Spec: §4.4 — DDS sample on notify_topic → oneway GIOP 1.2 request to every target in targets (corbaloc: or IOR); an XCDR2 sample is dropped and counted; reconnect after an error.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (Notifier, resolve_target).

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (three DDS samples reach an omniORB servant as on_value), crates/corba-dds-bridge/src/bridge_daemon.rs::tests::corbaloc_and_ior_targets_resolve.

Status: done

§4.5 Object-key generation SHA-256

Spec: §4.5 — object_key = SHA-256(repo_id + "\0" + canonical)[..16].

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::object_key.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::the_shutdown_answers_pending_requests_then_closes_the_connection (the test addresses the mapped operation through object_key), crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (omniORB addresses through the key in the IOR).

Status: done

§4.6 Fragment handling GIOP 1.1+

Spec: §4.6 — messages above fragment_size as fragments, each but the last ending on an 8-octet boundary of the message; inbound reassembly.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (write_giop, Reassembly).

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{outbound_fragments_end_on_8_octet_boundaries, a_fragmented_message_is_put_back_together}, crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (echo of 200 000 bytes, fragment_size 16384, fragmented in both directions, against omniORB 4.3.3).

Status: done

§4.7 LocateRequest/Reply OBJECT_HERE/UNKNOWN/FORWARD

Spec: §4.7 — LocateReply with OBJECT_HERE/UNKNOWN_OBJECT/ OBJECT_FORWARD.

Repo: —

Tests: —

Status: open — OBJECT_HERE and UNKNOWN_OBJECT are built in the daemon (crates/corba-dds-bridge/src/bridge_daemon.rs::serve_connection, branch LocateRequest), but without a test (tests/cross_vendor.rs::locate_request_handler_classifies_known_and_unknown checks src/locate.rs of the library, not the daemon); OBJECT_FORWARD is not built.

§5 Topic mapping

§5.1 DDS-topic slug per operation

Spec: §5.1 — MarketData::Quote::request_quote::Request / ...::Reply as default; override via request_topic.dds_name.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::slug.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::the_slug_of_section_5_1.

Status: done

§5.2 Type discovery via idl-rust codegen

Spec: §5.2 — one generated request/reply type per mapping with an exception variant; IDL in /var/lib/zerodds/corba-bridge/. Built: the fixed layout of §4.3.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (on_request, on_reply: fixed layout).

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (the DDS backend declares request and reply type after the layout).

Status: partial — IDL generation per mapping and the exception variant in the reply type are not built; the bridge does not know the IDL type and passes the argument bytes through.

§6 QoS translation

§6 DDS-QoS → CORBA-behavior map

Spec: §6 — Reliability/Durability/Lifespan/Deadline/Liveliness/ Partition; BEST_EFFORT only for notify.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::read_mapping (qos.reliability, qos.durability; best_effort refused for request-reply).

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{the_shipped_example_reads_as_it_says, what_the_daemon_does_not_build_is_refused}.

Status: partial — reliability and durability go to the DDS entities; a replay per request hash for TRANSIENT_LOCAL, lifespan, deadline and partition are not built.

§7 Security

§7.1 SSLIOP TLS-over-IIOP + SSL component Tag 0x06

Spec: §7.1 — corba.ssliop.enabled enables TLS on ssliop.bind, require_client_cert against ca_file; SSL component in the IOR.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (TlsShared, accept_loop), crates/corba-dds-bridge/src/daemon_runtime.rs::build_corba_tls_config.

Tests: crates/corba-dds-bridge/tests/security_e2e.rs::{build_corba_tls_config_loads_self_signed, build_corba_tls_config_with_mtls_succeeds, build_corba_tls_config_rejects_missing_cert}, crates/corba-dds-bridge/tests/bridge_e2e.rs::a_certificate_that_does_not_load_is_exit_4.

crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_over_ssliop_passes_the_acl_with_the_allowed_certificate_only (omniORB 4.3.3 with libomnisslTP4, clientTransportRule * ssl, port from TAG_SSL_SEC_TRANS, client certificate required; the Linux test host).

Status: done

§7.2 CSIv2 SAS_ContextElement + GSSUP

Spec: §7.2 — SAS_ContextElement, EstablishTrustInClient/Target, GSSUP user/password fallback.

Repo: —

Tests: —

Status: open — CSIv2 is not built in the daemon; csiv2.enabled: true is refused (crates/corba-dds-bridge/src/bridge_daemon.rs, test what_the_daemon_does_not_build_is_refused). The building blocks crates/corba-csiv2/ and crates/corba-dds-bridge/src/csiv2_wire.rs are not wired to the daemon.

§7.3 ACL per mapping

Spec: §7.3 — subject from the client certificate’s subject DN; a rule with a matching subject lists the repo_id in allow_invoke (prefix with *); otherwise default_deny; refused: NO_PERMISSION.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (subject_allowed, on_request), crates/bridge-security/src/ctx.rs::extract_mtls_subject.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::acl_rules_match_subjects_and_repo_id_prefixes.

crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_over_ssliop_passes_the_acl_with_the_allowed_certificate_only (certificate A passes and runs into TIMEOUT, certificate B of the same CA gets NO_PERMISSION; omniORB 4.3.3, Linux test host).

The subject is the subject DN per RFC 4514 (crates/bridge-security/src/ctx.rs::mtls_subject_from_der, checked against openssl x509 -nameopt RFC2253); a rule may name the fingerprint mtls:<SHA-256> instead (as the omniORB test does). The GSSUP username of §7.2 depends on CSIv2 (§7.2, open).

Status: done

§8 Operations + observability

§8.1 Structured JSON logging

Spec: §8.1 — JSON log with timestamp, level, event and the fields of the event; --log-level.

Repo: —

Tests: —

Status: open — crates/corba-dds-bridge/src/bridge_daemon.rs (log, event_level, level_rank) writes one JSON line per event to stderr with level, event and the event fields, filtered by log_level; timestamp is missing, and no test checks the form of a line.

§8.2 Prometheus metrics

Spec: §8.2 — ten families zerodds_corba_bridge_* (requests/replies/pending/latency/timeouts/…).

Repo: crates/corba-dds-bridge/src/daemon_runtime.rs (BridgeMetrics, serve_admin_endpoints), crates/corba-dds-bridge/src/bin/zerodds-corba-bridged.rs (metrics_addr_for).

Tests: crates/corba-dds-bridge/src/daemon_runtime.rs::tests::{metrics_register_idempotent, admin_endpoint_serves_metrics_path}, crates/corba-dds-bridge/tests/bridge_e2e.rs::the_metrics_of_section_8_2_count_a_timed_out_request (through --metrics: a request without a backend counts as system_exception, timeout, reply sent, sample published; LocateRequest; red without the count on the timeout path).

Status: done — the families of §8.2 except csiv2_failures_total (CSIv2 not built, §7.2).

§8.3 OTLP spans

Spec: §8.3 — OTEL_EXPORTER_OTLP_ENDPOINT → spans per GIOP exchange (giop.request, dds.publish, dds.subscribe, giop.reply).

Repo: crates/corba-dds-bridge/src/daemon_runtime.rs (otlp_config_from_env, spawn_otlp_flush_loop).

Tests: crates/corba-dds-bridge/src/daemon_runtime.rs::tests::otlp_config_parses_endpoint.

Status: partial — the exporter starts from the environment, but bridge_daemon.rs creates no spans.

§9 Lifecycle

§9.1 Startup sequence

Spec: §9.1 — config → TLS → DCPS → reader/writer per mapping → IIOP/SSLIOP bind → NameService rebind → signal handler.

Repo: crates/corba-dds-bridge/src/bin/zerodds-corba-bridged.rs, crates/corba-dds-bridge/src/bridge_daemon.rs::run.

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant, crates/corba-dds-bridge/tests/bridge_e2e.rs::a_request_to_an_unknown_object_is_object_not_exist.

Status: partial — the NameService rebind does not occur while publish_to_naming is not built; the other steps run in the order of the spec.

§9.2 Shutdown SIGTERM/SIGINT/SIGHUP

Spec: §9.2 — drain of at most 30 s: new requests TRANSIENT, pending ones get their reply or TIMEOUT, the rest TRANSIENT after 30 s; then CloseConnection; SIGHUP reloads TLS and ACL.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (drain, DRAIN_LIMIT, Conn), crates/corba-dds-bridge/src/daemon_runtime.rs::install_signal_watcher.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::the_shutdown_answers_pending_requests_then_closes_the_connection (request during the drain → TRANSIENT, pending request → TIMEOUT, then CloseConnection and EOF; red without drain).

crates/corba-dds-bridge/tests/bridge_e2e.rs::{a_sighup_applies_the_new_acl_and_a_broken_file_keeps_the_old_one, a_sighup_serves_new_connections_with_the_new_certificate} (SIGHUP to the binary; both red without apply_reload).

Status: partial — the branch after 30 s (drain_expired) has no test.

§10 Cross-vendor

§10 RTPS peer + TAO/JacORB/omniORB/Ice-Java

Spec: §10 — the daemon is a normal RTPS peer; CORBA side against TAO/JacORB/omniORB/Ice-Java CORBA compat.

Repo: crates/corba-dds-bridge/tests/omniorb_e2e.rs, crates/corba-dds-bridge/tests/omniorb/{Calc.idl, calc_client.cc, listener_server.cc}.

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (#[ignore], needs omniidl, g++ and libomniORB4; green on the Linux test host against omniORB 4.3.3), crates/corba-dds-bridge/tests/cross_vendor.rs::catior_reads_the_ior_the_daemon_prints.

Status: partial — measured against omniORB. TAO, JacORB and Ice-Java are not measured; the rest is the open item §10/§12.

§11 Packaging

§11 Linux/macOS/Windows/Docker layout

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

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

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::the_shipped_example_reads_as_it_says (the shipped example configuration through the real loader), 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, every_man_page_names_its_parser_and_what_an_unknown_key_does}, tools/traceability/tests/deployment_layout.rs.

Status: done

§12 Testing

§12.1 Unit tests per module

Spec: §12.1 — config/giop_codec/iiop_transport/ior/object_key/ csiv2/dds_pump/request_correlator with ≥ 5 tests each.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs, crates/corba-giop/, crates/corba-iiop/, crates/corba-ior/.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{the_shipped_example_reads_as_it_says, the_slug_of_section_5_1, what_the_daemon_does_not_build_is_refused, a_system_exception_body_is_the_giop_layout, outbound_fragments_end_on_8_octet_boundaries, a_fragmented_message_is_put_back_together, corbaloc_and_ior_targets_resolve, acl_rules_match_subjects_and_repo_id_prefixes}.

Status: partial — the daemon has eight unit tests in one module; the clause’s split with ≥ 5 tests per module does not exist, and csiv2 is not built.

§12.2 Integration tests bridge_e2e

Spec: §12.2 — daemon, a foreign CORBA client, a DDS service process, round trip through the bridge.

Repo: crates/corba-dds-bridge/tests/omniorb_e2e.rs, crates/corba-dds-bridge/tests/bridge_e2e.rs.

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant, crates/corba-dds-bridge/tests/bridge_e2e.rs::{a_request_to_an_unknown_object_is_object_not_exist, the_shutdown_answers_pending_requests_then_closes_the_connection, a_certificate_that_does_not_load_is_exit_4, dump_iors_writes_stringified_ior}.

Status: done

§12.3 Multi-vendor cross_vendor.rs

Spec: §12.3 — Cyclone DDS subscriber + TAO client + ZeroDDS CORBA bridge in a compose.

Repo: crates/corba-dds-bridge/tests/cross_vendor.rs.

Tests: crates/corba-dds-bridge/tests/cross_vendor.rs::{omniidl_smoke_check_present, catior_reads_the_ior_the_daemon_prints} — both behind --features cross-vendor-tests and #[ignore].

Status: partial — the DDS side behind the bridge is ZeroDDS; a Cyclone DDS backend and a TAO client are not measured. Cross-ref: the open item below.

§10/§12 Cross-vendor harness — TAO, JacORB, Ice-Java, Cyclone

Spec: §10 + §12.3 — the CORBA side against TAO, JacORB and Ice-Java; a Cyclone DDS backend behind the bridge.

Repo: —

Tests: —

Status: open — measured is omniORB with a ZeroDDS backend (tests/omniorb_e2e.rs). Plan: run the same cases with a TAO and a JacORB client from crates/corba-interop/competitors/ and with a Cyclone DDS backend after the layout of §4.3 on the Linux test host.

§13 Cross-references

Spec: §13 — library crates/corba-dds-bridge/, crates/corba-iiop/, crates/corba-giop/ and the Rust codegen in crates/lang-rules/; OMG GIOP/IIOP/CSIv2/SSLIOP; wire format; deployment.

Repo: —

Tests: —

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

§14 Versioning

§14 SemVer bump rules

Spec: §14 — patch=bugfixes, minor=additive mapping configuration, major=wire-protocol changes.

Repo: —

Tests: —

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


Audit status

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

Test run: cargo test -p zerodds-corba-dds-bridge — 51 lib tests, 6 bridge_e2e, 9 security_e2e green, 0 failed (macOS). tests/omniorb_e2e.rs (#[ignore]) and tests/cross_vendor.rs (--features cross-vendor-tests, #[ignore]) run on the Linux test host against omniORB 4.3.3.

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

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

Quelle: docs/specs/zerodds-corba-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-corba-bridged CLI

Spec: §2 — --config/--set/--check-config, die Kurzformen --iiop-bind/--ssliop-bind/--domain/--naming-service/--orb-id/ --tls-cert+--tls-key/--topic/--log-level/--metrics als --set ihres Datei-Schlüssels; Exit-Codes 0–5.

Repo: crates/corba-dds-bridge/src/bin/zerodds-corba-bridged.rs (dünne CLI), crates/corba-dds-bridge/src/bridge_daemon.rs::run (Exit-Codes 2 Bind, 3 DDS, 4 TLS), man/man1/zerodds-corba-bridged.1.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::{version_flag_emits_one_line, unknown_arg_yields_exit_1, dump_iors_writes_stringified_ior, a_certificate_that_does_not_load_is_exit_4}.

Status: partial — Exit-Code 5 (NameService) entfällt, solange die NameService-Registrierung nicht gebaut ist (§4.1); Exit 2 und 3 sind im Code gesetzt, aber ohne eigenen Test.

§3 Config-File-Format

§3 YAML-Loader mit ENV-Substitution

Spec: §3 — Top-Level domain/log_level/corba/mappings/acl/ metrics; zerodds-config-Teilmenge mit include:, Drop-ins und ${VAR}; unbekannte Schlüssel und falsche Typen verhindern den Start; nicht Gebautes wird abgelehnt.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (DaemonConfig::from_config, read_mapping, is_key), crates/config/ (Parser, Schichtung, ${VAR}), packaging/linux/configs/corba-bridged.yaml.example, man/man5/zerodds-corba-bridged.yaml.5.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{the_shipped_example_reads_as_it_says, what_the_daemon_does_not_build_is_refused}, crates/config/tests/layering.rs::environment_references_expand_before_the_parse.

Status: done

§4 GIOP/IIOP-Wire-Protocol

§4.1 IOR-Generation IIOP/SSLIOP/Components

Spec: §4.1 — ein IOR pro Mapping mit type_id = repo_id, IIOP-Profil (host/port/object_key) und Components; SSL-Component bei SSLIOP; ior_file; NameService-Bind.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (build_ior, ior_lines, corba.iiop.advertise_host).

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::dump_iors_writes_stringified_ior, crates/corba-dds-bridge/tests/cross_vendor.rs::catior_reads_the_ior_the_daemon_prints (omniORB-catior liest die IOR, die der Daemon ausgibt; hinter --features cross-vendor-tests und #[ignore], auf dem Linux-Testhost gemessen), crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (omniORB ruft über die IOR aus ior_file).

crates/corba-dds-bridge/src/bridge_daemon.rs::tests::the_ior_carries_code_sets_and_the_ssl_component, crates/corba-ior/src/components.rs::tests::a_code_sets_encapsulation_pads_after_the_byte_order_octet (Encapsulation richtet ab dem Byte-Order-Oktett aus; die ungepolsterte Form nannte catior „Broken component with tag 1“).

Status: partial — TAG_CODE_SETS und TAG_SSL_SEC_TRANS gebaut, catior liest beide; kein TAG_ORB_TYPE (keine OMG-vergebene ORB-Kennung); publish_to_naming: true wird abgelehnt (NameService nicht gebaut).

§4.2 GIOP-Frame-Format Header + Body

Spec: §4.2 — 12-Byte-Header (GIOP/major/minor/flags/msg_type) + message_size + CDR-Body; msg_type 0–7.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::serve_connection (Header lesen, max_message_size, MessageError), Codec in crates/corba-giop/.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::a_request_to_an_unknown_object_is_object_not_exist, crates/corba-giop/src/header.rs::{magic_bytes_match_spec, header_size_is_12_bytes, round_trip_big_endian_request_header}, crates/corba-giop/src/message_type.rs::message_type_values_match_spec_table_15_1, crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant.

Status: done

§4.3 Request-Reply-Mapping CORBA→DDS

Spec: §4.3 — GIOP-Request → Mapping-Lookup → DDS-Request-Sample (u64 request_id + Argumente, XCDR1 in GIOP-Byte-Reihenfolge) → korrelierter Reply-Sample (request_id, reply_status, reserved, Body) → GIOP-Reply; TIMEOUT, OBJECT_NOT_EXIST, BAD_OPERATION, NO_PERMISSION, NO_IMPLEMENT (GIOP < 1.2), TRANSIENT, MARSHAL; CancelRequest.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (on_request, on_reply, timeout_loop, system_exception_body).

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (omniORB 4.3.3 auf dem Linux-Testhost: add → 42 über ein DDS-Backend, never → TIMEOUT, falsche Operation → BAD_OPERATION), crates/corba-dds-bridge/tests/bridge_e2e.rs::a_request_to_an_unknown_object_is_object_not_exist, crates/corba-dds-bridge/src/bridge_daemon.rs::tests::a_system_exception_body_is_the_giop_layout.

Status: partial — NO_PERMISSION, NO_IMPLEMENT, TRANSIENT bei DDS-Schreibfehler, MARSHAL und CancelRequest sind gebaut, aber ohne eigenen Test; correlation_id außer request_id wird abgelehnt.

§4.4 Notify-Mapping DDS→CORBA

Spec: §4.4 — DDS-Sample auf notify_topic → oneway GIOP-1.2-Request an jedes Ziel in targets (corbaloc: oder IOR); XCDR2-Sample verworfen und gezählt; Neuaufbau nach Fehler.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (Notifier, resolve_target).

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (drei DDS-Samples erreichen einen omniORB-Servant als on_value), crates/corba-dds-bridge/src/bridge_daemon.rs::tests::corbaloc_and_ior_targets_resolve.

Status: done

§4.5 Object-Key-Generation SHA-256

Spec: §4.5 — object_key = SHA-256(repo_id + "\0" + canonical)[..16].

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::object_key.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::the_shutdown_answers_pending_requests_then_closes_the_connection (der Test adressiert die Mapping-Operation über object_key), crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (omniORB adressiert über den Key der IOR).

Status: done

§4.6 Fragment-Handling GIOP 1.1+

Spec: §4.6 — Nachrichten über fragment_size als Fragmente, jedes außer dem letzten auf einer 8-Oktett-Grenze der Nachricht endend; Reassembly inbound.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (write_giop, Reassembly).

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{outbound_fragments_end_on_8_octet_boundaries, a_fragmented_message_is_put_back_together}, crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (echo über 200 000 Byte, fragment_size 16384, in beide Richtungen fragmentiert, gegen omniORB 4.3.3).

Status: done

§4.7 LocateRequest/Reply OBJECT_HERE/UNKNOWN/FORWARD

Spec: §4.7 — LocateReply mit OBJECT_HERE/UNKNOWN_OBJECT/ OBJECT_FORWARD.

Repo: —

Tests: —

Status: open — OBJECT_HERE und UNKNOWN_OBJECT sind im Daemon gebaut (crates/corba-dds-bridge/src/bridge_daemon.rs::serve_connection, Zweig LocateRequest), aber ohne Test (tests/cross_vendor.rs::locate_request_handler_classifies_known_and_unknown prüft src/locate.rs der Bibliothek, nicht den Daemon); OBJECT_FORWARD ist nicht gebaut.

§5 Topic-Mapping

§5.1 DDS-Topic-Slug per Operation

Spec: §5.1 — MarketData::Quote::request_quote::Request / ...::Reply als Default; Override per request_topic.dds_name.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::slug.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::the_slug_of_section_5_1.

Status: done

§5.2 Type-Discovery via idl-rust Codegen

Spec: §5.2 — pro Mapping ein generierter Request-/Reply-Typ mit Exception-Variante; IDL in /var/lib/zerodds/corba-bridge/. Gebaut: das feste Layout aus §4.3.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (on_request, on_reply: festes Layout).

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (das DDS-Backend deklariert Request- und Reply-Typ nach dem Layout).

Status: partial — die IDL-Generierung pro Mapping und die Exception-Variante im Reply-Typ sind nicht gebaut; die Bridge kennt den IDL-Typ nicht und reicht die Argument-Bytes durch.

§6 QoS-Translation

§6 DDS-QoS → CORBA-Behavior Map

Spec: §6 — Reliability/Durability/Lifespan/Deadline/Liveliness/ Partition; BEST_EFFORT nur für Notify.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs::read_mapping (qos.reliability, qos.durability; best_effort für Request-Reply abgelehnt).

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{the_shipped_example_reads_as_it_says, what_the_daemon_does_not_build_is_refused}.

Status: partial — Reliability und Durability gehen an die DDS-Entities; ein Replay pro Request-Hash für TRANSIENT_LOCAL, Lifespan, Deadline und Partition sind nicht gebaut.

§7 Security

§7.1 SSLIOP TLS-over-IIOP + SSL-Component Tag 0x06

Spec: §7.1 — corba.ssliop.enabled aktiviert TLS auf ssliop.bind, require_client_cert gegen ca_file; SSL-Component im IOR.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (TlsShared, accept_loop), crates/corba-dds-bridge/src/daemon_runtime.rs::build_corba_tls_config.

Tests: crates/corba-dds-bridge/tests/security_e2e.rs::{build_corba_tls_config_loads_self_signed, build_corba_tls_config_with_mtls_succeeds, build_corba_tls_config_rejects_missing_cert}, crates/corba-dds-bridge/tests/bridge_e2e.rs::a_certificate_that_does_not_load_is_exit_4.

crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_over_ssliop_passes_the_acl_with_the_allowed_certificate_only (omniORB 4.3.3 mit libomnisslTP4, clientTransportRule * ssl, Port aus TAG_SSL_SEC_TRANS, Client-Zertifikat verlangt; Linux-Testhost).

Status: done

§7.2 CSIv2 SAS_ContextElement + GSSUP

Spec: §7.2 — SAS_ContextElement, EstablishTrustInClient/Target, GSSUP-User/Pass-Fallback.

Repo: —

Tests: —

Status: open — CSIv2 ist im Daemon nicht gebaut; csiv2.enabled: true wird abgelehnt (crates/corba-dds-bridge/src/bridge_daemon.rs, Test what_the_daemon_does_not_build_is_refused). Die Bausteine crates/corba-csiv2/ und crates/corba-dds-bridge/src/csiv2_wire.rs sind nicht an den Daemon angebunden.

§7.3 ACL pro Mapping

Spec: §7.3 — Subject aus dem Subject-DN des Client-Zertifikats; Regel mit passendem Subject führt die repo_id in allow_invoke (Präfix mit *); sonst default_deny; verweigert: NO_PERMISSION.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (subject_allowed, on_request), crates/bridge-security/src/ctx.rs::extract_mtls_subject.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::acl_rules_match_subjects_and_repo_id_prefixes.

crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_over_ssliop_passes_the_acl_with_the_allowed_certificate_only (Zertifikat A passiert und läuft in TIMEOUT, Zertifikat B derselben CA bekommt NO_PERMISSION; omniORB 4.3.3, Linux-Testhost).

Das Subject ist der Subject-DN nach RFC 4514 (crates/bridge-security/src/ctx.rs::mtls_subject_from_der, gegen openssl x509 -nameopt RFC2253 geprüft); eine Regel darf stattdessen den Fingerprint mtls:<SHA-256> nennen (so der omniORB-Test). Der GSSUP-Username aus §7.2 hängt an CSIv2 (§7.2, open).

Status: done

§8 Operations + Observability

§8.1 Strukturiertes JSON-Logging

Spec: §8.1 — JSON-Log mit timestamp, level, event und den Feldern des Ereignisses; --log-level.

Repo: —

Tests: —

Status: open — crates/corba-dds-bridge/src/bridge_daemon.rs (log, event_level, level_rank) schreibt eine JSON-Zeile pro Ereignis auf stderr mit level, event und den Ereignisfeldern, gefiltert nach log_level; timestamp fehlt, und kein Test prüft die Form einer Zeile.

§8.2 Prometheus-Metrics

Spec: §8.2 — zehn Familien zerodds_corba_bridge_* (requests/replies/pending/latency/timeouts/…).

Repo: crates/corba-dds-bridge/src/daemon_runtime.rs (BridgeMetrics, serve_admin_endpoints), crates/corba-dds-bridge/src/bin/zerodds-corba-bridged.rs (metrics_addr_for).

Tests: crates/corba-dds-bridge/src/daemon_runtime.rs::tests::{metrics_register_idempotent, admin_endpoint_serves_metrics_path}, crates/corba-dds-bridge/tests/bridge_e2e.rs::the_metrics_of_section_8_2_count_a_timed_out_request (über --metrics: ein Request ohne Backend zählt als system_exception, Timeout, gesendeter Reply, veröffentlichtes Sample; LocateRequest; ohne die Zählung im Timeout-Pfad rot).

Status: done — die Familien aus §8.2 außer csiv2_failures_total (CSIv2 nicht gebaut, §7.2).

§8.3 OTLP-Spans

Spec: §8.3 — OTEL_EXPORTER_OTLP_ENDPOINT → Spans pro GIOP-Exchange (giop.request, dds.publish, dds.subscribe, giop.reply).

Repo: crates/corba-dds-bridge/src/daemon_runtime.rs (otlp_config_from_env, spawn_otlp_flush_loop).

Tests: crates/corba-dds-bridge/src/daemon_runtime.rs::tests::otlp_config_parses_endpoint.

Status: partial — der Exporter wird aus der Umgebung gestartet, aber bridge_daemon.rs erzeugt keine Spans.

§9 Lifecycle

§9.1 Startup-Sequence

Spec: §9.1 — Config → TLS → DCPS → Reader/Writer pro Mapping → IIOP/SSLIOP-Bind → NameService-Rebind → Signal-Handler.

Repo: crates/corba-dds-bridge/src/bin/zerodds-corba-bridged.rs, crates/corba-dds-bridge/src/bridge_daemon.rs::run.

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant, crates/corba-dds-bridge/tests/bridge_e2e.rs::a_request_to_an_unknown_object_is_object_not_exist.

Status: partial — der NameService-Rebind entfällt, solange publish_to_naming nicht gebaut ist; die übrigen Schritte laufen in der Reihenfolge der Spec.

§9.2 Shutdown SIGTERM/SIGINT/SIGHUP

Spec: §9.2 — Drain max. 30 s: neue Requests TRANSIENT, offene bekommen Reply oder TIMEOUT, der Rest nach 30 s TRANSIENT; dann CloseConnection; SIGHUP lädt TLS und ACL neu.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs (drain, DRAIN_LIMIT, Conn), crates/corba-dds-bridge/src/daemon_runtime.rs::install_signal_watcher.

Tests: crates/corba-dds-bridge/tests/bridge_e2e.rs::the_shutdown_answers_pending_requests_then_closes_the_connection (Request während des Drains → TRANSIENT, offener Request → TIMEOUT, dann CloseConnection und EOF; ohne drain rot).

crates/corba-dds-bridge/tests/bridge_e2e.rs::{a_sighup_applies_the_new_acl_and_a_broken_file_keeps_the_old_one, a_sighup_serves_new_connections_with_the_new_certificate} (SIGHUP an das Binary; ohne apply_reload beide rot).

Status: partial — der Zweig nach 30 s (drain_expired) hat keinen Test.

§10 Cross-Vendor

§10 RTPS-Peer + TAO/JacORB/omniORB/Ice-Java

Spec: §10 — Daemon ist normaler RTPS-Peer; CORBA-Seite gegen TAO/JacORB/omniORB/Ice-Java-CORBA-Compat.

Repo: crates/corba-dds-bridge/tests/omniorb_e2e.rs, crates/corba-dds-bridge/tests/omniorb/{Calc.idl, calc_client.cc, listener_server.cc}.

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant (#[ignore], braucht omniidl, g++ und libomniORB4; auf dem Linux-Testhost gegen omniORB 4.3.3 grün), crates/corba-dds-bridge/tests/cross_vendor.rs::catior_reads_the_ior_the_daemon_prints.

Status: partial — gegen omniORB gemessen. TAO, JacORB und Ice-Java sind nicht gemessen; der Rest steht im open-Item §10/§12.

§11 Packaging

§11 Linux/macOS/Windows/Docker Layout

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

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

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::the_shipped_example_reads_as_it_says (die ausgelieferte Beispiel-Konfiguration durch den echten Loader), 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, every_man_page_names_its_parser_and_what_an_unknown_key_does}, tools/traceability/tests/deployment_layout.rs.

Status: done

§12 Testing

§12.1 Unit-Tests pro Modul

Spec: §12.1 — config/giop_codec/iiop_transport/ior/object_key/ csiv2/dds_pump/request_correlator je ≥ 5 Tests.

Repo: crates/corba-dds-bridge/src/bridge_daemon.rs, crates/corba-giop/, crates/corba-iiop/, crates/corba-ior/.

Tests: crates/corba-dds-bridge/src/bridge_daemon.rs::tests::{the_shipped_example_reads_as_it_says, the_slug_of_section_5_1, what_the_daemon_does_not_build_is_refused, a_system_exception_body_is_the_giop_layout, outbound_fragments_end_on_8_octet_boundaries, a_fragmented_message_is_put_back_together, corbaloc_and_ior_targets_resolve, acl_rules_match_subjects_and_repo_id_prefixes}.

Status: partial — der Daemon hat acht Unit-Tests in einem Modul; die Aufteilung der Klausel mit ≥ 5 Tests pro Modul gibt es nicht, und csiv2 ist nicht gebaut.

§12.2 Integration-Tests bridge_e2e

Spec: §12.2 — Daemon, ein fremder CORBA-Client, ein DDS-Service-Prozess, Roundtrip über die Bridge.

Repo: crates/corba-dds-bridge/tests/omniorb_e2e.rs, crates/corba-dds-bridge/tests/bridge_e2e.rs.

Tests: crates/corba-dds-bridge/tests/omniorb_e2e.rs::omniorb_calls_reach_a_dds_backend_and_dds_samples_reach_an_omniorb_servant, crates/corba-dds-bridge/tests/bridge_e2e.rs::{a_request_to_an_unknown_object_is_object_not_exist, the_shutdown_answers_pending_requests_then_closes_the_connection, a_certificate_that_does_not_load_is_exit_4, dump_iors_writes_stringified_ior}.

Status: done

§12.3 Multi-Vendor cross_vendor.rs

Spec: §12.3 — Cyclone-DDS-Subscriber + TAO-Client + ZeroDDS- CORBA-Bridge im Compose.

Repo: crates/corba-dds-bridge/tests/cross_vendor.rs.

Tests: crates/corba-dds-bridge/tests/cross_vendor.rs::{omniidl_smoke_check_present, catior_reads_the_ior_the_daemon_prints} — beide hinter --features cross-vendor-tests und #[ignore].

Status: partial — die DDS-Seite hinter der Bridge ist ZeroDDS; ein Cyclone-DDS-Backend und ein TAO-Client sind nicht gemessen. Cross-Ref: das open-Item darunter.

§10/§12 Cross-Vendor-Harness — TAO, JacORB, Ice-Java, Cyclone

Spec: §10 + §12.3 — die CORBA-Seite gegen TAO, JacORB und Ice-Java; ein Cyclone-DDS-Backend hinter der Bridge.

Repo: —

Tests: —

Status: open — gemessen ist omniORB mit einem ZeroDDS-Backend (tests/omniorb_e2e.rs). Plan: dieselben Fälle mit einem TAO- und einem JacORB-Client aus crates/corba-interop/competitors/ und mit einem Cyclone-DDS-Backend nach dem Layout aus §4.3 auf dem Linux-Testhost fahren.

§13 Cross-References

§13 Verwandte Library + OMG-Specs + Daemons

Spec: §13 — Library crates/corba-dds-bridge/, crates/corba-iiop/, crates/corba-giop/ und der Rust-Codegen in crates/lang-rules/; OMG GIOP/IIOP/CSIv2/SSLIOP; Wire-Format; Deployment.

Repo: —

Tests: —

Status: n/a (informative) — Verweisliste.

§14 Versioning

§14 SemVer-Bump-Regeln

Spec: §14 — Patch=Bugfixes, Minor=additive Mapping-Konfiguration, Major=Wire-Protocol-Changes.

Repo: —

Tests: —

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


Audit-Status

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

Test-Lauf: cargo test -p zerodds-corba-dds-bridge — 51 Lib-Tests, 6 bridge_e2e, 9 security_e2e grün, 0 failed (macOS). tests/omniorb_e2e.rs (#[ignore]) und tests/cross_vendor.rs (--features cross-vendor-tests, #[ignore]) laufen auf dem Linux-Testhost gegen omniORB 4.3.3.

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