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
9 changes: 7 additions & 2 deletions .github/workflows/ios-appstore-gm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,15 @@ jobs:
--projectId="$INFISICAL_PROJECT_ID" --env=prod --path=/ 2>/dev/null || true
)"
[ -n "$val" ] || continue
echo "::add-mask::$val"
while IFS= read -r line; do
if [ -n "$line" ]; then
line="${line//%/%25}"; line="${line//$'\r'/%0D}"
printf '::add-mask::%s\n' "$line"
fi
done <<< "$val"
Comment thread
kody-ai[bot] marked this conversation as resolved.
Resolved
{ echo "${name}<<INFISICAL_EOF"; printf '%s\n' "$val"; echo "INFISICAL_EOF"; } >> "$GITHUB_ENV"
done
unset TOKEN CLIENT_ID CLIENT_SECRET val
unset TOKEN CLIENT_ID CLIENT_SECRET val line

- name: Import signing + ASC key
run: bash "$GITHUB_WORKSPACE/scripts/ios-appstore-gm-prepare.sh"
Expand Down
18 changes: 14 additions & 4 deletions .github/workflows/ios-ship.yml
Original file line number Diff line number Diff line change
Expand Up @@ -299,18 +299,28 @@ jobs:
echo "::error::Missing ASC key material in Infisical prod."
exit 1
fi
# Mask every line of the raw PEM before staging it. One add-mask
# carrying a multiline value only masks its first line.
while IFS= read -r line; do
if [ -n "$line" ]; then
line="${line//%/%25}"; line="${line//$'\r'/%0D}"
printf '::add-mask::%s\n' "$line"
fi
done <<< "$key_material"
# One line, so GITHUB_ENV carries it natively, and the raw PEM never
# reaches a step environment. The same form the client reads first.
# Mask the base64 form before it reaches GITHUB_ENV: GitHub prints
# every later step's env block in the public log.
key_b64="$(printf '%s' "$key_material" | base64 | tr -d '\n')"
echo "::add-mask::${key_b64}"
printf 'APPLE_API_KEY_ID=%s\n' "$ASC_KEY_ID" >> "$GITHUB_ENV"
printf 'APPLE_API_ISSUER_ID=%s\n' "$ASC_ISSUER_ID" >> "$GITHUB_ENV"
printf 'APPLE_API_KEY_P8_BASE64=%s\n' \
"$(printf '%s' "$key_material" | base64 | tr -d '\n')" \
>> "$GITHUB_ENV"
printf 'APPLE_API_KEY_P8_BASE64=%s\n' "$key_b64" >> "$GITHUB_ENV"
printf '%s\n' "$key_material" | bash "$GITHUB_WORKSPACE/scripts/ios-stage-asc-key.sh"
ASC_KEY_PATH="$(sed -n 's/^ASC_KEY_PATH=//p' "$GITHUB_ENV" | tail -n 1)"
export ASC_KEY_PATH
bash "$GITHUB_WORKSPACE/scripts/ios-appstore-gm-prepare.sh"
unset key_material TOKEN CLIENT_ID CLIENT_SECRET val IOS_DIST_P12_BASE64 IOS_DIST_P12_PASSWORD
unset key_material key_b64 line TOKEN CLIENT_ID CLIENT_SECRET val IOS_DIST_P12_BASE64 IOS_DIST_P12_PASSWORD

# Plan-build: compute each app's release build ONCE here and hand it to
# the ship steps as --build, so the two ships of one release can never
Expand Down
27 changes: 26 additions & 1 deletion scripts/test-ios-stage-asc-key.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ if ! grep -Fq 'scripts/ios-stage-asc-key.sh' "$workflow"; then
exit 1
fi

# The base64 form must be masked before it is written to GITHUB_ENV.
# GitHub prints later steps' env blocks, so an unmasked write puts the
# base64 private key in the public log.
mask_line="$(grep -n -F '::add-mask::${key_b64}' "$workflow" | head -n 1 | cut -d: -f1 || true)"
env_line="$(grep -n -F 'APPLE_API_KEY_P8_BASE64=%s' "$workflow" | head -n 1 | cut -d: -f1 || true)"
if [[ -z "$mask_line" || -z "$env_line" || "$mask_line" -ge "$env_line" ]]; then
echo 'base64 ASC key is not masked before it reaches GITHUB_ENV' >&2
exit 1
fi

# A second handoff cannot overwrite the first key, including through aliases.
bash "$repo_root/scripts/ios-stage-asc-key.sh" < "$tmp_dir/fixture" > "$tmp_dir/stdout" 2> "$tmp_dir/stderr"
second_path="$(tail -n 1 "$GITHUB_ENV" | sed 's/^ASC_KEY_PATH=//')"
Expand Down Expand Up @@ -105,10 +115,25 @@ env -u ASC_KEY_P8 PATH="$tmp_dir/bin:$PATH" \
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET=synthetic-secret \
ASC_TEST_FIXTURE="$tmp_dir/fixture" ASC_TEST_IMPORT_MARKER="$tmp_dir/imported" \
bash "$tmp_dir/workflow-load.sh" > "$tmp_dir/workflow-stdout" 2> "$tmp_dir/workflow-stderr"
if grep -Fq -f "$tmp_dir/fixture" "$tmp_dir/workflow-env" "$tmp_dir/workflow-stdout" "$tmp_dir/workflow-stderr"; then
# Mask carriers are the one place a fixture line may appear: the Actions
# runner consumes `::add-mask::` lines instead of listing them, but the
# local harness captures stdout verbatim. Strip carriers before the leak
# check, then assert each line and the base64 form were in fact carried.
grep -v '^::add-mask::' "$tmp_dir/workflow-stdout" > "$tmp_dir/workflow-stdout-unmasked" || true
if grep -Fq -f "$tmp_dir/fixture" "$tmp_dir/workflow-env" "$tmp_dir/workflow-stdout-unmasked" "$tmp_dir/workflow-stderr"; then
echo 'workflow leaked multiline key material' >&2
exit 1
fi
while IFS= read -r fixture_line; do
grep -Fqx "::add-mask::$fixture_line" "$tmp_dir/workflow-stdout"
done < "$tmp_dir/fixture"
workflow_b64="$(sed -n 's/^APPLE_API_KEY_P8_BASE64=//p' "$tmp_dir/workflow-env")"
[[ -n "$workflow_b64" ]]
grep -Fqx "::add-mask::$workflow_b64" "$tmp_dir/workflow-stdout"
if grep -Fq "$workflow_b64" "$tmp_dir/workflow-stdout-unmasked" "$tmp_dir/workflow-stderr"; then
echo 'workflow printed the base64 key outside a mask carrier' >&2
exit 1
fi
[[ "$(grep -c '^ASC_KEY_PATH=' "$tmp_dir/workflow-env")" == 1 ]]
workflow_key="$(sed -n 's/^ASC_KEY_PATH=//p' "$tmp_dir/workflow-env")"
cmp "$tmp_dir/fixture" "$workflow_key"
Expand Down
Loading