Skip to content

migration: loopback OAuth login and organization token submission - #8

Open
GroophyLifefor wants to merge 1 commit into
mainfrom
murat/cli-v2
Open

GroophyLifefor wants to merge 1 commit into
mainfrom
murat/cli-v2

Conversation

@GroophyLifefor

Copy link
Copy Markdown
Member

Closes #5.
Closes #6.

Loopback login with an in memory organization session and organization
token submission, verified end to end against the local ingestion service
(scan stored under the organization prefix, worker produced data.json and
report.pdf).

Adds a loopback OAuth login that keeps the organization session in memory
only, and submits scans with the organization token, the v2 client markers
and the x-org-id organization header. A rejected session triggers exactly
one re-authentication and one resubmission. The delivery email stays a
delivery address, name and company are optional, and the success output
prints the queued status and the accounts-ui reports URL.

Verified with unit tests, lint and an end-to-end run against the local
ingestion service.
@ns-control-tower

ns-control-tower commented Oct 9, 2026 •

Copy link
Copy Markdown

Walkthrough

Report submission migrates from an anonymous v1 POST to an authenticated v2 flow. A new lib/auth.js runs an ephemeral loopback OAuth server on 127.0.0.1: it binds a free port in 8765–8770, generates a random state, opens the accounts-ui /sign-in URL (printing it to stderr as a fallback), and waits for the callback. State is validated, the org token/console id are extracted into an in-memory session, and the server is closed. lib/submit.js now POSTs the report to upgrade.nodesource.io with a Bearer org token, x-org-id, and v2 headers; on a 401 it re-authenticates once via the injected relogin and retries exactly once. lib/constants.js names the two endpoints (overridable via env). Name/company became optional CRM fields; email remains required.

Validation: cloned the head, pnpm install --frozen-lockfile clean, standard lint clean, node --test test/auth.test.js test/submit.test.js → 36/36 pass. CI has no configured checks on this head.

Assessment

  • ⚠️ lib/auth.js:53 — Windows auto-open truncates the sign-in URL. cmd /c start "" <url> receives the URL unquoted (libuv doesn't quote arg strings without spaces), and & is a cmd.exe command separator, so start opens only the URL up to the first & — port and state never reach the accounts UI and the loopback callback can't complete. Login still works via the printed stderr URL, but the auto-open path silently fails on Windows. Fix: quote the URL (or use explorer.exe). Couldn't reproduce on this Linux sandbox — please verify on Windows.
  • 🛠️ lib/submit.js:329 — re-auth reuses a stale x-org-id. On a 401, post() swaps in the fresh token but keeps the original session.consoleId; if the user re-auths into a different org the retry pairs a new token with a stale org id. Refresh consoleId from freshSession.

The core auth design is sound: loopback-only binding, random state CSRF guard, no credentials written to disk or logs (verified by tests A11/S7), CSP on callback responses, and clean server teardown on every settle path. This is an auth/data change — 🚩 a human reviewer should sign off on the loopback contract and the token-in-query-string delivery alongside the accounts-ui/upgrade-api teams.

Verdict: REQUEST_CHANGES — one blocking Windows compatibility defect in the browser launcher; the rest of the change is well-structured and well-tested.

overview
oauth-flow-view
submit-flow-view

Comment thread lib/auth.js
return new Promise((resolve) => {
const platform = process.platform
const command = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open'
const args = platform === 'win32' ? ['/c', 'start', '', url] : [url]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

lib/auth.js:53

On Windows the sign-in URL is handed to cmd /c start "" <url>. The URL's query string contains & (.../sign-in?extension=nsolid-plugin&port=8765&state=…), and & is a command separator for cmd.exe. Because the argument has no spaces, libuv's argument quoting leaves it unquoted, so cmd.exe splits the line and start receives only the URL up to the first & — port and state never reach the accounts UI, so the loopback callback can't complete. The full URL is also printed to stderr, so a user can still finish the login manually, but the auto-open path silently fails on Windows.

Quote the URL so cmd.exe treats it as a single token, e.g. ['/c', 'start', '', "${url}"] (or open via explorer.exe <url>, which does not reparse shell metacharacters), and confirm on a Windows host.

🤖 Ask ns-control-tower to fix this

@ns-control-tower please fix: on Windows defaultBrowserLauncher passes the sign-in URL unquoted to cmd /c start, so & in the query string truncates it; quote the URL (or use explorer.exe) so the full URL opens.

Comment thread lib/submit.js
}
log.info('Session rejected, re-authenticating once')
const freshSession = await deps.relogin()
token = freshSession?.token

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

lib/submit.js:329

After a 401, post() reuses the original session.consoleId for the x-org-id header while swapping in the fresh token. login() also returns a consoleId, so if the user re-authenticates into a different org the retry sends a fresh token paired with a stale org id (a second 401/403 would then surface, but the request is still inconsistent). Refresh consoleId from freshSession too — or rebuild the header — so the retry is self-consistent.

🤖 Ask ns-control-tower to fix this

@ns-control-tower please fix: on 401 re-auth in submitReport, refresh session.consoleId from the freshSession so the retried x-org-id matches the new token.

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.

Submit scans with the organization session and delivery email Implement loopback OAuth login for the ns-upgrade CLI

2 participants