summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorsommerfeld <sommerfeld@sommerfeld.dev>2026-09-26 22:23:04 +0100
committersommerfeld <sommerfeld@sommerfeld.dev>2026-09-26 22:23:04 +0100
commitdeb462188fc2adc168c782fca51fae746a299cca (patch)
treefd5a99dfd7647dace178040eb23d77e084309543
parent1f79a073474b41263f50c3c0b35dc17b5cdddcf7 (diff)
downloaddotfiles-deb462188fc2adc168c782fca51fae746a299cca.tar.gz
dotfiles-deb462188fc2adc168c782fca51fae746a299cca.tar.bz2
dotfiles-deb462188fc2adc168c782fca51fae746a299cca.zip
Declare official Keybase APT setup for Canonical
-rw-r--r--.chezmoiignore1
-rw-r--r--docs/canonical-laptop.md14
-rw-r--r--dot_config/autostart/keybase.desktop5
-rw-r--r--meta/canonical/apt.txt1
-rw-r--r--scripts/canonical.py35
-rw-r--r--tests/test_canonical.py29
6 files changed, 82 insertions, 3 deletions
diff --git a/.chezmoiignore b/.chezmoiignore
index c054bca..a3bbf94 100644
--- a/.chezmoiignore
+++ b/.chezmoiignore
@@ -100,6 +100,7 @@ canonical-desktop.sh
canonical-nvim-lock.sh
.config/nix/nix.conf
.config/autostart/dotfiles-*.desktop
+.config/autostart/keybase.desktop
.config/systemd/user/gpg-agent.service.d/canonical.conf
.local/lib/dotfiles/
.local/share/gnome-shell/extensions/corporate-panel@dotfiles/
diff --git a/docs/canonical-laptop.md b/docs/canonical-laptop.md
index 733e3ba..ef988e1 100644
--- a/docs/canonical-laptop.md
+++ b/docs/canonical-laptop.md
@@ -177,6 +177,20 @@ without using its cached output. Bootstrap does not need a manual crate prefetch
compositors; it cannot inject keys into GNOME without virtual-keyboard protocol
support.
+## Keybase
+
+Keybase uses its [official APT installation](https://keybase.io/docs/the_app/install_linux).
+It is declared in `meta/canonical/apt.txt`. When it is absent, package setup
+downloads the official amd64 DEB over HTTPS and installs it with apt. That
+package adds Keybase's update repository. An existing installation is retained
+without downloading the bootstrap package again. Normal APT upgrades update it.
+
+The managed `~/.config/autostart/keybase.desktop` uses `/usr/bin/run_keybase -a`
+to start the service and GUI in the tray at GNOME login. It uses the same
+autostart filename as Keybase, so it does not add a second launcher. Open
+`run_keybase` once to sign in. Test the tray icon and a notification from
+another account. No Keybase Snap or Nix service is installed on this role.
+
## Work Keys and Containers
Transfer and import only the existing **work** secret key through a protected
diff --git a/dot_config/autostart/keybase.desktop b/dot_config/autostart/keybase.desktop
new file mode 100644
index 0000000..c5ef2db
--- /dev/null
+++ b/dot_config/autostart/keybase.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Type=Application
+Name=Keybase
+Exec=/usr/bin/run_keybase -a
+OnlyShowIn=GNOME;
diff --git a/meta/canonical/apt.txt b/meta/canonical/apt.txt
index 909470f..25c7551 100644
--- a/meta/canonical/apt.txt
+++ b/meta/canonical/apt.txt
@@ -10,3 +10,4 @@ python3-gi
imv
gnome-shell-ubuntu-extensions
network-manager-openvpn-gnome
+keybase
diff --git a/scripts/canonical.py b/scripts/canonical.py
index 35bfdcb..a4e0b5d 100644
--- a/scripts/canonical.py
+++ b/scripts/canonical.py
@@ -5,6 +5,7 @@ import json
import os
import platform
import subprocess
+import tempfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
@@ -74,6 +75,8 @@ def require_canonical() -> None:
def install() -> None:
subprocess.run(["sudo", "apt-get", "update"], check=True)
+ if "keybase" in packages("apt"):
+ install_keybase()
subprocess.run(["sudo", "apt-get", "install", *packages("apt")], check=True)
for command in snap_install_commands():
if subprocess.run(
@@ -87,6 +90,38 @@ def install() -> None:
subprocess.run(command, check=True)
+def install_keybase() -> None:
+ status = subprocess.run(
+ ["dpkg-query", "-W", "-f=${Status}", "keybase"],
+ check=False,
+ capture_output=True,
+ text=True,
+ )
+ if status.returncode == 0 and status.stdout == "install ok installed":
+ return
+ if platform.machine() != "x86_64":
+ raise SystemExit("The Keybase bootstrap package requires amd64.")
+ with tempfile.TemporaryDirectory(prefix="keybase-") as directory:
+ Path(directory).chmod(0o755)
+ package = str(Path(directory) / "keybase_amd64.deb")
+ subprocess.run(
+ [
+ "curl",
+ "--fail",
+ "--location",
+ "--proto",
+ "=https",
+ "--proto-redir",
+ "=https",
+ "--output",
+ package,
+ "https://prerelease.keybase.io/keybase_amd64.deb",
+ ],
+ check=True,
+ )
+ subprocess.run(["sudo", "apt-get", "install", package], check=True)
+
+
def require_lab() -> None:
marker = Path("/etc/canonical-lab")
if not marker.is_file() or marker.stat().st_uid != 0:
diff --git a/tests/test_canonical.py b/tests/test_canonical.py
index 4097b3c..1a9be82 100644
--- a/tests/test_canonical.py
+++ b/tests/test_canonical.py
@@ -39,11 +39,34 @@ class PackageTests(unittest.TestCase):
canonical.install()
self.assertFalse(any("set" in call.args[0] for call in command.call_args_list))
- def test_keybase_is_not_installed_or_autostarted(self):
+ def test_keybase_is_installed_and_autostarted_through_apt(self):
+ self.assertIn("keybase", canonical.packages("apt"))
self.assertNotIn("keybase", canonical.packages("snap"))
- self.assertFalse(
- (ROOT / "dot_config/autostart/dotfiles-keybase.desktop").exists()
+ entry = (ROOT / "dot_config/autostart/keybase.desktop").read_text()
+ self.assertIn("Exec=/usr/bin/run_keybase -a", entry)
+ self.assertIn("OnlyShowIn=GNOME;", entry)
+
+ def test_installed_keybase_is_not_bootstrapped_again(self):
+ with patch.object(canonical.subprocess, "run") as run:
+ run.return_value = subprocess.CompletedProcess(
+ [], 0, "install ok installed"
+ )
+ canonical.install_keybase()
+ self.assertEqual(run.call_count, 1)
+
+ def test_missing_keybase_uses_official_bootstrap_package(self):
+ with (
+ patch.object(canonical.platform, "machine", return_value="x86_64"),
+ patch.object(canonical.subprocess, "run") as run,
+ ):
+ run.return_value = subprocess.CompletedProcess([], 1, "")
+ canonical.install_keybase()
+ commands = [call.args[0] for call in run.call_args_list]
+ self.assertEqual(
+ commands[1][-1], "https://prerelease.keybase.io/keybase_amd64.deb"
)
+ self.assertEqual(commands[2][:3], ["sudo", "apt-get", "install"])
+ self.assertTrue(commands[2][-1].endswith("/keybase_amd64.deb"))
def test_extensions_install_without_shell_confirmation(self):
with (