Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ jobs:
node --check scripts/ci/verify-cli-release-channel.js
node --check scripts/ci/verify-cli-upgrade-result.js
node --check scripts/ci/verify-standalone-runtime.js
node --check scripts/ci/verify-standalone-dependencies.js
php -l scripts/ci/probe-standalone-runtime.php
bash -n scripts/ci/verify-release-tag-source.sh
bash -n scripts/ci/establish-native-prerequisites.sh
Expand All @@ -95,6 +96,7 @@ jobs:
python scripts/ci/test-native-prerequisites.py
node --test scripts/ci/test-release-workflow-metadata.js
node --test scripts/ci/test-standalone-runtime.js
node --test scripts/ci/test-standalone-dependencies.js
node --test scripts/ci/test-cli-release-channel.js
node --test scripts/ci/test-cli-upgrade-result.js
node --test scripts/ci/test-release-metadata.js
Expand Down
73 changes: 64 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,9 @@ jobs:
fi
release_metadata="$(node scripts/ci/release-version.js metadata "$tag")"
read -r prerelease make_latest <<< "$release_metadata"
if [ "$tag" = "2.0.0" ]; then
if [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]; then
echo "::error::Stable 2.0.0 publication requires a protected main-branch dispatch"
exit 1
fi
if [ "$tag" = "2.0.0" ] && [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]; then
echo "::error::Stable 2.0.0 publication requires a protected main-branch dispatch"
exit 1
fi
fi
if ! printf '%s\n' "$commit" | grep -Eq '^[0-9a-f]{40}$'; then
Expand Down Expand Up @@ -481,6 +479,8 @@ jobs:
scripts/ci/establish-native-prerequisites.sh
scripts/ci/probe-standalone-runtime.php
scripts/ci/verify-standalone-runtime.js
scripts/ci/verify-standalone-dependencies.js
scripts/ci/standalone-dependencies.json
sparse-checkout-cone-mode: false

- name: Download PHAR artifact
Expand Down Expand Up @@ -606,6 +606,10 @@ jobs:
macOS)
package_identity="$(brew list --versions | sort)"
;;
*)
echo "::error::Unsupported native build platform"
exit 1
;;
esac
native_toolchain_id="$(
{
Expand All @@ -624,10 +628,11 @@ jobs:
run: |
set -euo pipefail
sha256_file() {
local file="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
sha256sum "$file" | awk '{print $1}'
else
shasum -a 256 "$1" | awk '{print $1}'
shasum -a 256 "$file" | awk '{print $1}'
fi
}
sha256_stdin() {
Expand All @@ -648,6 +653,8 @@ jobs:
sha256_file release-toolchain-control/scripts/ci/establish-native-prerequisites.sh
)"
extensions_sha="$(printf '%s' "$SPC_EXTENSIONS" | sha256_stdin)"
dependency_identity="$(node release-toolchain-control/scripts/ci/verify-standalone-dependencies.js identity)"
printf '%s\n' "$dependency_identity" > build/.tools/dependency-policy.json
runner_image="${ImageOS}-${ImageVersion}"
toolchain_id="$(
printf '%s\n' \
Expand All @@ -656,6 +663,7 @@ jobs:
"spc_revision=$SPC_REVISION" \
"php_version=$PHP_VERSION" \
"extensions=$SPC_EXTENSIONS" \
"dependency_policy=$dependency_identity" \
"native_toolchain_id=${{ steps.native-prerequisites.outputs.toolchain_id }}" \
"native_prerequisite_identity=${{ steps.native-prerequisites.outputs.identity }}" \
"native_prerequisite_script_sha256=$native_prerequisite_script_sha" \
Expand Down Expand Up @@ -755,11 +763,14 @@ jobs:
# Keep the SHA-256-verified musl archive and lock established above.
# This remains the trusted input to spc download on a cold build.
rm -rf source buildroot
dependency_policy="$GITHUB_WORKSPACE/release-toolchain-control/scripts/ci/verify-standalone-dependencies.js"
openssl_url="$(node "$dependency_policy" url)"
case "$SPC_DOWNLOAD_OUTER_ATTEMPTS" in
''|*[!0-9]*)
echo "::error::SPC_DOWNLOAD_OUTER_ATTEMPTS must be a positive integer"
exit 1
;;
*) ;;
esac
if [ "$SPC_DOWNLOAD_OUTER_ATTEMPTS" -lt 1 ]; then
echo "::error::SPC_DOWNLOAD_OUTER_ATTEMPTS must be at least 1"
Expand All @@ -770,7 +781,9 @@ jobs:
while [ "$attempt" -le "$SPC_DOWNLOAD_OUTER_ATTEMPTS" ]; do
if ./spc download --with-php=${{ env.PHP_VERSION }} \
--for-extensions="$SPC_EXTENSIONS" --prefer-pre-built \
--custom-url="openssl:$openssl_url" \
--without-suggestions --retry="${SPC_DOWNLOAD_RETRY}"; then
node "$dependency_policy" verify-download downloads > openssl-source-verification.json
exit 0
fi

Expand Down Expand Up @@ -926,6 +939,8 @@ jobs:
build/.tools/phpmicro-timing.json
build/.tools/standalone-runtime.json
build/.tools/standalone-runtime-verification.json
build/.tools/dependency-policy.json
build/.tools/openssl-source-verification.json
if-no-files-found: warn

- name: Combine PHAR into standalone binary
Expand Down Expand Up @@ -991,11 +1006,17 @@ jobs:
run: |
php scripts/ci/test-start-dev-signals.php "$GITHUB_WORKSPACE/build/dw-${{ matrix.name }}"

- name: Retain the verified standalone dependency inventory
if: needs.resolve-release.outputs.cache_warm != 'true'
run: cp build/.tools/standalone-runtime-verification.json build/dw-${{ matrix.name }}.dependencies.json

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: needs.resolve-release.outputs.cache_warm != 'true'
with:
name: dw-${{ matrix.name }}
path: build/dw-${{ matrix.name }}
path: |
build/dw-${{ matrix.name }}
build/dw-${{ matrix.name }}.dependencies.json
if-no-files-found: error

build-binary-windows:
Expand Down Expand Up @@ -1038,6 +1059,8 @@ jobs:
.github/workflows/release.yml
scripts/ci/probe-standalone-runtime.php
scripts/ci/verify-standalone-runtime.js
scripts/ci/verify-standalone-dependencies.js
scripts/ci/standalone-dependencies.json
sparse-checkout-cone-mode: false

- name: Download PHAR artifact
Expand Down Expand Up @@ -1171,13 +1194,20 @@ jobs:
$extensionsSha = [Convert]::ToHexString(
[Security.Cryptography.SHA256]::HashData($extensionsBytes)
).ToLowerInvariant()
$dependencyPolicy = Join-Path $env:GITHUB_WORKSPACE "release-toolchain-control\scripts\ci\verify-standalone-dependencies.js"
$dependencyIdentity = & node $dependencyPolicy identity
if ($LASTEXITCODE -ne 0) {
throw "Could not resolve the pinned standalone dependency policy"
}
$dependencyIdentity | Set-Content -Path build\.tools\dependency-policy.json -Encoding utf8
$runnerImage = "$env:ImageOS-$env:ImageVersion"
$identity = @(
"schema=$env:PHPMICRO_CACHE_SCHEMA"
"spc_version=$env:SPC_VERSION"
"spc_revision=$env:SPC_REVISION"
"php_version=$env:PHP_VERSION_WINDOWS"
"extensions=$env:SPC_EXTENSIONS_WINDOWS"
"dependency_policy=$dependencyIdentity"
"native_toolchain_id=${{ steps.native-prerequisites.outputs.toolchain_id }}"
"workflow_sha256=$workflowSha"
"runner_label=windows-2022"
Expand Down Expand Up @@ -1262,6 +1292,11 @@ jobs:
working-directory: build\.tools
run: |
Remove-Item -Recurse -Force downloads,source,buildroot -ErrorAction SilentlyContinue
$dependencyPolicy = Join-Path $env:GITHUB_WORKSPACE "release-toolchain-control\scripts\ci\verify-standalone-dependencies.js"
$opensslUrl = & node $dependencyPolicy url
if ($LASTEXITCODE -ne 0) {
throw "Could not resolve the pinned OpenSSL source"
}
$outerAttempts = [int]$env:SPC_DOWNLOAD_OUTER_ATTEMPTS
if ($outerAttempts -lt 1) {
Write-Error "SPC_DOWNLOAD_OUTER_ATTEMPTS must be at least 1"
Expand All @@ -1271,8 +1306,13 @@ jobs:
for ($attempt = 1; $attempt -le $outerAttempts; $attempt++) {
.\spc.exe download --with-php=${{ env.PHP_VERSION_WINDOWS }} `
--for-extensions="$env:SPC_EXTENSIONS_WINDOWS" --prefer-pre-built `
--custom-url="openssl:$opensslUrl" `
--without-suggestions --retry="$env:SPC_DOWNLOAD_RETRY"
if ($LASTEXITCODE -eq 0) {
node $dependencyPolicy verify-download downloads > openssl-source-verification.json
if ($LASTEXITCODE -ne 0) {
throw "The OpenSSL source failed its pinned SHA-256 policy"
}
break
}

Expand Down Expand Up @@ -1444,6 +1484,8 @@ jobs:
build/.tools/phpmicro-timing.json
build/.tools/standalone-runtime.json
build/.tools/standalone-runtime-verification.json
build/.tools/dependency-policy.json
build/.tools/openssl-source-verification.json
if-no-files-found: warn

- name: Combine PHAR into standalone binary
Expand All @@ -1462,11 +1504,18 @@ jobs:
.\build\dw-windows-x86_64.exe runtime:check
.\build\dw-windows-x86_64.exe list

- name: Retain the verified standalone dependency inventory
if: needs.resolve-release.outputs.cache_warm != 'true'
shell: pwsh
run: Copy-Item build\.tools\standalone-runtime-verification.json build\dw-windows-x86_64.dependencies.json

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: needs.resolve-release.outputs.cache_warm != 'true'
with:
name: dw-windows-x86_64
path: build/dw-windows-x86_64.exe
path: |
build/dw-windows-x86_64.exe
build/dw-windows-x86_64.dependencies.json
if-no-files-found: error

bundle-release:
Expand Down Expand Up @@ -1643,6 +1692,10 @@ jobs:
dw-linux-aarch64
dw-macos-aarch64
dw-windows-x86_64.exe
dw-linux-x86_64.dependencies.json
dw-linux-aarch64.dependencies.json
dw-macos-aarch64.dependencies.json
dw-windows-x86_64.dependencies.json
install.sh
install.ps1
verify-release.sh
Expand Down Expand Up @@ -1725,12 +1778,14 @@ jobs:
echo "::error::DURABLE_WORKFLOW_RELEASE_ASSET_ATTEMPTS must be a positive integer"
exit 1
;;
*) ;;
esac
case "$sleep_seconds" in
''|*[!0-9]*)
echo "::error::DURABLE_WORKFLOW_RELEASE_ASSET_RETRY_SLEEP must be a non-negative integer"
exit 1
;;
*) ;;
esac
if [ "$attempts" -lt 1 ]; then
echo "::error::DURABLE_WORKFLOW_RELEASE_ASSET_ATTEMPTS must be at least 1"
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ make phar

Run `make help` for the complete local development surface.

Standalone release builds use the reviewed [dependency source policy](scripts/ci/standalone-dependencies.json).
The workflow verifies the OpenSSL archive before compilation and checks the
produced runtime after both cold builds and cache restores. Each release includes
per-platform `.dependencies.json` inventories in the normal checksum and
attestation set, recording PHP, OpenSSL, libcurl and available library versions.

## License

MIT
21 changes: 21 additions & 0 deletions scripts/ci/probe-standalone-runtime.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,29 @@

declare(strict_types=1);

$opensslLibraryVersion = null;
if (extension_loaded('openssl')) {
ob_start();
phpinfo(INFO_MODULES);
$moduleInfo = ob_get_clean();
if (is_string($moduleInfo) && preg_match(
'/OpenSSL Library Version(?:\s*=>)?\s*(OpenSSL \d+\.\d+\.\d+)(?:\s|$)/',
strip_tags($moduleInfo),
$matches,
) === 1) {
$opensslLibraryVersion = $matches[1];
}
}

echo json_encode([
'php_version' => PHP_VERSION,
'php_version_id' => PHP_VERSION_ID,
'sapi' => PHP_SAPI,
'os_family' => PHP_OS_FAMILY,
'openssl_version' => $opensslLibraryVersion,
'openssl_header_version' => defined('OPENSSL_VERSION_TEXT') ? OPENSSL_VERSION_TEXT : null,
'curl' => extension_loaded('curl') ? curl_version() : null,
'pcre_version' => defined('PCRE_VERSION') ? PCRE_VERSION : null,
'oniguruma_version' => defined('MB_ONIGURUMA_VERSION') ? MB_ONIGURUMA_VERSION : null,
'iconv_version' => defined('ICONV_VERSION') ? ICONV_VERSION : null,
], JSON_THROW_ON_ERROR).PHP_EOL;
13 changes: 13 additions & 0 deletions scripts/ci/standalone-dependencies.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"schema": "durable-workflow.cli.standalone-dependencies/v1",
"openssl": {
"version": "3.5.9",
"support_ends": "2030-04-08",
"filename": "openssl-3.5.9.tar.gz",
"url": "https://github.com/openssl/openssl/releases/download/openssl-3.5.9/openssl-3.5.9.tar.gz",
"sha256": "603f5602e2eef00d77fbd429d34dcd5822bb301757a1bc9cdb24c670f1eb859a"
},
"curl": {
"minimum_version": "8.23.0"
}
}
Loading
Loading