Harden scratch setup bootstrap and authority admin scopes

This commit is contained in:
master
2026-03-12 13:12:32 +02:00
parent 29b68f5bee
commit 509b97a1a7
7 changed files with 144 additions and 12 deletions

View File

@@ -406,7 +406,7 @@ services:
Platform__EnvironmentSettings__TokenEndpoint: "https://stella-ops.local/connect/token" Platform__EnvironmentSettings__TokenEndpoint: "https://stella-ops.local/connect/token"
Platform__EnvironmentSettings__RedirectUri: "https://stella-ops.local/auth/callback" Platform__EnvironmentSettings__RedirectUri: "https://stella-ops.local/auth/callback"
Platform__EnvironmentSettings__PostLogoutRedirectUri: "https://stella-ops.local/" Platform__EnvironmentSettings__PostLogoutRedirectUri: "https://stella-ops.local/"
Platform__EnvironmentSettings__Scope: "openid profile email offline_access ui.read ui.admin ui.preferences.read ui.preferences.write authority:tenants.read authority:users.read authority:roles.read authority:clients.read authority:tokens.read authority:branding.read authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve policy:run policy:activate policy:audit policy:edit policy:operate policy:publish airgap:seal airgap:status:read orch:read orch:quota analytics.read advisory:read advisory-ai:view advisory-ai:operate vex:read vexhub:read exceptions:read exceptions:approve aoc:verify findings:read release:read release:write release:publish scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin ops.health integration:read integration:write integration:operate packs.read packs.write packs.run packs.approve registry.admin timeline:read timeline:write trust:read trust:write trust:admin signer:read signer:sign signer:rotate signer:admin" Platform__EnvironmentSettings__Scope: "openid profile email offline_access ui.read ui.admin ui.preferences.read ui.preferences.write authority:tenants.read authority:tenants.write authority:users.read authority:users.write authority:roles.read authority:roles.write authority:clients.read authority:clients.write authority:tokens.read authority:tokens.revoke authority:branding.read authority:branding.write authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve policy:run policy:activate policy:audit policy:edit policy:operate policy:publish airgap:seal airgap:status:read orch:read orch:quota analytics.read advisory:read advisory-ai:view advisory-ai:operate vex:read vexhub:read exceptions:read exceptions:approve aoc:verify findings:read release:read release:write release:publish scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin ops.health integration:read integration:write integration:operate packs.read packs.write packs.run packs.approve registry.admin timeline:read timeline:write trust:read trust:write trust:admin signer:read signer:sign signer:rotate signer:admin"
STELLAOPS_ROUTER_URL: "http://router.stella-ops.local" STELLAOPS_ROUTER_URL: "http://router.stella-ops.local"
STELLAOPS_PLATFORM_URL: "http://platform.stella-ops.local" STELLAOPS_PLATFORM_URL: "http://platform.stella-ops.local"
STELLAOPS_AUTHORITY_URL: "http://authority.stella-ops.local" STELLAOPS_AUTHORITY_URL: "http://authority.stella-ops.local"
@@ -509,7 +509,7 @@ services:
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__ClientId: "stella-ops-ui" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__ClientId: "stella-ops-ui"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__DisplayName: "Stella Ops Console" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__DisplayName: "Stella Ops Console"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__AllowedGrantTypes: "authorization_code refresh_token" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__AllowedGrantTypes: "authorization_code refresh_token"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__AllowedScopes: "openid profile email offline_access ui.read ui.admin ui.preferences.read ui.preferences.write authority:tenants.read authority:users.read authority:roles.read authority:clients.read authority:tokens.read authority:branding.read authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve policy:run policy:activate policy:audit policy:edit policy:operate policy:publish airgap:seal airgap:status:read orch:read orch:quota analytics.read advisory:read advisory-ai:view advisory-ai:operate vex:read vexhub:read exceptions:read exceptions:approve aoc:verify findings:read release:read release:write release:publish scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin ops.health integration:read integration:write integration:operate packs.read packs.write packs.run packs.approve registry.admin timeline:read timeline:write trust:read trust:write trust:admin signer:read signer:sign signer:rotate signer:admin" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__AllowedScopes: "openid profile email offline_access ui.read ui.admin ui.preferences.read ui.preferences.write authority:tenants.read authority:tenants.write authority:users.read authority:users.write authority:roles.read authority:roles.write authority:clients.read authority:clients.write authority:tokens.read authority:tokens.revoke authority:branding.read authority:branding.write authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve policy:run policy:activate policy:audit policy:edit policy:operate policy:publish airgap:seal airgap:status:read orch:read orch:quota analytics.read advisory:read advisory-ai:view advisory-ai:operate vex:read vexhub:read exceptions:read exceptions:approve aoc:verify findings:read release:read release:write release:publish scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin ops.health integration:read integration:write integration:operate packs.read packs.write packs.run packs.approve registry.admin timeline:read timeline:write trust:read trust:write trust:admin signer:read signer:sign signer:rotate signer:admin"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__RedirectUris: "https://stella-ops.local/auth/callback https://stella-ops.local/auth/silent-refresh https://127.1.0.1/auth/callback https://127.1.0.1/auth/silent-refresh" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__RedirectUris: "https://stella-ops.local/auth/callback https://stella-ops.local/auth/silent-refresh https://127.1.0.1/auth/callback https://127.1.0.1/auth/silent-refresh"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__PostLogoutRedirectUris: "https://stella-ops.local/ https://127.1.0.1/" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__PostLogoutRedirectUris: "https://stella-ops.local/ https://127.1.0.1/"
STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__RequirePkce: "true" STELLAOPS_AUTHORITY_AUTHORITY__PLUGINS__DESCRIPTORS__standard__BootstrapClients__0__RequirePkce: "true"

View File

@@ -6,7 +6,7 @@
"tokenEndpoint": "https://stella-ops.local/connect/token", "tokenEndpoint": "https://stella-ops.local/connect/token",
"redirectUri": "https://stella-ops.local/auth/callback", "redirectUri": "https://stella-ops.local/auth/callback",
"postLogoutRedirectUri": "https://stella-ops.local/", "postLogoutRedirectUri": "https://stella-ops.local/",
"scope": "openid profile email offline_access ui.read ui.admin ui.preferences.read ui.preferences.write authority:tenants.read authority:users.read authority:roles.read authority:clients.read authority:tokens.read authority:branding.read authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve policy:run policy:activate policy:audit policy:edit policy:operate policy:publish airgap:seal airgap:status:read orch:read orch:quota analytics.read advisory:read advisory-ai:view advisory-ai:operate vex:read vexhub:read exceptions:read exceptions:approve aoc:verify findings:read release:read release:write release:publish scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin ops.health integration:read integration:write integration:operate packs.read packs.write packs.run packs.approve registry.admin timeline:read timeline:write", "scope": "openid profile email offline_access ui.read ui.admin ui.preferences.read ui.preferences.write authority:tenants.read authority:tenants.write authority:users.read authority:users.write authority:roles.read authority:roles.write authority:clients.read authority:clients.write authority:tokens.read authority:tokens.revoke authority:branding.read authority:branding.write authority.audit.read graph:read sbom:read scanner:read policy:read policy:simulate policy:author policy:review policy:approve policy:run policy:activate policy:audit policy:edit policy:operate policy:publish airgap:seal airgap:status:read orch:read orch:quota analytics.read advisory:read advisory-ai:view advisory-ai:operate vex:read vexhub:read exceptions:read exceptions:approve aoc:verify findings:read release:read release:write release:publish scheduler:read scheduler:operate notify.viewer notify.operator notify.admin notify.escalate evidence:read export.viewer export.operator export.admin vuln:view vuln:investigate vuln:operate vuln:audit platform.context.read platform.context.write doctor:run doctor:admin ops.health integration:read integration:write integration:operate packs.read packs.write packs.run packs.approve registry.admin timeline:read timeline:write",
"audience": "stella-ops-api", "audience": "stella-ops-api",
"dpopAlgorithms": [ "dpopAlgorithms": [
"ES256" "ES256"

View File

@@ -637,8 +637,12 @@ VALUES
ARRAY['https://stella-ops.local/', 'https://127.1.0.1/'], ARRAY['https://stella-ops.local/', 'https://127.1.0.1/'],
ARRAY['openid', 'profile', 'email', 'offline_access', ARRAY['openid', 'profile', 'email', 'offline_access',
'ui.read', 'ui.admin', 'ui.preferences.read', 'ui.preferences.write', 'ui.read', 'ui.admin', 'ui.preferences.read', 'ui.preferences.write',
'authority:tenants.read', 'authority:users.read', 'authority:roles.read', 'authority:tenants.read', 'authority:tenants.write',
'authority:clients.read', 'authority:tokens.read', 'authority:branding.read', 'authority:users.read', 'authority:users.write',
'authority:roles.read', 'authority:roles.write',
'authority:clients.read', 'authority:clients.write',
'authority:tokens.read', 'authority:tokens.revoke',
'authority:branding.read', 'authority:branding.write',
'authority.audit.read', 'authority.audit.read',
'graph:read', 'sbom:read', 'scanner:read', 'graph:read', 'sbom:read', 'scanner:read',
'policy:read', 'policy:simulate', 'policy:author', 'policy:review', 'policy:approve', 'policy:read', 'policy:simulate', 'policy:author', 'policy:review', 'policy:approve',

View File

@@ -56,7 +56,7 @@ The scripts will:
4. Start infrastructure and wait for healthy containers 4. Start infrastructure and wait for healthy containers
5. Create or reuse the external frontdoor Docker network from `.env` (`FRONTDOOR_NETWORK`, default `stellaops_frontdoor`) 5. Create or reuse the external frontdoor Docker network from `.env` (`FRONTDOOR_NETWORK`, default `stellaops_frontdoor`)
6. Stop repo-local host-run Stella services that would lock build outputs, then build repo-owned .NET solutions and publish backend services locally into small Docker contexts before building hardened runtime images (vendored dependency trees such as `node_modules` are excluded) 6. Stop repo-local host-run Stella services that would lock build outputs, then build repo-owned .NET solutions and publish backend services locally into small Docker contexts before building hardened runtime images (vendored dependency trees such as `node_modules` are excluded)
7. Launch the full platform with health checks 7. Launch the full platform with health checks and wait for the first-user frontdoor bootstrap path (`/welcome`, `/envsettings.json`, OIDC discovery, `/connect/authorize`) before reporting success
Open **https://stella-ops.local** when setup completes. Open **https://stella-ops.local** when setup completes.

View File

@@ -29,7 +29,7 @@ Setup scripts validate prerequisites, build solutions and Docker images, and lau
./scripts/setup.sh --images-only # only build Docker images ./scripts/setup.sh --images-only # only build Docker images
``` ```
The scripts will check for required tools (dotnet 10.x, node 20+, npm 10+, docker, git), warn about missing hosts file entries, copy `.env` from the example if needed, and stop repo-local host-run Stella services before the solution build so scratch bootstraps do not fail on locked `bin/Debug` outputs. See the manual steps below for details on each stage. The scripts will check for required tools (dotnet 10.x, node 20+, npm 10+, docker, git), warn about missing hosts file entries, copy `.env` from the example if needed, and stop repo-local host-run Stella services before the solution build so scratch bootstraps do not fail on locked `bin/Debug` outputs. A full setup now waits for the first-user frontdoor bootstrap path as well: `/welcome`, `/envsettings.json`, OIDC discovery, and a PKCE-style `/connect/authorize` request must all be live before the script prints success. See the manual steps below for details on each stage.
On Windows and Linux, the backend image builder now publishes each selected .NET service locally and builds the hardened runtime image from a small temporary context. That avoids repeatedly streaming the whole monorepo into Docker during scratch setup. On Windows and Linux, the backend image builder now publishes each selected .NET service locally and builds the hardened runtime image from a small temporary context. That avoids repeatedly streaming the whole monorepo into Docker during scratch setup.

View File

@@ -470,11 +470,21 @@ function Start-Platform {
function Test-ExpectedHttpStatus([string]$url, [int[]]$allowedStatusCodes, [int]$timeoutSeconds = 5, [int]$attempts = 6, [int]$retryDelaySeconds = 2) { function Test-ExpectedHttpStatus([string]$url, [int[]]$allowedStatusCodes, [int]$timeoutSeconds = 5, [int]$attempts = 6, [int]$retryDelaySeconds = 2) {
for ($attempt = 1; $attempt -le $attempts; $attempt++) { for ($attempt = 1; $attempt -le $attempts; $attempt++) {
$statusCode = $null $statusCode = $null
$previousCertificateCallback = $null
$hasCertificateCallbackOverride = $false
try { try {
$request = [System.Net.WebRequest]::Create($url) $request = [System.Net.WebRequest]::Create($url)
$request.Method = 'GET' $request.Method = 'GET'
$request.Timeout = $timeoutSeconds * 1000 $request.Timeout = $timeoutSeconds * 1000
if ($request -is [System.Net.HttpWebRequest]) {
$request.AllowAutoRedirect = $false
}
if ($url.StartsWith('https://', [System.StringComparison]::OrdinalIgnoreCase)) {
$previousCertificateCallback = [System.Net.ServicePointManager]::ServerCertificateValidationCallback
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
$hasCertificateCallbackOverride = $true
}
$response = [System.Net.HttpWebResponse]$request.GetResponse() $response = [System.Net.HttpWebResponse]$request.GetResponse()
try { try {
@@ -492,6 +502,10 @@ function Test-ExpectedHttpStatus([string]$url, [int[]]$allowedStatusCodes, [int]
} }
} }
} catch { } catch {
} finally {
if ($hasCertificateCallbackOverride) {
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $previousCertificateCallback
}
} }
if ($null -ne $statusCode -and $allowedStatusCodes -contains $statusCode) { if ($null -ne $statusCode -and $allowedStatusCodes -contains $statusCode) {
@@ -506,6 +520,52 @@ function Test-ExpectedHttpStatus([string]$url, [int[]]$allowedStatusCodes, [int]
return $null return $null
} }
function Test-FrontdoorBootstrap {
$baseUrl = 'https://stella-ops.local'
$probes = @(
@{
Name = 'Frontdoor readiness'
Url = "$baseUrl/health/ready"
AllowedStatusCodes = @(200)
},
@{
Name = 'Frontdoor welcome page'
Url = "$baseUrl/welcome"
AllowedStatusCodes = @(200)
},
@{
Name = 'Frontdoor environment settings'
Url = "$baseUrl/envsettings.json"
AllowedStatusCodes = @(200)
},
@{
Name = 'Authority discovery'
Url = "$baseUrl/.well-known/openid-configuration"
AllowedStatusCodes = @(200)
},
@{
Name = 'Authority authorize bootstrap'
Url = "$baseUrl/connect/authorize?client_id=stella-ops-ui&redirect_uri=https%3A%2F%2Fstella-ops.local%2Fauth%2Fcallback&response_type=code&scope=openid%20profile%20email&state=setup-smoke&nonce=setup-smoke&code_challenge=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&code_challenge_method=S256"
AllowedStatusCodes = @(200, 302, 303)
}
)
Write-Step 'Waiting for frontdoor bootstrap readiness'
foreach ($probe in $probes) {
$statusCode = Test-ExpectedHttpStatus $probe.Url $probe.AllowedStatusCodes -timeoutSeconds 5 -attempts 24 -retryDelaySeconds 5
if ($null -ne $statusCode) {
Write-Ok "$($probe.Name) (HTTP $statusCode)"
continue
}
Write-Fail "$($probe.Name) did not reach an expected status ($($probe.AllowedStatusCodes -join '/'))"
return $false
}
return $true
}
# ─── 8. Smoke test ───────────────────────────────────────────────────────── # ─── 8. Smoke test ─────────────────────────────────────────────────────────
function Test-Smoke { function Test-Smoke {
@@ -559,6 +619,14 @@ function Test-Smoke {
$hasBlockingFailures = $true $hasBlockingFailures = $true
} }
if (-not $InfraOnly) {
if (Test-FrontdoorBootstrap) {
Write-Ok 'Frontdoor bootstrap path is ready for first-user sign-in'
} else {
$hasBlockingFailures = $true
}
}
# Platform container health summary # Platform container health summary
Write-Step 'Container health summary' Write-Step 'Container health summary'
Push-Location $ComposeDir Push-Location $ComposeDir
@@ -679,7 +747,8 @@ if ($InfraOnly) {
Start-Infrastructure Start-Infrastructure
$infraSmokeFailed = Test-Smoke $infraSmokeFailed = Test-Smoke
if ($infraSmokeFailed) { if ($infraSmokeFailed) {
Write-Warn 'Infrastructure started with blocking smoke failures. Review output and docker compose logs.' Write-Fail 'Infrastructure setup did not pass blocking smoke tests. Review output and docker compose logs.'
exit 1
} }
Write-Host "`nDone (infra only). Infrastructure is running." -ForegroundColor Green Write-Host "`nDone (infra only). Infrastructure is running." -ForegroundColor Green
exit 0 exit 0
@@ -696,7 +765,8 @@ if (-not $SkipImages) {
Start-Platform Start-Platform
$platformSmokeFailed = Test-Smoke $platformSmokeFailed = Test-Smoke
if ($platformSmokeFailed) { if ($platformSmokeFailed) {
Write-Warn 'Setup completed with blocking smoke failures. Review output and docker compose logs.' Write-Fail 'Setup did not pass blocking smoke tests. Review output and docker compose logs.'
exit 1
} }
Write-Host "`n=============================================" -ForegroundColor Green Write-Host "`n=============================================" -ForegroundColor Green

View File

@@ -339,7 +339,7 @@ http_status() {
local status="" local status=""
for (( attempt=1; attempt<=attempts; attempt++ )); do for (( attempt=1; attempt<=attempts; attempt++ )); do
status=$(curl -s -o /dev/null --connect-timeout 5 -w '%{http_code}' "$url" 2>/dev/null || true) status=$(curl -sk -o /dev/null --connect-timeout 5 -w '%{http_code}' "$url" 2>/dev/null || true)
if [[ -n "$status" && "$status" != "000" ]]; then if [[ -n "$status" && "$status" != "000" ]]; then
printf '%s' "$status" printf '%s' "$status"
return 0 return 0
@@ -353,16 +353,54 @@ http_status() {
return 0 return 0
} }
frontdoor_bootstrap_ready() {
step 'Waiting for frontdoor bootstrap readiness'
local probes=(
"Frontdoor readiness|https://stella-ops.local/health/ready|200"
"Frontdoor welcome page|https://stella-ops.local/welcome|200"
"Frontdoor environment settings|https://stella-ops.local/envsettings.json|200"
"Authority discovery|https://stella-ops.local/.well-known/openid-configuration|200"
"Authority authorize bootstrap|https://stella-ops.local/connect/authorize?client_id=stella-ops-ui&redirect_uri=https%3A%2F%2Fstella-ops.local%2Fauth%2Fcallback&response_type=code&scope=openid%20profile%20email&state=setup-smoke&nonce=setup-smoke&code_challenge=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&code_challenge_method=S256|200,302,303"
)
local entry name url allowed status matched
for entry in "${probes[@]}"; do
IFS='|' read -r name url allowed <<<"$entry"
status="$(http_status "$url" 24 5)"
matched=false
IFS=',' read -ra allowed_codes <<<"$allowed"
for code in "${allowed_codes[@]}"; do
if [[ "$status" == "$code" ]]; then
matched=true
break
fi
done
if [[ "$matched" == "true" ]]; then
ok "$name (HTTP $status)"
continue
fi
fail "$name did not reach an expected status ($allowed)"
return 1
done
ok 'Frontdoor bootstrap path is ready for first-user sign-in'
}
# ─── 8. Smoke test ───────────────────────────────────────────────────────── # ─── 8. Smoke test ─────────────────────────────────────────────────────────
smoke_test() { smoke_test() {
step 'Running smoke tests' step 'Running smoke tests'
local has_blocking_failures=false
# Infrastructure checks # Infrastructure checks
if docker exec stellaops-dev-postgres pg_isready -U stellaops &>/dev/null; then if docker exec stellaops-dev-postgres pg_isready -U stellaops &>/dev/null; then
ok 'PostgreSQL' ok 'PostgreSQL'
else else
warn 'PostgreSQL not responding' warn 'PostgreSQL not responding'
has_blocking_failures=true
fi fi
local pong; pong=$(docker exec stellaops-dev-valkey valkey-cli ping 2>/dev/null || true) local pong; pong=$(docker exec stellaops-dev-valkey valkey-cli ping 2>/dev/null || true)
@@ -370,6 +408,7 @@ smoke_test() {
ok 'Valkey' ok 'Valkey'
else else
warn 'Valkey not responding' warn 'Valkey not responding'
has_blocking_failures=true
fi fi
local rustfs_url rustfs_status local rustfs_url rustfs_status
@@ -379,6 +418,7 @@ smoke_test() {
ok "RustFS S3 endpoint (HTTP $rustfs_status)" ok "RustFS S3 endpoint (HTTP $rustfs_status)"
else else
warn 'RustFS S3 endpoint did not respond with an expected status (wanted 200/403)' warn 'RustFS S3 endpoint did not respond with an expected status (wanted 200/403)'
has_blocking_failures=true
fi fi
local registry_url registry_status local registry_url registry_status
@@ -388,6 +428,13 @@ smoke_test() {
ok "Zot registry endpoint (HTTP $registry_status)" ok "Zot registry endpoint (HTTP $registry_status)"
else else
warn 'Zot registry endpoint did not respond with an expected status (wanted 200/401)' warn 'Zot registry endpoint did not respond with an expected status (wanted 200/401)'
has_blocking_failures=true
fi
if [[ "$INFRA_ONLY" != "true" ]]; then
if ! frontdoor_bootstrap_ready; then
has_blocking_failures=true
fi
fi fi
# Platform container health summary # Platform container health summary
@@ -429,9 +476,14 @@ smoke_test() {
ok 'Platform listening on https://stella-ops.local (TLS handshake pending)' ok 'Platform listening on https://stella-ops.local (TLS handshake pending)'
else else
warn 'Platform not yet accessible at https://stella-ops.local (may still be starting)' warn 'Platform not yet accessible at https://stella-ops.local (may still be starting)'
has_blocking_failures=true
fi fi
cd "$ROOT" cd "$ROOT"
if [[ "$has_blocking_failures" == "true" ]]; then
return 1
fi
} }
# ─── Main ─────────────────────────────────────────────────────────────────── # ─── Main ───────────────────────────────────────────────────────────────────
@@ -454,7 +506,10 @@ ensure_env
start_infra start_infra
if [[ "$INFRA_ONLY" == "true" ]]; then if [[ "$INFRA_ONLY" == "true" ]]; then
smoke_test if ! smoke_test; then
fail 'Infrastructure setup did not pass blocking smoke tests. Review output and docker compose logs.'
exit 1
fi
echo '' echo ''
echo 'Done (infra only). Infrastructure is running.' echo 'Done (infra only). Infrastructure is running.'
exit 0 exit 0
@@ -473,7 +528,10 @@ if [[ "$SKIP_IMAGES" != "true" ]]; then
fi fi
start_platform start_platform
smoke_test if ! smoke_test; then
fail 'Setup did not pass blocking smoke tests. Review output and docker compose logs.'
exit 1
fi
echo '' echo ''
echo '=============================================' echo '============================================='