feat: add Qubes development formula

Contributing to Qubes OS using Debian is possible, but there are edge
cases with linter versions, GUI editor versions, test packages in
run-tests that are better supported on Fedora, as this is the template
that Qubes OS developers most use.

Fixes: https://github.com/ben-grande/qusal/issues/139
Fixes: https://github.com/ben-grande/qusal/issues/126
This commit is contained in:
Ben Grande 2025-08-04 08:03:16 +02:00
parent 8ecfc09552
commit 5cb6350e22
No known key found for this signature in database
GPG key ID: 00C64E14F51F9E56
20 changed files with 564 additions and 62 deletions

View file

@ -28,6 +28,7 @@ host:
- rpm_spec/qusal-mirage-builder.spec
- rpm_spec/qusal-opentofu.spec
- rpm_spec/qusal-qubes-builder.spec
- rpm_spec/qusal-qubes-dev.spec
- rpm_spec/qusal-reader.spec
- rpm_spec/qusal-remmina.spec
- rpm_spec/qusal-signal.spec

View file

@ -0,0 +1,118 @@
# SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
%define project qubes-dev
%define license_csv AGPL-3.0-or-later
## Reproducibility.
%define source_date_epoch_from_changelog 1
%define use_source_date_epoch_as_buildtime 1
%define clamp_mtime_to_source_date_epoch 1
## Changelog is trimmed according to current date, not last date from changelog.
%define _changelog_trimtime 0
%define _changelog_trimage 0
%global _buildhost %{name}
## Python bytecode interferes when updates occur and restart is not done.
%undefine __brp_python_bytecompile
Name: qusal-qubes-dev
Version: 0.0.1
Release: 1%{?dist}
Summary: Development environment for Qubes OS
Group: qusal
Packager: %{?_packager}%{!?_packager:Ben Grande <ben.grande.b@gmail.com>}
Vendor: Ben Grande
License: AGPL-3.0-or-later
URL: https://github.com/ben-grande/qusal
BugURL: https://github.com/ben-grande/qusal/issues
Source0: %{name}-%{version}.tar.gz
BuildArch: noarch
Requires: qubes-mgmt-salt
Requires: qubes-mgmt-salt-dom0
Requires: qusal-dev
Requires: qusal-dotfiles
Requires: qusal-sys-net
Requires: qusal-utils
%description
Setup a development qube named "qubes-dev", dedicated to contributing to Qubes
OS repositories. As there there is a very broad set of repositories, only
common packages will be installed. The qube has netvm but can reach remote
servers if the policy allows.
%prep
%setup -q
%build
%check
%pre
%install
rm -rf -- %{buildroot}
install -m 755 -d -- \
%{buildroot}/srv/salt/qusal \
%{buildroot}%{_docdir}/%{name} \
%{buildroot}%{_defaultlicensedir}/%{name}
for license in $(printf '%s\n' "%{license_csv}" | tr "," " "); do
license_dir="LICENSES"
if test -d "salt/%{project}/LICENSES"; then
license_dir="salt/%{project}/LICENSES"
fi
install -m 644 -- \
"${license_dir}/${license}.txt" %{buildroot}%{_defaultlicensedir}/%{name}/
done
install -m 644 -- salt/%{project}/README.md %{buildroot}%{_docdir}/%{name}/
rm -rf -- \
salt/%{project}/LICENSES \
salt/%{project}/README.md \
salt/%{project}/.*
cp -rv -- salt/%{project} %{buildroot}/srv/salt/qusal/%{name}
%post
if test "$1" = "1"; then
## Install
qubesctl state.apply qubes-dev.create
qubesctl --skip-dom0 --targets=tpl-qubes-dev state.apply qubes-dev.install
qubesctl --skip-dom0 --targets=dvm-qubes-dev state.apply qubes-dev.configure-dvm
qubesctl --skip-dom0 --targets=qubes-dev state.apply qubes-dev.configure
if test -n "${proxy_target}"; then
sudo qubesctl --skip-dom0 --targets="${proxy_target}" state.apply sys-net.install-proxy
elif test "$1" = "2"; then
## Upgrade
true
fi
%preun
if test "$1" = "0"; then
## Uninstall
true
elif test "$1" = "1"; then
## Upgrade
true
fi
%postun
if test "$1" = "0"; then
## Uninstall
true
elif test "$1" = "1"; then
## Upgrade
true
fi
%files
%defattr(-,root,root,-)
%license %{_defaultlicensedir}/%{name}/*
%doc %{_docdir}/%{name}/README.md
%dir /srv/salt/qusal/%{name}
/srv/salt/qusal/%{name}/*
%dnl TODO: missing '%ghost', files generated during %post, such as Qrexec policies.
%changelog

View file

@ -0,0 +1,64 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
- {{ slsdotpath }}.home-cleanup
- dotfiles.copy-all
- utils.tools.zsh
- sys-pgp.install-client
- sys-git.install-client
- sys-ssh-agent.install-client
"{{ slsdotpath }}-installed-common":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs:
## Necessary
- qubes-core-agent-passwordless-root
- ca-certificates
## Usability
- tmux
- xclip
- bash-completion
## Reading documentation
- man-db
- info
- texinfo
## Searching files
- file
- tree
- ripgrep
- fzf
## Lint
- gitlint
## Fedora doesn't have: ruby-mdl (markdownlint, mdl)
{% set pkg = {
'Debian': {
'pkg': ['shellcheck', 'vim-nox', 'fd-find', 'ruby-mdl'],
},
'RedHat': {
'pkg': ['ShellCheck', 'vim-enhanced', 'fd-find', 'passwd'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-installed-os-specific-common":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'tpl-dev':
- match: list
- dev.install-common

View file

@ -0,0 +1,45 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- dev.install-common
- dev.install-python
"{{ slsdotpath }}-installed-qusal":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs:
- yamllint
- codespell
- pre-commit
- reuse
## Debian doesn't have: salt-lint
{% set pkg = {
'Debian': {
'pkg': [],
},
'RedHat': {
'pkg': ['salt-lint'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-installed-os-specific-qusal":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
{% endif -%}

View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'tpl-dev':
- match: list
- dev.install-qusal

View file

@ -1,5 +1,5 @@
{#
SPDX-FileCopyrightText: 2023 - 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
@ -7,66 +7,6 @@ SPDX-License-Identifier: AGPL-3.0-or-later
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.common.update
- {{ slsdotpath }}.home-cleanup
- dotfiles.copy-all
- utils.tools.zsh
- sys-pgp.install-client
- sys-git.install-client
- sys-ssh-agent.install-client
"{{ slsdotpath }}-installed":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs:
## Necessary
- qubes-core-agent-passwordless-root
- ca-certificates
## Usability
- tmux
- xclip
- bash-completion
## Reading documentation
- man-db
- info
- texinfo
## Searching files
- file
- tree
- ripgrep
- fzf
## Lint
- pre-commit
- precious
- reuse
- gitlint
- pylint
- yamllint
- ruby-mdl
- codespell
## Fedora doesn't have: ruby-mdl (markdownlint, mdl)
## Debian doesn't have: salt-lint
{% set pkg = {
'Debian': {
'pkg': ['shellcheck', 'vim-nox', 'fd-find'],
},
'RedHat': {
'pkg': ['ShellCheck', 'vim-enhanced', 'fd-find', 'salt-lint', 'passwd'],
},
}.get(grains.os_family) -%}
"{{ slsdotpath }}-installed-os-specific":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs: {{ pkg.pkg|sequence|yaml }}
- dev.install-qusal
{% endif -%}

83
salt/qubes-dev/README.md Normal file
View file

@ -0,0 +1,83 @@
# qubes-dev
Development environment for Qubes OS.
## Table of Contents
* [Description](#description)
* [Installation](#installation)
* [Access Control](#access-control)
* [Usage](#usage)
## Description
Setup a development qube named "qubes-dev", dedicated to contributing to Qubes
OS repositories. As there there is a very broad set of repositories, only
common packages will be installed. The qube has netvm but can reach remote
servers if the policy allows.
## Installation
* Top:
```sh
sudo qubesctl top.enable qubes-dev
sudo qubesctl --targets=tpl-qubes-dev,dvm-qubes-dev,qubes-dev state.apply
sudo qubesctl top.disable qubes-dev
proxy_target="$(qusal-report-updatevm-origin)"
if test -n "${proxy_target}"; then
sudo qubesctl --skip-dom0 --targets="${proxy_target}" state.apply sys-net.install-proxy
fi
```
* State:
<!-- pkg:begin:post-install -->
```sh
sudo qubesctl state.apply qubes-dev.create
sudo qubesctl --skip-dom0 --targets=tpl-qubes-dev state.apply qubes-dev.install
sudo qubesctl --skip-dom0 --targets=dvm-qubes-dev state.apply qubes-dev.configure-dvm
sudo qubesctl --skip-dom0 --targets=qubes-dev state.apply qubes-dev.configure
proxy_target="$(qusal-report-updatevm-origin)"
if test -n "${proxy_target}"; then
sudo qubesctl --skip-dom0 --targets="${proxy_target}" state.apply sys-net.install-proxy
fi
```
<!-- pkg:end:post-install -->
The installation will make the Qusal TCP Proxy available in the `updatevm`
(after it is restarted in case it is template based). If you want to have the
proxy available on a `netvm` that is not deployed by Qusal, install the Qusal
TCP proxy on the templates of your `netvm`:
```sh
sudo qubesctl --skip-dom0 --targets=TEMPLATE state.apply sys-net.install-proxy
```
Remember to restart the `netvms` after the proxy installation for the changes
to take effect.
## Access Control
_Default policy_: `denies` `all` qubes from calling `qusal.ConnectTCP`
Allow qube `qubes-dev` to `connect` to `github.com:22` via `disp-sys-net` but
not to any other host or via any other qube:
```qrexecpolicy
qusal.ConnectTCP +github.com+22 qubes-dev @default allow target=disp-sys-net
qusal.ConnectTCP * qubes-dev @anyvm deny
```
## Usage
The development qube `qubes-dev` can be used for:
* everything the [dev](../dev/README.md) qube can do;
* contributing to Qubes OS
As the `qubes-dev` qube has no netvm, configure the Qrexec policy to allow or
ask calls to the `qusal.ConnectTCP` RPC service, so the qube can communicate
with a remote repository for example.

8
salt/qubes-dev/clone.sls Normal file
View file

@ -0,0 +1,8 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% from 'utils/macros/clone-template.sls' import clone_template -%}
{{ clone_template('fedora-minimal', sls_path) }}

10
salt/qubes-dev/clone.top Normal file
View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'dom0':
- match: nodegroup
- qubes-dev.clone

View file

@ -0,0 +1,12 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- utils.tools.zsh.touch-zshrc
{% endif -%}

View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'*':
- match: nodegroup
- qubes-dev.configure-dvm

View file

@ -0,0 +1,13 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- {{ slsdotpath }}.home-cleanup
- dotfiles.copy-all
{% endif -%}

View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'*':
- match: nodegroup
- qubes-dev.configure

103
salt/qubes-dev/create.sls Normal file
View file

@ -0,0 +1,103 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{%- from "qvm/template.jinja" import load -%}
include:
- {{ slsdotpath }}.clone
- sys-net.show-updatevm-origin
{% load_yaml as defaults -%}
name: tpl-{{ slsdotpath }}
force: True
require:
- sls: {{ slsdotpath }}.clone
prefs:
- audiovm: ""
{%- endload %}
{{ load(defaults) }}
{% load_yaml as defaults -%}
name: {{ slsdotpath }}
force: True
require:
- sls: {{ slsdotpath }}.clone
present:
- template: tpl-{{ slsdotpath }}
- label: purple
prefs:
- template: tpl-{{ slsdotpath }}
- label: purple
- netvm: ""
- audiovm: ""
- vcpus: 1
- memory: 400
- maxmem: 600
- autostart: False
- include_in_backups: True
features:
- enable:
- service.split-gpg2-client
- service.qusal-proxy-client
- service.crond
- disable:
- service.cups
- service.cups-browsed
{%- endload %}
{{ load(defaults) }}
{% load_yaml as defaults -%}
name: dvm-{{ slsdotpath }}
force: True
require:
- sls: {{ slsdotpath }}.clone
present:
- template: tpl-{{ slsdotpath }}
- label: red
prefs:
- template: tpl-{{ slsdotpath }}
- label: red
- audiovm: ""
- vcpus: 1
- memory: 400
- maxmem: 600
- autostart: False
- template_for_dispvms: True
- include_in_backups: False
features:
- enable:
- appmenus-dispvm
- disable:
- service.cups
- service.cups-browsed
{%- endload %}
{{ load(defaults) }}
{% load_yaml as defaults -%}
name: disp-{{ slsdotpath }}
force: True
require:
- qvm: dvm-{{ slsdotpath }}
present:
- template: dvm-{{ slsdotpath }}
- label: red
- class: DispVM
prefs:
- template: dvm-{{ slsdotpath }}
- label: red
- audiovm: ""
- vcpus: 1
- memory: 400
- maxmem: 600
- autostart: False
- include_in_backups: False
features:
- disable:
- appmenus-dispvm
- service.cups
- service.cups-browsed
{%- endload %}
{{ load(defaults) }}

10
salt/qubes-dev/create.top Normal file
View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'dom0':
- match: nodegroup
- qubes-dev.create

19
salt/qubes-dev/init.top Normal file
View file

@ -0,0 +1,19 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'dom0':
- match: nodegroup
- qubes-dev.create
'tpl-qubes-dev':
- qubes-dev.install
'dvm-qubes-dev':
- qubes-dev.configure-dvm
'qubes-dev':
- qubes-dev.configure
'(I@qubes:type:template or I@qubes:type:standalone) and (G@kernel:Linux or G@kernel:*BSD)':
- match: compound
- sys-net.install-proxy

View file

@ -0,0 +1,25 @@
{#
SPDX-FileCopyrightText: 2023 - 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
{% if grains['nodename'] != 'dom0' -%}
include:
- dev.install-common
- dev.install-python
"{{ slsdotpath }}-installed":
pkg.installed:
- require:
- sls: utils.tools.common.update
- install_recommends: False
- skip_suggestions: True
- setopt: "install_weak_deps=False"
- pkgs:
- glade
- qt6-designer
# TODO: reboot vm and test missing packages on tests
{% endif -%}

View file

@ -0,0 +1,10 @@
{#
SPDX-FileCopyrightText: 2025 Benjamin Grande M. S. <ben.grande.b@gmail.com>
SPDX-License-Identifier: AGPL-3.0-or-later
#}
base:
'tpl-qubes-dev':
- match: list
- qubes-dev.install

1
salt/qubes-dev/version Normal file
View file

@ -0,0 +1 @@
0.0.1