From b18defdf5a1fda6b2c2dca14f97fd7bf752409b2 Mon Sep 17 00:00:00 2001 From: emranemran Date: Wed, 4 Nov 2026 16:11:19 -0800 Subject: [PATCH 1/6] ci: prepare fleet checks behind deployment freeze --- .github/FLEET-CI.md | 32 ++++++++++++++ .github/fleet-ci.json | 17 ++++++++ .github/workflows/fleet-ci-notify.yml | 61 +++++++++++++++++++++++++++ .github/workflows/tests.yml | 36 ++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 .github/FLEET-CI.md create mode 100644 .github/fleet-ci.json create mode 100644 .github/workflows/fleet-ci-notify.yml diff --git a/.github/FLEET-CI.md b/.github/FLEET-CI.md new file mode 100644 index 0000000..34535d1 --- /dev/null +++ b/.github/FLEET-CI.md @@ -0,0 +1,32 @@ +# Fleet CI and deployment freeze + +CI tests source changes. The fleet builder in `livepeer/simple-infra` builds and publishes deployment images. +This PR does not authorize a staging or production deployment. + +## Source contract + +The receiver is `agent-fleet-build.yaml` on `livepeer/simple-infra` main. +Inputs are `source_repository`, `source_sha` (full commit SHA), and `ci_run_id`. +`.github/fleet-ci.json` identifies this repository's trusted source workflow. +The receiver must independently check that the run succeeded for this repository, workflow, SHA, main branch, and push event. +Use the exact SHA from the run. A newer main commit does not invalidate an older successful run. + +## Freeze + +`FLEET_CI_NOTIFY_ENABLED` is false in this repository. +Missing or false disables notification before the GitHub App receives a token. +`FLEET_DEPLOYMENTS_ENABLED` is false in simple-infra. The new CD workflows must enforce it. +The new flag does not disable existing manual workflows. Any Grafana staging work remains separately authorized. +Keep this PR in draft. Do not merge it or enable notifications during the freeze. + +## Activation after the freeze + +1. Merge the reviewed CI PR after its required checks pass. +2. Check that post-merge CI reports success for that exact commit. +3. Confirm Pulumi's receiver validates the source contract and refuses deployment while its gate is false. +4. Configure `FLEET_CI_APP_ID` and `FLEET_CI_APP_PRIVATE_KEY`. The App needs Actions write on simple-infra. +5. Enable source notifications only after Emran authorizes activation. Production remains manual in the CD workflow. + + +For other repositories, retain their existing required checks until the new check is observed on a PR. +Do not enable auto-merge or change release tag rules as part of this freeze preparation. diff --git a/.github/fleet-ci.json b/.github/fleet-ci.json new file mode 100644 index 0000000..c224fbd --- /dev/null +++ b/.github/fleet-ci.json @@ -0,0 +1,17 @@ +{ + "schema_version": 1, + "repository": "livepeer/livepeer-python-gateway", + "source_workflow": ".github/workflows/tests.yml", + "source_workflow_name": "Tests", + "source_event": "push", + "source_branch": "main", + "receiver_repository": "livepeer/simple-infra", + "receiver_workflow": "agent-fleet-build.yaml", + "receiver_ref": "main", + "notification_gate": "FLEET_CI_NOTIFY_ENABLED", + "affected_components": [ + "sdk-service", + "fal-app", + "tool-app" + ] +} diff --git a/.github/workflows/fleet-ci-notify.yml b/.github/workflows/fleet-ci-notify.yml new file mode 100644 index 0000000..c078daa --- /dev/null +++ b/.github/workflows/fleet-ci-notify.yml @@ -0,0 +1,61 @@ +name: Notify fleet builder + +# Disabled during the deployment freeze. This workflow dispatches builds only. +# It never checks out the source run and never obtains GCP credentials. +on: + workflow_run: + workflows: ["Tests"] + types: [completed] + branches: [main] + +permissions: + contents: read + actions: read + +jobs: + notify: + if: >- + vars.FLEET_CI_NOTIFY_ENABLED == 'true' && + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + github.event.workflow_run.head_branch == 'main' && + github.event.workflow_run.head_repository.full_name == github.repository + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - name: Check the source run before creating a builder token + env: + GH_TOKEN: ${{ github.token }} + SOURCE_REPOSITORY: ${{ github.repository }} + SOURCE_SHA: ${{ github.event.workflow_run.head_sha }} + CI_RUN_ID: ${{ github.event.workflow_run.id }} + run: | + [[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]] + [[ "$CI_RUN_ID" =~ ^[0-9]+$ ]] + gh api "repos/$SOURCE_REPOSITORY/actions/runs/$CI_RUN_ID" > "$RUNNER_TEMP/source-run.json" + jq -e --arg repo "$SOURCE_REPOSITORY" --arg sha "$SOURCE_SHA" ' + .repository.full_name == $repo and .head_repository.full_name == $repo and + .head_sha == $sha and .head_branch == "main" and .event == "push" and + .path == ".github/workflows/tests.yml" and + .status == "completed" and .conclusion == "success" + ' "$RUNNER_TEMP/source-run.json" + - name: Create a token for the builder repository only + id: app + uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3 + with: + app-id: ${{ vars.FLEET_CI_APP_ID }} + private-key: ${{ secrets.FLEET_CI_APP_PRIVATE_KEY }} + owner: livepeer + repositories: simple-infra + permission-actions: write + - name: Notify the central builder with the tested source revision + env: + GH_TOKEN: ${{ steps.app.outputs.token }} + SOURCE_REPOSITORY: ${{ github.repository }} + SOURCE_SHA: ${{ github.event.workflow_run.head_sha }} + CI_RUN_ID: ${{ github.event.workflow_run.id }} + run: | + gh workflow run agent-fleet-build.yaml --repo livepeer/simple-infra --ref main \ + --field source_repository="$SOURCE_REPOSITORY" \ + --field source_sha="$SOURCE_SHA" \ + --field ci_run_id="$CI_RUN_ID" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9e84691..1581c56 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,12 +5,19 @@ on: push: branches: - main + merge_group: + workflow_call: permissions: contents: read +concurrency: + group: gateway-tests-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: ruff: + timeout-minutes: 10 runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -25,6 +32,7 @@ jobs: run: uv run --frozen --group lint ruff check . pytest: + timeout-minutes: 20 runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -37,3 +45,31 @@ jobs: run: uv sync --locked --group test - name: Run pytest with coverage run: uv run --frozen --group test pytest --cov=livepeer_gateway --cov-branch --cov-report=term-missing + + package: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + python-version: '3.12' + - name: Build the wheel and source distribution without publishing + run: uv build --no-sources + + ci-gate: + name: ci-gate + if: always() + needs: [ruff, pytest, package] + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Require every CI job to succeed + env: + RUFF_RESULT: ${{ needs.ruff.result }} + PYTEST_RESULT: ${{ needs.pytest.result }} + PACKAGE_RESULT: ${{ needs.package.result }} + run: | + test "$RUFF_RESULT" = success + test "$PYTEST_RESULT" = success + test "$PACKAGE_RESULT" = success From ed835cdc7f1c1d5cd9b9f191049aba5e6cd64fdc Mon Sep 17 00:00:00 2001 From: emranemran Date: Wed, 4 Nov 2026 17:08:28 -0800 Subject: [PATCH 2/6] ci: preserve validation for every merged commit --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1581c56..9fa9257 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ permissions: contents: read concurrency: - group: gateway-tests-${{ github.ref }} + group: gateway-tests-${{ github.event_name == 'push' && github.run_id || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: From 76d9fb97526979fe3e8ca86eb59d7ed0b2deb98d Mon Sep 17 00:00:00 2001 From: emranemran Date: Thu, 5 Nov 2026 10:30:41 -0800 Subject: [PATCH 3/6] Keep shared repository CI consumer-neutral --- .github/FLEET-CI.md | 32 -------------- .github/fleet-ci.json | 17 -------- .github/workflows/fleet-ci-notify.yml | 61 --------------------------- 3 files changed, 110 deletions(-) delete mode 100644 .github/FLEET-CI.md delete mode 100644 .github/fleet-ci.json delete mode 100644 .github/workflows/fleet-ci-notify.yml diff --git a/.github/FLEET-CI.md b/.github/FLEET-CI.md deleted file mode 100644 index 34535d1..0000000 --- a/.github/FLEET-CI.md +++ /dev/null @@ -1,32 +0,0 @@ -# Fleet CI and deployment freeze - -CI tests source changes. The fleet builder in `livepeer/simple-infra` builds and publishes deployment images. -This PR does not authorize a staging or production deployment. - -## Source contract - -The receiver is `agent-fleet-build.yaml` on `livepeer/simple-infra` main. -Inputs are `source_repository`, `source_sha` (full commit SHA), and `ci_run_id`. -`.github/fleet-ci.json` identifies this repository's trusted source workflow. -The receiver must independently check that the run succeeded for this repository, workflow, SHA, main branch, and push event. -Use the exact SHA from the run. A newer main commit does not invalidate an older successful run. - -## Freeze - -`FLEET_CI_NOTIFY_ENABLED` is false in this repository. -Missing or false disables notification before the GitHub App receives a token. -`FLEET_DEPLOYMENTS_ENABLED` is false in simple-infra. The new CD workflows must enforce it. -The new flag does not disable existing manual workflows. Any Grafana staging work remains separately authorized. -Keep this PR in draft. Do not merge it or enable notifications during the freeze. - -## Activation after the freeze - -1. Merge the reviewed CI PR after its required checks pass. -2. Check that post-merge CI reports success for that exact commit. -3. Confirm Pulumi's receiver validates the source contract and refuses deployment while its gate is false. -4. Configure `FLEET_CI_APP_ID` and `FLEET_CI_APP_PRIVATE_KEY`. The App needs Actions write on simple-infra. -5. Enable source notifications only after Emran authorizes activation. Production remains manual in the CD workflow. - - -For other repositories, retain their existing required checks until the new check is observed on a PR. -Do not enable auto-merge or change release tag rules as part of this freeze preparation. diff --git a/.github/fleet-ci.json b/.github/fleet-ci.json deleted file mode 100644 index c224fbd..0000000 --- a/.github/fleet-ci.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "schema_version": 1, - "repository": "livepeer/livepeer-python-gateway", - "source_workflow": ".github/workflows/tests.yml", - "source_workflow_name": "Tests", - "source_event": "push", - "source_branch": "main", - "receiver_repository": "livepeer/simple-infra", - "receiver_workflow": "agent-fleet-build.yaml", - "receiver_ref": "main", - "notification_gate": "FLEET_CI_NOTIFY_ENABLED", - "affected_components": [ - "sdk-service", - "fal-app", - "tool-app" - ] -} diff --git a/.github/workflows/fleet-ci-notify.yml b/.github/workflows/fleet-ci-notify.yml deleted file mode 100644 index c078daa..0000000 --- a/.github/workflows/fleet-ci-notify.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Notify fleet builder - -# Disabled during the deployment freeze. This workflow dispatches builds only. -# It never checks out the source run and never obtains GCP credentials. -on: - workflow_run: - workflows: ["Tests"] - types: [completed] - branches: [main] - -permissions: - contents: read - actions: read - -jobs: - notify: - if: >- - vars.FLEET_CI_NOTIFY_ENABLED == 'true' && - github.event.workflow_run.conclusion == 'success' && - github.event.workflow_run.event == 'push' && - github.event.workflow_run.head_branch == 'main' && - github.event.workflow_run.head_repository.full_name == github.repository - runs-on: ubuntu-24.04 - timeout-minutes: 5 - steps: - - name: Check the source run before creating a builder token - env: - GH_TOKEN: ${{ github.token }} - SOURCE_REPOSITORY: ${{ github.repository }} - SOURCE_SHA: ${{ github.event.workflow_run.head_sha }} - CI_RUN_ID: ${{ github.event.workflow_run.id }} - run: | - [[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]] - [[ "$CI_RUN_ID" =~ ^[0-9]+$ ]] - gh api "repos/$SOURCE_REPOSITORY/actions/runs/$CI_RUN_ID" > "$RUNNER_TEMP/source-run.json" - jq -e --arg repo "$SOURCE_REPOSITORY" --arg sha "$SOURCE_SHA" ' - .repository.full_name == $repo and .head_repository.full_name == $repo and - .head_sha == $sha and .head_branch == "main" and .event == "push" and - .path == ".github/workflows/tests.yml" and - .status == "completed" and .conclusion == "success" - ' "$RUNNER_TEMP/source-run.json" - - name: Create a token for the builder repository only - id: app - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3 - with: - app-id: ${{ vars.FLEET_CI_APP_ID }} - private-key: ${{ secrets.FLEET_CI_APP_PRIVATE_KEY }} - owner: livepeer - repositories: simple-infra - permission-actions: write - - name: Notify the central builder with the tested source revision - env: - GH_TOKEN: ${{ steps.app.outputs.token }} - SOURCE_REPOSITORY: ${{ github.repository }} - SOURCE_SHA: ${{ github.event.workflow_run.head_sha }} - CI_RUN_ID: ${{ github.event.workflow_run.id }} - run: | - gh workflow run agent-fleet-build.yaml --repo livepeer/simple-infra --ref main \ - --field source_repository="$SOURCE_REPOSITORY" \ - --field source_sha="$SOURCE_SHA" \ - --field ci_run_id="$CI_RUN_ID" From f471b3c20bfec87f4b68b3dd731a53a8db7b9d64 Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Thu, 5 Nov 2026 12:32:17 -0800 Subject: [PATCH 4/6] ci: retain package builds and skip fork code execution --- .github/workflows/codeql.yml | 43 ++++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 34 ++++++++-------------------- 2 files changed, 52 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..c791b86 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,43 @@ +name: CodeQL + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "23 6 * * 1" + workflow_dispatch: + +permissions: + contents: read + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + if: >- + !github.event.pull_request || + github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: python + build-mode: none + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: github/codeql-action/init@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + - uses: github/codeql-action/analyze@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9fa9257..1b6b0ef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,19 +5,15 @@ on: push: branches: - main - merge_group: - workflow_call: permissions: contents: read -concurrency: - group: gateway-tests-${{ github.event_name == 'push' && github.run_id || github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - jobs: ruff: - timeout-minutes: 10 + if: >- + !github.event.pull_request || + github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -32,7 +28,9 @@ jobs: run: uv run --frozen --group lint ruff check . pytest: - timeout-minutes: 20 + if: >- + !github.event.pull_request || + github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -47,6 +45,9 @@ jobs: run: uv run --frozen --group test pytest --cov=livepeer_gateway --cov-branch --cov-report=term-missing package: + if: >- + !github.event.pull_request || + github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -56,20 +57,3 @@ jobs: python-version: '3.12' - name: Build the wheel and source distribution without publishing run: uv build --no-sources - - ci-gate: - name: ci-gate - if: always() - needs: [ruff, pytest, package] - runs-on: ubuntu-latest - timeout-minutes: 5 - steps: - - name: Require every CI job to succeed - env: - RUFF_RESULT: ${{ needs.ruff.result }} - PYTEST_RESULT: ${{ needs.pytest.result }} - PACKAGE_RESULT: ${{ needs.package.result }} - run: | - test "$RUFF_RESULT" = success - test "$PYTEST_RESULT" = success - test "$PACKAGE_RESULT" = success From 5b522fc1eb55e35801f6335ab4e99ba5164835e0 Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Thu, 5 Nov 2026 13:24:13 -0800 Subject: [PATCH 5/6] ci: remove custom CodeQL workflow --- .github/workflows/codeql.yml | 43 ------------------------------------ 1 file changed, 43 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index c791b86..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: CodeQL - -on: - pull_request: - push: - branches: [main] - schedule: - - cron: "23 6 * * 1" - workflow_dispatch: - -permissions: - contents: read - -jobs: - analyze: - name: Analyze (${{ matrix.language }}) - if: >- - !github.event.pull_request || - github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - contents: read - security-events: write - strategy: - fail-fast: false - matrix: - include: - - language: actions - build-mode: none - - language: python - build-mode: none - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - uses: github/codeql-action/init@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - - uses: github/codeql-action/analyze@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 - with: - category: "/language:${{ matrix.language }}" From bb58cda21993116b2e959080cac89d9a7367abca Mon Sep 17 00:00:00 2001 From: Josh Allmann Date: Thu, 5 Nov 2026 13:40:02 -0800 Subject: [PATCH 6/6] ci: allow approved fork validation with read-only permissions --- .github/workflows/tests.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1b6b0ef..93d805d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,9 +11,6 @@ permissions: jobs: ruff: - if: >- - !github.event.pull_request || - github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -28,9 +25,6 @@ jobs: run: uv run --frozen --group lint ruff check . pytest: - if: >- - !github.event.pull_request || - github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 @@ -45,9 +39,6 @@ jobs: run: uv run --frozen --group test pytest --cov=livepeer_gateway --cov-branch --cov-report=term-missing package: - if: >- - !github.event.pull_request || - github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest timeout-minutes: 10 steps: