From 58040164c2c3b7dff9de66ec4afd70382b3803d3 Mon Sep 17 00:00:00 2001 From: "benjamin.baker" Date: Wed, 2 Sep 2026 07:58:31 -0400 Subject: [PATCH] auto-detect and stage corp TLS-inspection root CA before docker build GE/Zscaler proxy inspection breaks npm ci silently, leaving node_modules incomplete and vite missing at build time. Detect the root CA from the host's chain to the npm registry and stage it as corp-root-ca.pem so the Dockerfile trusts it; harmless on clean networks. --- scripts/dev-bootstrap.ps1 | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/scripts/dev-bootstrap.ps1 b/scripts/dev-bootstrap.ps1 index e60962b2..20b9fefa 100644 --- a/scripts/dev-bootstrap.ps1 +++ b/scripts/dev-bootstrap.ps1 @@ -98,6 +98,51 @@ function Test-Command { return [bool](Get-Command $Name -ErrorAction SilentlyContinue) } +# Detect a corporate TLS-inspection root CA (e.g. Zscaler) by inspecting the +# certificate chain the host uses to reach the npm registry, then stage it as +# corp-root-ca.pem in the build context so the Docker frontend build can trust +# it. On a clean network this simply stages a public root, which is harmless. +# Writes nothing and returns quietly when detection is not possible. +function Set-CorpRootCa { + param( + [Parameter(Mandatory)][string]$RepoRoot + ) + + $certPath = Join-Path $RepoRoot 'corp-root-ca.pem' + + try { + $request = [System.Net.HttpWebRequest]::Create('https://registry.npmjs.org/') + $request.Method = 'HEAD' + $request.Timeout = 10000 + try { $response = $request.GetResponse(); $response.Close() } catch { } + + $cert = $request.ServicePoint.Certificate + if (-not $cert) { + Write-Warn 'Could not read the TLS certificate chain; skipping corp CA staging.' + return + } + + $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain + $chain.ChainPolicy.RevocationMode = 'NoCheck' + $cert2 = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($cert) + [void]$chain.Build($cert2) + + $root = $chain.ChainElements[$chain.ChainElements.Count - 1].Certificate + $issuer = $root.Subject + + $builder = New-Object System.Text.StringBuilder + [void]$builder.AppendLine('-----BEGIN CERTIFICATE-----') + [void]$builder.AppendLine([System.Convert]::ToBase64String($root.RawData, 'InsertLineBreaks')) + [void]$builder.AppendLine('-----END CERTIFICATE-----') + Set-Content -Path $certPath -Value $builder.ToString() -Encoding ASCII + + Write-Ok "Staged corp-root-ca.pem from root CA: $issuer" + } + catch { + Write-Warn "Corp CA detection failed ($($_.Exception.Message)); continuing without it." + } +} + # Confirm a dependency, offering a winget install when it is missing. Returns # $true when the dependency is present (or was just installed), $false when the # dev declined or install failed. @@ -246,6 +291,9 @@ try { # --- 4. Build and start --------------------------------------------------- + Write-Step 'Detecting corporate TLS-inspection CA for the Docker build' + Set-CorpRootCa -RepoRoot $repoRoot + Write-Step "Building and starting the '$($config.Project)' stack" $composeArgs = @( 'compose',