Skip to content

Fix review findings in saved-session restore (follow-up to #490) - #491

Open
jacalata wants to merge 6 commits into
developmentfrom
jac/fix-session-restore-review
Open

jacalata wants to merge 6 commits into
developmentfrom
jac/fix-session-restore-review

Conversation

@jacalata

@jacalata jacalata commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #490. Addresses the Copilot review comments on that PR and the problems found in a full review of session.py. Each item is stated as problem, then fix.

Saved-session reuse

  • Problem: a saved token was reattached regardless of which server or site the new command targeted. Fix: it is reused only when server and site match the saved ones; otherwise the command signs in normally.
  • Problem: if the saved session's server URL could not be opened (for example a malformed URL), the process exited instead of falling back to a normal sign-in. Fix: the failure is caught and the command falls back.
  • Problem: logout only deleted the local file, leaving the token valid on the server. Fix: it signs the saved token out on the server first. A failed server sign-out is logged and does not stop the local cleanup, and a live session is signed out once, not twice.
  • Problem: site names were lowercased when saved, but site names are case-sensitive. Fix: they keep their case. default still maps to the default site, and username and server URL are still lowercased.
  • --server clears the saved site, so logging in to a new server does not carry over the old site.

Session file

  • Problem: ~/tableau_auth.json was written with default permissions and holds the token or PAT secret. Fix: it is created with mode 0600. A failed chmod is logged and the write still happens.
  • Problem: proxy and HTTP option values could appear in logs, including proxy credentials. Fix: they are redacted.
  • Problem: a partially written or empty file could be half-loaded and then wiped. Fix: loading uses safe lookups and stops after clearing an empty file.

Cleanups

  • Removed the duplicated TOKEN_CRED_TYPE / PASSWORD_CRED_TYPE definitions, the unused last_command, and several dead checks.
  • Sign-in reads the token from the public auth_token property instead of a private attribute.

Tests

  • test_session.py goes from a handful of tests to about 105. Several earlier assertions always passed (was_called() is always truthy on a mock); they now assert real behaviour.
  • The test module no longer reads or deletes the real ~/tableau_auth.json.

Sessions saved by older versions have a lowercased site name. If a later command passes -t with different casing, that session is not reused and the command signs in again.

🤖 Generated with Claude Code

jacalata and others added 3 commits November 2, 2026 17:15
Review of the #490 session-restore change, plus fixes found while reviewing
session.py as a whole.

Restore saved session:
- Do not reuse the saved token when --server or --site targets a different
  server or site than the one it was saved for.
- Attach the saved token inside the try block, so a failure falls back to a
  fresh sign-in instead of aborting the command.

Session file:
- Create the file with mode 0600 and tighten existing files on save.
- Redact user:password in proxy URLs wherever they are logged.
- Load optional keys with .get() so a file from another version keeps the
  session.

Logic fixes:
- host:port server URLs get the default https scheme before parsing.
- logout signs out the saved token on the server; local cleanup still runs
  if that fails.
- _clear_data resets server_url (it previously reset a nonexistent attribute).
- Token name prints only when set; certificate prints independently.
- Trailing newline is stripped from password and token files.
- Proxy applies to https as well as http.
- Timeout values of zero or less become 0.
- Empty session file is wiped once.
- Site name keeps its case; only the "default" check is case-insensitive.

Cleanup: remove duplicate credential-type constants, duplicate logging_level
assignment, redundant session-file read, and unused exception bindings.

Tests: replace was_called()/has_been_called() (always truthy on a mock) with
real assertions, fix clear_session which was never collected, and add
coverage for the fixes and for _update_session_data, _sign_in,
_validate_existing_signin, saved credentials, --no-cookie, and logout.

Co-Authored-By: Claude Code <noreply@anthropic.com>
… tests

- Read the saved token from TSC's public auth_token property, not _auth_token.
- Log validation failures with the shared internal_error message.
- Remove connection checks that could not fire after the connection is set.
- Remove the unused last_command attribute.
- Add tests for _remove_json, _wipe_bad_json and an unreadable session file.

Co-Authored-By: Claude Code <noreply@anthropic.com>
…ate session tests

- Catch SystemExit from _open_connection_with_opts in session restore and
  saved-token sign-out so a bad server URL falls back instead of exiting.
- Restore the unexpected_server_response message for ServerResponseError.
- Sign out the saved token only when there is no live connection.
- Patch Session._get_file_path for the whole test module so tests never
  touch the real ~/tableau_auth.json.
- Add tests for connection failures, live-session logout and chmod failure.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 3, 2026 01:50
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
tabcmd
   __main__.py121212 0%
   _version.py111111 0%
   tabcmd.py151515 0%
   version.py1066 40%
tabcmd/commands
   commands.py101010 0%
   constants.py771414 82%
   server.py1351818 87%
tabcmd/commands/auth
   session.py4553131 93%
tabcmd/commands/datasources_and_workbooks
   datasources_and_workbooks_command.py1701818 89%
   datasources_workbooks_views_url_parser.py14255 96%
   delete_command.py702323 67%
   export_command.py1262121 83%
   get_url_command.py1274747 63%
   publish_command.py1341616 88%
   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.py661818 73%
   list_command.py771212 84%
   list_sites_command.py2922 93%
tabcmd/commands/user
   add_users_command.py2955 83%
   create_site_users.py1151414 88%
   create_users_command.py5999 85%
   delete_site_users_command.py4355 88%
   user_data.py2223131 86%
tabcmd/execution
   _version.py222 0%
   global_options.py15544 97%
   localize.py671111 84%
   logger_config.py7266 92%
   tabcmd_controller.py4077 82%
TOTAL310344286% 

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.

🟡 Changes recommended

Scheme-relative server URLs break sign-in, and logout ignores explicit HTTP options and can block indefinitely without a finite timeout, preventing local cleanup.

3 open issues
What changed in this PR

This follow-up to #490 hardens saved-session handling in tabcmd and expands regression coverage for authentication and local session storage.

Changes:

  • Restricts saved-token reuse to matching servers and sites, preserves site-name casing, and adds server-side logout.
  • Tightens session-file permissions, redacts proxy credentials in logs, and improves URL, timeout, and credential-file handling.
  • Expands session tests, replaces ineffective mock assertions, and isolates tests from the real session file.
File Description
tests/​commands/​test_session.py Expands authentication, logout, storage, and connection-option tests with isolated session files.
tabcmd/​commands/​auth/​session.py Hardens session restoration, logout, credential storage, and connection handling.

Review effort: Balanced

Comment thread tabcmd/commands/auth/session.py Resolved
Comment thread tabcmd/commands/auth/session.py Resolved
Comment thread tabcmd/commands/auth/session.py Resolved
…acks

- _get_server_base_url: only a leading scheme:// counts as a scheme; handle
  scheme-relative URLs; reject URLs with no host instead of silently falling
  back to the saved server or http://localhost.
- logout honours --proxy, --no-proxy, --timeout, --certificate and
  --no-certcheck. --server and --site are not forwarded.
- Session probe and logout sign-out default to a 30 second timeout when
  --timeout is not set. Other commands still wait for the server.
- Those two paths raise instead of printing an error and exiting when the
  connection cannot be opened.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 3, 2026 05:13

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.

🟡 Changes recommended

The 30-second probe timeout persists on the returned session, potentially causing long-running commands to fail unexpectedly; restore the configured timeout and add regression coverage.

2 open issues
2 resolved since last review

Review effort: Balanced

Comment on lines +363 to +365
server = self._open_connection_with_opts(
raise_on_failure=True, default_timeout=DEFAULT_SESSION_REQUEST_TIMEOUT
)
Co-Authored-By: Claude Code <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 4, 2026 01:51

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.

🟡 Changes recommended

The restore probe’s 30-second timeout persists on the returned server, causing long-running commands using saved sessions to time out unexpectedly when no user timeout was specified.

3 open issues
1 resolved since last review

Review effort: Balanced

logger.debug(_("tabcmd.launching"))
session = Session()
# only the connection options; --server and --site must not redirect the saved token
session._update_http_options(args)
Comment thread tests/commands/test_session.py Resolved
The probe used a 30 second timeout, and that value stayed on the server
returned to the command. Commands that run with a saved session and no
--timeout could then fail on slow responses instead of waiting. Reset the
timeout to the configured value once the probe succeeds.

Logout also reapplies the requested logging level, since creating the
Session resets the root logger to INFO.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings November 7, 2026 06:19

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 was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

This branch has not been deployed

No deployments
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