inspector/core/auth/node
Repository files (latest commit first)
Filename Latest commit message Latest commit date
cliffhall 050556e1a7 fix(auth): address Copilot review round 4 on the secret-store PR
Four findings (two inline, two suppressed), all taken. Three are the lock,
which is where the remaining sharp edges were.

- **A lock could be created and then never stamped.** If `mkdir` succeeded
  but writing the owner token failed, the catch treated it as "cannot lock
  here", returned the no-op release, and left the directory behind. The
  mutation then ran unlocked *and* every later writer queued behind an
  orphan nobody could deliberately release, until it aged out. The
  acquisition now tracks whether it created the directory, removes it on a
  failed stamp, and refuses rather than entering the section unlocked.

- **An old mtime was being treated as proof the owner was dead.** It is
  not: a holder that is SIGSTOPed, starved by a blocked event loop, or on a
  machine that suspended is alive and not running, and expiring it on
  elapsed time alone takes the lock out from under a live critical section
  — the lost update the lock exists to prevent, arrived at through the
  machinery meant to prevent it. The heartbeat narrowed the window; it
  could not close it, because the holder that most needs protecting is
  precisely the one not running its timers.

  The owner stamp now carries `pid` and `host`, and staleness only *opens*
  the question — on the same host a waiter asks the OS whether that pid
  still exists (`kill(pid, 0)`, which sends no signal; `EPERM` counts as
  alive, so a holder running as another user is never stolen from). Only a
  genuinely absent process is stolen from. Where the stamp cannot be
  trusted — another machine over a shared filesystem, or a missing/corrupt
  owner file — the mtime remains the answer, because the alternative is a
  lock nothing can ever break, turning one dead process into a permanent
  outage.

- **Podman was classified as a host.** `/.dockerenv` is Docker's marker and
  rootless Podman has no equivalent of it, while its cgroup paths say
  `libpod-<id>.scope` rather than the literal "podman" the pattern looked
  for. Such a box fell back to a file in the ephemeral writable layer and
  reported it as durable — the wrong way round to be wrong.
  `/run/.containerenv` and `libpod` are both recognized now.

- **Two tests floated a second `acquireLock`**, so the test could finish and
  `afterEach` could remove the temp directory while the acquisition was
  still running. Both hold and settle it now.

Separately, a defect of my own found while re-reading round 3:
`describeFileStore` called `tightenSecretFilePermissions`, so the function
whose job is to *describe* the store issued a `chmod` on every
`GET /api/config` — once per page load, on a file another process may be
mid-write on. Split out a read-only `readSecretFilePermissions`; the repair
stays at startup, where it happens once and its outcome is announced.

Tests: a stale lock whose owner is alive is not stolen (and survives the
attempt), one whose pid is gone is, one stamped by another host is; a
failed ownership stamp reports and leaves nothing behind; Podman via both
signals; and the read-only permission check leaves a 0644 file at 0644.
Full `npm run ci` green — 5,711 tests under the coverage gate.

Signed-off-by: cliffhall <cliff@futurescale.com>
2026-08-22 13:40:32 -04:00
..
file-secret-store.ts fix(auth): address Copilot review round 4 on the secret-store PR 2026-08-22 13:40:32 -04:00
index.ts chore: close quality-gate coverage gaps (#1689) (#1766) 2026-07-24 17:20:12 -04:00
oauth-callback-server.ts feat(web): enforce localhost-only binding; expand loopback origin allow-list (#1796) 2026-07-26 22:15:10 -04:00
oauth-persist-file.ts fix(auth): keep oauth-persist browser-safe (move Node file backend out) 2026-07-08 16:20:31 -04:00
runner-interactive-oauth.ts fix(auth): explicit re-authorize when the OAuth callback state was lost (#1808) (#1810) 2026-07-27 18:08:31 -04:00
runner-oauth-callback.ts chore(deps): migrate to eslint 10 to clear the brace-expansion DoS advisory (#1900) 2026-08-01 20:13:30 -04:00
secret-store-selection.ts fix(auth): address Copilot review round 4 on the secret-store PR 2026-08-22 13:40:32 -04:00
secret-store.ts fix(auth): address Copilot review round 3 on the secret-store PR 2026-08-22 13:19:56 -04:00
storage-node.ts CLI: catalog listing, auth flags, and OAuth browser UX (#1782) 2026-07-26 16:55:25 -04:00