Skip to content

--auto-close accepts deadlines longer than the session can live and reports them as real #18

Description

@artemiia

When you start a share you can give it a deadline with --auto-close, and the reference invites you to think in long spans — the accepted units include days, weeks, months and years. But an ordinary share only lives twelve hours. The relay stamps every non-persistent session with a twelve-hour expiry at creation and deletes it when that moment arrives. If you ask for anything longer, nothing refuses you and nothing warns you: the command succeeds, the share opens normally, and the CLI reports the deadline you asked for as though it were real.

So shell --auto-close 7d <long job> tells you the session closes in seven days, and shell list keeps agreeing (CLOSES: in 6d23h) every time you look. Both numbers are fiction. Twelve hours later the relay expires the session and anyone opening the link you handed out gets "Session ended. This sharing link no longer exists."

The cause is that two different clocks are reported as one. The CLI computes your requested deadline locally and prints it as closes_at; the server independently sets expires_at from its own fixed lifetime. Both values travel back in the same payload, side by side, and nothing in the CLI ever compares them.

Reproduction

shell 0.7.3, default (non-persistent) session, three consecutive runs:

$ shell --json --auto-close 7d sleep 20
closes_at reported: +6d23h
expires_at actual : +0d11h      <- the link dies here
$ shell list
ID          UPTIME  RELAY   CLOSES    ACCESS            COMMAND
AN9yfku0Ww  3s      online  in 6d23h  interactive+e2ee  sleep 30

Measured across a range, on a session created at 09:43Z:

--auto-close closes_at reported expires_at actual
1h 2026-09-03T12:43+02:00 2026-09-03T21:43Z ok
9h 2026-09-03T20:44+02:00 2026-09-03T21:44Z ok
24h 2026-09-04T11:44+02:00 2026-09-03T21:44Z misreported
7d 2026-09-10T11:44+02:00 2026-09-03T21:44Z misreported
30d 2026-10-03T11:44+02:00 2026-09-03T21:44Z misreported

Root cause

SESSION_TTL_MS = 12 * 60 * 60 * 1000 (worker/index.ts:41), applied at creation as expiresAt = createdAt + (persistent ? PERSISTENT_TTL_MS : SESSION_TTL_MS) (worker/index.ts:600) and enforced at worker/index.ts:739-741, which calls this.expire() and returns {exists:false} with 404.

On the CLI side the requested deadline is parsed at cmd/shell/main.go:69 and emitted as closes_at at cmd/shell/main.go:216. It is never compared against session.ExpiresAt, which arrives in the same struct — there is no reconciliation anywhere in cmd/shell.

Scope

--persistent raises the server lifetime to thirty days (PERSISTENT_TTL_MS, worker/index.ts:43), and a seven-day deadline there is genuinely honoured — confirmed, expires_at lands at +29d23h, 2/2 runs. Pushing past thirty days on a persistent session reproduces the same misreporting. The general rule: any deadline exceeding the session's actual lifetime is accepted, echoed back, and silently truncated.

Impact

The twelve-hour cap is reasonable; the false confidence built on top of it is the problem. Without closes_at a user would verify before promising a colleague a week of access. Instead the tool states a specific date, repeats it in shell list on every check, and gives no hint at any point that the figure is unachievable. The mistake surfaces hours later in someone else's browser as a dead link, with nothing in front of the owner connecting that failure to the flag that caused it.

Suggested fixes

Any one of:

  • Reject a deadline longer than the session can live, and say why.
  • Clamp it to the real expiry and report the clamped value.
  • Keep accepting it, but display min(closes_at, expires_at) so the reported figure never exceeds what the relay will deliver.

Whichever is chosen, shell list's CLOSES column should reflect the same reconciled value.

Environment

shell 0.7.3 (latest; matches release.json and GitHub latest), installed via curl -fsSL https://shell.online/install | sh, sha256 024510fb1ef100c89bf64e404f27df2ccd323825d4f935ef2f50459121366419. macOS 26.2, arm64.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions