diff --git a/scripts/Deploy-Brass.ps1 b/scripts/Deploy-Brass.ps1 index 554a081..9567975 100644 --- a/scripts/Deploy-Brass.ps1 +++ b/scripts/Deploy-Brass.ps1 @@ -259,30 +259,68 @@ if ($shouldRunPack -and -not $DryRun -and $ManifestPublicUrl) { catch { throw "Failed to fetch deployed manifest: $($_.Exception.Message)" } $expectedHost = ([uri]$ManifestPublicUrl).Host - $problems = @() - $lock = Get-Content (Join-Path $repoRoot 'pack\pack.lock.json') -Raw | ConvertFrom-Json - if ($live.version -ne $lock.version) { - $problems += "version mismatch: live=$($live.version), local=$($lock.version)" - } + $problems = @() + $hasLockField = { param($name) ($lock.PSObject.Properties.Name -contains $name) -and $lock.$name } + + # ── Top-level required fields (sourced from pack.lock) ── + if (-not $live.name) { $problems += "name missing" } + elseif ($live.name -ne $lock.name) { $problems += "name mismatch: live=$($live.name), local=$($lock.name)" } + if (-not $live.version) { $problems += "version missing" } + elseif ($live.version -ne $lock.version) { $problems += "version mismatch: live=$($live.version), local=$($lock.version)" } + if (-not $live.minecraft.version) { $problems += "minecraft.version missing" } + elseif ($live.minecraft.version -ne $lock.minecraft) { $problems += "minecraft.version mismatch: live=$($live.minecraft.version), local=$($lock.minecraft)" } + if (-not $live.loader.type) { $problems += "loader.type missing" } + elseif ($live.loader.type -ne $lock.loader.type) { $problems += "loader.type mismatch: live=$($live.loader.type), local=$($lock.loader.type)" } + if (-not $live.loader.version) { $problems += "loader.version missing" } + elseif ($live.loader.version -ne $lock.loader.version) { $problems += "loader.version mismatch: live=$($live.loader.version), local=$($lock.loader.version)" } + + # ── Launcher metadata (always required once a launcher has ever shipped) ── if (-not $live.launcherVersion) { $problems += "launcherVersion missing (old launchers won't see upgrade banner)" } if (-not $live.launcherUrl) { $problems += "launcherUrl missing" } if ($live.launcherUrl -and ([uri]$live.launcherUrl).Host -ne $expectedHost) { - $problems += "launcherUrl host is $([uri]$live.launcherUrl).Host, expected $expectedHost" + $problems += "launcherUrl host is $(([uri]$live.launcherUrl).Host), expected $expectedHost" } - # Sample a self-hosted file (skip CDN-hosted mods) - $local = $live.files | Where-Object { $_.url -notmatch 'modrinth|forgecdn|curseforge' } | Select-Object -First 1 - if ($local -and ([uri]$local.url).Host -ne $expectedHost) { - $problems += "self-hosted file URL host is $([uri]$local.url).Host, expected $expectedHost (path: $($local.path))" + + # ── Optional fields: consistency check. If pack.lock has it, manifest must too. ── + if ((& $hasLockField 'panelUrl') -and -not $live.panelUrl) { + $problems += "panelUrl missing from manifest but set in pack.lock.json (friend whitelist requests will fail)" + } + if ((& $hasLockField 'defaultShader') -and -not $live.defaultShader) { + $problems += "defaultShader missing from manifest but set in pack.lock.json" + } + if ((& $hasLockField 'defaultServer') -and (-not $live.defaultServer -or -not $live.defaultServer.ip)) { + $problems += "defaultServer missing/incomplete in manifest but set in pack.lock.json" + } + + # ── files[]: every entry has the shape clients depend on; self-hosted URLs use expected host ── + if (-not $live.files -or $live.files.Count -eq 0) { + $problems += "files array is empty" + } else { + $i = 0 + foreach ($f in $live.files) { + if (-not $f.path) { $problems += "files[$i].path missing" } + if (-not $f.url) { $problems += "files[$i].url missing (path=$($f.path))" } + if (-not $f.sha1 -or $f.sha1.Length -ne 40) { $problems += "files[$i].sha1 invalid (path=$($f.path))" } + if (-not $f.size -or $f.size -le 0) { $problems += "files[$i].size invalid (path=$($f.path))" } + # Self-hosted (non-CDN) URLs must use the expected host. CDN mods are exempt. + if ($f.url -and $f.url -notmatch 'modrinth|forgecdn|curseforge') { + $h = ([uri]$f.url).Host + if ($h -ne $expectedHost) { + $problems += "files[$i] self-hosted URL host is $h, expected $expectedHost (path=$($f.path))" + } + } + $i++ + } } if ($problems.Count -gt 0) { Write-Host "" Write-Host "DEPLOYED MANIFEST FAILED VERIFICATION:" -ForegroundColor Red foreach ($p in $problems) { Write-Host " - $p" -ForegroundColor Red } - throw "Deployed manifest is missing required fields. Fix and redeploy." + throw "Deployed manifest has $($problems.Count) issue(s). Fix and redeploy." } - Write-Host (" version={0} launcherVersion={1} ok" -f $live.version, $live.launcherVersion) -ForegroundColor DarkGray + Write-Host (" version={0} launcherVersion={1} files={2} ok" -f $live.version, $live.launcherVersion, $live.files.Count) -ForegroundColor DarkGray } }