Skip to content

Fix #434: map "Local" auth_setting to ServerDefault - #446

Open
jacalata wants to merge 2 commits into
developmentfrom
jac/434-local-auth
Open

jacalata wants to merge 2 commits into
developmentfrom
jac/434-local-auth

Conversation

@jacalata

@jacalata jacalata commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Closes #434.

Motivation

tabcmd Classic accepts Local as an auth type on the CLI and in CSV
column 7, but TSC's UserItem.Auth enum has no Local value, so
passing it through crashed on server.users.add. Anyone importing a
Classic-authored CSV containing Local in column 7 hit a hard failure.

Behavior change

For users: Userdata.to_tsc_user() maps Local (case-insensitive)
to TSC.UserItem.Auth.ServerDefault and logs a WARNING naming the
affected user so the operator sees the remap happened. A silent remap
would be surprising -- if the site's actual default auth isn't the
same as Classic's Local, created users would have a different auth
method than intended.

Test plan

  • tests/commands/test_user_utils.py — 3 new tests cover exact-case
    Local, lowercase local, and non-Local pass-through
  • Test asserts the WARNING is emitted
  • Full test_user_utils.py suite: 18 passed

🤖 Generated with Claude Code

Source

Classic tabcmd's --auth-type help text (app-tabcmd/build/resources/main/com/tableausoftware/tabcmd/tabcmd_messages_en.properties:77) says "For Tableau Server, TYPE may be Local (default) or SAML" — but the Java source (app-tabcmd/src/.../commands/CreateSiteUsers.java:38-42) only accepts TableauId → DEFAULT, SAML → SAML, OpenID → OIDC. Classic will actually reject Local at CLI parse time. This PR handles what users expect based on the Classic docs (and what Cloud CSVs carrying per-row Local in the auth column produce), by mapping the incoming Local to ServerDefault and logging the remap. Not literal Classic parity — the Classic code never accepted Local — but matches Classic's documented behavior and Cloud CSV backward-compat.

tabcmd Classic accepts "Local" as an auth type on the CLI and CSV
column 7. tabcmd 2 kept "Local" in the accepted list but TSC's
UserItem.Auth enum has no Local value, so when the user reached
server.users.add() the wire representation raised ValueError.

Map Classic's "Local" -> TSC.UserItem.Auth.ServerDefault in
Userdata.to_tsc_user() so CSVs authored for Classic import cleanly.
Case-insensitive to match Classic behavior.

Fixes #434.
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tabcmd
   __main__.py121212 0%
   _version.py111111 0%
   tabcmd.py151515 0%
   version.py955 44%
tabcmd/commands
   commands.py101010 0%
   constants.py771818 77%
   server.py1351818 87%
tabcmd/commands/auth
   session.py3945050 87%
tabcmd/commands/datasources_and_workbooks
   datasources_and_workbooks_command.py1571818 89%
   datasources_workbooks_views_url_parser.py14255 96%
   delete_command.py601616 73%
   export_command.py1202525 79%
   get_url_command.py1274747 63%
   publish_command.py1232828 77%
   runschedule_command.py2177 67%
tabcmd/commands/extracts
   create_extracts_command.py4288 81%
   decrypt_extracts_command.py2722 93%
   delete_extracts_command.py3766 84%
   encrypt_extracts_command.py2722 93%
   extracts.py2022 90%
   reencrypt_extracts_command.py2722 93%
   refresh_extracts_command.py481010 79%
tabcmd/commands/group
   create_group_command.py2955 83%
   delete_group_command.py2722 93%
tabcmd/commands/project
   create_project_command.py4688 83%
   delete_project_command.py3544 89%
   publish_samples_command.py3044 87%
tabcmd/commands/site
   create_site_command.py3455 85%
   delete_site_command.py2722 93%
   edit_site_command.py3822 95%
   list_command.py771212 84%
   list_sites_command.py2922 93%
tabcmd/commands/user
   add_users_command.py2955 83%
   create_site_users.py581111 81%
   create_users_command.py5999 85%
   delete_site_users_command.py4355 88%
   user_data.py2263030 87%
tabcmd/execution
   _version.py222 0%
   global_options.py12588 94%
   localize.py661111 83%
   logger_config.py6066 90%
   tabcmd_controller.py4277 83%
TOTAL287745784% 

A silent remap is surprising: an operator who typed Local (or imported a
Classic CSV that uses it) previously got a user with ServerDefault auth
and no signal that anything changed. Emit a WARNING that names the user
and states both the input and remapped auth so the operator can spot
unexpected remaps in a large batch. Adds a matching assertion in the
existing test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

The CLI override bypasses remapping, warning visibility and compiled localization need fixes, and a test assertion must be stabilized.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity · 1 Medium severity · 1 Low severity

Open (3)
What changed in this PR

Maps case-insensitive Local authentication values to TSC’s ServerDefault and logs a warning.

Changes:

  • Adds auth remapping and warning behavior.
  • Adds English localization text.
  • Adds unit tests for remapping and pass-through behavior.
File Summary
tests/​commands/​test_user_utils.py Adds remapping tests; the warning assertion depends on the stale localization key (nit, 2 votes).
tabcmd/​locales/​en/​tabcmd_messages_en.properties Adds warning text; compiled localization artifacts remain outdated (moderate, 3 votes).
tabcmd/​commands/​user/​user_data.py Implements CSV remapping, but CLI overrides bypass it (critical, 3 votes); warning output also misses the configured command logger (moderate, 1 vote).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +51 to +55
auth = self.auth
if isinstance(auth, str) and auth.lower() == "local":
logging.getLogger(__name__).warning(
_("tabcmd.user.warning.local_auth_remapped").format(self.name)
)
tabcmd.status.waiting_for_refresh_job=Waiting for refresh job to begin
tabcmd.user.error.site_role_required=Site role is required
tabcmd.user.help.auth_type=Assigns the authentication type for all users in the CSV file. Possible values:
tabcmd.user.warning.local_auth_remapped=User "{0}": auth_setting "Local" is not a Tableau Server auth type; mapped to ServerDefault. The site's default auth method will be used.
Comment on lines +164 to +166
# In tests the gettext catalog isn't loaded, so `_()` returns the raw key;
# we just assert the localize key made it to the log record.
assert any("local_auth_remapped" in msg for msg in logs.output), logs.output
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.

2 participants