Skip to content

Commit a81e4ba

Browse files
dnzxybillybooth
andauthored
Browser Build "Validate Secrets" Improvements (LoopKit#77)
* Added improved validation and more descriptive error messages * Add validations from suggestions and test feedback * Modify validate_secrets to run in readonly mode * Streamline naming 1/3 * Streamline naming 2/3 * Streamline naming 3/3, add back validation preceding build * Fix LoopWidgetExtension bundle identifier * Add fastlane patterns back after accidentally removing them * Fix Match-Secrets auto-creation and if-condition * validate_secrets.yml: Set pipefail option so that fastlane exit codes are handled correctly * workflows: Include branch in (run) names and use consistent capitalization across reusable job names * This commit is purely aesthetic and aims to make the display names of Jobs consistent across workflows. Likewise, makes spacing and validation error messages consistent. * validate_secrets.yml: Make annotations more "actionable". * validate_secrets.yml: Improve error annotations around GH_PAT permissions * Trivial changes to FASTLANE / ASC error annotations (mention 'Keys' tab) --------- Co-authored-by: Billy Booth <billy@appliedolap.com>
1 parent 484d3b4 commit a81e4ba

File tree

5 files changed

+140
-63
lines changed

5 files changed

+140
-63
lines changed

.github/workflows/add_identifiers.yml

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
name: 2. Add Identifiers
2-
run-name: Add Identifiers
2+
run-name: Add Identifiers (${{ github.ref_name }})
33
on:
44
workflow_dispatch:
55

66
jobs:
7-
secrets:
7+
validate:
8+
name: Validate
89
uses: ./.github/workflows/validate_secrets.yml
910
secrets: inherit
10-
11+
1112
identifiers:
12-
needs: secrets
13+
name: Add Identifiers
14+
needs: validate
1315
runs-on: macos-12
1416
steps:
1517
# Uncomment to manually select latest Xcode if needed

.github/workflows/build_loop.yml

+18-18
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ on:
55

66
## Remove the "#" sign from the beginning of the line below to get automated builds on push (code changes in your repository)
77
#push:
8-
8+
99
schedule:
10-
- cron: '0 8 * * 3' # Checks for updates at 08:00 am UTC every Wednesday
11-
- cron: '0 8 1 * 6' # Builds the app on the 1st Saturday every month at 08:00 am UTC
10+
- cron: '0 8 * * 3' # Checks for updates at 08:00 UTC every Wednesday
11+
- cron: '0 8 1 * 6' # Builds the app on the 1st Saturday every month at 08:00 UTC
1212

1313
env:
1414
UPSTREAM_REPO: LoopKit/LoopWorkspace
@@ -18,21 +18,22 @@ env:
1818
WORKFLOW_PERMISSIONS: false
1919

2020
jobs:
21-
secrets:
21+
validate:
22+
name: Validate
2223
uses: ./.github/workflows/validate_secrets.yml
2324
secrets: inherit
24-
25+
2526
# Checks if GH_PAT holds workflow permissions
2627
# Checks for existence of alive branch; if non-existent creates it
2728
check_alive_and_permissions:
28-
needs: secrets
29+
needs: validate
2930
runs-on: ubuntu-latest
3031
name: Check alive branch and permissions
3132
permissions:
3233
contents: write
3334
outputs:
3435
WORKFLOW_PERMISSION: ${{ steps.workflow-permission.outputs.has_permission }}
35-
36+
3637
steps:
3738
- name: Check for workflow permissions
3839
id: workflow-permission
@@ -49,7 +50,7 @@ jobs:
4950
echo "Automated build features will be skipped!"
5051
echo "has_permission=false" >> $GITHUB_OUTPUT # Set WORKFLOW_PERMISSION to false.
5152
fi
52-
53+
5354
- name: Check for alive branch
5455
if: steps.workflow-permission.outputs.has_permission == 'true'
5556
env:
@@ -62,7 +63,7 @@ jobs:
6263
echo "Branch 'alive' does not exist."
6364
echo "ALIVE_BRANCH_EXISTS=false" >> $GITHUB_ENV # Set ALIVE_BRANCH_EXISTS to false
6465
fi
65-
66+
6667
- name: Create alive branch
6768
if: env.ALIVE_BRANCH_EXISTS != 'true'
6869
env:
@@ -82,7 +83,7 @@ jobs:
8283
/repos/${{ github.repository_owner }}/LoopWorkspace/git/refs \
8384
-f ref='refs/heads/alive' \
8485
-f sha=$SHA
85-
86+
8687
# Checks for changes in upstream repository; if changes exist prompts sync for build
8788
# Performs keepalive to avoid stale fork
8889
check_latest_from_upstream:
@@ -91,7 +92,7 @@ jobs:
9192
name: Check upstream and keep alive
9293
outputs:
9394
NEW_COMMITS: ${{ steps.sync.outputs.has_new_commits }}
94-
95+
9596
steps:
9697
- name: Checkout target repo
9798
if: |
@@ -101,7 +102,7 @@ jobs:
101102
with:
102103
token: ${{ secrets.GH_PAT }}
103104
ref: alive
104-
105+
105106
- name: Sync upstream changes
106107
if: | # do not run the upstream sync action on the upstream repository
107108
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
@@ -114,7 +115,7 @@ jobs:
114115
target_repo_token: ${{ secrets.GH_PAT }}
115116
upstream_sync_branch: ${{ env.UPSTREAM_BRANCH }}
116117
upstream_sync_repo: ${{ env.UPSTREAM_REPO }}
117-
118+
118119
# Display a sample message based on the sync output var 'has_new_commits'
119120
- name: New commits found
120121
if: |
@@ -127,7 +128,7 @@ jobs:
127128
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
128129
vars.SCHEDULED_SYNC != 'false' && steps.sync.outputs.has_new_commits == 'false'
129130
run: echo "There were no new commits."
130-
131+
131132
- name: Show value of 'has_new_commits'
132133
if: needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' && vars.SCHEDULED_SYNC != 'false'
133134
run: |
@@ -142,7 +143,7 @@ jobs:
142143
uses: gautamkrishnar/keepalive-workflow@v1 # using the workflow with default settings
143144
with:
144145
time_elapsed: 20 # Time elapsed from the previous commit to trigger a new automated commit (in days)
145-
146+
146147
- name: Show scheduled build configuration message
147148
if: needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION != 'true'
148149
run: |
@@ -152,7 +153,6 @@ jobs:
152153
echo "If you want to enable automatic builds and updates for your Loop, please follow the instructions \
153154
under the following path <code>LoopWorkspace/fastlane/testflight.md</code>." >> $GITHUB_STEP_SUMMARY
154155
155-
156156
# Builds Loop
157157
build:
158158
name: Build
@@ -169,7 +169,7 @@ jobs:
169169
steps:
170170
- name: Select Xcode version
171171
run: "sudo xcode-select --switch /Applications/Xcode_14.3.1.app/Contents/Developer"
172-
172+
173173
- name: Checkout Repo for syncing
174174
if: |
175175
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&
@@ -178,7 +178,7 @@ jobs:
178178
with:
179179
token: ${{ secrets.GH_PAT }}
180180
ref: ${{ env.TARGET_BRANCH }}
181-
181+
182182
- name: Sync upstream changes
183183
if: | # do not run the upstream sync action on the upstream repository
184184
needs.check_alive_and_permissions.outputs.WORKFLOW_PERMISSION == 'true' &&

.github/workflows/create_certs.yml

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
name: 3. Create Certificates
2-
run-name: Create Certificates
2+
run-name: Create Certificates (${{ github.ref_name }})
33
on:
44
workflow_dispatch:
55

66
jobs:
7-
secrets:
7+
validate:
8+
name: Validate
89
uses: ./.github/workflows/validate_secrets.yml
910
secrets: inherit
10-
11+
1112
certificates:
12-
needs: secrets
13+
name: Create Certificates
14+
needs: validate
1315
runs-on: macos-12
1416
steps:
1517
# Uncomment to manually select latest Xcode if needed

.github/workflows/validate_secrets.yml

+103-37
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,136 @@
11
name: 1. Validate Secrets
2-
run-name: Validate Secrets
2+
run-name: Validate Secrets (${{ github.ref_name }})
33
on: [workflow_call, workflow_dispatch]
4-
4+
55
jobs:
6-
validate:
7-
runs-on: macos-12
6+
validate-access-token:
7+
name: Access
8+
runs-on: macos-13
9+
env:
10+
GH_PAT: ${{ secrets.GH_PAT }}
11+
GH_TOKEN: ${{ secrets.GH_PAT }}
12+
steps:
13+
- name: Validate Access Token
14+
run: |
15+
# Validate Fastlane Access Token (GH_PAT)
16+
if [ -z "$GH_PAT" ]; then
17+
failed=true
18+
echo "::error::The GH_PAT secret is unset or empty. Set it and try again."
19+
elif [ "$(gh api -H "Accept: application/vnd.github+json" /repos/${{ github.repository_owner }}/LoopWorkspace | jq --raw-output '.permissions.push')" != "true" ]; then
20+
failed=true
21+
echo "::error::The GH_PAT secret is set but invalid or lacking at least 'repo' permission scope ('repo, workflow' is okay too).\
22+
Verify that token permissions are set correctly (or update them) at https://github.com/settings/tokens and try again."
23+
fi
24+
25+
# Exit unsuccessfully if secret validation failed.
26+
if [ $failed ]; then
27+
exit 2
28+
fi
29+
30+
validate-match-secrets:
31+
name: Match-Secrets
32+
needs: validate-access-token
33+
runs-on: macos-13
34+
env:
35+
GH_TOKEN: ${{ secrets.GH_PAT }}
36+
steps:
37+
- name: Validate Match-Secrets
38+
run: |
39+
# Validate Match-Secrets
40+
if [ "$(gh repo list --json name | jq --raw-output 'any(.name=="Match-Secrets")')" != "true" ]; then
41+
echo "A 'Match-Secrets' repository could not be found. Attempting to create one...";
42+
43+
if gh repo create Match-Secrets --private >/dev/null && [ "$(gh repo list --json name,visibility | jq --raw-output '.[] | select(.name=="Match-Secrets") | .visibility == "PRIVATE"')" == "true" ]; then
44+
echo "Created a private 'Match-Secrets' repository."
45+
else
46+
failed=true
47+
echo "::error::Cannot access or create a private 'Match-Secrets' repository. The GH_PAT secret is lacking at least the 'repo' permission scope required to access or create the repository.\
48+
Verify that token permissions are set correctly (or update them) at https://github.com/settings/tokens and try again."
49+
fi
50+
elif [ "$(gh repo list --json name,visibility | jq --raw-output '.[] | select(.name=="Match-Secrets") | .visibility == "PUBLIC"')" == "true" ]; then
51+
failed=true
52+
echo "::error::A 'Match-Secrets' repository was found, but it is is public. Delete it and try again (a private repository will be created for you)."
53+
fi
54+
55+
# Exit unsuccessfully if secret validation failed.
56+
if [ $failed ]; then
57+
exit 2
58+
fi
59+
60+
validate-fastlane-secrets:
61+
name: Fastlane
62+
needs: validate-match-secrets
63+
runs-on: macos-13
64+
env:
65+
GH_PAT: ${{ secrets.GH_PAT }}
66+
GH_TOKEN: ${{ secrets.GH_PAT }}
67+
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
68+
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
69+
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
70+
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
71+
TEAMID: ${{ secrets.TEAMID }}
872
steps:
9-
# Checks-out the repo
1073
- name: Checkout Repo
1174
uses: actions/checkout@v3
12-
13-
# Validates the repo secrets
14-
- name: Validate Secrets
75+
76+
- name: Validate Fastlane Secrets
1577
run: |
16-
# Validate Secrets
17-
echo Validating Repository Secrets...
78+
# Validate Fastlane Secrets
1879
1980
# Validate TEAMID
2081
if [ -z "$TEAMID" ]; then
2182
failed=true
22-
echo "::error::TEAMID secret is unset or empty. Set it and try again."
83+
echo "::error::The TEAMID secret is unset or empty. Set it and try again."
2384
elif [ ${#TEAMID} -ne 10 ]; then
2485
failed=true
25-
echo "::error::TEAMID secret is set but has wrong length. Verify that it is set correctly and try again."
86+
echo "::error::The TEAMID secret is set but has wrong length. Verify that it is set correctly and try again."
87+
elif ! [[ $TEAMID =~ ^[A-Z0-9]+$ ]]; then
88+
failed=true
89+
echo "::error::The TEAMID secret is set but invalid. Verify that it is set correctly (only uppercase letters and numbers) and try again."
2690
fi
2791
28-
# Validate GH_PAT
29-
if [ -z "$GH_PAT" ]; then
30-
failed=true
31-
echo "::error::GH_PAT secret is unset or empty. Set it and try again."
32-
elif [ "$(gh api -H "Accept: application/vnd.github+json" /repos/${{ github.repository_owner }}/Match-Secrets | jq --raw-output '.permissions.push')" != "true" ]; then
92+
# Validate MATCH_PASSWORD
93+
if [ -z "$MATCH_PASSWORD" ]; then
3394
failed=true
34-
echo "::error::GH_PAT secret is set but invalid or lacking appropriate privileges on the ${{ github.repository_owner }}/Match-Secrets repository. Verify that it is set correctly and try again."
95+
echo "::error::The MATCH_PASSWORD secret is unset or empty. Set it and try again."
3596
fi
3697
98+
# Ensure that fastlane exit codes are handled when output is piped.
99+
set -o pipefail
100+
37101
# Validate FASTLANE_ISSUER_ID, FASTLANE_KEY_ID, and FASTLANE_KEY
102+
FASTLANE_KEY_ID_PATTERN='^[A-Z0-9]+$'
103+
FASTLANE_ISSUER_ID_PATTERN='^\{?[A-F0-9a-f]{8}-[A-F0-9a-f]{4}-[A-F0-9a-f]{4}-[A-F0-9a-f]{4}-[A-F0-9a-f]{12}\}?$'
104+
38105
if [ -z "$FASTLANE_ISSUER_ID" ] || [ -z "$FASTLANE_KEY_ID" ] || [ -z "$FASTLANE_KEY" ]; then
39106
failed=true
40107
[ -z "$FASTLANE_ISSUER_ID" ] && echo "::error::The FASTLANE_ISSUER_ID secret is unset or empty. Set it and try again."
41108
[ -z "$FASTLANE_KEY_ID" ] && echo "::error::The FASTLANE_KEY_ID secret is unset or empty. Set it and try again."
42109
[ -z "$FASTLANE_KEY" ] && echo "::error::The FASTLANE_KEY secret is unset or empty. Set it and try again."
43-
elif ! echo "$FASTLANE_KEY" | openssl pkcs8 -nocrypt >/dev/null; then
110+
elif [ ${#FASTLANE_KEY_ID} -ne 10 ]; then
44111
failed=true
45-
echo "::error::The FASTLANE_KEY secret is set but invalid. Verify that it is set correctly and try again."
46-
elif ! fastlane validate_secrets; then
112+
echo "::error::The FASTLANE_KEY_ID secret is set but has wrong length. Verify that you copied it correctly from the 'Keys' tab at https://appstoreconnect.apple.com/access/api and try again."
113+
elif ! [[ $FASTLANE_KEY_ID =~ $FASTLANE_KEY_ID_PATTERN ]]; then
47114
failed=true
48-
echo "::error::Unable to create a valid authorization token for the App Store Connect API.\
49-
Verify that the FASTLANE_ISSUER_ID, FASTLANE_KEY_ID, and FASTLANE_KEY secrets are set correctly and try again."
50-
fi
51-
52-
# Validate MATCH_PASSWORD
53-
if [ -z "$MATCH_PASSWORD" ]; then
115+
echo "::error::The FASTLANE_KEY_ID secret is set but invalid. Verify that you copied it correctly from the 'Keys' tab at https://appstoreconnect.apple.com/access/api and try again."
116+
elif ! [[ $FASTLANE_ISSUER_ID =~ $FASTLANE_ISSUER_ID_PATTERN ]]; then
54117
failed=true
55-
echo "::error::The MATCH_PASSWORD secret is unset or empty. Set it and try again."
118+
echo "::error::The FASTLANE_ISSUER_ID secret is set but invalid. Verify that you copied it correctly from the 'Keys' tab at https://appstoreconnect.apple.com/access/api and try again."
119+
elif ! echo "$FASTLANE_KEY" | openssl pkcs8 -nocrypt >/dev/null; then
120+
failed=true
121+
echo "::error::The FASTLANE_KEY secret is set but invalid. Verify that you copied it correctly from the API Key file (*.p8) you downloaded and try again."
122+
elif ! fastlane validate_secrets 2>&1 | tee fastlane.log; then
123+
if grep -q "bad decrypt" fastlane.log; then
124+
failed=true
125+
echo "::error::Unable to decrypt the Match-Secrets repository using the MATCH_PASSWORD secret. Verify that it is set correctly and try again."
126+
elif ! grep -q "No code signing identity found" fastlane.log; then
127+
failed=true
128+
echo "::error::Unable to create a valid authorization token for the App Store Connect API.\
129+
Verify that the FASTLANE_ISSUER_ID, FASTLANE_KEY_ID, and FASTLANE_KEY secrets are set correctly and try again."
130+
fi
56131
fi
57132
58133
# Exit unsuccessfully if secret validation failed.
59134
if [ $failed ]; then
60135
exit 2
61136
fi
62-
shell: bash
63-
env:
64-
TEAMID: ${{ secrets.TEAMID }}
65-
GH_PAT: ${{ secrets.GH_PAT }}
66-
FASTLANE_ISSUER_ID: ${{ secrets.FASTLANE_ISSUER_ID }}
67-
FASTLANE_KEY_ID: ${{ secrets.FASTLANE_KEY_ID }}
68-
FASTLANE_KEY: ${{ secrets.FASTLANE_KEY }}
69-
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
70-
GH_TOKEN: ${{ secrets.GH_PAT }}

fastlane/Fastfile

+7
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ platform :ios do
249249
end
250250

251251
find_bundle_id("com.#{TEAMID}.loopkit.Loop")
252+
253+
match(
254+
type: "appstore",
255+
git_basic_authorization: Base64.strict_encode64("#{GITHUB_REPOSITORY_OWNER}:#{GH_PAT}"),
256+
app_identifier: [],
257+
)
258+
252259
end
253260

254261
desc "Nuke Certs"

0 commit comments

Comments
 (0)