Let a personal access token reach /dbg

`/dbg` read only `::session/profile-id`, so scripted access meant logging
in with a password to obtain a cookie. A middleware after `actoken/authz`
fills `::session/profile-id` in from the token when there is no session,
which keeps one key for every existing handler to read and makes a
console session, keyed by profile, resolve the same way either way.

The admin gate is unchanged: devenv, or an address in `:admins`. What
changes is that a token now reaches those handlers where before only a
browser session did.

This stays off `graph-backend`. It is a change to what reaches an
admin-gated surface, and a reviewer should get to weigh it on its own
rather than find it inside a graph change.

AI-assisted-by: mixed models
This commit is contained in:
Álvaro Tejero Cantero 2026-08-07 01:44:21 +02:00
parent 6bd1af4f4a
commit 8613e66115
No known key found for this signature in database

View File

@ -22,6 +22,7 @@
[app.config :as cf]
[app.db :as db]
[app.features.file-migrations :as feat.fmig]
[app.http.access-token :as actoken]
[app.http.session :as session]
[app.rpc.commands.auth :as auth]
[app.rpc.commands.files-create :refer [create-file]]
@ -741,6 +742,27 @@
;; INIT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def normalize-identity
"Let a personal access token stand in for a browser session on `/dbg`.
The identity may arrive either way, and both are the same profile acting for
itself. The gate below, devenv or an address in `:admins`, does not change
with the carrier. What a token adds is scripted access, so a tool already
holding a profile's credentials can also pull the graph a build produced.
Normalizing here rather than in each handler keeps `::session/profile-id`
the one key every debug handler reads, so a console session keyed by profile
(`app.graph.debug`) is found whichever way the caller authenticated."
{:name ::normalize-identity
:compile
(fn [& _]
(fn [handler]
(fn [request]
(handler (cond-> request
(and (nil? (::session/profile-id request))
(some? (::actoken/profile-id request)))
(assoc ::session/profile-id (::actoken/profile-id request)))))))})
(defn authorized?
[pool {:keys [::session/profile-id]}]
(or (and (= "devenv" (cf/get :host)) profile-id)
@ -816,6 +838,8 @@
["/file-raw-export-import" {:handler (partial raw-export-import-handler cfg)}]]
graph? (into (graph-action-routes cfg)))
dbg (cond-> ["/dbg" {:middleware [[session/authz cfg]
[actoken/authz cfg]
[normalize-identity]
[with-authorization pool]]}
["" {:handler (partial index-handler cfg)}]
["/health" {:handler (partial health-handler cfg)}]