|
| 1 | +name: 'LATdx Apex Tests' |
| 2 | +description: >- |
| 3 | + Install the LATdx CLI, resolve a license (explicit key via the |
| 4 | + LATDX_LICENSE_KEY env var, or a short-lived OSS license minted from the |
| 5 | + GitHub Actions OIDC token on public repos), and run the full local Apex |
| 6 | + test suite against the job's default Salesforce org. |
| 7 | +
|
| 8 | +inputs: |
| 9 | + cli-version: |
| 10 | + description: "LATdx CLI version to install (semver like '0.31.1') or 'latest'." |
| 11 | + required: false |
| 12 | + default: 'latest' |
| 13 | + |
| 14 | +runs: |
| 15 | + using: composite |
| 16 | + steps: |
| 17 | + # LATdx's cache Phase 4 runs an apex-ls bridge on the JVM. Hosted images |
| 18 | + # vary (ubuntu-latest ships a recent Temurin, ubuntu-22.04 a default JDK |
| 19 | + # too old for the bridge jar -> "JVM exited (code=1)"), so pin a known-good |
| 20 | + # JDK on PATH rather than relying on the image default. |
| 21 | + - name: 'Set up Java for LATdx apex-ls' |
| 22 | + uses: actions/setup-java@v4 |
| 23 | + with: |
| 24 | + distribution: temurin |
| 25 | + java-version: '17' |
| 26 | + |
| 27 | + - name: 'Install LATdx CLI' |
| 28 | + shell: bash |
| 29 | + env: |
| 30 | + CLI_VERSION: ${{ inputs.cli-version }} |
| 31 | + run: | |
| 32 | + set -euo pipefail |
| 33 | + if [[ ! "$CLI_VERSION" =~ ^(latest|[0-9]+\.[0-9]+\.[0-9]+)$ ]]; then |
| 34 | + echo "::error::Invalid 'cli-version' input. Must be 'latest' or a semver like '0.31.1'." |
| 35 | + exit 1 |
| 36 | + fi |
| 37 | + # latdx.com serves the maintained install script, but Cloudflare |
| 38 | + # returns 403 to some hosted-runner egress IP ranges; fall back to |
| 39 | + # the GitHub raw mirror so the install succeeds from any runner. |
| 40 | + script="" |
| 41 | + for url in "https://latdx.com/install.sh" "https://raw.githubusercontent.com/nebulity/latdx-cli/main/install.sh"; do |
| 42 | + if script="$(curl -fsSL "$url")"; then |
| 43 | + break |
| 44 | + fi |
| 45 | + script="" |
| 46 | + done |
| 47 | + if [ -z "$script" ]; then |
| 48 | + echo "::error::Could not download the LATdx install script from any source." |
| 49 | + exit 1 |
| 50 | + fi |
| 51 | + if [ "$CLI_VERSION" = "latest" ]; then |
| 52 | + printf '%s' "$script" | bash |
| 53 | + else |
| 54 | + printf '%s' "$script" | bash -s -- "$CLI_VERSION" |
| 55 | + fi |
| 56 | + echo "$HOME/.local/bin" >> "$GITHUB_PATH" |
| 57 | +
|
| 58 | + - name: 'Verify LATdx CLI' |
| 59 | + shell: bash |
| 60 | + run: latdx --version |
| 61 | + |
| 62 | + - name: 'Resolve LATdx license' |
| 63 | + shell: bash |
| 64 | + run: | |
| 65 | + # The runner injects -e -o pipefail; this step must never fail the |
| 66 | + # job: every problem degrades to the free-tier cap with a warning. |
| 67 | + set +e +o pipefail |
| 68 | +
|
| 69 | + # Precedence: |
| 70 | + # 1. LATDX_LICENSE_KEY already in the environment (repo secret) -> use it. |
| 71 | + # 2. GH OIDC token available + repo public -> exchange for an OSS |
| 72 | + # auto-license via https://latdx.com/api/oss/license. |
| 73 | + # 3. Nothing -> daemon runs free-tier (capped at 100 tests, exit 2). |
| 74 | +
|
| 75 | + if [ -n "${LATDX_LICENSE_KEY:-}" ]; then |
| 76 | + echo "Using LATdx license from environment." |
| 77 | + exit 0 |
| 78 | + fi |
| 79 | +
|
| 80 | + if [ -z "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ] || [ -z "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]; then |
| 81 | + echo "::warning title=LATdx OSS license::OIDC token unavailable (missing 'permissions: id-token: write' on the job). Free-tier cap (100 tests/run) applies." |
| 82 | + exit 0 |
| 83 | + fi |
| 84 | +
|
| 85 | + OIDC_RESPONSE="$(curl -sS -f -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ |
| 86 | + "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=https%3A%2F%2Flatdx.com" 2>/dev/null)" |
| 87 | + CURL_RC=$? |
| 88 | + if [ "$CURL_RC" -ne 0 ]; then |
| 89 | + echo "::warning title=LATdx OSS license::OIDC token mint failed (curl rc=${CURL_RC}); falling back to free-tier cap." |
| 90 | + exit 0 |
| 91 | + fi |
| 92 | + OIDC_TOKEN="$(printf '%s' "$OIDC_RESPONSE" | jq -r '.value // empty' 2>/dev/null)" |
| 93 | + if [ -z "$OIDC_TOKEN" ]; then |
| 94 | + echo "::warning title=LATdx OSS license::OIDC response not parseable (length ${#OIDC_RESPONSE}); falling back to free-tier cap." |
| 95 | + exit 0 |
| 96 | + fi |
| 97 | + echo "Minted GitHub OIDC token (length ${#OIDC_TOKEN})." |
| 98 | +
|
| 99 | + EXCHANGE_BODY="$(mktemp)" |
| 100 | + EXCHANGE_HEADERS="$(mktemp)" |
| 101 | + trap 'rm -f "$EXCHANGE_BODY" "$EXCHANGE_HEADERS"' EXIT |
| 102 | +
|
| 103 | + # Try the branded origin first (it self-heals once its edge allows |
| 104 | + # GitHub Actions egress), then the Worker's *.workers.dev origin, |
| 105 | + # which is not behind the latdx.com zone's WAF/security rules that |
| 106 | + # currently 403 hosted-runner IPs. The OSS route authenticates on the |
| 107 | + # OIDC token's audience claim, not the request Host, so the same token |
| 108 | + # validates on either origin; the route's own OIDC + monthly-cap + |
| 109 | + # kill-switch protections apply regardless of which origin serves it. |
| 110 | + LATDX_JWT="" |
| 111 | + for OSS_URL in \ |
| 112 | + "https://latdx.com/api/oss/license" \ |
| 113 | + "https://latdx-site.asolokh.workers.dev/api/oss/license"; do |
| 114 | + HTTP_CODE="$(curl -sS -o "$EXCHANGE_BODY" -D "$EXCHANGE_HEADERS" -w "%{http_code}" \ |
| 115 | + -X POST "$OSS_URL" \ |
| 116 | + -H "Authorization: Bearer $OIDC_TOKEN" \ |
| 117 | + -H "Content-Type: application/json" \ |
| 118 | + --max-time 15)" |
| 119 | + [ $? -ne 0 ] && HTTP_CODE="000" |
| 120 | + echo "OSS license exchange via ${OSS_URL} -> HTTP ${HTTP_CODE}." |
| 121 | +
|
| 122 | + if [ "$HTTP_CODE" = "200" ]; then |
| 123 | + LATDX_JWT="$(jq -r '.license // empty' < "$EXCHANGE_BODY" 2>/dev/null)" |
| 124 | + if [ -n "$LATDX_JWT" ]; then |
| 125 | + echo "::add-mask::$LATDX_JWT" |
| 126 | + echo "LATDX_LICENSE_KEY=$LATDX_JWT" >> "$GITHUB_ENV" |
| 127 | + USED="$(jq -r '.monthly_used // "?"' < "$EXCHANGE_BODY" 2>/dev/null)" |
| 128 | + CAP="$(jq -r '.monthly_cap // "?"' < "$EXCHANGE_BODY" 2>/dev/null)" |
| 129 | + echo "OSS auto-license active (monthly_used=$USED, monthly_cap=$CAP); full suite enabled." |
| 130 | + break |
| 131 | + fi |
| 132 | + echo "::warning title=LATdx OSS license::200 without a license from ${OSS_URL}; trying next origin." |
| 133 | + elif [ "$HTTP_CODE" = "429" ]; then |
| 134 | + USED="$(jq -r '.monthly_used // "?"' < "$EXCHANGE_BODY" 2>/dev/null)" |
| 135 | + CAP="$(jq -r '.monthly_cap // "?"' < "$EXCHANGE_BODY" 2>/dev/null)" |
| 136 | + RESET="$(jq -r '.reset_at // "next UTC month"' < "$EXCHANGE_BODY" 2>/dev/null)" |
| 137 | + echo "::warning title=LATdx OSS license::Monthly cap reached (${USED}/${CAP}); resets ${RESET}." |
| 138 | + break |
| 139 | + else |
| 140 | + # 403/503/000/etc: log edge diagnostics (no secrets) and fall |
| 141 | + # through to the next origin. |
| 142 | + echo "--- server: $(grep -i '^server:' "$EXCHANGE_HEADERS" | tr -d '\r')" |
| 143 | + echo "--- cf-ray: $(grep -i '^cf-ray:' "$EXCHANGE_HEADERS" | tr -d '\r')" |
| 144 | + echo "--- body (first 200 chars): $(head -c 200 "$EXCHANGE_BODY" | tr '\n' ' ')" |
| 145 | + fi |
| 146 | + done |
| 147 | +
|
| 148 | + if [ -z "$LATDX_JWT" ]; then |
| 149 | + echo "::warning title=LATdx OSS license::No OSS license obtained from any origin; the run will halt on the CI license gate." |
| 150 | + fi |
| 151 | +
|
| 152 | + - name: 'Run Apex tests with LATdx' |
| 153 | + shell: bash |
| 154 | + run: | |
| 155 | + set +e |
| 156 | + latdx test run |
| 157 | + rc=$? |
| 158 | + set -e |
| 159 | + # Exit 2 is EXIT_LICENSE_REQUIRED: the CI license gate halted the run. |
| 160 | + # With no resolved license the gate blocks before any test executes |
| 161 | + # (it does not fall back to a 100-test free tier); a resolved free/pro |
| 162 | + # license would instead cap at 100. Either way no full suite ran. Keep |
| 163 | + # the pipeline green but say so honestly: lift it with the OSS |
| 164 | + # auto-license (OIDC, public repos) or LATDX_LICENSE_KEY. |
| 165 | + if [ "$rc" -eq 2 ]; then |
| 166 | + echo "::warning title=LATdx license::Run halted by the CI license gate (exit 2); no full suite ran. Provide an OSS auto-license or LATDX_LICENSE_KEY to run NebulaLogger's tests." |
| 167 | + exit 0 |
| 168 | + fi |
| 169 | + exit "$rc" |
0 commit comments