From 778c09371eac1eafff34c0411b4eb8fee48c3f23 Mon Sep 17 00:00:00 2001 From: Lauri Piisang Date: Mon, 24 Aug 2026 16:23:43 +0300 Subject: [PATCH 1/4] infra[notask]: make publish-sdk publish-only (drop PR trigger) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - publish-sdk ran on pull_request_target but never published on PRs (publish jobs gate on push/dispatch); the PR run only built — against base main and the published @qvac/inference — producing false reds during co-development - PR validation is already owned by required checks: pr-checks-sdk-pod (sdk/inference/bare-sdk build+lint+typecheck on PR head vs workspace inference), pr-checks-sdk-python, and pr-release-guard for release-* PRs - drop the pull_request_target trigger; publish-sdk runs on push/dispatch only - release publishing (push to release-*) and its release-merge-guard (push/dispatch-gated) are unchanged --- .github/workflows/publish-sdk.yml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.github/workflows/publish-sdk.yml b/.github/workflows/publish-sdk.yml index 7ff0f56ac4..43716ab2ea 100644 --- a/.github/workflows/publish-sdk.yml +++ b/.github/workflows/publish-sdk.yml @@ -12,23 +12,6 @@ on: - "packages/sdk/**" - "packages/bare-sdk/**" - "packages/sdk-python/**" - pull_request_target: - types: - - opened - - synchronize - - reopened - - edited - - labeled - branches: - - release-* - - feature-* - - tmp-* - - main - paths: - - "packages/inference/**" - - "packages/sdk/**" - - "packages/bare-sdk/**" - - "packages/sdk-python/**" workflow_dispatch: inputs: From e7cf6580193e1728b25e1b944df953b0431d8b7d Mon Sep 17 00:00:00 2001 From: Lauri Piisang Date: Mon, 24 Aug 2026 16:38:40 +0300 Subject: [PATCH 2/4] infra[notask]: build+publish SDK against the co-published inference - build-sdk installed the published @qvac/inference, which lags the unreleased engine API the SDK already consumes (e.g. VideoClientParams.reference_images); compile against the in-repo inference via sdk-source:workspace so the dist matches this run's engine - GPR mono builds published the SDK depending on stale public @qvac/inference; pin @qvac/inference to the @tetherto/inference-mono published in the same run (npm alias, versions match via shared GITHUB_RUN_ID) so a plain install of the mono SDK resolves a coherent engine - expose published_version from publish-gpr-inference; publish-gpr now needs it - npm/release path unchanged: dist compiles against the in-repo inference, the manifest keeps its committed range which resolves to the inference released in the same run --- .github/workflows/publish-sdk.yml | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-sdk.yml b/.github/workflows/publish-sdk.yml index 43716ab2ea..86e50cd23c 100644 --- a/.github/workflows/publish-sdk.yml +++ b/.github/workflows/publish-sdk.yml @@ -189,6 +189,16 @@ jobs: run: bun install working-directory: ${{ env.WORKDIR }} + # Compile the SDK against the in-repo @qvac/inference at this commit, not + # the previously-published npm release (which lags behind engine API the + # SDK already consumes). This only affects the dist built here; the + # published dependency is set per channel below — GPR is pinned to the + # co-published @tetherto/inference-mono (see publish-gpr), npm keeps its + # committed range (resolved to the inference released in the same run). + - name: Build against workspace @qvac/inference + run: bun run sdk-source:workspace + working-directory: ${{ env.WORKDIR }} + - name: Modify package name for branch-based builds working-directory: ${{ env.WORKDIR }} run: | @@ -517,7 +527,7 @@ jobs: publish-gpr: name: Publish to GitHub Packages (GPR) - needs: [build, publish-logic] + needs: [build, publish-logic, publish-gpr-inference] if: ${{ needs.publish-logic.outputs.publish_main == 'true' || needs.publish-logic.outputs.publish_feature == 'true' || needs.publish-logic.outputs.publish_tmp == 'true' }} runs-on: ubuntu-latest continue-on-error: true @@ -573,6 +583,28 @@ jobs: MODIFIED_NAME=$(node -p "require('./package.json').name") echo "Package name: $ORIGINAL_NAME → $MODIFIED_NAME" + # The dist was compiled against the in-repo engine, so the published mono + # build must depend on the inference published in THIS run, not the stale + # public @qvac/inference. GPR uses ${version}-tmp.runid-${run_id}, and + # run_id is shared across jobs, so this pin matches the co-published + # @tetherto/inference-mono exactly. An npm alias keeps the SDK's own + # `import '@qvac/inference'` resolving to that package. + - name: Pin @qvac/inference to the co-published inference-mono + working-directory: ${{ env.WORKDIR }} + env: + INFERENCE_MONO_VERSION: ${{ needs.publish-gpr-inference.outputs.published_version }} + run: | + set -euo pipefail + if [ -z "${INFERENCE_MONO_VERSION}" ]; then + echo "::warning::inference-mono version unavailable; leaving @qvac/inference unchanged" + exit 0 + fi + SPEC="npm:@tetherto/inference-mono@${INFERENCE_MONO_VERSION}" + echo "Pinning @qvac/inference -> ${SPEC}" + jq --arg spec "$SPEC" '.dependencies["@qvac/inference"] = $spec' package.json > package.json.tmp + mv package.json.tmp package.json + node -p "'@qvac/inference -> ' + require('./package.json').dependencies['@qvac/inference']" + - name: Publish to GitHub Package Registry id: publish uses: ./.github/actions/publish-library-to-gpr @@ -647,6 +679,8 @@ jobs: if: ${{ needs.publish-logic.outputs.publish_main == 'true' || needs.publish-logic.outputs.publish_feature == 'true' || needs.publish-logic.outputs.publish_tmp == 'true' }} runs-on: ubuntu-latest continue-on-error: true + outputs: + published_version: ${{ steps.publish.outputs.gpr_published_version }} permissions: contents: read packages: write From bebf635c7dc3409e9ecbcaaf18efd08cf198ec44 Mon Sep 17 00:00:00 2001 From: Lauri Piisang Date: Mon, 24 Aug 2026 17:52:20 +0300 Subject: [PATCH 3/4] =?UTF-8?q?infra[notask]:=20address=20review=20?= =?UTF-8?q?=E2=80=94=20fail-closed=20inference=20pin,=20drop=20dead=20PR?= =?UTF-8?q?=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pin @qvac/inference only when publish-gpr-inference actually succeeded; the GPR action writes gpr_published_version even on a failed publish, so a non-empty check alone could pin the SDK mono to a never-published inference (install -> 404). publish-gpr-inference is continue-on-error, so its failure doesn't skip publish-gpr - remove pull_request_target artifacts orphaned by dropping the PR trigger: base.sha/base.repo checkout fallbacks, "Fetch PR head commits" steps, and the PR_HEAD_SHA lockstep indirection — all resolved to github.sha on push --- .github/workflows/publish-sdk.yml | 49 +++++++++++-------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/.github/workflows/publish-sdk.yml b/.github/workflows/publish-sdk.yml index 86e50cd23c..f1c037356e 100644 --- a/.github/workflows/publish-sdk.yml +++ b/.github/workflows/publish-sdk.yml @@ -102,29 +102,18 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 with: - repository: ${{ github.event.pull_request.base.repo.full_name || github.repository }} - ref: ${{ github.event.pull_request.base.sha || github.sha }} + repository: ${{ github.repository }} + ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 - - name: Fetch PR head commits - if: github.event_name == 'pull_request_target' - run: | - git fetch origin ${{ github.event.pull_request.head.sha }} - - name: Verify inference / sdk / bare-sdk / python version lockstep shell: bash - env: - PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | - # pull_request_target pins the working tree to base.sha; read manifests - # from the PR head SHA so a missed sdk / bare-sdk / python bump fails - # pre-merge (pr-checks-sdk-python.yml may not run on an engine-only bump). - # # @qvac/inference is the sole version anchor: sdk, bare-sdk and # sdk-python must all match it. Run /qv-sdk-lockstep-sync to align. set -euo pipefail - REF="${PR_HEAD_SHA:-${GITHUB_SHA}}" + REF="${GITHUB_SHA}" INF_VER=$(git show "${REF}":packages/inference/package.json | jq -r .version) SDK_VER=$(git show "${REF}":packages/sdk/package.json | jq -r .version) BARE_VER=$(git show "${REF}":packages/bare-sdk/package.json | jq -r .version) @@ -309,8 +298,8 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 with: - repository: ${{ github.event.pull_request.base.repo.full_name || github.repository }} - ref: ${{ github.event.pull_request.base.sha || github.sha }} + repository: ${{ github.repository }} + ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Bun @@ -353,8 +342,8 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 with: - repository: ${{ github.event.pull_request.base.repo.full_name || github.repository }} - ref: ${{ github.event.pull_request.base.sha || github.sha }} + repository: ${{ github.repository }} + ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Bun @@ -412,22 +401,13 @@ jobs: run: working-directory: packages/sdk-python steps: - # pull_request_target: keep working tree on base.sha (do not execute PR head - # under this job's secrets). Contract/build smoke the base tree; PR contract - # coverage is pr-checks-sdk-python.yml. Lockstep reads head.sha like `build`. - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 with: - repository: ${{ github.event.pull_request.base.repo.full_name || github.repository }} - ref: ${{ github.event.pull_request.base.sha || github.sha }} + repository: ${{ github.repository }} + ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} - - name: Fetch PR head commits - if: github.event_name == 'pull_request_target' - working-directory: ${{ github.workspace }} - run: | - git fetch origin ${{ github.event.pull_request.head.sha }} - - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # 6.2.0 with: python-version: "3.10" @@ -447,13 +427,11 @@ jobs: - name: Verify version lockstep with @qvac/inference working-directory: ${{ github.workspace }} - env: - PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: | # @qvac/inference is the sole version anchor. This job can run # standalone (publish_pypi_only), so check python against the anchor. set -euo pipefail - REF="${PR_HEAD_SHA:-${GITHUB_SHA}}" + REF="${GITHUB_SHA}" INF_VER=$(git show "${REF}":packages/inference/package.json | jq -r .version) PY_VER=$(git show "${REF}":packages/sdk-python/src/tetherto/qvac_sdk/_generated/sdk_version.py | sed -n 's/^SDK_VERSION = "\(.*\)"/\1/p') if [ -z "$PY_VER" ]; then @@ -589,7 +567,14 @@ jobs: # run_id is shared across jobs, so this pin matches the co-published # @tetherto/inference-mono exactly. An npm alias keeps the SDK's own # `import '@qvac/inference'` resolving to that package. + # Fail closed: only pin when the inference GPR publish actually succeeded. + # publish-gpr-inference is continue-on-error and its action writes + # gpr_published_version even on a failed publish, so a non-empty check + # alone could pin to a version that was never published (install -> 404). + # If inference didn't publish, leave the committed range — installable, + # just not this run's engine. - name: Pin @qvac/inference to the co-published inference-mono + if: needs.publish-gpr-inference.result == 'success' working-directory: ${{ env.WORKDIR }} env: INFERENCE_MONO_VERSION: ${{ needs.publish-gpr-inference.outputs.published_version }} From ac6ffd3b34952cb71e2175e509778015140f214e Mon Sep 17 00:00:00 2001 From: Lauri Piisang Date: Mon, 24 Aug 2026 18:15:16 +0300 Subject: [PATCH 4/4] infra[notask]: set persist-credentials: false on checkouts (zizmor artipacked) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add persist-credentials: false to the 11 actions/checkout steps zizmor flagged as artipacked (build, build-bare-sdk, build-inference, build-sdk-python, publish-gpr*, publish-npm*, release-merge-guard) - safe: none of these jobs do authenticated git writes — tag/release creation lives in the reusable create-* workflows; these checkouts only read git locally or feed npm/GPR publish, so not persisting the token changes nothing - clears all 11 medium artipacked findings; zizmor reports no new findings --- .github/workflows/publish-sdk.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/publish-sdk.yml b/.github/workflows/publish-sdk.yml index f1c037356e..0ac8038b88 100644 --- a/.github/workflows/publish-sdk.yml +++ b/.github/workflows/publish-sdk.yml @@ -73,6 +73,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 with: + persist-credentials: false fetch-depth: 0 - uses: ./.github/actions/release-merge-guard with: @@ -105,6 +106,7 @@ jobs: repository: ${{ github.repository }} ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false fetch-depth: 0 - name: Verify inference / sdk / bare-sdk / python version lockstep @@ -301,6 +303,7 @@ jobs: repository: ${{ github.repository }} ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # 2.2.0 @@ -345,6 +348,7 @@ jobs: repository: ${{ github.repository }} ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - name: Setup Bun uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # 2.2.0 @@ -407,6 +411,7 @@ jobs: repository: ${{ github.repository }} ref: ${{ github.sha }} token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # 6.2.0 with: @@ -515,6 +520,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 + with: + persist-credentials: false - name: Download build artifacts uses: ./.github/actions/download-release-artifact @@ -613,6 +620,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 + with: + persist-credentials: false - name: Download bare-sdk dist artifact uses: ./.github/actions/download-release-artifact @@ -676,6 +685,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 + with: + persist-credentials: false - name: Download inference dist artifact uses: ./.github/actions/download-release-artifact @@ -753,6 +764,8 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 + with: + persist-credentials: false - name: Download build artifacts uses: ./.github/actions/download-release-artifact @@ -816,6 +829,8 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 + with: + persist-credentials: false - name: Download bare-sdk dist artifact uses: ./.github/actions/download-release-artifact @@ -873,6 +888,8 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2 + with: + persist-credentials: false - name: Download inference dist artifact uses: ./.github/actions/download-release-artifact