mirror of
https://github.com/selfxyz/self.git
synced 2026-01-08 22:28:11 -05:00
Remove personal access token (#1481)
* Refactor NFC scanner tests to use a global variable for platform OS, allowing dynamic switching between iOS and Android during tests. This change improves test isolation and avoids hoisting issues with jest.mock. * feat: add GitHub App token generation action for self repositories - Introduced a new action to generate GitHub App tokens for accessing repositories within the selfxyz organization. - Updated multiple workflows to utilize the new action for token generation, ensuring secure access to private repositories during CI processes. - Modified Podfile and scripts to support authentication using the generated token, enhancing the cloning of private modules in CI environments. * chore: enhance CI workflows with Git authentication for CocoaPods - Updated multiple CI workflows to include a step for configuring Git authentication for CocoaPods, ensuring secure access to private repositories without embedding credentials in URLs. - Added masking for sensitive tokens in logs to enhance security during CI processes. - Modified the Podfile to avoid printing authentication details in CI logs, improving overall security practices. * chore: enhance CI workflows with optional Git authentication configuration - Added new inputs to the GitHub action for generating GitHub tokens, allowing optional configuration of a ~/.netrc entry for Git authentication. - Updated multiple CI workflows to utilize the new configuration, improving security and simplifying access to private repositories during builds. - Removed redundant Git authentication steps from workflows, streamlining the CI process while maintaining secure access to necessary resources. * chore: update Podfile for secure Git authentication in CI - Modified the Podfile to enhance security by avoiding the embedding of credentials in URLs for accessing the NFCPassportReader repository during CI processes. - Added comments to guide developers on using workflow-provided authentication methods, improving overall security practices in the project.
This commit is contained in:
56
.github/actions/generate-github-token/action.yml
vendored
Normal file
56
.github/actions/generate-github-token/action.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: "Generate GitHub App Token"
|
||||
description: "Generates a GitHub App token for accessing repositories in the selfxyz organization"
|
||||
|
||||
inputs:
|
||||
app-id:
|
||||
description: "The GitHub App ID"
|
||||
required: true
|
||||
private-key:
|
||||
description: "The GitHub App private key"
|
||||
required: true
|
||||
configure-netrc:
|
||||
description: "If true, writes a ~/.netrc entry for github.com using the generated token (useful for CocoaPods / git HTTPS fetches)"
|
||||
required: false
|
||||
default: "false"
|
||||
netrc-machine:
|
||||
description: "The machine hostname to write into ~/.netrc (default: github.com)"
|
||||
required: false
|
||||
default: "github.com"
|
||||
owner:
|
||||
description: "The owner (organization) of the repositories"
|
||||
required: false
|
||||
default: "selfxyz"
|
||||
repositories:
|
||||
description: "Comma-separated list of repository names to grant access to"
|
||||
required: false
|
||||
default: "NFCPassportReader,android-passport-nfc-reader,react-native-passport-reader,mobile-sdk-native"
|
||||
|
||||
outputs:
|
||||
token:
|
||||
description: "The generated GitHub App installation token"
|
||||
value: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Generate GitHub App Token
|
||||
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ inputs.app-id }}
|
||||
private-key: ${{ inputs.private-key }}
|
||||
owner: ${{ inputs.owner }}
|
||||
repositories: ${{ inputs.repositories }}
|
||||
- name: Configure Git auth via ~/.netrc (optional)
|
||||
if: ${{ inputs.configure-netrc == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
TOKEN="${{ steps.app-token.outputs.token }}"
|
||||
MACHINE="${{ inputs.netrc-machine }}"
|
||||
|
||||
# Mask the token in logs defensively (it shouldn't print, but this protects against future edits).
|
||||
echo "::add-mask::${TOKEN}"
|
||||
|
||||
printf "machine %s\n login x-access-token\n password %s\n" "${MACHINE}" "${TOKEN}" > "${HOME}/.netrc"
|
||||
chmod 600 "${HOME}/.netrc"
|
||||
20
.github/workflows/mobile-bundle-analysis.yml
vendored
20
.github/workflows/mobile-bundle-analysis.yml
vendored
@@ -58,6 +58,14 @@ jobs:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
configure-netrc: "true"
|
||||
- name: Install Mobile Dependencies
|
||||
uses: ./.github/actions/mobile-setup
|
||||
with:
|
||||
@@ -66,7 +74,7 @@ jobs:
|
||||
ruby_version: ${{ env.RUBY_VERSION }}
|
||||
workspace: ${{ env.WORKSPACE }}
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Build dependencies
|
||||
shell: bash
|
||||
run: yarn workspace @selfxyz/common build
|
||||
@@ -114,6 +122,14 @@ jobs:
|
||||
with:
|
||||
path: app/ios/Pods
|
||||
lockfile: app/ios/Podfile.lock
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
configure-netrc: "true"
|
||||
- name: Install Mobile Dependencies
|
||||
uses: ./.github/actions/mobile-setup
|
||||
with:
|
||||
@@ -122,7 +138,7 @@ jobs:
|
||||
ruby_version: ${{ env.RUBY_VERSION }}
|
||||
workspace: ${{ env.WORKSPACE }}
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Build dependencies
|
||||
shell: bash
|
||||
run: yarn workspace @selfxyz/common build
|
||||
|
||||
20
.github/workflows/mobile-ci.yml
vendored
20
.github/workflows/mobile-ci.yml
vendored
@@ -267,6 +267,7 @@ jobs:
|
||||
- name: Cache Ruby gems
|
||||
uses: ./.github/actions/cache-bundler
|
||||
with:
|
||||
# TODO(jcortejoso): Confirm the path of the bundle cache
|
||||
path: app/ios/vendor/bundle
|
||||
lock-file: app/Gemfile.lock
|
||||
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.GH_GEMS_CACHE_VERSION }}-ruby${{ env.RUBY_VERSION }}
|
||||
@@ -314,6 +315,14 @@ jobs:
|
||||
bundle config set --local path 'vendor/bundle'
|
||||
bundle install --jobs 4 --retry 3
|
||||
working-directory: ./app
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
configure-netrc: "true"
|
||||
- name: Install iOS Dependencies
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
@@ -324,7 +333,7 @@ jobs:
|
||||
cd app/ios
|
||||
bundle exec bash scripts/pod-install-with-cache-fix.sh
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Resolve iOS workspace
|
||||
run: |
|
||||
WORKSPACE_OPEN="ios/OpenPassport.xcworkspace"
|
||||
@@ -469,12 +478,19 @@ jobs:
|
||||
run: |
|
||||
echo "Cache miss for built dependencies. Building now..."
|
||||
yarn workspace @selfxyz/mobile-app run build:deps
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
- name: Setup Android private modules
|
||||
run: |
|
||||
cd ${{ env.APP_PATH }}
|
||||
PLATFORM=android node scripts/setup-private-modules.cjs
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
CI: true
|
||||
- name: Build Android (with AAPT2 symlink fix)
|
||||
run: yarn android:ci
|
||||
|
||||
25
.github/workflows/mobile-deploy.yml
vendored
25
.github/workflows/mobile-deploy.yml
vendored
@@ -386,6 +386,7 @@ jobs:
|
||||
id: gems-cache
|
||||
uses: ./.github/actions/cache-bundler
|
||||
with:
|
||||
# TODO(jcortejoso): Confirm the path of the bundle cache
|
||||
path: ${{ env.APP_PATH }}/ios/vendor/bundle
|
||||
lock-file: app/Gemfile.lock
|
||||
cache-version: ${{ env.GH_CACHE_VERSION }}-${{ env.GH_GEMS_CACHE_VERSION }}-ruby${{ env.RUBY_VERSION }}
|
||||
@@ -429,6 +430,14 @@ jobs:
|
||||
fi
|
||||
|
||||
echo "✅ Lock files exist"
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
configure-netrc: "true"
|
||||
|
||||
- name: Install Mobile Dependencies (main repo)
|
||||
if: inputs.platform != 'android' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
||||
@@ -439,7 +448,7 @@ jobs:
|
||||
ruby_version: ${{ env.RUBY_VERSION }}
|
||||
workspace: ${{ env.WORKSPACE }}
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
|
||||
- name: Install Mobile Dependencies (forked PRs - no secrets)
|
||||
if: inputs.platform != 'android' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true
|
||||
@@ -692,7 +701,7 @@ jobs:
|
||||
IOS_TESTFLIGHT_GROUPS: ${{ secrets.IOS_TESTFLIGHT_GROUPS }}
|
||||
NODE_OPTIONS: "--max-old-space-size=8192"
|
||||
SEGMENT_KEY: ${{ secrets.SEGMENT_KEY }}
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
TURNKEY_AUTH_PROXY_CONFIG_ID: ${{ secrets.TURNKEY_AUTH_PROXY_CONFIG_ID }}
|
||||
TURNKEY_GOOGLE_CLIENT_ID: ${{ secrets.TURNKEY_GOOGLE_CLIENT_ID }}
|
||||
@@ -1047,6 +1056,14 @@ jobs:
|
||||
|
||||
echo "✅ Lock files exist"
|
||||
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
|
||||
- name: Install Mobile Dependencies (main repo)
|
||||
if: inputs.platform != 'ios' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
|
||||
uses: ./.github/actions/mobile-setup
|
||||
@@ -1056,7 +1073,7 @@ jobs:
|
||||
ruby_version: ${{ env.RUBY_VERSION }}
|
||||
workspace: ${{ env.WORKSPACE }}
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
PLATFORM: ${{ inputs.platform }}
|
||||
|
||||
- name: Install Mobile Dependencies (forked PRs - no secrets)
|
||||
@@ -1113,7 +1130,7 @@ jobs:
|
||||
cd ${{ env.APP_PATH }}
|
||||
PLATFORM=android node scripts/setup-private-modules.cjs
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
CI: true
|
||||
|
||||
- name: Build Dependencies (Android)
|
||||
|
||||
30
.github/workflows/mobile-e2e.yml
vendored
30
.github/workflows/mobile-e2e.yml
vendored
@@ -70,6 +70,14 @@ jobs:
|
||||
- name: Toggle Yarn hardened mode for trusted PRs
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }}
|
||||
run: echo "YARN_ENABLE_HARDENED_MODE=0" >> $GITHUB_ENV
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
configure-netrc: "true"
|
||||
- name: Install deps (internal PRs and protected branches)
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -79,7 +87,7 @@ jobs:
|
||||
retry_wait_seconds: 5
|
||||
command: yarn install --immutable --silent
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Install deps (forked PRs - no secrets)
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -138,7 +146,7 @@ jobs:
|
||||
cd app
|
||||
PLATFORM=android node scripts/setup-private-modules.cjs
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
CI: true
|
||||
- name: Build Android APK
|
||||
run: |
|
||||
@@ -149,6 +157,8 @@ jobs:
|
||||
- name: Clean up Gradle build artifacts
|
||||
uses: ./.github/actions/cleanup-gradle-artifacts
|
||||
- name: Verify APK and android-passport-nfc-reader integration
|
||||
env:
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
run: |
|
||||
echo "🔍 Verifying build artifacts..."
|
||||
APK_PATH="app/android/app/build/outputs/apk/debug/app-debug.apk"
|
||||
@@ -160,8 +170,8 @@ jobs:
|
||||
echo "📱 APK size: $APK_SIZE bytes"
|
||||
|
||||
# Verify private modules were properly integrated (skip for forks)
|
||||
if [ -z "${SELFXYZ_INTERNAL_REPO_PAT:-}" ]; then
|
||||
echo "🔕 No PAT available — skipping private module verification"
|
||||
if [ -z "${SELFXYZ_APP_TOKEN:-}" ]; then
|
||||
echo "🔕 No SELFXYZ_APP_TOKEN available — skipping private module verification"
|
||||
else
|
||||
# Verify android-passport-nfc-reader
|
||||
if [ -d "app/android/android-passport-nfc-reader" ]; then
|
||||
@@ -263,6 +273,14 @@ jobs:
|
||||
- name: Toggle Yarn hardened mode for trusted PRs
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }}
|
||||
run: echo "YARN_ENABLE_HARDENED_MODE=0" >> $GITHUB_ENV
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
configure-netrc: "true"
|
||||
- name: Install deps (internal PRs and protected branches)
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -272,7 +290,7 @@ jobs:
|
||||
retry_wait_seconds: 5
|
||||
command: yarn install --immutable --silent
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Install deps (forked PRs - no secrets)
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -360,7 +378,7 @@ jobs:
|
||||
echo "📦 Installing pods via centralized script…"
|
||||
BUNDLE_GEMFILE=../Gemfile bundle exec bash scripts/pod-install-with-cache-fix.sh
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Setup iOS Simulator
|
||||
run: |
|
||||
echo "Setting up iOS Simulator..."
|
||||
|
||||
26
.github/workflows/mobile-sdk-demo-e2e.yml
vendored
26
.github/workflows/mobile-sdk-demo-e2e.yml
vendored
@@ -73,6 +73,13 @@ jobs:
|
||||
- name: Toggle Yarn hardened mode for trusted PRs
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }}
|
||||
run: echo "YARN_ENABLE_HARDENED_MODE=0" >> $GITHUB_ENV
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
- name: Install deps (internal PRs and protected branches)
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -82,7 +89,7 @@ jobs:
|
||||
retry_wait_seconds: 5
|
||||
command: yarn install --immutable --silent
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Install deps (forked PRs - no secrets)
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -237,6 +244,13 @@ jobs:
|
||||
- name: Toggle Yarn hardened mode for trusted PRs
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false }}
|
||||
run: echo "YARN_ENABLE_HARDENED_MODE=0" >> $GITHUB_ENV
|
||||
- name: Generate token for self repositories
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: ./.github/actions/generate-github-token
|
||||
id: github-token
|
||||
with:
|
||||
app-id: ${{ vars.GH_WORKFLOWS_CROSS_ACCESS_ID }}
|
||||
private-key: ${{ secrets.GH_WORKFLOWS_CROSS_ACCESS_KEY }}
|
||||
- name: Install deps (internal PRs and protected branches)
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -246,7 +260,7 @@ jobs:
|
||||
retry_wait_seconds: 5
|
||||
command: yarn install --immutable --silent
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
- name: Install deps (forked PRs - no secrets)
|
||||
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
|
||||
uses: nick-fields/retry@v3
|
||||
@@ -322,15 +336,15 @@ jobs:
|
||||
max_attempts: 3
|
||||
retry_wait_seconds: 10
|
||||
command: |
|
||||
if [ -n "${SELFXYZ_INTERNAL_REPO_PAT}" ]; then
|
||||
echo "🔑 Using SELFXYZ_INTERNAL_REPO_PAT for private pod access"
|
||||
echo "::add-mask::${SELFXYZ_INTERNAL_REPO_PAT}"
|
||||
if [ -n "${SELFXYZ_APP_TOKEN}" ]; then
|
||||
echo "🔑 Using GitHub App token for private pod access"
|
||||
echo "::add-mask::${SELFXYZ_APP_TOKEN}"
|
||||
fi
|
||||
cd packages/mobile-sdk-demo/ios
|
||||
echo "📦 Installing pods via cache-fix script…"
|
||||
bash scripts/pod-install-with-cache-fix.sh
|
||||
env:
|
||||
SELFXYZ_INTERNAL_REPO_PAT: ${{ secrets.SELFXYZ_INTERNAL_REPO_PAT }}
|
||||
SELFXYZ_APP_TOKEN: ${{ steps.github-token.outputs.token }}
|
||||
GIT_TERMINAL_PROMPT: 0
|
||||
- name: Setup iOS Simulator
|
||||
run: |
|
||||
|
||||
@@ -33,7 +33,7 @@ def using_https_git_auth?
|
||||
auth_data.include?("Logged in to github.com account") &&
|
||||
auth_data.include?("Git operations protocol: https")
|
||||
rescue => e
|
||||
puts "gh auth status failed, assuming no HTTPS auth -- will try SSH"
|
||||
# Avoid printing auth-related details in CI logs.
|
||||
false
|
||||
end
|
||||
end
|
||||
@@ -51,18 +51,16 @@ target "Self" do
|
||||
# External fork - use public NFCPassportReader repository (placeholder)
|
||||
# TODO: Replace with actual public NFCPassportReader repository URL
|
||||
nfc_repo_url = "https://github.com/PLACEHOLDER/NFCPassportReader.git"
|
||||
puts "📦 Using public NFCPassportReader for external fork (#{ENV["GITHUB_REPOSITORY"]})"
|
||||
elsif ENV["GITHUB_ACTIONS"] == "true" && ENV["SELFXYZ_INTERNAL_REPO_PAT"]
|
||||
# Running in selfxyz GitHub Actions with PAT available - use private repo with token
|
||||
nfc_repo_url = "https://#{ENV["SELFXYZ_INTERNAL_REPO_PAT"]}@github.com/selfxyz/NFCPassportReader.git"
|
||||
puts "📦 Using private NFCPassportReader with PAT (selfxyz GitHub Actions)"
|
||||
elsif ENV["GITHUB_ACTIONS"] == "true"
|
||||
# CI: NEVER embed credentials in URLs. Rely on workflow-provided auth via:
|
||||
# - ~/.netrc or a Git credential helper, and token masking in logs.
|
||||
nfc_repo_url = "https://github.com/selfxyz/NFCPassportReader.git"
|
||||
elsif using_https_git_auth?
|
||||
# Local development with HTTPS GitHub auth via gh - use HTTPS to private repo
|
||||
nfc_repo_url = "https://github.com/selfxyz/NFCPassportReader.git"
|
||||
else
|
||||
# Local development in selfxyz repo - use SSH to private repo
|
||||
nfc_repo_url = "git@github.com:selfxyz/NFCPassportReader.git"
|
||||
puts "📦 Using SSH for private NFCPassportReader (local selfxyz development)"
|
||||
end
|
||||
|
||||
pod "NFCPassportReader", git: nfc_repo_url, commit: "9eff7c4e3a9037fdc1e03301584e0d5dcf14d76b"
|
||||
|
||||
@@ -109,7 +109,13 @@ clone_private_module() {
|
||||
local dir_name=$(basename "$target_dir")
|
||||
|
||||
# Use different clone methods based on environment
|
||||
if is_ci && [[ -n "${SELFXYZ_INTERNAL_REPO_PAT:-}" ]]; then
|
||||
if is_ci && [[ -n "${SELFXYZ_APP_TOKEN:-}" ]]; then
|
||||
# CI environment with GitHub App installation token
|
||||
git clone "https://x-access-token:${SELFXYZ_APP_TOKEN}@github.com/selfxyz/${repo_name}.git" "$dir_name" || {
|
||||
log "ERROR: Failed to clone $repo_name with GitHub App token"
|
||||
exit 1
|
||||
}
|
||||
elif is_ci && [[ -n "${SELFXYZ_INTERNAL_REPO_PAT:-}" ]]; then
|
||||
# CI environment with PAT (fallback if action didn't run)
|
||||
git clone "https://${SELFXYZ_INTERNAL_REPO_PAT}@github.com/selfxyz/${repo_name}.git" "$dir_name" || {
|
||||
log "ERROR: Failed to clone $repo_name with PAT"
|
||||
@@ -119,14 +125,14 @@ clone_private_module() {
|
||||
# Local development with SSH
|
||||
git clone "git@github.com:selfxyz/${repo_name}.git" "$dir_name" || {
|
||||
log "ERROR: Failed to clone $repo_name with SSH"
|
||||
log "Please ensure you have SSH access to the repository or set SELFXYZ_INTERNAL_REPO_PAT"
|
||||
log "Please ensure you have SSH access to the repository or set SELFXYZ_APP_TOKEN/SELFXYZ_INTERNAL_REPO_PAT"
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
log "ERROR: No authentication method available for cloning $repo_name"
|
||||
log "Please either:"
|
||||
log " - Set up SSH access (for local development)"
|
||||
log " - Set SELFXYZ_INTERNAL_REPO_PAT environment variable (for CI)"
|
||||
log " - Set SELFXYZ_APP_TOKEN or SELFXYZ_INTERNAL_REPO_PAT environment variable (for CI)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -194,14 +200,15 @@ log "✅ Package files backed up successfully"
|
||||
# Install SDK from tarball in app with timeout
|
||||
log "Installing SDK as real files..."
|
||||
if is_ci; then
|
||||
# Temporarily unset PAT to skip private modules during SDK installation
|
||||
env -u SELFXYZ_INTERNAL_REPO_PAT timeout 180 yarn add "@selfxyz/mobile-sdk-alpha@file:$TARBALL_PATH" || {
|
||||
# Temporarily unset both auth tokens to skip private modules during SDK installation
|
||||
# Both tokens must be unset to prevent setup-private-modules.cjs from attempting clones
|
||||
env -u SELFXYZ_INTERNAL_REPO_PAT -u SELFXYZ_APP_TOKEN timeout 180 yarn add "@selfxyz/mobile-sdk-alpha@file:$TARBALL_PATH" || {
|
||||
log "SDK installation timed out after 3 minutes"
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
# Temporarily unset PAT to skip private modules during SDK installation
|
||||
env -u SELFXYZ_INTERNAL_REPO_PAT yarn add "@selfxyz/mobile-sdk-alpha@file:$TARBALL_PATH"
|
||||
# Temporarily unset both auth tokens to skip private modules during SDK installation
|
||||
env -u SELFXYZ_INTERNAL_REPO_PAT -u SELFXYZ_APP_TOKEN yarn add "@selfxyz/mobile-sdk-alpha@file:$TARBALL_PATH"
|
||||
fi
|
||||
|
||||
# Verify installation (check for AAR file in both local and hoisted locations)
|
||||
|
||||
@@ -29,8 +29,9 @@ const PRIVATE_MODULES = [
|
||||
|
||||
// Environment detection
|
||||
// CI is set by GitHub Actions, CircleCI, etc. Check for truthy value
|
||||
const isCI = !!process.env.CI || process.env.GITHUB_ACTIONS === 'true';
|
||||
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
||||
const repoToken = process.env.SELFXYZ_INTERNAL_REPO_PAT;
|
||||
const appToken = process.env.SELFXYZ_APP_TOKEN; // GitHub App installation token
|
||||
const isDryRun = process.env.DRY_RUN === 'true';
|
||||
|
||||
// Platform detection for Android-specific modules
|
||||
@@ -150,13 +151,17 @@ function clonePrivateRepo(repoName, localPath) {
|
||||
|
||||
let cloneUrl;
|
||||
|
||||
if (isCI && repoToken) {
|
||||
if (isCI && appToken) {
|
||||
// CI environment with GitHub App installation token
|
||||
log('CI detected: Using SELFXYZ_APP_TOKEN for clone', 'info');
|
||||
cloneUrl = `https://x-access-token:${appToken}@github.com/${GITHUB_ORG}/${repoName}.git`;
|
||||
} else if (isCI && repoToken) {
|
||||
// CI environment with Personal Access Token
|
||||
log('CI detected: Using SELFXYZ_INTERNAL_REPO_PAT for clone', 'info');
|
||||
cloneUrl = `https://${repoToken}@github.com/${GITHUB_ORG}/${repoName}.git`;
|
||||
} else if (isCI) {
|
||||
log(
|
||||
'CI environment detected but SELFXYZ_INTERNAL_REPO_PAT not available - skipping private module setup',
|
||||
'CI environment detected but no token available - skipping private module setup',
|
||||
'info',
|
||||
);
|
||||
log(
|
||||
@@ -173,7 +178,7 @@ function clonePrivateRepo(repoName, localPath) {
|
||||
}
|
||||
|
||||
// Security: Use quiet mode for credentialed URLs to prevent token exposure
|
||||
const isCredentialedUrl = isCI && repoToken;
|
||||
const isCredentialedUrl = isCI && (appToken || repoToken);
|
||||
const quietFlag = isCredentialedUrl ? '--quiet' : '';
|
||||
const targetDir = path.basename(localPath);
|
||||
const cloneCommand = `git clone --branch ${BRANCH} --single-branch --depth 1 ${quietFlag} "${cloneUrl}" "${targetDir}"`;
|
||||
@@ -190,7 +195,7 @@ function clonePrivateRepo(repoName, localPath) {
|
||||
} catch (error) {
|
||||
if (isCI) {
|
||||
log(
|
||||
'Clone failed in CI environment. Check SELFXYZ_INTERNAL_REPO_PAT permissions.',
|
||||
'Clone failed in CI environment. Check SELFXYZ_APP_TOKEN or SELFXYZ_INTERNAL_REPO_PAT permissions.',
|
||||
'error',
|
||||
);
|
||||
} else {
|
||||
@@ -231,7 +236,7 @@ function setupPrivateModule(module) {
|
||||
}
|
||||
|
||||
// Security: Remove credential-embedded remote URL after clone
|
||||
if (isCI && repoToken && !isDryRun) {
|
||||
if (isCI && (appToken || repoToken) && !isDryRun) {
|
||||
scrubGitRemoteUrl(localPath, repoName);
|
||||
}
|
||||
|
||||
@@ -275,6 +280,11 @@ function setupAndroidPassportReader() {
|
||||
`Setup complete: ${successCount}/${PRIVATE_MODULES.length} modules cloned`,
|
||||
'warning',
|
||||
);
|
||||
} else {
|
||||
log(
|
||||
'No private modules were cloned - this is expected for forked PRs',
|
||||
'info',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,19 +3,35 @@
|
||||
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
|
||||
|
||||
// Mock Platform without requiring react-native to avoid memory issues
|
||||
// Use a simple object that can be modified directly
|
||||
// Use a global variable with getter to allow per-test platform switching
|
||||
// This pattern avoids hoisting issues with jest.mock
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import { parseScanResponse, scan } from '@/integrations/nfc/nfcScanner';
|
||||
import { PassportReader } from '@/integrations/nfc/passportReader';
|
||||
|
||||
const Platform = {
|
||||
OS: 'ios', // Default to iOS
|
||||
Version: 14,
|
||||
};
|
||||
// Declare global variable for platform OS that can be modified per-test
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var mockPlatformOS: 'ios' | 'android';
|
||||
}
|
||||
|
||||
// Initialize the global mock platform - default to iOS
|
||||
global.mockPlatformOS = 'ios';
|
||||
|
||||
// Override the react-native mock from jest.setup.js with a getter-based Platform
|
||||
// This allows tests to change Platform.OS dynamically by modifying global.mockPlatformOS
|
||||
jest.mock('react-native', () => ({
|
||||
Platform,
|
||||
Platform: {
|
||||
get OS() {
|
||||
return global.mockPlatformOS;
|
||||
},
|
||||
Version: 14,
|
||||
select: jest.fn((obj: Record<string, unknown>) => {
|
||||
const os = global.mockPlatformOS;
|
||||
return obj[os] || obj.default;
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
// Ensure the Node Buffer implementation is available to the module under test
|
||||
@@ -25,7 +41,7 @@ describe('parseScanResponse', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
// Reset Platform.OS to default before each test to prevent pollution
|
||||
Platform.OS = 'ios';
|
||||
global.mockPlatformOS = 'ios';
|
||||
});
|
||||
|
||||
it('parses iOS response', () => {
|
||||
@@ -93,9 +109,8 @@ describe('parseScanResponse', () => {
|
||||
});
|
||||
|
||||
it('parses Android response', () => {
|
||||
// Temporarily override Platform.OS for this test
|
||||
const originalOS = Platform.OS;
|
||||
Platform.OS = 'android';
|
||||
// Set Platform.OS to android for this test
|
||||
global.mockPlatformOS = 'android';
|
||||
|
||||
const mrz =
|
||||
'P<UTOERIKSSON<<ANNA<MARIA<<<<<<<<<<<<<<<<<<<L898902C<3UTO6908061F9406236ZE184226B<<<<<14';
|
||||
@@ -159,9 +174,6 @@ describe('parseScanResponse', () => {
|
||||
// dg2Hash should be parsed from hex string '1234': 12 = 18, 34 = 52
|
||||
expect(result.dg2Hash).toEqual([18, 52]);
|
||||
expect(result.dgPresents).toEqual([1, 2]);
|
||||
|
||||
// Restore original value
|
||||
Platform.OS = originalOS;
|
||||
});
|
||||
|
||||
it('handles malformed iOS response', () => {
|
||||
@@ -172,8 +184,8 @@ describe('parseScanResponse', () => {
|
||||
});
|
||||
|
||||
it('handles malformed Android response', () => {
|
||||
const originalOS = Platform.OS;
|
||||
Platform.OS = 'android';
|
||||
// Set Platform.OS to android for this test
|
||||
global.mockPlatformOS = 'android';
|
||||
|
||||
const response = {
|
||||
mrz: 'valid_mrz',
|
||||
@@ -182,9 +194,6 @@ describe('parseScanResponse', () => {
|
||||
};
|
||||
|
||||
expect(() => parseScanResponse(response)).toThrow();
|
||||
|
||||
// Restore original value
|
||||
Platform.OS = originalOS;
|
||||
});
|
||||
|
||||
it('handles missing required fields', () => {
|
||||
@@ -232,7 +241,7 @@ describe('scan', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
// Reset Platform.OS to default before each test to prevent pollution
|
||||
Platform.OS = 'ios';
|
||||
global.mockPlatformOS = 'ios';
|
||||
// Reset PassportReader mock before each test
|
||||
// The implementation checks for scanPassport property, so we need to ensure it exists
|
||||
Object.defineProperty(PassportReader, 'scanPassport', {
|
||||
|
||||
@@ -18,6 +18,7 @@ const BRANCH = 'main';
|
||||
// Environment detection
|
||||
const isCI = process.env.CI === 'true';
|
||||
const repoToken = process.env.SELFXYZ_INTERNAL_REPO_PAT;
|
||||
const appToken = process.env.SELFXYZ_APP_TOKEN; // GitHub App installation token
|
||||
const isDryRun = process.env.DRY_RUN === 'true';
|
||||
|
||||
function log(message, type = 'info') {
|
||||
@@ -89,19 +90,24 @@ function setupSubmodule() {
|
||||
|
||||
let submoduleUrl;
|
||||
|
||||
if (isCI && repoToken) {
|
||||
if (isCI && appToken) {
|
||||
// CI environment with GitHub App installation token
|
||||
// Security: NEVER embed credentials in git URLs. Rely on CI-provided auth via:
|
||||
// - ~/.netrc, a Git credential helper, or SSH agent configuration.
|
||||
submoduleUrl = `https://github.com/${GITHUB_ORG}/${REPO_NAME}.git`;
|
||||
} else if (isCI && repoToken) {
|
||||
// CI environment with Personal Access Token
|
||||
log('CI detected: Using SELFXYZ_INTERNAL_REPO_PAT for submodule', 'info');
|
||||
submoduleUrl = `https://${repoToken}@github.com/${GITHUB_ORG}/${REPO_NAME}.git`;
|
||||
// Security: NEVER embed credentials in git URLs. Rely on CI-provided auth via:
|
||||
// - ~/.netrc, a Git credential helper, or SSH agent configuration.
|
||||
submoduleUrl = `https://github.com/${GITHUB_ORG}/${REPO_NAME}.git`;
|
||||
} else if (isCI) {
|
||||
log('CI environment detected but SELFXYZ_INTERNAL_REPO_PAT not available - skipping private module setup', 'info');
|
||||
log('CI environment detected but no token available - skipping private module setup', 'info');
|
||||
log('This is expected for forked PRs or environments without access to private modules', 'info');
|
||||
return false; // Return false to indicate setup was skipped
|
||||
} else if (usingHTTPSGitAuth()) {
|
||||
submoduleUrl = `https://github.com/${GITHUB_ORG}/${REPO_NAME}.git`;
|
||||
} else {
|
||||
// Local development with SSH
|
||||
log('Local development: Using SSH for submodule', 'info');
|
||||
submoduleUrl = `git@github.com:${GITHUB_ORG}/${REPO_NAME}.git`;
|
||||
}
|
||||
|
||||
@@ -113,7 +119,7 @@ function setupSubmodule() {
|
||||
} else {
|
||||
// Add submodule
|
||||
const addCommand = `git submodule add -b ${BRANCH} "${submoduleUrl}" mobile-sdk-native`;
|
||||
if (isCI && repoToken) {
|
||||
if (isCI && (appToken || repoToken)) {
|
||||
// Security: Run command silently to avoid token exposure in logs
|
||||
runCommand(addCommand, { stdio: 'pipe' });
|
||||
} else {
|
||||
@@ -125,7 +131,7 @@ function setupSubmodule() {
|
||||
return true; // Return true to indicate successful setup
|
||||
} catch (error) {
|
||||
if (isCI) {
|
||||
log('Submodule setup failed in CI environment. Check SELFXYZ_INTERNAL_REPO_PAT permissions.', 'error');
|
||||
log('Submodule setup failed in CI environment. Check repository access/credentials configuration.', 'error');
|
||||
} else {
|
||||
log('Submodule setup failed. Ensure you have SSH access to the repository.', 'error');
|
||||
}
|
||||
@@ -169,7 +175,7 @@ function setupMobileSDKNative() {
|
||||
}
|
||||
|
||||
// Security: Remove credential-embedded remote URL after setup
|
||||
if (isCI && repoToken && !isDryRun) {
|
||||
if (isCI && (appToken || repoToken) && !isDryRun) {
|
||||
scrubGitRemoteUrl();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,12 +46,15 @@ target "SelfDemoApp" do
|
||||
nfc_repo_url = if !is_selfxyz_repo
|
||||
puts "📦 Using public NFCPassportReader for external fork (#{ENV["GITHUB_REPOSITORY"]})"
|
||||
"https://github.com/PLACEHOLDER/NFCPassportReader.git"
|
||||
elsif ENV["GITHUB_ACTIONS"] == "true" && ENV["SELFXYZ_INTERNAL_REPO_PAT"] && !ENV["SELFXYZ_INTERNAL_REPO_PAT"].empty?
|
||||
puts "📦 Using private NFCPassportReader with PAT (selfxyz GitHub Actions)"
|
||||
"https://#{ENV["SELFXYZ_INTERNAL_REPO_PAT"]}@github.com/selfxyz/NFCPassportReader.git"
|
||||
elsif ENV["GITHUB_ACTIONS"] == "true"
|
||||
# CI: NEVER embed credentials in URLs. Rely on workflow-provided auth via:
|
||||
# - ~/.netrc or a Git credential helper, and token masking in logs.
|
||||
"https://github.com/selfxyz/NFCPassportReader.git"
|
||||
elsif using_https_git_auth?
|
||||
# Local development with HTTPS GitHub auth via gh - use HTTPS to private repo
|
||||
"https://github.com/selfxyz/NFCPassportReader.git"
|
||||
else
|
||||
# Local development in selfxyz repo - use SSH to private repo
|
||||
puts "📦 Using SSH for private NFCPassportReader (local selfxyz development)"
|
||||
"git@github.com:selfxyz/NFCPassportReader.git"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user