Skip to content

Commit fbc58e6

Browse files
Add secrets to environment when non-root users
1 parent 5e17509 commit fbc58e6

File tree

5 files changed

+48
-23
lines changed

5 files changed

+48
-23
lines changed

dev/stdio_client.clj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131

3232
(def server (process/process
3333
{:out :stream :in :stream}
34-
"docker" "run" "-i" "--rm" "--workdir=/app"
35-
"mcp/discord:latest"))
34+
"docker" "run" "-i" "--workdir=/app"
35+
"--label=x-secret:stripe.secret_key=/secret/stripe.secret_key"
36+
"--entrypoint" "/bin/sh -c \"export STRIPE_SECRET_KEY=$(cat /secret/stripe.secret_key); node /app/dist/index.js --tools=all;\""
37+
"mcp/stripe:latest")))
3638

3739
(async/thread
3840
(loop []

src/docker.clj

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@
7777
(format "%s/Library/Containers/com.docker.docker/Data/backend.sock" (System/getenv "HOME"))]]
7878
(some unix-socket-file coll)))
7979

80+
(defn- get-jfs-socket []
81+
(let [coll [(or (System/getenv "JFS_SOCKET_PATH") "/jfs.sock")
82+
(format "%s/Library/Containers/com.docker.docker/Data/jfs.sock" (System/getenv "HOME"))]]
83+
(some unix-socket-file coll)))
84+
85+
(defn jfs-get-secret [s]
86+
(curl/get
87+
(format "http://localhost/secrets/%s" s)
88+
{:raw-args ["--unix-socket" (get-jfs-socket)]
89+
:throw false}))
90+
8091
(defn backend-is-logged-in? [_]
8192
(curl/get
8293
"http://localhost/registry/is-logged-in"
@@ -310,6 +321,7 @@
310321
(def pull (comp (status? 200 "pull-image") pull-image))
311322
(def images (comp ->json list-images))
312323
(def containers (comp ->json (status? 200 "list-containers") list-containers))
324+
(def secrets-get (comp ->json (status? 200 "secrets-get") jfs-get-secret))
313325

314326
(defn add-latest [image]
315327
(let [[_ tag] (re-find #".*(:.*)$" image)]
@@ -367,25 +379,35 @@
367379
[s])
368380
(string/join " ; ")))
369381

382+
(defn get-secrets [{:keys [secrets]}]
383+
(logger/info (format "getting secrets %s" secrets))
384+
(->> secrets
385+
(map (fn [[k v]]
386+
[v (:value (secrets-get (name k)))]))
387+
(into {})))
388+
370389
(defn inject-secret-transform [container-definition]
371390
(check-then-pull container-definition)
372-
(let [{:keys [Entrypoint Cmd Env]}
391+
(let [{:keys [Entrypoint Cmd Env User]}
373392
(->
374393
(image-inspect {:Name (:image container-definition)})
375394
:Config)
376395
real-entrypoint (string/join " " (concat
377396
(or (:entrypoint container-definition) Entrypoint)
378397
(or (:command container-definition) Cmd)))]
379-
(-> container-definition
380-
(assoc :entrypoint ["/bin/sh" "-c" (injected-entrypoint
381-
(:secrets container-definition)
382-
(concat
383-
Env
384-
(->> (:environment container-definition)
385-
(map (fn [[k v]] (format "%s=%s" (if (keyword? k) (name k) k) v)))
386-
(into [])))
387-
real-entrypoint)])
388-
(dissoc :command))))
398+
(if (#{"" "root"} User)
399+
(-> container-definition
400+
(assoc :entrypoint ["/bin/sh" "-c" (injected-entrypoint
401+
(:secrets container-definition)
402+
(concat
403+
Env
404+
(->> (:environment container-definition)
405+
(map (fn [[k v]] (format "%s=%s" (if (keyword? k) (name k) k) v)))
406+
(into [])))
407+
real-entrypoint)])
408+
(dissoc :command))
409+
(-> container-definition
410+
(update :environment (fnil merge {}) (get-secrets container-definition))))))
389411

390412
(defn run-streaming-function-with-no-stdin
391413
"run container function with no stdin, and no timeout, but streaming stdout"
@@ -660,9 +682,9 @@
660682
output-channel (async/chan)]
661683
(start x)
662684
(.start ^Thread
663-
(Thread.
664-
(fn []
665-
(read-loop socket-channel c))))
685+
(Thread.
686+
(fn []
687+
(read-loop socket-channel c))))
666688
(async/go
667689
(docker/wait x)
668690
(async/>! c :stopped)

src/extension/docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ services:
66
volumes:
77
- "/var/run/docker.sock:/var/run/docker.sock"
88
- "/run/host-services/backend.sock:/backend.sock"
9+
- "/run/guest-services/jfs.sock:/jfs.sock"
910
- "docker-prompts:/prompts"
1011
command:
1112
- serve

src/mcp/client.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
(into []))]
8181
(doseq [message messages]
8282
(if-let [p (get @response-promises (:id message))]
83-
(async/put! p message)
83+
(async/put! p message)
8484
(logger/debug "no promise found: " message)))
8585
(recur))
8686

@@ -153,8 +153,8 @@
153153
{:error :did-not-initialize})))
154154
(finally
155155
(when (and
156-
(not (true? stateful))
157-
(not (= "false" (System/getenv "GATEWAY_CONTAINER_RM"))))
156+
(not (true? stateful))
157+
(not (= "false" (System/getenv "GATEWAY_CONTAINER_RM"))))
158158
(remove))))))
159159
(catch Throwable t
160160
(logger/error (.getMessage t))

test/mcp/client_t.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@
127127
:secrets {:stripe.api_key "API_KEY"}
128128
:command ["--tools=all"
129129
"--api-key=$API_KEY"]})
130-
(get-mcp-tools-from-prompt {:mcp [{:container {:image "vonwig/stripe:latest"
131-
:secrets {:stripe.api_key "API_KEY"}
132-
:command ["--tools=all"
133-
"--api-key=$API_KEY"]}}]})
130+
(get-mcp-tools-from-prompt {:mcp [{:container {:image "mcp/stripe:latest"
131+
:secrets {:stripe.secret_key "STRIPE_SECRET_KEY"}
132+
:command ["--tools=all"]}}]
133+
:local-get-tools -get-tools})
134134
(get-mcp-tools-from-prompt {:mcp [{:container {:image "mcp/brave-search:latest"
135135
:workdir "/app"
136136
:secrets {:brave.api_key "BRAVE_API_KEY"}}}]})

0 commit comments

Comments
 (0)