diff --git a/scripts/install/install.ps1 b/scripts/install/install.ps1 index ed4a3e1a32..f66c965531 100644 --- a/scripts/install/install.ps1 +++ b/scripts/install/install.ps1 @@ -55,27 +55,35 @@ function Normalize-Version { return $RawVersion } -function Get-ReleaseAssetMetadata { +function Get-ReleaseAssetUrl { param( [string]$AssetName, [string]$ResolvedVersion ) - $release = Invoke-RestMethod -Uri "https://api.github.com/repos/openai/codex/releases/tags/rust-v$ResolvedVersion" - $asset = $release.assets | Where-Object { $_.name -eq $AssetName } | Select-Object -First 1 - if ($null -eq $asset) { - throw "Could not find release asset $AssetName for Codex $ResolvedVersion." + return "https://github.com/openai/codex/releases/download/rust-v$ResolvedVersion/$AssetName" +} + +function Get-ChecksumForAsset { + param( + [string]$ChecksumsPath, + [string]$AssetName + ) + + foreach ($line in Get-Content -LiteralPath $ChecksumsPath) { + $parts = $line -split "\s+", 2 + if ($parts.Length -ne 2) { + continue + } + + $digest = $parts[0] + $filename = $parts[1].TrimStart("*") + if ($filename -eq $AssetName -and $digest -match "^[0-9a-fA-F]{64}$") { + return $digest.ToLowerInvariant() + } } - $digestMatch = [regex]::Match([string]$asset.digest, "^sha256:([0-9a-fA-F]{64})$") - if (-not $digestMatch.Success) { - throw "Could not find SHA-256 digest for release asset $AssetName." - } - - return [PSCustomObject]@{ - Url = $asset.browser_download_url - Sha256 = $digestMatch.Groups[1].Value.ToLowerInvariant() - } + throw "Could not find SHA-256 checksum for release asset $AssetName." } function Test-ArchiveDigest { @@ -86,7 +94,7 @@ function Test-ArchiveDigest { $actualDigest = (Get-FileHash -LiteralPath $ArchivePath -Algorithm SHA256).Hash.ToLowerInvariant() if ($actualDigest -ne $ExpectedDigest) { - throw "Downloaded Codex archive checksum did not match release metadata. Expected $ExpectedDigest but got $actualDigest." + throw "Downloaded Codex archive checksum did not match release checksums. Expected $ExpectedDigest but got $actualDigest." } } @@ -637,7 +645,7 @@ Write-Step "Resolved version: $resolvedVersion" $conflictingInstall = Get-ConflictingInstall -VisibleBinDir $visibleBinDir $oldStandaloneBackup = $null -$packageAsset = "codex-npm-$npmTag-$resolvedVersion.tgz" +$packageAsset = "codex-standalone-$npmTag-$resolvedVersion.tar.gz" $tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ("codex-install-" + [System.Guid]::NewGuid().ToString("N")) New-Item -ItemType Directory -Force -Path $tempDir | Out-Null @@ -651,13 +659,17 @@ try { } $archivePath = Join-Path $tempDir $packageAsset + $checksumsPath = Join-Path $tempDir "codex-installer_SHA256SUMS" $extractDir = Join-Path $tempDir "extract" $stagingDir = Join-Path $releasesDir ".staging.$releaseName.$PID" - $assetMetadata = Get-ReleaseAssetMetadata -AssetName $packageAsset -ResolvedVersion $resolvedVersion + $archiveUrl = Get-ReleaseAssetUrl -AssetName $packageAsset -ResolvedVersion $resolvedVersion + $checksumsUrl = Get-ReleaseAssetUrl -AssetName "codex-installer_SHA256SUMS" -ResolvedVersion $resolvedVersion Write-Step "Downloading Codex CLI" - Invoke-WebRequest -Uri $assetMetadata.Url -OutFile $archivePath - Test-ArchiveDigest -ArchivePath $archivePath -ExpectedDigest $assetMetadata.Sha256 + Invoke-WebRequest -Uri $checksumsUrl -OutFile $checksumsPath + $expectedDigest = Get-ChecksumForAsset -ChecksumsPath $checksumsPath -AssetName $packageAsset + Invoke-WebRequest -Uri $archiveUrl -OutFile $archivePath + Test-ArchiveDigest -ArchivePath $archivePath -ExpectedDigest $expectedDigest New-Item -ItemType Directory -Force -Path $extractDir | Out-Null New-Item -ItemType Directory -Force -Path $releasesDir | Out-Null @@ -667,18 +679,17 @@ try { New-Item -ItemType Directory -Force -Path $stagingDir | Out-Null tar -xzf $archivePath -C $extractDir - $vendorRoot = Join-Path $extractDir "package/vendor/$target" $resourcesDir = Join-Path $stagingDir "codex-resources" New-Item -ItemType Directory -Force -Path $resourcesDir | Out-Null $copyMap = @{ - "codex/codex.exe" = "codex.exe" - "codex/codex-command-runner.exe" = "codex-resources\codex-command-runner.exe" - "codex/codex-windows-sandbox-setup.exe" = "codex-resources\codex-windows-sandbox-setup.exe" - "path/rg.exe" = "codex-resources\rg.exe" + "codex.exe" = "codex.exe" + "codex-resources\codex-command-runner.exe" = "codex-resources\codex-command-runner.exe" + "codex-resources\codex-windows-sandbox-setup.exe" = "codex-resources\codex-windows-sandbox-setup.exe" + "codex-resources\rg.exe" = "codex-resources\rg.exe" } foreach ($relativeSource in $copyMap.Keys) { - Copy-Item -LiteralPath (Join-Path $vendorRoot $relativeSource) -Destination (Join-Path $stagingDir $copyMap[$relativeSource]) + Copy-Item -LiteralPath (Join-Path $extractDir $relativeSource) -Destination (Join-Path $stagingDir $copyMap[$relativeSource]) } if (Test-Path -LiteralPath $releaseDir) { diff --git a/scripts/install/install.sh b/scripts/install/install.sh index 8c225e4d3b..6d8d9bfdc5 100755 --- a/scripts/install/install.sh +++ b/scripts/install/install.sh @@ -114,55 +114,29 @@ release_url_for_asset() { printf 'https://github.com/openai/codex/releases/download/rust-v%s/%s\n' "$resolved_version" "$asset" } -release_metadata_url() { - resolved_version="$1" +checksum_for_asset() { + checksums_path="$1" + asset="$2" - printf 'https://api.github.com/repos/openai/codex/releases/tags/rust-v%s\n' "$resolved_version" -} - -release_asset_digest() { - asset="$1" - resolved_version="$2" - release_json="$(download_text "$(release_metadata_url "$resolved_version")")" - - digest="$(printf '%s\n' "$release_json" | awk -v asset="$asset" ' - { - if ($0 ~ "\"name\":[[:space:]]*\"" asset "\"") { - in_asset = 1 - asset_depth = depth - } - - if (in_asset && /"digest":[[:space:]]*"[^"]+"/) { - sub(/^.*"digest":[[:space:]]*"/, "") - sub(/".*$/, "") - digest = $0 - } - - line = $0 - opens = gsub(/\{/, "{", line) - closes = gsub(/\}/, "}", line) - depth += opens - closes - - if (in_asset && depth < asset_depth) { - in_asset = 0 - } + digest="$(awk -v asset="$asset" ' + $2 == asset { + print $1 + found = 1 + exit } END { - if (digest != "") { - print digest + if (!found) { + exit 1 } } - ')" + ' "$checksums_path" || true)" - case "$digest" in - sha256:????????????????????????????????????????????????????????????????) - printf '%s\n' "${digest#sha256:}" - ;; - *) - echo "Could not find SHA-256 digest for release asset $asset." >&2 - exit 1 - ;; - esac + if ! printf '%s\n' "$digest" | grep -Eq '^[0-9a-fA-F]{64}$'; then + echo "Could not find SHA-256 checksum for release asset $asset." >&2 + exit 1 + fi + + printf '%s\n' "$digest" | tr 'A-F' 'a-f' } file_sha256() { @@ -193,7 +167,7 @@ verify_archive_digest() { actual_digest="$(file_sha256 "$archive_path")" if [ "$actual_digest" != "$expected_digest" ]; then - echo "Downloaded Codex archive checksum did not match release metadata." >&2 + echo "Downloaded Codex archive checksum did not match release checksums." >&2 echo "expected: $expected_digest" >&2 echo "actual: $actual_digest" >&2 exit 1 @@ -586,14 +560,14 @@ handle_conflicting_install() { install_release() { release_dir="$1" - vendor_root="$2" + archive_root="$2" stage_release="$RELEASES_DIR/.staging.$(basename "$release_dir").$$" mkdir -p "$RELEASES_DIR" rm -rf "$stage_release" mkdir -p "$stage_release/codex-resources" - cp "$vendor_root/codex/codex" "$stage_release/codex" - cp "$vendor_root/path/rg" "$stage_release/codex-resources/rg" + cp "$archive_root/codex" "$stage_release/codex" + cp "$archive_root/codex-resources/rg" "$stage_release/codex-resources/rg" chmod 0755 "$stage_release/codex" chmod 0755 "$stage_release/codex-resources/rg" @@ -692,7 +666,7 @@ else fi resolved_version="$(resolve_version)" -asset="codex-npm-$npm_tag-$resolved_version.tgz" +asset="codex-standalone-$npm_tag-$resolved_version.tar.gz" download_url="$(release_url_for_asset "$asset" "$resolved_version")" release_name="$resolved_version-$vendor_target" release_dir="$RELEASES_DIR/$release_name" @@ -728,10 +702,12 @@ if ! release_dir_is_complete "$release_dir" "$resolved_version" "$vendor_target" fi archive_path="$tmp_dir/$asset" + checksums_path="$tmp_dir/codex-installer_SHA256SUMS" extract_dir="$tmp_dir/extract" step "Downloading Codex CLI" - expected_digest="$(release_asset_digest "$asset" "$resolved_version")" + download_file "$(release_url_for_asset "codex-installer_SHA256SUMS" "$resolved_version")" "$checksums_path" + expected_digest="$(checksum_for_asset "$checksums_path" "$asset")" download_file "$download_url" "$archive_path" verify_archive_digest "$archive_path" "$expected_digest" @@ -739,7 +715,7 @@ if ! release_dir_is_complete "$release_dir" "$resolved_version" "$vendor_target" tar -xzf "$archive_path" -C "$extract_dir" step "Installing standalone package to $release_dir" - install_release "$release_dir" "$extract_dir/package/vendor/$vendor_target" + install_release "$release_dir" "$extract_dir" fi update_current_link "$release_dir" update_visible_command