Skip to content

Bound the internal session mutations to a namespace scope #6749

Description

@otavio

Problem Statement

#6745 made namespace scope a first-class, required value at the store seam: every
namespace-bound operation takes a scope.Scope, and deliberately crossing namespaces requires the
scope.NewUnbounded constructor with a written reason.

Four operations were deferred by that change rather than bounded, because their call chains carry no
namespace anywhere — bounding them changes the SSH-facing contract, which deserves its own change:

  • SessionService.DeactivateSession
  • SessionService.KeepAliveSession
  • SessionService.UpdateSession
  • SessionService.EventSession

All four resolve a session by UID alone. They currently carry an unbounded scope with the shared
reason constant reasonInternalSessionMutation (api/services/scope.go), so they are visible in the
audit grep, but nothing checks that the session they mutate belongs to the caller.

The cloud edition has the same shape in its session-recording reads
(cloud/internal/cloud/services/session.go, reason reasonSessionRecordingByUID): the console route
and the background asciinema task both resolve a session by UID with no namespace in the chain.

Why it was deferred

The SSH server drives these through /internal/sessions/*, and the session UID is the only
identifier it holds at that point. Threading a namespace down means changing the internal HTTP
contract and the SSH server's session bookkeeping — a wider blast radius than the store-seam sweep,
and one that wants its own testing.

Suggested approach

  • Decide where the namespace enters: the session UID could be resolved to its namespace once at the
    edge, or the SSH server could carry the tenant it already authenticated the device against.
  • Bound the four service methods (and the two cloud recording reads) to it.
  • Drop reasonInternalSessionMutation and reasonSessionRecordingByUID once nothing uses them.

Acceptance

  • grep -rn "scope.NewUnbounded(" --include="*.go" no longer lists the internal session mutations or
    the cloud recording reads.
  • The store isolation suite gains a cross-namespace negative test for each newly-bounded operation,
    in the same shape as api/store/storetest/scope_isolation_tests.go.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions