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',