fix(craft): document webapp preview base path and real lint/typecheck… #1089
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
| name: Build and Push Docker Images on Tag | |
| on: | |
| push: | |
| tags: | |
| - "*" | |
| workflow_dispatch: | |
| # Set restrictive default permissions for all jobs. Jobs that need more permissions | |
| # should explicitly declare them. | |
| permissions: | |
| # Required to checkout the repo on private repos (no-op on public) | |
| contents: read | |
| # Required for OIDC authentication with AWS | |
| id-token: write # zizmor: ignore[excessive-permissions] | |
| env: | |
| EDGE_TAG: ${{ startsWith(github.ref_name, 'nightly-latest') || github.ref_name == 'edge' }} | |
| jobs: | |
| # Determine which components to build based on the tag | |
| determine-builds: | |
| # NOTE: Github-hosted runners have about 20s faster queue times and are preferred here. | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 90 | |
| outputs: | |
| build-desktop: ${{ steps.check.outputs.build-desktop }} | |
| build-web: ${{ steps.check.outputs.build-web }} | |
| build-web-cloud: ${{ steps.check.outputs.build-web-cloud }} | |
| build-backend: ${{ steps.check.outputs.build-backend }} | |
| build-model-server: ${{ steps.check.outputs.build-model-server }} | |
| is-cloud-tag: ${{ steps.check.outputs.is-cloud-tag }} | |
| is-beta: ${{ steps.check.outputs.is-beta }} | |
| is-beta-standalone: ${{ steps.check.outputs.is-beta-standalone }} | |
| is-stable: ${{ steps.check.outputs.is-stable }} | |
| is-latest: ${{ steps.check.outputs.is-latest }} | |
| is-test-run: ${{ steps.check.outputs.is-test-run }} | |
| sanitized-tag: ${{ steps.check.outputs.sanitized-tag }} | |
| short-sha: ${{ steps.check.outputs.short-sha }} | |
| steps: | |
| - name: Checkout (for git tags) | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0 | |
| with: | |
| version: "0.11.25" | |
| enable-cache: false | |
| - name: Check which components to build and version info | |
| id: check | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| set -eo pipefail | |
| TAG="${GITHUB_REF_NAME}" | |
| # Sanitize tag name by replacing slashes with hyphens (for Docker tag compatibility) | |
| SANITIZED_TAG=$(echo "$TAG" | tr '/' '-') | |
| SHORT_SHA="${GITHUB_SHA::7}" | |
| # Initialize all flags to false | |
| IS_CLOUD=false | |
| IS_NIGHTLY=false | |
| IS_VERSION_TAG=false | |
| IS_STABLE=false | |
| IS_BETA=false | |
| IS_BETA_STANDALONE=false | |
| IS_LATEST=false | |
| IS_PROD_TAG=false | |
| IS_TEST_RUN=false | |
| BUILD_DESKTOP=false | |
| BUILD_WEB=false | |
| BUILD_WEB_CLOUD=false | |
| BUILD_BACKEND=true | |
| BUILD_MODEL_SERVER=true | |
| # Determine tag type based on pattern matching (do regex checks once) | |
| if [[ "$TAG" == *cloud* ]]; then | |
| IS_CLOUD=true | |
| fi | |
| if [[ "$TAG" == nightly* ]]; then | |
| IS_NIGHTLY=true | |
| fi | |
| if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then | |
| IS_VERSION_TAG=true | |
| fi | |
| if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| IS_STABLE=true | |
| fi | |
| if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-beta(\.[0-9]+)?$ ]]; then | |
| IS_BETA=true | |
| fi | |
| # Determine what to build based on tag type | |
| if [[ "$IS_CLOUD" == "true" ]]; then | |
| BUILD_WEB_CLOUD=true | |
| else | |
| BUILD_WEB=true | |
| # Only build desktop for semver tags (excluding beta) | |
| if [[ "$IS_VERSION_TAG" == "true" ]] && [[ "$IS_BETA" != "true" ]]; then | |
| BUILD_DESKTOP=true | |
| fi | |
| fi | |
| # Standalone version checks (for backend/model-server - version excluding cloud tags) | |
| if [[ "$IS_BETA" == "true" ]] && [[ "$IS_CLOUD" != "true" ]]; then | |
| IS_BETA_STANDALONE=true | |
| fi | |
| # Determine if this tag should get the "latest" Docker tag. | |
| # Only the highest semver stable tag (vX.Y.Z exactly) gets "latest". | |
| if [[ "$IS_STABLE" == "true" ]]; then | |
| HIGHEST_STABLE=$(uv run --no-sync --with onyx-devtools ods latest-stable-tag) || { | |
| echo "::error::Failed to determine highest stable tag via 'ods latest-stable-tag'" | |
| exit 1 | |
| } | |
| if [[ "$TAG" == "$HIGHEST_STABLE" ]]; then | |
| IS_LATEST=true | |
| fi | |
| fi | |
| # Determine if this is a production tag | |
| # Production tags are: version tags (v1.2.3*) or nightly tags | |
| if [[ "$IS_VERSION_TAG" == "true" ]] || [[ "$IS_NIGHTLY" == "true" ]]; then | |
| IS_PROD_TAG=true | |
| fi | |
| # Determine if this is a test run (workflow_dispatch on non-production ref) | |
| if [[ "$EVENT_NAME" == "workflow_dispatch" ]] && [[ "$IS_PROD_TAG" != "true" ]]; then | |
| IS_TEST_RUN=true | |
| fi | |
| { | |
| echo "build-desktop=$BUILD_DESKTOP" | |
| echo "build-web=$BUILD_WEB" | |
| echo "build-web-cloud=$BUILD_WEB_CLOUD" | |
| echo "build-backend=$BUILD_BACKEND" | |
| echo "build-model-server=$BUILD_MODEL_SERVER" | |
| echo "is-cloud-tag=$IS_CLOUD" | |
| echo "is-beta=$IS_BETA" | |
| echo "is-beta-standalone=$IS_BETA_STANDALONE" | |
| echo "is-stable=$IS_STABLE" | |
| echo "is-latest=$IS_LATEST" | |
| echo "is-test-run=$IS_TEST_RUN" | |
| echo "sanitized-tag=$SANITIZED_TAG" | |
| echo "short-sha=$SHORT_SHA" | |
| } >> "$GITHUB_OUTPUT" | |
| # Block the release when dependencies carry unignored critical vulnerabilities. | |
| # Runs the same `ods audit` gate used on PRs and nightly. Always runs (no skip | |
| # condition) so the build jobs that depend on it aren't skipped on test runs; | |
| # the audit itself degrades gracefully when the S3 allowlist or Dependabot API | |
| # is unavailable. | |
| audit-gate: | |
| needs: [determine-builds] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read # checkout + read lockfiles | |
| id-token: write # OIDC for fetching the S3 allowlist | |
| security-events: read # read Dependabot alerts | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0 | |
| with: | |
| version: "0.11.25" | |
| enable-cache: false | |
| - name: Configure AWS credentials | |
| continue-on-error: true # the audit still runs (with no suppressions) if creds are unavailable | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d # ratchet:aws-actions/configure-aws-credentials@v6.2.2 | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Run dependency audit | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: uv run --no-sync --with onyx-devtools ods audit --fail-on=critical | |
| check-version-tag: | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 10 | |
| if: ${{ !startsWith(github.ref_name, 'nightly-latest') && github.ref_name != 'edge' && github.event_name != 'workflow_dispatch' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0 | |
| with: | |
| version: "0.11.25" | |
| # NOTE: This isn't caching much and zizmor suggests this could be poisoned, so disable. | |
| enable-cache: false | |
| - name: Validate tag is versioned correctly | |
| run: | | |
| uv run --no-sync --with release-tag tag --check | |
| notify-slack-on-tag-check-failure: | |
| needs: | |
| - check-version-tag | |
| if: always() && needs.check-version-tag.result == 'failure' && github.event_name != 'workflow_dispatch' | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 10 | |
| environment: release | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Send Slack notification | |
| uses: ./.github/actions/slack-notify | |
| with: | |
| webhook-url: ${{ secrets.MONITOR_DEPLOYMENTS_WEBHOOK }} | |
| failed-jobs: "• check-version-tag" | |
| title: "🚨 Version Tag Check Failed" | |
| ref-name: ${{ github.ref_name }} | |
| # Create GitHub release first, before desktop builds start. | |
| # This ensures all desktop matrix jobs upload to the same release instead of | |
| # racing to create duplicate releases. | |
| create-release: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-desktop == 'true' | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| outputs: | |
| release-id: ${{ steps.create-release.outputs.id }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Determine release tag | |
| id: release-tag | |
| env: | |
| IS_TEST_RUN: ${{ needs.determine-builds.outputs.is-test-run }} | |
| SHORT_SHA: ${{ needs.determine-builds.outputs.short-sha }} | |
| run: | | |
| if [ "${IS_TEST_RUN}" == "true" ]; then | |
| echo "tag=v0.0.0-dev+${SHORT_SHA}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create GitHub Release | |
| id: create-release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.release-tag.outputs.tag }} | |
| run: | | |
| # Look up an existing release (including drafts) by tag name. | |
| # | |
| # NOTE: a draft release does not create the underlying git tag until | |
| # it is published, so `GET /releases/tags/{tag}` (and | |
| # `gh release view <tag>`) returns 404 for drafts. We must list | |
| # releases instead — that endpoint DOES include drafts — and match | |
| # on tag_name. | |
| get_release_id() { | |
| gh api --paginate "repos/${GITHUB_REPOSITORY}/releases" \ | |
| --jq ".[] | select(.tag_name == \"${TAG}\") | .id" | head -n1 | |
| } | |
| release_id=$(get_release_id) | |
| if [ -z "$release_id" ]; then | |
| release_id=$(gh api --method POST "repos/${GITHUB_REPOSITORY}/releases" \ | |
| -f tag_name="$TAG" \ | |
| -f name="$TAG" \ | |
| -f body="See the assets to download this version and install." \ | |
| -F draft=true \ | |
| --jq '.id') | |
| fi | |
| if [ -z "$release_id" ]; then | |
| echo "::error::Failed to resolve release id for tag ${TAG}" | |
| exit 1 | |
| fi | |
| echo "id=${release_id}" >> "$GITHUB_OUTPUT" | |
| build-desktop: | |
| needs: | |
| - determine-builds | |
| - create-release | |
| if: needs.determine-builds.outputs.build-desktop == 'true' | |
| permissions: | |
| id-token: write | |
| contents: write | |
| actions: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: "macos-latest" # Build a universal image for macOS. | |
| args: "--target universal-apple-darwin" | |
| rust-targets: "aarch64-apple-darwin,x86_64-apple-darwin" | |
| - platform: "ubuntu-24.04" | |
| args: "--bundles deb,rpm" | |
| - platform: "ubuntu-24.04-arm" # Only available in public repos. | |
| args: "--bundles deb,rpm" | |
| - platform: "windows-latest" | |
| args: "" | |
| # Cross-compiled Windows ARM64 build. Only the NSIS bundle supports | |
| # ARM64 (WiX/MSI does not), hence --bundles nsis. | |
| - platform: "windows-latest" | |
| args: "--target aarch64-pc-windows-msvc --bundles nsis" | |
| rust-targets: "aarch64-pc-windows-msvc" | |
| runs-on: ${{ matrix.platform }} | |
| timeout-minutes: 90 | |
| environment: release | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v7.0.0 | |
| with: | |
| # NOTE: persist-credentials is needed for tauri-action to upload assets to GitHub releases. | |
| persist-credentials: true # zizmor: ignore[artipacked] | |
| - name: Configure AWS credentials | |
| if: startsWith(matrix.platform, 'macos-') | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| if: startsWith(matrix.platform, 'macos-') | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| APPLE_ID, deploy/apple-id | |
| APPLE_PASSWORD, deploy/apple-password | |
| APPLE_CERTIFICATE, deploy/apple-certificate | |
| APPLE_CERTIFICATE_PASSWORD, deploy/apple-certificate-password | |
| KEYCHAIN_PASSWORD, deploy/keychain-password | |
| APPLE_TEAM_ID, deploy/apple-team-id | |
| parse-json-secrets: true | |
| - name: install dependencies (ubuntu only) | |
| if: startsWith(matrix.platform, 'ubuntu-') | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| libglib2.0-dev \ | |
| libgirepository1.0-dev \ | |
| libgtk-3-dev \ | |
| libjavascriptcoregtk-4.1-dev \ | |
| libwebkit2gtk-4.1-dev \ | |
| libayatana-appindicator3-dev \ | |
| gobject-introspection \ | |
| pkg-config \ | |
| curl \ | |
| xdg-utils | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # ratchet:oven-sh/setup-bun@v2 # zizmor: ignore[cache-poisoning] | |
| with: | |
| bun-version: "1.3.13" | |
| - name: install Rust stable | |
| uses: dtolnay/rust-toolchain@6d9817901c499d6b02debbb57edb38d33daa680b # zizmor: ignore[impostor-commit] | |
| with: | |
| # Extra targets for jobs that cross-compile (macOS universal, Windows ARM64). | |
| # Jobs building only for the host architecture leave this empty. | |
| targets: ${{ matrix.rust-targets || '' }} | |
| - name: install frontend dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Inject version (Unix) | |
| if: runner.os != 'Windows' | |
| working-directory: ./desktop | |
| env: | |
| SHORT_SHA: ${{ needs.determine-builds.outputs.short-sha }} | |
| IS_TEST_RUN: ${{ needs.determine-builds.outputs.is-test-run }} | |
| run: | | |
| if [ "${IS_TEST_RUN}" == "true" ]; then | |
| VERSION="0.0.0-dev+${SHORT_SHA}" | |
| else | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| fi | |
| echo "Injecting version: $VERSION" | |
| # Update Cargo.toml | |
| sed "s/^version = .*/version = \"$VERSION\"/" src-tauri/Cargo.toml > src-tauri/Cargo.toml.tmp | |
| mv src-tauri/Cargo.toml.tmp src-tauri/Cargo.toml | |
| # Update tauri.conf.json | |
| jq --arg v "$VERSION" '.version = $v' src-tauri/tauri.conf.json > src-tauri/tauri.conf.json.tmp | |
| mv src-tauri/tauri.conf.json.tmp src-tauri/tauri.conf.json | |
| # Update package.json | |
| jq --arg v "$VERSION" '.version = $v' package.json > package.json.tmp | |
| mv package.json.tmp package.json | |
| echo "Versions set to: $VERSION" | |
| - name: Inject version (Windows) | |
| if: runner.os == 'Windows' | |
| working-directory: ./desktop | |
| shell: pwsh | |
| env: | |
| IS_TEST_RUN: ${{ needs.determine-builds.outputs.is-test-run }} | |
| run: | | |
| # Windows MSI requires numeric-only build metadata, so we skip the SHA suffix | |
| if ($env:IS_TEST_RUN -eq "true") { | |
| $VERSION = "0.0.0" | |
| } else { | |
| # Strip 'v' prefix and any pre-release suffix (e.g., -beta.13) for MSI compatibility | |
| $VERSION = "$env:GITHUB_REF_NAME" -replace '^v', '' -replace '-.*$', '' | |
| } | |
| Write-Host "Injecting version: $VERSION" | |
| # Update Cargo.toml | |
| $cargo = Get-Content src-tauri/Cargo.toml -Raw | |
| $cargo = $cargo -replace '(?m)^version = .*', "version = `"$VERSION`"" | |
| Set-Content src-tauri/Cargo.toml $cargo -NoNewline | |
| # Update tauri.conf.json | |
| $json = Get-Content src-tauri/tauri.conf.json | ConvertFrom-Json | |
| $json.version = $VERSION | |
| $json | ConvertTo-Json -Depth 100 | Set-Content src-tauri/tauri.conf.json | |
| # Update package.json | |
| $pkg = Get-Content package.json | ConvertFrom-Json | |
| $pkg.version = $VERSION | |
| $pkg | ConvertTo-Json -Depth 100 | Set-Content package.json | |
| Write-Host "Versions set to: $VERSION" | |
| - name: Import Apple Developer Certificate | |
| if: startsWith(matrix.platform, 'macos-') | |
| run: | | |
| echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security set-keychain-settings -t 3600 -u build.keychain | |
| security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| security find-identity -v -p codesigning build.keychain | |
| - name: Verify Certificate | |
| if: startsWith(matrix.platform, 'macos-') | |
| run: | | |
| CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep -E "(Developer ID Application|Apple Distribution|Apple Development)" | head -n 1) | |
| CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') | |
| echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV | |
| echo "Certificate imported." | |
| - uses: tauri-apps/tauri-action@1deb371b0cd8bd54025b384f1cd735e725c4060f # ratchet:tauri-apps/tauri-action@action-v1.0.0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| APPLE_ID: ${{ env.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ env.APPLE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }} | |
| APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} | |
| with: | |
| projectPath: desktop | |
| # Use the release created by the create-release job to avoid race conditions | |
| # when multiple matrix jobs try to create/update the same release simultaneously | |
| releaseId: ${{ needs.create-release.outputs.release-id }} | |
| assetNamePattern: "[name]_[arch][ext]" | |
| args: ${{ matrix.args }} | |
| build-web-amd64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-web == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-web-amd64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-web-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| # web/Dockerfile pulls its hardened Node base from dhi.io, authenticated with the same | |
| # Docker account credentials (the account must have access to the DHI catalog). | |
| - name: Login to Docker Hardened Images (dhi.io) | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| registry: dhi.io | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push AMD64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./web | |
| file: ./web/Dockerfile | |
| platforms: linux/amd64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| NODE_OPTIONS=--max-old-space-size=8192 | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| build-web-arm64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-web == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-arm64 | |
| - run-id=${{ github.run_id }}-web-arm64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-web-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| # web/Dockerfile pulls its hardened Node base from dhi.io, authenticated with the same | |
| # Docker account credentials (the account must have access to the DHI catalog). | |
| - name: Login to Docker Hardened Images (dhi.io) | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| registry: dhi.io | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push ARM64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./web | |
| file: ./web/Dockerfile | |
| platforms: linux/arm64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| NODE_OPTIONS=--max-old-space-size=8192 | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| merge-web: | |
| needs: | |
| - determine-builds | |
| - build-web-amd64 | |
| - build-web-arm64 | |
| - image-audit | |
| if: always() && needs.build-web-amd64.result == 'success' && needs.build-web-arm64.result == 'success' && needs.image-audit.result == 'success' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-merge-web | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-web-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('web-{0}', needs.determine-builds.outputs.sanitized-tag) || github.ref_name }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta == 'true' && 'beta' || '' }} | |
| type=semver,pattern={{version}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| # Same tag set with a -dev suffix. Only the backend has a genuinely different dev image | |
| # (runtime + debugging tools); the web -dev tags point at the same manifest as their | |
| # plain counterparts so that one version string (IMAGE_TAG / helm global.version) selects | |
| # a whole deployment. The suffix is spelled out per tag rather than via flavor `suffix=` | |
| # so that disabled (empty) raw tags stay empty instead of degenerating to a bare "-dev". | |
| - name: Docker meta (dev) | |
| id: meta-dev | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('web-{0}-dev', needs.determine-builds.outputs.sanitized-tag) || format('{0}-dev', github.ref_name) }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta == 'true' && 'beta-dev' || '' }} | |
| type=semver,pattern={{version}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| - name: Create and push manifest | |
| env: | |
| IMAGE_REPO: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| AMD64_DIGEST: ${{ needs.build-web-amd64.outputs.digest }} | |
| ARM64_DIGEST: ${{ needs.build-web-arm64.outputs.digest }} | |
| META_TAGS: ${{ steps.meta.outputs.tags }} | |
| META_DEV_TAGS: ${{ steps.meta-dev.outputs.tags }} | |
| run: | | |
| IMAGES="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| $(printf '%s\n%s\n' "${META_TAGS}" "${META_DEV_TAGS}" | sed '/^$/d' | xargs -I {} echo -t {}) \ | |
| $IMAGES | |
| build-web-cloud-amd64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-web-cloud == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-web-cloud-amd64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-web-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| # web/Dockerfile pulls its hardened Node base from dhi.io, authenticated with the same | |
| # Docker account credentials (the account must have access to the DHI catalog). | |
| - name: Login to Docker Hardened Images (dhi.io) | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| registry: dhi.io | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push AMD64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./web | |
| file: ./web/Dockerfile | |
| platforms: linux/amd64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| NEXT_PUBLIC_CLOUD_ENABLED=true | |
| WEB_FRAME_PROTECTION_ENABLED=false | |
| NEXT_PUBLIC_POSTHOG_KEY=${{ secrets.POSTHOG_KEY }} | |
| NEXT_PUBLIC_POSTHOG_HOST=${{ secrets.POSTHOG_HOST }} | |
| NEXT_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }} | |
| NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${{ secrets.STRIPE_PUBLISHABLE_KEY }} | |
| NEXT_PUBLIC_RECAPTCHA_SITE_KEY=${{ vars.NEXT_PUBLIC_RECAPTCHA_SITE_KEY }} | |
| NEXT_PUBLIC_GTM_ENABLED=true | |
| NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=true | |
| NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=true | |
| NODE_OPTIONS=--max-old-space-size=8192 | |
| SENTRY_RELEASE=${{ github.sha }} | |
| secrets: | | |
| sentry_auth_token=${{ secrets.SENTRY_AUTH_TOKEN }} | |
| cache-from: type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| build-web-cloud-arm64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-web-cloud == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-arm64 | |
| - run-id=${{ github.run_id }}-web-cloud-arm64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-web-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| # web/Dockerfile pulls its hardened Node base from dhi.io, authenticated with the same | |
| # Docker account credentials (the account must have access to the DHI catalog). | |
| - name: Login to Docker Hardened Images (dhi.io) | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| registry: dhi.io | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push ARM64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./web | |
| file: ./web/Dockerfile | |
| platforms: linux/arm64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| NEXT_PUBLIC_CLOUD_ENABLED=true | |
| WEB_FRAME_PROTECTION_ENABLED=false | |
| NEXT_PUBLIC_POSTHOG_KEY=${{ secrets.POSTHOG_KEY }} | |
| NEXT_PUBLIC_POSTHOG_HOST=${{ secrets.POSTHOG_HOST }} | |
| NEXT_PUBLIC_SENTRY_DSN=${{ secrets.SENTRY_DSN }} | |
| NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${{ secrets.STRIPE_PUBLISHABLE_KEY }} | |
| NEXT_PUBLIC_RECAPTCHA_SITE_KEY=${{ vars.NEXT_PUBLIC_RECAPTCHA_SITE_KEY }} | |
| NEXT_PUBLIC_GTM_ENABLED=true | |
| NEXT_PUBLIC_FORGOT_PASSWORD_ENABLED=true | |
| NEXT_PUBLIC_INCLUDE_ERROR_POPUP_SUPPORT_LINK=true | |
| NODE_OPTIONS=--max-old-space-size=8192 | |
| SENTRY_RELEASE=${{ github.sha }} | |
| secrets: | | |
| sentry_auth_token=${{ secrets.SENTRY_AUTH_TOKEN }} | |
| cache-from: type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| merge-web-cloud: | |
| needs: | |
| - determine-builds | |
| - build-web-cloud-amd64 | |
| - build-web-cloud-arm64 | |
| - image-audit | |
| if: always() && needs.build-web-cloud-amd64.result == 'success' && needs.build-web-cloud-arm64.result == 'success' && needs.image-audit.result == 'success' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-merge-web-cloud | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-web-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('web-cloud-{0}', needs.determine-builds.outputs.sanitized-tag) || github.ref_name }} | |
| # -dev twin of the tag above, pointing at the same manifest — see the merge-web dev note. | |
| # Cloud tags build the web image here rather than in merge-web, so without this a cloud | |
| # deployment couldn't set a single -dev version across all of its images. | |
| - name: Docker meta (dev) | |
| id: meta-dev | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('web-cloud-{0}-dev', needs.determine-builds.outputs.sanitized-tag) || format('{0}-dev', github.ref_name) }} | |
| - name: Create and push manifest | |
| env: | |
| IMAGE_REPO: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| AMD64_DIGEST: ${{ needs.build-web-cloud-amd64.outputs.digest }} | |
| ARM64_DIGEST: ${{ needs.build-web-cloud-arm64.outputs.digest }} | |
| META_TAGS: ${{ steps.meta.outputs.tags }} | |
| META_DEV_TAGS: ${{ steps.meta-dev.outputs.tags }} | |
| run: | | |
| IMAGES="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| $(printf '%s\n%s\n' "${META_TAGS}" "${META_DEV_TAGS}" | sed '/^$/d' | xargs -I {} echo -t {}) \ | |
| $IMAGES | |
| build-backend-amd64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-backend == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-backend-amd64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| digest-dev: ${{ steps.build-dev.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-backend | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push AMD64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile | |
| target: runtime | |
| platforms: linux/amd64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| # Dev variant: runtime + interactive debugging tools, published with a -dev tag suffix by | |
| # merge-backend. Reuses the runtime stage from the build above via the local BuildKit | |
| # cache, so this only builds and pushes the extra apt layer. | |
| - name: Build and push AMD64 dev | |
| id: build-dev | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile | |
| target: dev | |
| platforms: linux/amd64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge-dev | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| build-backend-arm64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-backend == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-arm64 | |
| - run-id=${{ github.run_id }}-backend-arm64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| digest-dev: ${{ steps.build-dev.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-backend | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push ARM64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile | |
| target: runtime | |
| platforms: linux/arm64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| # Dev variant: runtime + interactive debugging tools, published with a -dev tag suffix by | |
| # merge-backend. Reuses the runtime stage from the build above via the local BuildKit | |
| # cache, so this only builds and pushes the extra apt layer. | |
| - name: Build and push ARM64 dev | |
| id: build-dev | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile | |
| target: dev | |
| platforms: linux/arm64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge-dev | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| merge-backend: | |
| needs: | |
| - determine-builds | |
| - build-backend-amd64 | |
| - build-backend-arm64 | |
| - image-audit | |
| if: always() && needs.build-backend-amd64.result == 'success' && needs.build-backend-arm64.result == 'success' && needs.image-audit.result == 'success' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-merge-backend | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-backend | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('backend-{0}', needs.determine-builds.outputs.sanitized-tag) || github.ref_name }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta' || '' }} | |
| type=semver,pattern={{version}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| # Same tag set with a -dev suffix, for the dev image variant (runtime + debugging tools). | |
| # The suffix is spelled out per tag rather than via flavor `suffix=` so that disabled | |
| # (empty) raw tags stay empty instead of degenerating to a bare "-dev" tag. | |
| - name: Docker meta (dev) | |
| id: meta-dev | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('backend-{0}-dev', needs.determine-builds.outputs.sanitized-tag) || format('{0}-dev', github.ref_name) }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta-dev' || '' }} | |
| type=semver,pattern={{version}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| - name: Create and push manifest | |
| env: | |
| IMAGE_REPO: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| AMD64_DIGEST: ${{ needs.build-backend-amd64.outputs.digest }} | |
| ARM64_DIGEST: ${{ needs.build-backend-arm64.outputs.digest }} | |
| META_TAGS: ${{ steps.meta.outputs.tags }} | |
| run: | | |
| IMAGES="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| $(printf '%s\n' "${META_TAGS}" | xargs -I {} echo -t {}) \ | |
| $IMAGES | |
| - name: Create and push dev manifest | |
| env: | |
| IMAGE_REPO: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| AMD64_DIGEST: ${{ needs.build-backend-amd64.outputs.digest-dev }} | |
| ARM64_DIGEST: ${{ needs.build-backend-arm64.outputs.digest-dev }} | |
| META_TAGS: ${{ steps.meta-dev.outputs.tags }} | |
| run: | | |
| IMAGES="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| $(printf '%s\n' "${META_TAGS}" | xargs -I {} echo -t {}) \ | |
| $IMAGES | |
| build-model-server-amd64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-model-server == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-model-server-amd64 | |
| - volume=40gb | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-model-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| with: | |
| buildkitd-flags: ${{ vars.DOCKER_DEBUG == 'true' && '--debug' || '' }} | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| # Dockerfile.model_server pulls its hardened Python base from dhi.io, authenticated | |
| # with the same Docker account credentials (the account must have DHI catalog access). | |
| - name: Login to Docker Hardened Images (dhi.io) | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| registry: dhi.io | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push AMD64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| env: | |
| DEBUG: ${{ vars.DOCKER_DEBUG == 'true' && 1 || 0 }} | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile.model_server | |
| platforms: linux/amd64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ env.EDGE_TAG != 'true' && vars.MODEL_SERVER_NO_CACHE == 'true' }} | |
| build-model-server-arm64: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.build-model-server == 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-arm64 | |
| - run-id=${{ github.run_id }}-model-server-arm64 | |
| - volume=40gb | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-model-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| with: | |
| buildkitd-flags: ${{ vars.DOCKER_DEBUG == 'true' && '--debug' || '' }} | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| # Dockerfile.model_server pulls its hardened Python base from dhi.io, authenticated | |
| # with the same Docker account credentials (the account must have DHI catalog access). | |
| - name: Login to Docker Hardened Images (dhi.io) | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| registry: dhi.io | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push ARM64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| env: | |
| DEBUG: ${{ vars.DOCKER_DEBUG == 'true' && 1 || 0 }} | |
| with: | |
| context: ./backend | |
| file: ./backend/Dockerfile.model_server | |
| platforms: linux/arm64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| ONYX_VERSION=${{ github.ref_name }} | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:edge | |
| type=registry,ref=${{ env.REGISTRY_IMAGE }}:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ env.EDGE_TAG != 'true' && vars.MODEL_SERVER_NO_CACHE == 'true' }} | |
| merge-model-server: | |
| needs: | |
| - determine-builds | |
| - build-model-server-amd64 | |
| - build-model-server-arm64 | |
| - image-audit | |
| if: always() && needs.build-model-server-amd64.result == 'success' && needs.build-model-server-arm64.result == 'success' && needs.image-audit.result == 'success' | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-merge-model-server | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/onyx-model-server | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('model-server-{0}', needs.determine-builds.outputs.sanitized-tag) || github.ref_name }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta' || '' }} | |
| type=semver,pattern={{version}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| # -dev twins of the tags above, pointing at the same manifest — see the merge-web dev note. | |
| - name: Docker meta (dev) | |
| id: meta-dev | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('model-server-{0}-dev', needs.determine-builds.outputs.sanitized-tag) || format('{0}-dev', github.ref_name) }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta-dev' || '' }} | |
| type=semver,pattern={{version}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| - name: Create and push manifest | |
| env: | |
| IMAGE_REPO: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| AMD64_DIGEST: ${{ needs.build-model-server-amd64.outputs.digest }} | |
| ARM64_DIGEST: ${{ needs.build-model-server-arm64.outputs.digest }} | |
| META_TAGS: ${{ steps.meta.outputs.tags }} | |
| META_DEV_TAGS: ${{ steps.meta-dev.outputs.tags }} | |
| run: | | |
| IMAGES="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| $(printf '%s\n%s\n' "${META_TAGS}" "${META_DEV_TAGS}" | sed '/^$/d' | xargs -I {} echo -t {}) \ | |
| $IMAGES | |
| prepare-sandbox: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| if: needs.determine-builds.outputs.is-test-run == 'true' || (needs.determine-builds.outputs.is-stable == 'true' || needs.determine-builds.outputs.is-beta-standalone == 'true' || needs.determine-builds.outputs.is-cloud-tag == 'true' || startsWith(github.ref_name, 'nightly-latest') || github.ref_name == 'edge') | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 10 | |
| environment: release | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| context-tag: ${{ steps.context.outputs.context-tag }} | |
| context-exists: ${{ steps.exists.outputs.context-exists }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/sandbox | |
| SANDBOX_CONTEXT: backend/onyx/server/features/build/sandbox/image | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Compute sandbox context tag | |
| id: context | |
| run: | | |
| set -euo pipefail | |
| digest="$(git ls-files -s -z "$SANDBOX_CONTEXT" | sort -z | sha256sum | cut -d' ' -f1)" | |
| echo "context-tag=ctx-${digest:0:20}" >> "$GITHUB_OUTPUT" | |
| - name: Configure AWS credentials | |
| if: needs.determine-builds.outputs.is-test-run != 'true' && vars.DOCKER_NO_CACHE != 'true' | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| if: needs.determine-builds.outputs.is-test-run != 'true' && vars.DOCKER_NO_CACHE != 'true' | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Login to Docker Hub | |
| if: needs.determine-builds.outputs.is-test-run != 'true' && vars.DOCKER_NO_CACHE != 'true' | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Check for existing context image | |
| id: exists | |
| env: | |
| CONTEXT_TAG: ${{ steps.context.outputs.context-tag }} | |
| DOCKER_NO_CACHE: ${{ vars.DOCKER_NO_CACHE == 'true' && 'true' || 'false' }} | |
| IS_TEST_RUN: ${{ needs.determine-builds.outputs.is-test-run }} | |
| run: | | |
| if [ "${IS_TEST_RUN}" = "true" ] || [ "${DOCKER_NO_CACHE}" = "true" ]; then | |
| echo "context-exists=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if docker buildx imagetools inspect "${REGISTRY_IMAGE}:${CONTEXT_TAG}" >/dev/null 2>&1; then | |
| echo "context-exists=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "context-exists=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| build-sandbox-amd64: | |
| needs: | |
| - determine-builds | |
| - prepare-sandbox | |
| if: needs.prepare-sandbox.result == 'success' && needs.prepare-sandbox.outputs.context-exists != 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-sandbox-amd64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/sandbox | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push AMD64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./backend/onyx/server/features/build/sandbox/image | |
| file: ./backend/onyx/server/features/build/sandbox/image/Dockerfile | |
| platforms: linux/amd64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: | | |
| type=registry,ref=${{ env.BASE_IMAGE_REGISTRY }}/onyxdotapp/sandbox:edge | |
| type=registry,ref=${{ env.BASE_IMAGE_REGISTRY }}/onyxdotapp/sandbox:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| build-sandbox-arm64: | |
| needs: | |
| - determine-builds | |
| - prepare-sandbox | |
| if: needs.prepare-sandbox.result == 'success' && needs.prepare-sandbox.outputs.context-exists != 'true' | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-arm64 | |
| - run-id=${{ github.run_id }}-sandbox-arm64 | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/sandbox | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Build and push ARM64 | |
| id: build | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: ./backend/onyx/server/features/build/sandbox/image | |
| file: ./backend/onyx/server/features/build/sandbox/image/Dockerfile | |
| platforms: linux/arm64 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: | | |
| type=registry,ref=${{ env.BASE_IMAGE_REGISTRY }}/onyxdotapp/sandbox:edge | |
| type=registry,ref=${{ env.BASE_IMAGE_REGISTRY }}/onyxdotapp/sandbox:latest | |
| cache-to: type=inline | |
| outputs: type=image,name=${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| merge-sandbox: | |
| needs: | |
| - determine-builds | |
| - prepare-sandbox | |
| - build-sandbox-amd64 | |
| - build-sandbox-arm64 | |
| - image-audit | |
| if: always() && needs.prepare-sandbox.result == 'success' && needs.image-audit.result == 'success' && (needs.prepare-sandbox.outputs.context-exists == 'true' || (needs.build-sandbox-amd64.result == 'success' && needs.build-sandbox-arm64.result == 'success')) | |
| runs-on: | |
| - runs-on | |
| - runner=2cpu-linux-x64 | |
| - run-id=${{ github.run_id }}-merge-sandbox | |
| - extras=ecr-cache | |
| timeout-minutes: 90 | |
| environment: release | |
| permissions: | |
| id-token: write | |
| env: | |
| REGISTRY_IMAGE: onyxdotapp/sandbox | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Get AWS Secrets | |
| uses: aws-actions/aws-secretsmanager-get-secrets@2cb1a461cbd4865ac4299648312e4704c646cd53 | |
| with: | |
| secret-ids: | | |
| DOCKER_USERNAME, deploy/docker-username | |
| DOCKER_TOKEN, deploy/docker-token | |
| parse-json-secrets: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ env.DOCKER_USERNAME }} | |
| password: ${{ env.DOCKER_TOKEN }} | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('sandbox-{0}', needs.determine-builds.outputs.sanitized-tag) || github.ref_name }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta' || '' }} | |
| type=semver,pattern={{version}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}},enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| # -dev twins of the tags above, pointing at the same manifest — see the merge-web dev note. | |
| # The sandbox image resolves off the same version knob as the rest of the deployment | |
| # (IMAGE_TAG in compose, global.version in the helm chart), so it needs the twins too. | |
| - name: Docker meta (dev) | |
| id: meta-dev | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 | |
| with: | |
| images: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| flavor: | | |
| latest=false | |
| tags: | | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run == 'true' && format('sandbox-{0}-dev', needs.determine-builds.outputs.sanitized-tag) || format('{0}-dev', github.ref_name) }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-latest == 'true' && 'latest-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && env.EDGE_TAG == 'true' && 'edge-dev' || '' }} | |
| type=raw,value=${{ needs.determine-builds.outputs.is-test-run != 'true' && needs.determine-builds.outputs.is-beta-standalone == 'true' && 'beta-dev' || '' }} | |
| type=semver,pattern={{version}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}.{{minor}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| type=semver,pattern={{major}}-dev,enable=${{ needs.determine-builds.outputs.is-stable == 'true' }} | |
| - name: Create and push manifest | |
| env: | |
| IMAGE_REPO: ${{ needs.determine-builds.outputs.is-test-run == 'true' && env.RUNS_ON_ECR_CACHE || env.REGISTRY_IMAGE }} | |
| CONTEXT_TAG: ${{ needs.prepare-sandbox.outputs.context-tag }} | |
| AMD64_DIGEST: ${{ needs.build-sandbox-amd64.outputs.digest }} | |
| ARM64_DIGEST: ${{ needs.build-sandbox-arm64.outputs.digest }} | |
| META_TAGS: ${{ steps.meta.outputs.tags }} | |
| META_DEV_TAGS: ${{ steps.meta-dev.outputs.tags }} | |
| DOCKER_NO_CACHE: ${{ vars.DOCKER_NO_CACHE == 'true' && 'true' || 'false' }} | |
| IS_TEST_RUN: ${{ needs.determine-builds.outputs.is-test-run }} | |
| run: | | |
| mapfile -t tags < <(printf '%s\n%s\n' "${META_TAGS}" "${META_DEV_TAGS}" | sed '/^$/d') | |
| tag_args=() | |
| for tag in "${tags[@]}"; do | |
| tag_args+=("-t" "$tag") | |
| done | |
| if [[ "$IS_TEST_RUN" == "true" ]]; then | |
| if [[ -z "$AMD64_DIGEST" || -z "$ARM64_DIGEST" ]]; then | |
| echo "::error::Missing sandbox image digest(s); cannot create test manifest" | |
| exit 1 | |
| fi | |
| images="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| "${tag_args[@]}" \ | |
| $images | |
| elif [[ "$DOCKER_NO_CACHE" != "true" ]] && docker buildx imagetools inspect "${REGISTRY_IMAGE}:${CONTEXT_TAG}" >/dev/null 2>&1; then | |
| docker buildx imagetools create \ | |
| "${tag_args[@]}" \ | |
| "${REGISTRY_IMAGE}:${CONTEXT_TAG}" | |
| else | |
| if [[ -z "$AMD64_DIGEST" || -z "$ARM64_DIGEST" ]]; then | |
| echo "::error::Missing sandbox image digest(s); cannot create ${CONTEXT_TAG}" | |
| exit 1 | |
| fi | |
| tag_args=("-t" "${REGISTRY_IMAGE}:${CONTEXT_TAG}" "${tag_args[@]}") | |
| images="${IMAGE_REPO}@${AMD64_DIGEST} ${IMAGE_REPO}@${ARM64_DIGEST}" | |
| docker buildx imagetools create \ | |
| "${tag_args[@]}" \ | |
| $images | |
| fi | |
| dispatch-cloud-deployment: | |
| needs: | |
| - determine-builds | |
| - merge-web-cloud | |
| - merge-backend | |
| - merge-model-server | |
| - merge-sandbox | |
| if: >- | |
| always() | |
| && needs.merge-web-cloud.result == 'success' | |
| && needs.merge-backend.result == 'success' | |
| && needs.merge-model-server.result == 'success' | |
| && needs.merge-sandbox.result == 'success' | |
| && needs.determine-builds.outputs.is-cloud-tag == 'true' | |
| && needs.determine-builds.outputs.is-test-run != 'true' | |
| # NOTE: Github-hosted runners have about 20s faster queue times and are preferred here. | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 10 | |
| permissions: {} | |
| steps: | |
| - name: Resolve dispatch target | |
| id: target | |
| env: | |
| CLOUD_DEPLOYMENT_REPO: ${{ vars.CLOUD_DEPLOYMENT_REPO }} | |
| run: | | |
| if [ -z "$CLOUD_DEPLOYMENT_REPO" ]; then | |
| echo "::error::CLOUD_DEPLOYMENT_REPO is not set" | |
| exit 1 | |
| fi | |
| echo "owner=${CLOUD_DEPLOYMENT_REPO%%/*}" >> "$GITHUB_OUTPUT" | |
| echo "repo=${CLOUD_DEPLOYMENT_REPO#*/}" >> "$GITHUB_OUTPUT" | |
| - name: Mint GitHub App installation token | |
| id: app-token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 | |
| with: | |
| client-id: ${{ vars.CLOUD_DEPLOYMENT_APP_ID }} | |
| private-key: ${{ secrets.CLOUD_DEPLOYMENT_APP_PRIVATE_KEY }} | |
| # Scope the token to the same repo the dispatch targets, derived from CLOUD_DEPLOYMENT_REPO. | |
| owner: ${{ steps.target.outputs.owner }} | |
| repositories: ${{ steps.target.outputs.repo }} | |
| permission-contents: write | |
| - name: Trigger new-cloud-image dispatch | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| CLOUD_DEPLOYMENT_REPO: ${{ vars.CLOUD_DEPLOYMENT_REPO }} | |
| VERSION: ${{ github.ref_name }} | |
| run: | | |
| gh api "repos/${CLOUD_DEPLOYMENT_REPO}/dispatches" \ | |
| -f event_type=new-cloud-image \ | |
| -F "client_payload[version]=${VERSION}" | |
| # Scan each freshly built image (amd64 digest) via `ods audit image`, reusing | |
| # osv-scanner and the shared S3 allowlist from the dependency `audit-gate`. | |
| # Runs before merge-* and every merge-* depends on it, so an unsuppressed | |
| # CRITICAL blocks the public tags. SARIF goes to the Security tab regardless. | |
| image-audit: | |
| needs: | |
| - determine-builds | |
| - build-web-amd64 | |
| - build-web-cloud-amd64 | |
| - build-backend-amd64 | |
| - build-model-server-amd64 | |
| - build-sandbox-amd64 | |
| if: >- | |
| always() && !cancelled() && | |
| (needs.build-web-amd64.result == 'success' || | |
| needs.build-web-cloud-amd64.result == 'success' || | |
| needs.build-backend-amd64.result == 'success' || | |
| needs.build-model-server-amd64.result == 'success' || | |
| needs.build-sandbox-amd64.result == 'success') | |
| runs-on: | |
| - runs-on | |
| # amd64 to match the images scanned: `ods audit image` uses the docker CLI, | |
| # which won't pull an amd64 image onto an arm64 host. | |
| - runner=2cpu-linux-x64 | |
| # osv-scanner pulls the image and writes a full `docker save` tar (~2x its | |
| # size); size the root volume up so large images don't fill the disk. | |
| - volume=60gb | |
| - run-id=${{ github.run_id }}-image-audit-${{ matrix.component }} | |
| - extras=ecr-cache | |
| permissions: | |
| contents: read # checkout + uv project context | |
| id-token: write # OIDC for fetching the S3 allowlist | |
| security-events: write # SARIF uploads | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - component: web | |
| registry-image: onyxdotapp/onyx-web-server | |
| - component: web-cloud | |
| registry-image: onyxdotapp/onyx-web-server | |
| - component: backend | |
| registry-image: onyxdotapp/onyx-backend | |
| - component: model-server | |
| registry-image: onyxdotapp/onyx-model-server | |
| - component: sandbox | |
| registry-image: onyxdotapp/sandbox | |
| steps: | |
| - name: Check if this scan should run | |
| id: should-run | |
| run: | | |
| case "$COMPONENT" in | |
| web) RESULT="$BUILD_WEB" ;; | |
| web-cloud) RESULT="$BUILD_WEB_CLOUD" ;; | |
| backend) RESULT="$BUILD_BACKEND" ;; | |
| model-server) RESULT="$BUILD_MODEL_SERVER" ;; | |
| sandbox) RESULT="$BUILD_SANDBOX" ;; | |
| esac | |
| if [ "$RESULT" == "success" ]; then | |
| echo "run=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "run=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| COMPONENT: ${{ matrix.component }} | |
| BUILD_WEB: ${{ needs.build-web-amd64.result }} | |
| BUILD_WEB_CLOUD: ${{ needs.build-web-cloud-amd64.result }} | |
| BUILD_BACKEND: ${{ needs.build-backend-amd64.result }} | |
| BUILD_MODEL_SERVER: ${{ needs.build-model-server-amd64.result }} | |
| BUILD_SANDBOX: ${{ needs.build-sandbox-amd64.result }} | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| if: steps.should-run.outputs.run == 'true' | |
| - name: Checkout | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Setup uv | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # ratchet:astral-sh/setup-uv@v8.2.0 | |
| with: | |
| version: "0.11.25" | |
| enable-cache: false | |
| - name: Configure AWS credentials | |
| if: steps.should-run.outputs.run == 'true' | |
| continue-on-error: true # the audit still runs (with no suppressions) if creds are unavailable | |
| uses: aws-actions/configure-aws-credentials@517a711dbcd0e402f90c77e7e2f81e849156e31d # ratchet:aws-actions/configure-aws-credentials@v6.2.2 | |
| with: | |
| role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| aws-region: us-east-2 | |
| - name: Login to Docker Hub | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: docker/login-action@c99871dec2022cc055c062a10cc1a1310835ceb4 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_TOKEN }} | |
| # Scan the by-digest image the build pushed, before merge-* tags it (same | |
| # content in the ECR cache for test runs). | |
| - name: Determine scan image | |
| if: steps.should-run.outputs.run == 'true' | |
| id: scan-image | |
| run: | | |
| case "$COMPONENT" in | |
| web) DIGEST="$DIGEST_WEB" ;; | |
| web-cloud) DIGEST="$DIGEST_WEB_CLOUD" ;; | |
| backend) DIGEST="$DIGEST_BACKEND" ;; | |
| model-server) DIGEST="$DIGEST_MODEL_SERVER" ;; | |
| sandbox) DIGEST="$DIGEST_SANDBOX" ;; | |
| esac | |
| if [ "$IS_TEST_RUN" == "true" ]; then | |
| echo "image=${RUNS_ON_ECR_CACHE}@${DIGEST}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "image=docker.io/${REGISTRY_IMAGE}@${DIGEST}" >> "$GITHUB_OUTPUT" | |
| fi | |
| env: | |
| COMPONENT: ${{ matrix.component }} | |
| IS_TEST_RUN: ${{ needs.determine-builds.outputs.is-test-run }} | |
| REGISTRY_IMAGE: ${{ matrix.registry-image }} | |
| DIGEST_WEB: ${{ needs.build-web-amd64.outputs.digest }} | |
| DIGEST_WEB_CLOUD: ${{ needs.build-web-cloud-amd64.outputs.digest }} | |
| DIGEST_BACKEND: ${{ needs.build-backend-amd64.outputs.digest }} | |
| DIGEST_MODEL_SERVER: ${{ needs.build-model-server-amd64.outputs.digest }} | |
| DIGEST_SANDBOX: ${{ needs.build-sandbox-amd64.outputs.digest }} | |
| - name: Run image vulnerability audit | |
| if: steps.should-run.outputs.run == 'true' | |
| # Exits non-zero on unsuppressed CRITICAL (gates the release). --format | |
| # writes SARIF to stdout (redirected to the file for the Security tab | |
| # upload) and the human-readable report + runbook to stderr, so the CI log | |
| # shows which advisories blocked and how to resolve/suppress them. On a | |
| # hard scan failure nothing is written, so seed a valid empty SARIF to keep | |
| # the always() upload below from choking. | |
| run: | | |
| uv run --no-sync --with onyx-devtools ods audit image "$IMAGE" \ | |
| --fail-on=critical --format=sarif,text > image-audit.sarif || status=$? | |
| if [ ! -s image-audit.sarif ]; then | |
| # $schema is a literal SARIF key, not a shell variable. | |
| # shellcheck disable=SC2016 | |
| echo '{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[]}' > image-audit.sarif | |
| fi | |
| exit "${status:-0}" | |
| env: | |
| IMAGE: ${{ steps.scan-image.outputs.image }} | |
| # Rolling main-HEAD builds (nightly-latest / edge) map to refs/heads/main so | |
| # the Security tab stays authoritative for main and alerts auto-resolve on | |
| # later main builds. Test runs (manual workflow_dispatch) upload against their | |
| # own ref/sha instead, so the scan + upload can be verified without polluting | |
| # main's alerts. Release/beta tags sit on older commits — they still gate, they | |
| # just don't upload. | |
| - name: Upload audit results to GitHub Security tab | |
| if: >- | |
| always() && steps.should-run.outputs.run == 'true' && | |
| ((env.EDGE_TAG == 'true' && needs.determine-builds.outputs.is-test-run != 'true') || | |
| needs.determine-builds.outputs.is-test-run == 'true') | |
| uses: github/codeql-action/upload-sarif@ba454b8ab46733eb6145342877cd148270bb77ab | |
| with: | |
| sarif_file: image-audit.sarif | |
| category: image-audit-${{ matrix.component }} | |
| ref: ${{ needs.determine-builds.outputs.is-test-run == 'true' && github.ref || 'refs/heads/main' }} | |
| sha: ${{ github.sha }} | |
| notify-slack-on-failure: | |
| needs: | |
| - determine-builds | |
| - audit-gate | |
| - create-release | |
| - build-desktop | |
| - build-web-amd64 | |
| - build-web-arm64 | |
| - merge-web | |
| - build-web-cloud-amd64 | |
| - build-web-cloud-arm64 | |
| - merge-web-cloud | |
| - build-backend-amd64 | |
| - build-backend-arm64 | |
| - merge-backend | |
| - build-model-server-amd64 | |
| - build-model-server-arm64 | |
| - merge-model-server | |
| - prepare-sandbox | |
| - build-sandbox-amd64 | |
| - build-sandbox-arm64 | |
| - merge-sandbox | |
| - image-audit | |
| if: always() && (needs.audit-gate.result == 'failure' || needs.create-release.result == 'failure' || needs.build-desktop.result == 'failure' || needs.build-web-amd64.result == 'failure' || needs.build-web-arm64.result == 'failure' || needs.merge-web.result == 'failure' || needs.build-web-cloud-amd64.result == 'failure' || needs.build-web-cloud-arm64.result == 'failure' || needs.merge-web-cloud.result == 'failure' || needs.build-backend-amd64.result == 'failure' || needs.build-backend-arm64.result == 'failure' || needs.merge-backend.result == 'failure' || needs.build-model-server-amd64.result == 'failure' || needs.build-model-server-arm64.result == 'failure' || needs.merge-model-server.result == 'failure' || needs.prepare-sandbox.result == 'failure' || needs.build-sandbox-amd64.result == 'failure' || needs.build-sandbox-arm64.result == 'failure' || needs.merge-sandbox.result == 'failure' || needs.image-audit.result == 'failure') && needs.determine-builds.outputs.is-test-run != 'true' | |
| # NOTE: Github-hosted runners have about 20s faster queue times and are preferred here. | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 90 | |
| environment: release | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Determine failed jobs | |
| id: failed-jobs | |
| shell: bash | |
| run: | | |
| FAILED_JOBS="" | |
| if [ "${NEEDS_AUDIT_GATE_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• audit-gate\\n" | |
| fi | |
| if [ "${NEEDS_CREATE_RELEASE_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• create-release\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_DESKTOP_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-desktop\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_WEB_AMD64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-web-amd64\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_WEB_ARM64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-web-arm64\\n" | |
| fi | |
| if [ "${NEEDS_MERGE_WEB_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• merge-web\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_WEB_CLOUD_AMD64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-web-cloud-amd64\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_WEB_CLOUD_ARM64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-web-cloud-arm64\\n" | |
| fi | |
| if [ "${NEEDS_MERGE_WEB_CLOUD_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• merge-web-cloud\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_BACKEND_AMD64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-backend-amd64\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_BACKEND_ARM64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-backend-arm64\\n" | |
| fi | |
| if [ "${NEEDS_MERGE_BACKEND_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• merge-backend\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_MODEL_SERVER_AMD64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-model-server-amd64\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_MODEL_SERVER_ARM64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-model-server-arm64\\n" | |
| fi | |
| if [ "${NEEDS_MERGE_MODEL_SERVER_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• merge-model-server\\n" | |
| fi | |
| if [ "${NEEDS_PREPARE_SANDBOX_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• prepare-sandbox\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_SANDBOX_AMD64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-sandbox-amd64\\n" | |
| fi | |
| if [ "${NEEDS_BUILD_SANDBOX_ARM64_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• build-sandbox-arm64\\n" | |
| fi | |
| if [ "${NEEDS_MERGE_SANDBOX_RESULT}" == "failure" ]; then | |
| FAILED_JOBS="${FAILED_JOBS}• merge-sandbox\\n" | |
| fi | |
| # Remove trailing \n and set output | |
| FAILED_JOBS=$(printf '%s' "$FAILED_JOBS" | sed 's/\\n$//') | |
| echo "jobs=$FAILED_JOBS" >> "$GITHUB_OUTPUT" | |
| env: | |
| NEEDS_AUDIT_GATE_RESULT: ${{ needs.audit-gate.result }} | |
| NEEDS_CREATE_RELEASE_RESULT: ${{ needs.create-release.result }} | |
| NEEDS_BUILD_DESKTOP_RESULT: ${{ needs.build-desktop.result }} | |
| NEEDS_BUILD_WEB_AMD64_RESULT: ${{ needs.build-web-amd64.result }} | |
| NEEDS_BUILD_WEB_ARM64_RESULT: ${{ needs.build-web-arm64.result }} | |
| NEEDS_MERGE_WEB_RESULT: ${{ needs.merge-web.result }} | |
| NEEDS_BUILD_WEB_CLOUD_AMD64_RESULT: ${{ needs.build-web-cloud-amd64.result }} | |
| NEEDS_BUILD_WEB_CLOUD_ARM64_RESULT: ${{ needs.build-web-cloud-arm64.result }} | |
| NEEDS_MERGE_WEB_CLOUD_RESULT: ${{ needs.merge-web-cloud.result }} | |
| NEEDS_BUILD_BACKEND_AMD64_RESULT: ${{ needs.build-backend-amd64.result }} | |
| NEEDS_BUILD_BACKEND_ARM64_RESULT: ${{ needs.build-backend-arm64.result }} | |
| NEEDS_MERGE_BACKEND_RESULT: ${{ needs.merge-backend.result }} | |
| NEEDS_BUILD_MODEL_SERVER_AMD64_RESULT: ${{ needs.build-model-server-amd64.result }} | |
| NEEDS_BUILD_MODEL_SERVER_ARM64_RESULT: ${{ needs.build-model-server-arm64.result }} | |
| NEEDS_MERGE_MODEL_SERVER_RESULT: ${{ needs.merge-model-server.result }} | |
| NEEDS_PREPARE_SANDBOX_RESULT: ${{ needs.prepare-sandbox.result }} | |
| NEEDS_BUILD_SANDBOX_AMD64_RESULT: ${{ needs.build-sandbox-amd64.result }} | |
| NEEDS_BUILD_SANDBOX_ARM64_RESULT: ${{ needs.build-sandbox-arm64.result }} | |
| NEEDS_MERGE_SANDBOX_RESULT: ${{ needs.merge-sandbox.result }} | |
| - name: Send Slack notification | |
| uses: ./.github/actions/slack-notify | |
| with: | |
| webhook-url: ${{ secrets.MONITOR_DEPLOYMENTS_WEBHOOK }} | |
| failed-jobs: ${{ steps.failed-jobs.outputs.jobs }} | |
| title: "🚨 Deployment Workflow Failed" | |
| ref-name: ${{ github.ref_name }} |