Compare commits
12
Commits
47362090c3
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
955b6640c3 | ||
|
|
ea791df4aa | ||
|
|
a587f0ab71 | ||
|
|
93f1b191c8 | ||
|
|
a51ed76119 | ||
|
|
5bca7e176a | ||
|
|
684d3f5a75 | ||
|
|
99fca0f746 | ||
|
|
9b1e2fb447 | ||
|
|
9d2379bb3e | ||
|
|
7a650dc7cc | ||
|
|
bb613ac803 |
@@ -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]].
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user