Title: Using git bundle to synchronize a repository between Qubes OS | |
dom0 and an AppVM | |
Author: Solène | |
Date: 17 June 2023 | |
Tags: security qubesos git | |
Description: In this article you will learn how to use git bundle in | |
order to synchronize git repositories between Qubes OS dom0 and an | |
AppVM. | |
# Introduction | |
In a previous article, I explained how to use Fossil version control | |
system to version the files you may write in dom0 and sync them against | |
a remote repository. | |
I figured how to synchronize a git repository between an AppVM and | |
dom0, then from the AppVM it can be synchronized remotely if you want. | |
This can be done using the git feature named bundle, which bundle git | |
artifacts into a single file. | |
Qubes OS project official website | |
Git bundle documentation | |
Using fossil to synchronize data from dom0 with a remote fossil repository | |
# What you will learn | |
In this setup, you will create a git repository (this could be a clone | |
of a remote repository) in an AppVM called Dev, and you will clone it | |
from there into dom0. | |
Then, you will learn how to send and receive changes between the AppVM | |
repo and the one in dom0, using git bundle. | |
# Setup | |
The first step is to have git installed in your AppVM and in dom0. | |
For the sake of simplicity for the guide, the path `/tmp/repo/` refers | |
to the git repository location in both dom0 and the AppVM, don't forget | |
to adapt to your setup. | |
In the AppVM Dev, create a git repository using `cd /tmp/ && git init | |
repo`. We need a first commit for the setup to work because we can't | |
bundle commits if there is nothing. So, commit at least one file in | |
that repo, if you have no idea, you can write a short README.md file | |
explaining what this repository is for. | |
In dom0, use the following command: | |
``` | |
qvm-run -u user --pass-io Dev "cd /tmp/repo/ && git bundle create - master" > /… | |
cd /tmp/ && git clone -b master /tmp/git.bundle repo | |
``` | |
Congratulations, you cloned the repository into dom0 using the bundle | |
file, the path `/tmp/git.bundle` is important because it's | |
automatically set as URL for the remote named "origin". If you want to | |
manage multiple git repositories this way, you should use a different | |
name for this exchange file for each repo. | |
``` | |
[solene@dom0 repo]$ git remote -v | |
origin /tmp/git.bundle (fetch) | |
origin /tmp/git.bundle (push) | |
``` | |
Back to the AppVM Dev, run the following command in the git repository, | |
this will configure the bundle file to use for the remote dom0. Like | |
previously, you can pick the name you prefer. | |
``` | |
git remote add dom0 /tmp/dom0.bundle | |
``` | |
# Workflow | |
Now, let's explain the workflow to exchange data between the AppVM and | |
dom0. From here, we will only use dom0. | |
Create a file `push.sh` in your git repository with the content: | |
``` | |
#!/bin/sh | |
REPO="/tmp/repo/" | |
BRANCH=master | |
# setup on the AppVM | |
# git remote add dom0 /tmp/dom0.bundle | |
git bundle create - origin/master..master | \ | |
qvm-run -u user --pass-io Dev "cat > /tmp/dom0.bundle" | |
qvm-run -u user --pass-io Dev "cd ${REPO} && git pull -r dom0 ${BRANCH}" | |
``` | |
Create a file `pull.sh` in your git repository with the content: | |
``` | |
#!/bin/sh | |
REPO="/tmp/repo/" | |
BRANCH=master | |
# init the repo on dom0 | |
# git clone -b ${BRANCH} /tmp/git.bundle | |
qvm-run -u user --pass-io Dev "cd ${REPO} && git bundle create - dom0/master..$… | |
git pull -r | |
``` | |
Make the files `push.sh` and `pull.sh` executable. | |
If you don't want to have the files committed in your repository, add | |
their names to the file `.gitignore`. | |
Now, you are able to send changes to the AppVM repo using `./push.sh`, | |
and receive changes using `./pull.sh`. | |
If needed, those scripts could be made more generic and moved in a | |
directory in your PATH instead of being used from within the git | |
repository. | |
## Explanations | |
Here are some explanations about those two scripts. | |
### Push.sh | |
In the script `push.sh`, `git bundle` is used to send a bundle file | |
over stdout containing artifacts from the remote AppVM last known | |
commit up to the latest commit in the current repository, hence | |
origin/master..master range. This data is piped into the file | |
`/tmp/dom0.bundle` in the AppVm, and was configured earlier as a remote | |
for the repository. | |
Then, the command `git pull -r dom0 master` is used to fetch the | |
changes from the bundle, and rebase the current repository, exactly | |
like you would do with a "real" remote over the network. | |
### Pull.sh | |
In the script `pull.sh`, we run the `git bundle` from within the AppVM | |
Dev to generate on stdout the bundle from the last known state of dom0 | |
up to the latest commit in the branch master, and pipe into the dom0 | |
file `/tmp/git.bundle`, remember that this file is the remote origin in | |
dom0's clone. | |
After the bundle creation, a regular `git pull -r` is used to fetch the | |
changes, and rebase the repository. | |
### Using branches | |
If you use different branches, this could require adding an extra | |
parameter to the script to make the variable BRANCH configurable. | |
# Conclusion | |
I find this setup really elegant, the safe `qvm-run` is used to | |
exchange static data between dom0 and the AppVM, no network is involved | |
in the process. Now there is no reason to have dom0 configuration file | |
not properly tracked within a version control system :) |