Skip to content
Open
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: 1 addition & 1 deletion .github/workflows/browserstack-e2e-android-journey.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ jobs:
e2e-android-journey-davinci:
name: E2E — Android BrowserStack (journey & davinci)
runs-on: ubuntu-latest
timeout-minutes: 55
timeout-minutes: 60
defaults:
run:
working-directory: PingTestRunner
Expand Down
40 changes: 38 additions & 2 deletions .github/workflows/browserstack-e2e-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ on:
PING_CALLBACK_TREES_ENABLED:
description: Flag enabling callback tree coverage in BrowserStack E2E tests
required: false
PINGONE_DISCOVERY_ENDPOINT:
description: PingOne DaVinci OIDC discovery endpoint
required: false
PINGONE_CLIENT_ID:
description: PingOne DaVinci OIDC client identifier
required: false
PINGONE_REDIRECT_URI:
description: PingOne DaVinci OIDC redirect URI
required: false
PINGONE_ACR_VALUES:
description: ACR values to route to the correct DaVinci flow
required: false
PINGONE_USERNAME:
description: PingOne DaVinci test account username
required: false
PINGONE_PASSWORD:
description: PingOne DaVinci test account password
required: false
CERTIFICATES_FILE_BASE64:
description: Apple signing certificate exported as base64 encoded .p12
required: true
Expand Down Expand Up @@ -80,7 +98,7 @@ jobs:
name: E2E — iOS BrowserStack
runs-on: ubuntu-latest
needs: prepare-ios-artifacts
timeout-minutes: 60
timeout-minutes: 70
outputs:
build_id: ${{ steps.start-build.outputs.build_id }}

Expand All @@ -98,6 +116,12 @@ jobs:
PING_CLIENT_ID: ${{ secrets.PING_CLIENT_ID }}
PING_REDIRECT_URI: ${{ secrets.PING_REDIRECT_URI }}
PING_CALLBACK_TREES_ENABLED: ${{ secrets.PING_CALLBACK_TREES_ENABLED }}
PINGONE_DISCOVERY_ENDPOINT: ${{ secrets.PINGONE_DISCOVERY_ENDPOINT }}
PINGONE_CLIENT_ID: ${{ secrets.PINGONE_CLIENT_ID }}
PINGONE_REDIRECT_URI: ${{ secrets.PINGONE_REDIRECT_URI }}
PINGONE_ACR_VALUES: ${{ secrets.PINGONE_ACR_VALUES }}
PINGONE_USERNAME: ${{ secrets.PINGONE_USERNAME }}
PINGONE_PASSWORD: ${{ secrets.PINGONE_PASSWORD }}

steps:
- name: Download IPA artifact
Expand Down Expand Up @@ -195,6 +219,12 @@ jobs:
--arg pingClientId "$PING_CLIENT_ID" \
--arg pingRedirectUri "$PING_REDIRECT_URI" \
--arg pingCallbackTreesEnabled "$PING_CALLBACK_TREES_ENABLED" \
--arg pingoneDiscoveryEndpoint "$PINGONE_DISCOVERY_ENDPOINT" \
--arg pingoneClientId "$PINGONE_CLIENT_ID" \
--arg pingoneRedirectUri "$PINGONE_REDIRECT_URI" \
--arg pingoneAcrValues "$PINGONE_ACR_VALUES" \
--arg pingoneUsername "$PINGONE_USERNAME" \
--arg pingonePassword "$PINGONE_PASSWORD" \
'{
app: $app,
testSuite: $testSuite,
Expand All @@ -215,7 +245,13 @@ jobs:
PING_DISCOVERY_ENDPOINT: $pingDiscoveryEndpoint,
PING_CLIENT_ID: $pingClientId,
PING_REDIRECT_URI: $pingRedirectUri,
PING_CALLBACK_TREES_ENABLED: $pingCallbackTreesEnabled
PING_CALLBACK_TREES_ENABLED: $pingCallbackTreesEnabled,
PINGONE_DISCOVERY_ENDPOINT: $pingoneDiscoveryEndpoint,
PINGONE_CLIENT_ID: $pingoneClientId,
PINGONE_REDIRECT_URI: $pingoneRedirectUri,
PINGONE_ACR_VALUES: $pingoneAcrValues,
PINGONE_USERNAME: $pingoneUsername,
PINGONE_PASSWORD: $pingonePassword
}
}'
)"
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ jobs:
PING_CLIENT_ID: ${{ secrets.PING_CLIENT_ID }}
PING_REDIRECT_URI: ${{ secrets.PING_REDIRECT_URI }}
PING_CALLBACK_TREES_ENABLED: ${{ secrets.PING_CALLBACK_TREES_ENABLED }}
PINGONE_DISCOVERY_ENDPOINT: ${{ secrets.PINGONE_DISCOVERY_ENDPOINT }}
PINGONE_CLIENT_ID: ${{ secrets.PINGONE_CLIENT_ID }}
PINGONE_REDIRECT_URI: ${{ secrets.PINGONE_REDIRECT_URI }}
PINGONE_ACR_VALUES: ${{ secrets.PINGONE_ACR_VALUES }}
PINGONE_USERNAME: ${{ secrets.PINGONE_USERNAME }}
PINGONE_PASSWORD: ${{ secrets.PINGONE_PASSWORD }}
CERTIFICATES_FILE_BASE64: ${{ secrets.CERTIFICATES_FILE_BASE64 }}
CERTIFICATES_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
Expand All @@ -202,3 +208,35 @@ jobs:
uses: ./.github/workflows/preview-docs.yml
with:
pr_number: ${{ github.event.pull_request.number }}

# Mend security scans replace the retired Mend GitHub App integration.
# All three jobs are skipped for fork PRs: repository secrets (MEND_EMAIL,
# MEND_USER_KEY) are never exposed to workflows from forks, so the scans would
# either fail or run unauthenticated - same guard the reference ping-android-sdk
# ci.yaml applies to its Mend jobs. Scan credentials are passed explicitly,
# never via secrets: inherit, so the exposure surface stays visible here.
mend-prepare-workspace:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/workflows/mend-prepare-workspace.yml

mend-sca-scan:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
needs: mend-prepare-workspace
permissions:
contents: read
checks: write
uses: ./.github/workflows/mend-sca-scan.yml
secrets:
MEND_EMAIL: ${{ secrets.MEND_EMAIL }}
MEND_USER_KEY: ${{ secrets.MEND_USER_KEY }}

mend-sast-scan:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
needs: mend-prepare-workspace
permissions:
contents: read
checks: write
uses: ./.github/workflows/mend-sast-scan.yml
secrets:
MEND_EMAIL: ${{ secrets.MEND_EMAIL }}
MEND_USER_KEY: ${{ secrets.MEND_USER_KEY }}
89 changes: 89 additions & 0 deletions .github/workflows/mend-prepare-workspace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#
# Copyright (c) 2026 Ping Identity Corporation. All rights reserved.
#
# This software may be modified and distributed under the terms
# of the MIT license. See the LICENSE file for details.
#
name: Mend Pruned Workspace

# Builds the pruned workspace scanned by mend-sca-scan.yml and publishes it as
# the mend-scan-workspace artifact.
#
# SCA scans a pruned workspace containing only packages/* (the published SDKs), NOT the
# full monorepo. The sample app and test runner are build/test tooling: their runtime
# dependency tree (react-native, metro, and everything transitively reachable from them,
# e.g. image-size) does not ship to consumers, so it is out of scope for the SDK's
# dependency inventory. The pruned workspace is generated from the real yarn.lock so
# resolved versions stay identical to what CI tests.
on:
workflow_call:

permissions:
contents: read

jobs:
prepare-workspace:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Set SCAN_DIR
run: echo "SCAN_DIR=${RUNNER_TEMP}/mend-scan" >> "$GITHUB_ENV"

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version-file: package.json

# Build the pruned workspace: packages/* only, with a generated root manifest that
# preserves packageManager, engines, and resolutions from the real root. The real
# yarn.lock is copied over and pruned by the install below, keeping the exact
# resolved versions CI tests against — no version drift between the two graphs.
# The yarn release binary is symlinked onto PATH because the Mend CLI shells out
# to `yarn` to enumerate the dependency graph: hosted runners preinstall yarn 1.x,
# which ignores .yarnrc.yml's yarnPath and does not support the install flags used
# here; containers used for local workflow runs (act) may have no yarn at all.
- name: Prepare pruned workspace
run: |
mkdir -p "${SCAN_DIR}/.yarn/releases"
cp -R packages "${SCAN_DIR}/packages"
cp .yarnrc.yml "${SCAN_DIR}/.yarnrc.yml"
cp .yarn/releases/*.cjs "${SCAN_DIR}/.yarn/releases/"
cp yarn.lock "${SCAN_DIR}/yarn.lock"
chmod +x "${SCAN_DIR}/.yarn/releases/"*.cjs
ln -sf "${SCAN_DIR}/.yarn/releases/yarn-4.11.0.cjs" /usr/local/bin/yarn
node -e '
const fs = require("fs");
const root = JSON.parse(fs.readFileSync("package.json", "utf8"));
const scan = {
name: "ping-sdk-mend-scan",
private: true,
packageManager: root.packageManager,
engines: root.engines,
resolutions: root.resolutions,
workspaces: { packages: ["packages/*"] },
};
fs.writeFileSync(process.env.SCAN_DIR + "/package.json", JSON.stringify(scan, null, 2) + "\n");
'

# --mode=update-lockfile resolves the pruned workspace and garbage-collects the
# lockfile entries no longer referenced (the entire app/test-runner tree) without
# fetching or linking packages.
- name: Resolve pruned lockfile
run: |
cd "${SCAN_DIR}"
yarn install --mode=update-lockfile

# upload-artifact v4 zips the tree without preserving symlinks, so the consumer
# (mend-sca-scan.yml) recreates the yarn shim from the bundled release binary.
- name: Upload pruned workspace
uses: actions/upload-artifact@v4
with:
name: mend-scan-workspace
path: ${{ env.SCAN_DIR }}
retention-days: 1
Loading
Loading