diff --git a/.github/workflows/check-certificates.yml b/.github/workflows/check-certificates.yml new file mode 100644 index 000000000..a3fe636ef --- /dev/null +++ b/.github/workflows/check-certificates.yml @@ -0,0 +1,114 @@ +name: Check for issues with signing certificates + +on: + schedule: + # run every 10 hours + - cron: "0 */10 * * *" + # workflow_dispatch event allows the workflow to be triggered manually. + # This could be used to run an immediate check after updating certificate secrets. + # See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#workflow_dispatch + workflow_dispatch: + +env: + # Begin notifications when there are less than this many days remaining before expiration + EXPIRATION_WARNING_PERIOD: 30 + +jobs: + check-certificates: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + matrix: + certificate: + - identifier: macOS signing certificate # Text used to identify the certificate in notifications + certificate-secret: INSTALLER_CERT_MAC_P12 # The name of the secret that contains the certificate + password-secret: INSTALLER_CERT_MAC_PASSWORD # The name of the secret that contains the certificate password + - identifier: Windows signing certificate + certificate-secret: INSTALLER_CERT_WINDOWS_PFX + password-secret: INSTALLER_CERT_WINDOWS_PASSWORD + + steps: + - name: Set certificate path environment variable + run: | + # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "CERTIFICATE_PATH=${{ runner.temp }}/certificate.p12" >> "$GITHUB_ENV" + - name: Decode certificate + env: + CERTIFICATE: ${{ secrets[matrix.certificate.certificate-secret] }} + run: | + echo "${{ env.CERTIFICATE }}" | base64 --decode > "${{ env.CERTIFICATE_PATH }}" + - name: Verify certificate + env: + CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }} + run: | + ( + openssl pkcs12 \ + -in "${{ env.CERTIFICATE_PATH }}" \ + -noout -passin env:CERTIFICATE_PASSWORD + ) || ( + echo "::error::Verification of ${{ matrix.certificate.identifier }} failed!!!" + exit 1 + ) + # See: https://github.com/rtCamp/action-slack-notify + - name: Slack notification of certificate verification failure + if: failure() + uses: rtCamp/action-slack-notify@v2.1.0 + env: + SLACK_WEBHOOK: ${{ secrets.TEAM_CREATE_CHANNEL_SLACK_WEBHOOK }} + SLACK_MESSAGE: | + :warning::warning::warning::warning: + WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} verification failed!!! + :warning::warning::warning::warning: + SLACK_COLOR: danger + MSG_MINIMAL: true + + - name: Get days remaining before certificate expiration date + env: + CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }} + id: get-days-before-expiration + run: | + EXPIRATION_DATE="$( + ( + openssl pkcs12 \ + -in "${{ env.CERTIFICATE_PATH }}" \ + -clcerts \ + -nodes \ + -passin env:CERTIFICATE_PASSWORD + ) | ( + openssl x509 \ + -noout \ + -enddate + ) | ( + grep \ + --max-count=1 \ + --only-matching \ + --perl-regexp \ + 'notAfter=(\K.*)' + ) + )" + DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))" + # Display the expiration information in the log + echo "Certificate expiration date: $EXPIRATION_DATE" + echo "Days remaining before expiration: $DAYS_BEFORE_EXPIRATION" + echo "::set-output name=days::$DAYS_BEFORE_EXPIRATION" + - name: Check if expiration notification period has been reached + id: check-expiration + run: | + if [[ ${{ steps.get-days-before-expiration.outputs.days }} -lt ${{ env.EXPIRATION_WARNING_PERIOD }} ]]; then + echo "::error::${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!!" + exit 1 + fi + - name: Slack notification of pending certificate expiration + # Don't send spurious expiration notification if verification fails + if: failure() && steps.check-expiration.outcome == 'failure' + uses: rtCamp/action-slack-notify@v2.1.0 + env: + SLACK_WEBHOOK: ${{ secrets.TEAM_CREATE_CHANNEL_SLACK_WEBHOOK }} + SLACK_MESSAGE: | + :warning::warning::warning::warning: + WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!! + :warning::warning::warning::warning: + SLACK_COLOR: danger + MSG_MINIMAL: true \ No newline at end of file