From 19e8b910eb74b41f762324ba1cbda5c5314787be Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Fri, 28 Nov 2025 06:18:29 +0100 Subject: [PATCH 01/11] docs: wsl_install - help update --- wsl/wsl_install.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsl/wsl_install.ps1 b/wsl/wsl_install.ps1 index ea14684..f293b3a 100644 --- a/wsl/wsl_install.ps1 +++ b/wsl/wsl_install.ps1 @@ -24,7 +24,7 @@ List of installation scopes. Valid values: - k8s_ext: (WSL2 only) - minikube, k3d, argorollouts-cli; autoselects docker and k8s_base scopes - nodejs: Node.js JavaScript runtime environment - pwsh: PowerShell Core and corresponding PS modules; autoselects shell scope -- python: uv, pip, venv +- python: uv, prek, pip, venv - rice: btop, cmatrix, cowsay, fastfetch - shell: bat, eza, oh-my-posh, ripgrep, yq - terraform: terraform, terrascan, tfswitch From ee48d2068ade04857aff7f1227417190cc8dab0b Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Fri, 28 Nov 2025 06:21:16 +0100 Subject: [PATCH 02/11] refactor(ps): wsl_setup - ssh key added confirmation --- wsl/wsl_setup.ps1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index 376d284..b744e7c 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -401,16 +401,15 @@ process { try { $sshStatus = wsl.exe --distribution $Distro --exec .assets/provision/setup_gh_ssh.sh | ConvertFrom-Json -AsHashtable -ErrorAction Stop if ($sshStatus.sshKey -eq 'added') { + Clear-Host # display message asking to authorize the SSH key $msg = [string]::Join("`n", "`e[97;1mSSH key added to GitHub:`e[0;90m $($sshStatus.title)`e[0m`n", "`e[97mTo finish setting up SSH authentication, open `e[34;4mhttps://github.com/settings/ssh`e[97;24m", "and authorize the newly added key for your organization (enable SSO if required).`e[0m", - "`npress any key to continue..." + "`npress Enter key to continue" ) - Write-Host $msg - # wait for user input to continue - [System.Console]::ReadKey() | Out-Null + Read-Host $msg } } catch { $sshStatus.sshKey = 'missing' From 7fdb240b3edf48d9b7f136ae3c450306ccbede6b Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Fri, 28 Nov 2025 06:22:57 +0100 Subject: [PATCH 03/11] docs: mentioned azcopy in az scope --- wsl/wsl_install.ps1 | 2 +- wsl/wsl_setup.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wsl/wsl_install.ps1 b/wsl/wsl_install.ps1 index f293b3a..b460518 100644 --- a/wsl/wsl_install.ps1 +++ b/wsl/wsl_install.ps1 @@ -16,7 +16,7 @@ The script will perform the following: Name of the WSL distro to install and set up. .PARAMETER Scope List of installation scopes. Valid values: -- az: azure-cli, Az PowerShell module if pwsh scope specified; autoselects python scope +- az: azure-cli, azcopy, Az PowerShell module if pwsh scope specified; autoselects python scope - conda: miniforge - distrobox: (WSL2 only) - podman and distrobox - docker: (WSL2 only) - docker, containerd buildx docker-compose diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index b744e7c..38a2b98 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -18,7 +18,7 @@ When GH repositories cloning is used, you need to generate and add an SSH key to Name of the WSL distro to set up. If not specified, script will update all existing distros. .PARAMETER Scope List of installation scopes. Valid values: -- az: azure-cli, Az PowerShell module if pwsh scope specified; autoselects python scope +- az: azure-cli, azcopy, Az PowerShell module if pwsh scope specified; autoselects python scope - conda: miniforge - distrobox: (WSL2 only) - podman and distrobox - docker: (WSL2 only) - docker, containerd buildx docker-compose From 7b27af0802ad6001fb92fe85d9bb42463d044b37 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Fri, 28 Nov 2025 06:30:58 +0100 Subject: [PATCH 04/11] feat: gremlins pre-commit hook --- .gitignore | 5 +++ .pre-commit-config.yaml | 7 ++++ tests/hooks/gremlins.py | 89 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 tests/hooks/gremlins.py diff --git a/.gitignore b/.gitignore index 596417f..ced3847 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,11 @@ /console/ /tmp.*/ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + # vagrant **/.vagrant/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f05b403..f2fcb33 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,4 +1,11 @@ repos: + - repo: local + hooks: + - id: gremlins-check + name: Detect gremlins / unwanted Unicode characters + entry: python3 -m tests.hooks.gremlins + language: system + types: [text] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: diff --git a/tests/hooks/gremlins.py b/tests/hooks/gremlins.py new file mode 100644 index 0000000..4cc5f5e --- /dev/null +++ b/tests/hooks/gremlins.py @@ -0,0 +1,89 @@ +""" +Scan staged text files for unwanted Unicode characters and fail if found. + +# :example +python3 -m tests.gremlins wsl/wsl_setup.ps1 +""" + +import os +import sys +import unicodedata +from typing import Iterable, List, Tuple + +FORBIDDEN_CHARS: Tuple[str, ...] = ( + # Zero-width / joiner + "\u200b", # U+200B ZERO WIDTH SPACE + "\u200c", # U+200C ZERO WIDTH NON-JOINER + "\u200d", # U+200D ZERO WIDTH JOINER + # Spaces / breaks + "\u00a0", # U+00A0 NO-BREAK SPACE + "\u202f", # U+202F NARROW NO-BREAK SPACE + "\u2009", # U+2009 THIN SPACE + "\u200a", # U+200A HAIR SPACE + # Control / formatting + "\u000c", # U+000C FORM FEED + "\u00ad", # U+00AD SOFT HYPHEN + # Dashes / hyphens + "\u2013", # U+2013 EN DASH + "\u2014", # U+2014 EM DASH + "\u2010", # U+2010 HYPHEN + # Quotes / punctuation that look like ASCII + "\u2018", # U+2018 LEFT SINGLE QUOTATION MARK + "\u2019", # U+2019 RIGHT SINGLE QUOTATION MARK + "\u201c", # U+201C LEFT DOUBLE QUOTATION MARK + "\u201d", # U+201D RIGHT DOUBLE QUOTATION MARK + "\u2026", # U+2026 HORIZONTAL ELLIPSIS +) + + +def find_forbidden_in_text(content: str, filename: str) -> List[str]: + """Return list of human readable reports for forbidden characters in content.""" + reports: List[str] = [] + for lineno, line in enumerate(content.splitlines(), start=1): + for ch in FORBIDDEN_CHARS: + if ch in line: + code = f"U+{ord(ch):04X}" + try: + name = unicodedata.name(ch) + except ValueError: + name = "" + reports.append(f"{filename}:{lineno}: contains {name} ({code})") + return reports + + +def is_text_file(path: str) -> bool: + """Quick heuristic to skip binary files.""" + try: + with open(path, "rb") as fh: + chunk = fh.read(4096) + # if NUL bytes present it's likely binary + return b"\x00" not in chunk + except OSError: + return False + + +def check_gremlins(argv: Iterable[str]) -> int: + """Entry point: argv should be list of filenames to check.""" + files = list(argv) + problems: List[str] = [] + for path in files: + if not os.path.exists(path) or not is_text_file(path): + continue + try: + with open(path, "r", encoding="utf-8", errors="replace") as fh: + content = fh.read() + except OSError: + continue + problems.extend(find_forbidden_in_text(content, path)) + + if problems: + print("Gremlin characters found:", file=sys.stderr) + for p in problems: + print(p, file=sys.stderr) + print("Remove or replace gremlin characters", file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(check_gremlins(sys.argv[1:])) From ca2a79dae6744a1805e8f20a3d71c538ff825654 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Fri, 28 Nov 2025 07:10:46 +0100 Subject: [PATCH 05/11] refactor: added k8s_dev scope --- .assets/provision/distro_check.sh | 1 + .assets/provision/install_flux.sh | 1 + .assets/provision/install_kustomize.sh | 1 + .assets/scripts/linux_setup.sh | 12 ++++--- wsl/wsl_install.ps1 | 7 ++-- wsl/wsl_setup.ps1 | 47 +++++++++++++++----------- 6 files changed, 42 insertions(+), 27 deletions(-) diff --git a/.assets/provision/distro_check.sh b/.assets/provision/distro_check.sh index 463cc87..1dde20d 100755 --- a/.assets/provision/distro_check.sh +++ b/.assets/provision/distro_check.sh @@ -15,6 +15,7 @@ declare -A state=( ["git_email"]=$([ -n "$(git config --global --get user.email 2>/dev/null)" ] && echo "true" || echo "false") ["gtkd"]=$(grep -Fqw "dark" /etc/profile.d/gtk_theme.sh 2>/dev/null && echo "true" || echo "false") ["k8s_base"]=$([ -f /usr/bin/kubectl ] && echo "true" || echo "false") + ["k8s_dev"]=$([ -f /usr/local/bin/helm ] && echo "true" || echo "false") ["k8s_ext"]=$([ -f /usr/local/bin/k3d ] && echo "true" || echo "false") ["oh_my_posh"]=$([ -f /usr/bin/oh-my-posh ] && echo "true" || echo "false") ["python"]=$([ -f $HOME/.local/bin/uv ] && echo "true" || echo "false") diff --git a/.assets/provision/install_flux.sh b/.assets/provision/install_flux.sh index d8eaf8b..39697f9 100755 --- a/.assets/provision/install_flux.sh +++ b/.assets/provision/install_flux.sh @@ -32,6 +32,7 @@ if type $APP &>/dev/null; then fi fi +printf "\e[92minstalling \e[1m$APP\e[22m v$REL\e[0m\n" >&2 __install="curl -sk https://fluxcd.io/install.sh | bash" if type $APP &>/dev/null; then eval $__install diff --git a/.assets/provision/install_kustomize.sh b/.assets/provision/install_kustomize.sh index a25231a..e71ed19 100755 --- a/.assets/provision/install_kustomize.sh +++ b/.assets/provision/install_kustomize.sh @@ -32,6 +32,7 @@ if type $APP &>/dev/null; then fi fi +printf "\e[92minstalling \e[1m$APP\e[22m v$REL\e[0m\n" >&2 # create temporary dir for the downloaded binary TMP_DIR=$(mktemp -dp "$HOME") # calculate download uri diff --git a/.assets/scripts/linux_setup.sh b/.assets/scripts/linux_setup.sh index 6e85daf..7923984 100755 --- a/.assets/scripts/linux_setup.sh +++ b/.assets/scripts/linux_setup.sh @@ -55,7 +55,7 @@ while IFS= read -r line; do done <<<"$distro_check" # add corresponding scopes grep -qw 'az' <<<${array[@]} && array+=(python) || true -grep -qw 'k8s_ext' <<<${array[@]} && array+=(docker) && array+=(k8s_base) || true +grep -qw 'k8s_ext' <<<${array[@]} && array+=(docker) && array+=(k8s_base) && array+=(k8s_dev) || true grep -qw 'pwsh' <<<${array[@]} && array+=(shell) || true grep -qw 'zsh' <<<${array[@]} && array+=(shell) || true # add oh_my_posh scope if necessary @@ -67,6 +67,7 @@ fi order=( docker k8s_base + k8s_dev k8s_ext python conda @@ -149,19 +150,22 @@ for sc in ${scope_arr[@]}; do printf "\e[96minstalling kubernetes base packages...\e[0m\n" sudo .assets/provision/install_kubectl.sh >/dev/null sudo .assets/provision/install_kubelogin.sh >/dev/null - sudo .assets/provision/install_cilium.sh >/dev/null - sudo .assets/provision/install_helm.sh >/dev/null sudo .assets/provision/install_k9s.sh >/dev/null sudo .assets/provision/install_kubecolor.sh >/dev/null sudo .assets/provision/install_kubectx.sh >/dev/null + ;; + k8s_dev) + printf "\e[96minstalling kubernetes base packages...\e[0m\n" + sudo .assets/provision/install_argorolloutscli.sh >/dev/null + sudo .assets/provision/install_cilium.sh >/dev/null sudo .assets/provision/install_flux.sh + sudo .assets/provision/install_helm.sh >/dev/null sudo .assets/provision/install_kustomize.sh ;; k8s_ext) printf "\e[96minstalling kubernetes additional packages...\e[0m\n" sudo .assets/provision/install_minikube.sh >/dev/null sudo .assets/provision/install_k3d.sh >/dev/null - sudo .assets/provision/install_argorolloutscli.sh >/dev/null ;; nodejs) printf "\e[96minstalling Node.js...\e[0m\n" diff --git a/wsl/wsl_install.ps1 b/wsl/wsl_install.ps1 index b460518..5e6c0ce 100644 --- a/wsl/wsl_install.ps1 +++ b/wsl/wsl_install.ps1 @@ -20,8 +20,9 @@ List of installation scopes. Valid values: - conda: miniforge - distrobox: (WSL2 only) - podman and distrobox - docker: (WSL2 only) - docker, containerd buildx docker-compose -- k8s_base: kubectl, kubelogin, cilium-cli, helm, k9s, flux, kustomize, kubecolor, kubectx, kubens -- k8s_ext: (WSL2 only) - minikube, k3d, argorollouts-cli; autoselects docker and k8s_base scopes +- k8s_base: kubectl, kubelogin, k9s, kubecolor, kubectx, kubens +- k8s_dev: argorollouts, cilium, helm, flux, kustomize cli tools +- k8s_ext: (WSL2 only) - minikube, k3d; autoselects docker, k8s_base and k8s_dev scopes - nodejs: Node.js JavaScript runtime environment - pwsh: PowerShell Core and corresponding PS modules; autoselects shell scope - python: uv, prek, pip, venv @@ -68,7 +69,7 @@ param ( [Parameter(Mandatory, Position = 0)] [string]$Distro, - [ValidateScript({ $_.ForEach({ $_ -in @('az', 'conda', 'distrobox', 'docker', 'k8s_base', 'k8s_ext', 'nodejs', 'oh_my_posh', 'pwsh', 'rice', 'shell', 'terraform', 'zsh') }) -notcontains $false })] + [ValidateScript({ $_.ForEach({ $_ -in @('az', 'conda', 'distrobox', 'docker', 'k8s_base', 'k8s_dev', 'k8s_ext', 'nodejs', 'oh_my_posh', 'pwsh', 'rice', 'shell', 'terraform', 'zsh') }) -notcontains $false })] [string[]]$Scope, [ValidateScript({ $_.ForEach({ $_ -match '^[\w-]+/[\w-]+$' }) -notcontains $false })] diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index 38a2b98..02bb71f 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -22,8 +22,9 @@ List of installation scopes. Valid values: - conda: miniforge - distrobox: (WSL2 only) - podman and distrobox - docker: (WSL2 only) - docker, containerd buildx docker-compose -- k8s_base: kubectl, kubelogin, cilium-cli, helm, k9s, flux, kustomize, kubecolor, kubectx, kubens -- k8s_ext: (WSL2 only) - minikube, k3d, argorollouts-cli; autoselects docker and k8s_base scopes +- k8s_base: kubectl, kubelogin, k9s, kubecolor, kubectx, kubens +- k8s_dev: argorollouts, cilium, helm, flux, kustomize cli tools +- k8s_ext: (WSL2 only) - minikube, k3d; autoselects docker, k8s_base and k8s_dev scopes - nodejs: Node.js JavaScript runtime environment - pwsh: PowerShell Core and corresponding PS modules; autoselects shell scope - python: uv, prek, pip, venv @@ -91,7 +92,7 @@ param ( [Alias('s')] [Parameter(ParameterSetName = 'Setup')] [Parameter(ParameterSetName = 'GitHub')] - [ValidateScript({ $_.ForEach({ $_ -in @('az', 'conda', 'distrobox', 'docker', 'k8s_base', 'k8s_ext', 'nodejs', 'oh_my_posh', 'pwsh', 'python', 'rice', 'shell', 'terraform', 'zsh') }) -notcontains $false }, + [ValidateScript({ $_.ForEach({ $_ -in @('az', 'conda', 'distrobox', 'docker', 'k8s_base', 'k8s_dev', 'k8s_ext', 'nodejs', 'oh_my_posh', 'pwsh', 'python', 'rice', 'shell', 'terraform', 'zsh') }) -notcontains $false }, ErrorMessage = 'Wrong scope provided. Valid values: az conda distrobox docker k8s_base k8s_ext pwsh python rice shell terraform zsh')] [string[]]$Scope, @@ -266,6 +267,7 @@ process { { $_.az } { $scopeSet.Add('az') | Out-Null } { $_.conda } { $scopeSet.Add('conda') | Out-Null } { $_.k8s_base } { $scopeSet.Add('k8s_base') | Out-Null } + { $_.k8s_dev } { $scopeSet.Add('k8s_dev') | Out-Null } { $_.k8s_ext } { $scopeSet.Add('k8s_ext') | Out-Null } { $_.pwsh } { $scopeSet.Add('pwsh') | Out-Null } { $_.python } { $scopeSet.Add('python') | Out-Null } @@ -275,7 +277,7 @@ process { # add corresponding scopes switch (@($scopeSet)) { az { $scopeSet.Add('python') | Out-Null } - k8s_ext { @('docker', 'k8s_base').ForEach({ $scopeSet.Add($_) | Out-Null }) } + k8s_ext { @('docker', 'k8s_base', 'k8s_dev').ForEach({ $scopeSet.Add($_) | Out-Null }) } pwsh { $scopeSet.Add('shell') | Out-Null } zsh { $scopeSet.Add('shell') | Out-Null } } @@ -296,19 +298,20 @@ process { switch ($_) { 'docker' { 1 } 'k8s_base' { 2 } - 'k8s_ext' { 3 } - 'python' { 4 } - 'conda' { 5 } - 'az' { 6 } - 'nodejs' { 7 } - 'terraform' { 8 } - 'oh_my_posh' { 9 } - 'shell' { 10 } - 'zsh' { 11 } - 'pwsh' { 12 } - 'distrobox' { 13 } - 'rice' { 14 } - default { 15 } + 'k8s_dev' { 3 } + 'k8s_ext' { 4 } + 'python' { 5 } + 'conda' { 6 } + 'az' { 7 } + 'nodejs' { 8 } + 'terraform' { 9 } + 'oh_my_posh' { 10 } + 'shell' { 11 } + 'zsh' { 12 } + 'pwsh' { 13 } + 'distrobox' { 14 } + 'rice' { 15 } + default { 16 } } } # display distro name and installed scopes @@ -450,12 +453,17 @@ process { Write-Host 'installing kubernetes base packages...' -ForegroundColor Cyan $rel_kubectl = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_kubectl.sh $Script:rel_kubectl && $($chk.k8s_base = $true) $rel_kubelogin = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_kubelogin.sh $Script:rel_kubelogin - $rel_cilium = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_cilium.sh $Script:rel_cilium - $rel_helm = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_helm.sh $Script:rel_helm $rel_k9s = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_k9s.sh $Script:rel_k9s $rel_kubecolor = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_kubecolor.sh $Script:rel_kubecolor $rel_kubectx = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_kubectx.sh $Script:rel_kubectx + continue + } + k8s_dev { + Write-Host 'installing kubernetes dev packages...' -ForegroundColor Cyan + $rel_argoroll = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_argorolloutscli.sh $Script:rel_argoroll + $rel_cilium = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_cilium.sh $Script:rel_cilium $rel_flux = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_flux.sh $Script:rel_flux + $rel_helm = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_helm.sh $Script:rel_helm $rel_kustomize = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_kustomize.sh $Script:rel_kustomize continue } @@ -463,7 +471,6 @@ process { Write-Host 'installing kubernetes additional packages...' -ForegroundColor Cyan $rel_minikube = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_minikube.sh $Script:rel_minikube $rel_k3d = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_k3d.sh $Script:rel_k3d - $rel_argoroll = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_argorolloutscli.sh $Script:rel_argoroll continue } nodejs { From a9d39615ee0e85c132c5c28d7d82df5f5c0004b7 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Fri, 28 Nov 2025 07:41:30 +0100 Subject: [PATCH 06/11] refactor(sh): install_gh Improved keyring upudate reliability --- .assets/provision/install_gh.sh | 42 +++++++++------------------------ 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/.assets/provision/install_gh.sh b/.assets/provision/install_gh.sh index 6e14008..89c83d9 100755 --- a/.assets/provision/install_gh.sh +++ b/.assets/provision/install_gh.sh @@ -7,10 +7,12 @@ if [ $EUID -ne 0 ]; then exit 1 fi +# dotsource file with common functions +. .assets/provision/source.sh + # determine system id SYS_ID="$(sed -En '/^ID.*(alpine|arch|fedora|debian|ubuntu|opensuse).*/{s//\1/;p;q}' /etc/os-release)" # check if package installed already using package manager -APP='gh' case $SYS_ID in alpine) apk -e info github-cli &>/dev/null && exit 0 || true @@ -19,42 +21,20 @@ arch) pacman -Qqe github-cli &>/dev/null && exit 0 || true ;; fedora | opensuse) - rpm -q $APP &>/dev/null && exit 0 || true + rpm -q gh &>/dev/null && exit 0 || true ;; debian | ubuntu) export DEBIAN_FRONTEND=noninteractive - curl -fsSLk https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null - chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" >/etc/apt/sources.list.d/github-cli.list - dpkg -s $APP &>/dev/null && exit 0 || true + mkdir -p -m 755 /etc/apt/keyrings + if download_file --uri "https://cli.github.com/packages/githubcli-archive-keyring.gpg" --target_dir "/etc/apt/keyrings"; then + chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" >/etc/apt/sources.list.d/github-cli.list + fi + dpkg -s gh &>/dev/null && exit 0 || true ;; esac -# dotsource file with common functions -. .assets/provision/source.sh - -# define variables -REL=$1 -# get latest release if not provided as a parameter -if [ -z "$REL" ]; then - REL="$(get_gh_release_latest --owner 'cli' --repo 'cli')" - if [ -z "$REL" ]; then - printf "\e[31mFailed to get the latest version of $APP.\e[0m\n" >&2 - exit 1 - fi -fi -# return the release -echo $REL - -if type $APP &>/dev/null; then - VER=$(gh --version | sed -En 's/.*\s([0-9\.]+)\s.*/\1/p') - if [ "$REL" = "$VER" ]; then - printf "\e[32m$APP v$VER is already latest\e[0m\n" >&2 - exit 0 - fi -fi - -printf "\e[92minstalling \e[1m$APP\e[22m v$REL\e[0m\n" >&2 +printf "\e[92minstalling \e[1mgithub-cli\e[0m\n" >&2 case $SYS_ID in alpine) apk add --no-cache github-cli >&2 2>/dev/null From 13e19839f74296f791bdc14fa6e7245bbf3ac1ae Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Mon, 1 Dec 2025 10:51:56 +0100 Subject: [PATCH 07/11] refactor(ps): wsl_setup Skip setup for the root WSL user. --- wsl/wsl_setup.ps1 | 51 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index 02bb71f..70d3217 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -236,6 +236,10 @@ begin { # script variable that determines if public SSH key has been added to GitHub $script:sshStatus = @{ 'sshKey' = 'missing' } + + # sets to track success and failed distros + $successDistros = [System.Collections.Generic.SortedSet[string]]::new() + $failDistros = [System.Collections.Generic.SortedSet[string]]::new() } process { @@ -253,11 +257,23 @@ process { Write-Host 'If the problem persists, run the wsl/wsl_restart.ps1 script as administrator and try again.' exit 1 } - if ($chk.def_uid -ne $chk.uid) { - Write-Host "`nSetting up user profile in WSL distro. Type 'exit' when finished to proceed with WSL setup!`n" -ForegroundColor Yellow - wsl.exe --distribution $Distro - # rerun distro_check to get updated user - $chk = wsl.exe -d $Distro --exec .assets/provision/distro_check.sh | ConvertFrom-Json -AsHashtable + if ($chk.uid -eq 0) { + if ($chk.def_uid -ge 1000) { + Write-Host "`nSetting up user profile in WSL distro. Type 'exit' when finished to proceed with WSL setup!`n" -ForegroundColor Yellow + wsl.exe --distribution $Distro + # rerun distro_check to get updated user + $chk = wsl.exe -d $Distro --exec .assets/provision/distro_check.sh | ConvertFrom-Json -AsHashtable + } else { + $msg = [string]::Join("`n", + "`n`e[93;1mWARNING: The '$Distro' WSL distro is set to use the root user.`e[0m`n", + 'This setup requires the non-root user to be configured as the default one.', + "`e[97;1mRun the script again after creating a non-root user profile.`e[0m" + ) + Write-Host $msg + # mark distro as failed + $failDistros.Add($Distro) | Out-Null + continue + } } $scopeSet = [System.Collections.Generic.HashSet[string]]::new() @@ -649,11 +665,13 @@ process { Write-Host 'configuring git...' -ForegroundColor Cyan wsl.exe --distribution $Distro --exec bash -c $cmnd } - } - #endregion + #endregion + # mark distro as successfully set up + $successDistros.Add($Distro) | Out-Null + } #region clone GitHub repositories - if ($PsCmdlet.ParameterSetName -eq 'GitHub') { + if ($PsCmdlet.ParameterSetName -eq 'GitHub' -and $Distro -notin $failDistros) { Write-Host 'cloning GitHub repositories...' -ForegroundColor Cyan wsl.exe --distribution $Distro --exec .assets/provision/setup_gh_repos.sh --repos "$Repos" } @@ -661,7 +679,22 @@ process { } end { - Write-Host "`n`e[1;95m<< WSL setup completed >>`e[0m`n" + if ($successDistros.Count) { + if ($successDistros.Count) { + Write-Host "`n`e[95m<< Successfully set up the `e[1m$successDistros`e[22m WSL distro >>`e[0m`n" + } else { + Write-Host "`n`e[95m<< Successfully set up the following WSL distros >>`e[0m`n" + $successDistros.ForEach({ Write-Host "`e[1;95m- $_`e[0m" }) + } + } + if ($failDistros.Count) { + if ($failDistros.Count) { + Write-Host "`n`e[91m<< Failed to set up the `e[4m$failDistros`e[24m WSL distro >>`e[0m`n" + } else { + Write-Host "`n`e[91m<< Failed to set up the following WSL distros >>`e[0m`n" + $failDistros.ForEach({ Write-Host "`e[1;91m- $_`e[0m" }) + } + } } clean { From 110c0bb194b12cf0cbb1cea2ef783a0923d6a013 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Wed, 24 Dec 2025 06:51:24 +0100 Subject: [PATCH 08/11] feat(sh): install_kind --- .assets/provision/install_kind.sh | 49 +++++++++++++++++++++++++++++++ .assets/scripts/linux_setup.sh | 5 ++-- wsl/wsl_setup.ps1 | 11 +++---- 3 files changed, 58 insertions(+), 7 deletions(-) create mode 100755 .assets/provision/install_kind.sh diff --git a/.assets/provision/install_kind.sh b/.assets/provision/install_kind.sh new file mode 100755 index 0000000..7863e60 --- /dev/null +++ b/.assets/provision/install_kind.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +: ' +sudo .assets/provision/install_kind.sh >/dev/null +' +if [ $EUID -ne 0 ]; then + printf '\e[31;1mRun the script as root.\e[0m\n' >&2 + exit 1 +fi + +# dotsource file with common functions +. .assets/provision/source.sh + +# define variables +APP='kind' +REL=$1 +OWNER='kubernetes-sigs' +REPO='kind' +# get latest release if not provided as a parameter +if [ -z "$REL" ]; then + REL="$(get_gh_release_latest --owner $OWNER --repo $REPO)" + if [ -z "$REL" ]; then + printf "\e[31mFailed to get the latest version of $APP.\e[0m\n" >&2 + exit 1 + fi +fi +# return the release +echo $REL + +if type $APP &>/dev/null; then + VER=$(kind version | sed -En 's/.*v([0-9\.]+).*/\1/p') + if [ "$REL" = "$VER" ]; then + printf "\e[32m$APP v$VER is already latest\e[0m\n" >&2 + exit 0 + fi +fi + +printf "\e[92minstalling \e[1m$APP\e[22m v$REL\e[0m\n" >&2 +# create temporary dir for the downloaded binary +TMP_DIR=$(mktemp -dp "$HOME") +# calculate download uri +URL="https://github.com/$OWNER/$REPO/releases/download/v${REL}/kind-linux-amd64" +# download and install file +if download_file --uri "$URL" --target_dir "$TMP_DIR"; then + mkdir -p /opt/kind + install -m 0755 "$TMP_DIR/kind-linux-amd64" /opt/kind/kind + [ -f /usr/bin/kind ] || ln -s /opt/kind/kind /usr/bin/kind +fi +# remove temporary dir +rm -fr "$TMP_DIR" diff --git a/.assets/scripts/linux_setup.sh b/.assets/scripts/linux_setup.sh index 7923984..e4c3d06 100755 --- a/.assets/scripts/linux_setup.sh +++ b/.assets/scripts/linux_setup.sh @@ -155,7 +155,7 @@ for sc in ${scope_arr[@]}; do sudo .assets/provision/install_kubectx.sh >/dev/null ;; k8s_dev) - printf "\e[96minstalling kubernetes base packages...\e[0m\n" + printf "\e[96minstalling kubernetes dev packages...\e[0m\n" sudo .assets/provision/install_argorolloutscli.sh >/dev/null sudo .assets/provision/install_cilium.sh >/dev/null sudo .assets/provision/install_flux.sh @@ -163,9 +163,10 @@ for sc in ${scope_arr[@]}; do sudo .assets/provision/install_kustomize.sh ;; k8s_ext) - printf "\e[96minstalling kubernetes additional packages...\e[0m\n" + printf "\e[96minstalling local kubernetes tools...\e[0m\n" sudo .assets/provision/install_minikube.sh >/dev/null sudo .assets/provision/install_k3d.sh >/dev/null + sudo .assets/provision/install_kind.sh >/dev/null ;; nodejs) printf "\e[96minstalling Node.js...\e[0m\n" diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index 70d3217..3ff9d60 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -24,7 +24,7 @@ List of installation scopes. Valid values: - docker: (WSL2 only) - docker, containerd buildx docker-compose - k8s_base: kubectl, kubelogin, k9s, kubecolor, kubectx, kubens - k8s_dev: argorollouts, cilium, helm, flux, kustomize cli tools -- k8s_ext: (WSL2 only) - minikube, k3d; autoselects docker, k8s_base and k8s_dev scopes +- k8s_ext: (WSL2 only) - minikube, k3d, kind local kubernetes tools; autoselects docker, k8s_base and k8s_dev scopes - nodejs: Node.js JavaScript runtime environment - pwsh: PowerShell Core and corresponding PS modules; autoselects shell scope - python: uv, prek, pip, venv @@ -93,7 +93,7 @@ param ( [Parameter(ParameterSetName = 'Setup')] [Parameter(ParameterSetName = 'GitHub')] [ValidateScript({ $_.ForEach({ $_ -in @('az', 'conda', 'distrobox', 'docker', 'k8s_base', 'k8s_dev', 'k8s_ext', 'nodejs', 'oh_my_posh', 'pwsh', 'python', 'rice', 'shell', 'terraform', 'zsh') }) -notcontains $false }, - ErrorMessage = 'Wrong scope provided. Valid values: az conda distrobox docker k8s_base k8s_ext pwsh python rice shell terraform zsh')] + ErrorMessage = 'Wrong scope provided. Valid values: az conda distrobox docker k8s_base k8s_dev k8s_ext nodejs pwsh python rice shell terraform zsh')] [string[]]$Scope, [Parameter(ParameterSetName = 'Update')] @@ -484,9 +484,10 @@ process { continue } k8s_ext { - Write-Host 'installing kubernetes additional packages...' -ForegroundColor Cyan + Write-Host 'installing local kubernetes tools...' -ForegroundColor Cyan $rel_minikube = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_minikube.sh $Script:rel_minikube $rel_k3d = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_k3d.sh $Script:rel_k3d + $rel_kind = wsl.exe --distribution $Distro --user root --exec .assets/provision/install_kind.sh $Script:rel_kind continue } nodejs { @@ -680,7 +681,7 @@ process { end { if ($successDistros.Count) { - if ($successDistros.Count) { + if ($successDistros.Count -eq 1) { Write-Host "`n`e[95m<< Successfully set up the `e[1m$successDistros`e[22m WSL distro >>`e[0m`n" } else { Write-Host "`n`e[95m<< Successfully set up the following WSL distros >>`e[0m`n" @@ -688,7 +689,7 @@ end { } } if ($failDistros.Count) { - if ($failDistros.Count) { + if ($failDistros.Count -eq 1) { Write-Host "`n`e[91m<< Failed to set up the `e[4m$failDistros`e[24m WSL distro >>`e[0m`n" } else { Write-Host "`n`e[91m<< Failed to set up the following WSL distros >>`e[0m`n" From 0115a87fb6c2b198550cec053ebd5cd8436d2305 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Wed, 24 Dec 2025 07:15:50 +0100 Subject: [PATCH 09/11] refactor(sh): install_gh Harden Debian based distros installation. --- .assets/provision/install_gh.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.assets/provision/install_gh.sh b/.assets/provision/install_gh.sh index 89c83d9..13d9934 100755 --- a/.assets/provision/install_gh.sh +++ b/.assets/provision/install_gh.sh @@ -25,11 +25,16 @@ fedora | opensuse) ;; debian | ubuntu) export DEBIAN_FRONTEND=noninteractive - mkdir -p -m 755 /etc/apt/keyrings - if download_file --uri "https://cli.github.com/packages/githubcli-archive-keyring.gpg" --target_dir "/etc/apt/keyrings"; then - chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg + # create temporary dir for the downloaded binary + TMP_DIR=$(mktemp -dp "$HOME") + if download_file --uri "https://cli.github.com/packages/githubcli-archive-keyring.gpg" --target_dir "$TMP_DIR"; then + mkdir -p -m 755 /etc/apt/keyrings + install -m 0644 "$TMP_DIR/githubcli-archive-keyring.gpg" /etc/apt/keyrings echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" >/etc/apt/sources.list.d/github-cli.list fi + # remove temporary dir + rm -fr "$TMP_DIR" + # check if installed already dpkg -s gh &>/dev/null && exit 0 || true ;; esac From 1b0a51d14bd482b9f293e93e1083d24407d9a685 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Wed, 24 Dec 2025 07:16:44 +0100 Subject: [PATCH 10/11] docs(ps): wsl_install: added kind to k8s_ext scope description --- wsl/wsl_install.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsl/wsl_install.ps1 b/wsl/wsl_install.ps1 index 5e6c0ce..d5edb11 100644 --- a/wsl/wsl_install.ps1 +++ b/wsl/wsl_install.ps1 @@ -22,7 +22,7 @@ List of installation scopes. Valid values: - docker: (WSL2 only) - docker, containerd buildx docker-compose - k8s_base: kubectl, kubelogin, k9s, kubecolor, kubectx, kubens - k8s_dev: argorollouts, cilium, helm, flux, kustomize cli tools -- k8s_ext: (WSL2 only) - minikube, k3d; autoselects docker, k8s_base and k8s_dev scopes +- k8s_ext: (WSL2 only) - minikube, k3d, kind local kubernetes tools; autoselects docker, k8s_base and k8s_dev scopes - nodejs: Node.js JavaScript runtime environment - pwsh: PowerShell Core and corresponding PS modules; autoselects shell scope - python: uv, prek, pip, venv From 8af33ec9f082568410499b66bfbe42c621e5d929 Mon Sep 17 00:00:00 2001 From: Szymon Osiecki Date: Wed, 24 Dec 2025 07:17:12 +0100 Subject: [PATCH 11/11] refactor(ps): wsl_setup - update key prompt message --- wsl/wsl_setup.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wsl/wsl_setup.ps1 b/wsl/wsl_setup.ps1 index 3ff9d60..7d1f9b6 100644 --- a/wsl/wsl_setup.ps1 +++ b/wsl/wsl_setup.ps1 @@ -426,7 +426,7 @@ process { "`e[97;1mSSH key added to GitHub:`e[0;90m $($sshStatus.title)`e[0m`n", "`e[97mTo finish setting up SSH authentication, open `e[34;4mhttps://github.com/settings/ssh`e[97;24m", "and authorize the newly added key for your organization (enable SSO if required).`e[0m", - "`npress Enter key to continue" + "`npress Enter to continue" ) Read-Host $msg } @@ -684,16 +684,16 @@ end { if ($successDistros.Count -eq 1) { Write-Host "`n`e[95m<< Successfully set up the `e[1m$successDistros`e[22m WSL distro >>`e[0m`n" } else { - Write-Host "`n`e[95m<< Successfully set up the following WSL distros >>`e[0m`n" - $successDistros.ForEach({ Write-Host "`e[1;95m- $_`e[0m" }) + Write-Host "`n`e[95m<< Successfully set up the following WSL distros >>`e[0m" + $successDistros.ForEach({ Write-Host "- $_" }) } } if ($failDistros.Count) { if ($failDistros.Count -eq 1) { Write-Host "`n`e[91m<< Failed to set up the `e[4m$failDistros`e[24m WSL distro >>`e[0m`n" } else { - Write-Host "`n`e[91m<< Failed to set up the following WSL distros >>`e[0m`n" - $failDistros.ForEach({ Write-Host "`e[1;91m- $_`e[0m" }) + Write-Host "`n`e[91m<< Failed to set up the following WSL distros >>`e[0m" + $failDistros.ForEach({ Write-Host "- $_" }) } } }