From ff412a4d7a28f4456960165e24f6bfded3f7fb44 Mon Sep 17 00:00:00 2001 From: max-rozen-oss-db <291811446+max-rozen-oss-db@users.noreply.github.com> Date: Fri, 9 Oct 2026 22:02:15 -0400 Subject: [PATCH 1/2] ci: Run Windows lanes on windows-latest and drop JFrog GitHub-hosted windows-latest reaches public PyPI and npm, so the Windows lanes no longer need the JFrog OIDC login. Fork PRs can't mint OIDC tokens, which made every Windows job fail on them. Co-authored-by: Isaac --- .github/workflows/ci.yml | 63 ++------------------- .github/workflows/integration.yml | 89 ++++-------------------------- tests/integration/README.md | 11 ++-- tests/test_e2e.py | 3 +- tests/test_integration_contract.py | 1 - tests/test_integration_runner.py | 6 +- 6 files changed, 25 insertions(+), 148 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d746a2405..ba98e46da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,6 @@ permissions: env: PYTHONUTF8: 1 - # Windows runners can't reach public PyPI or npm; they install through JFrog. - WINDOWS_PACKAGE_INDEX: https://databricks.jfrog.io/artifactory/api/pypi/db-pypi/simple - WINDOWS_NPM_REGISTRY: https://databricks.jfrog.io/artifactory/api/npm/db-npm/ concurrency: group: ci-${{ github.event.pull_request.number || github.ref }}-${{ github.event_name }} @@ -37,16 +34,13 @@ jobs: - run: just lint test: - name: Unit tests · ${{ matrix.os == 'windows-server-latest' && 'Windows' || 'Linux' }} + name: Unit tests · ${{ matrix.os == 'windows-latest' && 'Windows' || 'Linux' }} runs-on: ${{ matrix.os }} needs: lint - permissions: - contents: read - id-token: write strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-server-latest] + os: [ubuntu-latest, windows-latest] defaults: run: shell: bash @@ -58,23 +52,8 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 - - name: Authenticate to JFrog with GitHub OIDC - id: jfrog - if: ${{ runner.os == 'Windows' }} - uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1 - env: - JF_URL: https://databricks.jfrog.io - with: - oidc-provider-name: github-actions - name: Install dependencies - env: - UV_INDEX_DATABRICKS_PYPI_USERNAME: ${{ steps.jfrog.outputs.oidc-user }} - UV_INDEX_DATABRICKS_PYPI_PASSWORD: ${{ steps.jfrog.outputs.oidc-token }} run: | - if [[ "$RUNNER_OS" == Windows ]]; then - unset UV_INDEX_URL - export UV_DEFAULT_INDEX="databricks-pypi=$WINDOWS_PACKAGE_INDEX" - fi uv lock uv sync - run: uv run --no-sync pytest --ignore=tests/test_e2e.py @@ -101,21 +80,18 @@ jobs: uv run pytest tests/native_claude/test_mod.py -q e2e-shards: - name: ${{ matrix.name }} · ${{ matrix.os == 'windows-server-latest' && 'Windows' || 'Linux' }} + name: ${{ matrix.name }} · ${{ matrix.os == 'windows-latest' && 'Windows' || 'Linux' }} runs-on: ${{ matrix.os }} needs: lint # The merge queue runs only lint and unit tests; e2e already ran on the PR. if: ${{ github.event_name != 'merge_group' }} - permissions: - contents: read - id-token: write defaults: run: shell: bash strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-server-latest] + os: [ubuntu-latest, windows-latest] group: [gateway, claude, codex, gemini, opencode, copilot, pi] include: - group: gateway @@ -173,37 +149,11 @@ jobs: run: | test -f "$RUNNER_TEMP/.bin/databricks.exe" cygpath -w "$RUNNER_TEMP/.bin" >> "$GITHUB_PATH" - - name: Authenticate to JFrog with GitHub OIDC - id: jfrog - if: ${{ runner.os == 'Windows' }} - uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1 - env: - JF_URL: https://databricks.jfrog.io - with: - oidc-provider-name: github-actions - name: Install the shard's agent CLI if: ${{ matrix.package != '' }} - env: - NPM_TOKEN: ${{ steps.jfrog.outputs.oidc-token }} - run: | - if [[ "$RUNNER_OS" == Windows ]]; then - npmrc="$RUNNER_TEMP/jfrog.npmrc" - printf 'registry=%s\n//%s:_authToken=%s\n' \ - "$WINDOWS_NPM_REGISTRY" "${WINDOWS_NPM_REGISTRY#https://}" "$NPM_TOKEN" > "$npmrc" - npm install -g --userconfig "$npmrc" "$AGENT_PACKAGE" - rm "$npmrc" - else - npm install -g "$AGENT_PACKAGE" - fi + run: npm install -g "$AGENT_PACKAGE" - name: Install ug and test dependencies - env: - UV_INDEX_DATABRICKS_PYPI_USERNAME: ${{ steps.jfrog.outputs.oidc-user }} - UV_INDEX_DATABRICKS_PYPI_PASSWORD: ${{ steps.jfrog.outputs.oidc-token }} run: | - if [[ "$RUNNER_OS" == Windows ]]; then - unset UV_INDEX_URL - export UV_DEFAULT_INDEX="databricks-pypi=$WINDOWS_PACKAGE_INDEX" - fi uv lock uv tool install . uv sync @@ -230,9 +180,6 @@ jobs: needs: lint # The condition runs integration tests only if lint passes and the overall workflow is not cancelled. if: ${{ github.event_name != 'merge_group' && needs.lint.result == 'success' && !cancelled() }} - permissions: - contents: read - id-token: write uses: ./.github/workflows/integration.yml secrets: inherit diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 9c3fbff68..4b9055116 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -49,9 +49,6 @@ env: CODEX_VERSION: ${{ inputs.codex_version || '0.154.0' }} OPENCODE_VERSION: ${{ inputs.opencode_version || '1.18.31' }} PACKAGE_INDEX: ${{ inputs.default_index || 'https://pypi.org/simple' }} - # Windows runners install packages through the Databricks JFrog proxies. - WINDOWS_PACKAGE_INDEX: https://databricks.jfrog.io/artifactory/api/pypi/db-pypi/simple - WINDOWS_NPM_REGISTRY: https://databricks.jfrog.io/artifactory/api/npm/db-npm/ jobs: installation: @@ -90,15 +87,8 @@ jobs: installation-windows: name: Windows installation tests - if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} - runs-on: windows-server-latest + runs-on: windows-latest timeout-minutes: 20 - permissions: - contents: read - id-token: write - env: - PACKAGE_INDEX: https://databricks.jfrog.io/artifactory/api/pypi/db-pypi/simple - NPM_REGISTRY: https://databricks.jfrog.io/artifactory/api/npm/db-npm/ steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: @@ -109,22 +99,8 @@ jobs: - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: version: 0.9.8 - - name: Authenticate to JFrog with GitHub OIDC - id: jfrog - uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1 - env: - JF_URL: https://databricks.jfrog.io - with: - oidc-provider-name: github-actions - name: Test a fresh installed package without workspace credentials shell: pwsh - env: - # uv 0.9.8 resolves credentials for the named default index from - # UV_INDEX__USERNAME/PASSWORD without placing them in its URL. - UV_DEFAULT_INDEX: databricks-pypi=${{ env.PACKAGE_INDEX }} - UV_INDEX_DATABRICKS_PYPI_USERNAME: ${{ steps.jfrog.outputs.oidc-user }} - UV_INDEX_DATABRICKS_PYPI_PASSWORD: ${{ steps.jfrog.outputs.oidc-token }} - UG_INTEGRATION_NPM_TOKEN: ${{ steps.jfrog.outputs.oidc-token }} run: | $output = Join-Path $env:RUNNER_TEMP "ug-integration" $runnerArgs = @( @@ -132,8 +108,7 @@ jobs: "--ug-version", $env:UG_VERSION, "--entry-point", $env:ENTRY_POINT, "--claude-version", $env:CLAUDE_VERSION, - "--default-index", $env:UV_DEFAULT_INDEX, - "--npm-registry", $env:NPM_REGISTRY, + "--default-index", $env:PACKAGE_INDEX, "--installation-only", "--output", $output ) @@ -176,7 +151,7 @@ jobs: PY smoke: - name: Smoke journeys · ${{ matrix.agent == 'claude' && 'Claude' || 'Codex' }} · ${{ matrix.os == 'windows-server-latest' && 'Windows' || 'Linux' }} + name: Smoke journeys · ${{ matrix.agent == 'claude' && 'Claude' || 'Codex' }} · ${{ matrix.os == 'windows-latest' && 'Windows' || 'Linux' }} needs: workspace runs-on: ${{ matrix.os }} timeout-minutes: 20 @@ -184,13 +159,10 @@ jobs: # Both OS variants use the same workspace; avoid overlapping same-agent runs. group: integration-smoke-${{ github.run_id }}-${{ matrix.agent }} cancel-in-progress: false - permissions: - contents: read - id-token: write strategy: fail-fast: false matrix: - os: [ubuntu-22.04, windows-server-latest] + os: [ubuntu-22.04, windows-latest] agent: [claude, codex] env: UCODE_TEST_WORKSPACE: ${{ secrets.UCODE_TEST_WORKSPACE }} @@ -218,25 +190,9 @@ jobs: run: | test -f "$RUNNER_TEMP/.bin/databricks.exe" cygpath -w "$RUNNER_TEMP/.bin" >> "$GITHUB_PATH" - - name: Authenticate to JFrog with GitHub OIDC - id: jfrog - if: ${{ runner.os == 'Windows' }} - uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1 - env: - JF_URL: https://databricks.jfrog.io - with: - oidc-provider-name: github-actions - name: Run the selected live cases against the e2e workspace shell: bash - env: - UV_INDEX_DATABRICKS_PYPI_USERNAME: ${{ steps.jfrog.outputs.oidc-user }} - UV_INDEX_DATABRICKS_PYPI_PASSWORD: ${{ steps.jfrog.outputs.oidc-token }} - UG_INTEGRATION_NPM_TOKEN: ${{ steps.jfrog.outputs.oidc-token }} run: | - if [[ "$RUNNER_OS" == Windows ]]; then - PACKAGE_INDEX="databricks-pypi=$WINDOWS_PACKAGE_INDEX" - registry=(--npm-registry "$WINDOWS_NPM_REGISTRY") - fi case "$AGENT" in claude) args=(--claude-version "$CLAUDE_VERSION") ;; codex) args=(--codex-version "$CODEX_VERSION") ;; @@ -248,7 +204,7 @@ jobs: uv run --no-project --python 3.12 python scripts/run_integration.py \ --python 3.12 --ug-version "$UG_VERSION" --entry-point "$ENTRY_POINT" \ --default-index "$PACKAGE_INDEX" --output "$RUNNER_TEMP/ug-integration" \ - "${registry[@]}" "${args[@]}" -- -m "$TEST_MARKER" + "${args[@]}" -- -m "$TEST_MARKER" - name: Upload live test evidence if: ${{ !cancelled() }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 @@ -266,14 +222,9 @@ jobs: headless-windows: name: Windows headless journey · Claude needs: workspace - runs-on: windows-server-latest + runs-on: windows-latest timeout-minutes: 20 - permissions: - contents: read - id-token: write env: - PACKAGE_INDEX: https://databricks.jfrog.io/artifactory/api/pypi/db-pypi/simple - NPM_REGISTRY: https://databricks.jfrog.io/artifactory/api/npm/db-npm/ DEPENDENCY: ${{ inputs.dependency }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -299,22 +250,11 @@ jobs: Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append & $databricks version if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - name: Authenticate to JFrog with GitHub OIDC - id: jfrog - uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1 - env: - JF_URL: https://databricks.jfrog.io - with: - oidc-provider-name: github-actions - name: Configure and complete a real headless gateway task shell: pwsh env: UCODE_TEST_WORKSPACE: ${{ secrets.UCODE_TEST_WORKSPACE }} DATABRICKS_BEARER: ${{ secrets.DATABRICKS_BEARER }} - UV_DEFAULT_INDEX: databricks-pypi=${{ env.PACKAGE_INDEX }} - UV_INDEX_DATABRICKS_PYPI_USERNAME: ${{ steps.jfrog.outputs.oidc-user }} - UV_INDEX_DATABRICKS_PYPI_PASSWORD: ${{ steps.jfrog.outputs.oidc-token }} - UG_INTEGRATION_NPM_TOKEN: ${{ steps.jfrog.outputs.oidc-token }} run: | $output = Join-Path $env:RUNNER_TEMP "ug-integration" $runnerArgs = @( @@ -322,8 +262,7 @@ jobs: "--ug-version", $env:UG_VERSION, "--entry-point", $env:ENTRY_POINT, "--claude-version", $env:CLAUDE_VERSION, - "--default-index", $env:UV_DEFAULT_INDEX, - "--npm-registry", $env:NPM_REGISTRY, + "--default-index", $env:PACKAGE_INDEX, "--headless-only", "--output", $output ) @@ -345,7 +284,7 @@ jobs: ${{ runner.temp }}/ug-integration/wheels/ full: - name: Full journeys · ${{ matrix.agent == 'claude' && 'Claude' || 'Codex' }} · ${{ matrix.os == 'windows-server-latest' && 'Windows' || 'Linux' }} + name: Full journeys · ${{ matrix.agent == 'claude' && 'Claude' || 'Codex' }} · ${{ matrix.os == 'windows-latest' && 'Windows' || 'Linux' }} if: ${{ !cancelled() && needs.workspace.result == 'success' }} needs: [workspace, smoke] runs-on: ${{ matrix.os }} @@ -353,9 +292,6 @@ jobs: # Keep the previous per-agent serialization across the new OS matrix. group: integration-full-${{ github.run_id }}-${{ matrix.agent }} cancel-in-progress: false - permissions: - contents: read - id-token: write # The runner enforces its own 3600s pytest deadline; keep the job above it # so a slow run fails through the runner's report instead of a job kill. timeout-minutes: 70 @@ -364,7 +300,7 @@ jobs: # One runner per OS variant; concurrency above serializes variants per agent. max-parallel: 4 matrix: - os: [ubuntu-22.04, windows-server-latest] + os: [ubuntu-22.04, windows-latest] agent: [claude, codex] env: UCODE_TEST_WORKSPACE: ${{ secrets.UCODE_TEST_WORKSPACE }} @@ -379,18 +315,15 @@ jobs: # Non-blocking: continue-on-error and absent from the cujs `needs`, so a flaky OpenCode # leg cannot block merges. Add it to cujs once the lane is stable. opencode: - name: Full journeys · OpenCode · ${{ matrix.os == 'windows-server-latest' && 'Windows' || 'Linux' }} (non-blocking) + name: Full journeys · OpenCode · ${{ matrix.os == 'windows-latest' && 'Windows' || 'Linux' }} (non-blocking) if: ${{ !cancelled() && needs.workspace.result == 'success' }} needs: workspace continue-on-error: true runs-on: ${{ matrix.os }} - permissions: - contents: read - id-token: write strategy: fail-fast: false matrix: - os: [ubuntu-22.04, windows-server-latest] + os: [ubuntu-22.04, windows-latest] timeout-minutes: 30 env: UCODE_TEST_WORKSPACE: ${{ secrets.UCODE_TEST_WORKSPACE }} diff --git a/tests/integration/README.md b/tests/integration/README.md index e81b10ae2..24320155d 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -572,20 +572,19 @@ starting alongside unit tests and the existing agent e2e shards. Integration has no dependency on agent e2e; a failure there does not prevent integration from running. The final required `e2e` check waits for both suites and requires both to succeed. The required installation and live jobs run directly on fresh GitHub Ubuntu VMs, -not inside the optional Docker image. An advisory `windows-server-latest` job runs +not inside the optional Docker image. An advisory `windows-latest` job runs the five credential-free checks in `test_installation.py` (installation, CLI, auth-helper, and local MCP) and uploads `integration-installation-windows` evidence. It uses `continue-on-error` and is not part of `All integration tests` until the initial Windows issues are fixed. -The Windows job authenticates to the Databricks JFrog package proxy using -GitHub OIDC, following the organization's SDK CI setup. Its actual OS image is -recorded in `versions.json`; the organization can update the image behind the -runner label. The two POSIX version-floor journeys are outside this Windows subset. +It installs from public PyPI and npm, needs no credentials, and also runs on +fork PRs. Its actual OS image is recorded in `versions.json`; GitHub can update +the image behind the runner label. The two POSIX version-floor journeys are outside this Windows subset. It installs only Claude as the runner prerequisite; the five selected checks exercise ug and its local helpers, not either agent's inference path. An advisory **Windows headless journey · Claude** job installs the temporary Windows-pinned Claude version (currently 2.1.278) -on a native Windows runner using the same authenticated package proxies, +on a native Windows runner from public PyPI and npm, reuses the existing e2e workspace/bearer, and requires the unpredictable file value in the agent's structured final answer. It uploads `integration-headless-windows-claude` evidence and remains outside diff --git a/tests/test_e2e.py b/tests/test_e2e.py index c35dde42b..150061e71 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -780,8 +780,7 @@ def test_launch_gemini_per_model( f"({gemini.MAX_GEMINI_VERSION_TEXT}); run `ucode gemini` to downgrade." ) gemini_models: list = e2e_state.get("gemini_models") or [] - # Windows CI installs Gemini CLI from JFrog, which still serves a build under the ceiling, so - # it's the lane that launches these. Image-only models can't serve its tool calls. + # Image-only models can't serve Gemini CLI's tool calls. if os.name == "nt": gemini_models = [m for m in gemini_models if not m.endswith("-image")] if not gemini_models: diff --git a/tests/test_integration_contract.py b/tests/test_integration_contract.py index beda32fb2..d4433796b 100644 --- a/tests/test_integration_contract.py +++ b/tests/test_integration_contract.py @@ -128,7 +128,6 @@ def test_cuj_discovery_fails_for_a_file_without_a_check_name(tmp_path): ) # Fork PRs get no secrets or OIDC token, so jobs that need either must skip them. SKIPPED_ON_FORK_PRS = { - "installation-windows", "workspace", "smoke", "headless-windows", diff --git a/tests/test_integration_runner.py b/tests/test_integration_runner.py index f89b9eee4..2ba161981 100644 --- a/tests/test_integration_runner.py +++ b/tests/test_integration_runner.py @@ -40,11 +40,11 @@ def test_installer_environment_scopes_registry_credentials(): def test_npm_user_config_references_token_environment_without_embedding_it(): - config = runner.npm_user_config("https://databricks.jfrog.io/artifactory/api/npm/db-npm/") + config = runner.npm_user_config("https://registry.example.invalid/api/npm/db-npm/") assert config == ( - "registry=https://databricks.jfrog.io/artifactory/api/npm/db-npm/\n" - "//databricks.jfrog.io/artifactory/api/npm/db-npm/:_authToken=" + "registry=https://registry.example.invalid/api/npm/db-npm/\n" + "//registry.example.invalid/api/npm/db-npm/:_authToken=" "${UG_INTEGRATION_NPM_TOKEN}\n" "always-auth=true\n" ) From 9dd350223ef201bdedc93bcf0ab91c0e365055ef Mon Sep 17 00:00:00 2001 From: max-rozen-oss-db <291811446+max-rozen-oss-db@users.noreply.github.com> Date: Fri, 9 Oct 2026 22:22:09 -0400 Subject: [PATCH 2/2] Remove the integration runner's JFrog credential plumbing Only the Windows JFrog lanes set these env vars, so with JFrog gone the installer credential passthrough and npmrc writing are dead code. Co-authored-by: Isaac --- scripts/run_integration.py | 54 -------------------------------- tests/test_integration_runner.py | 52 ++---------------------------- 2 files changed, 3 insertions(+), 103 deletions(-) diff --git a/scripts/run_integration.py b/scripts/run_integration.py index 8300e237c..3def8c7ec 100644 --- a/scripts/run_integration.py +++ b/scripts/run_integration.py @@ -33,12 +33,6 @@ "opencode": "opencode-ai", } WINDOWS_PATHEXT = ".COM;.EXE;.BAT;.CMD" -UV_INDEX_CREDENTIAL_ENV = ( - "UV_INDEX_DATABRICKS_PYPI_USERNAME", - "UV_INDEX_DATABRICKS_PYPI_PASSWORD", -) -NPM_TOKEN_ENV = "UG_INTEGRATION_NPM_TOKEN" -INSTALLER_CREDENTIAL_ENV = (*UV_INDEX_CREDENTIAL_ENV, NPM_TOKEN_ENV) PTY_MODULES = {"pexpect", "pyte"} PTY_HELPERS = {"utils.terminal", "utils.mcp"} # Claude exports no spans on Windows, where ug writes no machine-wide Claude settings. @@ -50,38 +44,6 @@ } -def installer_environment( - base_environment: Mapping[str, str], - source_environment: Mapping[str, str], - credential_keys: Iterable[str], - npm_user_config: Path | None = None, -) -> dict[str, str]: - """Add only supported installer credentials to an isolated environment.""" - environment = dict(base_environment) - for key in credential_keys: - if value := source_environment.get(key): - environment[key] = value - if npm_user_config is not None: - environment["npm_config_userconfig"] = str(npm_user_config) - return environment - - -def npm_user_config(registry: str) -> str: - """Configure npm auth through an environment reference, never a raw token.""" - parsed = urllib.parse.urlsplit(registry) - if parsed.scheme not in {"http", "https"} or not parsed.netloc: - raise ValueError("The npm registry must be an absolute HTTP(S) URL.") - if parsed.username or parsed.password: - raise ValueError("The npm registry URL must not contain credentials.") - registry = registry.rstrip("/") + "/" - auth_path = parsed.path.rstrip("/") + "/" - return ( - f"registry={registry}\n" - f"//{parsed.netloc}{auth_path}:_authToken=${{{NPM_TOKEN_ENV}}}\n" - "always-auth=true\n" - ) - - def redact_secrets(value: str, secrets: Iterable[str]) -> str: for secret in sorted({secret for secret in secrets if secret}, key=len, reverse=True): value = value.replace(secret, "") @@ -519,16 +481,6 @@ def terminate(signum, frame): base_env["npm_config_fetch_timeout"] = "30000" base_env["UV_CACHE_DIR"] = str(output / "cache") base_env["UV_DEFAULT_INDEX"] = args.default_index - npm_token = os.environ.get(NPM_TOKEN_ENV, "") - npm_config = None - if npm_token: - npm_config = output / "installer.npmrc" - # npm expands the environment reference at request time. The short-lived - # token is never written to disk or included in an argument or URL. - npm_config.write_text(npm_user_config(args.npm_registry)) - python_install_env = installer_environment(base_env, os.environ, UV_INDEX_CREDENTIAL_ENV) - npm_install_env = installer_environment(base_env, os.environ, (NPM_TOKEN_ENV,), npm_config) - installer_secrets = tuple(os.environ.get(key, "") for key in INSTALLER_CREDENTIAL_ENV) bearer = os.environ.get("DATABRICKS_BEARER", "").strip() second_bearer = os.environ.get("DATABRICKS_SECOND_BEARER", "").strip() oauth_token = os.environ.get("CLAUDE_CODE_OAUTH_TOKEN", "").strip() @@ -542,7 +494,6 @@ def redact(value: str) -> str: second_bearer, oauth_token, *client_secrets, - *installer_secrets, ), ) @@ -631,7 +582,6 @@ def run(command, *, cwd=output, env=base_env, timeout=600) -> str: run( [uv, "build", "--wheel", "--out-dir", wheels, ROOT], cwd=ROOT, - env=python_install_env, ) (wheel,) = wheels.glob("*.whl") report["git_commit"] = run(["git", "rev-parse", "HEAD"], cwd=ROOT) @@ -664,7 +614,6 @@ def run(command, *, cwd=output, env=base_env, timeout=600) -> str: constraints.as_uri(), package, ], - env=python_install_env, ) run([uv, "pip", "check", "--python", python]) freeze = run([uv, "pip", "freeze", "--python", python]) @@ -731,7 +680,6 @@ def run(command, *, cwd=output, env=base_env, timeout=600) -> str: "--registry", args.npm_registry, ], - env=npm_install_env, ) else: run( @@ -747,7 +695,6 @@ def run(command, *, cwd=output, env=base_env, timeout=600) -> str: args.npm_registry, *[f"{AGENT_PACKAGES[a]}@{getattr(args, f'{a}_version')}" for a in agents], ], - env=npm_install_env, ) shutil.copyfile(npm_prefix / "package-lock.json", output / "npm-lock.json") report["npm_packages"] = json.loads( @@ -853,7 +800,6 @@ def run(command, *, cwd=output, env=base_env, timeout=600) -> str: args.default_index, *test_dependencies, ], - env=python_install_env, ) (output / "test-dependencies.txt").write_text( run([uv, "pip", "freeze", "--python", test_python]) + "\n" diff --git a/tests/test_integration_runner.py b/tests/test_integration_runner.py index 2ba161981..79e1abc92 100644 --- a/tests/test_integration_runner.py +++ b/tests/test_integration_runner.py @@ -9,57 +9,11 @@ def windows_live_environment(): return {"DATABRICKS_BEARER": "bearer"} -def test_installer_environment_scopes_registry_credentials(): - base = {"PATH": "tools", "UV_DEFAULT_INDEX": "databricks-pypi=https://example/simple"} - source = { - "UV_INDEX_DATABRICKS_PYPI_USERNAME": "oidc-user", - "UV_INDEX_DATABRICKS_PYPI_PASSWORD": "python-token", - "UG_INTEGRATION_NPM_TOKEN": "npm-token", - "UNRELATED_SECRET": "must-not-cross-the-boundary", - } - - python_environment = runner.installer_environment(base, source, runner.UV_INDEX_CREDENTIAL_ENV) - npm_environment = runner.installer_environment( - base, source, (runner.NPM_TOKEN_ENV,), Path("isolated.npmrc") - ) - - assert base == { - "PATH": "tools", - "UV_DEFAULT_INDEX": "databricks-pypi=https://example/simple", - } - assert python_environment == { - **base, - "UV_INDEX_DATABRICKS_PYPI_USERNAME": "oidc-user", - "UV_INDEX_DATABRICKS_PYPI_PASSWORD": "python-token", - } - assert npm_environment == { - **base, - "UG_INTEGRATION_NPM_TOKEN": "npm-token", - "npm_config_userconfig": "isolated.npmrc", - } - - -def test_npm_user_config_references_token_environment_without_embedding_it(): - config = runner.npm_user_config("https://registry.example.invalid/api/npm/db-npm/") - - assert config == ( - "registry=https://registry.example.invalid/api/npm/db-npm/\n" - "//registry.example.invalid/api/npm/db-npm/:_authToken=" - "${UG_INTEGRATION_NPM_TOKEN}\n" - "always-auth=true\n" - ) - - -def test_npm_user_config_rejects_credentials_in_registry_url(): - with pytest.raises(ValueError, match="must not contain credentials"): - runner.npm_user_config("https://user:token@example.invalid/npm/") - - -def test_installer_tokens_are_redacted_from_build_output(): - output = "failed for oidc-user with python-token and npm-token" +def test_secrets_are_redacted_from_build_output(): + output = "failed for bearer-a with token-b and token-c" assert ( - runner.redact_secrets(output, ("oidc-user", "python-token", "npm-token")) + runner.redact_secrets(output, ("bearer-a", "token-b", "token-c")) == "failed for with and " )