Commit ff6f50922e46
Changed files (28)
.ast-grep
rules
dots
config
claude
home
common
shell
tmux
scripts
keyboards
eyelash_corne
lib
moonlander
pkgs
audible-converter
my
scripts
systems
common
hardware
tools
nix-flake-update
nixpkgs-consolidate
tmp
.ast-grep/rules/bash-prefer-dollar-parens.yml
@@ -0,0 +1,12 @@
+id: bash-prefer-dollar-parens
+message: Use $(...) instead of backticks for command substitution
+severity: info
+language: Bash
+note: |
+ $(...) is preferred because:
+ - Easier to nest
+ - Clearer to read
+ - POSIX-compliant
+rule:
+ pattern: "`$CMD`"
+fix: "$($CMD)"
.ast-grep/rules/bash-require-strict-mode.yml
@@ -0,0 +1,23 @@
+id: bash-require-strict-mode
+message: Add 'set -euo pipefail' for safer bash scripts
+severity: error
+language: Bash
+note: |
+ set -e: Exit on error
+ set -u: Exit on undefined variable
+ set -o pipefail: Exit on pipe failure
+rule:
+ pattern:
+ context: |
+ #!/usr/bin/env bash
+ $$$REST
+ selector: program
+ not:
+ has:
+ any:
+ - pattern: set -euo pipefail
+ - pattern: set -euox pipefail
+ - pattern: set -Eeuo pipefail
+ - pattern: set -eufo pipefail
+ - pattern: set -euxo pipefail
+ - pattern: set -Eeuxo pipefail
.ast-grep/rules/bash-unsafe-rm-rf.yml
@@ -0,0 +1,25 @@
+id: bash-unsafe-rm-rf
+message: Potentially dangerous 'rm -rf' usage - ensure variable is not empty
+severity: warning
+language: Bash
+note: |
+ Always check variables are non-empty before rm -rf:
+ [[ -n "$VAR" ]] && rm -rf "$VAR"
+ Or use safer alternatives like find with -delete
+
+ Note: This rule may produce false positives when multiple conditions are chained.
+rule:
+ pattern: rm -rf $VAR
+ not:
+ inside:
+ any:
+ - pattern: |
+ if [[ -n "$VAR" ]]; then
+ $$$
+ fi
+ - pattern: |
+ if [ -n "$VAR" ]; then
+ $$$
+ fi
+ - pattern: |
+ [[ -n "$VAR" ]] && $$$
.ast-grep/rules/bash-use-command-over-which.yml
@@ -0,0 +1,8 @@
+id: bash-use-command-over-which
+message: Use 'command -v' instead of 'which'
+severity: warning
+language: Bash
+note: "'command -v' is POSIX-compliant and more portable than 'which'"
+rule:
+ pattern: which $CMD
+fix: command -v $CMD
.ast-grep/rules/general-deprecated-nix-commands.yml
@@ -0,0 +1,17 @@
+id: general-deprecated-nix-commands
+message: Use new nix command instead of legacy nix-env
+severity: info
+language: bash
+note: |
+ Legacy Nix commands are deprecated. Use the new nix CLI:
+
+ Instead of: Use:
+ nix-env -iA nix profile install
+ nix-env -q nix profile list
+ nix-build nix build
+ nix-shell nix develop (for flakes)
+rule:
+ any:
+ - pattern: nix-env -iA $PKG
+ - pattern: nix-env -i $PKG
+ - pattern: nix-env -q
.ast-grep/rules/general-hardcoded-paths.yml
@@ -0,0 +1,19 @@
+id: general-hardcoded-home-paths
+message: Hardcoded /home/vincent path found
+severity: warning
+language: bash
+note: |
+ Use $HOME or relative paths instead of hardcoded /home/vincent.
+ Makes scripts more portable and reusable.
+
+ Good alternatives:
+ - $HOME instead of /home/vincent
+ - $(git rev-parse --show-toplevel) for repo root
+ - Relative paths when possible
+rule:
+ pattern: "/home/vincent/$PATH"
+ not:
+ inside:
+ any:
+ - kind: comment
+ - pattern: '"$STRING"' # Inside quoted strings might be intentional
.ast-grep/rules/general-no-todo-fixme.yml
@@ -0,0 +1,11 @@
+id: general-no-todo-fixme
+message: TODO/FIXME comment found - track in org-mode instead
+severity: info
+language: python
+note: |
+ Consider tracking TODOs in org-mode todos.org instead of code comments.
+ This makes them more visible and trackable.
+rule:
+ any:
+ - pattern: "# TODO: $MSG"
+ - pattern: "# FIXME: $MSG"
.ast-grep/rules/nix-boolean-comparison.yml
@@ -0,0 +1,13 @@
+id: nix-boolean-comparison
+message: Don't compare booleans to true/false directly
+severity: warning
+language: Nix
+note: |
+ Use the boolean directly: if $VAR then ...
+ For false: if !$VAR then ...
+rule:
+ any:
+ - pattern: $VAR == true
+ - pattern: $VAR == false
+ - pattern: true == $VAR
+ - pattern: false == $VAR
.ast-grep/rules/nix-explicit-option-types.yml.disabled
@@ -0,0 +1,13 @@
+id: nix-explicit-option-types
+message: Always specify explicit type for mkOption
+severity: warning
+language: Nix
+note: Add 'type = types.<type>' to the option definition
+rule:
+ pattern: |
+ mkOption {
+ $$$OPTS
+ }
+ not:
+ has:
+ pattern: type = $TYPE
.ast-grep/rules/nix-prefer-inherit.yml
@@ -0,0 +1,10 @@
+id: nix-prefer-inherit
+message: Use 'inherit' for cleaner attribute sets
+severity: info
+language: Nix
+note: |
+ When an attribute name matches the variable name,
+ use 'inherit' instead of explicit assignment.
+rule:
+ pattern: $NAME = $NAME
+fix: inherit $NAME
.ast-grep/rules/nix-prefer-optional.yml
@@ -0,0 +1,8 @@
+id: nix-prefer-optional
+message: Use lib.optional for conditional list items
+severity: info
+language: Nix
+note: lib.optional returns [ $ITEM ] if condition is true, [] otherwise
+rule:
+ pattern: if $COND then [ $ITEM ] else []
+fix: lib.optional $COND $ITEM
.ast-grep/rules/security-unsafe-curl-pipe-sh.yml
@@ -0,0 +1,17 @@
+id: security-unsafe-curl-pipe-sh
+message: Unsafe pattern - curl | sh
+severity: error
+language: Bash
+note: |
+ This pattern is dangerous:
+ 1. No integrity check
+ 2. No review of what's being executed
+ 3. Vulnerable to MITM attacks
+
+ Better: Download, review, verify checksum, then execute
+rule:
+ any:
+ - pattern: curl $$$URL | sh
+ - pattern: curl $$$URL | bash
+ - pattern: wget -O- $$$URL | sh
+ - pattern: wget -O- $$$URL | bash
.ast-grep/rules/yaml-no-latest-tag.yml
@@ -0,0 +1,13 @@
+id: yaml-no-latest-tag
+message: Avoid 'latest' tag in container images
+severity: warning
+language: yaml
+note: |
+ Using 'latest' tag is not reproducible and can lead to unexpected updates.
+
+ Use specific versions or SHA digests:
+ - image: alpine:3.19
+ - image: alpine@sha256:abc123...
+rule:
+ pattern: |
+ image: $IMAGE:latest
dots/config/claude/statusline.sh
@@ -3,6 +3,8 @@
# Claude Code Statusline - Enhanced with NixOS/Homelab Context
#
# This statusline provides:
+
+set -euo pipefail
# - Line 1: Identity, model, project context, directory
# - Line 2: Active capabilities (skills, hooks)
#
home/common/shell/tmux/scripts/smart-clipboard.sh
@@ -3,6 +3,8 @@
# Detects environment and uses appropriate clipboard backend
# - OSC 52 for SSH sessions (works over network)
# - pbcopy for macOS
+
+set -euo pipefail
# - wl-copy for Wayland (Linux)
# - xclip for X11 (Linux)
keyboards/eyelash_corne/lib/functions.sh
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Author: Chmouel Boudjnah <chmouel@chmouel.com>
+set -euo pipefail
+
if [[ -e config/includes/local.h ]]; then
cat <<EOF >config/includes/local.h
#define MYDEBUG_PASTE_MACRO &kp D &kp E &kp B &kp U &kp G
keyboards/moonlander/go.sh
@@ -1,5 +1,6 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p qmk
+# shellcheck shell=bash
set -eufo pipefail
TARGET_USER=vincent
@@ -27,7 +28,7 @@ symlink() {
local keyboard="zsa/moonlander"
rm -f build/${p}/keyboards/${keyboard}/keymaps/${TARGET_USER}
mkdir -p build/${p}/keyboards/${keyboard}/keymaps
- ln -rvsf ${PWD}/config build/${p}/keyboards/${keyboard}/keymaps/${TARGET_USER}
+ ln -rvsf "${PWD}/config" build/${p}/keyboards/${keyboard}/keymaps/${TARGET_USER}
# [[ -e build/${p}/users/common ]] || ln -rvsf ${PWD}/common build/${p}/users/vincent
}
@@ -36,7 +37,7 @@ action() {
local action=$1
local p=qmk_firmware
symlink ${keyboard}
- make BUILD_DIR=${PWD}/build -j1 -C build/${p} ${keyboard}:${TARGET_USER}:${action}
+ make BUILD_DIR="${PWD}/build" -j1 -C build/${p} "${keyboard}:${TARGET_USER}:${action}"
}
build() {
@@ -48,7 +49,8 @@ flash() {
}
clean() {
- rm -rf build
+ local build_dir="build"
+ [[ -n "$build_dir" ]] && [[ -d "$build_dir" ]] && rm -rf "$build_dir"
git submodule update -f --recursive
}
@@ -67,7 +69,7 @@ if [[ $1 == update ]]; then
update
exit
elif [[ $1 == checkout ]]; then
- checkout ${2:-""}
+ checkout "${2:-}"
exit
elif [[ ${1} == clean ]]; then
clean
pkgs/audible-converter/convert.sh
@@ -115,7 +115,7 @@ setup_dirs() {
cleanup() {
if [ -d "$TEMP_DIR" ]; then
log_info "Cleaning up temporary files in: $TEMP_DIR"
- rm -rf "$TEMP_DIR"
+ [[ -n "$TEMP_DIR" ]] && rm -rf "$TEMP_DIR"
log_info "Cleanup complete"
fi
}
pkgs/my/scripts/bin/gcr-nuke.sh
@@ -1,15 +1,14 @@
#!/usr/bin/env bash
-set -e
-set -o pipefail
+set -euo pipefail
for repository in $(gcloud container images list --format='get(name)');
do
echo ">> Cleaning ${repository}…"
while true; do
- DIGEST=$(gcloud container images list-tags ${repository} --filter='-tags:*' --format='get(digest)' --limit=1)
+ DIGEST=$(gcloud container images list-tags "${repository}" --filter='-tags:*' --format='get(digest)' --limit=1)
if [ -z "${DIGEST}" ]; then
break
fi
- gcloud container images delete ${repository}@${DIGEST} --force-delete-tags --quiet || break
+ gcloud container images delete "${repository}@${DIGEST}" --force-delete-tags --quiet || break
done
done
pkgs/my/scripts/bin/gitwatch.sh
@@ -3,6 +3,8 @@
# gitwatch - watch file or directory and git commit all changes as they happen
#
# Copyright (C) 2013-2018 Patrick Lehner
+
+set -euo pipefail
# with modifications and contributions by:
# - Matthew McGowan
# - Dominik D. Geyer
@@ -325,6 +327,7 @@ diff-lines() {
# process some time (in case there are a lot of changes or w/e); if there is already a timer
# running when we receive an event, we kill it and start a new one; thus we only commit if there
# have been no changes reported during a whole timeout period
+# shellcheck disable=SC2294
eval "$INW" "${INW_ARGS[@]}" | while read -r line; do
# is there already a timeout process running?
if [[ -n $SLEEP_PID ]] && kill -0 "$SLEEP_PID" &> /dev/null; then
@@ -376,6 +379,7 @@ eval "$INW" "${INW_ARGS[@]}" | while read -r line; do
exit 0
fi
+ # shellcheck disable=SC2086
$GIT add $GIT_ADD_ARGS # add file(s) to index
# shellcheck disable=SC2086
$GIT commit $GIT_COMMIT_ARGS -m"$FORMATTED_COMMITMSG" # construct commit message and commit
systems/common/hardware/bluetooth.nix
@@ -1,4 +1,9 @@
-{ pkgs, desktop, ... }:
+{
+ pkgs,
+ lib,
+ desktop,
+ ...
+}:
{
hardware.bluetooth = {
enable = true;
@@ -10,6 +15,6 @@
};
};
};
- environment.systemPackages = if (builtins.isString desktop) then [ pkgs.blueberry ] else [ ];
+ environment.systemPackages = lib.optional (builtins.isString desktop) pkgs.blueberry;
services.blueman.enable = builtins.isString desktop;
}
tools/nix-flake-update/nix-flake-update.sh
@@ -86,7 +86,7 @@ cleanup() {
log "Cleaning up worktree: $WORKTREE_DIR"
cd "$REPO_PATH"
git worktree remove --force "$WORKTREE_DIR" 2>&1 | tee -a "$LOG_FILE" || true
- rm -rf "$WORKTREE_DIR" || true
+ [[ -n "$WORKTREE_DIR" ]] && rm -rf "$WORKTREE_DIR" || true
fi
if [ $exit_code -ne 0 ]; then
tools/nixpkgs-consolidate/nixpkgs-consolidate.sh
@@ -241,7 +241,7 @@ setup_worktree() {
git worktree prune 2>&1 | tee -a "$LOG_FILE" || true
if [ -d "$NIXPKGS_WORKTREE_PATH" ]; then
log "Removing stale worktree directory"
- rm -rf "$NIXPKGS_WORKTREE_PATH"
+ [[ -n "$NIXPKGS_WORKTREE_PATH" ]] && rm -rf "$NIXPKGS_WORKTREE_PATH"
fi
# Delete local consolidated branch if it exists and is not checked out
tools/tmp/bootstrap.sh
@@ -6,18 +6,25 @@
# - Fedora (>= 30)
# - Mac OS X (>= 10.14)
-set -e
+set -euo pipefail
# Install nix
setup_nix() {
echo "> Install nix"
- curl https://nixos.org/nix/install | sh
+ # Download installer script first for review
+ curl -o /tmp/nix-install.sh https://nixos.org/nix/install
+ echo "Review the installer at /tmp/nix-install.sh before continuing"
+ read -r -p "Press enter to continue with installation, or Ctrl-C to cancel: "
+ sh /tmp/nix-install.sh
+ rm /tmp/nix-install.sh
}
# Install home-manager (without running it)
setup_home-manager() {
echo "> Install home-manager"
- mkdir -m 0755 -p /nix/var/nix/{profiles,gcroots}/per-user/$USER
+ mkdir -p /nix/var/nix/{profiles,gcroots}/per-user/"$USER"
+ chmod 0755 /nix/var/nix/profiles/per-user/"$USER"
+ chmod 0755 /nix/var/nix/gcroots/per-user/"$USER"
nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager
nix-channel --update
}
@@ -44,19 +51,20 @@ setup_fedora() {
echo "> nix already present"
else
setup_nix
- echo "if [ -e $HOME/.nix-profile/etc/profile.d/nix.sh ]; then . $HOME/.nix-profile/etc/profile.d/nix.sh; fi # added by Nix installer" >> $HOME/.bashrc
- . $HOME/.bashrc
+ echo "if [ -e $HOME/.nix-profile/etc/profile.d/nix.sh ]; then . $HOME/.nix-profile/etc/profile.d/nix.sh; fi # added by Nix installer" >> "$HOME/.bashrc"
+ # shellcheck source=/dev/null
+ . "$HOME/.bashrc"
fi
if hash home-manager 2>/dev/null; then
echo "> home-manager already present"
else
setup_home-manager
- echo "export NIX_PATH=$HOME/.nix-defexpr/channels\${NIX_PATH:+:}\$NIX_PATH" >> $HOME/.bashrc
+ echo "export NIX_PATH=$HOME/.nix-defexpr/channels\${NIX_PATH:+:}\$NIX_PATH" >> "$HOME/.bashrc"
fi
if [[ ! -f $HOME/.config/nixpkgs/home.nix ]]; then
echo "> create a temporary home-manager configuration"
- mkdir -p $HOME/.config/nixpkgs/
- cat > $HOME/.config/nixpkgs/home.nix <<EOF
+ mkdir -p "$HOME/.config/nixpkgs/"
+ cat > "$HOME/.config/nixpkgs/home.nix" <<EOF
{
programs.home-manager.enable = true;
programs.man.enable = false;
@@ -66,14 +74,15 @@ setup_fedora() {
EOF
fi
echo "> setup nix caches"
- mkdir -p $HOME/.config/nix/
- cat > $HOME/.config/nix/nix.conf <<EOF
+ mkdir -p "$HOME/.config/nix/"
+ cat > "$HOME/.config/nix/nix.conf" <<EOF
substituters = http://nix.cache.home https://cache.nixos.org https://shortbrain.cachix.org
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= shortbrain.cachix.org-1:dqXcXzM0yXs3eo9ChmMfmob93eemwNyhTx7wCR4IjeQ=
EOF
run_home-manager
- echo ". \"$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh\"" >> $HOME/.bashrc
- . $HOME/.bashrc
+ echo ". \"$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh\"" >> "$HOME/.bashrc"
+ # shellcheck source=/dev/null
+ . "$HOME/.bashrc"
dnf copr enable evana/fira-code-fonts
dnf install fira-code-fonts
echo "> install ansible"
@@ -87,6 +96,7 @@ setup_osx() {
if [[ "$kernel_name" == "Darwin" ]]; then
IFS=$'\n' read -d "" -ra sw_vers < <(awk -F'<|>' '/key|string/ {print $3}' \
"/System/Library/CoreServices/SystemVersion.plist")
+ # shellcheck disable=SC2034
for ((i=0;i<${#sw_vers[@]};i+=2)) {
case ${sw_vers[i]} in
ProductName) darwin_name=${sw_vers[i+1]} ;;
@@ -99,7 +109,9 @@ setup_osx() {
IFS=" " read -ra uname <<< "$(uname -srm)"
kernel_name="${uname[0]}"
+# shellcheck disable=SC2034
kernel_version="${uname[1]}"
+# shellcheck disable=SC2034
kernel_machine="${uname[2]}"
case "$kernel_name" in
@@ -109,6 +121,7 @@ case "$kernel_name" in
# Source the os-release file
for file in "${files[@]}"; do
+ # shellcheck source=/dev/null
source "$file" && break
done
case "$ID" in
tools/boox-debloat.sh
@@ -216,11 +216,11 @@ if [ $HAS_ALT_LAUNCHER -eq 0 ]; then
# Cleanup
rm -f "$APK_PATH"
- rmdir "$TEMP_DIR"
+ [[ -n "$TEMP_DIR" ]] && [[ -d "$TEMP_DIR" ]] && rmdir "$TEMP_DIR"
else
echo -e "${RED} ✗ Failed to download AIO Launcher${NC}"
echo " You can install manually from Google Play Store instead."
- rm -rf "$TEMP_DIR"
+ [[ -n "$TEMP_DIR" ]] && [[ -d "$TEMP_DIR" ]] && rm -rf "$TEMP_DIR"
fi
else
echo -e "${YELLOW} Install AIO Launcher manually from Google Play Store:${NC}"
tools/test-all-packages.sh
@@ -3,6 +3,8 @@
#
# Usage: ./test-all-packages.sh
+set -euo pipefail
+
set -e
# Get script directory
tools/test-package.sh
@@ -3,7 +3,7 @@
#
# Usage: ./test-package.sh <package-name>
-set -e
+set -euo pipefail
PACKAGE=$1
install.sh
@@ -1,8 +1,10 @@
#!/usr/bin/env bash
# Install a new system
+set -euo pipefail
+
SYSTEM=$1
shift
nix --extra-experimental-features "nix-command flakes" run \
- 'github:nix-community/disko/latest#disko-install' -- --flake ".#${SYSTEM}" $@
+ 'github:nix-community/disko/latest#disko-install' -- --flake ".#${SYSTEM}" "$@"