Skip to content

4.3.2

Choose a tag to compare

@github-actions github-actions released this 01 Oct 18:43
· 54 commits to main since this release
Immutable release. Only release title and notes can be modified.
v4.3.2
d7af7da

Added

  • openehr-query can rewrite, locate and bind a query (#3505, #3506,
    #3507, #3508). visit::Visit and visit::VisitMut walk every node of the
    AST, so a consumer finds, replaces or removes a WHERE condition without
    its own recursive walk. Every IdentifiedPath and every WHERE condition
    carries an ast::Span, the byte range it was written at, so a diagnostic
    can point at a predicate without repeating its literal; spans take no part
    in equality. bind::bind substitutes ITS-REST query_parameters into the
    AST as typed literals the printer escapes, at every position the grammar
    admits a parameter, and reports an unbound, unknown, duplicate or
    unbindable parameter by name, never by value. The opt-in federation
    feature adds federation::parse_federated, which lifts a
    FROM ENDPOINT p [ … ] or ORGANISATION [ … ] directive out of a query
    and parses the rest as strict AQL. Breaking: WhereExpr::Identified and
    IdentifiedPath gained the span (WhereExpr::identified and
    IdentifiedPath::new build them without one).

  • openehr-its publishes the server router and the intermediary seams
    (#3509, #3510, #3511, #3512, #3514). Under rest-server, each API group's
    server module carries the trait, one success enum per operation (the
    documented 2xx answers with their Location, ETag and other headers)
    and router(api), an axum router binding every ROUTES entry to its trait
    method. A method refuses with rest::runtime::Refusal, an ApiError plus
    the headers its answer needs: the current ETag on a 412, or the
    OpenAPI-declared headers of a demographic 409/412 through the generated
    headers structs (Refusal::with_headers). Either renders as the ITS-REST
    Error JSON body. rest::server::router(api) mounts all six groups at
    once, and rest::server::with_fallbacks makes an unknown path answer 404
    and an undeclared method 405 with Allow, both with the Error body.
    rest::routes::lookup matches a method and path to its operation and path
    parameters without reading the body, and Client::forward sends a request
    once and returns every answer as received, so an intermediary passes bodies,
    Location and ETag through byte for byte. CredentialsProvider resolves
    the credential before every attempt and hears about a 401, for tokens that
    refresh. CallOptions gives a generated client a deadline and extra headers
    per call (with_options); the remaining budget reaches the engine as
    RequestTimeout, and an elapsed deadline is ClientError::DeadlineElapsed.
    Breaking: the server traits moved into <group>::server and return
    Result<success enum, Refusal>, and the response headers structs moved
    from client to the group module. The nine openehr-* crates step to 0.0.74.

  • The openehr-its ITS-REST client carries what a consumer meets on first
    adoption
    (#3487). The commit operations (COMPOSITION, EHR_STATUS, the
    directory, EHR creation, the demographic parties and relationships) take
    the committal-metadata headers the ITS-REST overview defines and the
    OpenAPI declares no parameter for: openehr-version,
    openehr-audit-details (one field line per value) and, on the COMPOSITION
    and CONTRIBUTION commits, openehr-template-id. Every documented 4xx
    outcome carries the answer body as an ErrorBody: the bytes as received,
    decoded as the ITS-REST Error when they are one, so a 422's
    validationErrors reach the caller; ClientError::Unauthorized,
    Forbidden, ServiceFailure and UndocumentedStatus carry the same body.
    A 400 whose body carries message alone decodes as the Error with an
    empty validationErrors. A path parameter keeps : literal, so a version
    uid is sent as the specification writes it. Credentials hold their secret
    in a secrecy::SecretString (redacted Debug, zeroed on drop), with
    Credentials::basic and Credentials::bearer constructors. The nine
    openehr-* crates step to 0.0.72.

  • openehr-its ships an ITS-REST client (#3485). The new rest-client
    feature adds a generated client per ITS-REST 1.1.0 API group
    (rest::generated::<group>::client) over a hand-written runtime
    (rest::client: the Transport engine trait, the shipped reqwest engine,
    Basic and Bearer credentials, the retry budget and ClientError). Each
    operation takes its parameter struct, with Prefer, If-Match and Accept
    as fields, and answers an outcome with one variant per status the OpenAPI
    documents for it; declared response headers such as ETag and Location
    come back in a typed struct. Any other status is
    ClientError::UndocumentedStatus, and 401, 403 and 5xx are their own
    errors. Idempotent requests are retried after a transport failure or a
    5xx; a POST is sent once. A create operation also answers NoContent,
    the 204 the ITS-REST overview prescribes under Prefer: return=minimal
    although the OpenAPI lists 201 alone. FerroBRIDGE keeps its hand-written
    client until it moves to this one (its issue #276). The DTOs, parameter
    structs and route tables move to a
    new rest feature over serde and http alone, which both rest-server and
    rest-client build on, so a client never compiles axum. full now
    includes rest-client. The nine openehr-* crates step to 0.0.71.

  • A CI guard keeps the Apache-2.0 crates free of BUSL-1.1 code:
    scripts/checks/licence-boundary.sh refuses a normal or build dependency,
    or a feature, from openehr-base, openehr-lang, openehr-term,
    openehr-rm, openehr-am or openehr-its on openehr-query,
    openehr-adl or openehr-sdt, and a license field that changes side.

Changed

  • The repository moved to the FerroHEALTH organization
    (https://github.com/FerroHEALTH/FerroEHR, #3516); the old
    rubentalstra/FerroEHR URLs redirect. Images and the Helm chart now publish
    to ghcr.io/ferrohealth/ferroehr, ghcr.io/ferrohealth/ferroehr-viewer,
    ghcr.io/ferrohealth/ferroehr-postgres and
    oci://ghcr.io/ferrohealth/charts/ferroehr, and the compose files, the chart
    and the book name those references. The v4.3.1 images and chart are copied
    there by digest. Everything published up to v4.3.1 stays available under
    ghcr.io/rubentalstra, and its signatures name rubentalstra/FerroEHR as the
    repository that built it. The roadmap board is now
    https://github.com/orgs/FerroHEALTH/projects/2. The nine openehr-* crates
    step to 0.0.75 for their new repository field.

  • The dependency set moves forward in one step. OpenTelemetry goes to
    0.33 (opentelemetry, opentelemetry_sdk, opentelemetry-otlp,
    opentelemetry-prometheus) with tracing-opentelemetry 0.34; the OpenAPI
    stack to utoipa 6, utoipa-axum 0.3 and utoipa-swagger-ui 10;
    jsonschema to 0.58, sevenz-rust2 to 0.23, lapin to 4.12 and config
    to 0.15.27. The bundled PostgreSQL image is rebuilt on the current
    postgres:18.6 upstream digest (sha256:5a5a84b1…), a same-version respin
    with rebuilt base packages. The nine openehr-* crates step to 0.0.73.

  • FerroTERM moves to 0.1.5 everywhere the product pins it. The quickstart
    overlay docker-compose.terminology.yml, the hosted sandbox compose file, the
    Helm chart (terminology.image.digest and the pinned version its tag default
    and Artifact Hub annotation read) and the integration test that starts the
    real server all name
    ghcr.io/rubentalstra/ferroterm:0.1.5@sha256:61a2d4aefc4a48e9e90b9a698a64bdfeb7ef6443744a1fe50972099456891fe9,
    the index digest read from GHCR. That release adds the history interaction,
    _summary and _elements on read, a 406 on an unacceptable Accept, refuses
    a write that would duplicate a canonical, and states the position of a
    refused expression constraint on the OperationOutcome. The chart version
    becomes 10.1.3; an install that pins the chart keeps running the image it
    pinned.

  • openehr-its is split in two, and the wire layer is Apache-2.0 again
    (#3482). The new crate openehr-sdt (BUSL-1.1) holds the hand-written
    Simplified Formats (FLAT, STRUCTURED, Web Template, TDD import), the
    template-independent RM-instance validation and the SMART on openEHR scope
    grammar. openehr-its keeps the ITS wire layer: the generated canonical JSON
    dispatch, the canonical XML codecs, the ITS-REST contract, the OPT 1.4 and
    AOM2 archetype XML codecs, and the hand-written runtimes, canonical JSON entry
    points and wire-validation dispatcher they need. From 0.0.69 it is published
    under Apache-2.0, so a consumer of canonical JSON takes on no BUSL-1.1 code.
    Rust callers import openehr_sdt::flat, openehr_sdt::rm_instance and
    openehr_sdt::smart_scopes in place of openehr_its::flat,
    openehr_its::rm_instance and openehr_its::rest::smart_scopes. The flat
    and cache features left openehr-its for openehr-sdt; a
    wasm32-unknown-unknown consumer of openehr-its now selects
    default-features = false, features = ["opt14"], and openehr-sdt with
    default-features = false compiles to the scope grammar alone, with no
    dependency. Published versions keep their licence: openehr-its 0.0.60 to
    0.0.67 stay BUSL-1.1 AND Apache-2.0.

  • The published openehr-* crates are nine, and all step to 0.0.69 (#3482).
    openehr-sdt was first published alone at 0.0.68, built against the 0.0.67
    siblings; it joins the lockstep line at 0.0.69 and publishes after
    openehr-its and before openehr-adl.

  • FerroTERM moves to 0.1.4 everywhere the product pins it (#3474). The
    quickstart overlay docker-compose.terminology.yml, the hosted sandbox
    compose file, the Helm chart (terminology.image.digest and the pinned
    version its tag default and Artifact Hub annotation read) and the
    integration test that starts the real server all name
    ghcr.io/rubentalstra/ferroterm:0.1.4@sha256:f3b5f35a60d99d5c837125e5f8cf39d8eeecf9f69dbc79b9a526cc45aa706470,
    the index digest read from GHCR. That release reloads its served set without
    a restart, treats an index root's child directories as releases, ships the
    ferroterm-sync service, and carries the standard concept status properties
    on locally authored code systems. The chart version becomes 10.1.2; an
    install that pins the chart keeps running the image it pinned.

Fixed

  • Two 500 answers from the openehr-its REST server runtime carry a fixed
    message
    (#3518). An illegal response header and an answer body that does
    not serialize put the header name or the serde error into the body the client
    received; both now answer with a fixed text.

  • The app and viewer images rebase onto a distroless base with the fixed
    OpenSSL
    (#3504). gcr.io/distroless/cc-debian13:nonroot moves to
    sha256:e792ab3d…, which carries the libssl3t64 update from DSA-6531-1
    (CVE-2026-75804, CVE-2026-84782). The image scan refused the previous base
    with both findings at HIGH, so the main images went untagged until this
    change.

  • An AQL path predicate whose node boolean opens with a parameter or an
    archetype id parses
    (#3513): CLUSTER k[$node and name/value='x'] and
    [openEHR-EHR-CLUSTER.device.v1 or at0001] were refused, though the
    grammar in QUERY/docs/AQL/master07-grammar.adoc admits both.

  • The no attribution in commits CI job no longer refuses the
    Co-authored-by: dependabot[bot] trailer GitHub writes when it squash-merges
    a Dependabot pull request, which had failed the last three pushes to main.
    The commit-msg hook keeps that line too.