mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-17 05:11:13 +08:00
master
31 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e78c648295 |
Images CI: publish samples once natively and stop compiling under QEMU (#4679)
# Description
Images CI took 45–100 min per image. The arm64 half of every
`linux/amd64,linux/arm64` build ran `dotnet restore` and `dotnet
publish` in an arm64 SDK container under QEMU. For `refserver`, publish
took 8 min natively for amd64 and 92 min emulated for arm64. On top of
that, every one of the 10 matrix legs recompiled the whole stack.
The output is framework-dependent portable IL, so the compile is now
done once, natively. The image legs only copy files onto the
per-platform runtime base image.
### Dockerfiles (all 10)
- **SDK stage runs on the build platform.** The `build` stage is pinned
to `--platform=$BUILDPLATFORM`. `-p:UseAppHost=false` keeps an x64 app
host out of the arm64 image.
- **New `prebuilt` stage.** It is chosen with a global `ARG
PUBLISH_SOURCE`, which defaults to `build`. Local `docker build` and the
`docker-compose` files are unchanged.
```dockerfile
FROM scratch AS prebuilt
ARG PUBLISH_DIR=artifacts/docker/publish
COPY ${PUBLISH_DIR}/ /app/publish/
FROM ${PUBLISH_SOURCE} AS publish
```
- **Pump: final-stage `RUN`s moved to a native stage.** The `sed` on
`openssl.cnf` and the `mkdir`/`chown`/`chmod` steps now run in a
`$BUILDPLATFORM` `layout` stage. The final stage copies `/layout/` to
`/`, so `/app` and `/diag` keep the `$APP_UID:0` owner and `g=u` mode
they had before. `openssl.cnf` therefore comes from the build-platform
base image. It is a plain config file, so it is expected to match
between architectures.
### `docker-image.yml`
- **Single image list.** The image list lives once, in `env.IMAGES`
(image, project, Dockerfile). `discover` emits it as the matrix.
- **New `publish-samples` job.** It runs `dotnet publish` for each
sample sequentially, so shared libraries compile once. It uses the same
options and NBGV version properties as the Dockerfiles and uploads the
output as the `docker-publish` artifact.
- **`build-and-push-image` legs.** Each leg:
- downloads the artifact;
- builds with `PUBLISH_SOURCE=prebuilt` and
`PUBLISH_DIR=artifacts/docker/publish/<image>`;
- no longer uses `setup-qemu-action`;
- is named `build-and-push-image (<image>)`.
- **`images summary`.** It now also fails when `publish-samples` fails.
### Docs
- `ContainerReferenceServer.md` describes the publish-once / copy-only
flow and the build arguments.
- `DeveloperGuide.md` mentions the `publish-samples` job in the Images
CI section.
Expected: one native publish of about 7 min, then 10 parallel
copy-and-push legs of a few minutes each. Not yet confirmed on CI: the
sandbox could not pull MCR base images, so the prebuilt multi-platform
builds were checked against a Debian-based stand-in base, and the
build-from-source path was not built.
## Related Issues
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [ ] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: romanett <7413710+romanett@users.noreply.github.com>
|
||
|
|
034d9934d1 |
Let pushes to protected branches finish their required checks (#4594)
# Description
Makes every push to `master` and `release/*` report both required
checks, so a release branch can be cut from `master`.
Two things stopped `master` commits from getting a green `images
summary`, which the `Release` ruleset requires, including when a branch
is created:
1. **Cancellation.** `CI` (`buildandtest.yml`) and `Images CI`
(`docker-image.yml`) used one concurrency group per ref with
`cancel-in-progress: true`. Each merge to `master` cancels the
still-running checks of the commit before it. A queued run in the same
group is replaced as well ("Canceling since a higher priority waiting
request … exists"). `Images CI` takes about 100 minutes, and `master`
currently gets a merge about every 90 minutes:
| Commit | `build-and-test summary` | `images summary` |
| --- | --- | --- |
| `87c35b84b` (#4572) | success | failure: `pumpserver` / `refserver`
cancelled after ~100 min by the #4573 push |
| `20c2d77d5` (#4573) | success | failure: `refserver` / `mcpserver` /
`pumpserver` cancelled by the #4577 push |
The ruleset has no bypass actors, so `git push origin
20c2d77d5:refs/heads/release/2.0` is rejected with `Required status
check "images summary" is failing`.
2. **Push path filter.** `Images CI`'s push trigger had `paths-ignore:
docs/**, tests/**`. A documentation- or test-only push to `master` or
`release/*` never started the workflow, so it never reported `images
summary` and could never be a cut point.
## Changes
- **Concurrency (both workflows):** pushes to protected lines (`master`,
`main`, `master378`, `release/*`) get one concurrency group per commit
(`github.sha`) and never cancel, so every commit runs its checks to
completion. Pull requests and other branches are unchanged: they group
by PR number or ref and cancel superseded runs.
- The per-commit group is needed as well as `cancel-in-progress: false`.
With a shared group GitHub still replaces a *queued* run.
- **`Images CI` push trigger:** the `paths-ignore` is gone. The
`discover` job now decides relevance for pushes the same way it already
did for pull requests.
- It diffs `github.event.before..HEAD` and skips the image builds for
docs/tests-only changes, while `images summary` still reports.
- A new branch (all-zero `before`) or a `before` commit the clone
doesn't have builds everything, and a failed diff still fails the gate.
- `main` and `master378` are not added to the push trigger: `main`
doesn't exist, and `master378` runs its own copy of this workflow.
## Verification
- The `discover` script was extracted and run locally for push events:
| Push | `relevant_changes` |
| --- | --- |
| docs-only | `false` (images skipped, summary reports) |
| workflow change | `true` |
| new branch | `true` |
| unknown `before` | `true` |
- The CI-related `Opc.Ua.Tools.Tests` (`~Ci`, 53 tests, including the
fail-closed diff pin) pass on net10.0.
## Cost
Overlapping merges to `master` now run CI and image builds in parallel
instead of cancelling each other, which uses more runner minutes on busy
days. Image pushes from overlapping `master` runs can finish out of
order, so `latest-master` reflects whichever finishes last. Version tags
are per build and unaffected.
## Related Issues
- Blocks cutting `release/2.0` for `2.0.0-preview.6` (see #4574).
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [ ] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
e9313ef957 |
Only use GitHub action for CI and nightly, establish release-branch-only package publication (#4513)
## Description Two related changes to how the 2.0 line is built and shipped. ### 1. Release-branch-only package publication - `master` produces development previews only. - Stable packages can only be built from a canonical `release/<major>.<minor>` branch and are promoted manually from the exact signed candidate artifact. - Core packages use explicit `major.minor.patch` versions (`2.0.0`, `2.0.1`, then `2.1.0`); git height never changes a stable package patch. - XRegistry, WoT Connectivity, Vision, Robotics, Redundancy, Positioning, OpenUSD, ISA95, AI, DI, the relevant MCP extensions, and OpenUSD connector tools remain `-preview.N` while following the core numeric version. - nuget.org receives only non-`.Debug` package IDs; GitHub Packages retains the complete signed Release/Debug candidate. - `docs/ReleaseProcess.md` is a reproducible runbook for developers and agents, with each step stating its completion evidence. Promotion is source-bound and byte-checked: `release.yml` checks out nothing until the candidate SHA is known, and `assert-published-packages-match.ps1` proves that any version already on a feed holds *this* candidate's content before `--skip-duplicate` is allowed to skip it. Canonical release-branch naming is matched case-sensitively with no leading zeroes, and `version.json`'s `publicReleaseRefSpec`, both policy helpers and the copy `release.yml` inlines are pinned to one expression by tests. ### 2. PR CI moved to GitHub-hosted runners - `.github/workflows/buildandtest.yml` (**CI**) now owns pull-request validation outright, covering the Windows Debug/Release net48 + net10.0 solution builds and fast tests that only Azure Pipelines ran, alongside the existing Linux/macOS, all-target and NativeAOT legs. `build-and-test summary` remains the stable required check name. - `.github/workflows/nightly.yml` is a new **manual-only** (`workflow_dispatch`) full-scope workflow covering the Azure nightly workload: all solutions x seven target profiles x Debug/Release, the net472/netstandard profiles, Windows + Linux NativeAOT, and the long-running and durable tiers. - Shared deterministic discovery/batching lives in `.github/scripts/get-ci-matrix.ps1` with a local composite action, so both entry points expand the same workload manifest instead of duplicating a large embedded script. - `azure-pipelines.yml` is set to `pr: none`. - The standalone pump sample image workflow is folded into the consolidated **Images CI** workflow, which now builds all ten images and publishes an `images summary` rollup suitable as a required check. ## Related Issues No related issue provided. ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. ## Validation - `Opc.Ua.Tools.Tests` full `net10.0` suite: **959 passed, 1 skipped, 0 failed**. - Version/package-policy regression subset (`PackageVersionPolicyTests`): **60 passed, 0 failed**. - GitHub Actions **CI** run 35719807620: **149/149 jobs green** on GitHub-hosted runners. - Canonical release-branch rule verified against the pinned nbgv 3.7.115 by building throwaway branches: `release/2.0`, `release/0.9`, `release/10.42` -> `PublicRelease=True`; `release/02.0`, `release/2.00`, `Release/2.0` -> `False`. - Package identity gate verified against a live nuget.org package: served packages carry a repository `.signature.p7s`, so equality is decided on content excluding that part. Re-signing and zip reordering produce an identical digest; a one-byte content change does not. - Synthetic Release-only, Debug-only, combined, preview, duplicate, orphaned-symbol, mismatched-root and accidental-stable-family package sets exercise the shared validator. - Stable-release rehearsal in an isolated `release/2.0` clone: `Opc.Ua.Di` packed as `2.0.0-preview.6` depending on stable Core `2.0.0`; `Opc.Ua.Di.Client` likewise against stable Client `2.0.0`. - All workflow YAML, `version.json`, the package-policy PowerShell scripts and the internal release-runbook anchors parse. ## Known validation limits - Full `UA.slnx` `net48` and `net10.0` local validation remains blocked by pre-existing `NETSDK1005` and dependency-version failures in unmodified fuzz/sample projects; the corresponding checklist items intentionally stay open. - The TRX-driven test verdict added for the intermittent at-exit host stall is proven by `CiTestVerdictTests`; the stall itself has not recurred since. - `nightly.yml` has not yet been run against a full-scope Azure run for tuple-level parity — see below. ## Operational follow-up This remains a preparation PR targeting `master`. It does **not** authorize a release. Release sequence: 1. Merge this PR. 2. Create canonical `release/2.0`, advance `master` to `2.1.0-preview.{height}`, and open a separate `2.0.0` version PR against `release/2.0`. 3. Follow [`docs/ReleaseProcess.md`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/docs/ReleaseProcess.md) for candidate dry-run, environment approval, promotion, tag/release finalization, and next-patch preview setup. CI migration steps still needing administrator access are tracked in [`docs/DeveloperGuide.md#migration-status`](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/docs/DeveloperGuide.md#migration-status): proving `nightly.yml` parity on a trusted SHA with the private fuzz corpus provisioned, turning off definition 14's service-side PR override, retiring the Azure full-scope schedules and push trigger, and retiring the duplicate `azure-pipelines-preview.yml` publisher. > **Before cutting `release/2.0`:** the `Release` ruleset requires the Azure context for *every* `refs/heads/release/*`, but a new 2.x branch inherits `pr: none`, so that context would never report and would block every PR into the new line. Exclude the new ref from that ruleset, or add a 2.x ruleset requiring `build-and-test summary`, as part of creating the branch. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
7bd90d1ed7 |
Update dependencies and re-enable macOS NativeAOT (#4493)
## Description Updates unpinned NuGet dependencies to current compatible stable versions, pins the repository and CI to .NET SDK 10.0.401 (.NET 10.0.12), and re-enables the macOS ARM64 NativeAOT lane. The existing intentional pins remain unchanged, including Moq, compatibility/security remediation pins, Roslyn compatibility versions, coordinated OpenUSD packages, and per-TFM MQTTnet/ASP.NET Core bands. The .NET 10.0.12 `Microsoft.DotNet.ILCompiler` package provenance was verified against the runtime relocation-anchor fix required for the Apple linker failure. ## Related Issues - Fixes #4443 ## Validation - `dotnet restore UA.slnx`: passed - Targeted .NET 10 build: passed - Core schema tests: 160 passed - Main NativeAOT tests: 178 passed - Historian NativeAOT tests: 2 passed - MCP NativeAOT tests: 3 passed - `git diff --check`: passed ## Checklist - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [ ] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran all tests locally using the UA.slnx solution against at least .NET Framework and .NET 10, and all passed. - [ ] I fixed all failing and flaky tests in the CI pipelines and all CodeQL warnings. - [ ] I have addressed all PR feedback received. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> |
||
|
|
d525bc3f28 |
Bound reconnect cleanup and organize samples by domain (#4276)
# Description This PR fixes bounded ManagedSession reconnect cleanup and reorganizes the sample applications into domain-focused folders. ## Reconnect cleanup - Bounds reconnect integration cleanup with independent 30-second close and dispose limits. - Sends `CloseSession` through the awaited transport request path during `Session.DisposeAsync`. - Preserves explicit `Session.CloseAsync` behavior that waits for or cancels outstanding publish requests. - Covers the disposal request path with a regression test. ## Sample organization - `samples/OpenUsd`: `GeneratorServer`, `SiteCompositionServer` - `samples/Redundancy`: `RedundantClient`, `RedundantServer`, `RedundantPubSub` - `samples/Isa95`: `MinimalIsa95Server` - `samples/MinimalApi`: `MinimalBoilerServer`, `MinimalCalcServer`, `MinimalClient` - `samples/DI`: `PumpDeviceIntegrationServer` - `samples/Lds`: `ConsoleLdsServer` - `samples/Reference`: `ConsoleReferenceClient`, `ConsoleReferenceServer` - `samples/PubSub`: `ConsoleReferencePubSubClient` `UA.slnx` now exposes the same requested domain groups. Project references, tests, runtime sample probes, CI workflows, Dockerfiles, Compose files, helper scripts, and documentation were updated to the new paths. `samples/Robotics/MinimalRobotServer` remains under `Robotics`. ## Validation - `dotnet build UA.slnx` - 3 Redundancy short-haul sample tests - 70 DI sample tests - 914 OpenUSD tests - 1 WotCon model-materialization test - 137 AOT tests - `docker compose config` for all 6 moved Redundancy Compose files ## Related Issues - Fixes #4273 ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce new build or analyzer warnings. - [x] I built the complete `UA.slnx` solution locally. - [ ] I ran all tests locally against at least .NET Framework and .NET 10. - [ ] I fixed all failing and flaky tests in the CI pipelines and all CodeQL warnings. - [x] I have addressed all PR feedback received. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: marcschier <11168470+marcschier@users.noreply.github.com> Co-authored-by: Marc Schier <mschier@microsoft.com> Co-authored-by: Marc Schier <marcschier@users.noreply.github.com> Copilot-Session: a2c2838f-74ae-4997-a1d4-50574d9e0636 |
||
|
|
ec02804157 |
Do not fail Docker builds on cache export errors (#4082)
## Summary - keep successful Docker builds from failing when GitHub Actions cache export is unavailable - apply the non-fatal cache export setting to both Docker image workflows ## Validation - targeted rerun of the failed MCP server Docker job succeeded - changed workflow YAML parsed successfully |
||
|
|
83f8db28a2 |
Bump setup-dotnet to v6 and fix UDP fake-time test hang (#4067)
# Description Updates every GitHub Actions workflow from `actions/setup-dotnet@v5` to `actions/setup-dotnet@v6` and fixes the net48 `UdpMessageRepeaterTests` hang observed in Azure build 15773. The hang dump showed NUnit blocked in `AsyncToSyncAdapter` waiting for an unfinished async test after virtual time advanced before the repeater registered its next delay timer. The tests now wait for each timer registration before advancing `FakeTimeProvider`, apply the same synchronization to cancellation coverage, and use real-time deadlines so regressions fail instead of hanging the test host. ## Related Issues - Replaces #4064 - Fixes the PubSub UDP net48 hang in [Azure build 15773](https://opcfoundation.visualstudio.com/865bd736-d0a6-4260-a336-d09d3eb39375/_build/results?buildId=15773) ## Testing - Exact PubSub UDP net48 pipeline selection: 175 passed, 4 skipped. - `UdpMessageRepeaterTests`: 30 consecutive net48 runs passed. - `UdpMessageRepeaterTests`: 10 passed on net10.0. ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
8538f531e7 | Update paths for the consolidated repository layout | ||
|
|
7f409657ad |
OPC UA Part 4 6.6 Redundancy (server + client) with opt-in distributed high-availability (#3918)
## Summary This branch implements **OPC 10000-4 §6.6 Redundancy** end to end — server and client, **transparent and non-transparent**, across all failover modes (`None`, `Cold`, `Warm`, `Hot`, `HotAndMirrored`, `Transparent`) — and layers an **opt-in distributed high-availability (HA)** capability on top so replicas can share address-space, session, and subscription state and expose redundancy to clients through the documented OPC UA mechanisms (for example, running a server replica set across nodes in Kubernetes). The single-instance, in-memory path stays **zero-overhead**: every distributed feature is opt-in through dependency injection, with a direct-construction fallback, and replaced APIs are kept and marked `[Obsolete]`. ## New packages | Package | Purpose | | --- | --- | | `OPCFoundation.NetStandard.Opc.Ua.Server.Redundancy` | §6.6 redundancy nodes plus opt-in distributed state: shared address space, secure session sharing, subscription/continuation-point mirroring, and leader election. | | `OPCFoundation.NetStandard.Opc.Ua.Server.Redundancy.Crdt` | Active/active, leaderless multi-writer replication via CRDTs (an extension beyond §6.6). | | `OPCFoundation.NetStandard.Opc.Ua.Server.Redundancy.K8s` | Kubernetes integration: Lease leader election, EndpointSlice peer discovery, and ServiceLevel-driven readiness. | Also adds the worked samples `Applications/RedundantServer` and `Applications/RedundantClient`, and the guides `Docs/HighAvailability.md` and `Docs/HighAvailabilityKubernetes.md`. ## Server side (§6.6) - `AddServerRedundancy(...)` populates the live `Server.ServerRedundancy` nodes (`RedundancySupport` plus `RedundantServerArray` / `ServerUriArray` / `CurrentServerId`) and drives `Server.ServiceLevel` from an `IServiceLevelProvider` (leader high, standby low). `Server.ServerRedundancy` is typed to the NonTransparent or Transparent subtype according to the configured mode. - `AddRequestServerStateChange(...)` implements the §6.6.5 manual-failover method, with `EstimatedReturnTime` and the Maintenance / NoData `ServiceLevel` sub-ranges. - Non-transparent peers resolve through `FindServers` (`ConfiguredRedundantServerSetProvider`) and advertise the `NTRS` discovery capability for GDS/NTRS registration. - Deterministic, replica-stable `EventId` synchronization for Transparent and HotAndMirrored sets (§6.6.2.2), excluding per-replica fields so de-duplicating clients do not double-process events. ## Client side (§6.6) - `DefaultServerRedundancyHandler` reads `Server.ServerRedundancy` and `Server.ServiceLevel` and fails over to the highest-ServiceLevel peer. It honors Maintenance (Part 4 Table 105 — disconnect to an available peer), keeps Warm backups disabled until failover (Table 107), and treats peers known only through `ServerUriArray` as failover candidates. - `RedundantManagedClient` implements the Cold, Warm, Hot (a), Hot (b), and HotAndMirrored client patterns: one active session, optional lightweight ServiceLevel status-check sessions to backups, and — for Hot (b) — merging of concurrent reporting streams with exact value-identity de-duplication. HotAndMirrored failover re-activates the mirrored session with the existing `AuthenticationToken` instead of recreating it. - Network redundancy: alternate communication paths via endpoint selection. ## Distributed state (opt-in; an extension beyond §6.6) - `ISharedKeyValueStore` (in-memory default) and `INodeStateStore`, with an `AddressSpaceSynchronizer` that bridges a `CustomNodeManager2`'s predefined nodes to the shared store, so node and reference additions/removals and value changes propagate to other replicas. `IDistributedValueCache` lets read/write callbacks cache the last value with a freshness bound; monitored items use the normal read pipeline and therefore participate only when the read path does. - **Secure session sharing (active/passive fast reconnect), server and client.** `DistributedSessionManager` (wired through a new additive `ISessionManagerFactory` seam on `StandardServer`) mirrors **encrypted** session state across replicas. On a failover reconnect the standby restores the session and performs the **full `ActivateSession` client-certificate signature validation** against a **single-use** `serverNonce` consumed via compare-and-swap across the replica set, enforcing the same SecurityPolicy and SecurityMode. The `AuthenticationToken` is a **lookup key only**, never an authenticator: entries are keyed by the SHA-256 digest of the token, and a cross-replica restore emits a distinct audit event. - Subscription, retransmission-queue, and continuation-point mirroring for subscription transfer and failover. - Leader election: a static single-leader provider and a shared-store **lease via compare-and-swap**, supporting active/passive and active/active (shared-read / master-write). - Fail-closed security defaults: shared records are protected at rest through `IRecordProtector`; secret-bearing mirrors require a registered protector or an explicit opt-out. ## Active/active (CRDT) `Opc.Ua.Server.Redundancy.Crdt` adds leaderless multi-writer address-space replication with CRDTs and gossip (`UseReplicatedAddressSpace`) plus CRDT-backed session metadata (`UseReplicatedSessions`). Networked gossip is **fail-closed without authenticated transport** (mutual TLS for TCP; an explicit opt-out for isolated dev/test). CRDT state is eventually consistent, so exactly-once decisions (such as the single-use nonce registry) stay on a strongly consistent store. The package is available on all stack target frameworks. ## Kubernetes `Opc.Ua.Server.Redundancy.K8s` provides Kubernetes Lease leader election, EndpointSlice-based peer discovery, and ServiceLevel-driven readiness for running an OPC UA server replica set. `Docs/HighAvailabilityKubernetes.md` covers StatefulSet/Deployment and Service manifests, RBAC, probes, time synchronization, secrets, gossip-port NetworkPolicy, and GDS/NTRS registration. ## Compatibility and validation - **Zero-overhead** single-instance default; additive, backward-compatible seams (for example `ISessionManagerFactory` and `IServerStartupTask`); replaced APIs marked `[Obsolete]` for migration. - Builds across the full stack TFM set (`net472`, `net48`, `netstandard2.0`, `netstandard2.1`, `net8.0`, `net9.0`, `net10.0`); NativeAOT-compatible where the runtime supports it. - Unit and integration tests for server, client, subscriptions, session mirroring, CRDT, and Kubernetes; the conformance suite stays green. See `Docs/HighAvailability.md` for the full OPC 10000-4 §6.6 mapping, the `Add*` (standard nodes) versus `Use*` (extension) builder convention, and the security/rotation guidance. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
f9a8343dea |
Full 1.05.06 compliant OPC UA Part 14 (PubSub) (#3892)
# Full OPC UA Part 14 (PubSub) — v1.05.06 This PR replaces the legacy PubSub stack with a modern, **OPC UA Part 14 v1.05.06**-compliant reimplementation built on current .NET: fully `async`, dependency-injection-first with a fluent builder (`services.AddOpcUa().AddPubSub(...)`), NativeAOT/trim-safe, and designed for high-throughput, highly-available, distributed deployments. The libraries — `Opc.Ua.PubSub`, `Opc.Ua.PubSub.Udp`, `Opc.Ua.PubSub.Mqtt`, `Opc.Ua.PubSub.Server`, and `Opc.Ua.PubSub.Adapter` — keep source compatibility with 1.5.378 where practical (obsolete shims) and ship a complete migration path. See the **[PubSub guide](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md)** and the **[2.0.x migration guide](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/migrate/2.0.x/pubsub.md)**. **Encodings & transports.** Both wire encodings are implemented in full — **UADP** (key/delta/event/keepalive, RawData, chunked, signed+encrypted) and **JSON** (verbose/compact, single-message, metadata; migrated from `Newtonsoft.Json` to `System.Text.Json`) — across **UDP** (uni/multi/broadcast + discovery), **MQTT** (3.1.1/5.0, retained metadata, TLS), and a from-scratch **DTLS 1.3** secured datagram transport (`opc.dtls://`) implemented on the .NET BCL crypto primitives (ECDHE, HelloRetryRequest cookies, certificate auth, AEAD record protection, HKDF key schedule), wired through `AddUdpTransport().WithDtls(...)`. Details in [Transports](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#transports) and [Encodings](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#encodings). A raw **Ethernet (Layer 2)** transport (`opc.eth://`, EtherType `0xB62C`, optional 802.1Q VLAN) carries UADP NetworkMessages directly in Ethernet II frames with no IP/UDP, via `AddEthTransport()` (`.WithPcap()` for cross-platform capture). See [Ethernet transport](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#ethernet--uadp-opceth). **Runtime schema generation.** A new schema subsystem (`Opc.Ua.Core.Schema`, `Opc.Ua.PubSub.Schema`) generates **XSD**, **OPC Binary (BSD)**, and **JSON Schema** for OPC UA data types at runtime — including PubSub NetworkMessage/DataSet message schemas — driven from the type system and source-generated metadata (no reflection; NativeAOT/trim-safe). It is consumable from the client, server, and PubSub stacks. See the **[Schema generation guide](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/SchemaGeneration.md)**. **Security, fail-closed.** Message-level security is wired end-to-end through `IPubSubSecurityWrapperResolver`: publishers are fail-closed (a secured group with no key source throws rather than emitting plaintext) and subscribers enforce per-reader inbound security. It includes AES-CTR (128/256) policies with HMAC-SHA-256, a deterministic 96-bit nonce with a messages-per-key cap, a monotonic sliding replay window, and a Security Key Service (SKS) pull client + in-memory server with SecurityGroups and key rotation. Two independent security assessments (IEC 62443-4-2 × OPC UA Part 2/4/14, plus a Microsoft SDL/SFI delta pass) drove remediation of all actionable findings — including orphaned message security, chunked-frame security bypass, unauthenticated Action invocation, pre-auth reassembly DoS, and DTLS hardening. See [Security](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#security) and [SKS](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#security-key-service-sks). **Server-side & high availability.** The runtime can optionally surface through a standard in-process OPC UA address space (`Opc.Ua.PubSub.Server`) with configuration methods, per-component diagnostics, the full PubSubState model, KeepAlive and MessageReceiveTimeout. Pluggable configuration/runtime-state stores, an id allocator, and HA runtime-state providers with failover support running publishers/subscribers in a distributed system. See [Server-side address space](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#server-side-address-space) and [High availability](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#high-availability-state-providers). **External-server adapter (bridge) with hot-reload.** A new `Opc.Ua.PubSub.Adapter` binds PubSub publishers, subscribers, and Action responders to an **external** OPC UA server over `ManagedSession` — cyclic Read or subscription-backed sources, browse-path node mapping, and metadata that resolves/retries and re-emits on model-change events. Adapter and PubSub configuration **hot-reload incrementally** (only changed writers/readers/responders are rewired; unchanged sessions are reused), driven by `IPubSubConfigurationStore.Changed` and `IOptionsMonitor`, with a pluggable change-feed source (e.g. etcd). See [Binding PubSub to an external server](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#binding-pubsub-to-an-external-opc-ua-server-client-session-adapters). **Samples, packaging & quality.** One combined sample, `ConsoleReferencePubSubClient`, demonstrates publisher, subscriber, and external-server modes on `Host.CreateApplicationBuilder` with full fluent/DI wiring; all libraries publish **NativeAOT with zero IL2026/IL3050 warnings** ([Native AOT](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/PubSub.md#native-aot), [DI](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/DependencyInjection.md)). The change ships comprehensive NUnit/integration suites and a libFuzzer harness, maintains ≥80% coverage on the new libraries, and is documented end-to-end ([What's new in 2.0](https://github.com/OPCFoundation/UA-.NETStandard/blob/part14pubsub/Docs/WhatsNewIn2.0.md)). |
||
|
|
03777ecb09 |
New Json decoder/encoders, array/matrix abstractions, ByteString, and more. (#3619)
- **Collections overhaul** — new/rewritten collection types (`ArrayOf`, `Collections` commits)
- **`Variant` builder/accessor** — new APIs for constructing and accessing Variants
- **`NodeId` operators made explicit** — breaking change for implicit conversions
- **Version bumped to 1.6** with preview build support
- **NumericRange** uses Variant
- **object** type accessors and general usage removed.
### 🏗️ Infrastructure
- Build config updated; `.NET 10` targeting
- InternalsVisibleTo moved to `.csproj`
- Pipeline/CI adjustments
|
||
|
|
cff3743c33 | Update build configuration to latest (#3607) | ||
|
|
b16c8020dd |
Bump actions/checkout from 5 to 6 (#3355)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
712e770fbe |
Restructure core and built in types into base assembly and nuget (#3326)
This change adds a **new Opc.Ua.Types** nuget that contains core types that do not rely on generated code. Why the name? Because almost all code that was in the Types subfolder is part of it, and because we do not want to change the name of the Opc.Ua.Core nuget/assembly because code relies on it. Any other name like base or bootstrap felt out of place due to the current structure already defining the name "types". Key design is to depend on only a small set of libraries with limited transitive dependencies, that includes hashcode, logging.abstraction, and for non standard20 builds System.Text.Json (needed for localizedText mul parsing). Also, key is to support .netstd 2.0 to support source generators and to allow removal of EEC_SUPPORT defines by removing std2.0 from core and all libraries. The changes are mostly restructuring, and thus small but contain some key changes: - **Status code** struct now comes with a Symbol field, which is used to carry symbols in case the code is not generated. Currently (until generated) the status code struct must be manually created with a symbol or the ToSymbolicId extension must be called in the core project. Future will generate Status code constants just like NodeId that contain the symbol which also removes the reflection-based lookup. Several tests needed to be adjusted as they checked the status code symbol strings instead of the code. - **Core identifiers** are copied as they were needed for code to compile, that includes attributes, a subset of status codes and node identifiers. These will never change so no need to generate them. - The types folder now contains **encoders**, except for json which is still in core. Once the json encoder is ported to system.text.json it will also be included and Newtonsoft.Json dropped as dependency (-> #3329). - Since types relies on **IOperationContext** and **ISystemContext**, and these export IUserIdentity which relies on crypto, these were split and extended in core with ISessionOperationContext and ISessionSystemContext, which mean changes to ServerSystemContext and introduction of SessionOperationContext and SessionSystemContext classes that extend OperationContext and SystemContext. Some runtime checks in the server are therefore needed to get at the session and auth info, however, those are anyway optional fields and are not on the critical paths, and thus a type check is in order (and was done in the past already, but against OperationContext class). - **Manifest resources** are now split between Core (nodeset zip, some generated resoures) and Types (built in bsd/xsds). This needs to be revisited later if the bsd/xsd need to be regenerated during type generation. Note that the embedded resource names changed as a result. Since these are only used internally and do not constitute public API this feels reasonable vs duplication of resources in 2 assemblies. - Reflection however now needs to load not just the built in **encodeables** from Opc.Ua.Types assembly, but also the generated encodeables from Opc.Ua.Core assembly. For this a new helper Utils method was added to get the Core assembly when linked against Opc.Ua.Core otherwise null. - Whatever utils methods needed to be split out into the new Opc.Ua.Types assembly, they are now in **CoreUtils** static class in Opc.Ua.Types, and Utils.xxxx forwards to them to ensure minimal changes. Later we would want to obsolete them in favor of CoreUtils, although it might make sense to split them again into domain specific utilities, such as networking, files, etc |
||
|
|
bdd1036127 |
Bump actions/setup-dotnet from 4 to 5 (#3191)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 4 to 5. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
f9cbb0c1bd |
Bump actions/checkout from 4 to 5 (#3165)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
516bad32eb |
Bump docker/build-push-action from 5 to 6 (#2647)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v5...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
2b0d7ff7da |
Bump actions/setup-dotnet from 3 to 4 (#2418)
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3 to 4. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
343f7b0fbc |
Add custom test targets to the build process, support for .NET 8. (#2410)
The goal is to reduce the overall number of builds, stop using end of life platforms in the build pipeline and to support build of future/deprecated build targets in a custom build step, which is also triggered weekly in the ci builds. In addition: - added a doc which describes the release and versioning strategy of this project - produce the Nuget packges with .NET 8 assemblies. - produce a Docker build based on a .NET 8 based container. - add custom test targets to test outdated platforms. Need a manual step to enable for VS or command line. - bug fixes: the latest move to an alternate crypto library for Bouncy Castle, which is only used for the GDS support and .NET Framework 4.6.2./netstandard2.0, revealed already a few issues which were previously not found. - only .NET8/.NET6/.NET Framework 4.8 are tested in Pull requests. Remaining builds in weekly scheduled builds. |
||
|
|
c6ee32a118 |
Bump docker/build-push-action from 4 to 5 (#2311)
* Bump docker/setup-buildx-action from 2 to 3 Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump docker/login-action from 2 to 3 Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump docker/metadata-action from 4 to 5 Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 4 to 5. - [Release notes](https://github.com/docker/metadata-action/releases) - [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md) - [Commits](https://github.com/docker/metadata-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/metadata-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump docker/setup-qemu-action from 2 to 3 Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump docker/build-push-action from 4 to 5 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
2f67543356 |
Bump docker/setup-qemu-action from 2 to 3 (#2314)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
13f36a858c |
Bump docker/login-action from 2 to 3 (#2312)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
2276c43b61 |
Bump actions/checkout from 3 to 4 (#2305)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
8851b040f3 |
fix docker manifest issue with ghcr (#2116)
ghcr doesn't support the new manifests. Must set provenance to false. see https://github.com/docker/build-push-action/issues/778 |
||
|
|
361e1d2fbd |
Bump docker/build-push-action from 3 to 4 (#2071)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
016207206c |
Bump BenchmarkDotNet from 0.13.3 to 0.13.4 (#2052)
* Bump BenchmarkDotNet from 0.13.3 to 0.13.4 * Update docker-image.yml ignore docker build for docs/tests Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Regen <mregen@microsoft.com> |
||
|
|
7c0ba9429c |
Bump Moq, Nunit.Console and BenchmarkDotNet (#2034)
* Bump BenchmarkDotNet from 0.13.2 to 0.13.3 * Bump Moq from 4.18.3 to 4.18.4 * Bump NUnit.Console from 3.16.0 to 3.16.1 * fix a typo * fix docker tag version Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Martin Regen <mregen@microsoft.com> |
||
|
|
61a61081f6 |
Improve ref server docker build (#2035)
- complete build in Dockerfile, not in ci pipeline - Use recommended build tasks for github actions - build multiarch with linux/amd64,linux/arm64 - docker signing support with cosign (yet disabled) |
||
|
|
8c0291b554 |
Bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.4.0 and github actions (#1985)
* Bump Microsoft.NET.Test.Sdk from 17.3.2 to 17.4.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.2 to 17.4.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.3.2...v17.4.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Martin Regen <mregen@microsoft.com> |
||
|
|
fd453f53e8 |
Add release tags to containers (#1706)
add a release tag, 1.x, 1.x.x tags when in a release build |
||
|
|
c6742add0a |
GH Action to build docker (#1644)
* Create docker-image.yml * Update docker-image.yml * Update docker-image.yml * Create docker-image.yml * Delete docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * net6 * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml |