Skip to content

Resolve current-user identity from the token, not the cached config username#242

Merged
bjornars merged 3 commits into
novem-code:mainfrom
bjornars:bsn/gql-me-identity
Jun 18, 2026
Merged

Resolve current-user identity from the token, not the cached config username#242
bjornars merged 3 commits into
novem-code:mainfrom
bjornars:bsn/gql-me-identity

Conversation

@bjornars

@bjornars bjornars commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Why

The config-file username is a cached label that goes stale when a user is renamed on the backend — the token keeps authenticating as the renamed user, but the stored name no longer matches. Using that cached name to build requests caused two bugs:

  • novem -p/-g/-m/-d/-j (without --for-user) listed via <type>(author: <config-username>). After a rename this returned the wrong/empty set, and with a dead token it silently fell back to that name's public view instead of the user's own visualizations.
  • is_me highlighting, @user~group paths and comment-thread paths all compared against / interpolated the stale name.

What

Commit 1 — token-resolved identity

  • List one's own VDEs via me { plots { … } } etc. (new list_my_*_gql), resolving identity server-side from the token. A bad token yields me: null → empty, closing the public-view leak. --for-user X keeps the author-filtered query (an intentional other-user/public lookup).
  • Add cached NovemGQL.current_username, resolved via the lightweight REST /whoami endpoint, used for is_me and own-group path building.
  • Comment/topic "me" highlight reuses the me { username } the topics query already returns (no extra round-trip).
  • Context._threads_base prefers the token-resolved _me when loaded, falling back to the config name offline (stays a pure path-builder — no forced network call).
  • Share the VDE field selection between the author- and me-scoped queries so they can't drift.

Commit 2 — polite CLI crash on a dead token

  • A configured-but-rejected token now aborts before the data-command dispatch with a clear message:
     ! Your novem token is invalid or has expired.
       Re-authenticate with:  novem --init
    
  • Only a definitive 401/403 aborts; transient/network errors fall through so the real command surfaces its own error, and a missing token is left alone (anonymous access stays valid).
  • The whoami response does double duty: a successful one seeds a per-token identity cache on the ConfigManager singleton, which current_username reuses — so there's exactly one /whoami per invocation.
  • CLI-only; library usage is unaffected.

Commit 3 — clean CLI error messages

  • The CLI surfaced uncaught API errors as Novem404: Resource not found: <url> (Are you authenticated?) — leaking the internal exception class, and nagging about auth even though the token is already validated at startup.
  • NovemException grows a cli_message hook; Novem404 overrides it to drop the (Are you authenticated?) hint. The hint still shows for library callers via str(exc), since they have no up-front auth check.
  • _cli_excepthook prints cli_message for our exceptions (no class-name prefix) and keeps Type: message for unexpected errors, to aid debugging.
  • Now reads: Resource not found: <url>.

Compatibility

No public SDK signatures change. The identity cache is token-keyed, CLI-only, cleared by config.reset(), and Session instances get their own isolated cache — library identity resolution (Context/comments via the topics query) is untouched.

Tests

690 passed, 4 skipped; flake8 + mypy clean. New coverage in tests/test_cli_dead_token.py (dead-token abort, no-leak-before-listing, single-whoami double-duty, missing-token-not-treated-as-dead) and tests/test_cli_error_output.py (no class-name/hint leak in CLI output; hint kept for the library). Verified live against prod: own listings show only the user's VDEs, --for-user shows the other user's, dead token exits 1, and is_me highlighting flows through the cached identity.

Screenies

image

bjornars added 3 commits June 18, 2026 21:16
The cached config-file username goes stale when a user is renamed on the
backend (the token keeps authenticating as the renamed user), and using it
to build requests caused two problems:

- `novem -p/-g/-m/-d/-j` (without --for-user) listed via
  `<type>(author: <config-username>)`. After a rename this returned the
  wrong/empty set, and with a dead token it silently fell back to that
  name's *public* view instead of the user's own visualizations.
- `is_me` highlighting, `@user~group` paths and comment-thread paths all
  compared against / interpolated the stale name.

Fixes:

- List one's own VDEs via `me { plots { ... } }` etc. (new `list_my_*_gql`),
  which resolves identity server-side from the token. A bad token yields
  `me: null` -> empty, closing the public-view leak. `--for-user X` keeps
  the author-filtered query (an intentional other-user/public lookup).
- Add cached `NovemGQL.current_username`, resolved via the lightweight REST
  `/whoami` endpoint, and use it for `is_me` and own-group path building.
- Comment/topic "me" highlight reuses the `me { username }` the topics
  query already returns (no extra round-trip).
- `Context._threads_base` prefers the token-resolved `_me` when loaded,
  falling back to the config name offline (stays a pure path-builder).
- Share the VDE field selection between the author- and me-scoped queries.

A friendly "you are not authenticated" error on a null/empty identity is
left as a TODO seam in `_list_me_vis` for a follow-up change.
A configured token that the backend rejects (e.g. expired, or revoked
after a rename) otherwise let the data commands fall through to empty or
public-only results with no explanation. The CLI now checks /whoami before
dispatching a data command: a definitive 401/403 prints a short re-auth
message and exits 1. Transient/network errors fall through so the real
command still surfaces its own error, and a missing token is left alone
(anonymous access is valid).

The whoami response does double duty: a successful one seeds a per-token
identity cache on the ConfigManager singleton, which NovemGQL.current_username
reuses — so the startup check is the only /whoami request per invocation.

Library usage is unaffected; the guard lives in the CLI entry path only.
The CLI surfaced uncaught API errors as "Novem404: Resource not found: <url>
(Are you authenticated?)" — leaking the internal exception class, and nagging
about auth even though the CLI now validates the token at startup.

- NovemException grows a `cli_message` hook (defaults to str(self)); Novem404
  overrides it to drop the "(Are you authenticated?)" hint. The hint still
  shows for library callers via str(), since they have no up-front auth check.
- _cli_excepthook prints `cli_message` for our own exceptions (no class-name
  prefix) and keeps `Type: message` for unexpected errors to aid debugging.
@myme

myme commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Does this veer into the space of #170 by any chance?

@bjornars

Copy link
Copy Markdown
Contributor Author

Does this veer into the space of #170 by any chance?

image

It do!

@bjornars bjornars linked an issue Jun 18, 2026 that may be closed by this pull request
@sondove

sondove commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

You can ask for multiple things in a gql query, so you can get both me and the comments in the same query, saving a roundtrio

@sondove

sondove commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

You can ask for multiple things in a gql query, so you can get both me and the comments in the same query, saving a roundtrio

I do not think we should use an extra roundtrip request for each usage when one is enough with just adding a top level { me } to the gql query.

If we need to tell it a user is auth or not then it's better to fire a second request on the 404, or if using gql, again use them me.

Though 404 is mostly useful for the rest requests

@sondove sondove 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.

Would love to avoid the extra request, but will not hold up progress

@bjornars bjornars merged commit 5c4f242 into novem-code:main Jun 18, 2026
5 checks passed
@bjornars

Copy link
Copy Markdown
Contributor Author

Would love to avoid the extra request, but will not hold up progress

I don't completely disagree. More than happy to review the pull request ☺️☺️

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.

cli: Allow usage without a novem.conf

3 participants