qubes-apply

python script to automate qubes saltstack

git clone https://9o.is/git/qubes-apply.git

commit 0435c974eaade17aa0506b8d6ded9edb899a3322
parent f40fc916d69b8249447d54368acfb7dd39aaec95
Author: Jul <jul@9o.is>
Date:   Fri, 27 Feb 2026 13:45:24 +0800

add client scripts

Diffstat:
MREADME.md | 8+++++---
Aclient/30-mgmt.policy | 2++
Aclient/qubes-apply | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Aclient/qubes.SaltQubesApply | 4++++
Aclient/qubes.SaltUserUpload | 10++++++++++
5 files changed, 72 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md @@ -8,11 +8,13 @@ Apply user Salt states to Qubes OS VMs with change detection. State is tracked in `/usr/local/var/qubes-apply/last-run.json`, which is just a json of sha1 hashes of parsed files and non-parsed directories. All top files are scanned and supports glob, pcre, and pillars `qubes:tags` `qubes:type:app` `qubes:type:template`. Only sls files in the `user_salt/base` directory (configurable) are parsed and recognize sls dependencies via the `includes` command. This is useful to group sls that are shared between vms. +## Working from a VM + +If you'd rather not work from dom0 `/srv` directory, see the `client` directory. It includes qubes-rpc commands and policy files and a qubes-apply command that packages the files and installs it to `/srv`. It's kind of a hack but works. + ## Installation -```bash -sudo make install -``` +In dom0, run the `sudo make install` or manually move the qubes-apply python script manually. ## Usage diff --git a/client/30-mgmt.policy b/client/30-mgmt.policy @@ -0,0 +1,2 @@ +qubes.SaltUserUpload * mgmt dom0 allow +qubes.SaltQubesApply * mgmt dom0 allow diff --git a/client/qubes-apply b/client/qubes-apply @@ -0,0 +1,51 @@ +#!/usr/bin/bash +set -eo pipefail + +configfile=$HOME/.config/qubes-apply/config + +if [ -n $configfile ]; then + . $HOME/.config/qubes-apply/config +fi + +cache_path="$HOME/.cache/qubes-apply" +package="/tmp/user-salt.tar" +args=($@) +paths=() + +for path in salt pillar formulas; do + if [ -d $project_path/$path ]; then + paths+=($path) + fi +done + +if [[ ! "${paths[@]}" ]]; then + echo "error: no valid directories found in '$project_path'" + exit 1 +fi + +if [[ " ${args[@]} " =~ ( -u | --upload-only ) ]]; then + upload_only=1 +fi + +if [ "$force_color" ]; then + args+=(--force-color) +fi + +if [[ " ${args[@]} " =~ ' --force-color ' ]]; then + qrexec_flags='--no-filter-escape-chars-stdout --no-filter-escape-chars-stderr' +fi + +mkdir -p $cache_path +[ -f $cache_path/log ] || touch $cache_path/log + +tar cf $package -C $project_path ${paths[@]} \ + --transform 's,^\(salt\|pillar\|formulas\),user_\1,' +qrexec-client-vm $qrexec_flags dom0 qubes.SaltUserUpload + +if [ "$upload_only" ]; then + echo "upload only enabled... skipping apply" +else + qrexec-client-vm $qrexec_flags dom0 \ + qubes.SaltQubesApply <<< "${args[@]}" | tee $cache_path/log +fi + diff --git a/client/qubes.SaltQubesApply b/client/qubes.SaltQubesApply @@ -0,0 +1,4 @@ +#!/usr/bin/bash + +read args +sudo qubes-apply ${args[@]} 2>&1 diff --git a/client/qubes.SaltUserUpload b/client/qubes.SaltUserUpload @@ -0,0 +1,10 @@ +#!/usr/bin/bash +set -ueo pipefail + +package="/tmp/user-salt.tar" + +echo "Installing user salt..." +sudo rm -rf $package /srv/user_* +qvm-run --pass-io mgmt "cat $package" > $package +sudo tar xf $package -C /srv +