Skip to content

Commit 355e447

Browse files
authored
Merge pull request #19 from per1234/check-certificates
Add template workflow to check for problems with signing certificates
2 parents 927220e + a322e92 commit 355e447

File tree

3 files changed

+313
-0
lines changed

3 files changed

+313
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# "Check Certificates" workflow
2+
3+
Workflow file: [check-certificates.yml](check-certificates.yml)
4+
5+
Check code signing certificates for problems or pending expiration.
6+
7+
## Setting up Slack webhook
8+
9+
1. Open https://arduino.slack.com/apps/A0F7XDUAZ-incoming-webhooks
10+
1. Click the "Add to Slack" button
11+
1. From the "Post to Channel" menu, select the appropriate channel.
12+
1. Click the "Add Incoming WebHooks integration"
13+
1. From the "Customize Icon" section, click the "Choose an emoji" button
14+
1. Enter `:warning:`
15+
1. Click the "Save Settings" button
16+
1. Copy the text in the "Webhook URL" field
17+
1. Save the webhook URL to a [repository secret](https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository) named `SLACK_WEBHOOK`
18+
- Make sure there is no newline at the end of the secret, otherwise the slack post process will fail.
19+
20+
## Readme badge
21+
22+
Markdown badge:
23+
24+
```markdown
25+
[![Check Certificates status](https://github.com/REPO_OWNER/REPO_NAME/actions/workflows/check-certificates.yml/badge.svg)](https://github.com/REPO_OWNER/REPO_NAME/actions/workflows/check-certificates.yml)
26+
```
27+
28+
Replace the `REPO_OWNER` and `REPO_NAME` placeholders in the URLs with the final repository owner and name ([example](https://raw.githubusercontent.com/arduino-libraries/ArduinoIoTCloud/master/README.md)).
29+
30+
---
31+
32+
Asciidoc badge:
33+
34+
```adoc
35+
image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-certificates.yml/badge.svg["Check Certificates status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-certificates.yml"]
36+
```
37+
38+
Define the `{repository-owner}` and `{repository-name}` attributes and use them throughout the readme ([example](https://raw.githubusercontent.com/arduino-libraries/WiFiNINA/master/README.adoc)).
39+
40+
## Commit message
41+
42+
```
43+
Add CI workflow to check for problems with signing certificates
44+
45+
The workflow runs on a schedule to check for problems with the signing certificates and notify if any are found.
46+
If a problem is found, a notification is posted to the Slack channel configured via the SLACK_WEBHOOK secret.
47+
```
48+
49+
## PR message
50+
51+
```markdown
52+
The workflow runs on a schedule to check for problems with the signing certificates and notify if any are found. If a problem is found, a notification is posted to the Slack channel configured via the `SLACK_WEBHOOK` secret.
53+
```
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-certificates.md
2+
name: Check Certificates
3+
4+
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
5+
on:
6+
push:
7+
paths:
8+
- ".github/workflows/check-certificates.ya?ml"
9+
pull_request:
10+
paths:
11+
- ".github/workflows/check-certificates.ya?ml"
12+
schedule:
13+
# Run every 10 hours.
14+
- cron: "0 */10 * * *"
15+
workflow_dispatch:
16+
repository_dispatch:
17+
18+
env:
19+
# Begin notifications when there are less than this many days remaining before expiration.
20+
EXPIRATION_WARNING_PERIOD: 30
21+
22+
jobs:
23+
check-certificates:
24+
name: ${{ matrix.certificate.identifier }}
25+
# Only run when the workflow will have access to the certificate secrets.
26+
# TODO: Update repository name.
27+
if: >
28+
(github.event_name != 'pull_request' && github.repository == 'REPO_OWNER/REPO_NAME') ||
29+
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'REPO_OWNER/REPO_NAME')
30+
runs-on: ubuntu-latest
31+
strategy:
32+
fail-fast: false
33+
34+
matrix:
35+
certificate:
36+
# Additional certificate definitions can be added to this list.
37+
- identifier: macOS signing certificate # Text used to identify certificate in notifications.
38+
certificate-secret: INSTALLER_CERT_MAC_P12 # Name of the secret that contains the certificate.
39+
password-secret: INSTALLER_CERT_MAC_PASSWORD # Name of the secret that contains the certificate password.
40+
41+
steps:
42+
- name: Set certificate path environment variable
43+
run: |
44+
# See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
45+
echo "CERTIFICATE_PATH=${{ runner.temp }}/certificate.p12" >> "$GITHUB_ENV"
46+
47+
- name: Decode certificate
48+
env:
49+
CERTIFICATE: ${{ secrets[matrix.certificate.certificate-secret] }}
50+
run: |
51+
echo "${{ env.CERTIFICATE }}" | base64 --decode > "${{ env.CERTIFICATE_PATH }}"
52+
53+
- name: Verify certificate
54+
env:
55+
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
56+
run: |
57+
(
58+
openssl pkcs12 \
59+
-in "${{ env.CERTIFICATE_PATH }}" \
60+
-noout -passin env:CERTIFICATE_PASSWORD
61+
) || (
62+
echo "::error::Verification of ${{ matrix.certificate.identifier }} failed!!!"
63+
exit 1
64+
)
65+
66+
- name: Slack notification of certificate verification failure
67+
if: failure()
68+
env:
69+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
70+
SLACK_MESSAGE: |
71+
:warning::warning::warning::warning:
72+
WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} verification failed!!!
73+
:warning::warning::warning::warning:
74+
SLACK_COLOR: danger
75+
MSG_MINIMAL: true
76+
uses: rtCamp/action-slack-notify@v2
77+
78+
- name: Get days remaining before certificate expiration date
79+
env:
80+
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
81+
id: get-days-before-expiration
82+
run: |
83+
EXPIRATION_DATE="$(
84+
(
85+
openssl pkcs12 \
86+
-in "${{ env.CERTIFICATE_PATH }}" \
87+
-clcerts \
88+
-nodes \
89+
-passin env:CERTIFICATE_PASSWORD
90+
) | (
91+
openssl x509 \
92+
-noout \
93+
-enddate
94+
) | (
95+
grep \
96+
--max-count=1 \
97+
--only-matching \
98+
--perl-regexp \
99+
'notAfter=(\K.*)'
100+
)
101+
)"
102+
103+
DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))"
104+
105+
# Display the expiration information in the log.
106+
echo "Certificate expiration date: $EXPIRATION_DATE"
107+
echo "Days remaining before expiration: $DAYS_BEFORE_EXPIRATION"
108+
109+
echo "::set-output name=days::$DAYS_BEFORE_EXPIRATION"
110+
111+
- name: Check if expiration notification period has been reached
112+
id: check-expiration
113+
run: |
114+
if [[ ${{ steps.get-days-before-expiration.outputs.days }} -lt ${{ env.EXPIRATION_WARNING_PERIOD }} ]]; then
115+
echo "::error::${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!!"
116+
exit 1
117+
fi
118+
119+
- name: Slack notification of pending certificate expiration
120+
# Don't send spurious expiration notification if verification fails.
121+
if: failure() && steps.check-expiration.outcome == 'failure'
122+
env:
123+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
124+
SLACK_MESSAGE: |
125+
:warning::warning::warning::warning:
126+
WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!!
127+
:warning::warning::warning::warning:
128+
SLACK_COLOR: danger
129+
MSG_MINIMAL: true
130+
uses: rtCamp/action-slack-notify@v2
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-certificates.md
2+
name: Check Certificates
3+
4+
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
5+
on:
6+
push:
7+
paths:
8+
- ".github/workflows/check-certificates.ya?ml"
9+
pull_request:
10+
paths:
11+
- ".github/workflows/check-certificates.ya?ml"
12+
schedule:
13+
# Run every 10 hours.
14+
- cron: "0 */10 * * *"
15+
workflow_dispatch:
16+
repository_dispatch:
17+
18+
env:
19+
# Begin notifications when there are less than this many days remaining before expiration.
20+
EXPIRATION_WARNING_PERIOD: 30
21+
22+
jobs:
23+
check-certificates:
24+
name: ${{ matrix.certificate.identifier }}
25+
# Only run when the workflow will have access to the certificate secrets.
26+
# TODO: Update repository name.
27+
if: >
28+
(github.event_name != 'pull_request' && github.repository == 'REPO_OWNER/REPO_NAME') ||
29+
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'REPO_OWNER/REPO_NAME')
30+
runs-on: ubuntu-latest
31+
strategy:
32+
fail-fast: false
33+
34+
matrix:
35+
certificate:
36+
# Additional certificate definitions can be added to this list.
37+
- identifier: macOS signing certificate # Text used to identify certificate in notifications.
38+
certificate-secret: INSTALLER_CERT_MAC_P12 # Name of the secret that contains the certificate.
39+
password-secret: INSTALLER_CERT_MAC_PASSWORD # Name of the secret that contains the certificate password.
40+
41+
steps:
42+
- name: Set certificate path environment variable
43+
run: |
44+
# See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
45+
echo "CERTIFICATE_PATH=${{ runner.temp }}/certificate.p12" >> "$GITHUB_ENV"
46+
47+
- name: Decode certificate
48+
env:
49+
CERTIFICATE: ${{ secrets[matrix.certificate.certificate-secret] }}
50+
run: |
51+
echo "${{ env.CERTIFICATE }}" | base64 --decode > "${{ env.CERTIFICATE_PATH }}"
52+
53+
- name: Verify certificate
54+
env:
55+
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
56+
run: |
57+
(
58+
openssl pkcs12 \
59+
-in "${{ env.CERTIFICATE_PATH }}" \
60+
-noout -passin env:CERTIFICATE_PASSWORD
61+
) || (
62+
echo "::error::Verification of ${{ matrix.certificate.identifier }} failed!!!"
63+
exit 1
64+
)
65+
66+
- name: Slack notification of certificate verification failure
67+
if: failure()
68+
env:
69+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
70+
SLACK_MESSAGE: |
71+
:warning::warning::warning::warning:
72+
WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} verification failed!!!
73+
:warning::warning::warning::warning:
74+
SLACK_COLOR: danger
75+
MSG_MINIMAL: true
76+
uses: rtCamp/action-slack-notify@v2
77+
78+
- name: Get days remaining before certificate expiration date
79+
env:
80+
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
81+
id: get-days-before-expiration
82+
run: |
83+
EXPIRATION_DATE="$(
84+
(
85+
openssl pkcs12 \
86+
-in "${{ env.CERTIFICATE_PATH }}" \
87+
-clcerts \
88+
-nodes \
89+
-passin env:CERTIFICATE_PASSWORD
90+
) | (
91+
openssl x509 \
92+
-noout \
93+
-enddate
94+
) | (
95+
grep \
96+
--max-count=1 \
97+
--only-matching \
98+
--perl-regexp \
99+
'notAfter=(\K.*)'
100+
)
101+
)"
102+
103+
DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))"
104+
105+
# Display the expiration information in the log.
106+
echo "Certificate expiration date: $EXPIRATION_DATE"
107+
echo "Days remaining before expiration: $DAYS_BEFORE_EXPIRATION"
108+
109+
echo "::set-output name=days::$DAYS_BEFORE_EXPIRATION"
110+
111+
- name: Check if expiration notification period has been reached
112+
id: check-expiration
113+
run: |
114+
if [[ ${{ steps.get-days-before-expiration.outputs.days }} -lt ${{ env.EXPIRATION_WARNING_PERIOD }} ]]; then
115+
echo "::error::${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!!"
116+
exit 1
117+
fi
118+
119+
- name: Slack notification of pending certificate expiration
120+
# Don't send spurious expiration notification if verification fails.
121+
if: failure() && steps.check-expiration.outcome == 'failure'
122+
env:
123+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
124+
SLACK_MESSAGE: |
125+
:warning::warning::warning::warning:
126+
WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!!
127+
:warning::warning::warning::warning:
128+
SLACK_COLOR: danger
129+
MSG_MINIMAL: true
130+
uses: rtCamp/action-slack-notify@v2

0 commit comments

Comments
 (0)