Repository navigation
fix(oaistream): replay reasoning content with opt-out #10797
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Quality gate for every PR and the release pipeline for main and v* tags. | |
| # | |
| # `gate` is the only check the main ruleset needs to require: it fails when any | |
| # job it needs failed or was cancelled and passes when they succeeded or were | |
| # skipped (docs-only PRs skip every Go job; a main push whose SHA already | |
| # passed the merge queue skips them too). Add a job to `gate.needs` to make it | |
| # blocking; the ruleset never has to change. | |
| name: ci | |
| permissions: | |
| contents: read | |
| # Main, tag and merge-queue runs get a group of their own so they are never | |
| # queued behind or cancelled by another run; PR runs supersede the previous | |
| # run on the ref. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event_name != 'pull_request' && github.run_id || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| image_mode: | |
| description: Publish on main with auto; test images without publishing on other branches or with build-only | |
| type: choice | |
| required: false | |
| default: auto | |
| options: | |
| - auto | |
| - build-only | |
| expected_sha: | |
| description: Optional immutable 40-character commit SHA to verify before authentication | |
| type: string | |
| required: false | |
| default: '' | |
| push: | |
| branches: [ main ] | |
| tags: [ "v*" ] | |
| pull_request: | |
| merge_group: | |
| jobs: | |
| # Decides what the run has to do: | |
| # code false on docs-only PRs (every changed file under docs/), which | |
| # skip the Go jobs. Markdown elsewhere is test data, so only docs/ | |
| # counts. Anything but a PR runs all. | |
| # tested true on a main push whose commit already passed a merge-queue | |
| # run of this workflow: the queue tested this exact SHA minutes | |
| # ago, so the push builds, publishes, and refreshes test caches. | |
| # A push that bypassed the queue runs everything. | |
| changes: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| actions: read | |
| outputs: | |
| code: ${{ github.event_name != 'pull_request' || steps.filter.outputs.docs_count != steps.filter.outputs.all_count }} | |
| tested: ${{ steps.queue.outputs.tested == 'true' }} | |
| steps: | |
| - id: filter | |
| if: github.event_name == 'pull_request' | |
| uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3 | |
| with: | |
| filters: | | |
| docs: | |
| - 'docs/**' | |
| all: | |
| - '**' | |
| - name: Look for a green merge-queue run of this commit | |
| id: queue | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| WORKFLOW_PATH: ${{ github.workflow_ref }} | |
| run: | | |
| # workflow_ref is owner/repo/.github/workflows/ci.yml@refs/heads/main | |
| workflow_file="${WORKFLOW_PATH#"$GH_REPO"/}" | |
| workflow_file="${workflow_file%@*}" | |
| # shellcheck disable=SC2016 # $file is a jq variable | |
| runs=$(gh api "repos/$GH_REPO/actions/runs?event=merge_group&head_sha=$GITHUB_SHA&status=success&per_page=20" \ | |
| | jq --arg file "$workflow_file" '[.workflow_runs[] | select(.path == $file)] | length') | |
| if [[ "$runs" -gt 0 ]]; then | |
| echo "tested=true" >> "$GITHUB_OUTPUT" | |
| echo "::notice::${GITHUB_SHA} passed the merge queue; lint and test jobs are skipped on this push" | |
| else | |
| echo "tested=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| lint: | |
| needs: changes | |
| if: needs.changes.outputs.tested != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| with: | |
| cache-name: test-linux | |
| save: 'false' | |
| task: 'false' | |
| - name: golangci-lint | |
| uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 | |
| with: | |
| version: v2.14.0 | |
| # The rest of `task lint`: project cops and go.mod tidiness. | |
| - name: Project cops | |
| run: go run ./lint . | |
| - name: go mod tidy | |
| run: go mod tidy --diff >/dev/null || (echo 'go.mod/go.sum are not tidy' && exit 1) | |
| - name: Shell scripts | |
| run: | | |
| shellcheck scripts/*.sh | |
| ./scripts/ci-report-failures-test.sh | |
| ./scripts/models-delta-test.sh | |
| - name: GitHub Actions | |
| uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2.2.0 | |
| with: | |
| version: 1.7.12 | |
| fail-on-error: true | |
| pyflakes: false | |
| # actionlint does not know GitHub's `$/` same-repository action syntax | |
| # yet. The action splits flags on whitespace, hence the \s pattern. | |
| flags: -ignore action\s.\$/\S+.\sin\sinvalid\sformat | |
| # Static security audit of workflows and composite actions; config in | |
| # .github/zizmor.yml. Findings at low severity and above fail the job. | |
| - name: zizmor | |
| uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4 | |
| with: | |
| advanced-security: false | |
| annotations: true | |
| min-severity: low | |
| version: v1.30.0 | |
| - name: Workflow invariants | |
| run: ./scripts/workflow-lint.sh | |
| test-linux: | |
| needs: changes | |
| if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tested != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| - name: Build | |
| run: task build | |
| - name: Test | |
| run: task test-ci | |
| - name: Upload test report | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: go-test-${{ github.job }} | |
| path: ${{ runner.temp }}/go-test.json | |
| retention-days: 14 | |
| if-no-files-found: ignore | |
| - name: Test binary | |
| run: task test-binary | |
| # Plan storage relies on OS-specific file locking and path semantics, so the | |
| # full suite also runs natively on Windows. | |
| test-windows: | |
| needs: changes | |
| if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tested != 'true' | |
| runs-on: windows-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| # Real-time scanning of every compiled object and test binary is the | |
| # dominant I/O cost on hosted Windows runners. | |
| - name: Exclude build paths from Defender | |
| continue-on-error: true | |
| shell: pwsh | |
| run: | | |
| $paths = @($env:GITHUB_WORKSPACE, $env:RUNNER_TEMP, (go env GOROOT), (go env GOPATH), (go env GOCACHE), (go env GOMODCACHE)) | |
| Add-MpPreference -ExclusionPath $paths | |
| Get-MpPreference | Select-Object -ExpandProperty ExclusionPath | |
| - name: Test | |
| run: task test-ci | |
| - name: Upload test report | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: go-test-${{ github.job }} | |
| path: ${{ runner.temp }}/go-test.json | |
| retention-days: 14 | |
| if-no-files-found: ignore | |
| # Compile-only checks kept out of `test-linux` so they run alongside it. | |
| cross-compile: | |
| needs: changes | |
| if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tested != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| - name: Plan storage build tags | |
| run: task check-plan-cross | |
| - name: WASM runtime, tools and providers | |
| run: task test-wasm-js | |
| - name: WASM JavaScript bridge | |
| run: task test-wasm-bridge | |
| licenses: | |
| needs: changes | |
| if: needs.changes.outputs.code == 'true' && needs.changes.outputs.tested != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| with: | |
| cache-name: test-linux | |
| save: 'false' | |
| task: 'false' | |
| - name: Check licenses | |
| run: | | |
| go install github.com/google/go-licenses@v1.6.0 | |
| go-licenses check . --allowed_licenses=Apache-2.0,MIT,BSD-3-Clause,BSD-2-Clause --ignore modernc.org/mathutil --ignore github.com/hashicorp/hcl/v2 | |
| # setup-go saves only on main. Refresh the test caches when merge-queue | |
| # validation skips their jobs, without running tests again. | |
| warm-cache: | |
| needs: changes | |
| if: needs.changes.outputs.tested == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| cache-name: test-linux | |
| - os: windows-latest | |
| cache-name: test-windows | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| with: | |
| cache-name: ${{ matrix.cache-name }} | |
| task: 'false' | |
| - if: runner.os == 'Windows' | |
| name: Exclude build paths from Defender | |
| continue-on-error: true | |
| shell: pwsh | |
| run: | | |
| $paths = @($env:GITHUB_WORKSPACE, $env:RUNNER_TEMP, (go env GOROOT), (go env GOPATH), (go env GOCACHE), (go env GOMODCACHE)) | |
| Add-MpPreference -ExclusionPath $paths | |
| - name: Compile packages | |
| run: go build ./... | |
| - name: Compile tests | |
| shell: bash | |
| env: | |
| TEST_OUTPUT: ${{ runner.os == 'Windows' && 'NUL' || '/dev/null' }} | |
| run: go test -c -o "$TEST_OUTPUT" ./... | |
| # Race detector on main only: it is several times slower than `task test` | |
| # and must not sit on the PR critical path. Not needed by `gate`. | |
| test-race: | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: $/.github/actions/setup-go | |
| - name: Test with the race detector | |
| run: task test-race | |
| # Non-blocking triage for test failures on the canonical repository's main | |
| # branch. cross-compile orders this after all test jobs but is not reported. | |
| report-main-failures: | |
| if: >- | |
| always() && | |
| github.event_name == 'push' && | |
| github.ref == 'refs/heads/main' && | |
| github.repository == 'docker/docker-agent' && | |
| (needs.test-linux.result == 'failure' || | |
| needs.test-windows.result == 'failure' || | |
| needs.test-race.result == 'failure') | |
| needs: [ test-linux, test-windows, test-race, cross-compile ] | |
| permissions: | |
| contents: read | |
| actions: read | |
| issues: write | |
| concurrency: | |
| group: ci-report-main-failures | |
| cancel-in-progress: false | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Report failed tests | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| RUN_ID: ${{ github.run_id }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| AFTER_SHA: ${{ github.sha }} | |
| run: ./scripts/ci-report-failures.sh | |
| # Builds the image and the sandbox template, on Build Cloud whenever the run | |
| # can authenticate to Docker Hub: both platforms natively on one runner. | |
| # main, v* tags and `image_mode: auto` dispatches on main push by digest, | |
| # untagged; every other run builds into the cache only. Runs that cannot | |
| # authenticate (PRs from forks, PRs opened by Dependabot and other bots | |
| # running with a read-only token, CI in a fork of this repo) fall back to a | |
| # plain builder on the runner, linux/amd64 only, nothing pushed, so the | |
| # Dockerfile is still exercised. Not gated on the test jobs: nothing | |
| # user-visible moves until `publish`. | |
| image: | |
| needs: changes | |
| if: >- | |
| needs.changes.outputs.code == 'true' && ( | |
| github.event_name == 'pull_request' || | |
| github.event_name == 'push' || | |
| github.event_name == 'merge_group' || | |
| (github.event_name == 'workflow_dispatch' && startsWith(github.ref, 'refs/heads/')) | |
| ) | |
| permissions: | |
| contents: read | |
| id-token: write | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| outputs: | |
| publish: ${{ steps.mode.outputs.publish }} | |
| image-digest: ${{ steps.image.outputs.digest }} | |
| template-digest: ${{ steps.template.outputs.digest }} | |
| env: | |
| IMAGE: docker/docker-agent | |
| TEMPLATE: docker/docker-agent-sbx-templates | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Decide build mode | |
| id: mode | |
| env: | |
| PUBLISH: >- | |
| ${{ github.repository == 'docker/docker-agent' && | |
| (github.event_name == 'push' || | |
| (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && | |
| (inputs.image_mode == '' || inputs.image_mode == 'auto'))) && 'true' || 'false' }} | |
| # Empty on fork PRs, Dependabot PRs and in forks of this repo. | |
| CONNECTION_ID: ${{ vars.DOCKERHUB_OIDC_CONNECTION_ID }} | |
| run: | | |
| # Build Cloud needs the Hub OIDC connection id and an OIDC token; the | |
| # token endpoint is only exposed when id-token: write was granted. | |
| if [[ -n "$CONNECTION_ID" && -n "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]]; then | |
| builder=cloud | |
| elif [[ "$PUBLISH" == true ]]; then | |
| echo "publishing requires Build Cloud: DOCKERHUB_OIDC_CONNECTION_ID or the OIDC token is unavailable" >&2 | |
| exit 1 | |
| else | |
| builder=local | |
| echo "::notice::Build Cloud unavailable for this run; building linux/amd64 on the runner" | |
| fi | |
| echo "builder=$builder" >> "$GITHUB_OUTPUT" | |
| if [[ "$PUBLISH" == true ]]; then | |
| { | |
| echo "publish=true" | |
| echo "image-outputs=type=image,name=${IMAGE},push-by-digest=true,name-canonical=true,push=true" | |
| echo "template-outputs=type=image,name=${TEMPLATE},push-by-digest=true,name-canonical=true,push=true" | |
| echo "provenance=mode=max" | |
| echo "git-tag=${GITHUB_REF_NAME}" | |
| echo "git-commit=${GITHUB_SHA}" | |
| # Build records are useful on PRs; skip the upload for release builds. | |
| echo "record-upload=false" | |
| } >> "$GITHUB_OUTPUT" | |
| else | |
| { | |
| echo "publish=false" | |
| echo "image-outputs=type=cacheonly" | |
| echo "template-outputs=type=cacheonly" | |
| echo "provenance=false" | |
| echo "git-tag=pr" | |
| echo "git-commit=dev" | |
| # A read-only token (the local case) cannot upload the record artifact. | |
| echo "record-upload=$([[ "$builder" == cloud ]] && echo true || echo false)" | |
| } >> "$GITHUB_OUTPUT" | |
| fi | |
| if [[ "$builder" == cloud ]]; then | |
| echo "platforms=linux/amd64,linux/arm64" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "platforms=linux/amd64" >> "$GITHUB_OUTPUT" | |
| fi | |
| - if: steps.mode.outputs.builder == 'cloud' | |
| uses: $/.github/actions/setup-buildx | |
| id: cloud | |
| with: | |
| connection-id: ${{ vars.DOCKERHUB_OIDC_CONNECTION_ID }} | |
| expected-sha: ${{ inputs.expected_sha }} | |
| - if: steps.mode.outputs.builder == 'local' | |
| uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 | |
| id: local | |
| with: | |
| cache-binary: false | |
| - name: Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: ${{ env.IMAGE }} | |
| - name: Build image | |
| id: image | |
| uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 | |
| env: | |
| DOCKER_BUILD_RECORD_UPLOAD: ${{ steps.mode.outputs.record-upload }} | |
| DOCKER_BUILD_SUMMARY: ${{ steps.mode.outputs.record-upload }} | |
| with: | |
| builder: ${{ steps.cloud.outputs.builder || steps.local.outputs.name }} | |
| context: . | |
| platforms: ${{ steps.mode.outputs.platforms }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| load: false | |
| github-token: '' | |
| sbom: ${{ steps.mode.outputs.publish }} | |
| provenance: ${{ steps.mode.outputs.provenance }} | |
| outputs: ${{ steps.mode.outputs.image-outputs }} | |
| build-args: | | |
| GIT_TAG=${{ steps.mode.outputs.git-tag }} | |
| GIT_COMMIT=${{ steps.mode.outputs.git-commit }} | |
| # A stage of the same Dockerfile with identical build args, so it reuses | |
| # the builder-linux layer above and embeds the exact same binary. | |
| - name: Build template | |
| id: template | |
| uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 | |
| env: | |
| DOCKER_BUILD_RECORD_UPLOAD: ${{ steps.mode.outputs.record-upload }} | |
| DOCKER_BUILD_SUMMARY: ${{ steps.mode.outputs.record-upload }} | |
| with: | |
| builder: ${{ steps.cloud.outputs.builder || steps.local.outputs.name }} | |
| context: . | |
| target: template | |
| platforms: ${{ steps.mode.outputs.platforms }} | |
| load: false | |
| github-token: '' | |
| sbom: ${{ steps.mode.outputs.publish }} | |
| provenance: ${{ steps.mode.outputs.provenance }} | |
| outputs: ${{ steps.mode.outputs.template-outputs }} | |
| build-args: | | |
| GIT_TAG=${{ steps.mode.outputs.git-tag }} | |
| GIT_COMMIT=${{ steps.mode.outputs.git-commit }} | |
| # Single required status check; see the header comment. | |
| gate: | |
| if: always() | |
| needs: [ changes, lint, test-linux, test-windows, cross-compile, licenses, image ] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Check results | |
| env: | |
| RESULTS: ${{ toJSON(needs) }} | |
| run: | | |
| { | |
| echo "| job | result |" | |
| echo "|---|---|" | |
| jq -r 'to_entries[] | "| \(.key) | \(.value.result) |"' <<< "$RESULTS" | |
| } | tee -a "$GITHUB_STEP_SUMMARY" | |
| jq -e '[.[] | .result] | all(. == "success" or . == "skipped")' <<< "$RESULTS" >/dev/null | |
| # Moves tags onto the digests pushed by `image` once the gate is green. On | |
| # main only edge moves; on a v* tag the version tag and the floating latest | |
| # tag that sandboxes pull by default. | |
| publish: | |
| if: needs.image.outputs.publish == 'true' | |
| needs: [ gate, image ] | |
| permissions: | |
| contents: read | |
| id-token: write | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| IMAGE: docker/docker-agent | |
| TEMPLATE: docker/docker-agent-sbx-templates | |
| IMAGE_DIGEST: ${{ needs.image.outputs.image-digest }} | |
| TEMPLATE_DIGEST: ${{ needs.image.outputs.template-digest }} | |
| steps: | |
| # imagetools talks to the registry directly; no builder needed. | |
| - uses: $/.github/actions/setup-buildx | |
| with: | |
| connection-id: ${{ vars.DOCKERHUB_OIDC_CONNECTION_ID }} | |
| builder: 'false' | |
| - name: Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 | |
| with: | |
| images: ${{ env.IMAGE }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=edge | |
| - name: Tag image | |
| env: | |
| VERSION: ${{ steps.meta.outputs.version }} | |
| run: | | |
| : "${IMAGE_DIGEST:?image produced no digest}" | |
| mapfile -t tags < <(jq -r '.tags[]' <<< "$DOCKER_METADATA_OUTPUT_JSON") | |
| args=() | |
| for tag in "${tags[@]}"; do args+=(-t "$tag"); done | |
| docker buildx imagetools create "${args[@]}" "${IMAGE}@${IMAGE_DIGEST}" | |
| docker buildx imagetools inspect "${IMAGE}:${VERSION}" | |
| - name: Tag template | |
| run: | | |
| : "${TEMPLATE_DIGEST:?image produced no template digest}" | |
| if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then | |
| version="${GITHUB_REF_NAME#v}" | |
| tags=(-t "${TEMPLATE}:${version}" -t "${TEMPLATE}:latest") | |
| else | |
| version=edge | |
| tags=(-t "${TEMPLATE}:edge") | |
| fi | |
| docker buildx imagetools create "${tags[@]}" "${TEMPLATE}@${TEMPLATE_DIGEST}" | |
| docker buildx imagetools inspect "${TEMPLATE}:${version}" |