Skip to content

feat(session): serve session expiry from VIPER 2, not the legacy CFM - #304

Open
rlorenzo wants to merge 1 commit into
fix/session-refresh-pathbasefrom
feature/session-timeout-endpoint
Open

rlorenzo wants to merge 1 commit into
fix/session-refresh-pathbasefrom
feature/session-timeout-endpoint

Conversation

@rlorenzo

@rlorenzo rlorenzo commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Stacked on #302. Review that one first.

Replaces the Razor dialog's poll to legacy seconds_until_timeout_v2.cfm with GET /api/sessionTimeout. The CFM took loginID as an unauthenticated query parameter, so anyone could read anyone's expiry. The new endpoint takes no parameters and derives the user from the cookie.

The endpoint must never extend the session. ApiController and AreaController both renew it on every action, so SessionTimeoutController inherits ControllerBase. A reflection test pins that. Because the poll is now same-origin it also passes through cookie authentication, so OnCheckSlidingExpiration declines to slide the auth cookie for this endpoint; otherwise an open tab could keep a login alive past its 12 hours. It is [AllowAnonymous] (main's FallbackPolicy would otherwise redirect an expired cookie to CAS) so a caller with no session gets 0 seconds and a Log in button.

SessionTimeoutService.GetStatus builds the response for both this endpoint and RefreshSession, so both carry the local UTC offset and neither leaks the entity. A user with a valid cookie but no row (pages served by a plain Controller never write one) gets a full window instead of "expired". DB errors return 600 seconds like the CFM did. The three branches are unit tested.

Also: anonymous visitors no longer poll; the warning clears itself when the session is extended in another tab; midnight renders as 12 AM.

The SPA still uses the CFM. #306 migrates it.

@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from 95891e8 to b893056 Compare August 7, 2026 19:17
@rlorenzo

rlorenzo commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 3f0bc404-1702-4e51-8529-3bab6cf20a0c

📥 Commits

Reviewing files that changed from the base of the PR and between bc04fe0 and 551ed0c.

📒 Files selected for processing (11)
  • test/Classes/AuthorizationFallbackTests.cs
  • test/Classes/SessionTimeoutServiceTests.cs
  • test/Controllers/SessionTimeoutControllerTests.cs
  • web/Classes/Utilities/SessionTimeoutService.cs
  • web/Controllers/HomeController.cs
  • web/Controllers/SessionTimeoutController.cs
  • web/Models/SessionTimeoutCheck.cs
  • web/Models/SessionTimeoutStatus.cs
  • web/Program.cs
  • web/Views/Shared/Components/SessionTimeout/Default.cshtml
  • web/Views/Shared/Components/SessionTimeout/SessionTimeout.cs
💤 Files with no reviewable changes (1)
  • web/Models/SessionTimeoutCheck.cs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds a session-timeout status model and API, prevents timeout polling from extending authentication cookies, updates the session-timeout view, and replaces the previous status model and service method.

Changes

Session timeout status and service

Layer / File(s) Summary
Status contract and conversion
web/Models/SessionTimeoutStatus.cs, web/Models/SessionTimeoutCheck.cs, web/Classes/Utilities/SessionTimeoutService.cs, test/Classes/SessionTimeoutServiceTests.cs
Adds SessionTimeoutStatus, removes SessionTimeoutCheck, and maps stored, authenticated, and anonymous sessions to status values.
Session timeout endpoint and cookie control
web/Controllers/SessionTimeoutController.cs, web/Program.cs, test/Controllers/SessionTimeoutControllerTests.cs, test/Classes/AuthorizationFallbackTests.cs
Adds the anonymous /api/sessionTimeout endpoint, handles read failures, and prevents cookie renewal for timeout requests.
Session timeout view integration
web/Views/Shared/Components/SessionTimeout/*, web/Controllers/HomeController.cs
Polls the new endpoint, updates warning behavior and time formatting, renders only for authenticated users, and returns the new status from session refresh.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 551ed

This replaces Razor timeout polling with a non-renewing session-status API, updates warning behavior, and preserves session refresh status responses. No concrete current-head merge-blocking risk is identified.

Sequence Diagram(s)

sequenceDiagram
  participant SessionTimeoutView
  participant SessionTimeoutController
  participant SessionTimeoutService
  participant VIPERContext
  SessionTimeoutView->>SessionTimeoutController: GET /api/sessionTimeout
  SessionTimeoutController->>SessionTimeoutService: GetStatus(VIPERContext)
  SessionTimeoutService->>VIPERContext: Read session timeout record
  VIPERContext-->>SessionTimeoutService: Session timeout data
  SessionTimeoutService-->>SessionTimeoutController: SessionTimeoutStatus
  SessionTimeoutController-->>SessionTimeoutView: Return status
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 18 functions across 9 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the migration from the legacy CFM endpoint to GET /api/sessionTimeout and covers the related session-expiration behavior.
Title check ✅ Passed The title clearly summarizes the main change: serving session expiry from VIPER 2 instead of the legacy CFM endpoint.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 18 functions across 9 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/session-timeout-endpoint

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/Controllers/SessionTimeoutController.cs`:
- Around line 66-70: Replace the filtered generic catch in the session-timeout
handling with separate catch blocks for SqlException and
InvalidOperationException. In both blocks, preserve the existing Logger.Error
call and Status fallback response.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a02c865c-16f7-4431-9a5e-4f20891d1ebd

📥 Commits

Reviewing files that changed from the base of the PR and between e05b9b3 and b893056.

📒 Files selected for processing (6)
  • test/Controllers/SessionTimeoutControllerTests.cs
  • web/Classes/SessionTimeoutStatus.cs
  • web/Classes/Utilities/SessionTimeoutService.cs
  • web/Controllers/SessionTimeoutController.cs
  • web/Views/Shared/Components/SessionTimeout/Default.cshtml
  • web/Views/Shared/Components/SessionTimeout/SessionTimeout.cs

Comment thread web/Controllers/SessionTimeoutController.cs
@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from b893056 to d056d7b Compare August 7, 2026 21:29
@codecov-commenter

Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

@codecov-commenter

codecov-commenter commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 40.90909% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 45.07%. Comparing base (f783416) to head (81c4a61).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
web/Controllers/SessionTimeoutController.cs 28.57% 13 Missing and 2 partials ⚠️
web/Classes/Utilities/SessionTimeoutService.cs 50.00% 6 Missing ⚠️
...Shared/Components/SessionTimeout/SessionTimeout.cs 0.00% 3 Missing ⚠️
web/Controllers/HomeController.cs 0.00% 1 Missing ⚠️
...ws/Shared/Components/SessionTimeout/Default.cshtml 0.00% 1 Missing ⚠️
Additional details and impacted files
@@                       Coverage Diff                        @@
##           fix/session-refresh-pathbase     #304      +/-   ##
================================================================
+ Coverage                         45.04%   45.07%   +0.02%     
================================================================
  Files                               941      942       +1     
  Lines                             49176    49202      +26     
  Branches                           6594     6595       +1     
================================================================
+ Hits                              22152    22177      +25     
+ Misses                            26080    26079       -1     
- Partials                            944      946       +2     
Flag Coverage Δ
backend 42.35% <40.90%> (+0.02%) ⬆️
frontend 63.35% <ø> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
web/Models/SessionTimeoutStatus.cs 100.00% <100.00%> (ø)
web/Controllers/HomeController.cs 27.93% <0.00%> (ø)
...ws/Shared/Components/SessionTimeout/Default.cshtml 0.00% <0.00%> (ø)
...Shared/Components/SessionTimeout/SessionTimeout.cs 0.00% <0.00%> (ø)
web/Classes/Utilities/SessionTimeoutService.cs 13.11% <50.00%> (+13.11%) ⬆️
web/Controllers/SessionTimeoutController.cs 28.57% <28.57%> (ø)

... and 2 files with indirect coverage changes

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Replaces the legacy ColdFusion session-timeout polling endpoint with a first-party ASP.NET Core API, and updates the session-timeout UI to use it while avoiding polling for anonymous visitors.

Changes:

  • Add /api/sessionTimeout controller returning session timeout status derived from the auth cookie and DB record.
  • Update the session timeout component and client script to poll the new API and improve warning reset/formatting.
  • Remove the old SessionTimeoutCheck model and add a small test to prevent inheriting session-extending controller bases/filters.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
web/Views/Shared/Components/SessionTimeout/SessionTimeout.cs Stops rendering the timeout UI for anonymous users to avoid false “expired” dialogs.
web/Views/Shared/Components/SessionTimeout/Default.cshtml Switches polling to the new API, adds reset behavior, and centralizes time formatting.
web/Models/SessionTimeoutCheck.cs Removes legacy model no longer used by the new polling contract.
web/Controllers/SessionTimeoutController.cs Introduces the new read-only polling endpoint and ensures no-store caching.
web/Classes/Utilities/SessionTimeoutService.cs Exposes timeout duration for reuse by the new controller.
web/Classes/SessionTimeoutStatus.cs Adds the JSON contract returned to the session-timeout dialog.
test/Controllers/SessionTimeoutControllerTests.cs Adds regression tests to ensure the polling controller doesn’t extend sessions via base types/filters.

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

Comment thread web/Controllers/SessionTimeoutController.cs
Comment thread web/Controllers/SessionTimeoutController.cs Outdated
Comment thread web/Controllers/SessionTimeoutController.cs
Comment thread web/Classes/Utilities/SessionTimeoutService.cs Outdated
Comment thread web/Controllers/SessionTimeoutController.cs
@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch 3 times, most recently from 633ad99 to 3ffa268 Compare August 8, 2026 17:35
@rlorenzo
rlorenzo requested a lite review from Copilot August 8, 2026 17:43
@rlorenzo

rlorenzo commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/Controllers/SessionTimeoutControllerTests.cs`:
- Around line 14-31: Add execution tests for
SessionTimeoutController.GetSessionTimeout covering a stored expiry, an
authenticated user without a stored row, an anonymous user, and each fallback
exception path. Assert both SecondsUntilTimeout and the returned offset
timestamp contract, using the existing test setup and collaborators rather than
only reflection-based checks.

In `@web/Controllers/SessionTimeoutController.cs`:
- Line 52: Update SessionTimeoutController.GetSessionTimeout() to use a
read-only SessionTimeouts query with AsNoTracking(), filtering by LoginId and
Service, instead of calling SessionTimeoutService.GetSessionTimeout() and its
Find-based path.

In `@web/Views/Shared/Components/SessionTimeout/Default.cshtml`:
- Around line 47-51: Update the secondsUntilTimeout boundary in the session
timeout polling condition to use <= 300 instead of < 300, ensuring the warning
and 15-second pre-expiry polling path also run when the API returns exactly 300
seconds.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad6355cf-63f9-459e-91c1-76b73e3f1971

📥 Commits

Reviewing files that changed from the base of the PR and between b893056 and 3ffa268.

📒 Files selected for processing (6)
  • .review-pr-ignored-304
  • test/Controllers/SessionTimeoutControllerTests.cs
  • web/Classes/Utilities/SessionTimeoutService.cs
  • web/Controllers/SessionTimeoutController.cs
  • web/Models/SessionTimeoutCheck.cs
  • web/Views/Shared/Components/SessionTimeout/Default.cshtml
💤 Files with no reviewable changes (1)
  • web/Models/SessionTimeoutCheck.cs

Comment thread test/Controllers/SessionTimeoutControllerTests.cs
Comment thread web/Controllers/SessionTimeoutController.cs Outdated
Comment thread web/Views/Shared/Components/SessionTimeout/Default.cshtml Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

web/Controllers/SessionTimeoutController.cs:56

  • secondsUntilTimeout can become negative if the stored SessionTimeoutDateTime is already in the past (clock skew, delayed poll, stale DB row). Returning a negative value is surprising for the client contract and can lead to inconsistent UI behavior; clamp it to 0 on the server.
                    return Status(record.SessionTimeoutDateTime,
                        (int)(record.SessionTimeoutDateTime - DateTime.Now).TotalSeconds);

@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from 3ffa268 to f959924 Compare August 8, 2026 18:08
@rlorenzo
rlorenzo requested a lite review from Copilot August 8, 2026 18:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from f959924 to 4c01b44 Compare August 10, 2026 03:27
@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from 4c01b44 to f8e26f4 Compare August 10, 2026 05:56
@rlorenzo rlorenzo mentioned this pull request Aug 20, 2026
@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch 2 times, most recently from 0b52272 to 551ed0c Compare September 9, 2026 04:05
@rlorenzo

rlorenzo commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new controller’s remarks are still ambiguous/contradictory around “ApiController” vs [ApiController], which can mislead maintainers and risk regressions to the non-extending guarantee.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread web/Controllers/SessionTimeoutController.cs
@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from 551ed0c to 94632f3 Compare September 9, 2026 15:49
@rlorenzo
rlorenzo requested a lite review from Copilot September 9, 2026 18:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The changes align with the stated security/session requirements and are backed by targeted unit tests that pin the “must not extend session” invariants and core status-mapping branches.

Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

- Keep the endpoint read-only by deriving from ControllerBase, since
  ApiController and AreaController both write a fresh expiry on every
  action and would stop the session ever timing out
- Read the user from the auth cookie, replacing the legacy endpoint's
  unauthenticated loginID query parameter
- Tell an authenticated user with no row apart from a dead session,
  which legacy could not do and so reported as expired
- Skip the poll for anonymous visitors, who would otherwise be told on
  public pages that a session they never had has expired
- Stand the warning down when the session is extended elsewhere, and
  render midnight as 12 AM rather than 0 AM
- Drop the ViewComponent's hardcoded localhost and double slash, now
  that the poll is same-origin
- Delete the unused SessionTimeoutCheck model, which was added as this
  endpoint's DTO in 2023 and never wired up
@rlorenzo
rlorenzo force-pushed the feature/session-timeout-endpoint branch from 94632f3 to 81c4a61 Compare September 9, 2026 18:34
@rlorenzo
rlorenzo requested a lite review from Copilot September 9, 2026 18:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The endpoint migration and “no session/cookie renewal” requirements are implemented and backed by targeted unit tests that pin the critical invariants.

Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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.

3 participants