Skip to content

PHPC-1584: Sign releases #1544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
May 10, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ runs:
steps:
- name: Prepare build environment
id: prepare-build-env
uses: ./.github/workflows/windows/prepare-build
uses: ./.github/actions/windows/prepare-build
with:
version: ${{ inputs.version }}
arch: ${{ inputs.arch }}
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/commit-and-tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e

PACKAGE_VERSION=$1
GPG_KEY_ID=$2
TAG_MESSAGE_FILE=$3

gpgloader

# Create signed "Package x.y.z" commit
echo "Create package commit"
git commit -m "Package ${PACKAGE_VERSION}" -s --gpg-sign=${GPG_KEY_ID} phongo_version.h

# Create signed "Release x.y.z" tag
echo "Create release tag"
git tag -F ${TAG_MESSAGE_FILE} -s --local-user=${GPG_KEY_ID} ${PACKAGE_VERSION}
95 changes: 82 additions & 13 deletions .github/workflows/package-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
submodules: true

- name: "Build Driver"
uses: ./.github/workflows/linux/build
uses: ./.github/actions/linux/build
with:
version: "8.3"

Expand All @@ -38,27 +38,43 @@ jobs:
# PECL always uses the version for the package name.
# Read it from the version file and store in env to use when uploading artifacts
- name: "Read current package version"
run: echo "PACKAGE_VERSION=$(./bin/update-release-version.php get-version)" >> "$GITHUB_ENV"
run: |
PACKAGE_VERSION=$(./bin/update-release-version.php get-version)
echo "PACKAGE_VERSION=${PACKAGE_VERSION}" >> "$GITHUB_ENV"
echo "PACKAGE_FILE=mongodb-${PACKAGE_VERSION}.tgz" >> "$GITHUB_ENV"

- name: "Create detached signature for PECL package"
uses: mongodb-labs/drivers-github-tools/garasign/gpg-sign@main
with:
filenames: ${{ env.PACKAGE_FILE }}
garasign_username: ${{ secrets.GRS_CONFIG_USER1_USERNAME }}
garasign_password: ${{ secrets.GRS_CONFIG_USER1_PASSWORD }}
artifactory_username: ${{ secrets.ARTIFACTORY_USER }}
artifactory_password: ${{ secrets.ARTIFACTORY_PASSWORD }}

- name: "Install release archive to verify correctness"
run: sudo pecl install mongodb-${{ env.PACKAGE_VERSION }}.tgz
run: sudo pecl install ${{ env.PACKAGE_FILE }}

- name: "Upload artifact"
- name: "Upload artifacts"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize these steps predate the PR, but can you remind me why we use both actions/upload-artifact and gh release upload? The former attaches the package and signature files to the action, while the latter attaches them to a GitHub release. Are both needed?

The only prior art that comes to mind was how we handle Windows DLLs by temporarily storing them on an action (from the build step) and having the release action transfer them to the GitHub release.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this workflow is enabled for every tag, I wanted to upload the artifacts to the build as well in case we push a tag manually (e.g. for a pre-release) where there is no draft release yet. In that case, we'd still be able to download the artifacts manually and upload them to the release manually. I'm happy to remove this once we've covered every possible angle of the release process.

uses: actions/upload-artifact@v4
with:
name: mongodb-${{ env.PACKAGE_VERSION }}.tgz
path: mongodb-${{ env.PACKAGE_VERSION }}.tgz
name: ${{ env.PACKAGE_FILE }}
path: |
${{ env.PACKAGE_FILE }}
${{ env.PACKAGE_FILE }}.sig
retention-days: 3

- name: "Upload release artifact"
run: gh release upload ${{ github.ref_name }} mongodb-${{ env.PACKAGE_VERSION }}.tgz
- name: "Upload release artifacts"
run: gh release upload ${{ github.ref_name }} ${{ env.PACKAGE_FILE }} ${{ env.PACKAGE_FILE }}.sig
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

build-windows:
name: "Create Windows package"
runs-on: windows-2022
# windows-latest is required to use enableCrossOsArchive with Ubuntu in the
# next step. See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cross-os-cache
runs-on: windows-latest
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using windows-latest is necessary to be able to share the cached build artifacts.

defaults:
run:
shell: cmd
Expand All @@ -78,7 +94,7 @@ jobs:

- name: "Build Driver"
id: build-driver
uses: ./.github/workflows/windows/build
uses: ./.github/actions/windows/build
with:
version: ${{ matrix.php }}
arch: ${{ matrix.arch }}
Expand All @@ -91,20 +107,73 @@ jobs:
env:
BUILD_DIR: ${{ steps.build-driver.outputs.build-dir }}

- name: "Cache build artifacts for subsequent builds"
uses: actions/cache/save@v4
with:
key: ${{ github.sha }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}
enableCrossOsArchive: true
path: |
php_mongodb.dll
php_mongodb.pdb

sign-and-publish-windows:
name: "Sign and Publish Windows package"
needs: [build-windows]
# ubuntu-latest is required to use enableCrossOsArchive
# See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#cross-os-cache
runs-on: "ubuntu-latest"

strategy:
fail-fast: false
matrix:
# Note: keep this in sync with the Windows matrix in windows-tests.yml
php: [ "7.4", "8.0", "8.1", "8.2", "8.3" ]
arch: [ x64, x86 ]
ts: [ ts, nts ]

steps:
- uses: actions/checkout@v4

- name: Restore cached build artifacts
id: cache-build-artifacts
uses: actions/cache/restore@v4
with:
fail-on-cache-miss: true
key: ${{ github.sha }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}
enableCrossOsArchive: true
path: |
php_mongodb.dll
php_mongodb.pdb

- name: "Create detached DLL signature"
uses: mongodb-labs/drivers-github-tools/garasign/gpg-sign@main
with:
filenames: php_mongodb.dll
garasign_username: ${{ secrets.GRS_CONFIG_USER1_USERNAME }}
garasign_password: ${{ secrets.GRS_CONFIG_USER1_PASSWORD }}
artifactory_username: ${{ secrets.ARTIFACTORY_USER }}
artifactory_password: ${{ secrets.ARTIFACTORY_PASSWORD }}

- name: "Upload DLL and PDB files as build artifacts"
uses: actions/upload-artifact@v4
with:
name: php_mongodb-${{ github.ref_name }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}
path: |
php_mongodb.dll
php_mongodb.dll.sig
php_mongodb.pdb
CREDITS
CONTRIBUTING.md
LICENSE
README.md
THIRD_PARTY_NOTICES
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This list of filenames is duplicated in the zip command below. Is it worth trying to use a single variable for these, or would that be difficult given the with.path context here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the examples for the upload-artifact action, I didn't see filenames being space separated. Since I wanted to get rid of this artifact upload once we're sure that we've covered all possible releases (including pre-releases), I'm happy to remove this upload, which solves the problem.

retention-days: 3

- name: "Create and upload release artifact"
run: |
set ARCHIVE=php_mongodb-${{ github.ref_name }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}.zip
zip %ARCHIVE% php_mongodb.dll php_mongodb.pdb CREDITS CONTRIBUTING.md LICENSE README.md THIRD_PARTY_NOTICES
gh release upload ${{ github.ref_name }} %ARCHIVE%
ARCHIVE=php_mongodb-${{ github.ref_name }}-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.arch }}.zip
zip ${ARCHIVE} php_mongodb.dll php_mongodb.dll.sig php_mongodb.pdb CREDITS CONTRIBUTING.md LICENSE README.md THIRD_PARTY_NOTICES
gh release upload ${{ github.ref_name }} ${ARCHIVE}
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47 changes: 35 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@ jobs:
git config user.name "${GIT_AUTHOR_NAME}"
git config user.email "${GIT_AUTHOR_EMAIL}"

# Create the "Package x.y.z" commit that will be the base of our tag
- name: "Create release commit"
run: git commit -m "Package ${{ env.PACKAGE_VERSION }}" phongo_version.h

# Create a draft release with a changelog
# TODO: Consider using the API to generate changelog
- name: "Create draft release with generated changelog"
Expand All @@ -101,14 +97,39 @@ jobs:
- name: "Read changelog from draft release"
run: gh release view ${{ env.PACKAGE_VERSION }} --json body --template '{{ .body }}' >> changelog

# TODO: Sign tag
- name: "Create release tag"
run: git tag -a -F changelog ${{ env.PACKAGE_VERSION }}

- name: "Update version information to next patch development release"
- name: "Prepare tag message"
run: |
./bin/update-release-version.php to-next-patch-dev
git commit -m "Back to -dev" phongo_version.h
echo -e "Release ${PACKAGE_VERSION}\n" > tag-message
cat changelog >> tag-message

# This step creates the "Package x.y.z" commit that will be the base of
# our tag and creates the release tag. This is run inside the container in
# order to create signed git artifacts
- name: "Create package commit and release tag"
uses: mongodb-labs/drivers-github-tools/garasign/git-sign@main
with:
command: "$(pwd)/.github/workflows/commit-and-tag.sh ${{ env.PACKAGE_VERSION }} ${{ vars.GPG_KEY_ID }} tag-message"
garasign_username: ${{ secrets.GRS_CONFIG_USER1_USERNAME }}
garasign_password: ${{ secrets.GRS_CONFIG_USER1_PASSWORD }}
artifactory_username: ${{ secrets.ARTIFACTORY_USER }}
artifactory_password: ${{ secrets.ARTIFACTORY_PASSWORD }}

# This step needs to happen outside of the container, as PHP is not
# available within.
- name: "Bump to next development release"
run: ./bin/update-release-version.php to-next-patch-dev

# Create a signed "back to -dev" commit, again inside the container
- name: "Create dev commit"
uses: mongodb-labs/drivers-github-tools/garasign/git-sign@main
with:
# Setup can be skipped as it was already done before
skip_setup: true
command: "git commit -m 'Back to -dev' -s --gpg-sign=${{ vars.GPG_KEY_ID }} phongo_version.h"
garasign_username: ${{ secrets.GRS_CONFIG_USER1_USERNAME }}
garasign_password: ${{ secrets.GRS_CONFIG_USER1_PASSWORD }}
artifactory_username: ${{ secrets.ARTIFACTORY_USER }}
artifactory_password: ${{ secrets.ARTIFACTORY_PASSWORD }}

# TODO: Manually merge using ours strategy. This avoids merge-up pull requests being created
# Process is:
Expand All @@ -122,7 +143,9 @@ jobs:

- name: "Prepare release message"
run: |
echo "${{ format(env.default-release-message, env.PACKAGE_VERSION, inputs.jira-version-number) }}" > release-message
cat > release-message <<'EOL'
${{ format(env.default-release-message, env.PACKAGE_VERSION, inputs.jira-version-number) }}
EOL
cat changelog >> release-message

# Update release with correct release information
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:

- name: "Build Driver"
id: build-driver
uses: ./.github/workflows/linux/build
uses: ./.github/actions/linux/build
with:
version: ${{ matrix.php-version }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/windows-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:

- name: "Build Driver"
id: build-driver
uses: ./.github/workflows/windows/build
uses: ./.github/actions/windows/build
with:
version: ${{ matrix.php }}
arch: ${{ matrix.arch }}
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:

- name: Prepare build environment
id: prepare-build
uses: ./.github/workflows/windows/prepare-build
uses: ./.github/actions/windows/prepare-build
with:
version: ${{ matrix.php }}
arch: ${{ matrix.arch }}
Expand Down
48 changes: 47 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,53 @@ This extension is intended to be used alongside the
[MongoDB PHP Library](https://github.com/mongodb/mongo-php-library), which is
distributed as the
[`mongodb/mongodb`](https://packagist.org/packages/mongodb/mongodb) package for
for [Composer](https://getcomposer.org).
[Composer](https://getcomposer.org).

## Release Integrity

Releases are created automatically and signed using the
[PHP team's GPG key](https://pgp.mongodb.com/php-driver.asc). This applies to
the git tag as well as all release packages provided as part of a
[GitHub release](https://github.com/mongodb/mongo-php-library/releases). To
verify the provided packages, download the key and import it using `gpg`:

```shell
gpg --import php-driver.asc
```

### PECL package

PECL packages are made available as release artifacts on GitHub, as well as on
the [PECL homepage](https://pecl.php.net/mongodb). The GitHub release will also
contain a detached signature file for the PECL package (named
`mongodb-X.Y.Z.tgz.sig`).

To verify the integrity of the downloaded package, run the following command:

```shell
gpg --verify mongodb-X.Y.Z.tgz.sig mongodb-X.Y.Z.tgz
```

> [!NOTE]
> No verification is done when using `pecl` to install the package. To ensure
> release integrity when using `pecl`, download the tarball manually from the
> GitHub release, verify the signature, then install the package from the
> downloaded tarball using `pecl install mongodb-X.Y.Z.tgz`.

### Windows

Windows binaries distributed through GitHub releases contain a detached
signature for the `php_mongodb.dll` file named `php_mongodb.dll.sig`. To verify
the integrity of the DLL, run the following command:

```shell
gpg --verify php_mongodb.dll.sig php_mongodb.dll.tgz
```

> [!NOTE]
> Windows binaries distributed directly through PECL are not signed by MongoDB
> and cannot be verified. If you need to verify the integrity of the downloaded
> binary, always download them from the GitHub release.

## Reporting Issues

Expand Down