diff --git a/.github/workflows/build-openssl.yml b/.github/workflows/build-openssl.yml index 2d59f70..381d156 100644 --- a/.github/workflows/build-openssl.yml +++ b/.github/workflows/build-openssl.yml @@ -1,11 +1,11 @@ -name: Build OpenSSL 3.x +name: Build OpenSSL run-name: Build OpenSSL ${{ inputs.version }} via ${{ github.event_name }} on: workflow_dispatch: inputs: build_type: - description: 'Build Type' + description: 'Build Source: OpenSSL Release or OpenSSL Branch/OpenSSL fork' required: true type: choice options: @@ -13,7 +13,7 @@ on: - branch default: release version: - description: 'OpenSSL Version or Branch (e.g., 3.4.0 or master)' + description: 'OpenSSL Release Version, OpenSSL Branch Name or OpenSSL Fork Repo(e.g. 3.4.0, master, or user/repo/branch)' required: true type: string ignore_eol: @@ -49,20 +49,31 @@ jobs: # 0. VALIDATE VERSION & EOL # ========================================================================= validate-version: - name: Validate ${{ inputs.build_type == 'release' && 'Version' || 'Branch' }} + name: Validate Inputs runs-on: ubuntu-latest + permissions: + actions: write outputs: version: ${{ steps.check.outputs.version }} + target_repo: ${{ steps.check.outputs.target_repo }} ref: ${{ steps.check.outputs.ref }} + sha: ${{ steps.check.outputs.sha }} artifact_version: ${{ steps.check.outputs.artifact_version }} + slugified_version: ${{ steps.check.outputs.slugified_version }} + is_fork: ${{ steps.check.outputs.is_fork }} steps: - name: Check EOL or Branch Existence id: check + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | VERSION="${{ inputs.version }}" BUILD_TYPE="${{ inputs.build_type }}" IGNORE_EOL="${{ inputs.ignore_eol }}" + TARGET_REPO="openssl/openssl" + IS_FORK="false" + if [ "$BUILD_TYPE" == "release" ]; then MAJOR_MINOR=$(echo "$VERSION" | cut -d. -f1,2) EOL_DATE=$(curl -s https://endoflife.date/api/openssl.json | jq -r ".[] | select(.cycle == \"$MAJOR_MINOR\") | .eol") @@ -80,20 +91,56 @@ jobs: echo "⚠️ Ignore EOL is checked. Proceeding anyway." fi fi - echo "ref=openssl-$VERSION" >> $GITHUB_OUTPUT - echo "artifact_version=$VERSION" >> $GITHUB_OUTPUT + TARGET_REF="openssl-$VERSION" + + echo "🔍 Resolving SHA for tag '$TARGET_REF'..." + SHA=$(git ls-remote --tags https://github.com/$TARGET_REPO.git "$TARGET_REF" | awk '{print $1}') + if [ -z "$SHA" ]; then + echo "❌ Tag '$TARGET_REF' not found in $TARGET_REPO." + exit 1 + fi + + ARTIFACT_VERSION="$VERSION" + SLUGIFIED_VERSION="$VERSION" else # Branch Mode - echo "🔍 Verifying branch '$VERSION' in upstream repository..." - if ! git ls-remote --heads https://github.com/openssl/openssl.git "$VERSION" | grep -q "$VERSION"; then - echo "❌ Branch '$VERSION' does not exist in openssl/openssl repository." - exit 1 + if [[ "$VERSION" == */*/* ]]; then + # Format: user/repo/branch + TARGET_REPO=$(echo "$VERSION" | cut -d'/' -f1,2) + TARGET_REF=$(echo "$VERSION" | cut -d'/' -f3-) + IS_FORK="true" + else + TARGET_REF="$VERSION" fi + + echo "🔍 Resolving SHA for branch/ref '$TARGET_REF' in repository '$TARGET_REPO'..." + SHA=$(git ls-remote https://github.com/$TARGET_REPO.git "$TARGET_REF" | awk '{print $1}') + + if [ -z "$SHA" ]; then + # Check if it's already a SHA + if [[ "$TARGET_REF" =~ ^[0-9a-f]{40}$ ]]; then + SHA="$TARGET_REF" + else + echo "❌ Reference '$TARGET_REF' does not exist in $TARGET_REPO." + exit 1 + fi + fi + TIMESTAMP=$(date -u +%Y%m%dT%H%M%SZ) - echo "ref=$VERSION" >> $GITHUB_OUTPUT - echo "artifact_version=${VERSION}_${TIMESTAMP}" >> $GITHUB_OUTPUT + # Slugify the whole version input (e.g. user/repo/branch -> user_repo_branch) + SLUGIFIED_VERSION=$(echo "$VERSION" | sed 's/\//_/g') + # Truncate for filename safety + SAFE_PART=$(echo "$SLUGIFIED_VERSION" | cut -c 1-100) + ARTIFACT_VERSION="${SAFE_PART}_${TIMESTAMP}" fi + # Output resolved information + echo "target_repo=$TARGET_REPO" >> $GITHUB_OUTPUT + echo "is_fork=$IS_FORK" >> $GITHUB_OUTPUT + echo "ref=$TARGET_REF" >> $GITHUB_OUTPUT + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "artifact_version=$ARTIFACT_VERSION" >> $GITHUB_OUTPUT + echo "slugified_version=$SLUGIFIED_VERSION" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT # ========================================================================= @@ -106,8 +153,8 @@ jobs: steps: - uses: actions/checkout@v6 with: - repository: openssl/openssl - ref: ${{ needs.validate-version.outputs.ref }} + repository: ${{ needs.validate-version.outputs.target_repo }} + ref: ${{ needs.validate-version.outputs.sha }} - name: Build Common Assets run: | @@ -149,7 +196,7 @@ jobs: ----------------------------------------------- Windows file systems fail to extract Unix symbolic links. To ensure cross-platform compatibility, this archive contains only the physical shared library files. - If this package includes the 'install_symlinks.sh' script, you MUST run it from the root of the extracted directory to recreate the required library symlinks (e.g., libcrypto.so -> libcrypto.so.3). + If this package includes the 'install_symlinks.sh' script, you MUST run it from the root of the extracted directory to recreate the required library symlinks (e.g., libcrypto.so -> libcrypto.so.X). $ cd $ sh ./install_symlinks.sh @@ -202,8 +249,8 @@ jobs: steps: - uses: actions/checkout@v6 with: - repository: openssl/openssl - ref: ${{ needs.validate-version.outputs.ref }} + repository: ${{ needs.validate-version.outputs.target_repo }} + ref: ${{ needs.validate-version.outputs.sha }} - name: Compile Windows (Standard) if: matrix.platform.label == 'Windows' && matrix.platform.arch != 'arm64ec' @@ -260,8 +307,8 @@ jobs: mkdir raw_artifact\dist\lib\import copy "%PREFIX%\bin\openssl.exe" raw_artifact\dist\ copy "%PREFIX%\bin\*.dll" raw_artifact\dist\ - copy "%PREFIX%\lib\engines-3\*.dll" raw_artifact\dist\engines\ - copy "%PREFIX%\lib\ossl-modules\*.dll" raw_artifact\dist\providers\ + for /d %%d in ("%PREFIX%\lib\engines-*") do copy "%%d\*.dll" raw_artifact\dist\engines\ + for /d %%d in ("%PREFIX%\lib\ossl-modules*") do copy "%%d\*.dll" raw_artifact\dist\providers\ copy "%PREFIX%\lib\*.lib" raw_artifact\dist\lib\import\ ) else ( mkdir raw_artifact\dist\lib\static @@ -340,16 +387,18 @@ jobs: if [ "$LABEL" == "Android" ]; then find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "*.so" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true else - # Versioned libs only - find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "*.so.3" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true - find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "*.3.dylib" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true + # Versioned libs only: libcrypto.so.X, libssl.so.X or libcrypto.X.dylib, libssl.X.dylib + find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libcrypto.so.*" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true + find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libssl.so.*" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true + find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libcrypto.*.dylib" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true + find "$PREFIX/lib" "$PREFIX/lib64" -maxdepth 1 -type f -name "libssl.*.dylib" -exec cp {} raw_artifact/dist/ \; 2>/dev/null || true fi # Engines & Providers - find "$PREFIX" -path "*/engines-3/*.so" -exec cp {} raw_artifact/dist/engines/ \; 2>/dev/null || true - find "$PREFIX" -path "*/engines-3/*.dylib" -exec cp {} raw_artifact/dist/engines/ \; 2>/dev/null || true - find "$PREFIX" -path "*/ossl-modules/*.so" -exec cp {} raw_artifact/dist/providers/ \; 2>/dev/null || true - find "$PREFIX" -path "*/ossl-modules/*.dylib" -exec cp {} raw_artifact/dist/providers/ \; 2>/dev/null || true + find "$PREFIX" -path "*/engines-*/*.so" -exec cp {} raw_artifact/dist/engines/ \; 2>/dev/null || true + find "$PREFIX" -path "*/engines-*/*.dylib" -exec cp {} raw_artifact/dist/engines/ \; 2>/dev/null || true + find "$PREFIX" -path "*/ossl-modules*/*.so" -exec cp {} raw_artifact/dist/providers/ \; 2>/dev/null || true + find "$PREFIX" -path "*/ossl-modules*/*.dylib" -exec cp {} raw_artifact/dist/providers/ \; 2>/dev/null || true # Stripping (Non-macOS) if [ "$LABEL" != "macOS" ]; then @@ -358,12 +407,26 @@ jobs: fi # Symlinks script (Linux/macOS) - if [ "$LABEL" == "Linux" ]; then - echo -e "#!/bin/sh\necho \"Restoring shared library symlinks...\"\nln -sf libcrypto.so.3 libcrypto.so\nln -sf libssl.so.3 libssl.so" > raw_artifact/dist/install_symlinks.sh - chmod +x raw_artifact/dist/install_symlinks.sh - elif [ "$LABEL" == "macOS" ]; then - echo -e "#!/bin/sh\necho \"Restoring shared library symlinks...\"\nln -sf libcrypto.3.dylib libcrypto.dylib\nln -sf libssl.3.dylib libssl.dylib" > raw_artifact/dist/install_symlinks.sh - chmod +x raw_artifact/dist/install_symlinks.sh + if [ "$LABEL" == "Linux" ] || [ "$LABEL" == "macOS" ]; then + echo "#!/bin/sh" > raw_artifact/dist/install_symlinks.sh + echo "echo \"Restoring shared library symlinks...\"" >> raw_artifact/dist/install_symlinks.sh + + cd raw_artifact/dist + for lib in libcrypto libssl; do + if [ "$LABEL" == "Linux" ]; then + REAL_FILE=$(ls ${lib}.so.* 2>/dev/null | head -n 1) + if [ -n "$REAL_FILE" ]; then + echo "ln -sf $REAL_FILE ${lib}.so" >> install_symlinks.sh + fi + else + REAL_FILE=$(ls ${lib}.*.dylib 2>/dev/null | head -n 1) + if [ -n "$REAL_FILE" ]; then + echo "ln -sf $REAL_FILE ${lib}.dylib" >> install_symlinks.sh + fi + fi + done + chmod +x install_symlinks.sh + cd - > /dev/null fi else @@ -556,19 +619,33 @@ jobs: # Create Metadata if [ "${{ inputs.build_type }}" == "branch" ]; then - echo "branch: ${{ needs.validate-version.outputs.version }}" > dist/version.txt + echo "branch: ${{ needs.validate-version.outputs.slugified_version }}" > dist/version.txt else - echo "${{ needs.validate-version.outputs.version }}" > dist/version.txt + echo "${{ needs.validate-version.outputs.slugified_version }}" > dist/version.txt fi # Create Symlink Script (POSIX only, if not already present) if [ ! -f dist/install_symlinks.sh ]; then - if [ "${{ matrix.label }}" == "Linux" ]; then - echo -e "#!/bin/sh\necho \"Restoring shared library symlinks...\"\nln -sf libcrypto.so.3 libcrypto.so\nln -sf libssl.so.3 libssl.so" > dist/install_symlinks.sh - chmod +x dist/install_symlinks.sh - elif [ "${{ matrix.label }}" == "macOS" ]; then - echo -e "#!/bin/sh\necho \"Restoring shared library symlinks...\"\nln -sf libcrypto.3.dylib libcrypto.dylib\nln -sf libssl.3.dylib libssl.dylib" > dist/install_symlinks.sh - chmod +x dist/install_symlinks.sh + if [ "${{ matrix.label }}" == "Linux" ] || [ "${{ matrix.label }}" == "macOS" ]; then + echo "#!/bin/sh" > dist/install_symlinks.sh + echo "echo \"Restoring shared library symlinks...\"" >> dist/install_symlinks.sh + + cd dist + for lib in libcrypto libssl; do + if [ "${{ matrix.label }}" == "Linux" ]; then + REAL_FILE=$(ls ${lib}.so.* 2>/dev/null | head -n 1) + if [ -n "$REAL_FILE" ]; then + echo "ln -sf $REAL_FILE ${lib}.so" >> install_symlinks.sh + fi + else + REAL_FILE=$(ls ${lib}.*.dylib 2>/dev/null | head -n 1) + if [ -n "$REAL_FILE" ]; then + echo "ln -sf $REAL_FILE ${lib}.dylib" >> install_symlinks.sh + fi + fi + done + chmod +x install_symlinks.sh + cd - > /dev/null fi fi @@ -590,7 +667,7 @@ jobs: retention-days: 5 - name: Upload Build Metadata (Once) - if: matrix.label == 'Linux' && matrix.arch == 'x64' + if: matrix.label == 'Linux' && matrix.arch == 'x64' && needs.validate-version.outputs.is_fork == 'false' uses: actions/upload-artifact@v7 with: name: build-metadata @@ -615,7 +692,7 @@ jobs: echo "Fetching artifacts for run ${{ github.run_id }}..." # Use gh api to list artifacts - ARTIFACTS=$(gh api repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts --paginate) + ARTIFACTS=$(gh api repos/${{ github.repository }}/actions/artifacts --paginate) # Filter for IDs of artifacts that start with 'raw-' or are 'openssl-common-assets' IDS=$(echo "$ARTIFACTS" | jq -r '.artifacts[] | select (.name | startswith("raw-") or . == "openssl-common-assets") | .id') diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index dde9071..c0d63e6 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -14,7 +14,7 @@ on: # Automatic Trigger (Chained) workflow_run: - workflows: ["Build OpenSSL 3.x"] + workflows: ["Build OpenSSL"] types: - completed branches: diff --git a/README.md b/README.md index d6e94b7..a299c16 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,15 @@ When redistributing OpenSSL alongside your application, you only need to deploy #### 🔴 REQUIRED (Must be deployed) These files are strictly required for your application to run and to comply with licensing. -* **`libcrypto`** shared library (e.g., `libcrypto-3-x64.dll`, `libcrypto.so.3`, `libcrypto.3.dylib`) -* **`libssl`** shared library (e.g., `libssl-3-x64.dll`, `libssl.so.3`, `libssl.3.dylib`) +* **`libcrypto`** shared library (e.g., `libcrypto-X-x64.dll`, `libcrypto.so.X`, `libcrypto.X.dylib`) +* **`libssl`** shared library (e.g., `libssl-X-x64.dll`, `libssl.so.X`, `libssl.X.dylib`) * **`LICENSE.txt`** (Required by the Apache License 2.0) #### 🟡 OPTIONAL (Deploy only if needed) Include these only if your application explicitly relies on them. * **`openssl` / `openssl.exe`** (The standalone command-line utility) * **`engines/`** (Legacy hardware/engine support modules) -* **`providers/`** (OpenSSL 3.x provider modules, such as `legacy.dll` / `legacy.so`) +* **`providers/`** (OpenSSL provider modules, such as `legacy.dll` / `legacy.so`) #### ⛔ DO NOT DEPLOY (Development only) These files are for compiling/linking your software and should **not** be shipped to end-users. @@ -54,7 +54,7 @@ These files are for compiling/linking your software and should **not** be shippe #### 🐧 POSIX Specifics (Linux / macOS / Unix) Windows file systems often fail to extract Unix symbolic links. To ensure cross-platform compatibility, our archives contain **only the physical shared library files** (no symlinks). -If your package includes the `install_symlinks.sh` script, you **MUST** run it from the root of the extracted directory on your target POSIX system to recreate the required library symlinks (e.g., `libcrypto.so` -> `libcrypto.so.3`). +If your package includes the `install_symlinks.sh` script, you **MUST** run it from the root of the extracted directory on your target POSIX system to recreate the required library symlinks (e.g., `libcrypto.so` -> `libcrypto.so.X`). ```bash $ cd diff --git a/doc/MAINTAINING.md b/doc/MAINTAINING.md index 8687fd2..b2371d2 100644 --- a/doc/MAINTAINING.md +++ b/doc/MAINTAINING.md @@ -13,40 +13,44 @@ The pipeline consists of three primary workflows: * Explicitly passes `build_type="release"` to ensure correct mode selection. 2. **Build (`build-openssl.yml`):** - * **Validate Mode & Version:** Handles two build modes: - * `release`: Uses official tags (e.g., `openssl-3.4.0`) and performs EOL checks. - * `branch`: Clones a specific git branch (e.g., `master`, `openssl-3.0`) and verifies its existence. + * **Validate Mode & Version:** Handles three build scenarios: + * `release`: Uses official tags (e.g., `3.4.0`) and performs EOL checks. + * `branch`: Clones an official branch (e.g., `master`, `openssl-3.1`). + * `fork`: Clones a public fork using the `user/repo/branch` format. + * **Deterministic Builds:** The validator resolves all inputs to a specific **Commit SHA** at the start of the run. All subsequent jobs (Compile, Package) use this SHA to ensure "point-in-time" consistency. + * **Human-Readable UI:** The workflow dynamically updates the GitHub Run Name to a slugified `user_repo_branch` scheme (e.g., `Build OpenSSL slontis_openssl_fix-logic`) for better visibility. * **Build Common Assets:** Compiles architecture-independent headers and HTML docs once. - * Generates a centralized `README.txt`. - * Extracts `LICENSE.txt` from the source root. - * Removes unnecessary large directories to keep the "common assets" artifact lean. - * **Compile Binaries (Fan-Out):** A highly parallel matrix that splits builds by OS, Architecture, AND Linkage (`shared` vs `static`). Uses parallelized `make -j$(nproc)` for speed. - * **Package Release (Fan-In):** Downloads assets and raw binaries. - * *Adaptive Merging:* Handles inconsistent `actions/download-artifact` behavior by detecting both nested and flattened artifact structures. - * *macOS:* Combines x64 and arm64 into Universal binaries using `lipo` and `install_name_tool`. - * *Naming:* Releases use standard version naming; Branch builds use `_` (e.g., `master_20260314T150000Z`). - * *Metadata:* Generates `version.txt`. If in `branch` mode, prepends `branch: ` to the content. - * **Cleanup:** Deletes intermediate artifacts via GitHub API unless `keep_raw_artifacts` is true. + * **Compile Binaries (Fan-Out):** A highly parallel matrix that splits builds by OS, Architecture, AND Linkage. + * **Package Release (Fan-In):** + * *Slugified Naming:* Filenames and internal metadata use a standardized `user_repo_branch` scheme where all `/` are replaced by `_`. + * *Release Gatekeeping:* If a build is detected as a **Fork**, the workflow intentionally withholds the `build-metadata` artifact. This acts as a "hard stop" that prevents the Publish workflow from creating an official release from untrusted code. + * **Cleanup:** Deletes intermediate artifacts unless `keep_raw_artifacts` is true. 3. **Publish (`publish-release.yml`):** - * Triggered automatically when a Build completes. + * Triggered automatically when a Build completes (on `main` branch). + * Requires the `build-metadata` artifact to function. * Creates a Draft release and opens a GitHub Issue for maintainer review. ## 🛠️ Manual Operations ### How to build manually -1. Go to **Actions** tab -> **Build OpenSSL 3.x**. +1. Go to **Actions** tab -> **Build OpenSSL**. 2. Click **Run workflow**. -3. **Build Type:** Select `release` for official tags or `branch` for moving git branches. -4. **OpenSSL Version or Branch:** Enter the tag (e.g., `3.4.0`) or branch name (e.g., `openssl-3.6`). -5. *(Optional)* Check **Ignore EOL Check** if you need to build an unsupported release. -6. *(Optional)* Check **Keep raw build artifacts** for debugging. +3. **Build Source:** + * Select `release` for official OpenSSL releases (tags). + * Select `branch` for official OpenSSL branches or external OpenSSL forks. +4. **OpenSSL Release Version, OpenSSL Branch Name or OpenSSL Fork Repo:** + * Official Release: `3.4.0` + * Official Branch: `master` + * OpenSSL Fork: `user/repo/branch` (e.g., `slontis/openssl/fix-arm64ec`) +5. *(Optional)* Check **Ignore EOL Check** for legacy builds. +6. *(Optional)* Check **Keep raw build artifacts** for debugging compilation issues. ### How to publish a release manually If an automatic publish fails: 1. Go to **Actions** tab -> **Publish Release**. 2. Click **Run workflow**. -3. Provide the **Build Workflow Run ID** (found in the URL of the successful build run). +3. Provide the **Build Workflow Run ID**. 4. Toggle **Create as Draft** as needed. ### Reviewing and Publishing Drafts @@ -55,8 +59,3 @@ If an automatic publish fails: 3. Verify the artifacts and release notes. 4. Click **Edit**, uncheck "Set as a draft", and click **Publish release**. 5. Close the notification issue. - -### Secrets Configuration -* **Secret Name:** `RBPW_PAT` -* **Required Scopes:** `repo`, `actions:write`. -* **Note:** Required for workflow chaining (`check-upstream` -> `build-openssl`). Standard operations use the default `GITHUB_TOKEN`.