aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-13 21:08:21 +0000
committertv <tv@krebsco.de>2026-11-13 22:14:19 +0100
commitc3ca6d4b991ea24192ac4ddec156d0530b462c3e (patch)
treedebd57542fb475f46c6accef974ce1ca4e6fd670
parent4afd7d2793e85f260a2a3c20a423f0d1a4844ea7 (diff)
populate: keep URLs, refs, and names from being taken for options
A git source's url and ref are strings, and git clone, git remote, and git fetch took ones starting with - for options, e.g. --upload-pack, which runs a command where the repository is local. They come after -- now, and so does a pass source's name for git log and pass show. git-ref-option gives a ref that git fetch would take for --upload-pack.
-rw-r--r--CHANGELOG.md2
-rw-r--r--pkgs/populate/default.nix15
-rw-r--r--tests/scenarios.nix23
3 files changed, 33 insertions, 7 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0f9380..767652b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
## Unreleased
+- Git can't take a `git` source's `url` or `ref`, or a `pass` source's
+ `name`, for an option.
- `git` sources with a branch or tag as `ref` follow it: populate fetches
the branch or tag on every run, and resets the work tree to what it
fetched.
diff --git a/pkgs/populate/default.nix b/pkgs/populate/default.nix
index f2e6c80..dd0beab 100644
--- a/pkgs/populate/default.nix
+++ b/pkgs/populate/default.nix
@@ -1199,26 +1199,27 @@ let
${if source.shallow then /* sh */ ''
git init ${quote target.path}
'' else /* sh */ ''
- git clone --recurse-submodules ${quote source.url} ${quote target.path}
+ git clone --recurse-submodules -- ${quote source.url} ${quote target.path}
''}
fi
cd ${quote target.path}
if ! url=$(git config remote.origin.url); then
- git remote add origin ${quote source.url}
+ git remote add -- origin ${quote source.url}
elif test "$url" != ${quote source.url}; then
- git remote set-url origin ${quote source.url}
+ git remote set-url -- origin ${quote source.url}
fi
# A commit, given by its hash or a prefix thereof, gets fetched only if
# the work tree lacks it, unless fetchAlways is set. A branch or tag
# gets fetched on every run, so the work tree follows it: resetting to
# its name would reset to a local branch, which fetching doesn't move.
+ # After --, a ref can't be taken for an option.
ref=${quote source.ref}
fetch() {
${if source.shallow then /* sh */ ''
- git fetch --depth=1 origin "$1"
+ git fetch --depth=1 origin -- "$1"
'' else /* sh */ ''
- git fetch origin "$1"
+ git fetch origin -- "$1"
''}
}
if printf %s "$ref" | grep -Eqx '[0-9a-f]{4,40}'; then
@@ -1257,7 +1258,7 @@ let
if test -e ${quote source.dir}/.git; then
local_pass_info=${quote source.name}\ $(
- ${git}/bin/git -C ${quote source.dir} log -1 --format=%H ${quote source.name}
+ ${git}/bin/git -C ${quote source.dir} log -1 --format=%H -- ${quote source.name}
# we append a hash for every symlink, otherwise we would miss updates on
# files where the symlink points to
${findutils}/bin/find ${quote source.dir}/${quote source.name} -type l \
@@ -1289,7 +1290,7 @@ let
pass_out=$PWD/$rel_name
${coreutils}/bin/mkdir -p "$(${coreutils}/bin/dirname "$pass_out")"
- PASSWORD_STORE_DIR=${quote source.dir} ${pass}/bin/pass show "$pass_name" > "$pass_out"
+ PASSWORD_STORE_DIR=${quote source.dir} ${pass}/bin/pass show -- "$pass_name" > "$pass_out"
if [ -n "$pass_date" ]; then
${coreutils}/bin/touch -d "$pass_date" "$pass_out"
fi
diff --git a/tests/scenarios.nix b/tests/scenarios.nix
index 2fc1bd7..8093e02 100644
--- a/tests/scenarios.nix
+++ b/tests/scenarios.nix
@@ -2104,6 +2104,29 @@ assert !(krops.isLocalTarget (targets.remote "/"));
}
];
}))
+ # A ref that git fetch would take for an option: --upload-pack runs a
+ # command where the repository is local.
+ (s "git-ref-option" (let
+ elsewhere = "/var/krops-elsewhere";
+ in {
+ isolate = true;
+ prepare = ''
+ rm -fR ${elsewhere}
+ git clone -q --bare ${gitUrl} ${elsewhere}/repo.git
+ '';
+ phases = [
+ {
+ sources.x.git = {
+ url = "${elsewhere}/repo.git";
+ ref = "--upload-pack=touch ${elsewhere}/ran; git-upload-pack";
+ };
+ expect.fail = "invalid refspec";
+ check = ''
+ test ! -e ${elsewhere}/ran || fail "the ref ran a command"
+ '';
+ }
+ ];
+ }))
# A file in populate's state replaced by a symlink to a file outside.
(s "state-key" (let
sources.x.flake-input = {