Skip to content
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
2 changes: 2 additions & 0 deletions .changeset/nine-hoops-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
42 changes: 23 additions & 19 deletions .github/workflows/expo-native-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ env:
SDK_PACK_DIR: /tmp/clerk-expo-pack
E2E_INSTANCE_NAME: clerkstage-with-native-components
BAPI_URL: https://api.clerkstage.dev
MAESTRO_VERSION: '2.6.1'
MAESTRO_RUNNER_VERSION: '1.1.21'

jobs:
native-build:
Expand Down Expand Up @@ -214,34 +214,33 @@ jobs:
path: ${{ steps.native-build-key.outputs.artifact }}
key: ${{ steps.native-build-cache.outputs.cache-primary-key }}

- name: Cache Maestro
- name: Cache maestro-runner
if: steps.keys.outputs.pk != ''
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.maestro
key: maestro-${{ runner.os }}-${{ env.MAESTRO_VERSION }}
path: ~/.maestro-runner
key: maestro-runner-${{ runner.os }}-${{ runner.arch }}-${{ env.MAESTRO_RUNNER_VERSION }}

- name: Install Maestro
- name: Install maestro-runner
if: steps.keys.outputs.pk != ''
# pipefail + binary check so a curl flake doesn't leave a missing
# binary that only surfaces later as exit-code-127.
run: |
set -o pipefail
if [ -x "$HOME/.maestro/bin/maestro" ]; then
echo "Using cached Maestro"
if [ -x "$HOME/.maestro-runner/bin/maestro-runner" ]; then
echo "Using cached maestro-runner"
else
installed=0
for i in 1 2 3; do
if curl -fLs --retry 3 --retry-delay 5 "https://get.maestro.mobile.dev" | MAESTRO_VERSION="$MAESTRO_VERSION" bash; then
if [ -x "$HOME/.maestro/bin/maestro" ]; then installed=1; break; fi
if curl -fsSL --retry 3 --retry-delay 5 "https://open.devicelab.dev/install/maestro-runner" |
bash -s -- --version "$MAESTRO_RUNNER_VERSION"; then
if [ -x "$HOME/.maestro-runner/bin/maestro-runner" ]; then installed=1; break; fi
fi
echo "Maestro install attempt $i failed (or binary missing); retrying"
echo "maestro-runner install attempt $i failed (or binary missing); retrying"
sleep 5
done
[ "$installed" = 1 ] || { echo "::error::Maestro install failed after 3 attempts"; exit 1; }
[ "$installed" = 1 ] || { echo "::error::maestro-runner install failed after 3 attempts"; exit 1; }
fi
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"
"$HOME/.maestro/bin/maestro" --version
echo "$HOME/.maestro-runner/bin" >> "$GITHUB_PATH"
"$HOME/.maestro-runner/bin/maestro-runner" --version
Comment on lines +217 to +243

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

installer="$(mktemp)"
trap 'rm -f "$installer"' EXIT

curl --proto '=https' --tlsv1.2 -fsSL \
  'https://open.devicelab.dev/install/maestro-runner' \
  -o "$installer"

grep -nE 'sha256|sha512|checksum|signature|version|download' "$installer" || true

Repository: clerk/javascript

Length of output: 1003


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file=".github/workflows/expo-native-build.yml"
sed -n '200,250p' "$file"

printf '\n--- installer excerpt ---\n'
curl --proto '=https' --tlsv1.2 -fsSL 'https://open.devicelab.dev/install/maestro-runner' | sed -n '1,180p'

Repository: clerk/javascript

Length of output: 7243


Avoid piping the Maestro installer into bash The workflow still executes mutable remote code here, and the installer skips integrity checking when the .sha256 file is missing. Fetch a pinned artifact/installer and fail closed unless integrity metadata is present.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/expo-native-build.yml around lines 217 - 243, The Install
maestro-runner step must stop piping the mutable remote installer directly into
bash. Replace that flow with downloading a pinned installer or artifact plus its
required integrity metadata, fail if the checksum file is unavailable, verify
the downloaded content before execution, and retain the existing retry and
cached-binary behavior around the verified installation.


- name: Boot iOS simulator
id: sim
Expand Down Expand Up @@ -289,6 +288,9 @@ jobs:
env:
CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }}
CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }}
MAESTRO_DEVICE: ${{ steps.sim.outputs.udid }}
MAESTRO_DRIVER: wda
MAESTRO_PLATFORM: ios
SIM_UDID: ${{ steps.sim.outputs.udid }}
run: |
echo "Using simulator $SIM_UDID"
Expand Down Expand Up @@ -352,6 +354,8 @@ jobs:
env:
CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }}
CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }}
MAESTRO_DRIVER: devicelab
MAESTRO_PLATFORM: android
with:
api-level: 34
target: google_apis
Expand All @@ -377,9 +381,9 @@ jobs:
curl -fsS -X DELETE "$BAPI_URL/v1/users/$USER_ID" \
-H "Authorization: Bearer $CLERK_SECRET_KEY" || true

# Maestro debug files record flow env (and typed input) in plaintext;
# Test reports record flow env (and typed input) in plaintext;
# add-mask only covers step logs, not artifact contents.
- name: Scrub test credentials from Maestro debug output
- name: Scrub test credentials from maestro-runner reports
if: always() && (steps.run_e2e_ios.outcome == 'failure' || steps.run_e2e_android.outcome == 'failure')
env:
CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }}
Expand All @@ -388,10 +392,10 @@ jobs:
[ -n "$CLERK_TEST_PASSWORD" ] || exit 0
# shellcheck disable=SC2016
find "$RUNNER_TEMP/maestro-debug" -type f \
\( -name '*.json' -o -name '*.log' -o -name '*.txt' -o -name '*.yaml' \) \
\( -name '*.html' -o -name '*.json' -o -name '*.log' -o -name '*.txt' -o -name '*.xml' -o -name '*.yaml' \) \
-exec perl -pi -e 's/\Q$ENV{CLERK_TEST_PASSWORD}\E/[REDACTED]/g' {} +

- name: Upload Maestro artifacts on e2e failure
- name: Upload maestro-runner artifacts on e2e failure
if: always() && (steps.run_e2e_ios.outcome == 'failure' || steps.run_e2e_android.outcome == 'failure')
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
Expand Down
24 changes: 15 additions & 9 deletions integration/tests/expo-native/run-flows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"

command -v maestro >/dev/null 2>&1 || {
echo "maestro CLI is required: https://docs.maestro.dev/getting-started/installing-maestro"
command -v maestro-runner >/dev/null 2>&1 || {
echo "maestro-runner is required: https://devicelab.dev/open-source/maestro-runner/docs/getting-started"
exit 1
}

Expand All @@ -25,10 +25,17 @@ command -v maestro >/dev/null 2>&1 || {

force_stop() { if [ "$#" -gt 0 ]; then "$@" >/dev/null 2>&1 || true; fi; }

debug_args=()
if [ -n "${MAESTRO_DEBUG_OUTPUT:-}" ]; then
debug_args=(--debug-output "$MAESTRO_DEBUG_OUTPUT" --flatten-debug-output)
fi
run_flow() {
local output_name=$1
shift
local output_root=${MAESTRO_DEBUG_OUTPUT:-${TMPDIR:-/tmp}/clerk-expo-maestro-runner}

maestro-runner test \
--output "$output_root/$output_name" \
--flatten \
--artifacts on-failure \
"$@"
}

record_result() {
local flow=$1
Expand All @@ -54,7 +61,7 @@ fi
warmup_started=$SECONDS
warmup_result=failed
for warmup_attempt in 1 2; do
if maestro test ${debug_args+"${debug_args[@]}"} flows/subflows/_warmup.yaml; then
if run_flow "warmup-attempt-$warmup_attempt" flows/subflows/_warmup.yaml; then
warmup_result=passed
break
fi
Expand Down Expand Up @@ -82,10 +89,9 @@ for flow in flows/*.yaml; do
flow_started=$SECONDS
flow_result=failed
for attempt in 1 2; do
if maestro test \
if run_flow "${flow##*/}-attempt-$attempt" \
--env CLERK_TEST_EMAIL="$CLERK_TEST_EMAIL" \
--env CLERK_TEST_PASSWORD="$CLERK_TEST_PASSWORD" \
${debug_args+"${debug_args[@]}"} \
"$flow"; then
flow_result=passed
break
Expand Down
Loading