From 9a27858125f4b5e9b7e43fb7079bf02b578d32f2 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Wed, 3 Jun 2026 23:22:57 +0330 Subject: [PATCH] ci: trust Nexus mirror CA in backend dotnet restore (fixes skipped deploys) The mirror's Let's Encrypt cert renewed under the new ISRG Root YR root, which isn't in the dotnet SDK image's trust store. `dotnet restore` validates TLS and fails (NU1301 / unable to get local issuer certificate), so both backend CI jobs fail and the deploy is skipped. The npm jobs are unaffected because they already pass --strict-ssl=false. Pin the mirror's intermediate (CN=YR2, CA:TRUE, valid to Sept 2028) and add it as a trust anchor before restore in: - CI api-build + admin-api-build jobs (.gitea/workflows/ci-cd.yml) - docker/api/Dockerfile + docker/admin-api/Dockerfile (deploy image builds) Also set NUGET_CERT_REVOCATION_MODE=offline in the CI restore steps to avoid CRL/OCSP fetches to lencr.org (filtered from Iran). Permanent fix is server-side (re-chain to ISRG Root X1 or update trust stores); this unblocks CI/deploys without depending on that. Co-Authored-By: Claude Opus 4.8 --- .gitea/workflows/ci-cd.yml | 18 ++++++++++++++++++ docker/admin-api/Dockerfile | 5 +++++ docker/api/Dockerfile | 6 ++++++ docker/nexus-mirror-ca.crt | 28 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 docker/nexus-mirror-ca.crt diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 5eb1c3e..ec674cf 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -80,10 +80,20 @@ jobs: EOF + - name: Trust Nexus mirror CA + # The mirror's Let's Encrypt cert renewed under the new ISRG Root YR, which is + # not yet in the SDK image's trust store. The npm jobs skip TLS via + # --strict-ssl=false; dotnet validates, so add the mirror's intermediate + # (CA:TRUE, valid to Sept 2028) as a trust anchor. + run: | + cp docker/nexus-mirror-ca.crt /usr/local/share/ca-certificates/nexus-mirror-ca.crt + update-ca-certificates + - name: Restore run: dotnet restore src/Meezi.API/Meezi.API.csproj --configfile /tmp/nuget.ci.config env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 + NUGET_CERT_REVOCATION_MODE: offline - name: Build run: dotnet build src/Meezi.API/Meezi.API.csproj --no-restore -c Release @@ -128,10 +138,18 @@ jobs: EOF + - name: Trust Nexus mirror CA + # See api-build: trust the mirror's intermediate so dotnet restore validates + # the new ISRG Root YR chain (npm jobs sidestep this with --strict-ssl=false). + run: | + cp docker/nexus-mirror-ca.crt /usr/local/share/ca-certificates/nexus-mirror-ca.crt + update-ca-certificates + - name: Restore run: dotnet restore src/Meezi.Admin.API/Meezi.Admin.API.csproj --configfile /tmp/nuget.ci.config env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 + NUGET_CERT_REVOCATION_MODE: offline - name: Build run: dotnet build src/Meezi.Admin.API/Meezi.Admin.API.csproj --no-restore -c Release diff --git a/docker/admin-api/Dockerfile b/docker/admin-api/Dockerfile index de6928b..f7e9ad3 100644 --- a/docker/admin-api/Dockerfile +++ b/docker/admin-api/Dockerfile @@ -8,6 +8,11 @@ COPY global.json Directory.Build.props Directory.Packages.props ./ # nuget.docker.config points to Nexus mirror (mirror.soroushasadi.com) COPY nuget.docker.config ./nuget.config +# Trust the Nexus mirror's TLS CA (new ISRG Root YR chain, not in the SDK image's +# trust store). See docker/api/Dockerfile for the full rationale. +COPY docker/nexus-mirror-ca.crt /usr/local/share/ca-certificates/nexus-mirror-ca.crt +RUN update-ca-certificates + COPY src/Meezi.Shared/Meezi.Shared.csproj src/Meezi.Shared/ COPY src/Meezi.Core/Meezi.Core.csproj src/Meezi.Core/ COPY src/Meezi.Infrastructure/Meezi.Infrastructure.csproj src/Meezi.Infrastructure/ diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 70f299d..4ee4dd4 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -8,6 +8,12 @@ COPY global.json Directory.Build.props Directory.Packages.props ./ # nuget.docker.config points to Nexus mirror (mirror.soroushasadi.com) COPY nuget.docker.config ./nuget.config +# Trust the Nexus mirror's TLS CA: its Let's Encrypt cert renewed under the new +# ISRG Root YR, which isn't in the SDK image's trust store yet. Add the mirror's +# intermediate (CA:TRUE, valid to Sept 2028) as an anchor so dotnet restore validates. +COPY docker/nexus-mirror-ca.crt /usr/local/share/ca-certificates/nexus-mirror-ca.crt +RUN update-ca-certificates + COPY src/Meezi.Shared/Meezi.Shared.csproj src/Meezi.Shared/ COPY src/Meezi.Core/Meezi.Core.csproj src/Meezi.Core/ COPY src/Meezi.Infrastructure/Meezi.Infrastructure.csproj src/Meezi.Infrastructure/ diff --git a/docker/nexus-mirror-ca.crt b/docker/nexus-mirror-ca.crt new file mode 100644 index 0000000..d587bae --- /dev/null +++ b/docker/nexus-mirror-ca.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE2jCCAsKgAwIBAgIQTr0klH4k05SALYSlL9WzGTANBgkqhkiG9w0BAQsFADAu +MQswCQYDVQQGEwJVUzENMAsGA1UEChMESVNSRzEQMA4GA1UEAxMHUm9vdCBZUjAe +Fw0yNTA5MDMwMDAwMDBaFw0yODA5MDIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQDEwNZUjIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDZ0LxwBppqh84luqMerV/eeL/fXQ7mLQQv1Lnp +WKZbyvGpx6wh6AfnslAnF6ewTkcHA+gSOoBvm3Dfm06AuGiF+KRut4fAcowqnAQQ +CW98+QPP/eOv/wug7Iyk4NkOxf2I6g2f55T6nJoOTLFcukeRq80JGQEYan+dPFr9 +OGUgQK2hGKgNkW87pappsOAuUJcroYhRt5uUis4qaZireiseu32gzDJNBAiKtsvd +6HX4v25bpkRNcS/B/Gtc9kVbUpD+2PLPxdei3Tim55k4tfAEXwD2qyiPTxrTNq6l +N+AMr5g2c1dNqkOTwjxeV6L5lpP1rGiYvLnRaPlOqyZRPW+5AgMBAAGjge4wgesw +DgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMBMBIGA1UdEwEB/wQI +MAYBAf8CAQAwHQYDVR0OBBYEFEAVLSZ57TIgnt+ach3WMh+BDIEMMB8GA1UdIwQY +MBaAFN7nW2DQIm1AKH0/DQH+pLVStFGUMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEF +BQcwAoYWaHR0cDovL3lyLmkubGVuY3Iub3JnLzATBgNVHSAEDDAKMAgGBmeBDAEC +ATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veXIuYy5sZW5jci5vcmcvMA0GCSqG +SIb3DQEBCwUAA4ICAQB0ZUQWZ9/Yn9COEpo+JfecMnB0h0vwDm/M66IqXqw3LoaL +mx9lZvRTeDIS67PUeI3yCA2W6PKRD0/FE/G57lOmS+Xy5AaaL00ICGOqjNcCaMWW +8o8nevHOd4i4lqgtznE/28QwlcdJyF8yBiWHpnyjhEpmNWJURgOCOg2xpwRMBCsj +MScqYPtOhBeuYQvSwAEeTML2Ukh6uGuX4E14q65Ja8cdjF5bAldnP1eE4FBaAwsZ +G2fOqqrKV03Y85Nw2btedP1AtliQuJZs/Jo/gXxXdc7LrH3McgnpnbTiAncX7yES +hP6kzQejllqMCIt52HOjxDGWafS7Xw+DKwqmH+Eqy8dcbOuag/1AYlQoKNVK3F5q +Hh6tEDiMqQcLIibGKteE6iHo4A/bIScbzrhXUYuism42ZYzmc48FMVIH3qy4L84E +TdAH2gtxw0PAhvRVXp8HP7wfngpzsN/8xOTpeRSbM4+Qbc56G6+Bifmv6sk1ieQb +NA3wJdl4DDUuQSV8hBgx6zoI1ZSGORprDFux7c6rhc77QZMSRrEgomBeklervEve +86ylWmZ3WWHV6RLMi8xNvjd71r4EPIGgY7BZU/VPBkq+uA7Gb6mbJnFgV43uh3xy +LRFgxIAphIukwTGSMZZR+AI+Qnp0BYTWovHXozOf3H8r6hozEoT02JHn0AeTfA== +-----END CERTIFICATE-----