From bcd7d6a846b1c52ecdaf48f0c173106181fa269e Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 23 Sep 2026 09:28:31 -0600 Subject: [PATCH 1/5] Fix creds --- .github/workflows/publish-docs.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 04d087ca..4887dcab 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -50,14 +50,14 @@ jobs: aws s3 cp "$DOCS_DIR"/ "$VERSIONED_PREFIX" --recursive aws s3 cp "$DOCS_DIR"/ "$LATEST_PREFIX" --recursive env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} AWS_DEFAULT_REGION: "us-east-1" - name: Invalidate cloudfront cache run: | aws cloudfront create-invalidation --distribution-id EJJ40KLJ3TRY9 --paths "/client-sdk-cpp/*" env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} AWS_DEFAULT_REGION: "us-east-1" From 8d76ef9e8e87d47f866cd8cf1430e0ed754ca869 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 23 Sep 2026 09:53:56 -0600 Subject: [PATCH 2/5] Try smoke on docs --- .github/workflows/ci.yml | 8 ++++++++ .github/workflows/publish-docs.yml | 33 +++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f26e5dd..716ff58c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,6 +117,13 @@ jobs: name: Link Check uses: ./.github/workflows/link_check.yml + # Confirms the org docs-deploy key still exists. The release publish path + # stays inside publish-docs.yml; this call only runs the credentials job. + docs-deploy-credentials: + name: Docs Deploy Credentials + uses: ./.github/workflows/publish-docs.yml + secrets: inherit + cpp-tools: name: C++ Tools needs: changes @@ -152,6 +159,7 @@ jobs: - cpp-tools - generate-docs - link-check + - docs-deploy-credentials - rust-release-check if: always() steps: diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 4887dcab..1e5a3e0c 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -5,6 +5,14 @@ on: # "published" covers newly published stable releases and prereleases. # "released" also catches promotion of an existing prerelease to stable. types: [published, released] + # CI calls this on every pull request and main push. Only the credentials + # job runs there; validate and publish stay on the release trigger. + workflow_call: + secrets: + DOCS_DEPLOY_AWS_ACCESS_KEY: + required: false + DOCS_DEPLOY_AWS_API_SECRET: + required: false permissions: contents: read @@ -13,6 +21,7 @@ permissions: jobs: validate: name: Validate (build docs) + if: github.event_name == 'release' uses: ./.github/workflows/generate-docs.yml with: version: ${{ github.event.release.tag_name }} @@ -26,7 +35,8 @@ jobs: needs: validate # The GitHub release is the source of truth. Drafts do not emit these # events until published; prereleases validate docs but never deploy them. - if: github.event.release.draft == false && github.event.release.prerelease == false + # event_name keeps a CI workflow_call from publishing. + if: github.event_name == 'release' && github.event.release.draft == false && github.event.release.prerelease == false runs-on: ubuntu-latest steps: - name: Download docs artifact @@ -61,3 +71,24 @@ jobs: AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} AWS_DEFAULT_REGION: "us-east-1" + + # Proves the docs-deploy key is still a real AWS access key. This is the + # failure mode from v1.10.2 onward (InvalidAccessKeyId). It does not upload + # or invalidate CloudFront; those permissions are still exercised on release. + credentials: + name: Check AWS credentials + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + runs-on: ubuntu-latest + steps: + - name: Verify docs deploy credentials + env: + AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} + AWS_DEFAULT_REGION: "us-east-1" + run: | + set -euo pipefail + if [[ -z "${AWS_ACCESS_KEY_ID}" || -z "${AWS_SECRET_ACCESS_KEY}" ]]; then + echo "Docs deploy AWS credentials are not available to this workflow." + exit 1 + fi + aws sts get-caller-identity --query Arn --output text From beb748e4019da1c7b8d737135db5ac38149163a5 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 23 Sep 2026 11:29:54 -0600 Subject: [PATCH 3/5] Attempt unified flow --- .github/workflows/ci.yml | 25 ++-- .github/workflows/docs.yml | 224 ++++++++++++++++++++++++++++ .github/workflows/generate-docs.yml | 170 --------------------- .github/workflows/make-release.yml | 4 +- .github/workflows/publish-docs.yml | 94 ------------ AGENTS.md | 5 +- 6 files changed, 239 insertions(+), 283 deletions(-) create mode 100644 .github/workflows/docs.yml delete mode 100644 .github/workflows/generate-docs.yml delete mode 100644 .github/workflows/publish-docs.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 716ff58c..0c20ff88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,8 +71,7 @@ jobs: - docs/** - scripts/generate-docs.sh - .github/workflows/ci.yml - - .github/workflows/generate-docs.yml - - .github/workflows/publish-docs.yml + - .github/workflows/docs.yml cpp_tools: - src/** - include/** @@ -117,24 +116,21 @@ jobs: name: Link Check uses: ./.github/workflows/link_check.yml - # Confirms the org docs-deploy key still exists. The release publish path - # stays inside publish-docs.yml; this call only runs the credentials job. - docs-deploy-credentials: - name: Docs Deploy Credentials - uses: ./.github/workflows/publish-docs.yml - secrets: inherit - cpp-tools: name: C++ Tools needs: changes if: ${{ needs.changes.outputs.cpp_tools == 'true' || github.event_name == 'workflow_dispatch' }} uses: ./.github/workflows/cpp-tools.yml - generate-docs: - name: Generate Docs + docs: + name: Docs needs: changes - if: ${{ needs.changes.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' }} - uses: ./.github/workflows/generate-docs.yml + uses: ./.github/workflows/docs.yml + with: + build_docs: ${{ needs.changes.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' }} + # Deploy credentials are deliberately withheld from pull requests. + check_credentials: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + secrets: inherit # Only runs on a client-sdk-rust submodule bump. Runs in parallel and is not a # dependency of builds/tests, so developer iteration against an unreleased @@ -157,9 +153,8 @@ jobs: - tests - license-check - cpp-tools - - generate-docs + - docs - link-check - - docs-deploy-credentials - rust-release-check if: always() steps: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..009c2ac2 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,224 @@ +name: Docs + +on: + release: + # A stable release publishes docs. A prerelease still builds the docs and + # checks the deploy credentials, but does not publish. + types: [published] + workflow_call: + inputs: + build_docs: + description: "Build and verify the documentation" + required: false + type: boolean + default: true + check_credentials: + description: "Check the docs deploy AWS credentials" + required: false + type: boolean + default: false + version: + description: "Documentation version (e.g. v0.1.0)" + required: false + type: string + upload_artifact: + description: "Upload the generated docs as a workflow artifact" + required: false + type: boolean + default: true + artifact_name: + description: "Name of the uploaded docs artifact" + required: false + type: string + default: livekit-cpp-docs + artifact_retention_days: + description: "Artifact retention in days" + required: false + type: number + default: 7 + secrets: + DOCS_DEPLOY_AWS_ACCESS_KEY: + required: false + DOCS_DEPLOY_AWS_API_SECRET: + required: false + outputs: + project_number: + description: "Doxygen PROJECT_NUMBER used for the build" + value: ${{ jobs.build.outputs.project_number }} + artifact_name: + description: "Uploaded docs artifact name" + value: ${{ jobs.build.outputs.artifact_name }} + +permissions: + contents: read + actions: read + +jobs: + build: + name: Generate and verify docs + if: github.event_name == 'release' || inputs.build_docs + runs-on: ubuntu-latest + outputs: + project_number: ${{ steps.build_docs.outputs.project_number }} + artifact_name: ${{ steps.artifact_meta.outputs.name }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # Required so git describe in generate-docs.sh can resolve a version. + fetch-depth: 0 + + - name: Install Doxygen + run: | + sudo apt-get update + sudo apt-get install -y doxygen graphviz + + - name: Generate docs + id: build_docs + shell: bash + env: + INPUT_VERSION: ${{ github.event_name == 'release' && github.event.release.tag_name || inputs.version || '' }} + run: | + set -euo pipefail + + args=() + if [[ -n "$INPUT_VERSION" ]]; then + args+=(--version "$INPUT_VERSION") + elif [[ "${{ github.ref_type }}" == "tag" ]]; then + args+=(--version "${{ github.ref_name }}") + fi + + ./scripts/generate-docs.sh "${args[@]}" + + - name: Print docs version + shell: bash + run: | + set -euo pipefail + + PROJECT_NUMBER="${{ steps.build_docs.outputs.project_number }}" + if [[ -z "$PROJECT_NUMBER" ]]; then + echo "ERROR: build_docs step did not emit a project_number output." + exit 1 + fi + + echo "Docs version: ${PROJECT_NUMBER}" + { + echo "Docs version: \`${PROJECT_NUMBER}\`" + echo "" + echo "> Note: On a non-tag/release run, the version resolves to:" + echo " \`--\`" + } >>"$GITHUB_STEP_SUMMARY" + + - name: Verify docs were generated + shell: bash + run: | + set -euo pipefail + if [[ ! -f docs/doxygen/html/index.html ]]; then + echo "ERROR: Expected docs at docs/doxygen/html/index.html but file not found." + exit 1 + fi + + - name: Resolve artifact metadata + id: artifact_meta + if: github.event_name == 'release' || inputs.upload_artifact + shell: bash + env: + INPUT_NAME: ${{ inputs.artifact_name || format('livekit-cpp-docs-{0}', github.run_id) }} + INPUT_RETENTION: ${{ inputs.artifact_retention_days || 7 }} + run: | + set -euo pipefail + if [[ -z "$INPUT_NAME" ]]; then + echo "ERROR: Artifact name resolved to empty." + exit 1 + fi + echo "name=${INPUT_NAME}" >>"$GITHUB_OUTPUT" + echo "retention=${INPUT_RETENTION}" >>"$GITHUB_OUTPUT" + + - name: Upload docs artifact + if: steps.artifact_meta.outputs.name != '' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: ${{ steps.artifact_meta.outputs.name }} + path: docs/doxygen/html/ + retention-days: ${{ steps.artifact_meta.outputs.retention }} + if-no-files-found: error + + - name: Re-download artifact + if: steps.artifact_meta.outputs.name != '' + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ steps.artifact_meta.outputs.name }} + path: html + + - name: Verify downloaded artifact + if: steps.artifact_meta.outputs.name != '' + shell: bash + run: | + set -euo pipefail + + TOTAL=$(find html -type f | wc -l | tr -d ' ') + echo "Total files: ${TOTAL}" + if [[ ! -f html/index.html ]]; then + echo "ERROR: html/index.html is missing; the publish artifact layout regressed." + exit 1 + fi + + credentials: + name: Check AWS credentials + # CI enables this only for trusted main pushes. Release events always + # check credentials before publishing. PR jobs never receive deploy keys. + if: github.event_name == 'release' || inputs.check_credentials + runs-on: ubuntu-latest + steps: + - name: Verify docs deploy credentials + env: + AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} + AWS_DEFAULT_REGION: "us-east-1" + run: | + set -euo pipefail + if [[ -z "${AWS_ACCESS_KEY_ID}" || -z "${AWS_SECRET_ACCESS_KEY}" ]]; then + echo "Docs deploy AWS credentials are not available to this workflow." + exit 1 + fi + aws sts get-caller-identity --query Arn --output text + + publish: + name: Publish (S3 + CloudFront) + needs: [build, credentials] + if: github.event_name == 'release' && github.event.release.prerelease == false + runs-on: ubuntu-latest + steps: + - name: Download docs artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: ${{ needs.build.outputs.artifact_name }} + path: html + + - name: S3 Upload + env: + AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} + AWS_DEFAULT_REGION: "us-east-1" + run: | + set -euo pipefail + + if [[ ! -f html/index.html ]]; then + echo "Expected docs at html/index.html but file not found." + exit 1 + fi + + VERSIONED_PREFIX="s3://livekit-docs/client-sdk-cpp/${{ needs.build.outputs.project_number }}" + LATEST_PREFIX="s3://livekit-docs/client-sdk-cpp" + + aws s3 cp html/ "$VERSIONED_PREFIX" --recursive + aws s3 cp html/ "$LATEST_PREFIX" --recursive + + - name: Invalidate CloudFront cache + env: + AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} + AWS_DEFAULT_REGION: "us-east-1" + run: | + aws cloudfront create-invalidation \ + --distribution-id EJJ40KLJ3TRY9 \ + --paths "/client-sdk-cpp/*" diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml deleted file mode 100644 index d7bea1cf..00000000 --- a/.github/workflows/generate-docs.yml +++ /dev/null @@ -1,170 +0,0 @@ -name: Generate docs -permissions: - contents: read - -# Generates Doxygen docs and uploads them as a workflow artifact. - -# This workflow is used to validate documentation before merge, for example catching -# things like broken @ref tags, missing @param tags, etc. - -# The artifact is attached to the workflow run so reviewers can download a preview, -# but also to verify the documentation artifact is valid for subsequent release runs -# that will publish them to the LiveKit docs web page: https://docs.livekit.io/reference/client-sdk-cpp/ -# Called by top-level ci.yml on PRs. PR trigger lives in the parent -# so a single "CI" check gates every PR regardless of paths. -on: - workflow_call: - inputs: - version: - description: 'Documentation version (e.g. v0.1.0)' - required: false - type: string - upload_artifact: - description: 'Upload the generated docs folder as a workflow artifact' - required: false - type: boolean - default: true - artifact_name: - description: 'Name to use for the uploaded docs artifact' - required: false - type: string - default: livekit-cpp-docs - artifact_retention_days: - description: 'Retention (days) for the uploaded docs artifact' - required: false - type: number - default: 7 - outputs: - project_number: - description: 'Doxygen PROJECT_NUMBER used for the build (e.g., v1.2.3)' - value: ${{ jobs.validate.outputs.project_number }} - artifact_name: - description: 'Name of the uploaded docs artifact (empty if upload was skipped via upload_artifact: false)' - value: ${{ jobs.validate.outputs.artifact_name }} - -jobs: - validate: - name: Generate and verify docs - runs-on: ubuntu-latest - outputs: - project_number: ${{ steps.build_docs.outputs.project_number }} - artifact_name: ${{ steps.artifact_meta.outputs.name }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - # fetch-depth: 0 is required so `git describe --tags` in - # scripts/generate-docs.sh resolves the right version from the git history. - fetch-depth: 0 - - # Doxygen is available on ubuntu-latest, but we install explicitly for stability - - name: Install Doxygen - run: | - sudo apt-get update - sudo apt-get install -y doxygen graphviz - - - name: Generate docs (Doxygen) - id: build_docs - shell: bash - env: - INPUT_VERSION: ${{ inputs.version || '' }} - run: | - set -euo pipefail - - args=() - if [[ -n "$INPUT_VERSION" ]]; then - args+=(--version "$INPUT_VERSION") - elif [[ "${{ github.ref_type }}" == "tag" ]]; then - args+=(--version "${{ github.ref_name }}") - fi - - ./scripts/generate-docs.sh "${args[@]}" - - - name: Print docs version - shell: bash - run: | - set -euo pipefail - - PROJECT_NUMBER="${{ steps.build_docs.outputs.project_number }}" - - if [[ -z "$PROJECT_NUMBER" ]]; then - echo "ERROR: build_docs step did not emit a project_number output." - exit 1 - fi - - echo "Docs version: ${PROJECT_NUMBER}" - - { - echo "Docs version: \`${PROJECT_NUMBER}\`" - echo "" - echo "> Note: On a non-tag/release run, the version will resolve to:" - echo " \`--\`" - } >>"$GITHUB_STEP_SUMMARY" - - - name: Verify docs were generated - shell: bash - run: | - set -euo pipefail - if [[ ! -f docs/doxygen/html/index.html ]]; then - echo "ERROR: Expected docs at docs/doxygen/html/index.html but file not found." - exit 1 - fi - - # `inputs.*` is only populated on `workflow_call`. On a direct - # `pull_request` trigger every `inputs.*` lookup is the empty string, so - # we OR-fold to the documented defaults to keep PR runs behaving the same - # as the workflow_call default of `upload_artifact: true`. - - name: Resolve artifact metadata - id: artifact_meta - if: inputs.upload_artifact || github.event_name == 'pull_request' - shell: bash - env: - INPUT_NAME: ${{ inputs.artifact_name || 'livekit-cpp-docs' }} - INPUT_RETENTION: ${{ inputs.artifact_retention_days || '7' }} - run: | - set -euo pipefail - if [[ -z "$INPUT_NAME" ]]; then - echo "ERROR: artifact name resolved to empty." - exit 1 - fi - echo "name=${INPUT_NAME}" >>"$GITHUB_OUTPUT" - echo "retention=${INPUT_RETENTION}" >>"$GITHUB_OUTPUT" - - - name: Upload docs artifact - if: steps.artifact_meta.outputs.name != '' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: ${{ steps.artifact_meta.outputs.name }} - path: docs/doxygen/html/ - retention-days: ${{ steps.artifact_meta.outputs.retention }} - if-no-files-found: error - - # Simple check to make sure the documentation artifact is valid. - - name: Re-download artifact (publish workflow pre-validation) - if: steps.artifact_meta.outputs.name != '' - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: ${{ steps.artifact_meta.outputs.name }} - path: html - - - name: Inspect downloaded artifact - if: steps.artifact_meta.outputs.name != '' - shell: bash - run: | - set -euo pipefail - - NAME="${{ steps.artifact_meta.outputs.name }}" - ROOT="html" - - echo "Artifact '${NAME}' extracted into '${ROOT}/'. Top-level contents:" - # `sed -n '1,Np'` reads the whole pipe before truncating its output, - # so the producer (ls) never hits SIGPIPE under `pipefail`. - ls -la "$ROOT" | sed -n '1,40p' - - TOTAL=$(find "$ROOT" -type f | wc -l | tr -d ' ') - echo "Total files: ${TOTAL}" - - if [[ ! -f "${ROOT}/index.html" ]]; then - echo "ERROR: ${ROOT}/index.html is missing -- artifact layout regressed." - echo " publish-docs.yml expects html/index.html." - exit 1 - fi diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index cdf5583d..51c81d7a 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -461,13 +461,13 @@ jobs: # Build docs for validation and retain them as a workflow artifact. Publishing # is triggered separately by the GitHub release's authoritative state. - generate-docs: + docs: name: Generate Documentation needs: release permissions: contents: read actions: read - uses: ./.github/workflows/generate-docs.yml + uses: ./.github/workflows/docs.yml with: version: ${{ needs.release.outputs.version }} upload_artifact: true diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml deleted file mode 100644 index 1e5a3e0c..00000000 --- a/.github/workflows/publish-docs.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Publish docs - -on: - release: - # "published" covers newly published stable releases and prereleases. - # "released" also catches promotion of an existing prerelease to stable. - types: [published, released] - # CI calls this on every pull request and main push. Only the credentials - # job runs there; validate and publish stay on the release trigger. - workflow_call: - secrets: - DOCS_DEPLOY_AWS_ACCESS_KEY: - required: false - DOCS_DEPLOY_AWS_API_SECRET: - required: false - -permissions: - contents: read - actions: read - -jobs: - validate: - name: Validate (build docs) - if: github.event_name == 'release' - uses: ./.github/workflows/generate-docs.yml - with: - version: ${{ github.event.release.tag_name }} - upload_artifact: true - # Suffix with run_id so concurrent publish runs cannot collide on the - # artifact namespace within the same repository. - artifact_name: livekit-cpp-docs-${{ github.run_id }} - - publish: - name: Publish (S3 + CloudFront) - needs: validate - # The GitHub release is the source of truth. Drafts do not emit these - # events until published; prereleases validate docs but never deploy them. - # event_name keeps a CI workflow_call from publishing. - if: github.event_name == 'release' && github.event.release.draft == false && github.event.release.prerelease == false - runs-on: ubuntu-latest - steps: - - name: Download docs artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: ${{ needs.validate.outputs.artifact_name }} - path: html - - - name: S3 Upload - run: | - DOCS_DIR="html" - if [[ ! -d "$DOCS_DIR" ]]; then - echo "Expected docs at $DOCS_DIR but directory not found." - exit 1 - fi - - VERSIONED_PREFIX="s3://livekit-docs/client-sdk-cpp/${{ needs.validate.outputs.project_number }}" - LATEST_PREFIX="s3://livekit-docs/client-sdk-cpp" - - # Upload immutable versioned docs, then refresh rolling latest. - aws s3 cp "$DOCS_DIR"/ "$VERSIONED_PREFIX" --recursive - aws s3 cp "$DOCS_DIR"/ "$LATEST_PREFIX" --recursive - env: - AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} - AWS_DEFAULT_REGION: "us-east-1" - - - name: Invalidate cloudfront cache - run: | - aws cloudfront create-invalidation --distribution-id EJJ40KLJ3TRY9 --paths "/client-sdk-cpp/*" - env: - AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} - AWS_DEFAULT_REGION: "us-east-1" - - # Proves the docs-deploy key is still a real AWS access key. This is the - # failure mode from v1.10.2 onward (InvalidAccessKeyId). It does not upload - # or invalidate CloudFront; those permissions are still exercised on release. - credentials: - name: Check AWS credentials - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false - runs-on: ubuntu-latest - steps: - - name: Verify docs deploy credentials - env: - AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_DEPLOY_AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_DEPLOY_AWS_API_SECRET }} - AWS_DEFAULT_REGION: "us-east-1" - run: | - set -euo pipefail - if [[ -z "${AWS_ACCESS_KEY_ID}" || -z "${AWS_SECRET_ACCESS_KEY}" ]]; then - echo "Docs deploy AWS credentials are not available to this workflow." - exit 1 - fi - aws sts get-caller-identity --query Arn --output text diff --git a/AGENTS.md b/AGENTS.md index 45c875eb..58985b83 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -258,7 +258,7 @@ with the same library loaded elsewhere in the host process. ### Public API Documentation (Doxygen) The public API (`include/livekit/*.h`) is what consumers read first and is also -published as a Doxygen site (`docs/doxygen/Doxyfile`, `.github/workflows/publish-docs.yml`). +published as a Doxygen site (`docs/doxygen/Doxyfile`, `.github/workflows/docs.yml`). Every doc comment in `include/livekit/` must use the rules below, and PRs that add or modify public symbols are gated on these rules during review. @@ -392,7 +392,8 @@ all filtered stages; normal pull requests and pushes use the path filters. - `.github/workflows/cpp-tools.yml` — Reusable SDK-specific `clang-format` and `clang-tidy` workflow. It prepares the build environment and invokes the project wrappers backed by the shared `cpp-tools` scripts. -- `.github/workflows/generate-docs.yml` — Reusable Doxygen docs validation. +- `.github/workflows/docs.yml` — Reusable Doxygen docs validation, deploy + credential check on trusted `main` pushes, and stable-release publishing. - `.github/workflows/rust-release-check.yml` — Reusable check that the pinned `client-sdk-rust` submodule commit maps to a published release. Gated by the `rust_submodule` path filter so it only runs on a submodule bump, runs in From 55d4f4dde79464dc5019e950811d0e14c4991e42 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 23 Sep 2026 11:40:50 -0600 Subject: [PATCH 4/5] Tmp run on PR --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c20ff88..ff6679e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,8 +128,9 @@ jobs: uses: ./.github/workflows/docs.yml with: build_docs: ${{ needs.changes.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' }} - # Deploy credentials are deliberately withheld from pull requests. - check_credentials: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + # TEMPORARY: Exercise the org deploy credentials on same-repository PRs. + # Remove the pull_request clause after verifying the credential migration. + check_credentials: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) }} secrets: inherit # Only runs on a client-sdk-rust submodule bump. Runs in parallel and is not a From d00338a09eeddd03e10e9a6fd84642206047ed5b Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 23 Sep 2026 11:51:44 -0600 Subject: [PATCH 5/5] Fixes --- .github/workflows/ci.yml | 5 ++--- .github/workflows/docs.yml | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff6679e1..0c20ff88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,9 +128,8 @@ jobs: uses: ./.github/workflows/docs.yml with: build_docs: ${{ needs.changes.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' }} - # TEMPORARY: Exercise the org deploy credentials on same-repository PRs. - # Remove the pull_request clause after verifying the credential migration. - check_credentials: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) }} + # Deploy credentials are deliberately withheld from pull requests. + check_credentials: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} secrets: inherit # Only runs on a client-sdk-rust submodule bump. Runs in parallel and is not a diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 009c2ac2..856aadf7 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,8 +3,9 @@ name: Docs on: release: # A stable release publishes docs. A prerelease still builds the docs and - # checks the deploy credentials, but does not publish. - types: [published] + # checks the deploy credentials, but does not publish. "released" also + # catches promotion of an existing prerelease to stable. + types: [published, released] workflow_call: inputs: build_docs: