Skip to content

fix(terminal-server): bump session TTL to 90d and bind IPv6 dual-stack#87

Open
dvlexp wants to merge 1 commit into
evolution-foundation:mainfrom
dvlexp:fix/terminal-server-ttl-ipv6
Open

fix(terminal-server): bump session TTL to 90d and bind IPv6 dual-stack#87
dvlexp wants to merge 1 commit into
evolution-foundation:mainfrom
dvlexp:fix/terminal-server-ttl-ipv6

Conversation

@dvlexp
Copy link
Copy Markdown

@dvlexp dvlexp commented May 23, 2026

Problem

Two independent issues with the terminal server causing session loss and connectivity failures:

  1. Sessions expiring nightly — the default TTL of 24h caused all persisted sessions to be deleted every night, requiring users to restart their conversations daily
  2. IPv6 clients unable to connect — binding on 0.0.0.0 (IPv4 only) drops connections from Tailscale and modern browsers that prefer IPv6

Solution

dashboard/terminal-server/src/server.js

  • Default TTL changed from 24h to 90 days; still overridable via TERMINAL_SESSION_TTL_HOURS env var
  • server.listen bind address changed from '0.0.0.0' to '::' — IPv6 wildcard enables dual-stack, so IPv4 clients are still served via the OS dual-stack mapping

dashboard/terminal-server/src/utils/session-store.js

  • sessionTtlMs default updated to match (90 days)
  • maxFileAgeDays updated from 7 to 90 to stay consistent

Test Plan

  • Start terminal server, create a session, wait 25h — session still persists on restart
  • Connect from an IPv6-only client (Tailscale endpoint) — connection succeeds
  • TERMINAL_SESSION_TTL_HOURS=1 env override still works — sessions expire in 1h

Files Changed

File Change
dashboard/terminal-server/src/server.js TTL default 24h→90d, bind '::'
dashboard/terminal-server/src/utils/session-store.js TTL + maxFileAgeDays 7→90

Summary by Sourcery

Increase terminal session persistence and enable IPv6 dual-stack binding for the terminal server.

New Features:

  • Allow the terminal server to accept connections over IPv6 while still supporting IPv4 via dual-stack binding.

Bug Fixes:

  • Prevent unintended nightly expiration of terminal sessions by extending the default session TTL.

Enhancements:

  • Extend default terminal session TTL and associated persisted session file retention to 90 days for longer-lived sessions.

- Default TTL increased from 24h to 90 days in both server.js and
  session-store.js; still overridable via TERMINAL_SESSION_TTL_HOURS env.
- Bind address changed from '0.0.0.0' to '::' (IPv6 wildcard, dual-stack)
  so clients connecting via IPv6 (Tailscale, modern browsers) reach the
  server. IPv4 is still served via the dual-stack mapping.
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 23, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Increases default terminal session persistence to 90 days and updates the server to listen on the IPv6 wildcard address for dual-stack connectivity, keeping env overrides intact and aligning on-disk session storage retention with the new TTL.

File-Level Changes

Change Details Files
Increase default in-memory session TTL and make it configurable via environment variable while keeping GC behavior unchanged.
  • Update TerminalServer default session TTL from 24 hours to 90 days when no valid TERMINAL_SESSION_TTL_HOURS is provided
  • Retain existing behavior where a positive TERMINAL_SESSION_TTL_HOURS overrides the default TTL
  • Leave session garbage-collection interval logic and defaults unchanged
dashboard/terminal-server/src/server.js
Bind the HTTP/WebSocket server to an IPv6 wildcard address to support IPv4+IPv6 clients.
  • Change server.listen bind address from IPv4-only 0.0.0.0 to IPv6 wildcard :: so the OS provides dual-stack handling
  • Keep the listening port and server initialization flow the same
dashboard/terminal-server/src/server.js
Align persisted session storage TTL and maximum file age with the new 90-day default.
  • Update SessionStore default sessionTtlMs from 24 hours to 90 days when not overridden by options
  • Increase maxFileAgeDays default from 7 to 90 days so persisted sessions are not deleted prematurely
  • Keep storage directory and initialization logic unchanged
dashboard/terminal-server/src/utils/session-store.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The 90-day TTL and max file age values are duplicated between TerminalServer and SessionStore; consider centralizing these defaults in a shared constant to avoid future drift.
  • Binding the server to '::' can behave differently across platforms (e.g., disabled dual-stack or missing IPv6), so it may be safer to allow the bind address to be configurable or to fall back to '0.0.0.0' when '::' fails.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The 90-day TTL and max file age values are duplicated between `TerminalServer` and `SessionStore`; consider centralizing these defaults in a shared constant to avoid future drift.
- Binding the server to `'::'` can behave differently across platforms (e.g., disabled dual-stack or missing IPv6), so it may be safer to allow the bind address to be configurable or to fall back to `'0.0.0.0'` when `'::'` fails.

## Individual Comments

### Comment 1
<location path="dashboard/terminal-server/src/server.js" line_range="539" />
<code_context>

     return new Promise((resolve, reject) => {
-      server.listen(this.port, '0.0.0.0', (err) => {
+      server.listen(this.port, '::', (err) => {
         if (err) return reject(err);
         this.server = server;
</code_context>
<issue_to_address>
**issue:** Binding to '::' may drop IPv4-only accessibility depending on OS and Node configuration.

This change depends on IPv4-mapped IPv6 support, which varies by OS and configuration. On some platforms it will serve only IPv6 and break IPv4-only clients. If you want dual-stack behavior, consider omitting the host argument or explicitly listening on both IPv4 and IPv6 instead of relying on v4-mapped v6.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


return new Promise((resolve, reject) => {
server.listen(this.port, '0.0.0.0', (err) => {
server.listen(this.port, '::', (err) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue: Binding to '::' may drop IPv4-only accessibility depending on OS and Node configuration.

This change depends on IPv4-mapped IPv6 support, which varies by OS and configuration. On some platforms it will serve only IPv6 and break IPv4-only clients. If you want dual-stack behavior, consider omitting the host argument or explicitly listening on both IPv4 and IPv6 instead of relying on v4-mapped v6.

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.

1 participant