export has to be in a separate line. Cannot be only 1 line. Because export always exits 0. Hence, breaking error handling. So please first set tag, then export in separate line.
How would the user be sure that script is non-malicious? Same bootstrap issue. Unicode check + script review required. Outside of skillset of many users.
export has to be in a separate line. Cannot be only 1 line. Because export always exits 0. Hence, breaking error handling. So please first set tag, then export in separate line.
Done, thanks.
How would the user be sure that script is non-malicious? Same bootstrap issue. Unicode check + script review required. Outside of skillset of many users.
Hm ok. So the user must manually copy/paste from wiki and execute that initial verification code.
That seems ugly, but kind of impossible otherwise.
How about an interactive shell that runs on the first container start (writes a file in ~/binary-mnt with check value)ā¦
Maybe best to avoid dockerhub remote docker upload? Doesnāt seem to provide much? Lower maintenance effort. More up-to-date. Maybe more secure as we avoid a huge binary image on a third-party remote server?
Would it make sense if the docker start script would run the docker build script when needed for better usability? Any docker convention for that?
Does the git fetcher + verifier be part of docker? Could be a standalone script that gets called by a docker script.
Yeah, I didnāt consider the security concerns.
Dockerhub only hosts docker images (I believe). The image weād push to hub.docker.com is the docker image that is built by derivative-maker-docker-image. So ~150MB, probably less with compression.
Building is already simplified with derivative-maker-docker-image.
Offering docker pull would be an even simpler way for users to get the docker image without building it, but I agree that it might not be appropriate here. Iāll scrap that from the readme.
Yes, that makes sense. This would pretty much be the equivalent of docker pull, because 0 user interaction is required to create the docker image. Less even.
Iāll add that.
Yes, much needed clean up of that part. Iāll take a look at those scripts.
What Iāve done so far is to create a volume that mounts the key location
This ensures that the key only needs to be imported once, even on container restarts. [ -d "~/.gnupg" ] and f ~/.gnupg/pubring.kbx can now be conditioned too.
So in combination with --list-keys and pointing to a separate script that does fetch, checkout and verify is probably best.
git verify-commit only checks that a signature was created with a known key. It does not check which key. How to fix using a shell command? Ideally git verify-commit --fingerprint xxxxxx. But that does not exist at time of writing as far as I know. Without bash scripting (more error prone, dangerous). Hereās how:
git verify-commit HEAD
signed_by_fingerprint="$(git show --no-patch --pretty=format:%GF HEAD)"
git verify-commit -- "master^{commit}"
gpg: Signature made Sat Jun 14 13:22:04 2025 UTC
gpg: using RSA key 6E979B28A6F37C43BE30AFA1CB8D50BB77BB3C48
gpg: issuer "adrelanos@whonix.org"
gpg: Good signature from "Patrick Schleizer <adrelanos@kicksecure.com>" [unknown]
gpg: aka "Patrick Schleizer <adrelanos@riseup.net>" [unknown]
gpg: aka "Patrick Schleizer <adrelanos@whonix.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 916B 8D99 C38E AF5E 8ADC 7A2A 8D66 066A 2EEA CCDA
Subkey fingerprint: 6E97 9B28 A6F3 7C43 BE30 AFA1 CB8D 50BB 77BB 3C48
git show --no-patch --pretty=format:%GF "master^{commit}"
6E979B28A6F37C43BE30AFA1CB8D50BB77BB3C48
Iāll add the sub_key_fingerprint to buildconfig.d/30_signing_key.conf
And then just do a check against signed_by_fingerprint.
Iāll put /usr/bin/dm-git-tag-checkout-latest in help-steps, modify it slightly and move the entire git stage from derivative-maker-docker-start to prepare-build-machine by calling this script.
derivative-maker-docker-start will only export $TAG, $GIT and other similar env stuff. Strictly to be passed on.
derivative-maker/help-steps/git-gpg-verify can be used, but this is not wanted.
Why not just do curl -O https://www.whonix.org/keys/derivative.asc "${KEY_VOLUME}/derviatvie.asc" in derivative-maker-docker-run?
That provides the key through --volume mount, making it available before submodule sync. Then you just do the import in the container and verify normally. buildconfig.d/30_signing_key.conf will then simply say derivative_signing_key="~/.gnugp/derivative.asc"
I wrote something else where the user has to manually download and gpg import the key to "${KEY_VOLUME}" if itās empty, but this seems better.
import_key() {
local derivative_signing_key_fingerprint_item
for derivative_signing_key_fingerprint_item in "${derivative_signing_key_fingerprint_list[@]}"; do
if ! gpg --quiet --list-keys -- "${derivative_signing_key_fingerprint_item}" &>/dev/null; then
missing_key=true
fi
done
if [ ! "${missing_key}" = "true" ]; then
return 0
fi
for derivative_signing_public_key_item in "${derivative_signing_public_key_list[@]}"; do
gpg --keyid-format long --import --import-options show-only --with-fingerprint -- "${derivative_signing_public_key_item}"
gpg --import -- "${derivative_signing_public_key_item}"
gpg --check-sigs -- "${derivative_signing_public_key_item}"
fi
--check-sigs is passed a key, instead of a fingerprint (will cause error)
Maybe something like this for example, where fingerprints are associated with a key and only checked individually. (added another key with fingerprints to illustrate)
derivative_signing_public_key_list=("./keys/derivative.asc" "./keys/derivative2.asc")
derivative_signing_key_fingerprint_list=(
"916B8D99C38EAF5E8ADC7A2A8D66066A2EEACCDA
6E979B28A6F37C43BE30AFA1CB8D50BB77BB3C48"
"ADC7A2A8D66066A2EEACCDA916B8D99C38EAF5E8
BE30AFA1CB8D50B6E979B28A6F37C43B77BB3C48
1CB8D50B6E979B28A6F376F37C43B77BB3C4AGA4"
)
for key_index in "${!derivative_signing_public_key_list[@]}"; do
for derivative_signing_key_fingerprint_item in ${derivative_signing_key_fingerprint_list["$key_index"]}; do
if ! gpg --quiet --list-keys -- "${derivative_signing_key_fingerprint_item}" &>/dev/null; then
gpg --keyid-format long --import --import-options show-only --with-fingerprint -- "${derivative_signing_public_key_list["$key_index"]}"
gpg --import -- "${derivative_signing_public_key_list["$key_index"]}"
gpg --check-sigs -- "${derivative_signing_key_fingerprint_item}"
fi
done
done
As for this part, [ -z "${GIT}" ] could incorporate all corresponding git commands in an if.
## TODO: review
## - security
## - avoid developer loss of progress
return 0
Iām sure @arraybolt3 has got it covered, though.
Iām a little confused about the intention here - is the goal to check all of the fingerprints in the list, or only one of them? If the goal is to check only one of them, you can make this a bit more efficient by adding a break as the last statement in the if block. If you want to check all of them, you need to move the gpg --check-sigs command out of the if block.
Iām looking at this right now - I was thinking of doing something a bit like this, but I fear a developer one day using --git when they didnāt mean to and potentially losing uncommitted changes. (This could easily happen in my setup, where I use an additional wrapper script to call derivative-maker with the right arguments so I donāt have to remember them every time I call the script. Iāve more than once ran a build with the wrong arguments as a result.) So Iām thinking of making it so that if the user is doing anything that will change the git state (pulling, fetching, checking out, etc.), it checks for uncommitted changes using [ -z "$(git status --porcelain=v1 2>/dev/null)" ] first, and bails out if they exist. (Fancy git command shamelessly stolen from https://stackoverflow.com/a/3879077/19474638 :P)
Edit: Actually, help-steps/git_sanity_test can be used to do that job.
Yes break went missing there, just a quick example.
You donāt need to check all the fingerprints, if gpg --quiet --list-keys returns 1 on a single fingerprint, then you just import that key, and move on to the next fingerprint set & key.
Iāll test this and add it to git-gpg-verify if itās fine. You have write permissions on my fork anyway.
if [ ! "$(git status --porcelain)" = "" ]; then
error "Command git status --porcelain failed at the beginning!"
fi
if [ ! "$(git status --porcelain)" = "" ]; then
error "Command git status --porcelain failed at the end!"
fi
Edit: help-steps/git-sanity-test checks status with regards to dist_build_ignore_uncommitted" = "true" and --allow-uncommitted
git_sanity_test_check_for_uncommitted_changes() {
if [ -n "$(git status --porcelain)" ]; then
if [ "$dist_build_ignore_uncommitted" = "true" ]; then
true "${bold}${cyan}$BASH_SOURCE INFO: Git reports uncommitted changes! But you requested to ignore uncommitted changes, continuing... ${reset}"
true "${cyan}$BASH_SOURCE INFO: Running \"git status\" for debugging. ${reset}"
git status
true "${cyan}$BASH_SOURCE INFO: Running git \"clean -d --force --force --dry-run\" for debugging. ${reset}"
git clean -d --force --force --dry-run
true
else
error "Uncommitted changes! See above!"
So if --allow-uncommitted true then all thatās needed in git-gpg-verify is if [ -z "$(git status --porcelain)" ] which conditions the execution of these state altering git commands.
I can do that, or if youād like to thatās fine too.
If uncommitted, only checking out when a different tag is chosen from the current one and stashing first. Something like this could be a reasonable compromise compared to just exiting completely.
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
git pull
git checkout "${TAG}"
else
true "INFO: Uncommitted changes found. Skipping upstream merge."
if [ "${TAG}" != "$(git describe)" ]; then
true "INFO: Saving current changes before switch to ${TAG}."
git stash
git checkout "${TAG}"
fi
fi
I donāt like the āsecretā git stash. People would have to read this specific part of the source code to know that their changes were being saved in this way, and I donāt think that most people will do that (there are many parts of derivative-maker I still havenāt read). Aborting the build entirely is annoying, but thatās actually a good thing since it forces the user to pay attention to whatās happening. (There are also other things that can mangle uncommitted changes during a build, so in most instances itās a good idea for the developer to always commit everything before a build. I frequently make ācheckpointā commits that I later throw away in order to prevent lost changes.)
Iāll take a look at adding the fingerprint check code, I have some changes in my local fork of derivative-maker and can integrate those while doing other polish and whatnot.