| 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 :) |