Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ This repository contains documentation and module demo applications showcasing d
- [Module 03: Remote Teleoperation with RTI Real-Time WAN Transport](#module-03-remote-teleoperation-with-rti-real-time-wan-transport)
- [Module 04: Security Threat Demonstration](#module-04-security-threat-demonstration)
- [Hands-On: Architecture](#hands-on-architecture)
- [Architecture Overview](#architecture-overview)
- [Hands-On: Architecture](#hands-on-architecture)
- [Architecture Overview](#architecture-overview)
- [Data Types](#data-types)
- [Quality of Service (QoS)](#quality-of-service-qos)
Expand Down Expand Up @@ -139,6 +137,12 @@ The RTI MedTech Reference Architecture demonstrates use cases and capabilities o

Use the module-specific READMEs when you want to run a demo. They describe what each workflow launches, why it exists, and the exact `launch.py` commands to use from the repository root.

`launch.py` accepts either a single module (`python3 launch.py <module> [apps ...] [-s]`) or a **predefined scenario** that launches a curated set of applications across modules in one command (`python3 launch.py --scenario <name> [-s]`). Scenarios are declared in [`resource/config/scenarios.json`](./resource/config/scenarios.json) and cover common multi-component workflows (e.g. `record`, `replay`, `teleop-or-side`, `security-threat`). List them with:

```bash
python3 launch.py --list-scenarios
```

### [Module 01: Digital Operating Room](./modules/01-operating-room/)

### [Module 02: RTI Recording Service & RTI Replay Service](./modules/02-record-playback/)
Expand Down Expand Up @@ -220,10 +224,12 @@ This reference architecture defines the following QoS Profiles in [Qos.xml](./sy
| Qos Library | Qos Profile | Intended Use
| ----------- | --------- | -----------
| System | DefaultParticipant | Common, or base, *system configuration* (e.g. transport, network interfaces, discovery, thread priorities, etc.)
| System | WanConfig | WAN transport (UDPv4_WAN) configuration, used by Module 03: Remote Teleoperation
| DataFlow | Streaming | Periodic data that is published at a high frequency (i.e. frequencies <1 second)
| DataFlow | Status | "Current status"-like data, sent once at the beginning of operation and again only upon change to the status
| DataFlow | Command | Data that represents commands or trigger some action in the system
| DataFlow | Heartbeat | Assert and detect the presence of system devices
| DataFlow | SecureLog | Reliable, transient-local delivery for the DDS Security builtin secure-log topic

### Domains & Topics

Expand All @@ -242,11 +248,12 @@ Legend:

This reference architecture defines the following Domains in [DomainLibrary.xml](./system_arch/xml_app_creation/DomainLibrary.xml):

| Domain | Intended Use
| ------ | -----------
| OperationalDataDomain | Real-time operational medical device data
| Domain | Domain ID | Intended Use
| ------ | --------- | -----------
| OperationalDataDomain | 0 | Real-time operational medical device data
| SecureLogDomain | 0 | DDS Security builtin secure logging (consumed by the SecureLogReader participant)

*Note, this reference architecture defines just a single Domain. As a Connext system design scales over time, additional domains could be defined for monitoring, logging, etc. Those additional domains should not affect the performance of our operational data, and therefore should belong to a different domain.*
*Note, both domains are defined with the same Domain ID (`0`), so they currently resolve to the **same** DDS domain. `SecureLogDomain` is defined separately to keep the secure-logging configuration distinct, so that as a Connext system design scales over time, logging (and other concerns such as monitoring) can be moved to a different Domain ID without touching the operational data configuration. Isolating such data on a separate domain ensures it does not affect the performance of operational data.*

This reference architecture defines the following Topics in [DomainLibrary.xml](./system_arch/xml_app_creation/DomainLibrary.xml):

Expand All @@ -257,6 +264,7 @@ This reference architecture defines the following Topics in [DomainLibrary.xml](
| OperationalDataDomain | `t/DeviceHeartbeat` | Assert that a unique system component is alive
| OperationalDataDomain | `t/DeviceCommand` | Command initiating a status (e.g. `START`, `SHUTDOWN`) to a unique system component
| OperationalDataDomain | `t/Vitals` | Data representative of a unique patient's collected vital signs
| SecureLogDomain | `DDS:Security:LogTopicV2` | DDS Security builtin logging topic, carrying the `DDSSecurity::BuiltinLoggingTypeV2` type

*Note, this reference architecture defines a unique Topic for each Data Type defined. While a Topic may only reference a single Data Type, a multi-purpose Data Type can be associated with multiple Topics. It is a **best practice** to limit the number of defined Topics, but in doing so, it may be feasible to reuse a Data Type for several Topics.*

Expand Down Expand Up @@ -302,6 +310,8 @@ This reference architecture defines the following DomainParticipants in [Partici
| OperationalDataDomain | Orchestrator | `t/DeviceStatus`, `t/DeviceHeartbeat` | `t/DeviceCommand` | Administer device-level commands and monitor presence and status of all devices.
| OperationalDataDomain | PatientSensor | `t/DeviceCommand` | `t/Vitals`, `t/DeviceStatus`, `t/DeviceHeartbeat` | Stream simulated patient vitals.
| OperationalDataDomain | PatientMonitor | `t/DeviceCommand`, `t/Vitals` | `t/DeviceStatus`, `t/DeviceHeartbeat` | Process and display patient vitals.
| OperationalDataDomain | SystemObserver (external/optional) | All available topics | -- | Read-only observer integration: subscribes to every operational Topic and publishes nothing. Its DDS Security permissions allow subscribe on any Topic and deny all publication.
| SecureLogDomain | SecureLogReader | `DDS:Security:LogTopicV2` | -- | Subscribe to the DDS Security builtin secure-log topic.

*Note, this reference architecture utilizes one DomainParticipant for each device application. It is a **best practice** to define one DomainParticipant per application. However, in more complex systems, an application may be required to operate on multiple Domains. This requires defining multiple DomainParticipants for those applications that run in parallel.*

Expand All @@ -311,14 +321,19 @@ DDS Security defines authentication, access control, and encryption capabilities

DDS Security is meant to be a pluggable component to the system architecture. This reference architecture demonstrates the flexibility of the RTI Security Plugins, and how a system can be secured purely through configuration. It should be noted that enabling security does have an effect on performance - both at initialization due to authentication and in steady-state operation due to encryption. It is because of this, that a system's architecture should be designed with security in mind, even if application code has no dependency on the use of security.

The reference architecture configures security in [SecureAppsQos.xml](./system_arch/qos/SecureAppsQos.xml) with:
The reference architecture configures security in [SecureAppsQos.xml](./system_arch/qos/SecureAppsQos.xml) following the [Builtin Security Plugins domain-level protection](https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_secure/users_manual/p3_advanced/threat_modeling.html#dds-security-threat-protection) pattern with topic-level protection for sensitive topics:

| Component | Security Features
| ---------------------- | -----------------
| **LAN Communications** | Domain 0 governance, participant-specific certificates and permissions
| **WAN Communications** | Domain 1 governance for WAN connections
| **LAN Communications** | `OperationalDomain` governance with `ENCRYPT_WITH_ORIGIN_AUTHENTICATION` RTPS protection, PSK encryption (`OperationalDomain.psk`), participant-specific certificates and permissions
| **WAN Communications** | `TeleopWanDomain` governance with `ENCRYPT_WITH_ORIGIN_AUTHENTICATION` RTPS protection, PSK encryption (`TeleopWanDomain.psk`) for WAN connections (Module 03)
| **Topic-level protection** | `t/Vitals` and `t/MotorControl` topics use `metadata_protection_kind=ENCRYPT` for insider confidentiality protection
| **RTI Services** | Dedicated security profiles for Recording/Replay Services and Routing Services

For independent, security-specific observer integrations (not part of the demo applications), use [SecureExternalAppsQos.xml](./system_arch/qos/SecureExternalAppsQos.xml). It provides the `SecureExternalAppsQosLib::SecureSystemObserver` QoS snippet, which is intended to be composed into external DomainParticipants.

This external snippet is ideal for Connext Studio when configuring an RTI Spy source: include [SecureExternalAppsQos.xml](./system_arch/qos/SecureExternalAppsQos.xml) and apply `SecureSystemObserver` so Spy can attach as a read-only secure observer.

Security Artifacts Structure in [security](./system_arch/security/):

- `ca/` - Certificate Authority hierarchy (root CA → intermediate identity CA + intermediate permissions CA)
Expand All @@ -338,12 +353,12 @@ Check out the the [system_arch](./system_arch/) folder, where the system archite
- [RTI XML-Based Application Creation](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/xml_application_creation/xml_based_app_creation_guide/XMLAppCreationGSG_title.htm#)
- [RTI System Designer](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/tools/system_designer/index.html)
- [RTI Core Libraries Users Manual](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/users_manual/users_manual/title.htm#)
- [RTI Security Plugins](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_secure/users_manual/index.html)
- [RTI Security Plugins](https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_secure/users_manual/index.html)
- [RTI Connext Modern C++ API](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/api/connext_dds/api_cpp2/index.html) *, used in Module 01: Digital Operating Room*
- [RTI Connext Python API](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/api/connext_dds/api_python/index.html) *, used in Module 01: Digital Operating Room*
- [RTI Recording Service & Replay Service](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/services/recording_service/introduction.html) *, used in Module 02: RTI Recording Service & RTI Replay Service*
- [Connext Real-Time WAN Transport](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/users_manual/users_manual/PartRealtimeWAN.htm) *, used in Module 03: Remote Teleoperation with RTI Real-Time WAN Transport*
- [RTI Routing Service](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/services/routing_service/index.html) *, used in Module 03: Remote Teleoperation with RTI Real-Time WAN Transport*
- [RTI Cloud Discovery Service](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/addon_products/cloud_discovery_service/index.html) *, used in Module 03: Remote Teleoperation with RTI Real-Time WAN Transport*
- [RTI Security Plugins Users Manual](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_secure/users_manual/index.html) *, used in Module 04: Security Threat Demonstration*
- [RTI Security Plugins Users Manual](https://community.rti.com/static/documentation/connext-dds/current/doc/manuals/connext_dds_secure/users_manual/index.html) *, used in Module 04: Security Threat Demonstration*
- [RTI Connext Third-Party Software](https://community.rti.com/static/documentation/connext-dds/7.7.0/doc/manuals/connext_dds_professional/release_notes_3rdparty/index.html)
83 changes: 45 additions & 38 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,28 @@ the commit is recorded:

| Hook | What it checks / fixes |
| --- | --- |
| `ruff` | Python lint — auto-fixes where possible |
| `ruff-check` | Python lint — auto-fixes where possible |
| `ruff-format` | Python formatting — auto-reformats files |
| `trailing-whitespace` | Removes trailing whitespace from all text files |
| `end-of-file-fixer` | Ensures files end with a single newline |
| `check-yaml` | Validates YAML syntax |
| `check-yaml` | Validates YAML syntax (excludes `.clang-format`) |
| `check-json` | Validates JSON syntax |
| `check-toml` | Validates TOML syntax |
| `check-xml` | Validates XML syntax |
| `check-merge-conflict` | Blocks committed merge-conflict markers |
| `check-case-conflict` | Blocks names that collide on case-insensitive filesystems |
| `check-illegal-windows-names` | Blocks filenames invalid on Windows |
| `check-executables-have-shebangs` / `check-shebang-scripts-are-executable` | Keep executable bits and shebangs consistent |
| `detect-private-key` | Blocks accidentally committed private keys |
| `requirements-txt-fixer` | Normalizes `requirements*.txt` ordering |
| `mixed-line-ending` | Enforces LF (CRLF for batch files) |
| `name-tests-test` | Enforces `test_*` naming for pytest files |
| `check-added-large-files` | Blocks files larger than 500 KB |
| `codespell` | Checks spelling for source and docs using `pyproject.toml` settings |
| `clang-format` | Reformats C/C++ source files |
| `rumdl` | Markdown lint + auto-fix |
| `rumdl-fmt` | Markdown formatting pass |
| `rumdl` / `rumdl-fmt` | Markdown lint + auto-fix and formatting pass |

See `.pre-commit-config.yaml` for the authoritative hook list and configuration.

If a hook **modifies files**, the commit is aborted. Re-stage the modified
files and commit again:
Expand All @@ -123,22 +134,17 @@ committing. In exceptional circumstances you can bypass hooks with

### CI pipeline (`.github/workflows/ci.yml`)

The pipeline has two jobs; `test` runs only after `lint` passes:

| Job | What it does |
| --- | --- |
| Lint & Format | `ruff check`, `ruff format --check`, codespell, clang-format dry-run, markdown lint via `rvben/rumdl` action |
| Build | CMake configure + build all C++ modules |
| Project-level Tests | `pytest tests/` |
| Unit Tests | Fast Python type/script/QoS tests |
| DDS Communication Tests | Non-GUI DDS pub/sub tests |
| Integration Tests | Slow end-to-end demo flow tests |
| GUI Tests | Headless Qt application tests |
| Security Tests | DDS Security plugin tests |
| Module 02 Tests | Record/Playback module tests |
| Module 04 Tests | Security Threat module tests |

CI uses a pinned Ruff version (see [Upgrading Ruff](#upgrading-ruff)). If
pre-commit and CI share the same pin, a clean local commit will not produce
lint failures in CI.
| `lint` (Lint & Format) | Runs **all** pre-commit hooks across the repo (`pre-commit/action` with `--all-files`) — the same ruff, ruff-format, codespell, clang-format, rumdl, and hygiene hooks you run locally. |
| `test` (Build & Test) | Installs Connext (apt) and Python deps, builds all C++ modules with `python build.py`, generates the system and Module 04 security artifacts, starts Xvfb, then runs the full suite from the repo root with `python -m pytest -v -m "not build_pipeline"` and uploads `results.xml`. |

Because the `lint` job runs `pre-commit` itself, CI and your local hooks execute
the **exact same** hook versions (pinned in `.pre-commit-config.yaml`). A clean
local commit will therefore not produce lint failures in CI. See
[Upgrading Ruff](#upgrading-ruff) for how the Ruff pin is managed.

## Testing CI Locally with act (Optional)

Expand Down Expand Up @@ -191,8 +197,9 @@ docker compose -f tests/docker/docker-compose.yml run --rm --build test \
modules/01-operating-room/tests/test_types.py -v
```

> **Note:** The Docker default command runs `pytest -v` via the
> test entrypoint. It executes functional/behavioral tests. It does **not** run Ruff lint,
> **Note:** With no arguments, the Docker test entrypoint runs `pytest` over the
> whole repo (it passes any arguments you supply straight through to pytest).
> It executes functional/behavioral tests. It does **not** run Ruff lint,
> rumdl markdown lint, or clang-format; those are enforced by pre-commit
> (locally) and the CI lint job (on push/PR).

Expand Down Expand Up @@ -228,37 +235,37 @@ Before opening a PR, verify:

## Upgrading Ruff

Ruff is pinned in two places so that local pre-commit hooks and CI produce
identical results. When upgrading, update **both together**:
The CI `lint` job runs `pre-commit`, so there is a **single** Ruff pin that
governs both local hooks and CI: the `astral-sh/ruff-pre-commit` revision in
`.pre-commit-config.yaml`. Bump that one pin to upgrade Ruff everywhere.

| File | Setting to change |
| --- | --- |
| `.github/workflows/ci.yml` | `pip install ruff==<new-version>` |
| `.pre-commit-config.yaml` | `rev: v<new-version>` under `astral-sh/ruff-pre-commit` |
| File | Setting to change | When |
| --- | --- | --- |
| `.pre-commit-config.yaml` | `rev: v<new-version>` under `astral-sh/ruff-pre-commit` | Every Ruff bump (this is the authoritative pin used by CI). |
| `pyproject.toml` | `required-version = ">=<major.minor>"` | Only when raising the minimum supported version. |
| `requirements-dev.txt` | `ruff>=<major.minor>` | Only when raising the minimum supported version. |

`pyproject.toml` carries a minimum version (`required-version = ">=0.15"`) and
`requirements-dev.txt` carries a matching lower bound (`ruff>=0.15`). These do
**not** need to change on every Ruff bump unless the new version introduces a
breaking change to the configuration format.
The `pyproject.toml` and `requirements-dev.txt` bounds are lower bounds for
developers who run Ruff outside pre-commit; they do **not** need to change on
every Ruff bump unless the new version introduces a breaking change to the
configuration format.

### Procedure

```bash
# 1. Update the two pinned locations (ci.yml and .pre-commit-config.yaml)

# 2. Update your local pre-commit environment
# 1. Update the pin in .pre-commit-config.yaml
pre-commit autoupdate --freeze # or manually set the rev

# 3. Run the full pre-commit suite to surface any new lint findings
# 2. Run the full pre-commit suite to surface any new lint findings
pre-commit run --all-files

# 4. Fix any new violations introduced by the new Ruff version
# 3. Fix any new violations introduced by the new Ruff version

# 5. Update the minimum version bounds if appropriate
# 4. Update the minimum version bounds only if appropriate
# pyproject.toml: required-version = ">=<new-major.minor>"
# requirements-dev.txt: ruff>=<new-major.minor>

# 6. Commit everything together
git add .pre-commit-config.yaml .github/workflows/ci.yml pyproject.toml requirements-dev.txt
# 5. Commit everything together
git add .pre-commit-config.yaml pyproject.toml requirements-dev.txt
git commit -m "chore: bump Ruff to <new-version>"
```
4 changes: 2 additions & 2 deletions docs/release/RELEASE_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,8 @@ and update them as part of the release process.

| Dependency | Current Minimum Version | Tracked In |
| --- | --- | --- |
| RTI Connext DDS | 7.3.0 | CMakeLists.txt, README.md |
| RTI Code Generator | 4.3.0 | Generated source headers |
| RTI Connext DDS | 7.7.0 | README.md, `.github/workflows/ci.yml` |
| RTI Code Generator | Bundled with Connext 7.7.0 | Generated source headers |
| CMake | 3.17 | CMakeLists.txt |

**When a dependency version changes:**
Expand Down
2 changes: 2 additions & 0 deletions modules/02-record-playback/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Module-specific notes:
## Run the Demo

> Important: Run the commands below from the repository root. `launch.py` lives at the project root and is the single runtime entrypoint for this project.
>
> Tip: the predefined `record` and `replay` scenarios bundle the operating room apps and the corresponding service into a single command (e.g. `python3 launch.py --scenario record`). The step-by-step flow below instead runs them in separate terminals so you can start and stop the service independently of the OR apps. Run `python3 launch.py --list-scenarios` to see all scenarios.

### 1. Run Operating Room Applications

Expand Down
Loading
Loading