mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:46 +01:00
feat(nixpak): sandbox Bambu Studio and OrcaSlicer (#495)
Assisted-by: DeepSeek Harness (deepseek-flash)
This commit is contained in:
1 parent
1a939e2c9a
commit
c3990cc4be
10 files changed
+255
-31
No files matched your search
+15
-13
@@ -19,19 +19,21 @@ Deployed and interactively validated on the Linux desktop host (2026-10-31). Pol
|
||||
`Media` means audio playback, microphone, Camera and ScreenCast portals. Writable paths are listed
|
||||
explicitly; other files use the document portal. Every app also has private writable state.
|
||||
|
||||
| App | Network | Writable paths | Grants |
|
||||
| ------------ | ------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| Firefox | Host loopback | `~/.mozilla`, personal files, Trash, Firefox artwork | Audio, browserpass, MPRIS, idle; camera/screen sharing intentionally unavailable |
|
||||
| Chromium | Host loopback | `~/.config/chromium`, personal files | Media, browserpass, MPRIS, idle, v12 Secret |
|
||||
| Chrome | Isolated | `~/.config/google-chrome`, Downloads | Media, browserpass, MPRIS, idle, v12 Secret |
|
||||
| Brave Origin | Isolated | `~/.config/BraveSoftware/Brave-Origin`, Downloads | v12 Secret |
|
||||
| Edge | Isolated | `~/.config/microsoft-edge`, Downloads | v12 Secret |
|
||||
| QQ | Isolated | Personal files, private app state | Media, notifications, tray, MPRIS, idle, accessibility |
|
||||
| Telegram | Isolated | Personal files, private app state | Media, notifications, tray, MPRIS, idle, accessibility, Ayatana indicators |
|
||||
| Zoom | Isolated | `~/.zoom`, `zoomus.conf`, `zoom.conf`, Downloads, `Documents/Zoom`, private app state | Media, X11/XWayland, FHS, SNI tray, idle, `/dev/video0-1`, read-only `/sys/class/drm` |
|
||||
| WeChat | Isolated | Documents, Downloads, app-scoped `wechat` data, private app state | Media, Wayland, X11 fallback, SNI tray, file chooser portal |
|
||||
| Foliate | None | app-scoped state | File chooser, OpenURI, notifications, IME, accessibility |
|
||||
| Krita | None | app-scoped state | File chooser, OpenURI, print, inhibit, notifications, IME, accessibility |
|
||||
| App | Network | Writable paths | Grants |
|
||||
| ------------ | ------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| Firefox | Host loopback | `~/.mozilla`, personal files, Trash, Firefox artwork | Audio, browserpass, MPRIS, idle; camera/screen sharing intentionally unavailable |
|
||||
| Chromium | Host loopback | `~/.config/chromium`, personal files | Media, browserpass, MPRIS, idle, v12 Secret |
|
||||
| Chrome | Isolated | `~/.config/google-chrome`, Downloads | Media, browserpass, MPRIS, idle, v12 Secret |
|
||||
| Brave Origin | Isolated | `~/.config/BraveSoftware/Brave-Origin`, Downloads | v12 Secret |
|
||||
| Edge | Isolated | `~/.config/microsoft-edge`, Downloads | v12 Secret |
|
||||
| QQ | Isolated | Personal files, private app state | Media, notifications, tray, MPRIS, idle, accessibility |
|
||||
| Telegram | Isolated | Personal files, private app state | Media, notifications, tray, MPRIS, idle, accessibility, Ayatana indicators |
|
||||
| Zoom | Isolated | `~/.zoom`, `zoomus.conf`, `zoom.conf`, Downloads, `Documents/Zoom`, private app state | Media, X11/XWayland, FHS, SNI tray, idle, `/dev/video0-1`, read-only `/sys/class/drm` |
|
||||
| WeChat | Isolated | Documents, Downloads, app-scoped `wechat` data, private app state | Media, Wayland, X11 fallback, SNI tray, file chooser portal |
|
||||
| Foliate | None | Documents/Downloads/Pictures read-only, app-scoped state | File chooser, OpenURI, notifications, IME, accessibility |
|
||||
| Krita | None | Documents/Downloads/Pictures writable, app-scoped state | File chooser, OpenURI, print, inhibit, notifications, IME, accessibility |
|
||||
| Bambu Studio | Isolated | Documents/Downloads/Pictures writable, app-scoped state | X11/XWayland, PulseAudio, cloud/LAN network, file chooser, notifications, IME, accessibility |
|
||||
| OrcaSlicer | Isolated | Documents/Downloads/Pictures writable, app-scoped state | X11/XWayland, cloud/LAN network, file chooser, notifications, IME, accessibility |
|
||||
|
||||
All browsers get read-only NSS certificates, printing, native notifications and accessibility.
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
lib,
|
||||
bambu-studio,
|
||||
mkNixPak,
|
||||
buildEnv,
|
||||
makeDesktopItem,
|
||||
runCommandLocal,
|
||||
...
|
||||
}:
|
||||
let
|
||||
appId = "com.bambulab.BambuStudio";
|
||||
package = bambu-studio;
|
||||
|
||||
wrapped = mkNixPak {
|
||||
config = {
|
||||
imports = [ ./modules/slicer-policy.nix ];
|
||||
app = {
|
||||
inherit package;
|
||||
binPath = "bin/bambu-studio";
|
||||
};
|
||||
flatpak = { inherit appId; };
|
||||
# The Agora SDK used by the printer camera preview aborts when
|
||||
# PulseAudio initialization fails.
|
||||
slicer.enablePulse = true;
|
||||
# Work around wxWidgets HiDPI text clipping under fractional scaling.
|
||||
# https://github.com/bambulab/BambuStudio/issues/4959
|
||||
bubblewrap.env.GDK_DPI_SCALE = "0.8";
|
||||
};
|
||||
};
|
||||
exe = lib.getExe wrapped.config.script;
|
||||
assets = runCommandLocal "bambu-studio-desktop-assets" { } ''
|
||||
mkdir -p $out/share
|
||||
ln -s ${package}/share/icons $out/share/icons
|
||||
'';
|
||||
in
|
||||
buildEnv {
|
||||
inherit (wrapped.config.script) name passthru;
|
||||
meta = wrapped.config.script.meta // {
|
||||
mainProgram = "bambu-studio";
|
||||
};
|
||||
paths = [
|
||||
wrapped.config.script
|
||||
assets
|
||||
(makeDesktopItem {
|
||||
name = "com.bambulab.BambuStudio";
|
||||
desktopName = "BambuStudio";
|
||||
genericName = "3D Printing Software";
|
||||
comment = "PC software for BambuLab 3D printers";
|
||||
exec = "${exe} %U";
|
||||
icon = "BambuStudio";
|
||||
terminal = false;
|
||||
startupWMClass = "bambu-studio";
|
||||
categories = [
|
||||
"Graphics"
|
||||
"3DGraphics"
|
||||
"Engineering"
|
||||
];
|
||||
mimeTypes = [
|
||||
"model/stl"
|
||||
"model/3mf"
|
||||
"application/vnd.ms-3mfdocument"
|
||||
"application/prs.wavefront-obj"
|
||||
"application/x-amf"
|
||||
"x-scheme-handler/bambustudio"
|
||||
"model/step"
|
||||
];
|
||||
extraConfig.X-Flatpak = appId;
|
||||
})
|
||||
];
|
||||
}
|
||||
@@ -29,6 +29,8 @@ in
|
||||
microsoft-edge = wrapper super ./microsoft-edge.nix;
|
||||
foliate = wrapper super ./foliate.nix;
|
||||
krita = wrapper pkgs-stable ./krita.nix;
|
||||
bambu-studio = wrapper pkgs-master ./bambu-studio.nix;
|
||||
orca-slicer = wrapper pkgs-master ./orca-slicer.nix;
|
||||
zoom = wrapper super ./zoom.nix;
|
||||
wechat = wrapper pkgs-patched ./wechat.nix;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Shared policy for the wxWidgets/GTK3 slicers. Both applications are X11-only
|
||||
# and use pasta networking for cloud services and LAN printer discovery.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
sloth,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.slicer;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./desktop-base.nix
|
||||
./network.nix
|
||||
];
|
||||
options.slicer.enablePulse = lib.mkEnableOption "PulseAudio for Bambu printer video preview";
|
||||
config = {
|
||||
pasta.mode = "isolate";
|
||||
bubblewrap = {
|
||||
sockets = {
|
||||
x11 = true;
|
||||
pulse = lib.mkForce cfg.enablePulse;
|
||||
};
|
||||
env = {
|
||||
DISPLAY = sloth.envOr "DISPLAY" "";
|
||||
XAUTHORITY = sloth.envOr "XAUTHORITY" (sloth.concat' sloth.homeDir "/.Xauthority");
|
||||
GDK_BACKEND = "x11";
|
||||
};
|
||||
# File-manager launches pass host paths into the sandbox. Slicers both read
|
||||
# models and write sliced output, so give the common document directories
|
||||
# read-write access; the file chooser still handles other locations.
|
||||
bind.rw = [
|
||||
sloth.xdgDocumentsDir
|
||||
sloth.xdgDownloadDir
|
||||
sloth.xdgPicturesDir
|
||||
];
|
||||
};
|
||||
portalGroups = {
|
||||
fileChooser = true;
|
||||
openUri = true;
|
||||
notifications = true;
|
||||
inputMethod = true;
|
||||
};
|
||||
desktopIntegration = {
|
||||
notifications = true;
|
||||
accessibility = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
lib,
|
||||
orca-slicer,
|
||||
mkNixPak,
|
||||
buildEnv,
|
||||
makeDesktopItem,
|
||||
runCommandLocal,
|
||||
...
|
||||
}:
|
||||
let
|
||||
appId = "com.orcaslicer.OrcaSlicer";
|
||||
package = orca-slicer;
|
||||
|
||||
wrapped = mkNixPak {
|
||||
config = {
|
||||
imports = [ ./modules/slicer-policy.nix ];
|
||||
app = {
|
||||
inherit package;
|
||||
binPath = "bin/orca-slicer";
|
||||
};
|
||||
flatpak = { inherit appId; };
|
||||
# WebKitGTK's DMA-BUF renderer produces a blank home page under
|
||||
# XWayland on NVIDIA; force the software path like Bambu does.
|
||||
bubblewrap.env.WEBKIT_DISABLE_DMABUF_RENDERER = "1";
|
||||
};
|
||||
};
|
||||
exe = lib.getExe wrapped.config.script;
|
||||
assets = runCommandLocal "orca-slicer-desktop-assets" { } ''
|
||||
mkdir -p $out/share
|
||||
ln -s ${package}/share/icons $out/share/icons
|
||||
'';
|
||||
in
|
||||
buildEnv {
|
||||
inherit (wrapped.config.script) name passthru;
|
||||
meta = wrapped.config.script.meta // {
|
||||
mainProgram = "orca-slicer";
|
||||
};
|
||||
paths = [
|
||||
wrapped.config.script
|
||||
assets
|
||||
(makeDesktopItem {
|
||||
name = "com.orcaslicer.OrcaSlicer";
|
||||
desktopName = "OrcaSlicer";
|
||||
genericName = "3D Printing Software";
|
||||
comment = "G-code generator for 3D printers";
|
||||
exec = "${exe} %U";
|
||||
icon = "OrcaSlicer";
|
||||
terminal = false;
|
||||
startupWMClass = "orca-slicer";
|
||||
categories = [
|
||||
"Graphics"
|
||||
"3DGraphics"
|
||||
"Engineering"
|
||||
];
|
||||
mimeTypes = [
|
||||
"model/stl"
|
||||
"model/3mf"
|
||||
"application/vnd.ms-3mfdocument"
|
||||
"application/prs.wavefront-obj"
|
||||
"application/x-amf"
|
||||
"x-scheme-handler/orcaslicer"
|
||||
"model/step"
|
||||
];
|
||||
extraConfig.X-Flatpak = appId;
|
||||
})
|
||||
];
|
||||
}
|
||||
@@ -74,10 +74,9 @@ let
|
||||
mediaCheck =
|
||||
app: expected:
|
||||
if expected then
|
||||
app.bubblewrap.sockets.pulse && app.portalGroups.camera && app.portalGroups.screenCast
|
||||
app.portalGroups.camera && app.portalGroups.screenCast
|
||||
else
|
||||
!app.bubblewrap.sockets.pulse
|
||||
&& !app.bubblewrap.sockets.pipewire
|
||||
!app.bubblewrap.sockets.pipewire
|
||||
&& !app.portalGroups.camera
|
||||
&& !app.portalGroups.screenCast
|
||||
&& !(hasDbusFragment app "org.freedesktop.portal.Camera")
|
||||
@@ -125,6 +124,7 @@ let
|
||||
"${name}/network" = networkCheck app spec.network;
|
||||
"${name}/x11" = app.bubblewrap.sockets.x11 == (spec.x11 or false);
|
||||
"${name}/media" = mediaCheck app (spec.media or false);
|
||||
"${name}/pulse" = app.bubblewrap.sockets.pulse == (spec.pulse or (spec.media or false));
|
||||
"${name}/mpris" = app.desktopIntegration.mpris == (spec.mpris or false);
|
||||
"${name}/notifications" = app.desktopIntegration.notifications == (spec.notifications or true);
|
||||
"${name}/tray" = trayCheck app (spec.tray or false);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
load,
|
||||
mkAppPolicy,
|
||||
...
|
||||
}:
|
||||
let
|
||||
app = load "bambu-studio";
|
||||
in
|
||||
mkAppPolicy "bambu-studio" {
|
||||
network = "pasta";
|
||||
media = false;
|
||||
pulse = true;
|
||||
x11 = true;
|
||||
notifications = true;
|
||||
extraChecks = {
|
||||
gdkX11 = app.bubblewrap.env.GDK_BACKEND == "x11";
|
||||
fileChooser = app.portalGroups.fileChooser;
|
||||
openUri = app.portalGroups.openUri;
|
||||
inputMethod = app.portalGroups.inputMethod;
|
||||
accessibility = app.desktopIntegration.accessibility;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
load,
|
||||
mkAppPolicy,
|
||||
...
|
||||
}:
|
||||
let
|
||||
app = load "orca-slicer";
|
||||
in
|
||||
mkAppPolicy "orca-slicer" {
|
||||
network = "pasta";
|
||||
media = false;
|
||||
x11 = true;
|
||||
notifications = true;
|
||||
extraChecks = {
|
||||
gdkX11 = app.bubblewrap.env.GDK_BACKEND == "x11";
|
||||
webkitDmabuf = app.bubblewrap.env.WEBKIT_DISABLE_DMABUF_RENDERER == "1";
|
||||
fileChooser = app.portalGroups.fileChooser;
|
||||
openUri = app.portalGroups.openUri;
|
||||
inputMethod = app.portalGroups.inputMethod;
|
||||
accessibility = app.desktopIntegration.accessibility;
|
||||
};
|
||||
}
|
||||
@@ -24,6 +24,8 @@ Nixpak wrappers are accepted in three layers:
|
||||
| WeChat (native nixpak) | Pass | Interactive Wayland validation pending |
|
||||
| Foliate | Pass | Interactive validation pending |
|
||||
| Krita | Pass | Interactive validation pending |
|
||||
| Bambu Studio | Pass | Interactive validation pending |
|
||||
| OrcaSlicer | Pass | Interactive validation pending |
|
||||
|
||||
Intentional exceptions:
|
||||
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
{
|
||||
pkgs,
|
||||
pkgs-stable,
|
||||
pkgs-master,
|
||||
pkgs-blender,
|
||||
...
|
||||
}:
|
||||
let
|
||||
bambu-studio = pkgs.symlinkJoin {
|
||||
name = "bambu-studio-${pkgs-master.bambu-studio.version}";
|
||||
paths = [ pkgs-master.bambu-studio ];
|
||||
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
# Work around wxWidgets HiDPI text clipping under fractional scaling.
|
||||
# https://github.com/bambulab/BambuStudio/issues/4959
|
||||
wrapProgram $out/bin/bambu-studio --set GDK_DPI_SCALE 0.8
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
home.packages = with pkgs-stable; [
|
||||
# creative
|
||||
pkgs.nixpaks.krita # digital painting
|
||||
musescore # music notation
|
||||
pkgs-master.orca-slicer # 3d printer slicer app
|
||||
bambu-studio # bambu 3d printer slicer app
|
||||
pkgs.nixpaks.orca-slicer # 3d printer slicer app
|
||||
pkgs.nixpaks.bambu-studio # bambu 3d printer slicer app
|
||||
pkgs-blender.blender # 3d modeling
|
||||
];
|
||||
|
||||
|
||||
Reference in new issue
Block a user