Skip to content

ssh: always re-upload dev builds of the tunnel binary - #6820

Merged
anton-107 merged 1 commit into
mainfrom
ssh-dev-upload-overwrite
Sep 24, 2026
Merged

anton-107 merged 1 commit into
mainfrom
ssh-dev-upload-overwrite

Conversation

@anton-107

Copy link
Copy Markdown
Contributor

Changes

uploadReleases no longer skips the upload for dev and snapshot versions (build.IsDevelopmentVersion) when the binary already exists at the versioned workspace path. Release versions still skip the upload.

Also updates the rule in experimental/ssh/CLAUDE.md that said to delete the versioned workspace directory before re-verifying. After this change, the remaining pitfall is that connect reuses a server that's already running the previous binary.

 uploadReleases(version)
   for arch in [amd64, arm64]
-    if binary exists at the versioned path
-      continue                   # rebuilt dev binary silently not uploaded
+    if IsDevelopmentVersion(version)
+      log "overwriting"          # rebuilt without a commit keeps its version string
+    else if binary exists at the versioned path
+      continue                   # a released version's binary never changes
     upload databricks.zip        # import-file unzips it next to the binary

Why

Dev and snapshot builds keep the same version string when rebuilt without a new commit. The rebuilt binary was silently not re-uploaded, and the cluster kept running the old one. Re-uploading dev builds every time costs only CLI developers.

Possible follow-up, out of scope here: getReleaseName still detects dev versions with strings.Contains(version, "dev") instead of build.IsDevelopmentVersion.

Tests

  • New TestUploadReleasesWithExistingBinary. The dev version re-uploads both arches, and the release version skips. It fails without the fix.
  • TestSSHServerBootstrap fails locally on main too, because the local interpreter is Python 3.6. That failure is unrelated to this change.

This pull request and its description were written by Isaac.

uploadReleases skipped the upload whenever the binary already existed at the
versioned workspace path. Dev and snapshot builds keep the same version string
when rebuilt without a new commit, so the rebuilt binary was silently not
uploaded and the cluster kept running the old one. Dev versions now always
overwrite; release versions still skip.

Co-authored-by: Isaac <no-reply@databricks.com>
@anton-107
anton-107 requested a review from a team as a code owner September 23, 2026 14:36
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 51ee98a

Run: 35875477212

Env ✅​pass 🙈​skip Time
✅​ aws linux 276 15 8:58
✅​ aws windows 278 13 7:07
✅​ azure linux 275 15 7:17
✅​ azure windows 277 13 5:06
✅​ gcp linux 276 15 7:45
✅​ gcp windows 278 13 4:45
Top 4 slowest tests (at least 2 minutes):
duration env testname
5:39 aws windows TestAccept
4:38 gcp windows TestAccept
3:41 azure windows TestAccept
2:08 gcp linux TestFilerWorkspaceFilesExtensionsReadDir

@simonfaltum simonfaltum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review (automated, 1 agent(s))

Verdict: Approved

0 Critical | 0 Major | 1 Gap (Nit) | 0 Nit | 0 Suggestion

See inline comments for details.

Comment on lines +103 to +140
func TestUploadReleasesWithExistingBinary(t *testing.T) {
tests := []struct {
name string
version string
wantUploaded []string
}{
{
name: "release version skips the upload",
version: "1.12.0",
wantUploaded: nil,
},
{
name: "dev version overwrites the binary",
version: "1.12.1-dev+abcdef123456",
wantUploaded: []string{"amd64", "arm64"},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := t.Context()
workspaceFiler, err := filer.NewLocalClient(t.TempDir())
require.NoError(t, err)
for _, arch := range []string{"amd64", "arm64"} {
remoteBinaryPath := strings.TrimSuffix(getReleaseName(arch, tt.version), ".zip") + "/databricks"
err := workspaceFiler.Write(ctx, remoteBinaryPath, strings.NewReader("old"), filer.CreateParentDirectories)
require.NoError(t, err)
}

var uploaded []string
getRelease := func(ctx context.Context, architecture, version, releasesDir string) (io.ReadCloser, error) {
uploaded = append(uploaded, architecture)
return io.NopCloser(strings.NewReader("new")), nil
}

err = uploadReleases(ctx, workspaceFiler, getRelease, tt.version, "")
require.NoError(t, err)
assert.Equal(t, tt.wantUploaded, uploaded)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Gap (Nit)] Test asserts getRelease was called, not that overwrite landed

TestUploadReleasesWithExistingBinary does fail without the skip fix: both cases seed remoteBinaryPath, so Stat succeeds, and the pre-fix loop would continue for the dev version too. That part is good, and the release case is a useful guard against “always upload.” It does not, however, assert overwrite. After uploadReleases the test only compares the uploaded slice; it never Reads anything. Setup writes "old" to {release}/databricks (the Stat path). Production writes "new" to {release}/databricks.zip with filer.OverwriteIfExists. Those are different paths. Under LocalClient, the zip path does not exist yet, so Write would succeed even without OverwriteIfExists. The case named “dev version overwrites the binary” therefore does not show that new bytes replaced old ones. LocalClient also does not unzip, so it cannot honestly assert the databricks file content anyway.

Suggestion: After a successful upload, for the dev case Read {release}/databricks.zip and assert the body is "new"; for the release case assert that zip was not created and {release}/databricks is still "old". Stronger still: also pre-seed the zip path with "old" so dropping OverwriteIfExists fails locally. Do not assert {release}/databricks became "new" in this unit test — that only happens via workspace import-file unzip.

@rclarey rclarey left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manually tested with --debug and works as expected ✅

@anton-107
anton-107 added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 3cb46b8 Sep 24, 2026
29 of 30 checks passed
@anton-107
anton-107 deleted the ssh-dev-upload-overwrite branch September 24, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants