mirror of
https://github.com/ivuorinen/dotfiles.git
synced 2026-02-08 07:50:53 +00:00
fix(lint): fix all sonarcloud detected issues (#279)
* fix(ci): replace broad permissions with specific scopes in workflows
Replace read-all/write-all with minimum required permission scopes
across all GitHub Actions workflows to follow the principle of least
privilege (SonarCloud rule githubactions:S8234).
* fix(shell): use [[ instead of [ for conditional tests
Replace single brackets with double brackets in bash conditional
expressions across 14 files (28 changes). All scripts use bash
shebangs so [[ is safe everywhere (SonarCloud rule shelldre:S7688).
* fix(shell): add explicit return statements to functions
Add return 0 as the last statement in ~46 shell functions across
17 files that previously relied on implicit return codes
(SonarCloud rule shelldre:S7682).
* fix(shell): assign positional parameters to local variables
Replace direct $1/$2/$3 usage with named local variables in _log(),
msg(), msg_err(), msg_done(), msg_run(), msg_ok(), and array_diff()
(SonarCloud rule shelldre:S7679).
* fix(python): replace dict() constructor with literal
Use {} instead of dict() for empty dictionary initialization
(SonarCloud rule python:S7498).
* fix(shell): fix husky shebang and tolerate npm outdated exit code
* docs(shell): add function docstring comments
* fix(shell): fix heredoc indentation in x-sonarcloud
* feat(python): add ruff linter and formatter configuration
* fix(ci): align megalinter config with biome, ruff, and shfmt settings
* fix(ci): disable black and yaml-prettier in megalinter config
* chore(ci): update ruff-pre-commit to v0.15.0 and fix hook name
* fix(scripts): check for .git dir before skipping clone in install-fonts
* fix(shell): address code review issues in scripts and shared.sh
- Guard wezterm show-keys failure in create-wezterm-keymaps.sh
- Stop masking git failures with return 0 in install-cheat-purebashbible.sh
- Add missing shared.sh source in install-xcode-cli-tools.sh
- Replace exit 1 with return 1 in sourced shared.sh
* fix(scripts): address code review and security findings
- Guard wezterm show-keys failure in create-wezterm-keymaps.sh
- Stop masking git failures with return 0 in install-cheat-purebashbible.sh
- Add missing shared.sh source in install-xcode-cli-tools.sh
- Replace exit 1 with return 1 in sourced shared.sh
- Remove shell=True subprocess calls in x-git-largest-files.py
* style(shell): apply shfmt formatting and add args to pre-commit hook
* fix(python): suppress bandit false positives in x-git-largest-files
* fix(python): add nosemgrep suppression for check_output call
* feat(format): add prettier for YAML formatting
Install prettier, add .prettierrc.json config (200-char width, 2-space
indent, LF endings), .prettierignore, yarn scripts (lint:prettier,
fix:prettier, format:yaml), and pre-commit hook scoped to YAML files.
* style(yaml): apply prettier formatting
* fix(scripts): address remaining code review findings
- Python: use list comprehension to filter empty strings instead of
slicing off the last element
- create-wezterm-keymaps: write to temp file and mv for atomic updates
- install-xcode-cli-tools: fix shellcheck source directive path
* fix(python): sort imports alphabetically in x-git-largest-files
* fix(lint): disable PYTHON_ISORT in MegaLinter, ruff handles it
* chore(git): add __pycache__ to gitignore
* fix(python): rename ambiguous variable l to line (E741)
* style: remove trailing whitespace and blank lines
* style(fzf): apply shfmt formatting
* style(shell): apply shfmt formatting
* docs(plans): add design documents
* style(docs): add language specifier to fenced code block
* feat(lint): add markdown-table-formatter to dev tooling
Add markdown-table-formatter as a dev dependency with yarn scripts
(lint:md-table, fix:md-table) and a local pre-commit hook to
automatically format markdown tables on commit.
This commit is contained in:
@@ -20,7 +20,7 @@ Some problematic code has been fixed per `shellcheck` suggestions.
|
||||
## Sourced
|
||||
|
||||
| Script | Source |
|
||||
| ----------------------- | ----------------- |
|
||||
|-------------------------|-------------------|
|
||||
| `x-dupes` | skx/sysadmin-util |
|
||||
| `x-foreach` | mvdan/dotfiles |
|
||||
| `x-multi-ping` | skx/sysadmin-util |
|
||||
|
||||
@@ -64,6 +64,7 @@ menu_builder()
|
||||
done
|
||||
}
|
||||
|
||||
# Handle install section commands
|
||||
section_install()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT install <command>"
|
||||
@@ -193,6 +194,7 @@ section_install()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle Homebrew section commands
|
||||
section_brew()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT brew <command>"
|
||||
@@ -291,6 +293,7 @@ section_brew()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle helper utility commands
|
||||
section_helpers()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT helpers <command>"
|
||||
@@ -367,6 +370,7 @@ section_helpers()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle apt package manager commands
|
||||
section_apt()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT apt <command>"
|
||||
@@ -435,6 +439,7 @@ section_apt()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle documentation generation commands
|
||||
section_docs()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT docs <command>"
|
||||
@@ -459,6 +464,7 @@ section_docs()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle dotfiles formatting and reset commands
|
||||
section_dotfiles()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT dotfiles <command>"
|
||||
@@ -526,6 +532,7 @@ section_dotfiles()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle system check commands (arch, hostname)
|
||||
section_check()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT check <command>"
|
||||
@@ -552,6 +559,7 @@ section_check()
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle install script execution
|
||||
section_scripts()
|
||||
{
|
||||
USAGE_PREFIX="$SCRIPT scripts <command>"
|
||||
@@ -619,6 +627,7 @@ section_tests()
|
||||
esac
|
||||
}
|
||||
|
||||
# Display main usage information for all sections
|
||||
usage()
|
||||
{
|
||||
echo ""
|
||||
@@ -642,6 +651,7 @@ usage()
|
||||
section_helpers
|
||||
}
|
||||
|
||||
# Parse section argument and dispatch to handler
|
||||
main()
|
||||
{
|
||||
SECTION="${1:-}"
|
||||
|
||||
@@ -22,32 +22,37 @@ if [ "$DEBUG" -eq 1 ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
# Output functions
|
||||
# Print an error message in red
|
||||
msg_err()
|
||||
{
|
||||
echo -e "\e[31m$*\e[0m" >&2
|
||||
}
|
||||
|
||||
# Print a success message in green
|
||||
msg_success()
|
||||
{
|
||||
echo -e "\e[32m$*\e[0m"
|
||||
}
|
||||
|
||||
# Print a warning message in yellow
|
||||
msg_warn()
|
||||
{
|
||||
echo -e "\e[33m$*\e[0m" >&2
|
||||
}
|
||||
|
||||
# Print an info message in blue
|
||||
msg_info()
|
||||
{
|
||||
echo -e "\e[36m$*\e[0m"
|
||||
}
|
||||
|
||||
# Print a debug message when verbose mode is on
|
||||
msg_debug()
|
||||
{
|
||||
[[ $VERBOSE -eq 1 ]] && echo -e "\e[35m$*\e[0m"
|
||||
}
|
||||
|
||||
# Display usage information and examples
|
||||
show_help()
|
||||
{
|
||||
cat << EOF
|
||||
|
||||
@@ -90,13 +90,14 @@ declare -A DIR_HAS_REPOS
|
||||
# Record start time
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# Logging functions
|
||||
# Log an error message
|
||||
log_error()
|
||||
{
|
||||
print_color "31" "ERROR:" >&2
|
||||
echo " $*" >&2
|
||||
}
|
||||
|
||||
# Log an informational message
|
||||
log_info()
|
||||
{
|
||||
if [[ $VERBOSE -eq 1 ]]; then
|
||||
@@ -105,6 +106,7 @@ log_info()
|
||||
fi
|
||||
}
|
||||
|
||||
# Log a warning message
|
||||
log_warn()
|
||||
{
|
||||
print_color "33" "WARNING:" >&2
|
||||
@@ -911,6 +913,7 @@ process_in_parallel()
|
||||
echo -e "\nProcessed $total repositories in $dur (Total runtime: $runtime)"
|
||||
}
|
||||
|
||||
# Check a directory for git status with progress tracking
|
||||
check_directory_with_progress()
|
||||
{
|
||||
local dir
|
||||
|
||||
@@ -23,21 +23,25 @@ CLR_RESET="\033[0m"
|
||||
# │ Color functions │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
|
||||
# Wrap text in red color
|
||||
function __color_red()
|
||||
{
|
||||
local MSG="$1"
|
||||
echo -e "${CLR_RED}${MSG}${CLR_RESET}"
|
||||
}
|
||||
# Wrap text in yellow color
|
||||
function __color_yellow()
|
||||
{
|
||||
local MSG="$1"
|
||||
echo -e "${CLR_YELLOW}${MSG}${CLR_RESET}"
|
||||
}
|
||||
# Wrap text in green color
|
||||
function __color_green()
|
||||
{
|
||||
local MSG="$1"
|
||||
echo -e "${CLR_GREEN}${MSG}${CLR_RESET}"
|
||||
}
|
||||
# Wrap text in blue color
|
||||
function __color_blue()
|
||||
{
|
||||
local MSG="$1"
|
||||
@@ -48,36 +52,43 @@ function __color_blue()
|
||||
# │ Helpers │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
|
||||
# Print blue arrow marker
|
||||
function __log_marker()
|
||||
{
|
||||
echo -e "${CLR_BLUE}➜${CLR_RESET}"
|
||||
}
|
||||
|
||||
# Print green checkmark marker
|
||||
function __log_marker_ok()
|
||||
{
|
||||
echo -e "${CLR_GREEN}✔${CLR_RESET}"
|
||||
}
|
||||
|
||||
# Print blue checkmark marker
|
||||
function __log_marker_ok_blue()
|
||||
{
|
||||
echo -e "${CLR_BLUE}✔${CLR_RESET}"
|
||||
}
|
||||
|
||||
# Print yellow warning marker
|
||||
function __log_marker_warn()
|
||||
{
|
||||
echo -e "${CLR_YELLOW}⁕${CLR_RESET}"
|
||||
}
|
||||
|
||||
# Print yellow question marker
|
||||
function __log_marker_question()
|
||||
{
|
||||
echo -e "${CLR_YELLOW}?${CLR_RESET}"
|
||||
}
|
||||
|
||||
# Print red error marker
|
||||
function __log_marker_err()
|
||||
{
|
||||
echo -e "${CLR_RED}⛌${CLR_RESET}"
|
||||
}
|
||||
|
||||
# Print indentation spacing
|
||||
function __log_indent()
|
||||
{
|
||||
echo " "
|
||||
@@ -87,71 +98,85 @@ function __log_indent()
|
||||
# │ Log functions │
|
||||
# ╰──────────────────────────────────────────────────────────╯
|
||||
|
||||
# Print a message with arrow marker
|
||||
function msg()
|
||||
{
|
||||
echo -e "$(__log_marker) $1"
|
||||
}
|
||||
|
||||
# Print a celebration message
|
||||
function msg_yay()
|
||||
{
|
||||
echo -e "🎉 $1"
|
||||
}
|
||||
|
||||
# Print a celebration message with checkmark
|
||||
function msg_yay_done()
|
||||
{
|
||||
echo -e "🎉 $1 ...$(__log_marker_ok)"
|
||||
}
|
||||
|
||||
# Print a message with completion checkmark
|
||||
function msg_done()
|
||||
{
|
||||
echo -e "$(__log_marker) $1 ...$(__log_marker_ok)"
|
||||
}
|
||||
|
||||
# Print a completion checkmark suffix
|
||||
function msg_done_suffix()
|
||||
{
|
||||
echo -e "$(__log_marker) ...$(__log_marker_ok)"
|
||||
}
|
||||
|
||||
# Print a prompt-style message
|
||||
function msg_prompt()
|
||||
{
|
||||
echo -e "$(__log_marker_question) $1"
|
||||
}
|
||||
|
||||
# Print a prompt message with checkmark
|
||||
function msg_prompt_done()
|
||||
{
|
||||
echo -e "$(__log_marker_question) $1 ...$(__log_marker_ok)"
|
||||
}
|
||||
|
||||
# Print an indented message
|
||||
function msg_nested()
|
||||
{
|
||||
echo -e "$(__log_indent)$(__log_marker) $1"
|
||||
}
|
||||
|
||||
# Print an indented message with checkmark
|
||||
function msg_nested_done()
|
||||
{
|
||||
echo -e "$(__log_indent)$(__log_marker) $1 ...$(__log_marker_ok)"
|
||||
}
|
||||
|
||||
# Print a running-task message in green
|
||||
function msg_run()
|
||||
{
|
||||
echo -e "${CLR_GREEN}➜ $1${CLR_RESET} $2"
|
||||
}
|
||||
|
||||
# Print a running-task message with checkmark
|
||||
function msg_run_done()
|
||||
{
|
||||
echo -e "${CLR_GREEN}➜ $1${CLR_RESET} $2 ...$(__log_marker_ok)"
|
||||
}
|
||||
|
||||
# Print an ok/success message
|
||||
function msg_ok()
|
||||
{
|
||||
echo -e "$(__log_marker_ok) $1"
|
||||
}
|
||||
|
||||
# Print a warning message
|
||||
function msg_warn()
|
||||
{
|
||||
echo -e "$(__log_marker_warn) $1"
|
||||
}
|
||||
|
||||
# Print an error message
|
||||
function msg_err()
|
||||
{
|
||||
echo -e "$(__log_marker_err) $1"
|
||||
@@ -174,6 +199,7 @@ ask()
|
||||
# If this is being sourced, no need to run the next steps.
|
||||
[ "$sourced" = 1 ] && return
|
||||
|
||||
# Run visual tests for all message types
|
||||
function __tests()
|
||||
{
|
||||
msg "[ msg ]"
|
||||
@@ -192,6 +218,7 @@ function __tests()
|
||||
msg_yay_done "[ yay_done ]"
|
||||
}
|
||||
|
||||
# Show usage information and examples
|
||||
function usage()
|
||||
{
|
||||
echo "usage: msgr [type] [message] [optional second message]"
|
||||
|
||||
@@ -19,7 +19,7 @@ set -euo pipefail # Add error handling
|
||||
LATEST_VERSION_FORMULA="php" # The formula name for latest PHP version
|
||||
PHP_VERSION_FILE=".php-version" # File name to look for when auto-switching
|
||||
|
||||
# Switch brew php version
|
||||
# Verify that Homebrew is installed
|
||||
function check_dependencies()
|
||||
{
|
||||
if ! command -v brew > /dev/null 2>&1; then
|
||||
@@ -28,6 +28,7 @@ function check_dependencies()
|
||||
fi
|
||||
}
|
||||
|
||||
# Display help message and usage examples
|
||||
function usage()
|
||||
{
|
||||
echo "Brew PHP Switcher - Switch between PHP versions installed via Homebrew"
|
||||
@@ -53,6 +54,7 @@ function usage()
|
||||
exit 0
|
||||
}
|
||||
|
||||
# List all PHP versions installed via Homebrew
|
||||
function list_php_versions()
|
||||
{
|
||||
# Check Homebrew's installation path for PHP versions
|
||||
@@ -185,6 +187,7 @@ function list_php_versions()
|
||||
done
|
||||
}
|
||||
|
||||
# Convert a version number to a Homebrew formula name
|
||||
function get_php_formula_for_version()
|
||||
{
|
||||
local version="$1"
|
||||
@@ -199,6 +202,7 @@ function get_php_formula_for_version()
|
||||
echo "php@$version"
|
||||
}
|
||||
|
||||
# Check if a Homebrew formula is installed
|
||||
function check_formula_installed()
|
||||
{
|
||||
local formula="$1"
|
||||
@@ -216,6 +220,7 @@ function check_formula_installed()
|
||||
return 1
|
||||
}
|
||||
|
||||
# Unlink the currently active PHP version
|
||||
function unlink_current_php()
|
||||
{
|
||||
local current_formula=""
|
||||
@@ -241,6 +246,7 @@ function unlink_current_php()
|
||||
fi
|
||||
}
|
||||
|
||||
# Link a specific PHP formula as the active version
|
||||
function link_php_version()
|
||||
{
|
||||
local formula="$1"
|
||||
@@ -265,6 +271,7 @@ function link_php_version()
|
||||
fi
|
||||
}
|
||||
|
||||
# Display the currently active PHP version
|
||||
function get_current_version()
|
||||
{
|
||||
if ! command -v php > /dev/null 2>&1; then
|
||||
@@ -300,6 +307,7 @@ function get_current_version()
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate PHP version format (x.y or latest)
|
||||
function validate_version()
|
||||
{
|
||||
local version="$1"
|
||||
@@ -312,6 +320,7 @@ function validate_version()
|
||||
fi
|
||||
}
|
||||
|
||||
# Search for .php-version file in directory hierarchy
|
||||
function find_php_version_file()
|
||||
{
|
||||
local dir="$PWD"
|
||||
@@ -334,6 +343,7 @@ function find_php_version_file()
|
||||
return 1
|
||||
}
|
||||
|
||||
# Auto-switch PHP based on .php-version file
|
||||
function auto_switch_php_version()
|
||||
{
|
||||
local version_file
|
||||
@@ -360,6 +370,7 @@ function auto_switch_php_version()
|
||||
switch_php_version "$version"
|
||||
}
|
||||
|
||||
# Switch to a specific PHP version
|
||||
function switch_php_version()
|
||||
{
|
||||
local version="$1"
|
||||
@@ -398,6 +409,7 @@ function switch_php_version()
|
||||
echo "PHP executable: $(command -v php)"
|
||||
}
|
||||
|
||||
# Parse arguments and dispatch to appropriate action
|
||||
function main()
|
||||
{
|
||||
local version=""
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#
|
||||
# Modified by Ismo Vuorinen <https://github.com/ivuorinen> 2023
|
||||
|
||||
# Display usage information for pushover
|
||||
__pushover_usage()
|
||||
{
|
||||
printf "pushover <options> <message>\n"
|
||||
@@ -23,6 +24,7 @@ __pushover_usage()
|
||||
return 1
|
||||
}
|
||||
|
||||
# Format an optional curl form field
|
||||
__pushover_opt_field()
|
||||
{
|
||||
field=$1
|
||||
@@ -33,6 +35,7 @@ __pushover_opt_field()
|
||||
fi
|
||||
}
|
||||
|
||||
# Send a pushover notification via curl
|
||||
__pushover_send_message()
|
||||
{
|
||||
device="${1:-}"
|
||||
|
||||
@@ -10,6 +10,7 @@ VERSION="1.0.0"
|
||||
LANG_MAP="c:.c,.h|cpp:.cpp,.cc,.cxx,.hpp,.hxx|csharp:.cs|go:.go|java:.java|
|
||||
javascript:.js,.jsx,.mjs,.ts,.tsx|python:.py|ruby:.rb|swift:.swift"
|
||||
|
||||
# Display usage information and options
|
||||
usage()
|
||||
{
|
||||
cat << EOF
|
||||
@@ -24,22 +25,26 @@ EOF
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
# Log a timestamped message to stderr
|
||||
log()
|
||||
{
|
||||
printf '[%s] %s\n' "$(date '+%H:%M:%S')" "$*" >&2
|
||||
}
|
||||
# Log an error message and exit
|
||||
err()
|
||||
{
|
||||
log "ERROR: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Verify codeql binary is available in PATH
|
||||
check_codeql()
|
||||
{
|
||||
command -v codeql > /dev/null 2>&1 || err "codeql binary not found in PATH"
|
||||
log "Found codeql: $(codeql version --format=terse)"
|
||||
}
|
||||
|
||||
# Get or create the CodeQL cache directory
|
||||
get_cache_dir()
|
||||
{
|
||||
cache="${XDG_CACHE_HOME:-$HOME/.cache}/codeql"
|
||||
@@ -47,6 +52,7 @@ get_cache_dir()
|
||||
printf '%s' "$cache"
|
||||
}
|
||||
|
||||
# Detect supported programming languages in source path
|
||||
detect_languages()
|
||||
{
|
||||
src_path="$1"
|
||||
@@ -85,6 +91,7 @@ detect_languages()
|
||||
printf '%s' "$detected" | tr ' ' '\n' | sort -u | tr '\n' ' ' | sed 's/ $//'
|
||||
}
|
||||
|
||||
# Create a CodeQL database for a language
|
||||
create_database()
|
||||
{
|
||||
lang="$1"
|
||||
@@ -98,6 +105,7 @@ create_database()
|
||||
--overwrite
|
||||
}
|
||||
|
||||
# Display analysis result statistics from SARIF file
|
||||
show_results_stats()
|
||||
{
|
||||
sarif_file="$1"
|
||||
@@ -126,6 +134,7 @@ show_results_stats()
|
||||
return 0
|
||||
}
|
||||
|
||||
# Run CodeQL analysis for a single language
|
||||
analyze_language()
|
||||
{
|
||||
lang="$1"
|
||||
@@ -172,6 +181,7 @@ analyze_language()
|
||||
rm -rf "$db_path"
|
||||
}
|
||||
|
||||
# Parse arguments and run CodeQL analysis pipeline
|
||||
main()
|
||||
{
|
||||
src_path="."
|
||||
|
||||
@@ -24,7 +24,7 @@ str_to_operator = {
|
||||
def vercmp(expr):
|
||||
"""Version Comparison function."""
|
||||
words = expr.split()
|
||||
comparisons = [words[i: i + 3] for i in range(0, len(words) - 2, 2)]
|
||||
comparisons = [words[i : i + 3] for i in range(0, len(words) - 2, 2)]
|
||||
for left, op_str, right in comparisons:
|
||||
compare_op = str_to_operator[op_str]
|
||||
if not compare_op(version.parse(left), version.parse(right)):
|
||||
@@ -63,7 +63,7 @@ def test():
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
assert False, "invalid operator did not raise"
|
||||
raise AssertionError("invalid operator did not raise")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -190,6 +190,7 @@ get_custom_group()
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if a key matches the skipped keys list
|
||||
is_skipped()
|
||||
{
|
||||
local key=$1
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Python script to find the largest files in a git repository.
|
||||
# The general method is based on the script in this blog post:
|
||||
@@ -32,60 +31,60 @@
|
||||
|
||||
# vim:tw=120:ts=4:ft=python:norl:
|
||||
|
||||
from subprocess import check_output, Popen, PIPE
|
||||
import argparse
|
||||
import glob
|
||||
import signal
|
||||
import sys
|
||||
from subprocess import PIPE, Popen, check_output # nosec B404
|
||||
|
||||
sortByOnDiskSize = False
|
||||
|
||||
class Blob(object):
|
||||
sha1 = ''
|
||||
size = 0
|
||||
packed_size = 0
|
||||
path = ''
|
||||
|
||||
def __init__(self, line):
|
||||
cols = line.split()
|
||||
self.sha1, self.size, self.packed_size = cols[0], int(cols[2]), int(cols[3])
|
||||
class Blob:
|
||||
sha1 = ""
|
||||
size = 0
|
||||
packed_size = 0
|
||||
path = ""
|
||||
|
||||
def __repr__(self):
|
||||
return '{} - {} - {} - {}'.format(
|
||||
self.sha1, self.size, self.packed_size, self.path)
|
||||
def __init__(self, line):
|
||||
cols = line.split()
|
||||
self.sha1, self.size, self.packed_size = cols[0], int(cols[2]), int(cols[3])
|
||||
|
||||
def __lt__(self, other):
|
||||
if (sortByOnDiskSize):
|
||||
return self.size < other.size
|
||||
else:
|
||||
return self.packed_size < other.packed_size
|
||||
def __repr__(self):
|
||||
return f"{self.sha1} - {self.size} - {self.packed_size} - {self.path}"
|
||||
|
||||
def csv_line(self):
|
||||
return "{},{},{},{}".format(
|
||||
self.size/1024, self.packed_size/1024, self.sha1, self.path)
|
||||
def __lt__(self, other):
|
||||
if sortByOnDiskSize:
|
||||
return self.size < other.size
|
||||
else:
|
||||
return self.packed_size < other.packed_size
|
||||
|
||||
def csv_line(self):
|
||||
return f"{self.size / 1024},{self.packed_size / 1024},{self.sha1},{self.path}"
|
||||
|
||||
|
||||
def main():
|
||||
global sortByOnDiskSize
|
||||
global sortByOnDiskSize
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
args = parse_arguments()
|
||||
sortByOnDiskSize = args.sortByOnDiskSize
|
||||
size_limit = 1024*args.filesExceeding
|
||||
args = parse_arguments()
|
||||
sortByOnDiskSize = args.sortByOnDiskSize
|
||||
size_limit = 1024 * args.filesExceeding
|
||||
|
||||
if args.filesExceeding > 0:
|
||||
print("Finding objects larger than {}kB…".format(args.filesExceeding))
|
||||
else:
|
||||
print("Finding the {} largest objects…".format(args.matchCount))
|
||||
if args.filesExceeding > 0:
|
||||
print(f"Finding objects larger than {args.filesExceeding}kB…")
|
||||
else:
|
||||
print(f"Finding the {args.matchCount} largest objects…")
|
||||
|
||||
blobs = get_top_blobs(args.matchCount, size_limit)
|
||||
blobs = get_top_blobs(args.matchCount, size_limit)
|
||||
|
||||
populate_blob_paths(blobs)
|
||||
print_out_blobs(blobs)
|
||||
populate_blob_paths(blobs)
|
||||
print_out_blobs(blobs)
|
||||
|
||||
|
||||
def get_top_blobs(count, size_limit):
|
||||
"""Get top blobs from git repository
|
||||
"""Get top blobs from git repository
|
||||
|
||||
Args:
|
||||
count (int): How many items to return
|
||||
@@ -93,110 +92,141 @@ def get_top_blobs(count, size_limit):
|
||||
|
||||
Returns:
|
||||
dict: Dictionary of Blobs
|
||||
"""
|
||||
sort_column = 4
|
||||
"""
|
||||
sort_column = 4
|
||||
|
||||
if sortByOnDiskSize:
|
||||
sort_column = 3
|
||||
if sortByOnDiskSize:
|
||||
sort_column = 3
|
||||
|
||||
verify_pack = "git verify-pack -v `git rev-parse --git-dir`/objects/pack/pack-*.idx | grep blob | sort -k{}nr".format(sort_column) # noqa: E501
|
||||
output = check_output(verify_pack, shell=True).decode('utf-8').strip().split("\n")[:-1] # noqa: E501
|
||||
git_dir = check_output(["git", "rev-parse", "--git-dir"]).decode("utf-8").strip() # nosec B603 # nosemgrep
|
||||
idx_files = glob.glob(f"{git_dir}/objects/pack/pack-*.idx")
|
||||
verify_pack = Popen( # nosec B603
|
||||
["git", "verify-pack", "-v", *idx_files],
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
)
|
||||
grep_blob = Popen(["grep", "blob"], stdin=verify_pack.stdout, stdout=PIPE, stderr=PIPE) # nosec B603
|
||||
if verify_pack.stdout:
|
||||
verify_pack.stdout.close()
|
||||
sort_cmd = Popen( # nosec B603
|
||||
["sort", f"-k{sort_column}nr"],
|
||||
stdin=grep_blob.stdout,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
)
|
||||
if grep_blob.stdout:
|
||||
grep_blob.stdout.close()
|
||||
output = [line for line in sort_cmd.communicate()[0].decode("utf-8").strip().split("\n") if line]
|
||||
|
||||
blobs = dict()
|
||||
# use __lt__ to do the appropriate comparison
|
||||
compare_blob = Blob("a b {} {} c".format(size_limit, size_limit))
|
||||
for obj_line in output:
|
||||
blob = Blob(obj_line)
|
||||
blobs = {}
|
||||
# use __lt__ to do the appropriate comparison
|
||||
compare_blob = Blob(f"a b {size_limit} {size_limit} c")
|
||||
for obj_line in output:
|
||||
blob = Blob(obj_line)
|
||||
|
||||
if size_limit > 0:
|
||||
if compare_blob < blob:
|
||||
blobs[blob.sha1] = blob
|
||||
else:
|
||||
break
|
||||
else:
|
||||
blobs[blob.sha1] = blob
|
||||
if size_limit > 0:
|
||||
if compare_blob < blob:
|
||||
blobs[blob.sha1] = blob
|
||||
else:
|
||||
break
|
||||
else:
|
||||
blobs[blob.sha1] = blob
|
||||
|
||||
if len(blobs) == count:
|
||||
break
|
||||
if len(blobs) == count:
|
||||
break
|
||||
|
||||
return blobs
|
||||
return blobs
|
||||
|
||||
|
||||
def populate_blob_paths(blobs):
|
||||
"""Populate blob paths that only have a path
|
||||
"""Populate blob paths that only have a path
|
||||
|
||||
Args:
|
||||
blobs (Blob, dict): Dictionary of Blobs
|
||||
"""
|
||||
if len(blobs):
|
||||
print("Finding object paths…")
|
||||
Args:
|
||||
blobs (Blob, dict): Dictionary of Blobs
|
||||
"""
|
||||
if len(blobs):
|
||||
print("Finding object paths…")
|
||||
|
||||
# Only include revs which have a path. Other revs aren't blobs.
|
||||
rev_list = "git rev-list --all --objects | awk '$2 {print}'"
|
||||
all_object_lines = check_output(rev_list, shell=True).decode('utf-8').strip().split("\n")[:-1] # noqa: E501
|
||||
outstanding_keys = list(blobs.keys())
|
||||
# Only include revs which have a path. Other revs aren't blobs.
|
||||
rev_list = Popen(["git", "rev-list", "--all", "--objects"], stdout=PIPE, stderr=PIPE) # nosec B603
|
||||
awk_filter = Popen(["awk", "$2 {print}"], stdin=rev_list.stdout, stdout=PIPE, stderr=PIPE) # nosec B603
|
||||
if rev_list.stdout:
|
||||
rev_list.stdout.close()
|
||||
all_object_lines = [line for line in awk_filter.communicate()[0].decode("utf-8").strip().split("\n") if line]
|
||||
outstanding_keys = list(blobs.keys())
|
||||
|
||||
for line in all_object_lines:
|
||||
cols = line.split()
|
||||
sha1, path = cols[0], " ".join(cols[1:])
|
||||
for line in all_object_lines:
|
||||
cols = line.split()
|
||||
sha1, path = cols[0], " ".join(cols[1:])
|
||||
|
||||
if (sha1 in outstanding_keys):
|
||||
outstanding_keys.remove(sha1)
|
||||
blobs[sha1].path = path
|
||||
if sha1 in outstanding_keys:
|
||||
outstanding_keys.remove(sha1)
|
||||
blobs[sha1].path = path
|
||||
|
||||
# short-circuit the search if we're done
|
||||
if not len(outstanding_keys):
|
||||
break
|
||||
# short-circuit the search if we're done
|
||||
if not len(outstanding_keys):
|
||||
break
|
||||
|
||||
|
||||
def print_out_blobs(blobs):
|
||||
if len(blobs):
|
||||
csv_lines = ["size,pack,hash,path"]
|
||||
if len(blobs):
|
||||
csv_lines = ["size,pack,hash,path"]
|
||||
|
||||
for blob in sorted(blobs.values(), reverse=True):
|
||||
csv_lines.append(blob.csv_line())
|
||||
for blob in sorted(blobs.values(), reverse=True):
|
||||
csv_lines.append(blob.csv_line())
|
||||
|
||||
command = ["column", "-t", "-s", ","]
|
||||
p = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
command = ["column", "-t", "-s", ","]
|
||||
p = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
|
||||
# Encode the input as bytes
|
||||
input_data = ("\n".join(csv_lines) + "\n").encode()
|
||||
# Encode the input as bytes
|
||||
input_data = ("\n".join(csv_lines) + "\n").encode()
|
||||
|
||||
stdout, _ = p.communicate(input_data)
|
||||
stdout, _ = p.communicate(input_data)
|
||||
|
||||
print("\nAll sizes in kB. The pack column is the compressed size of the object inside the pack file.\n") # noqa: E501
|
||||
print("\nAll sizes in kB. The pack column is the compressed size of the object inside the pack file.\n")
|
||||
|
||||
print(stdout.decode("utf-8").rstrip('\n'))
|
||||
else:
|
||||
print("No files found which match those criteria.")
|
||||
print(stdout.decode("utf-8").rstrip("\n"))
|
||||
else:
|
||||
print("No files found which match those criteria.")
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='List the largest files in a git repository'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-c', '--match-count', dest='matchCount', type=int, default=10,
|
||||
help='Files to return. Default is 10. Ignored if --files-exceeding is used.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--files-exceeding', dest='filesExceeding', type=int, default=0,
|
||||
help='The cutoff amount, in KB. Files with a pack size (or physical size, with -p) larger than this will be printed.' # noqa: E501
|
||||
)
|
||||
parser.add_argument(
|
||||
'-p', '--physical-sort', dest='sortByOnDiskSize',
|
||||
action='store_true', default=False,
|
||||
help='Sort by the on-disk size. Default is to sort by the pack size.'
|
||||
)
|
||||
parser = argparse.ArgumentParser(description="List the largest files in a git repository")
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--match-count",
|
||||
dest="matchCount",
|
||||
type=int,
|
||||
default=10,
|
||||
help="Files to return. Default is 10. Ignored if --files-exceeding is used.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--files-exceeding",
|
||||
dest="filesExceeding",
|
||||
type=int,
|
||||
default=0,
|
||||
help=(
|
||||
"The cutoff amount, in KB. Files with a pack size"
|
||||
" (or physical size, with -p) larger than this will be printed."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--physical-sort",
|
||||
dest="sortByOnDiskSize",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Sort by the on-disk size. Default is to sort by the pack size.",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
print('Caught Ctrl-C. Exiting.')
|
||||
def signal_handler(_signal, _frame):
|
||||
print("Caught Ctrl-C. Exiting.")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# Default function is main()
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -41,6 +41,7 @@ LOOP=0
|
||||
SLEEP=1
|
||||
TIMEOUT=5
|
||||
|
||||
# Display usage information and options
|
||||
usage()
|
||||
{
|
||||
echo "Usage: $0 [--loop|--forever] [--sleep=N] hostname1 hostname2 ..."
|
||||
|
||||
@@ -39,16 +39,19 @@ log_error()
|
||||
{
|
||||
echo -e "${RED}ERROR:${NC} $1" >&2
|
||||
}
|
||||
# Log a warning message
|
||||
log_warn()
|
||||
{
|
||||
echo -e "${YELLOW}WARN:${NC} $1" >&2
|
||||
}
|
||||
# Log an informational message
|
||||
log_info()
|
||||
{
|
||||
if [[ "${INFO:-0}" == "1" ]]; then
|
||||
echo -e "${GREEN}INFO:${NC} $1" >&2
|
||||
fi
|
||||
}
|
||||
# Log a debug message
|
||||
log_debug()
|
||||
{
|
||||
if [[ "${DEBUG:-0}" == "1" ]]; then
|
||||
|
||||
@@ -49,16 +49,19 @@ log_error()
|
||||
{
|
||||
echo -e "${RED}ERROR:${NC} $1" >&2
|
||||
}
|
||||
# Log a warning message
|
||||
log_warn()
|
||||
{
|
||||
echo -e "${YELLOW}WARN:${NC} $1" >&2
|
||||
}
|
||||
# Log an informational message
|
||||
log_info()
|
||||
{
|
||||
if [[ "${INFO:-0}" == "1" ]]; then
|
||||
echo -e "${GREEN}INFO:${NC} $1" >&2
|
||||
fi
|
||||
}
|
||||
# Log a debug message
|
||||
log_debug()
|
||||
{
|
||||
if [[ "${DEBUG:-0}" == "1" ]]; then
|
||||
@@ -467,24 +470,24 @@ EOF
|
||||
## Next Steps for LLM Analysis
|
||||
|
||||
1. **Validate against current code:**
|
||||
- Check if mentioned files and lines still match the reported issues
|
||||
- Verify issues are not already fixed in the current branch
|
||||
- Identify false positives and explain why they are false positives
|
||||
- Check if mentioned files and lines still match the reported issues
|
||||
- Verify issues are not already fixed in the current branch
|
||||
- Identify false positives and explain why they are false positives
|
||||
|
||||
2. **Prioritize fixes:**
|
||||
- Address BLOCKER and CRITICAL severity issues first
|
||||
- Group fixes by file to minimize context switching
|
||||
- Consider effort estimates when planning the fix order
|
||||
- Address BLOCKER and CRITICAL severity issues first
|
||||
- Group fixes by file to minimize context switching
|
||||
- Consider effort estimates when planning the fix order
|
||||
|
||||
3. **Group by file for implementation:**
|
||||
- Batch changes to the same file together
|
||||
- Consider dependencies between fixes
|
||||
- Plan atomic commits per logical change group
|
||||
- Batch changes to the same file together
|
||||
- Consider dependencies between fixes
|
||||
- Plan atomic commits per logical change group
|
||||
|
||||
4. **Track progress:**
|
||||
- Use todo lists and memory tools to track which issues are addressed
|
||||
- Mark false positives with clear reasoning
|
||||
- Verify fixes do not introduce new issues
|
||||
- Use todo lists and memory tools to track which issues are addressed
|
||||
- Mark false positives with clear reasoning
|
||||
- Verify fixes do not introduce new issues
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ get_state()
|
||||
# ERROR HANDLING AND CLEANUP
|
||||
# ============================================================================
|
||||
|
||||
# Clean up temporary files and handle exit
|
||||
cleanup()
|
||||
{
|
||||
exit_code=$?
|
||||
@@ -177,6 +178,7 @@ trap cleanup EXIT INT TERM
|
||||
# LOGGING FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
# Create audit directories and initialize log file
|
||||
setup_logging()
|
||||
{
|
||||
# Create all necessary directories
|
||||
@@ -197,6 +199,7 @@ setup_logging()
|
||||
} >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Log a message with timestamp and severity level
|
||||
log_message()
|
||||
{
|
||||
level="$1"
|
||||
@@ -225,6 +228,7 @@ log_message()
|
||||
# INPUT VALIDATION
|
||||
# ============================================================================
|
||||
|
||||
# Validate hostname format for SSH connection
|
||||
validate_hostname()
|
||||
{
|
||||
hostname="$1"
|
||||
@@ -244,6 +248,7 @@ validate_hostname()
|
||||
return 0
|
||||
}
|
||||
|
||||
# Validate username format for SSH connection
|
||||
validate_username()
|
||||
{
|
||||
username="$1"
|
||||
@@ -263,6 +268,7 @@ validate_username()
|
||||
return 0
|
||||
}
|
||||
|
||||
# Parse input file into validated host entries
|
||||
parse_host_list()
|
||||
{
|
||||
input_file="$1"
|
||||
@@ -309,6 +315,7 @@ parse_host_list()
|
||||
# SSH CONNECTION FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
# Execute SSH command with retry logic and key fallback
|
||||
ssh_with_retry()
|
||||
{
|
||||
host="$1"
|
||||
@@ -373,6 +380,7 @@ ssh_with_retry()
|
||||
return 1
|
||||
}
|
||||
|
||||
# Verify SSH connectivity to a host
|
||||
test_ssh_connectivity()
|
||||
{
|
||||
host="$1"
|
||||
@@ -392,6 +400,7 @@ test_ssh_connectivity()
|
||||
# SSH SECURITY AUDIT FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
# Audit SSH daemon configuration on a remote host
|
||||
check_sshd_config()
|
||||
{
|
||||
host="$1"
|
||||
@@ -451,6 +460,7 @@ check_sshd_config()
|
||||
# AUTOMATED UPDATES DETECTION
|
||||
# ============================================================================
|
||||
|
||||
# Check if automated security updates are enabled
|
||||
check_automated_updates()
|
||||
{
|
||||
host="$1"
|
||||
@@ -532,6 +542,7 @@ check_automated_updates()
|
||||
# PENDING REBOOT DETECTION
|
||||
# ============================================================================
|
||||
|
||||
# Detect if a remote host requires a reboot
|
||||
check_pending_reboot()
|
||||
{
|
||||
host="$1"
|
||||
@@ -602,6 +613,7 @@ check_pending_reboot()
|
||||
# REMEDIATION FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
# Create a timestamped backup of sshd_config
|
||||
backup_sshd_config()
|
||||
{
|
||||
host="$1"
|
||||
@@ -616,6 +628,7 @@ backup_sshd_config()
|
||||
" "$ssh_key"
|
||||
}
|
||||
|
||||
# Disable password authentication on a remote host
|
||||
disable_password_auth()
|
||||
{
|
||||
host="$1"
|
||||
@@ -668,6 +681,7 @@ ClientAliveCountMax 2
|
||||
# REPORTING FUNCTIONS
|
||||
# ============================================================================
|
||||
|
||||
# Generate CSV report from audit results
|
||||
generate_csv_report()
|
||||
{
|
||||
report_file="$1"
|
||||
@@ -693,6 +707,7 @@ generate_csv_report()
|
||||
done < "$HOSTS_LIST_FILE"
|
||||
}
|
||||
|
||||
# Display formatted audit summary to terminal
|
||||
display_summary()
|
||||
{
|
||||
printf '\n'
|
||||
@@ -743,6 +758,7 @@ display_summary()
|
||||
# MAIN AUDIT FUNCTION
|
||||
# ============================================================================
|
||||
|
||||
# Run all audit checks on a single host
|
||||
audit_host()
|
||||
{
|
||||
host_entry="$1"
|
||||
@@ -788,6 +804,7 @@ audit_host()
|
||||
# MAIN EXECUTION
|
||||
# ============================================================================
|
||||
|
||||
# Main entry point: parse args, run audits, generate report
|
||||
main()
|
||||
{
|
||||
input_file="${1:-}"
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
# <r> <g> <b> range from 0 to 255 inclusive.
|
||||
# The escape sequence ^[0m returns output to default
|
||||
|
||||
# Set terminal background to an RGB color
|
||||
setBackgroundColor()
|
||||
{
|
||||
echo -en "\x1b[48;2;$1;$2;$3""m"
|
||||
}
|
||||
|
||||
# Reset terminal output formatting
|
||||
resetOutput()
|
||||
{
|
||||
echo -en "\x1b[0m\n"
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Display usage information and options
|
||||
usage()
|
||||
{
|
||||
cat << EOF
|
||||
@@ -52,6 +53,7 @@ THUMB_SUFFIX="${THUMB_SUFFIX:-_thumb}"
|
||||
# List of MIME types supported by ImageMagick (adjust as needed)
|
||||
ALLOWED_MIMETYPES=("image/jpeg" "image/png" "image/gif" "image/bmp" "image/tiff" "image/webp")
|
||||
|
||||
# Verify ImageMagick is available
|
||||
check_magick_installed()
|
||||
{
|
||||
if ! command -v magick &> /dev/null; then
|
||||
@@ -60,6 +62,7 @@ check_magick_installed()
|
||||
fi
|
||||
}
|
||||
|
||||
# Verify mimetype command is available
|
||||
check_mimetype_installed()
|
||||
{
|
||||
if ! command -v mimetype &> /dev/null; then
|
||||
@@ -165,6 +168,7 @@ generate_thumbnails()
|
||||
done < <(find "$source_dir" -type f -print0)
|
||||
}
|
||||
|
||||
# Parse options, validate inputs, and generate thumbnails
|
||||
main()
|
||||
{
|
||||
parse_options "$@"
|
||||
|
||||
@@ -26,6 +26,7 @@ if [ "$#" -lt 2 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait until host stops responding to ping
|
||||
wait_for_host_down()
|
||||
{
|
||||
local host=$1
|
||||
@@ -37,6 +38,7 @@ wait_for_host_down()
|
||||
done
|
||||
}
|
||||
|
||||
# Wait for host to go down then execute command
|
||||
main()
|
||||
{
|
||||
local host=$1
|
||||
|
||||
@@ -30,6 +30,7 @@ if [ "$#" -lt 2 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract hostname from arguments, handling ssh shortcut
|
||||
get_host()
|
||||
{
|
||||
if [ "$1" = "ssh" ]; then
|
||||
@@ -39,6 +40,7 @@ get_host()
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait until host responds to ping
|
||||
wait_for_host()
|
||||
{
|
||||
local host=$1
|
||||
@@ -50,6 +52,7 @@ wait_for_host()
|
||||
done
|
||||
}
|
||||
|
||||
# Wait for host to come online then execute command
|
||||
main()
|
||||
{
|
||||
local host
|
||||
|
||||
Reference in New Issue
Block a user