dtcc-onboarding/flake.nix
2026-04-22 11:01:33 -05:00

250 lines
7.9 KiB
Nix

{
description = "A flake providing a NixOS Qemu VM for DTCC onboarding.";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = { self, nixpkgs }: let
# (note): Keep this up to date
constants = {
citrixDownloadPageUrl = "https://www.citrix.com/downloads/workspace-app/legacy-workspace-app-for-linux/workspace-app-for-linux-250810.html";
citrixTarballHash = "sha256-bd3ClxBRJgvjJW+waKBE31k9ePam+n2pHeSjlkvkDRo=";
dtccVdiUrl = "https://myvdi.dtcc.com";
icaDisclaimer = ''
WARNING: ICA files are only good to be used ONCE. If you've logged into the DTCC virtual
desktop using it before, you will get a connection error from Citrix upon trying to log in
with it again. To get a fresh ICA file, you need to _refresh_ your myvdi.dtcc.com page and
download it via 'Open' again.
The ICA files listed below are ordered from newest to oldest for your convenience,
so '1' is usually the correct choice. This file will get copied into the VM.
You are free to remove old/stale ICA files from your system.
'';
};
pkgs = import nixpkgs {
system = "x86_64-linux";
config = {
allowUnfree = true;
allowBroken = true;
permittedInsecurePackages = [
"libsoup-2.74.3"
];
};
overlays = [
(self: super: {
citrix_workspace = super.citrix_workspace.overrideAttrs (_: {
src = scripts.citrixTarballScraper;
});
ungoogled-chromium = super.ungoogled-chromium.override {
# Disables the prompt to create a default keyring on initial startup.
commandLineArgs = "--password-store=basic";
};
})
];
};
scripts.citrixTarballScraper = pkgs.stdenvNoCC.mkDerivation {
name = "citrix-workspace-src.tar.gz";
outputHashMode = "flat";
outputHashAlgo = "sha256";
outputHash = constants.citrixTarballHash;
nativeBuildInputs = [ pkgs.curl pkgs.cacert ];
# (credit): Based on the scraper used in the AUR PKGBUILD for `icaclient-beta`
buildCommand = ''
_body="$(curl -sL "${constants.citrixDownloadPageUrl}")"
_dl_urls="$(grep -F ".tar.gz?__gda__" <<< "$_body")"
_tarball_url=https:"$(sed -En 's|^.*rel="(//.*/linuxx64-[^"]*)".*$|\1|p' <<< "$_dl_urls")"
curl -L "$_tarball_url" -o "$out"
'';
};
scripts.launchVm = pkgs.writeShellScriptBin "launch-vm" ''
# Vibecoded w/ Claude
select_ica_file() {
local download_dir="''${XDG_DOWNLOAD_DIR:-$HOME/Downloads}"
local -a files
mapfile -t files < <(
{
find "$download_dir" -maxdepth 1 -name "*.ica" -type f -printf "%T@\t%p\n" 2>/dev/null
find "$PWD" -maxdepth 1 -name "*.ica" -type f -printf "%T@\t%p\n" 2>/dev/null
} \
| sort -u -t$'\t' -k2 \
| sort -rn -t$'\t' -k1 \
| cut -f2-
)
if [[ ''${#files[@]} -eq 0 ]]; then
echo "No .ica files found in $download_dir or $PWD." >&2
return 0
fi
echo "${constants.icaDisclaimer}" >&2
echo "Available .ica files:" >&2
for i in "''${!files[@]}"; do
echo " $((i+1))) ''${files[$i]}" >&2
done
local selection
while true; do
read -rp "Select file [1-''${#files[@]}] (leave blank to start interactive session): " \
selection >&2
if [[ -z "$selection" ]] || \
([[ "$selection" =~ ^[0-9]+$ ]] && \
(( selection >= 1 && selection <= ''${#files[@]} ))); then
break
fi
echo "Invalid selection, please enter a number between 1 and ''${#files[@]}." >&2
echo "Or leave blank to start an interactive session."
done
if [[ -n "$selection" ]]; then
echo "''${files[$((selection-1))]}"
fi
}
ica_file=$(select_ica_file)
mkdir -p /tmp/dtcc-onboarding
if [[ -n "''${ica_file}" ]]; then
cp "$ica_file" /tmp/dtcc-onboarding/dtcc-ica.ica
else
echo "Launching interactive session..." >&2
fi
${self.nixosConfigurations.dtcc-onboarding.config.system.build.vm}/bin/run-nixos-vm
'';
scripts.autolaunch = pkgs.writeShellScriptBin "autolaunch" ''
if [[ -f /mnt/ica/dtcc-ica.ica ]]; then
${pkgs.citrix_workspace}/bin/wfica /mnt/ica/dtcc-ica.ica
else
${pkgs.ungoogled-chromium}/bin/chromium ${constants.dtccVdiUrl}
fi
'';
in {
nixosConfigurations.dtcc-onboarding = nixpkgs.lib.nixosSystem {
inherit pkgs;
system = "x86_64-linux";
modules = [
"${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix"
({ pkgs, ... }: {
environment.systemPackages = with pkgs; [
citrix_workspace
ungoogled-chromium
gnomeExtensions.no-overview
];
services = {
displayManager.gdm = {
enable = true;
wayland = true;
};
displayManager.autoLogin = {
enable = true;
user = "nixos";
};
desktopManager.gnome.enable = true;
};
programs.dconf = {
enable = true;
profiles.user.databases = [{
settings = {
"org/gnome/shell" = {
enabled-extensions = [ "no-overview@fthx" ];
welcome-dialog-last-shown-version = "99.0";
};
};
}];
};
users.users.nixos = {
isNormalUser = true;
extraGroups = [ "wheel" ];
password = "";
};
security.sudo.wheelNeedsPassword = false;
xdg.mime.enable = true;
environment.etc."share/applications/mimeapps.list".text = ''
[Default Applications]
application/x-ica=wfica.desktop
'';
environment.etc."share/applications/wfica.desktop".text = ''
[Desktop Entry]
Type=Application
Name=Citrix Workspace
Exec=wfica %f
MimeType=application/x-ica;
NoDisplay=true
'';
environment.etc."chromium/policies/managed/default-browser.json".text = builtins.toJSON {
DefaultBrowserSettingEnabled = false;
};
environment.etc."chromium/policies/managed/downloads.json".text = builtins.toJSON {
PromptForDownloadLocation = false;
AutoOpenFileTypes = [ "ica" ];
};
# Launches Citrix or Chromium depending on whether the user specified a file on init.
systemd.user.services.autolaunch = {
description = "Launch Citrix ICA session";
wantedBy = [ "graphical-session.target" ];
after = [ "graphical-session.target" ];
environment.PATH = pkgs.lib.mkForce "/run/current-system/sw/bin:/run/wrappers/bin";
serviceConfig = {
ExecStart = "${scripts.autolaunch}/bin/autolaunch";
Restart = "no";
Type = "oneshot";
};
};
system.stateVersion = "25.11";
virtualisation = {
cores = 8;
memorySize = 10 * 1024;
msize = 128 * 1024;
diskSize = 12 * 1024;
qemu.options = [
"-vga none"
"-device virtio-vga"
"-audio pa,model=virtio"
];
sharedDirectories = {
default = {
source = "/tmp/dtcc-onboarding";
target = "/mnt/ica";
};
};
};
})
];
};
packages.x86_64-linux = {
inherit (scripts) citrixTarballScraper;
};
apps.x86_64-linux = {
default = {
type = "app";
program = "${scripts.launchVm}/bin/launch-vm";
};
};
};
}