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
70 changes: 70 additions & 0 deletions .github/actions/artifactory-oidc/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: "Artifactory OIDC Auth"
description: "Exchange GitHub OIDC token for Artifactory access token and configure Composer"

inputs:
artifactory-url:
description: "JFrog platform base URL. Falls back to ARTIFACTORY_URL env var."
required: false
default: ""
oidc-provider-name:
description: "OIDC provider name configured in Artifactory"
required: false
default: "github-actions-segmentio"
php-repo:
description: "Artifactory virtual PHP repository name"
required: false
default: "virtual-php-thirdparty"

runs:
using: "composite"
steps:
- name: Exchange GitHub OIDC token for Artifactory token
shell: bash
env:
INPUT_ARTIFACTORY_URL: ${{ inputs.artifactory-url }}
OIDC_PROVIDER_NAME: ${{ inputs.oidc-provider-name }}
PHP_REPO: ${{ inputs.php-repo }}
run: |
set -euo pipefail
ARTIFACTORY_URL="${INPUT_ARTIFACTORY_URL:-${ARTIFACTORY_URL:-}}"
if [ -z "${ARTIFACTORY_URL}" ]; then
echo "::error::ARTIFACTORY_URL is not set (pass as input or set as env var)"; exit 1
fi

OIDC_JWT=$(curl -sS \
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${ARTIFACTORY_URL}" \
-H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" | jq -r '.value')

if [ -z "$OIDC_JWT" ] || [ "$OIDC_JWT" = "null" ]; then
echo "::error::Failed to obtain GitHub OIDC token"; exit 1
fi

decode_seg() { local s="${1}"; local m=$(( ${#s} % 4 )); [ $m -ne 0 ] && s="${s}$(printf '=%.0s' $(seq 1 $((4-m))))"; echo "$s" | tr '_-' '/+' | base64 -d 2>/dev/null; }
PAYLOAD=$(decode_seg "$(echo "$OIDC_JWT" | cut -d. -f2)")
echo "OIDC token claims:"
echo " sub = $(echo "$PAYLOAD" | jq -r '.sub')"
echo " aud = $(echo "$PAYLOAD" | jq -r '.aud')"
echo " iss = $(echo "$PAYLOAD" | jq -r '.iss')"

RESP=$(curl -sS "${ARTIFACTORY_URL}/access/api/v1/oidc/token" \
-H 'Content-Type: application/json' \
-d "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:token-exchange\",
\"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\",
\"subject_token\":\"${OIDC_JWT}\",
\"provider_name\":\"${OIDC_PROVIDER_NAME}\"}")

ART_TOKEN=$(echo "$RESP" | jq -r '.access_token // empty')

if [ -z "$ART_TOKEN" ]; then
echo "::error::OIDC token exchange failed."
echo "$RESP" | jq 'if .access_token then .access_token="<redacted>" else . end' 2>/dev/null || echo "$RESP"
exit 1
fi
echo "::add-mask::$ART_TOKEN"

HOST=$(echo "${ARTIFACTORY_URL}" | sed -E 's#^https?://##')

composer config --global repositories.packagist composer \
"https://:${ART_TOKEN}@${HOST}/artifactory/api/composer/${PHP_REPO}"
composer config --global repositories.packagist.org false
echo "Configured Composer to resolve through Artifactory (${PHP_REPO})"
158 changes: 158 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
name: CI

on:
push:
branches: [master, main]
pull_request:
workflow_dispatch:

permissions:
id-token: write
contents: read

env:
ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }}

jobs:
coding-standard:
name: Coding Standards
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }}

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up PHP
uses: shivammathur/setup-php@cf4cade2721270509d5b1c766dad417c269cbb11 # v2
with:
php-version: "8.2"
coverage: none
tools: cs2pr

- name: Configure Artifactory
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: ./.github/actions/artifactory-oidc
with:
artifactory_url: ${{ vars.ARTIFACTORY_URL }}

- name: Install Composer dependencies
run: composer install --no-scripts --no-interaction --prefer-dist

- name: Check coding standards
continue-on-error: true
run: ./vendor/bin/phpcs -s --report-full --report-checkstyle=./phpcs-report.xml

- name: Show PHPCS results in PR
run: cs2pr ./phpcs-report.xml

lint:
name: "Lint: PHP ${{ matrix.php }}"
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }}
strategy:
fail-fast: false
matrix:
php: ["8.1", "8.2", "8.3", "8.4"]

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up PHP
uses: shivammathur/setup-php@cf4cade2721270509d5b1c766dad417c269cbb11 # v2
with:
php-version: ${{ matrix.php }}
coverage: none
tools: cs2pr

- name: Configure Artifactory
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: ./.github/actions/artifactory-oidc
with:
artifactory_url: ${{ vars.ARTIFACTORY_URL }}

- name: Install Composer dependencies
run: composer install --no-scripts --no-interaction --prefer-dist

- name: Lint against parse errors
run: composer lint

test:
name: "Test: PHP ${{ matrix.php }}"
needs: [coding-standard, lint]
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }}
strategy:
fail-fast: false
matrix:
php: ["8.1", "8.2", "8.3", "8.4"]

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up PHP
uses: shivammathur/setup-php@cf4cade2721270509d5b1c766dad417c269cbb11 # v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
ini-values: error_reporting=E_ALL, display_errors=On
extensions: curl, json, mbstring

- name: Configure Artifactory
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: ./.github/actions/artifactory-oidc
with:
artifactory_url: ${{ vars.ARTIFACTORY_URL }}

- name: Install Composer dependencies
run: composer install --no-scripts --no-interaction --prefer-dist

- name: Run tests
run: ./vendor/bin/phpunit --no-coverage

- name: Run tests with coverage
if: ${{ matrix.php == '8.2' }}
run: ./vendor/bin/phpunit

- name: Upload coverage to Codecov
if: ${{ success() && matrix.php == '8.2' }}
uses: codecov/codecov-action@e851fdd58d965fa1d6a5b0db7cb65a4d42b992fc # v5
with:
files: ./build/logs/clover.xml
fail_ci_if_error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

build-verification:
name: Build Verification
needs: [test]
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || 'ubuntu-x64' }}

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up PHP
uses: shivammathur/setup-php@cf4cade2721270509d5b1c766dad417c269cbb11 # v2
with:
php-version: "8.2"
coverage: none

- name: Configure Artifactory
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: ./.github/actions/artifactory-oidc
with:
artifactory_url: ${{ vars.ARTIFACTORY_URL }}

- name: Install Composer dependencies (production)
run: composer install --no-scripts --no-interaction --prefer-dist --no-dev --optimize-autoloader

- name: Verify autoload
run: php -r "require 'vendor/autoload.php'; echo 'Autoload OK' . PHP_EOL;"

- name: Verify package structure
run: |
# Ensure required files exist for Packagist
test -f composer.json
test -f LICENSE.md
test -d lib
echo "Package structure verified"
40 changes: 28 additions & 12 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,61 @@ name: E2E Tests

on:
push:
branches: [master]
branches: [master, main]
pull_request:
branches: [master]
branches: [master, main]
workflow_dispatch:
inputs:
e2e_tests_ref:
description: 'Branch or ref of sdk-e2e-tests to use'
description: "Branch or ref of sdk-e2e-tests to use"
required: false
default: 'main'
default: "main"

permissions:
id-token: write
contents: read

env:
ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }}

jobs:
e2e-tests:
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
# Skip for forks — E2E tests require internal infrastructure
if: ${{ !github.event.pull_request.head.repo.fork }}
runs-on: ubuntu-x64

steps:
- name: Checkout SDK
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
path: sdk

- name: Checkout sdk-e2e-tests
uses: actions/checkout@v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
repository: segmentio/sdk-e2e-tests
ref: ${{ inputs.e2e_tests_ref || 'main' }}
token: ${{ secrets.E2E_TESTS_TOKEN }}
path: sdk-e2e-tests

- name: Setup PHP
uses: shivammathur/setup-php@v2
uses: shivammathur/setup-php@cf4cade2721270509d5b1c766dad417c269cbb11 # v2
with:
php-version: '8.2'
php-version: "8.2"
extensions: curl, json

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: "20"

- name: Configure Artifactory
uses: ./sdk/.github/actions/artifactory-oidc
with:
artifactory_url: ${{ vars.ARTIFACTORY_URL }}

- name: Install SDK dependencies
working-directory: sdk
run: composer install --no-scripts --no-interaction --prefer-dist

- name: Run E2E tests
working-directory: sdk-e2e-tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ jobs:

- name: Send coverage report to Codecov
if: ${{ success() && matrix.coverage }}
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@e851fdd58d965fa1d6a5b0db7cb65a4d42b992fc # v5
with:
files: ./build/logs/clover.xml
fail_ci_if_error: true
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
composer.lock
vendor
composer.phar
test/analytics.log
Expand Down
Loading