ae91e6b7f7
#816 finding: the SDK checks that the server certificate names the host only when a session is created with checkDomain:true. The driver, the AdminUI browser and Client.Shared all called the 8-argument DefaultSessionFactory.CreateAsync, which forwards checkDomain:false — so no host-name check ever ran (why a trusted NAT cert for *.invalid browsed fine over an IP in #813). When enabled the SDK (Session.OpenAsync -> ValidateDomains -> FindDomain) compares ConfiguredEndpoint.EndpointUrl.IdnHost — the CONFIGURED host, because OpcUaEndpointSelection/EndpointSelector rewrote the advertised one — against the cert's DNS/IP SANs; secured sessions only, and the auto-accept handler accepts a mismatch. Policy: certificateValidation.validateServerHostName, tri-state. Unset = OpcUaCertificateValidationOptions.DefaultValidateServerHostName = false, the pre-#816 behaviour, so nothing changes on upgrade; true = validate the configured host; false = explicit NAT/port-publish opt-out. Threaded into the driver, the AdminUI browser (same JSON) and the AdminUI form (a select that keeps "unset" unset), Client.Shared ConnectionSettings.ValidateServerHostName and the CLI --validate-host-name. A driver refusal names the opt-out. #818: the NAT fixture's /app/pki is on the opc-plc-nat-pki volume (verified: same thumbprint across --force-recreate), its PUBLIC cert is committed as Docker/nat/opc-plc-nat-server.der, and NatPublishedEndpointBrowseTests run every secure browse on a throwaway PKI (internal browser seam): refusal with nothing trusted, positive with the cert trusted (unset/false host check), and a BadCertificateHostNameInvalid refusal with the check on. The trusted cert is OPCUA_NAT_SERVER_CERT or the committed one (skip on thumbprint mismatch); OPCUA_NAT_SERVER_CERT_TRUSTED is retired. CI exports its throwaway NAT container's public cert. ServerHostNameValidationTests pin the driver against the plain opc-plc. MIN_EXECUTED not raised (needs a hosted run): +6 in v2-integration (440 -> 446), documented in scripts/ci/README.md.
101 lines
5.0 KiB
YAML
101 lines
5.0 KiB
YAML
# Fixture-backed integration leg (#757 item b). UNVERIFIED on a hosted runner until its first run.
|
|
#
|
|
# Separate from v2-ci.yml on purpose: the 60-minute whole-solution unit-tests job is untouched, so
|
|
# it gets no slower or flakier. This workflow builds ONLY the five fixture-backed *.IntegrationTests
|
|
# projects and runs them against THROWAWAY containers that the job itself creates and removes
|
|
# (scripts/ci/integration-fixtures.sh): SQL Server 2022, PostgreSQL 17 (seeded), QuestDB and the public
|
|
# opc-plc image (twice: plain, and a port-NAT copy behind OPCUA_NAT_ENDPOINT for the #806/#813 NAT browse tests).
|
|
# Nothing here touches the shared 10.100.0.35 host, so CI does not depend on that box.
|
|
#
|
|
# Explicit `docker run` steps rather than a `services:` block: whether the Gitea act_runner honours
|
|
# `services:` (and makes service ports reachable from the job) is not documented in infra/README.md §10,
|
|
# and the Sql/Postgres fixtures need a post-start seed step anyway. The script needs only a reachable
|
|
# docker daemon on the runner.
|
|
#
|
|
# Gate: MIN_EXECUTED turns a fixture outage (every test Assert.Skip-ing) into a RED job instead of a
|
|
# silent green, which is the whole point of this leg. Not covered here (no public/pullable image or
|
|
# needs credentials/TLS): Modbus/S7/AB/FOCAS/TwinCAT sims, Mqtt, MTConnect, Oracle, Host real-infra mode.
|
|
|
|
name: v2-integration
|
|
|
|
# Triggers start CONSERVATIVE (manual + nightly) because the shared runner is already heavily loaded
|
|
# (#718: load avg ~35-51 on 22 cores during unit-tests) and this leg is unverified on it. Once the first
|
|
# hosted runs are green and the runner has headroom, widen to push/PR on master (paths below).
|
|
# push: { branches: [master] }
|
|
# pull_request: { branches: [master], paths: ["src/Drivers/**", "src/Core/**", "tests/Drivers/**", "scripts/ci/**", ".github/workflows/v2-integration.yml"] }
|
|
on:
|
|
workflow_dispatch: {}
|
|
schedule:
|
|
- cron: "41 2 * * *"
|
|
|
|
# Own group (not lmxopcua-v2-ci): sharing it would let a pending integration run supersede a pending
|
|
# unit-tests run (Gitea supersedes pending runs per group). Same semantics as v2-ci: one active run,
|
|
# an active run is never cancelled.
|
|
concurrency:
|
|
group: lmxopcua-v2-integration
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
DOTNET_NOLOGO: "1"
|
|
DOTNET_CLI_TELEMETRY_OPTOUT: "1"
|
|
|
|
jobs:
|
|
integration-tests:
|
|
runs-on: ubuntu-latest
|
|
# #718: bound a stall. Expected runtime is well under an hour (image pulls + 5 small projects);
|
|
# the per-test --blame-hang below names a hung test, this cancels the job if even that fails.
|
|
timeout-minutes: 60
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: 10.0.x
|
|
- name: docker available
|
|
run: docker version --format '{{.Server.Version}}'
|
|
- name: start throwaway fixtures
|
|
run: bash scripts/ci/integration-fixtures.sh up
|
|
- name: dotnet test (fixture-backed integration projects)
|
|
env:
|
|
# Mirrors the unit-tests leg: one worker, bounded xUnit parallelism, hang killer.
|
|
INTEGRATION_PROJECTS: >-
|
|
Driver.Sql Driver.Historian.SqlServer Driver.Historian.QuestDb
|
|
Driver.OpcUaClient Driver.OpcUaClient.Browser
|
|
run: |
|
|
set -euo pipefail
|
|
for p in $INTEGRATION_PROJECTS; do
|
|
dotnet test "tests/Drivers/ZB.MOM.WW.OtOpcUa.$p.IntegrationTests/ZB.MOM.WW.OtOpcUa.$p.IntegrationTests.csproj" \
|
|
--configuration Release -m:1 --settings scripts/ci/ci.runsettings \
|
|
--filter "Category!=E2E&Category!=LiveIntegration" \
|
|
--logger "trx;LogFileName=$p.trx" --results-directory artifacts/trx \
|
|
--blame-hang --blame-hang-timeout 20m --blame-hang-dump-type none
|
|
done
|
|
# A fixture that never came up Assert.Skip()s every test and would otherwise pass. The floor is set
|
|
# from a local run against the same containers (see scripts/ci/README.md); raise it as suites grow.
|
|
- name: assert not-all-skipped
|
|
if: always()
|
|
env:
|
|
# #816/#818 added 6 executing OpcUaClient tests; raise to 446 once a hosted run confirms them
|
|
# (scripts/ci/README.md §"Fixture-backed integration").
|
|
MIN_EXECUTED: "440"
|
|
run: bash scripts/ci/assert-not-all-skipped.sh artifacts/trx/*.trx
|
|
- name: fixture logs on failure
|
|
if: failure()
|
|
continue-on-error: true
|
|
run: |
|
|
for c in otopcua-ci-mssql otopcua-ci-pg otopcua-ci-questdb otopcua-ci-opcplc otopcua-ci-opcplc-nat; do
|
|
echo "=== $c ==="; docker logs --tail 40 "$c" 2>&1 || true
|
|
done
|
|
- name: stop fixtures
|
|
if: always()
|
|
continue-on-error: true
|
|
run: bash scripts/ci/integration-fixtures.sh down
|
|
# v3 on purpose — see v2-ci.yml (act_runner reports as GHES; upload-artifact@v4+ refuses it).
|
|
- name: upload trx
|
|
if: always()
|
|
continue-on-error: true
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: integration-trx
|
|
path: artifacts/trx/*.trx
|
|
if-no-files-found: warn
|