diff --git a/.github/workflows/Build-Test-And-Deploy.yml b/.github/workflows/Build-Test-And-Deploy.yml
index a2d75099..cd27eeea 100644
--- a/.github/workflows/Build-Test-And-Deploy.yml
+++ b/.github/workflows/Build-Test-And-Deploy.yml
@@ -80,6 +80,14 @@ jobs:
cache-dir: buildkit-cache
skip-extraction: false
+ - name: Generate Docker NuGet credentials config
+ env:
+ NUGET_FEED_TOKEN: ${{ secrets.AZURE_DEVOPS_PAT }}
+ run: |
+ mkdir -p "${RUNNER_TEMP}/nuget"
+ bash scripts/nuget/emit-creds-config.sh > "${RUNNER_TEMP}/nuget/NuGet.Config"
+ chmod 600 "${RUNNER_TEMP}/nuget/NuGet.Config"
+
# Only build for dev registry — prod gets the image via az acr import in deploy-production
- name: Build Container Image
if: github.event_name != 'pull_request_target' && github.event_name != 'pull_request'
@@ -88,12 +96,16 @@ jobs:
tags: ${{ vars.DEVCONTAINER_REGISTRY }}/essentialcsharpweb:${{ github.sha }},${{ vars.DEVCONTAINER_REGISTRY }}/essentialcsharpweb:latest
file: ./EssentialCSharp.Web/Dockerfile
context: .
- secrets: |
- "nuget_pat=${{ secrets.AZURE_DEVOPS_PAT }}"
+ secret-files: |
+ "nuget_config=${{ runner.temp }}/nuget/NuGet.Config"
outputs: type=docker,dest=${{ github.workspace }}/essentialcsharpwebimage.tar
cache-from: type=gha,scope=essentialcsharpweb-main
cache-to: type=gha,mode=max,scope=essentialcsharpweb-main
+ - name: Remove Docker NuGet credentials config
+ if: always()
+ run: rm -f "${RUNNER_TEMP}/nuget/NuGet.Config"
+
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
@@ -321,4 +333,3 @@ jobs:
az logout
az cache purge
az account clear
-
diff --git a/EssentialCSharp.Web/Dockerfile b/EssentialCSharp.Web/Dockerfile
index 682dd378..5c2c90d1 100644
--- a/EssentialCSharp.Web/Dockerfile
+++ b/EssentialCSharp.Web/Dockerfile
@@ -26,18 +26,13 @@ COPY EssentialCSharp.Chat.Tests/EssentialCSharp.Chat.Tests.csproj ./EssentialCSh
COPY EssentialCSharp.Chat/EssentialCSharp.Chat.csproj ./EssentialCSharp.Chat/
COPY EssentialCSharp.Web.Tests/EssentialCSharp.Web.Tests.csproj ./EssentialCSharp.Web.Tests/
COPY EssentialCSharp.Web/EssentialCSharp.Web.csproj ./EssentialCSharp.Web/
-RUN --mount=type=secret,id=nuget_pat,required=false \
+RUN mkdir -p /root/.nuget/NuGet
+RUN --mount=type=secret,id=nuget_config,required=false,target=/root/.nuget/NuGet/NuGet.Config \
--mount=type=cache,id=essentialcsharp-web-nuget,target=/root/.nuget/packages \
- if [ "$ACCESS_TO_NUGET_FEED" = "true" ] && [ ! -s /run/secrets/nuget_pat ]; then \
- echo "ERROR: ACCESS_TO_NUGET_FEED=true but nuget_pat secret is missing or empty" >&2; exit 1; \
+ if [ "$ACCESS_TO_NUGET_FEED" = "true" ] && [ ! -s /root/.nuget/NuGet/NuGet.Config ]; then \
+ echo "ERROR: ACCESS_TO_NUGET_FEED=true but nuget_config secret is missing or empty" >&2; exit 1; \
fi && \
- if [ "$ACCESS_TO_NUGET_FEED" = "true" ]; then \
- mkdir -p /root/.nuget/NuGet && \
- printf '\n\n \n \n \n \n \n \n\n' \
- "$(cat /run/secrets/nuget_pat)" > /root/.nuget/NuGet/NuGet.Config; \
- fi && \
- dotnet restore "EssentialCSharp.Web.slnx" -p:AccessToNugetFeed=$ACCESS_TO_NUGET_FEED && \
- rm -f /root/.nuget/NuGet/NuGet.Config
+ dotnet restore "EssentialCSharp.Web.slnx" -p:AccessToNugetFeed=$ACCESS_TO_NUGET_FEED
COPY . .
COPY --from=frontend-build /frontend/EssentialCSharp.Web/wwwroot/dist ./EssentialCSharp.Web/wwwroot/dist
RUN --mount=type=cache,id=essentialcsharp-web-nuget,target=/root/.nuget/packages \
diff --git a/scripts/nuget/emit-creds-config.sh b/scripts/nuget/emit-creds-config.sh
new file mode 100644
index 00000000..ab5f58a9
--- /dev/null
+++ b/scripts/nuget/emit-creds-config.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+# shellcheck source=scripts/nuget/feed.sh
+source "${script_dir}/feed.sh"
+
+token="${1:-${NUGET_FEED_TOKEN:-}}"
+username="${2:-${FEED_USERNAME}}"
+
+if [[ -z "${token}" ]]; then
+ echo "emit-creds-config.sh: no token (pass as \$1 or set NUGET_FEED_TOKEN)" >&2
+ exit 1
+fi
+
+xml_escape() {
+ local value="${1}"
+ value="${value//&/&}"
+ value="${value//<}"
+ value="${value//>/>}"
+ value="${value//\"/"}"
+ printf '%s' "${value}"
+}
+
+if [[ ! "${FEED_NAME}" =~ ^[A-Za-z_][A-Za-z0-9._-]*$ ]]; then
+ echo "emit-creds-config.sh: FEED_NAME must be a valid NuGet.Config XML element name" >&2
+ exit 1
+fi
+
+escaped_username="$(xml_escape "${username}")"
+escaped_token="$(xml_escape "${token}")"
+
+cat <
+
+
+ <${FEED_NAME}>
+
+
+ ${FEED_NAME}>
+
+
+EOF
diff --git a/scripts/nuget/feed.sh b/scripts/nuget/feed.sh
new file mode 100644
index 00000000..12b8944c
--- /dev/null
+++ b/scripts/nuget/feed.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+FEED_NAME="${FEED_NAME:-EssentialCSharp}"
+FEED_USERNAME="${FEED_USERNAME:-az}"