Skip to content

air: strip control characters from server-supplied names in air list and air get - #7601

Merged
dimk0 merged 2 commits into
mainfrom
air-strip-control-chars
Nov 14, 2026
Merged

dimk0 merged 2 commits into
mainfrom
air-strip-control-chars

Conversation

@dimk0

@dimk0 dimk0 commented Nov 13, 2026

Copy link
Copy Markdown
Member

Changes

  • A new stripControl helper in cmd/air removes terminal escape sequences (CSI, OSC, DCS, ...) and C0/C1 control characters from a string. Printable text, including non-ASCII, is kept.
  • It is applied where server-supplied names become display values:
    • the MLflow run name as it is fetched (fetchMLflowRunName), before it is shortened to the column width or written to the air list cache;
    • every air list table cell (cell), which also covers rows read from a cache written before this change;
    • the Experiment, MLflow Run and User fields of the air get box and the air list info pane (renderFields).
  • JSON output and link targets are unchanged.
  • The logs pane and air logs are out of scope: training logs legitimately contain colour codes.

Why

air list and air get printed the MLflow run name, experiment name and user name exactly as the server sent them. A name carrying a set-window-title sequence (OSC 0), a clear-screen sequence (CSI 2J) or a carriage return reached the terminal of anyone who listed the run, for example with --all-users, so whoever named a run could clear the screen, retitle the window, write the clipboard (OSC 52) or overwrite a line so a fake row appeared. Not code execution; low to moderate severity. Pre-existing before #7582. Internal ticket: CNXT-2620.

Tests

  • TestStripControl: OSC terminated by BEL and by ST, OSC 52, CSI clear-screen and colour, carriage return, tab and newline, DEL, C1 controls, NUL, a two-byte escape sequence, a trailing ESC; plain and non-ASCII text are unchanged.
  • TestFetchMLflowRunName gains a case where the MLflow API returns a name with an OSC, a CSI and a carriage return.
  • TestRenderFieldsStripsControlCharacters and TestRenderRowStripsControlCharacters cover the air get box and the air list row, and check that column widths still line up.
  • New acceptance test acceptance/air/control-chars: air get and air list text output with escapes in the run name, experiment name and creator; air list -o json shows the strings passed through unchanged. Verified to fail without the fix.

This pull request and its description were written by Isaac.

@dimk0
dimk0 requested review from a team as code owners November 13, 2026 13:14
@dimk0
dimk0 requested a review from anton-107 November 13, 2026 13:14
dimk0 pushed a commit that referenced this pull request Nov 13, 2026
Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions github-actions Bot added the AIR Databricks AI Runtime CLI label Nov 13, 2026
dimk0 pushed a commit that referenced this pull request Nov 13, 2026
Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Commit: 2118b25de | Workflow run

Regression test report

Selected 1 changed tests (limit=20, 0 not selected)

1 tests: regression=1 unreleased=0 coverage=0 failing=0
test branch main (bdb37ab) latest (v1.26.0)
TestAccept/air/control-chars ✅ ❌ ❌
TestAccept/air/control-chars: branch ✅ | main (bdb37ab) ❌ | latest (v1.26.0) ❌

main (bdb37ab):

acceptance_test.go:1374: Diff:
        --- air/control-chars/output.txt
        +++ /tmp/TestAcceptaircontrol-chars1859562620/002/output.txt
        @@ -11,9 +11,10 @@
         │  Retries       0                                               │
         │  Max Retries   0                                               │
         │  Duration      12s                                             │
        -│  Experiment    my-exp                                          │
        -│  MLflow Run    my-run                                          │
        -│  User          user@example.com                                │
        +│  Experiment    my�]0;pwned�-exp                                          │
        +│  MLflow Run    �]0;pwned�my�[2J-run
        +                                          │
        +│  User          user�[31m@example.com                                │
         │  Accelerators  1x A10                                          │
         │  Environment   N/A                                             │
         │                                                                │
        @@ -26,7 +27,8 @@
         
         >>> [CLI] air list --all-users
            Run ID  Experiment  Status     Started              Duration  Progress  MLflow                  User              Accelerators
        -   123     my-exp      ● SUCCESS  [TIMESTAMP]       12s         -  my-run                  user@example.com  1x A10
        +   123     my�]0;pwned�-exp      ● SUCCESS  [TIMESTAMP]       12s         -  �]0;pwned�my�[2J-run
        +                  user�[31m@example.com  1x A10
         
         === list (json): strings are passed through as the server sent them
         
        
FAIL

latest (v1.26.0):

acceptance_test.go:1374: Diff:
        --- air/control-chars/output.txt
        +++ /tmp/TestAcceptaircontrol-chars452064892/002/output.txt
        @@ -11,9 +11,10 @@
         │  Retries       0                                               │
         │  Max Retries   0                                               │
         │  Duration      12s                                             │
        -│  Experiment    my-exp                                          │
        -│  MLflow Run    my-run                                          │
        -│  User          user@example.com                                │
        +│  Experiment    my�]0;pwned�-exp                                          │
        +│  MLflow Run    �]0;pwned�my�[2J-run
        +                                          │
        +│  User          user�[31m@example.com                                │
         │  Accelerators  1x A10                                          │
         │  Environment   N/A                                             │
         │                                                                │
        @@ -26,7 +27,8 @@
         
         >>> [CLI] air list --all-users
            Run ID  Experiment  Status     Started              Duration  Progress  MLflow                  User              Accelerators
        -   123     my-exp      ● SUCCESS  [TIMESTAMP]       12s         -  my-run                  user@example.com  1x A10
        +   123     my�]0;pwned�-exp      ● SUCCESS  [TIMESTAMP]       12s         -  �]0;pwned�my�[2J-run
        +                  user�[31m@example.com  1x A10
         
         === list (json): strings are passed through as the server sent them
         
        @@ -42,12 +44,7 @@
                 "user": "user\u001b[31m@example.com",
                 "status": "SUCCESS",
                 "started_at": "[TIMESTAMP]",
        -        "is_sweep": false,
        -        "experiment_name": "my\u001b]0;pwned\u0007-exp",
        -        "duration_seconds": 12,
        -        "accelerator_type": "GPU_1xA10",
        -        "num_accelerators": 1,
        -        "dashboard_url": "[DATABRICKS_URL]/jobs/runs/123?o=[WORKSPACE_ID]"
        +        "is_sweep": false
               }
             ]
           }
        
FAIL

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Integration test report

Commit: 2118b25

Run: 43548233730

Env 🔄​flaky 💚​RECOVERED ✅​pass 🙈​skip Time
🔄​ aws linux-2core-8gb 2 1 268 16 5:44
💚​ aws-windows-latest-4core-16gb 1 272 14 5:56
💚​ azure linux-2core-8gb 1 269 16 4:41
💚​ azure-windows-latest-4core-16gb 1 271 14 5:40
💚​ gcp linux-2core-8gb 1 270 16 5:21
💚​ gcp-windows-latest-4core-16gb 1 272 14 5:51
Test Name aws linux-2core-8gb aws-windows-latest-4core-16gb azure linux-2core-8gb azure-windows-latest-4core-16gb gcp linux-2core-8gb gcp-windows-latest-4core-16gb
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🔄​ TestFilerWorkspaceNotebook 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestFilerWorkspaceNotebook/rJupyterNb.ipynb 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
Top 3 slowest tests (at least 2 minutes):
duration env testname
5:52 aws-windows-latest-4core-16gb TestAccept
5:45 gcp-windows-latest-4core-16gb TestAccept
5:09 azure-windows-latest-4core-16gb TestAccept

dimk0 pushed a commit that referenced this pull request Nov 13, 2026
The fragment belongs to PR #7601's branch, not this one; here it fails
the changelog validator because its link does not include #7598.

This reverts commit 95e6c90.

Co-authored-by: Isaac <no-reply@databricks.com>

@caroline-db caroline-db 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.

lgtm

@dimk0
dimk0 added this pull request to the merge queue Nov 14, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 14, 2026
@dimk0
dimk0 added this pull request to the merge queue Nov 14, 2026
Dima Kotlyarov and others added 2 commits November 14, 2026 02:46
…and air get

`air list` and `air get` showed the MLflow run name, experiment name and
user name as the server sent them, so a name carrying terminal escape
sequences reached the terminal of anyone who listed the run. A new
`stripControl` helper drops escape sequences (CSI, OSC, DCS, ...) and
C0/C1 control characters, and is applied where those names become display
values: the MLflow run name as it is fetched (before it is shortened or
cached), each `air list` table cell, and the Experiment, MLflow Run and
User fields of the `air get` box and the `air list` info pane. JSON output
and link targets are unchanged.

Internal ticket: CNXT-2620.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
@dimk0
dimk0 removed this pull request from the merge queue due to a manual request Nov 14, 2026
@dimk0
dimk0 force-pushed the air-strip-control-chars branch from fe99575 to 2118b25 Compare November 14, 2026 02:46
@dimk0
dimk0 enabled auto-merge November 14, 2026 02:47
@dimk0
dimk0 added this pull request to the merge queue Nov 14, 2026
Merged via the queue into main with commit 2699068 Nov 14, 2026
28 checks passed
@dimk0
dimk0 deleted the air-strip-control-chars branch November 14, 2026 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AIR Databricks AI Runtime CLI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants