From 30243d46eb18888f5965a33996a338800bfbc937 Mon Sep 17 00:00:00 2001 From: Jac Date: Mon, 2 Nov 2026 10:48:05 -0800 Subject: [PATCH 1/2] test(e2e): round-trip CSVImport bug coverage for TSC #1811 (#472) * test(e2e): round-trip CSVImport bug coverage for #1811 Adds a two-row CSV fixture and one createsiteusers e2e test exercising every UserItem.CSVImport bug fixed in TSC #1811 (issue #1809): AUTH column readable at 8 columns, mixed-case usernames preserved, TableauIDWithMFA in the auth allowlist, case-insensitive validation of role/admin/publisher tokens, and the @property_is_enum guard active on the parsed auth_setting. Test runs under the same server-admin / site-admin gate as test_users_create_site_users and shares its ordering slot; skips cleanly when the caller lacks admin scope or a credentials file. Related: #297 (license-name case sensitivity still surfacing after partial fixes), #434 (Local auth accepted by the CLI but crashes on TSC call). * test(e2e): pass --no-complete + drop --role Publisher on CSVImport 1811 test `createsiteusers` runs `--complete` by default, which invokes tabcmd's duplicate strict validator (`UserCommand._validate_user_or_throw`). That validator rejects `len(line) > 7` and validates license values case-sensitively -- both of which the CSVImport #1811 fixture is specifically meant to exercise. Under `--complete`, the CSV never reached TSC's `UserItem.CSVImport` and the test fell through tabcmd-side. `--no-complete` skips tabcmd's validator so the fixture reaches TSC's parser. Removing `--role Publisher` lets each row's own license field be validated -- restoring coverage of the case-insensitive-license fix. Also corrected the docstring: five of the six bugs, since the sixth (unknown-AUTH rejection) is a negative-path check that doesn't fit a single happy-path fixture and is already covered by TSC's unit tests. * docs: correct test docstring -- this test doesn't reach TSC's CSVImport yet createsiteusers parses the CSV itself via UserCommand.get_users_from_file() / _parse_line() and builds TSC.UserItem directly; it doesn't delegate to TSC's UserItem.CSVImport. The docstring claimed the opposite. Co-Authored-By: Claude Code * test(e2e): use a valid TSC auth value in the CSVImport fixture TableauID is not a member of TSC.UserItem.Auth in the pinned tableauserverclient (0.42), so the first row raised ValueError before the server call. Use ServerDefault for that row. Co-Authored-By: Claude Code --------- Co-authored-by: Claude Code --- tests/assets/users_csvimport_bugs_1811.csv | 2 ++ tests/e2e/online_tests.py | 39 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/assets/users_csvimport_bugs_1811.csv diff --git a/tests/assets/users_csvimport_bugs_1811.csv b/tests/assets/users_csvimport_bugs_1811.csv new file mode 100644 index 00000000..c63ae1bc --- /dev/null +++ b/tests/assets/users_csvimport_bugs_1811.csv @@ -0,0 +1,2 @@ +UserMixedCase_1811_A@example.com, ,"Mixed Case LDAP User 1811A",Viewer,none,no,mixedcase_1811_a@example.com,ServerDefault +UserMixedCase_1811_B@example.com, ,"MFA User 1811B",Creator,none,no,mfa_1811_b@example.com,TableauIDWithMFA diff --git a/tests/e2e/online_tests.py b/tests/e2e/online_tests.py index 8f1d50d6..a2229045 100644 --- a/tests/e2e/online_tests.py +++ b/tests/e2e/online_tests.py @@ -74,6 +74,7 @@ def get_publishable_name(file_value: str) -> str: TWB_FILE_WITH_EMBEDDED_CONNECTION = "EmbeddedCredentials.twb" USERS_DETAILS_FILE = "detailed_users.csv" + USERS_CSVIMPORT_1811_FILE = "users_csvimport_bugs_1811.csv" USERNAMES_FILE = "usernames.csv" @@ -316,6 +317,44 @@ def test_users_create_site_users(self): arguments = [command, users, "--role", "Publisher"] _test_command(arguments) + @pytest.mark.order(2) + def test_users_create_site_users_csvimport_bugs_1811(self): + """Round-trip coverage for five of the six ``UserItem.CSVImport`` bugs + fixed in tableau/server-client-python#1811 (issue #1809). Once tabcmd + delegates its CSV stack to TSC's ``CSVImport``, this fixture is the + regression guarantee that the delegation preserved each fix. + + Exercises, in one two-row CSV: + + * the 8-column AUTH bound (row length now readable), + * mixed-case usernames preserved verbatim (case-sensitive auth systems), + * ``TableauIDWithMFA`` accepted in the auth allowlist, + * capitalised role/admin/publisher tokens accepted case-insensitively, + * the ``@property_is_enum(Auth)`` guard active on the parsed + ``UserItem.auth_setting``. + + The sixth bug (unknown-AUTH rejection) is a negative-path check that + doesn't fit a single happy-path fixture; TSC's own unit tests cover it. + + ``--no-complete`` skips tabcmd's duplicate strict validator so the CSV + reaches tabcmd's own row parser (``UserCommand.get_users_from_file`` / + ``_parse_line``), which builds the ``TSC.UserItem`` directly -- tabcmd + doesn't delegate to TSC's ``UserItem.CSVImport`` yet, so this exercises + the same validation rules #1811 fixed, via tabcmd's current parsing + path rather than through ``CSVImport`` itself. No ``--role`` override, + so the role field in each row is what gets validated (that's the point + of the case-insensitivity check). + + Related: tabcmd #297 (license-name case sensitivity), #434 (``Local`` + auth accepted by the CLI but rejected server-side). + """ + if not server_admin and not site_admin: + pytest.skip("Must be server or site administrator to create site users") + command = "createsiteusers" + users = os.path.join("tests", "assets", TestAssets.USERS_CSVIMPORT_1811_FILE) + arguments = [command, users, "--no-complete"] + _test_command(arguments) + @pytest.mark.order(3) def test_group_creategroup(self): if not server_admin and not site_admin: From df274cc331626aebed40a517bda4a12caf9bb935 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2026 11:42:31 +0000 Subject: [PATCH 2/2] Bump github/codeql-action from 4.39.1 to 4.39.3 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.39.1 to 4.39.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v4.39.1...v4.39.3) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.39.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 770fed93..05c01c1f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v4.39.1 + uses: github/codeql-action/init@v4.39.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,6 +53,6 @@ jobs: # queries: security-extended,security-and-quality - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4.39.1 + uses: github/codeql-action/analyze@v4.39.3 with: category: "/language:${{matrix.language}}"