Tighten quire.stdlib mirror API
Caller resolves the auth header so mirror works with any credential
source, not just the runtime secret store. `λ` and a small `cat` helper
replace the manual nil-checks and imperative push-args construction.

Assisted-by: Claude Opus 4.7 via Claude Code
change yoqznqswpqsntmvzoknpvoyxnzkmospo
commit 91d521d4aadda940d61d02e6d46c474aa5e4ad75
author Alpha Chen <alpha@kejadlen.dev>
date
parent yluxrrnl
diff --git a/docs/CI-FENNEL.md b/docs/CI-FENNEL.md
index 7ce54ea..c055ac1 100644
--- a/docs/CI-FENNEL.md
+++ b/docs/CI-FENNEL.md
@@ -244,18 +244,19 @@ The kernel (`sh`/`secret`/`jobs`) stays small. Higher-level operations like tag-
 
 (ci.job :mirror [:quire/push :test]
   (fn []
-    (let [push (runtime.jobs :quire/push)]
-      (mirror {:url     "https://github.com/example/repo.git"
-               :secret  :github_auth_header
-               :sha     push.sha
-               :tag     (.. "quire-" (string.sub push.sha 1 8))
-               :git-dir (. push :git-dir)
-               :refs    ["refs/heads/main"]}))))
+    (let [push (runtime.jobs :quire/push)
+          auth (runtime.secret :github_auth_header)]
+      (mirror {:url         "https://github.com/example/repo.git"
+               :auth-header auth
+               :sha         push.sha
+               :tag         (.. "quire-" (string.sub push.sha 1 8))
+               :git-dir     (. push :git-dir)
+               :refs        ["refs/heads/main"]}))))
 ```
 
 Available helpers:
 
-* `(mirror opts)` — tag a commit and push it (plus optional refs) to a remote. `opts.url`, `opts.secret`, `opts.sha`, `opts.tag`, and `opts.git-dir` are required; `opts.refs` defaults to `[]`. The auth header (resolved via `runtime.secret`) is passed via `GIT_CONFIG_*` env vars rather than `-c http.extraHeader=…` in argv, so it doesn't appear in `ps` listings. Returns `{:tag :pushed_refs}`. Raises on missing required opts, unknown secrets, or non-zero git exits.
+* `(mirror opts)` — tag a commit and push it (plus optional refs) to a remote. `opts.url`, `opts.auth-header`, `opts.sha`, `opts.tag`, and `opts.git-dir` are required; `opts.refs` defaults to `[]`. The caller resolves the credential (typically via `runtime.secret`) and passes the full HTTP header line as `:auth-header`; mirror passes it to git via `GIT_CONFIG_*` env vars rather than `-c http.extraHeader=…` in argv, so it doesn't appear in `ps` listings. Returns `{:tag :pushed_refs}`. Raises on missing required opts or non-zero git exits.
 
 `(ci.mirror …)` (the registration-time form) remains as a convenience wrapper that registers a singleton `quire/mirror` job. Use the stdlib form when you want to mirror conditionally or as part of a larger run-fn.
 
diff --git a/quire-core/src/ci/runtime.rs b/quire-core/src/ci/runtime.rs
index 96ddfbf..1234446 100644
--- a/quire-core/src/ci/runtime.rs
+++ b/quire-core/src/ci/runtime.rs
@@ -975,11 +975,12 @@ mod tests {
 (local {{: mirror}} (require :quire.stdlib))
 (ci.job :go [:quire/push]
   (fn []
-    (mirror {{:url "{url}"
-             :secret :github_token
-             :sha "{sha}"
-             :tag "v1"
-             :git-dir "{git_dir}"}})))"#,
+    (let [auth (runtime.secret :github_token)]
+      (mirror {{:url "{url}"
+               :auth-header auth
+               :sha "{sha}"
+               :tag "v1"
+               :git-dir "{git_dir}"}}))))"#,
             url = format!("file://{}", target.display()),
             sha = sha,
             git_dir = bare.display(),
@@ -999,39 +1000,13 @@ mod tests {
 (local {: mirror} (require :quire.stdlib))
 (ci.job :go [:quire/push]
   (fn []
-    (mirror {:secret :github_token :sha "x" :tag "v1" :git-dir "/tmp"})))"#;
+    (mirror {:auth-header "x" :sha "x" :tag "v1" :git-dir "/tmp"})))"#;
         let (_runtime, run_fn) = rt(source, HashMap::new());
         let err = run_fn.call::<mlua::Value>(()).unwrap_err();
         let msg = err.to_string();
         assert!(
-            msg.contains("missing required option :url"),
+            msg.contains("Missing argument url"),
             "expected missing-:url error, got: {msg}"
         );
     }
-
-    #[test]
-    fn stdlib_mirror_errors_on_unknown_secret() {
-        let (_dir, bare, target, sha) = bare_repo_with_target();
-        let source = format!(
-            r#"(local ci (require :quire.ci))
-(local {{: mirror}} (require :quire.stdlib))
-(ci.job :go [:quire/push]
-  (fn []
-    (mirror {{:url "{url}"
-             :secret :nope
-             :sha "{sha}"
-             :tag "v1"
-             :git-dir "{git_dir}"}})))"#,
-            url = format!("file://{}", target.display()),
-            sha = sha,
-            git_dir = bare.display(),
-        );
-        let (_runtime, run_fn) = rt(&source, HashMap::new());
-        let err = run_fn.call::<mlua::Value>(()).unwrap_err();
-        let msg = err.to_string();
-        assert!(
-            msg.contains("unknown secret") && msg.contains("nope"),
-            "expected unknown-secret error mentioning the name, got: {msg}"
-        );
-    }
 }
diff --git a/quire-core/src/ci/stdlib.fnl b/quire-core/src/ci/stdlib.fnl
index c5d5c7d..c028d12 100644
--- a/quire-core/src/ci/stdlib.fnl
+++ b/quire-core/src/ci/stdlib.fnl
@@ -5,34 +5,37 @@
 
 (local M {})
 
-(fn missing [field]
-  (error (.. "quire.stdlib.mirror: missing required option :" field)))
-
 (fn trim [s]
   (string.gsub s "%s+$" ""))
 
+(fn cat [...]
+  ;; Concatenate sequence tables into a fresh sequence.
+  (let [out []]
+    (each [_ t (ipairs [...])]
+      (each [_ x (ipairs t)]
+        (table.insert out x)))
+    out))
+
 ;; (mirror opts)
 ;;
 ;; Tag a commit and push the tag (plus optional refs) to a remote.
 ;;
-;; opts: {:url       — remote URL (required)
-;;        :secret    — secret name resolved via runtime.secret (required)
-;;        :sha       — commit to tag (required)
-;;        :tag       — tag name (required)
-;;        :git-dir   — bare git directory the run is scoped to (required)
-;;        :refs      — extra refs to push alongside the tag (optional, default [])}
+;; opts: {:url         — remote URL (required)
+;;        :auth-header — full HTTP header line passed to git as
+;;                       `http.extraHeader`; resolve via
+;;                       `runtime.secret` at the call site (required)
+;;        :sha         — commit to tag (required)
+;;        :tag         — tag name (required)
+;;        :git-dir     — bare git directory the run is scoped to (required)
+;;        :refs        — extra refs to push alongside the tag
+;;                       (optional, default [])}
 ;;
-;; Returns {:tag :pushed_refs}. Raises on missing required opts,
-;; unknown secrets, or non-zero git exits.
-(fn M.mirror [opts]
-  (let [{: secret : sh} (require :quire.runtime)
-        url (or opts.url (missing :url))
-        secret-name (or opts.secret (missing :secret))
-        sha (or opts.sha (missing :sha))
-        tag (or opts.tag (missing :tag))
-        git-dir (or (. opts :git-dir) (missing :git-dir))
-        refs (or opts.refs [])
-        auth-header (secret secret-name)
+;; Returns {:tag :pushed_refs}. Raises on missing required opts or
+;; non-zero git exits. `lambda` checks the required bindings for nil
+;; at the call site.
+(λ M.mirror [{: url : auth-header : sha : tag : git-dir :refs ?refs}]
+  (let [{: sh} (require :quire.runtime)
+        refs (or ?refs [])
         ;; Pass http.extraHeader via GIT_CONFIG_* env (git 2.31+)
         ;; instead of `-c http.extraHeader=…` in argv. Keeps the auth
         ;; header out of `ps` and out of any argv logging we add
@@ -45,13 +48,12 @@
         tag-result (sh [:git :tag tag sha] sh-opts)]
     (when (not= 0 tag-result.exit)
       (error (.. "git tag failed: " (trim tag-result.stderr))))
-    (let [push-args [:git :push :--porcelain url]]
-      (each [_ ref (ipairs refs)]
-        (table.insert push-args ref))
-      (table.insert push-args (.. :refs/tags/ tag))
-      (let [push-result (sh push-args sh-opts)]
-        (when (not= 0 push-result.exit)
-          (error (.. "git push failed: " (trim push-result.stderr))))
-        {: tag :pushed_refs refs}))))
+    (let [push-args (cat [:git :push :--porcelain url]
+                         refs
+                         [(.. :refs/tags/ tag)])
+          push-result (sh push-args sh-opts)]
+      (when (not= 0 push-result.exit)
+        (error (.. "git push failed: " (trim push-result.stderr))))
+      {: tag :pushed_refs refs})))
 
 M