Check Certificates #4606
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-certificates.md | |
name: Check Certificates | |
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows | |
on: | |
push: | |
paths: | |
- ".github/workflows/check-certificates.ya?ml" | |
pull_request: | |
paths: | |
- ".github/workflows/check-certificates.ya?ml" | |
schedule: | |
# Run every 10 hours. | |
- cron: "0 */10 * * *" | |
workflow_dispatch: | |
repository_dispatch: | |
env: | |
# Begin notifications when there are less than this many days remaining before expiration. | |
EXPIRATION_WARNING_PERIOD: 30 | |
jobs: | |
check-certificates: | |
name: ${{ matrix.certificate.identifier }} | |
# Only run when the workflow will have access to the certificate secrets. | |
if: > | |
(github.event_name != 'pull_request' && github.repository == 'arduino/arduino-cli') || | |
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'arduino/arduino-cli') | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
certificate: | |
# Additional certificate definitions can be added to this list. | |
- identifier: macOS signing certificate # Text used to identify certificate in notifications. | |
certificate-secret: INSTALLER_CERT_MAC_P12 # Name of the secret that contains the certificate. | |
password-secret: INSTALLER_CERT_MAC_PASSWORD # Name of the secret that contains the certificate password. | |
type: pkcs12 | |
- identifier: Windows signing certificate | |
certificate-secret: INSTALLER_CERT_WINDOWS_CER | |
# The password for the Windows certificate is not needed, because its not a container, but a single certificate. | |
type: x509 | |
steps: | |
- name: Set certificate path environment variable | |
run: | | |
# See: https://docs.github.com/en/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 ${{ matrix.certificate.type }} \ | |
-in "${{ env.CERTIFICATE_PATH }}" \ | |
-legacy \ | |
-noout \ | |
-passin env:CERTIFICATE_PASSWORD | |
) || ( | |
echo "::error::Verification of ${{ matrix.certificate.identifier }} failed!!!" | |
exit 1 | |
) | |
- name: Slack notification of certificate verification failure | |
if: failure() | |
env: | |
SLACK_WEBHOOK: ${{ secrets.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 | |
uses: rtCamp/action-slack-notify@v2 | |
- name: Get days remaining before certificate expiration date | |
env: | |
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }} | |
id: get-days-before-expiration | |
run: | | |
if [[ ${{ matrix.certificate.type }} == "pkcs12" ]]; then | |
EXPIRATION_DATE="$( | |
( | |
openssl pkcs12 \ | |
-in ${{ env.CERTIFICATE_PATH }} \ | |
-clcerts \ | |
-legacy \ | |
-nodes \ | |
-passin env:CERTIFICATE_PASSWORD | |
) | ( | |
openssl x509 \ | |
-noout \ | |
-enddate | |
) | ( | |
grep \ | |
--max-count=1 \ | |
--only-matching \ | |
--perl-regexp \ | |
'notAfter=(\K.*)' | |
) | |
)" | |
elif [[ ${{ matrix.certificate.type }} == "x509" ]]; then | |
EXPIRATION_DATE="$( | |
( | |
openssl x509 \ | |
-in ${{ env.CERTIFICATE_PATH }} \ | |
-noout \ | |
-enddate | |
) | ( | |
grep \ | |
--max-count=1 \ | |
--only-matching \ | |
--perl-regexp \ | |
'notAfter=(\K.*)' | |
) | |
)" | |
fi | |
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 "days=$DAYS_BEFORE_EXPIRATION" >> $GITHUB_OUTPUT | |
- 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' | |
env: | |
SLACK_WEBHOOK: ${{ secrets.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 | |
uses: rtCamp/action-slack-notify@v2 |