14 Commits
Author SHA1 Message Date
lyrathorpe 955b6640c3 Merge pull request 'fix(darwin): disable hot-corners' (#109) from fix/disable-hot-corners into main
CI / flake (push) Successful in 4m32s
Reviewed-on: #109
2026-08-28 14:51:27 +01:00
lyrathorpe ea791df4aa fix(darwin): disable hot-corners
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m29s
I hate them and I need to ensure they never come back
2026-08-28 14:46:40 +01:00
lyrathorpe a587f0ab71 Merge pull request 'fix(wsl): provide xdg-open so browser-based logins work' (#108) from fix/wsl-xdg-open into main
CI / flake (push) Successful in 4m27s
Reviewed-on: #108
2026-08-28 13:53:39 +01:00
lyrathorpe 93f1b191c8 Merge pull request 'feat(tmux): show window names in the status bar and pane titles on the border' (#107) from feat/tmux-window-and-pane-titles into main
CI / flake (push) Successful in 5m23s
Reviewed-on: #107
2026-08-28 13:49:32 +01:00
Emma Thorpe a51ed76119 fix(wsl): provide xdg-open so browser-based logins work
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m30s
WSL has no xdg-open and no Linux browser, so anything that shells out to one
fails with:

  exec: "xdg-open,x-www-browser,www-browser": executable file not found in $PATH

kubelogin's interactive login hits this, which matters because interactive is
the mode the shared cluster kubeconfig uses and the mode documented for
re-authenticating after a PIM activation.

Ships an xdg-open on PATH that hands the URL to Windows via powershell.exe,
falling back to explorer.exe, and points $BROWSER at it for tools that read the
variable instead of calling xdg-open. wslu would be the conventional answer but
has been removed from nixpkgs after upstream archived the project.
2026-08-28 13:48:52 +01:00
Emma Thorpe 5bca7e176a feat(tmux): show window names in the status bar and pane titles on the border
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 4m9s
Catppuccin renders #T, the pane title, in the window list. Any program in the
pane can overwrite that with an OSC escape -- the shell writes the hostname and
Claude Code writes its current task -- so a window renamed with prefix+, never
appeared anywhere.

The status bar now shows the window name, falling back to the pane title while a
window holds a single pane. Once a window is split, pane titles appear on the
pane borders instead; pane-border-status takes no format, so a
window-layout-changed hook recomputes it on both split and close. Adds a binding
for select-pane -T, which has no default.
2026-08-28 12:22:37 +01:00
lyrathorpe 684d3f5a75 Merge pull request 'docs(memory): record that Entra group member reads hide service principals' (#106) from docs/memory-entra-group-member-reads into main
CI / flake (push) Successful in 4m5s
Reviewed-on: #106
2026-08-28 11:35:21 +01:00
Emma Thorpe 99fca0f746 docs(memory): record that Entra group member reads hide service principals
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 1m3s
az ad group member list and GET /groups/{id}/members return an empty
collection, without error, for groups whose members are service principals.
Records the reads that do work and the rule to trust a Terraform plan over
that output.
2026-08-28 11:33:33 +01:00
lyrathorpe 9b1e2fb447 Merge pull request 'chore(nix): statix bool_comparison + stale-path comment fixes' (#58) from chore/nix-cleanup into main
CI / flake (push) Successful in 5m13s
Reviewed-on: #58
2026-08-26 20:48:37 +01:00
lyrathorpe 9d2379bb3e docs(rpi5): fix stale features.nix path in comment
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 7m19s
2026-08-26 20:41:05 +01:00
lyrathorpe 7a650dc7cc docs(sway): fix stale features.nix path in comment 2026-08-26 20:41:05 +01:00
lyrathorpe bb613ac803 refactor(users): drop redundant == true (statix bool_comparison) 2026-08-26 20:41:05 +01:00
lyrathorpe 47362090c3 Merge pull request 'docs(memory): record the Task Type field now required on WSP tickets' (#105) from docs/memory-jira-task-type into main
CI / flake (push) Successful in 4m8s
Reviewed-on: #105
2026-08-25 14:33:03 +01:00
Emma Thorpe 8c5773447e docs(memory): record the Task Type field now required on WSP tickets
CI / flake (push) Skipped
CI / flake (pull_request) Successful in 57s
Creating a WSP Task now fails with "Task Type is required to create a Task
issue". The field is customfield_15622 and the create validator enforces it
even though createmeta does not list it as required - the same trap the note
already records for Bug's versions field.
2026-08-25 14:25:24 +01:00
9 changed files with 76 additions and 5 deletions
+1
View File
@@ -16,3 +16,4 @@
- [Nix shell tooling](nix_shell_tooling.md) — any nixpkgs tool runs ad hoc via `nix run`/`nix shell nixpkgs#<pkg>`; a missing command is never a dead end
- [WSP local build and test](wsp_local_build_and_test.md) — core-services-cloud on this box: dotnet via nix, artifactory creds from `~/.artifactoryenv` sourced per command, how to tell auth failure from a code failure
- [WSP-32957 PIM migration](wsp_32957_pim_migration.md) — AKS RBAC to PIM + AutoPerm decommission; prod is in the Technical Preview subscription, three tenants; resume via `~/code/WSP-32957-CONTINUATION.md`
- [Entra group member reads](entra_group_member_reads.md) — `az ad group member list` hides service principal members; use the servicePrincipal cast or transitiveMemberOf, and trust the Terraform plan over it
@@ -0,0 +1,28 @@
---
name: entra-group-member-reads
description: az ad group member list and Graph /members silently omit service principal members — use the servicePrincipal cast or transitiveMemberOf when a group is expected to hold an SPN.
metadata:
node_type: memory
type: reference
---
`az ad group member list --group <id>` and `GET /groups/{id}/members` both return an **empty collection**, with no error, for a group whose only members are service principals — at least when called with Lyra's user account. The read looks authoritative and is not.
**Reliable reads instead:**
```sh
# members, cast to the type that is being hidden
az rest --method get --url "https://graph.microsoft.com/v1.0/groups/<gid>/members/microsoft.graph.servicePrincipal?\$select=id,displayName"
# count, which does not filter
az rest --method get --url "https://graph.microsoft.com/v1.0/groups/<gid>/members/\$count" --headers ConsistencyLevel=eventual
# from the principal's side
az rest --method get --url "https://graph.microsoft.com/v1.0/servicePrincipals/<spid>/transitiveMemberOf?\$select=id,displayName"
az rest --method post --url "https://graph.microsoft.com/v1.0/servicePrincipals/<spid>/checkMemberGroups" \
--body '{"groupIds":["<gid>"]}' --headers "Content-Type=application/json"
```
**How to apply:** any group that deployment or automation identities belong to — `*-cluster-admins`, `*-keyvault`, anything created by `rg-prereqs` — must be checked with one of the above before concluding it is empty. Cross-check against Terraform: a plan reporting "No changes" against a `members` attribute is strong evidence the membership is present, and outranks the `az` read. On 2026-08-28 the plain read produced a Bug (WSP-33432, cancelled) claiming five `*-cluster-admins` groups across three tenants had been emptied; all five held their deployment principals the whole time.
Related: [[wsp-32957-pim-migration]].
+3 -1
View File
@@ -9,7 +9,9 @@ Field map for the **WSP (Workspace Platform)** Jira project, to create tickets w
**Issue-type IDs:** Epic `10000`, Story `10004`, Task `10008`, Bug `10123`, Sub-task `10009`.
**Fast path — use Task, not Bug.** A `Task` requires only `summary` (project/issuetype auto, reporter defaults to caller). A `Bug` requires six extra fields (below), so only pick Bug when it must be a Bug. The sibling infra/remediation tickets in WSP are Tasks.
**Fast path — use Task, not Bug.** A `Task` requires `summary` plus **Task Type** `customfield_15622` (added since this note was first written; the create validator enforces it even though `createmeta` omits it, same trap as Bug's `versions`). Options value=id: Dev Task=34065, CQE Task=34066, Investigation=34067, Security=34068, Maintenance=34069, Release=34070 — use `Maintenance` for refactors and tidy-ups, `Dev Task` for feature work. A `Bug` requires six extra fields (below), so only pick Bug when it must be a Bug. The sibling infra/remediation tickets in WSP are Tasks.
Example Task `additional_fields`: `{"customfield_15622":{"id":"34069"},"components":[{"name":"Multicluster Platform"}]}`
**Bug required fields** (enforced by the create validator; note `createmeta` omits `versions` but the API rejects without it):
+19
View File
@@ -313,6 +313,14 @@ in
extraConfig = ''
set -g @catppuccin_flavor 'mocha'
set -g @catppuccin_window_status_style 'rounded'
# Catppuccin's default window text is #T, the pane title, which every
# program in the pane is free to overwrite -- the shell writes the
# hostname, Claude Code writes its current task, and a hand-set window
# name never appears. Show the window name instead, falling back to the
# pane title when the window holds a single pane and the two carry the
# same information anyway.
set -g @catppuccin_window_text ' #{?#{==:#{window_panes},1},#T,#W}'
set -g @catppuccin_window_current_text ' #{?#{==:#{window_panes},1},#T,#W}'
'';
}
resurrect # save/restore sessions
@@ -357,6 +365,17 @@ in
set -g renumber-windows on
set -g set-clipboard on
# Pane titles on the border, but only once a window is split -- a single
# pane's title is already in the status bar. pane-border-status takes no
# format, so the hook recomputes it whenever the layout changes, which
# covers both splitting and closing a pane.
set -g pane-border-format " #P #{pane_title} "
set -g pane-border-status off
set-hook -g window-layout-changed 'set -Fw pane-border-status "#{?#{>:#{window_panes},1},top,off}"'
# Pane titles have no default binding.
bind T command-prompt -p "pane title:" "select-pane -T '%%'"
# Catppuccin v2 statusline. Must run after the plugin has loaded;
# home-manager appends this extraConfig after the whole plugin list.
set -g status-left-length 100
+5
View File
@@ -161,6 +161,11 @@
dock = {
show-recents = false;
mru-spaces = false; # don't reorder spaces by use
# Disable hot-corners
wvous-tr-corner = 1;
wvous-tl-corner = 1;
wvous-bl-corner = 1;
wvous-br-corner = 1;
};
finder = {
AppleShowAllExtensions = true;
+1 -1
View File
@@ -17,7 +17,7 @@
# Headless server: the Sway desktop is intentionally not set up. modules/sway.nix is
# not imported and features.swayDesktop.enable defaults to false (declared in
# system/modules/features.nix), so this host keeps plain TTY/SSH login.
# modules/features.nix), so this host keeps plain TTY/SSH login.
# Raspberry Pi boots via U-Boot + extlinux, not GRUB/systemd-boot. The
# raspberry-pi-5 nixos-hardware profile supplies the kernel, firmware and
+1 -1
View File
@@ -12,7 +12,7 @@ let
in
{
# The features.swayDesktop.enable option is declared in
# system/modules/features.nix (so headless hosts can read/set it without
# modules/features.nix (so headless hosts can read/set it without
# importing this module). This module only provides its implementation.
config = lib.mkIf cfg.enable {
programs.sway = {
+2 -2
View File
@@ -29,10 +29,10 @@
// lib.optionalAttrs (spec ? linger) { inherit (spec) linger; }
) hostUsers;
programs.firefox = lib.mkIf (config.features.swayDesktop.enable == true) {
programs.firefox = lib.mkIf config.features.swayDesktop.enable {
enable = true;
};
programs.thunderbird = lib.mkIf (config.features.swayDesktop.enable == true) {
programs.thunderbird = lib.mkIf config.features.swayDesktop.enable {
enable = true;
};
}
+16
View File
@@ -47,7 +47,23 @@
pkgs.terraform-docs # generate Terraform module docs
pkgs.yq-go # jq for YAML
pkgs.gcx # Grafana Cloud CLI (dashboards, SLOs, synthetics, alerts)
# WSL ships no xdg-open, so anything that shells out to a browser dies with
# `exec: "xdg-open,x-www-browser,www-browser": executable file not found`.
# kubelogin's interactive login is the one that bites: it is the login mode
# the shared cluster kubeconfig uses. Hand the URL to Windows instead.
# (wslu, the usual answer, is gone from nixpkgs -- upstream archived it.)
(pkgs.writeShellScriptBin "xdg-open" ''
url="$1"
if command -v powershell.exe >/dev/null 2>&1; then
exec powershell.exe -NoProfile -Command "Start-Process '$url'"
fi
exec explorer.exe "$url"
'')
];
# Honoured by tools that read $BROWSER rather than calling xdg-open.
home.sessionVariables.BROWSER = "xdg-open";
services.ssh-agent.enable = true;
# Colourised kubectl. enableAlias points `kubectl` at kubecolor, which parses