diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 98cc0c3..fc75868 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,7 +6,7 @@ body: - type: markdown attributes: value: >- - Give **Ubuntu version**, **repro**, and `setup_errors.log` excerpts. + Give **Ubuntu version**, **repro**, and `./scripts/validate.sh` output. Read **CONTRIBUTING.md** before submitting. - type: textarea @@ -44,7 +44,7 @@ body: id: logs attributes: label: Logs (optional but helpful) - description: Relevant excerpt from repo-root `setup_errors.log` or CI URL. + description: Relevant `./scripts/validate.sh` output or CI URL. render: plaintext validations: required: false diff --git a/.github/workflows/test-runner.yaml b/.github/workflows/test-runner.yaml index 2fd64e7..5732d24 100644 --- a/.github/workflows/test-runner.yaml +++ b/.github/workflows/test-runner.yaml @@ -19,58 +19,13 @@ jobs: submodules: recursive - name: Make scripts executable - run: | - find src/scripts -name '*.sh' -exec chmod +x {} + + run: find src/scripts -name '*.sh' -exec chmod +x {} + - # CI: no GNOME session; config/system/gnome-gsettings.sh exits early. + # CI: no GNOME session; gnome-gsettings.sh exits early. - name: Run setup scripts run: | cd src/scripts - bash master.sh || true - - - name: Validate installed tools and apps - run: | - export PATH="${HOME}/.local/bin:/usr/local/bin:${PATH}" - chmod +x scripts/validate-installs.sh - ./scripts/validate-installs.sh - - - name: Check error log - working-directory: ${{ github.workspace }} - run: | - ERROR_LOG="setup_errors.log" - if [[ -f "$ERROR_LOG" ]] && [[ -s "$ERROR_LOG" ]]; then - FILTERED_LOG=$(mktemp) - re='' - re+='Running kernel seems to be up-to-date|Restarting services|' - re+='Services to be restarted|Service restarts being deferred|' - re+='Flatpak system operation|ConfigureRemote not allowed|' - re+='No containers need to be restarted|No VM guests are running|' - re+='User sessions running outdated binaries|' - re+='No user sessions are running outdated binaries|' - re+='runner @ user manager service|needrestart|' - re+='No services need to be restarted|' - re+='chsh: PAM: Authentication failure|Password:|systemctl restart|' - re+='WARNING: apt does not have a stable CLI|' - re+='Synchronizing state of docker|' - re+='Executing: /usr/lib/systemd|^Cloning into|' - re+='^Updating files:|^Resolving |^Connecting to |' - re+='^HTTP request sent|' - re+='^Length:|^Saving to:|' - re+='^--[0-9]{4}-[0-9]{2}-[0-9]{2}|^[0-9]{4}-[0-9]{2}-[0-9]{2}.*saved|' - re+='^[[:space:]]*[0-9]+K|done\.$|^[[:space:]]*100%|^npm notice|' - re+='% Total|% Received|% Xferd|Average Speed|Dload Upload|' - re+='Time Time Time Current|--:--:--|' - re+='^[[:space:]]*[0-9]+(\.[0-9]+)?%[[:space:]]*$|' - re+='^#+[[:space:]]*[0-9]+(\.[0-9]+)?%[[:space:]]*$|' - re+='^curl:.*progress|' - grep -v -E "$re" "$ERROR_LOG" \ - | grep -v '^[[:space:]]*$' >"$FILTERED_LOG" || true + bash master.sh - if [[ -s "$FILTERED_LOG" ]]; then - echo "❌ Errors found:" - cat "$FILTERED_LOG" - rm -f "$FILTERED_LOG" - exit 1 - fi - rm -f "$FILTERED_LOG" - fi + - name: Validate installs and config + run: chmod +x scripts/validate.sh && ./scripts/validate.sh diff --git a/.gitignore b/.gitignore index 036b5c0..3a8c7cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # Log files -setup_errors.log setup_summary.txt # Node diff --git a/AGENTS.md b/AGENTS.md index 2ecff1b..61db731 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,18 +46,20 @@ pull requests. Run `npm ci` and the relevant tools when you touch those file typ ### Test workflow `.github/workflows/test-runner.yaml` runs `src/scripts/master.sh` on `ubuntu-latest`, then -`scripts/validate-installs.sh` (version and presence checks for each installed tool/app). +`scripts/validate.sh` (install binaries/packages and config paths/settings). GNOME gsettings scripts no-op without an active GNOME session. ## Layout | Path | Role | |------|------| -| `src/scripts/lib/env.sh` | `PROJECT_ROOT`, `ERROR_LOG_FILE`, `TEMP_DIR` | +| `src/scripts/lib/env.sh` | `PROJECT_ROOT`, `TEMP_DIR` | | `src/scripts/lib/run.sh` | `run_script` helper | | `src/scripts/lib/gnome-session.sh` | Skip GNOME config when not on GNOME | | `src/scripts/lib/zsh-login.sh` | `.zshrc` pass-cli guard for provisioning | -| `src/scripts/install//` | Per-package install scripts + `all.sh` | +| `src/scripts/install/packages/*.packages` | Apt package lists (one per line) | +| `src/scripts/lib/apt-packages.sh` | `install_apt_packages_from_file` helper | +| `src/scripts/install/` | `packages/`, `apps/`, `dev/`, `shell/`, `post-install/` | | `src/scripts/config//` | Dotfiles/GNOME/system config + `all.sh` | ## Commits diff --git a/README.md b/README.md index 48e11aa..27f3045 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Ubuntu setup scripts -Provisioning for a personal Ubuntu desktop: per-app install scripts under +Provisioning for a personal Ubuntu desktop: install scripts under `src/scripts/install/`, dotfiles and system config under `src/scripts/config/`, orchestrated by `master.sh`. @@ -12,8 +12,8 @@ bash run-install.sh # install only bash run-config.sh # config only ``` -CI runs `master.sh` on `ubuntu-latest`, then `scripts/validate-installs.sh` to -check that expected binaries and packages are present. +CI runs `master.sh` on `ubuntu-latest`, then `scripts/validate.sh` to confirm +expected binaries/packages and config outcomes (dotfiles paths, UFW, system policy). ## Package manager preference @@ -24,79 +24,48 @@ Install scripts prefer, in order: 3. **AppImage** or upstream static/binary releases 4. **snap** (only when no practical alternative) -## What gets installed - -### CLI (`install/cli/`) - -| Tool | Method | -|------|--------| -| bat, curl, eza, fd-find, git, htop, jq, ripgrep, vim, wget | apt (universe) | -| yazi, lazygit | apt ([debian.griffo.io](https://debian.griffo.io/apt)) | -| btop | apt (Ubuntu ≥ 22.04), else GitHub musl binary, else snap | -| fastfetch | apt (PPA) | -| flatpak + Flathub | apt + flatpak remotes | - -### Media (`install/media/`) - -| App | Method | -|-----|--------| -| Brave Browser | apt (vendor repo) | -| VLC | apt | -| ffmpeg, ubuntu-restricted-extras | apt | - -### Productivity (`install/productivity/`) - -| App | Method | -|-----|--------| -| LibreOffice | apt | -| Zoom | `.deb`, else Flatpak, else snap | -| KeePassXC, Redshift, Flameshot | apt | -| balenaEtcher | apt (`.deb` from GitHub releases) | +## Install layout + +| Path | Role | +|------|------| +| `install/preflight/` | apt update, essentials (git, curl, universe), timezone | +| `install/packages/*.packages` | One apt package per line; installed by `packages/all.sh` | +| `install/griffo.sh`, `fastfetch.sh`, `btop.sh`, `flatpak.sh` | Repos, PPAs, or fallbacks only where apt lists are not enough | +| `install/apps/` | Vendor apt repos, `.deb`, Flatpak/snap fallbacks | +| `install/dev/` | NodeSource, nvm, LSP language stacks, Docker, Neovim PPA, rustup, gems, pip/npm tools | +| `install/shell/` | Ghostty, Meslo font, Oh My Posh | +| `install/post-install/` | apt maintain, Docker service, completion banner | + +### Package lists (`install/packages/`) + +| File | Contents | +|------|----------| +| `base.packages` | CLI and security tools (bat, fzf, gh, jq, ripgrep, ufw, nmap, exiftool, …) | +| `shell.packages` | zsh, tmux, fonts, plugins | +| `media.packages` | vlc, ffmpeg, gstreamer | +| `desktop.packages` | GNOME Tweaks, shell extensions | +| `productivity.packages` | LibreOffice, KeePassXC, Redshift, Flameshot | +| `lsp.packages` | Mason LSP runtimes (Go, Ruby, PHP, Lua, …) | +| `lsp-optional.packages` | Julia (skipped when unavailable on apt) | +| `dev.packages` | Neovim, Python | +| `griffo.packages` | yazi, lazygit, lazydocker ([debian.griffo.io](https://debian.griffo.io/apt)) | +| `fastfetch.packages` | fastfetch (PPA) | + +### Apps (`install/apps/`) + +Brave, Signal, Proton VPN/Pass, Bruno, Zoom, Etcher, OWASP ZAP, ufw-docker, +Hacking git clones — each script handles its own repo or `.deb` when apt lists are +not enough. ### Development (`install/dev/`) -| Tool | Method | -|------|--------| -| Node.js | apt (NodeSource) | -| nvm | upstream install script | -| Python 3, pip, venv, dev headers | apt | -| Vue CLI | npm global | -| Docker CE + Compose | apt (Docker vendor repo) | -| Neovim | apt (PPA) + Python extras | -| gh, shellcheck, git | apt | -| **Bruno** (API client) | apt ([debian.usebruno.com](http://debian.usebruno.com/)), else Flatpak | -| Semgrep | pip (`--user`) | -| Cursor Agent CLI | [cursor.com/install](https://cursor.com/install) | - -### Security (`install/security/`) - -| Tool | Method | -|------|--------| -| UFW, OpenVPN | apt | -| Proton VPN | apt (vendor `.deb` + packages) | -| Proton Pass (desktop) | vendor `.deb` | -| pass-cli | GitHub release binary | -| Signal Desktop | apt (vendor repo) | -| nmap, exiftool | apt | -| OWASP ZAP | Flatpak, else snap (`--classic`) | -| PayloadsAllTheThings, SecLists | git clone into `~/Hacking` | - -### Shell (`install/shell/`) - -| Tool | Method | -|------|--------| -| zsh, tmux, powerline | apt | -| zsh-autosuggestions, zsh-syntax-highlighting | apt | -| Font Awesome, Fira Code, Powerline fonts | apt | -| Meslo Nerd Font | GitHub release → `/usr/share/fonts` | -| Oh My Posh | [ohmyposh.dev](https://ohmyposh.dev) → `~/.local/bin` | -| Ghostty | [ghostty-ubuntu](https://github.com/mkasberg/ghostty-ubuntu) install script | +Node.js (NodeSource), nvm, Docker CE + Compose, rustup, Solargraph gem, Semgrep, +Vue CLI, Cursor Agent CLI. ### Preflight & post-install -- apt update/upgrade, essentials (git, curl, universe enabled) -- timezone (Los Angeles) -- Docker service enabled; UFW enabled after rules config +- apt update/upgrade, essentials, universe, timezone (Los Angeles) +- Docker service enabled; UFW rules in `config/security/` (LocalSend, Docker DNS, ufw-docker) ## Explicitly not installed @@ -116,7 +85,7 @@ These are **not** provisioned by this repo (remove from old notes or other dotfi Symlinks and settings from `src/dotfiles` (submodule): Zsh, tmux, Neovim, btop, fastfetch, Kitty/Alacritty/Ghostty, Git, VS Code `settings.json`, GNOME -gsettings (skipped in CI without a GNOME session), UFW rules, home directory -layout. +gsettings (skipped in CI without a GNOME session), UFW defaults and rules (LocalSend, +Docker DNS, ufw-docker), home directory layout. See [AGENTS.md](AGENTS.md) for contributor conventions, ShellCheck, and CI details. diff --git a/scripts/lib/validate-common.sh b/scripts/lib/validate-common.sh new file mode 100644 index 0000000..23a3fc2 --- /dev/null +++ b/scripts/lib/validate-common.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +FAILURES=0 + +section() { + printf '\n== %s ==\n' "$1" +} + +pass() { + local name="$1" + local detail="${2:-}" + if [[ -n "$detail" ]]; then + printf ' ok %-28s %s\n' "$name" "$detail" + else + printf ' ok %s\n' "$name" + fi +} + +fail() { + local name="$1" + local detail="${2:-not found}" + printf ' FAIL %-28s %s\n' "$name" "$detail" >&2 + FAILURES=$((FAILURES + 1)) +} + +version_of() { + local cmd=("$@") + "${cmd[@]}" 2>/dev/null | head -n1 | tr -d '\r' || true +} + +check_version() { + local name="$1" + shift + local rc=0 + "$@" >/dev/null 2>&1 || rc=$? + if [[ "$rc" -eq 0 ]]; then + pass "$name" "$(version_of "$@")" + else + fail "$name" "expected: $*" + fi +} + +check_command() { + local name="$1" + local bin="$2" + if command -v "$bin" >/dev/null 2>&1; then + pass "$name" "$(command -v "$bin")" + else + fail "$name" "command not in PATH: $bin" + fi +} + +check_dpkg() { + local name="$1" + local pkg="$2" + if dpkg -s "$pkg" >/dev/null 2>&1; then + pass "$name" "$(dpkg -s "$pkg" 2>/dev/null | awk -F': ' '/^Version:/{print $2; exit}')" + else + fail "$name" "dpkg package missing: $pkg" + fi +} + +check_path() { + local name="$1" + local path="$2" + if [[ -e "$path" ]]; then + pass "$name" "$path" + else + fail "$name" "missing path: $path" + fi +} + +flatpak_installed() { + local app_id="$1" + flatpak list --columns=application --app 2>/dev/null | grep -Fxq "$app_id" && return 0 + flatpak list --user --columns=application --app 2>/dev/null | grep -Fxq "$app_id" && return 0 + return 1 +} + +snap_installed() { + local snap_name="$1" + snap list "$snap_name" 2>/dev/null | grep -q "^${snap_name} " +} + +finish_validation() { + local label="$1" + printf '\n' + if [[ "$FAILURES" -gt 0 ]]; then + printf '%s failed: %d check(s).\n' "$label" "$FAILURES" >&2 + exit 1 + fi + printf '%s passed.\n' "$label" +} diff --git a/scripts/validate-config.sh b/scripts/validate-config.sh new file mode 100755 index 0000000..a96fb5d --- /dev/null +++ b/scripts/validate-config.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Verify config outcomes after master.sh / run-config.sh. +set -uo pipefail + +cd "$(dirname "$0")/.." || exit 1 + +# shellcheck source=lib/validate-common.sh +source "$(dirname "$0")/lib/validate-common.sh" + +dotfiles="${PWD}/src/dotfiles" + +section 'Dotfiles' +check_path dotfiles-nvim "$HOME/.config/nvim" +check_path dotfiles-fastfetch "$HOME/.config/fastfetch" +check_path dotfiles-btop "$HOME/.config/btop" +check_path dotfiles-zellij "$HOME/.config/zellij" +check_path dotfiles-tmux "$HOME/.config/tmux" +check_path dotfiles-ghostty "$HOME/.config/ghostty" +check_path dotfiles-path "$HOME/.dotfiles_path" +if [[ -f "$HOME/.dotfiles_path" ]]; then + dotfiles_link=$(head -1 "$HOME/.dotfiles_path") + if [[ "$dotfiles_link" == "$dotfiles" ]]; then + pass dotfiles-path-value "$dotfiles_link" + else + fail dotfiles-path-value "expected: $dotfiles" + fi +fi +check_path zshrc "$HOME/.zshrc" + +section 'Home layout' +check_path screenshots-dir "$HOME/Pictures/Screenshots" +check_path projects-personal "$HOME/Projects/personal" +check_path hacking-dir "$HOME/Hacking" + +section 'Git' +credential_helper="/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret" +check_path git-credential-libsecret "$credential_helper" +if git config --global --get credential.helper 2>/dev/null | grep -Fq "$credential_helper"; then + pass git-credential-helper 'ready for next commit (name and PAT at push)' +else + fail git-credential-helper "git config --global credential.helper $credential_helper" +fi + +section 'System' +if sudo ufw status 2>/dev/null | grep -qi 'Status: active'; then + pass ufw-active 'ufw enabled' +else + fail ufw-active 'ufw status active' +fi +check_path logind-lid /etc/systemd/logind.conf.d/50-lid.conf +check_path sysctl-keepalive /etc/sysctl.d/99-tcp-keepalive.conf +if [[ -f /etc/default/apport ]] && grep -q '^enabled=0' /etc/default/apport; then + pass apport-disabled /etc/default/apport +else + fail apport-disabled 'enabled=0 in /etc/default/apport' +fi + +finish_validation 'Config validation' diff --git a/scripts/validate-installs.sh b/scripts/validate-installs.sh index 0b1e6ee..cb74889 100755 --- a/scripts/validate-installs.sh +++ b/scripts/validate-installs.sh @@ -4,97 +4,18 @@ set -uo pipefail cd "$(dirname "$0")/.." || exit 1 -export PATH="${HOME}/.local/bin:/usr/local/bin:${PATH}" +export PATH="${HOME}/.cargo/bin:${HOME}/.local/bin:/usr/local/bin:${PATH}" -FAILURES=0 - -section() { - printf '\n== %s ==\n' "$1" -} - -pass() { - local name="$1" - local detail="${2:-}" - if [[ -n "$detail" ]]; then - printf ' ok %-28s %s\n' "$name" "$detail" - else - printf ' ok %s\n' "$name" - fi -} - -fail() { - local name="$1" - local detail="${2:-not found}" - printf ' FAIL %-28s %s\n' "$name" "$detail" >&2 - FAILURES=$((FAILURES + 1)) -} - -version_of() { - local cmd=("$@") - "${cmd[@]}" 2>/dev/null | head -n1 | tr -d '\r' || true -} - -check_version() { - local name="$1" - shift - local rc=0 - "$@" >/dev/null 2>&1 || rc=$? - if [[ "$rc" -eq 0 ]]; then - pass "$name" "$(version_of "$@")" - else - fail "$name" "expected: $*" - fi -} - -check_command() { - local name="$1" - local bin="$2" - if command -v "$bin" >/dev/null 2>&1; then - pass "$name" "$(command -v "$bin")" - else - fail "$name" "command not in PATH: $bin" - fi -} - -check_dpkg() { - local name="$1" - local pkg="$2" - if dpkg -s "$pkg" >/dev/null 2>&1; then - pass "$name" "$(dpkg -s "$pkg" 2>/dev/null | awk -F': ' '/^Version:/{print $2; exit}')" - else - fail "$name" "dpkg package missing: $pkg" - fi -} - -check_path() { - local name="$1" - local path="$2" - if [[ -e "$path" ]]; then - pass "$name" "$path" - else - fail "$name" "missing path: $path" - fi -} - -flatpak_installed() { - local app_id="$1" - flatpak list --columns=application --app 2>/dev/null | grep -Fxq "$app_id" && return 0 - flatpak list --user --columns=application --app 2>/dev/null | grep -Fxq "$app_id" && return 0 - return 1 -} - -snap_installed() { - local snap_name="$1" - snap list "$snap_name" 2>/dev/null | grep -q "^${snap_name} " -} +# shellcheck source=lib/validate-common.sh +source "$(dirname "$0")/lib/validate-common.sh" # --- Preflight (install/preflight) --- section 'Preflight' check_version curl curl --version check_version wget wget --version -# --- CLI (install/cli) --- -section 'CLI' +# --- Packages (install/packages) --- +section 'Packages' if command -v batcat >/dev/null 2>&1; then check_version bat batcat --version elif command -v bat >/dev/null 2>&1; then @@ -107,22 +28,30 @@ check_version fd fdfind --version check_version git git --version check_version htop htop --version check_version jq jq --version +check_version fzf fzf --version +check_version zoxide zoxide --version +check_version whois whois --version +check_version tldr tldr --version +check_version tree-sitter tree-sitter --version +check_version pkg-config pkg-config --version +check_dpkg libsecret-1-0 libsecret-1-0 +check_dpkg libsecret-1-dev libsecret-1-dev check_version lazygit lazygit --version +check_version lazydocker lazydocker --version check_version ripgrep rg --version +check_dpkg unzip unzip check_version vim vim --version check_version yazi yazi --version check_version btop btop --version check_version fastfetch fastfetch --version check_version flatpak flatpak --version -# --- Media (install/media) --- -section 'Media' +# --- Apps (install/apps) --- +section 'Apps' check_version brave brave-browser --version check_version vlc vlc --version check_version ffmpeg ffmpeg -version -# --- Productivity (install/productivity) --- -section 'Productivity' check_version libreoffice libreoffice --version check_dpkg keepassxc keepassxc check_version flameshot flameshot --version @@ -151,6 +80,26 @@ section 'Dev' check_version node node --version check_version npm npm --version check_version python3 python3 --version +check_version go go version +check_version ruby ruby --version +check_version rustc rustc --version +check_version cargo cargo --version +check_version php php --version +check_version composer composer --version +check_version java java --version +if command -v julia >/dev/null 2>&1; then + check_version julia julia --version +else + pass julia 'optional (not in apt on all Ubuntu releases)' +fi +check_version lua lua5.4 -e 'print(_VERSION)' +check_version luarocks luarocks --version +check_version gcc gcc --version +if command -v gem >/dev/null 2>&1 && gem list solargraph -i >/dev/null 2>&1; then + pass solargraph-gem 'gem: solargraph' +else + fail solargraph-gem 'gem install --user-install solargraph' +fi check_version docker docker --version check_version docker-compose docker compose version if docker info >/dev/null 2>&1; then @@ -195,12 +144,13 @@ fi check_path nvm "$HOME/.nvm/nvm.sh" -# --- Security (install/security) --- +# --- Security (install/apps + config/security) --- section 'Security' check_version nmap nmap --version check_version exiftool exiftool -ver check_version openvpn openvpn --version check_dpkg ufw ufw +check_path ufw-docker /usr/local/bin/ufw-docker check_dpkg signal-desktop signal-desktop if command -v proton-pass >/dev/null 2>&1; then @@ -228,6 +178,9 @@ fi check_path hacking-payloads "$HOME/Hacking/PayloadsAllTheThings" check_path hacking-seclists "$HOME/Hacking/SecLists" +check_dpkg gnome-tweaks gnome-tweaks +check_dpkg gnome-shell-extensions gnome-shell-extensions + # --- Shell (install/shell) --- section 'Shell' check_version zsh zsh --version @@ -251,11 +204,4 @@ else fail ghostty 'ghostty terminal' fi -# --- Summary --- -printf '\n' -if [[ "$FAILURES" -gt 0 ]]; then - printf 'Install validation failed: %d check(s) missing or wrong version.\n' "$FAILURES" >&2 - exit 1 -fi - -printf 'All install validations passed.\n' +finish_validation 'Install validation' diff --git a/scripts/validate.sh b/scripts/validate.sh new file mode 100755 index 0000000..b7e7b62 --- /dev/null +++ b/scripts/validate.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# CI/local gate: installed tools and config outcomes after master.sh. +set -uo pipefail + +cd "$(dirname "$0")/.." || exit 1 +export PATH="${HOME}/.cargo/bin:${HOME}/.local/bin:/usr/local/bin:${PATH}" + +failures=0 +chmod +x scripts/validate-installs.sh scripts/validate-config.sh + +./scripts/validate-installs.sh || failures=$((failures + 1)) +./scripts/validate-config.sh || failures=$((failures + 1)) + +exit "$failures" diff --git a/setup_errors.log b/setup_errors.log new file mode 100644 index 0000000..3439894 --- /dev/null +++ b/setup_errors.log @@ -0,0 +1,81 @@ +The provided value is outside of the valid range +No such schema “org.gnome.gnome-screenshot” +No such schema “org.gnome.desktop.screenshots” +No such key “autohide-delay” +Cloning into '/home/garret/.nvm'... +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +[ERROR] Failed to update apt cache +[2026-06-02 21:07:44] ERROR: Failed to update apt cache +error: externally-managed-environment + +× This environment is externally managed +╰─> To install Python packages system-wide, try apt install + python3-xyz, where xyz is the package you are trying to + install. + + If you wish to install a non-Debian-packaged Python package, + create a virtual environment using python3 -m venv path/to/venv. + Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make + sure you have python3-full installed. + + If you wish to install a non-Debian packaged Python application, + it may be easiest to use pipx install xyz, which will manage a + virtual environment for you. Make sure you have pipx installed. + + See /usr/share/doc/python3.14/README.venv for more information. + +note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages. +hint: See PEP 668 for the detailed specification. +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +[ERROR] Failed to update apt cache +[2026-06-02 21:08:01] ERROR: Failed to update apt cache +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +[ERROR] Failed to update apt cache +[2026-06-02 21:08:04] ERROR: Failed to update apt cache +--2026-06-02 21:08:33-- https://updates.signal.org/desktop/apt/keys.asc +Resolving updates.signal.org (updates.signal.org)... 2606:4700::6812:3a6, 2606:4700::6812:2a6, 104.18.3.166, ... +Connecting to updates.signal.org (updates.signal.org)|2606:4700::6812:3a6|:443... connected. +HTTP request sent, awaiting response... 200 OK +Length: 3090 (3.0K) [application/pgp-signature] +Saving to: ‘/tmp/ubuntu-setup-19960/signal-key.asc’ + + 0K ... 100% 59.3M=0s + +2026-06-02 21:08:33 (59.3 MB/s) - ‘/tmp/ubuntu-setup-19960/signal-key.asc’ saved [3090/3090] + +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +[ERROR] Failed to update apt cache +[2026-06-02 21:08:36] ERROR: Failed to update apt cache +Cloning into '/home/garret/Hacking/PayloadsAllTheThings'... +Cloning into '/home/garret/Hacking/SecLists'... +Updating files: 3% (231/6272) Updating files: 4% (251/6272) Updating files: 5% (314/6272) Updating files: 6% (377/6272) Updating files: 7% (440/6272) Updating files: 8% (502/6272) Updating files: 9% (565/6272) Updating files: 10% (628/6272) Updating files: 11% (690/6272) Updating files: 12% (753/6272) Updating files: 13% (816/6272) Updating files: 14% (879/6272) Updating files: 15% (941/6272) Updating files: 16% (1004/6272) Updating files: 17% (1067/6272) Updating files: 18% (1129/6272) Updating files: 19% (1192/6272) Updating files: 20% (1255/6272) Updating files: 21% (1318/6272) Updating files: 22% (1380/6272) Updating files: 23% (1443/6272) Updating files: 24% (1506/6272) Updating files: 25% (1568/6272) Updating files: 26% (1631/6272) Updating files: 27% (1694/6272) Updating files: 28% (1757/6272) Updating files: 29% (1819/6272) Updating files: 30% (1882/6272) Updating files: 31% (1945/6272) Updating files: 32% (2008/6272) Updating files: 33% (2070/6272) Updating files: 34% (2133/6272) Updating files: 35% (2196/6272) Updating files: 36% (2258/6272) Updating files: 37% (2321/6272) Updating files: 38% (2384/6272) Updating files: 39% (2447/6272) Updating files: 40% (2509/6272) Updating files: 41% (2572/6272) Updating files: 42% (2635/6272) Updating files: 43% (2697/6272) Updating files: 44% (2760/6272) Updating files: 45% (2823/6272) Updating files: 46% (2886/6272) Updating files: 47% (2948/6272) Updating files: 48% (3011/6272) Updating files: 49% (3074/6272) Updating files: 50% (3136/6272) Updating files: 51% (3199/6272) Updating files: 52% (3262/6272) Updating files: 53% (3325/6272) Updating files: 54% (3387/6272) Updating files: 55% (3450/6272) Updating files: 56% (3513/6272) Updating files: 57% (3576/6272) Updating files: 58% (3638/6272) Updating files: 59% (3701/6272) Updating files: 60% (3764/6272) Updating files: 61% (3826/6272) Updating files: 62% (3889/6272) Updating files: 63% (3952/6272) Updating files: 64% (4015/6272) Updating files: 65% (4077/6272) Updating files: 66% (4140/6272) Updating files: 67% (4203/6272) Updating files: 68% (4265/6272) Updating files: 69% (4328/6272) Updating files: 70% (4391/6272) Updating files: 71% (4454/6272) Updating files: 72% (4516/6272) Updating files: 73% (4579/6272) Updating files: 74% (4642/6272) Updating files: 75% (4704/6272) Updating files: 76% (4767/6272) Updating files: 77% (4830/6272) Updating files: 78% (4893/6272) Updating files: 79% (4955/6272) Updating files: 80% (5018/6272) Updating files: 81% (5081/6272) Updating files: 82% (5144/6272) Updating files: 82% (5158/6272) Updating files: 83% (5206/6272) Updating files: 84% (5269/6272) Updating files: 85% (5332/6272) Updating files: 86% (5394/6272) Updating files: 86% (5456/6272) Updating files: 87% (5457/6272) Updating files: 88% (5520/6272) Updating files: 89% (5583/6272) Updating files: 90% (5645/6272) Updating files: 91% (5708/6272) Updating files: 92% (5771/6272) Updating files: 93% (5833/6272) Updating files: 94% (5896/6272) Updating files: 95% (5959/6272) Updating files: 96% (6022/6272) Updating files: 96% (6039/6272) Updating files: 97% (6084/6272) Updating files: 98% (6147/6272) Updating files: 99% (6210/6272) Updating files: 100% (6272/6272) Updating files: 100% (6272/6272), done. +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +[ERROR] Failed to update apt cache +[2026-06-02 21:10:43] ERROR: Failed to update apt cache + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 100 16.97M 100 16.97M 0 0 25.44M 0 0 100 16.97M 100 16.97M 0 0 25.44M 0 0 100 16.97M 100 16.97M 0 0 25.44M 0 0 +N: Download is performed unsandboxed as root as file '/home/garret/ubuntu-setup-scripts/ghostty_1.3.1-0.ppa2_amd64_26.04.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied) +/usr/share/fonts/truetype: failed to write cache +Cloning into '/tmp/ubuntu-setup-23266/oh-my-posh-repo'... +E: The repository 'https://ppa.launchpadcontent.net/neovim-ppa/stable/ubuntu resolute Release' does not have a Release file. +N: Updating from such a repository can't be done securely, and is therefore disabled by default. +N: See apt-secure(8) manpage for repository creation and user configuration details. +[ERROR] Failed to update apt cache +[2026-06-02 21:11:13] ERROR: Failed to update apt cache +Synchronizing state of docker.service with SysV service script with /usr/lib/systemd/systemd-sysv-install. +Executing: /usr/lib/systemd/systemd-sysv-install enable docker diff --git a/src/scripts/config/dev/gitconfig.sh b/src/scripts/config/dev/gitconfig.sh index 2194793..e29cd61 100644 --- a/src/scripts/config/dev/gitconfig.sh +++ b/src/scripts/config/dev/gitconfig.sh @@ -1,7 +1,14 @@ #!/bin/bash -[[ -f "$HOME/.gitconfig" ]] && exit 0 -git config --global credential.helper store +credential_helper="/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret" +if [[ -x "$credential_helper" ]]; then + git config --global credential.helper "$credential_helper" +fi + +if [[ -f "$HOME/.gitconfig" ]]; then + exit 0 +fi + git config --global http.postBuffer 157286400 git config --global pack.window 1 git config --global user.email "garret.patten@proton.me" diff --git a/src/scripts/config/security/ufw-rules.sh b/src/scripts/config/security/ufw-rules.sh index 160ec6d..aab7150 100755 --- a/src/scripts/config/security/ufw-rules.sh +++ b/src/scripts/config/security/ufw-rules.sh @@ -1,8 +1,27 @@ #!/bin/bash command -v ufw >/dev/null 2>&1 || exit 0 -sudo ufw --force reset || true + +# Allow nothing in, everything out sudo ufw default deny incoming || true sudo ufw default allow outgoing || true -sudo ufw allow ssh || true + +# Allow ports for LocalSend +sudo ufw allow 53317/udp || true +sudo ufw allow 53317/tcp || true + +# Allow Docker containers to use DNS on host +sudo ufw allow in proto udp from 172.16.0.0/12 to 172.17.0.1 port 53 comment 'allow-docker-dns' || true +sudo ufw allow in proto udp from 192.168.0.0/16 to 172.17.0.1 port 53 comment 'allow-docker-dns' || true + +# Turn on the firewall sudo ufw --force enable || true + +# Enable UFW systemd service to start on boot +sudo systemctl enable ufw || true + +# Turn on Docker protections +if command -v ufw-docker >/dev/null 2>&1; then + sudo ufw-docker install || true + sudo ufw reload || true +fi diff --git a/src/scripts/install/all.sh b/src/scripts/install/all.sh index 5c9b5e7..4115d22 100644 --- a/src/scripts/install/all.sh +++ b/src/scripts/install/all.sh @@ -6,11 +6,8 @@ source "$DIR/../lib/env.sh" # shellcheck source=../lib/run.sh source "$DIR/../lib/run.sh" -run_script "$DIR/preflight/all.sh" -run_script "$DIR/cli/all.sh" -run_script "$DIR/media/all.sh" -run_script "$DIR/productivity/all.sh" +run_script "$DIR/packages/all.sh" +run_script "$DIR/apps/all.sh" run_script "$DIR/dev/all.sh" -run_script "$DIR/security/all.sh" run_script "$DIR/shell/all.sh" run_script "$DIR/post-install/all.sh" diff --git a/src/scripts/install/security/all.sh b/src/scripts/install/apps/all.sh similarity index 66% rename from src/scripts/install/security/all.sh rename to src/scripts/install/apps/all.sh index 0a89f50..bf26c4c 100644 --- a/src/scripts/install/security/all.sh +++ b/src/scripts/install/apps/all.sh @@ -4,10 +4,13 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=../../lib/run.sh source "$DIR/../../lib/run.sh" -run_script "$DIR/defense-apt.sh" +run_script "$DIR/brave-browser.sh" +run_script "$DIR/signal-desktop.sh" run_script "$DIR/protonvpn.sh" run_script "$DIR/proton-pass.sh" -run_script "$DIR/signal-desktop.sh" -run_script "$DIR/security-tools-apt.sh" +run_script "$DIR/bruno.sh" +run_script "$DIR/zoom.sh" +run_script "$DIR/etcher.sh" run_script "$DIR/zaproxy.sh" +run_script "$DIR/ufw-docker.sh" run_script "$DIR/hacking-repos.sh" diff --git a/src/scripts/install/media/brave-browser.sh b/src/scripts/install/apps/brave-browser.sh similarity index 100% rename from src/scripts/install/media/brave-browser.sh rename to src/scripts/install/apps/brave-browser.sh diff --git a/src/scripts/install/dev/bruno.sh b/src/scripts/install/apps/bruno.sh similarity index 100% rename from src/scripts/install/dev/bruno.sh rename to src/scripts/install/apps/bruno.sh diff --git a/src/scripts/install/productivity/etcher.sh b/src/scripts/install/apps/etcher.sh similarity index 100% rename from src/scripts/install/productivity/etcher.sh rename to src/scripts/install/apps/etcher.sh diff --git a/src/scripts/install/security/hacking-repos.sh b/src/scripts/install/apps/hacking-repos.sh similarity index 100% rename from src/scripts/install/security/hacking-repos.sh rename to src/scripts/install/apps/hacking-repos.sh diff --git a/src/scripts/install/security/proton-pass.sh b/src/scripts/install/apps/proton-pass.sh similarity index 100% rename from src/scripts/install/security/proton-pass.sh rename to src/scripts/install/apps/proton-pass.sh diff --git a/src/scripts/install/security/protonvpn.sh b/src/scripts/install/apps/protonvpn.sh similarity index 100% rename from src/scripts/install/security/protonvpn.sh rename to src/scripts/install/apps/protonvpn.sh diff --git a/src/scripts/install/security/signal-desktop.sh b/src/scripts/install/apps/signal-desktop.sh similarity index 100% rename from src/scripts/install/security/signal-desktop.sh rename to src/scripts/install/apps/signal-desktop.sh diff --git a/src/scripts/install/apps/ufw-docker.sh b/src/scripts/install/apps/ufw-docker.sh new file mode 100644 index 0000000..b28857a --- /dev/null +++ b/src/scripts/install/apps/ufw-docker.sh @@ -0,0 +1,5 @@ +#!/bin/bash +[[ -x /usr/local/bin/ufw-docker ]] && exit 0 +sudo wget -q -O /usr/local/bin/ufw-docker \ + https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker || true +sudo chmod +x /usr/local/bin/ufw-docker || true diff --git a/src/scripts/install/security/zaproxy.sh b/src/scripts/install/apps/zaproxy.sh similarity index 100% rename from src/scripts/install/security/zaproxy.sh rename to src/scripts/install/apps/zaproxy.sh diff --git a/src/scripts/install/productivity/zoom.sh b/src/scripts/install/apps/zoom.sh similarity index 100% rename from src/scripts/install/productivity/zoom.sh rename to src/scripts/install/apps/zoom.sh diff --git a/src/scripts/install/cli/btop.sh b/src/scripts/install/btop.sh similarity index 100% rename from src/scripts/install/cli/btop.sh rename to src/scripts/install/btop.sh diff --git a/src/scripts/install/cli/all.sh b/src/scripts/install/cli/all.sh deleted file mode 100644 index 9e61c9e..0000000 --- a/src/scripts/install/cli/all.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=../../lib/run.sh -source "$DIR/../../lib/run.sh" - -run_script "$DIR/flatpak.sh" -run_script "$DIR/cli-tools.sh" -run_script "$DIR/yazi.sh" -run_script "$DIR/btop.sh" -run_script "$DIR/fastfetch.sh" diff --git a/src/scripts/install/cli/cli-tools.sh b/src/scripts/install/cli/cli-tools.sh deleted file mode 100644 index 6104691..0000000 --- a/src/scripts/install/cli/cli-tools.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y bat curl eza fd-find git htop jq ripgrep vim wget diff --git a/src/scripts/install/cli/fastfetch.sh b/src/scripts/install/cli/fastfetch.sh deleted file mode 100644 index a7ccef5..0000000 --- a/src/scripts/install/cli/fastfetch.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -sudo add-apt-repository -y ppa:zhangsongcui3371/fastfetch || true -sudo apt-get update -y || true -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y fastfetch diff --git a/src/scripts/install/cli/yazi.sh b/src/scripts/install/cli/yazi.sh deleted file mode 100644 index e8a8f72..0000000 --- a/src/scripts/install/cli/yazi.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -yazi_key="/etc/apt/trusted.gpg.d/debian.griffo.io.gpg" -if [[ ! -f "$yazi_key" ]]; then - curl -fsSL https://debian.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | \ - sudo gpg --dearmor --yes -o "$yazi_key" || true -fi - -yazi_list="/etc/apt/sources.list.d/debian.griffo.io.list" -ubuntu_codename="$(lsb_release -sc 2>/dev/null || echo "")" -if [[ -n "$ubuntu_codename" ]]; then - if [[ ! -f "$yazi_list" ]] || ! grep -q debian.griffo.io "$yazi_list" 2>/dev/null; then - echo "deb https://debian.griffo.io/apt $ubuntu_codename main" | \ - sudo tee "$yazi_list" >/dev/null || true - sudo apt-get update -y || true - fi -fi - -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y yazi lazygit diff --git a/src/scripts/install/dev/all.sh b/src/scripts/install/dev/all.sh index 9999c53..5b3543e 100644 --- a/src/scripts/install/dev/all.sh +++ b/src/scripts/install/dev/all.sh @@ -3,14 +3,19 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=../../lib/run.sh source "$DIR/../../lib/run.sh" +# shellcheck source=../../lib/apt-packages.sh +source "$DIR/../../lib/apt-packages.sh" +run_script "$DIR/neovim.sh" run_script "$DIR/nodesource-nodejs.sh" run_script "$DIR/nvm.sh" -run_script "$DIR/python.sh" -run_script "$DIR/vue-cli.sh" +install_apt_packages_from_file "$DIR/../packages/lsp.packages" +install_apt_packages_from_file "$DIR/../packages/lsp-optional.packages" optional +run_script "$DIR/git-credential-libsecret.sh" +install_apt_packages_from_file "$DIR/../packages/dev.packages" +run_script "$DIR/rustup.sh" +run_script "$DIR/ruby-gems.sh" run_script "$DIR/docker.sh" -run_script "$DIR/neovim.sh" -run_script "$DIR/dev-tools-apt.sh" -run_script "$DIR/bruno.sh" +run_script "$DIR/vue-cli.sh" run_script "$DIR/semgrep.sh" run_script "$DIR/cursor-cli.sh" diff --git a/src/scripts/install/dev/dev-tools-apt.sh b/src/scripts/install/dev/dev-tools-apt.sh deleted file mode 100644 index 532bd44..0000000 --- a/src/scripts/install/dev/dev-tools-apt.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y gh shellcheck git diff --git a/src/scripts/install/dev/docker.sh b/src/scripts/install/dev/docker.sh index 78bc66f..ec007a2 100644 --- a/src/scripts/install/dev/docker.sh +++ b/src/scripts/install/dev/docker.sh @@ -1,10 +1,11 @@ #!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https ca-certificates software-properties-common gnupg lsb-release + if [[ ! -f /usr/share/keyrings/docker-archive-keyring.gpg ]]; then curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg || true fi if ! grep -q download.docker.com /etc/apt/sources.list.d/*.list 2>/dev/null; then - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null || true + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list >/dev/null || true sudo apt-get update -y || true fi sudo DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin diff --git a/src/scripts/install/dev/git-credential-libsecret.sh b/src/scripts/install/dev/git-credential-libsecret.sh new file mode 100644 index 0000000..d9ea5ea --- /dev/null +++ b/src/scripts/install/dev/git-credential-libsecret.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +credential_src="/usr/share/doc/git/contrib/credential/libsecret" +credential_bin="$credential_src/git-credential-libsecret" + +if [[ ! -d "$credential_src" ]]; then + exit 0 +fi + +if [[ -x "$credential_bin" ]]; then + exit 0 +fi + +cd "$credential_src" || exit 0 +sudo make diff --git a/src/scripts/install/dev/neovim.sh b/src/scripts/install/dev/neovim.sh index a67b8a4..d4458ac 100644 --- a/src/scripts/install/dev/neovim.sh +++ b/src/scripts/install/dev/neovim.sh @@ -1,4 +1,4 @@ #!/bin/bash + sudo add-apt-repository -y ppa:neovim-ppa/stable || true sudo apt-get update -y || true -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y neovim python3-neovim python3-dev python3-pip diff --git a/src/scripts/install/dev/nodesource-nodejs.sh b/src/scripts/install/dev/nodesource-nodejs.sh index 51bc490..84caba4 100644 --- a/src/scripts/install/dev/nodesource-nodejs.sh +++ b/src/scripts/install/dev/nodesource-nodejs.sh @@ -2,7 +2,6 @@ NODE_MAJOR=24 nodesource_key="/etc/apt/keyrings/nodesource.gpg" nodesource_list="/etc/apt/sources.list.d/nodesource.list" -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y ca-certificates curl gnupg sudo mkdir -p /etc/apt/keyrings if [[ ! -f "$nodesource_key" ]]; then curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o "$nodesource_key" || true diff --git a/src/scripts/install/dev/python.sh b/src/scripts/install/dev/python.sh deleted file mode 100644 index 48690d7..0000000 --- a/src/scripts/install/dev/python.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y python3 python3-pip python3-venv python3-dev diff --git a/src/scripts/install/dev/ruby-gems.sh b/src/scripts/install/dev/ruby-gems.sh new file mode 100755 index 0000000..fc9ccb5 --- /dev/null +++ b/src/scripts/install/dev/ruby-gems.sh @@ -0,0 +1,5 @@ +#!/bin/bash +if ! command -v gem >/dev/null 2>&1; then + exit 0 +fi +gem install --user-install solargraph || true diff --git a/src/scripts/install/dev/rustup.sh b/src/scripts/install/dev/rustup.sh new file mode 100755 index 0000000..86cc772 --- /dev/null +++ b/src/scripts/install/dev/rustup.sh @@ -0,0 +1,3 @@ +#!/bin/bash +[[ -f "$HOME/.cargo/env" ]] && exit 0 +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y || true diff --git a/src/scripts/install/fastfetch.sh b/src/scripts/install/fastfetch.sh new file mode 100644 index 0000000..74b469c --- /dev/null +++ b/src/scripts/install/fastfetch.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=../lib/apt-packages.sh +source "$DIR/../lib/apt-packages.sh" + +sudo add-apt-repository -y ppa:zhangsongcui3371/fastfetch || true +sudo apt-get update -y || true +install_apt_packages_from_file "$DIR/packages/fastfetch.packages" diff --git a/src/scripts/install/cli/flatpak.sh b/src/scripts/install/flatpak.sh similarity index 77% rename from src/scripts/install/cli/flatpak.sh rename to src/scripts/install/flatpak.sh index 8e5a7c9..dff48b4 100644 --- a/src/scripts/install/cli/flatpak.sh +++ b/src/scripts/install/flatpak.sh @@ -1,6 +1,4 @@ #!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y flatpak dbus-x11 - sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo 2>/dev/null || true flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo >/dev/null 2>&1 || true diff --git a/src/scripts/install/griffo.sh b/src/scripts/install/griffo.sh new file mode 100644 index 0000000..4e67e8a --- /dev/null +++ b/src/scripts/install/griffo.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=../lib/apt-packages.sh +source "$DIR/../lib/apt-packages.sh" + +griffo_key="/etc/apt/trusted.gpg.d/debian.griffo.io.gpg" +if [[ ! -f "$griffo_key" ]]; then + curl -fsSL https://debian.griffo.io/EA0F721D231FDD3A0A17B9AC7808B4DD62C41256.asc | \ + sudo gpg --dearmor --yes -o "$griffo_key" || true +fi + +griffo_list="/etc/apt/sources.list.d/debian.griffo.io.list" +ubuntu_codename="$(lsb_release -sc 2>/dev/null || echo "")" +if [[ -n "$ubuntu_codename" ]]; then + if [[ ! -f "$griffo_list" ]] || ! grep -q debian.griffo.io "$griffo_list" 2>/dev/null; then + echo "deb https://debian.griffo.io/apt $ubuntu_codename main" | \ + sudo tee "$griffo_list" >/dev/null || true + sudo apt-get update -y || true + fi +fi + +install_apt_packages_from_file "$DIR/packages/griffo.packages" diff --git a/src/scripts/install/media/all.sh b/src/scripts/install/media/all.sh deleted file mode 100644 index cc97867..0000000 --- a/src/scripts/install/media/all.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=../../lib/run.sh -source "$DIR/../../lib/run.sh" - -run_script "$DIR/brave-browser.sh" -run_script "$DIR/vlc.sh" -run_script "$DIR/multimedia.sh" diff --git a/src/scripts/install/media/multimedia.sh b/src/scripts/install/media/multimedia.sh deleted file mode 100644 index 5825087..0000000 --- a/src/scripts/install/media/multimedia.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y ffmpeg gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav -echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true" | sudo debconf-set-selections || true -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y ubuntu-restricted-extras || true diff --git a/src/scripts/install/media/vlc.sh b/src/scripts/install/media/vlc.sh deleted file mode 100644 index d8f007b..0000000 --- a/src/scripts/install/media/vlc.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y vlc diff --git a/src/scripts/install/packages/all.sh b/src/scripts/install/packages/all.sh new file mode 100644 index 0000000..50c8207 --- /dev/null +++ b/src/scripts/install/packages/all.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=../../lib/run.sh +source "$DIR/../../lib/run.sh" +# shellcheck source=../../lib/apt-packages.sh +source "$DIR/../../lib/apt-packages.sh" + +for list in base shell media desktop productivity; do + install_apt_packages_from_file "$DIR/${list}.packages" +done + +echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true" | sudo debconf-set-selections || true +sudo DEBIAN_FRONTEND=noninteractive apt-get install -y ubuntu-restricted-extras || true + +run_script "$DIR/../griffo.sh" +run_script "$DIR/../fastfetch.sh" +run_script "$DIR/../btop.sh" +run_script "$DIR/../flatpak.sh" diff --git a/src/scripts/install/packages/base.packages b/src/scripts/install/packages/base.packages new file mode 100644 index 0000000..a337a9d --- /dev/null +++ b/src/scripts/install/packages/base.packages @@ -0,0 +1,30 @@ +# CLI, security, and general apt tools (universe/main). Preflight installs git/curl first. + +bat +btop +dbus-x11 +eza +fd-find +flatpak +fzf +gcc +gh +htop +jq +make +libimage-exiftool-perl +libsecret-1-0 +libsecret-1-dev +nmap +openvpn +pkg-config +ripgrep +shellcheck +tealdeer +tree-sitter-cli +ufw +unzip +vim +whois +wget +zoxide diff --git a/src/scripts/install/packages/desktop.packages b/src/scripts/install/packages/desktop.packages new file mode 100644 index 0000000..4d4a09a --- /dev/null +++ b/src/scripts/install/packages/desktop.packages @@ -0,0 +1,2 @@ +gnome-shell-extensions +gnome-tweaks diff --git a/src/scripts/install/packages/dev.packages b/src/scripts/install/packages/dev.packages new file mode 100644 index 0000000..26d72a3 --- /dev/null +++ b/src/scripts/install/packages/dev.packages @@ -0,0 +1,6 @@ +neovim +python3 +python3-dev +python3-neovim +python3-pip +python3-venv diff --git a/src/scripts/install/packages/fastfetch.packages b/src/scripts/install/packages/fastfetch.packages new file mode 100644 index 0000000..215b1e7 --- /dev/null +++ b/src/scripts/install/packages/fastfetch.packages @@ -0,0 +1 @@ +fastfetch diff --git a/src/scripts/install/packages/griffo.packages b/src/scripts/install/packages/griffo.packages new file mode 100644 index 0000000..5d2cb5a --- /dev/null +++ b/src/scripts/install/packages/griffo.packages @@ -0,0 +1,3 @@ +lazydocker +lazygit +yazi diff --git a/src/scripts/install/packages/lsp-optional.packages b/src/scripts/install/packages/lsp-optional.packages new file mode 100644 index 0000000..9146f2b --- /dev/null +++ b/src/scripts/install/packages/lsp-optional.packages @@ -0,0 +1 @@ +julia diff --git a/src/scripts/install/packages/lsp.packages b/src/scripts/install/packages/lsp.packages new file mode 100644 index 0000000..ca00c99 --- /dev/null +++ b/src/scripts/install/packages/lsp.packages @@ -0,0 +1,15 @@ +build-essential +composer +default-jdk-headless +golang-go +gzip +liblua5.4-dev +luarocks +lua5.4 +php-cli +php-mbstring +php-xml +php-zip +ruby-dev +ruby-full +tar diff --git a/src/scripts/install/packages/media.packages b/src/scripts/install/packages/media.packages new file mode 100644 index 0000000..8fd69aa --- /dev/null +++ b/src/scripts/install/packages/media.packages @@ -0,0 +1,5 @@ +ffmpeg +gstreamer1.0-libav +gstreamer1.0-plugins-bad +gstreamer1.0-plugins-ugly +vlc diff --git a/src/scripts/install/packages/productivity.packages b/src/scripts/install/packages/productivity.packages new file mode 100644 index 0000000..dfcbd06 --- /dev/null +++ b/src/scripts/install/packages/productivity.packages @@ -0,0 +1,6 @@ +flameshot +keepassxc +libreoffice +libreoffice-gtk3 +libreoffice-style-breeze +redshift diff --git a/src/scripts/install/packages/shell.packages b/src/scripts/install/packages/shell.packages new file mode 100644 index 0000000..5c39b84 --- /dev/null +++ b/src/scripts/install/packages/shell.packages @@ -0,0 +1,8 @@ +fonts-font-awesome +fonts-firacode +fonts-powerline +powerline +tmux +zsh +zsh-autosuggestions +zsh-syntax-highlighting diff --git a/src/scripts/install/post-install/all.sh b/src/scripts/install/post-install/all.sh index 89922b3..7d04b8e 100644 --- a/src/scripts/install/post-install/all.sh +++ b/src/scripts/install/post-install/all.sh @@ -6,5 +6,4 @@ source "$DIR/../../lib/run.sh" run_script "$DIR/apt-maintain.sh" run_script "$DIR/docker-service.sh" -run_script "$DIR/ufw-enable.sh" run_script "$DIR/completion-banner.sh" diff --git a/src/scripts/install/post-install/completion-banner.sh b/src/scripts/install/post-install/completion-banner.sh index 2ed5ebc..465b354 100644 --- a/src/scripts/install/post-install/completion-banner.sh +++ b/src/scripts/install/post-install/completion-banner.sh @@ -8,4 +8,4 @@ if [[ -f "$art" ]]; then echo "============================================================================" echo fi -echo "Setup completed. Check $ERROR_LOG_FILE for any errors." +echo "Setup completed." diff --git a/src/scripts/install/post-install/ufw-enable.sh b/src/scripts/install/post-install/ufw-enable.sh deleted file mode 100644 index 2e16e1b..0000000 --- a/src/scripts/install/post-install/ufw-enable.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -if command -v ufw >/dev/null 2>&1; then - sudo ufw --force enable || true -fi diff --git a/src/scripts/install/productivity/all.sh b/src/scripts/install/productivity/all.sh deleted file mode 100644 index fd782a1..0000000 --- a/src/scripts/install/productivity/all.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=../../lib/run.sh -source "$DIR/../../lib/run.sh" - -run_script "$DIR/libreoffice.sh" -run_script "$DIR/zoom.sh" -run_script "$DIR/productivity-apt.sh" -run_script "$DIR/etcher.sh" diff --git a/src/scripts/install/productivity/libreoffice.sh b/src/scripts/install/productivity/libreoffice.sh deleted file mode 100644 index 2e78754..0000000 --- a/src/scripts/install/productivity/libreoffice.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y libreoffice libreoffice-gtk3 libreoffice-style-breeze diff --git a/src/scripts/install/productivity/productivity-apt.sh b/src/scripts/install/productivity/productivity-apt.sh deleted file mode 100644 index 926f5e1..0000000 --- a/src/scripts/install/productivity/productivity-apt.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y keepassxc redshift flameshot diff --git a/src/scripts/install/security/defense-apt.sh b/src/scripts/install/security/defense-apt.sh deleted file mode 100644 index 8eb8629..0000000 --- a/src/scripts/install/security/defense-apt.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -sudo apt-get update -y || true -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y ufw openvpn diff --git a/src/scripts/install/security/security-tools-apt.sh b/src/scripts/install/security/security-tools-apt.sh deleted file mode 100644 index 8870f53..0000000 --- a/src/scripts/install/security/security-tools-apt.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y nmap exiftool diff --git a/src/scripts/install/shell/all.sh b/src/scripts/install/shell/all.sh index e07baf3..909500d 100644 --- a/src/scripts/install/shell/all.sh +++ b/src/scripts/install/shell/all.sh @@ -4,9 +4,6 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=../../lib/run.sh source "$DIR/../../lib/run.sh" -run_script "$DIR/shell-apt.sh" run_script "$DIR/ghostty.sh" -run_script "$DIR/fonts-apt.sh" run_script "$DIR/meslo-nerd-font.sh" -run_script "$DIR/zsh-plugins.sh" run_script "$DIR/oh-my-posh.sh" diff --git a/src/scripts/install/shell/fonts-apt.sh b/src/scripts/install/shell/fonts-apt.sh deleted file mode 100644 index f25535f..0000000 --- a/src/scripts/install/shell/fonts-apt.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y fonts-font-awesome fonts-firacode fonts-powerline diff --git a/src/scripts/install/shell/oh-my-posh.sh b/src/scripts/install/shell/oh-my-posh.sh index d8cb1ea..fa4e947 100644 --- a/src/scripts/install/shell/oh-my-posh.sh +++ b/src/scripts/install/shell/oh-my-posh.sh @@ -1,7 +1,5 @@ #!/bin/bash -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y unzip curl - install_script="$TEMP_DIR/oh-my-posh-install.sh" curl -fsSL https://ohmyposh.dev/install.sh -o "$install_script" || exit 0 bash "$install_script" -d "${HOME}/.local/bin" 2>/dev/null || true diff --git a/src/scripts/install/shell/shell-apt.sh b/src/scripts/install/shell/shell-apt.sh deleted file mode 100644 index 8a366ca..0000000 --- a/src/scripts/install/shell/shell-apt.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -sudo apt-get update -y || true -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y zsh tmux powerline diff --git a/src/scripts/install/shell/zsh-plugins.sh b/src/scripts/install/shell/zsh-plugins.sh deleted file mode 100644 index e33caf1..0000000 --- a/src/scripts/install/shell/zsh-plugins.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -sudo DEBIAN_FRONTEND=noninteractive apt-get install -y zsh-autosuggestions zsh-syntax-highlighting diff --git a/src/scripts/lib/apt-packages.sh b/src/scripts/lib/apt-packages.sh new file mode 100644 index 0000000..115e8d0 --- /dev/null +++ b/src/scripts/lib/apt-packages.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Read package names from a file (one per line; # comments and blanks ignored) and apt install. + +install_apt_packages_from_file() { + local packages_file="$1" + local optional="${2:-}" + + mapfile -t packages < <(grep -v '^#' "$packages_file" | grep -v '^[[:space:]]*$') + if [[ ${#packages[@]} -eq 0 ]]; then + return 0 + fi + + if [[ "$optional" == optional ]]; then + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}" || true + else + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages[@]}" + fi +} diff --git a/src/scripts/lib/env.sh b/src/scripts/lib/env.sh index c251399..343908e 100644 --- a/src/scripts/lib/env.sh +++ b/src/scripts/lib/env.sh @@ -5,6 +5,5 @@ SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PROJECT_ROOT="$(cd "$SCRIPTS_DIR/../.." && pwd)" export PROJECT_ROOT -export ERROR_LOG_FILE="${PROJECT_ROOT}/setup_errors.log" export TEMP_DIR="/tmp/ubuntu-setup-$$" mkdir -p "$TEMP_DIR" diff --git a/src/scripts/lib/run.sh b/src/scripts/lib/run.sh index d163420..0f27b72 100644 --- a/src/scripts/lib/run.sh +++ b/src/scripts/lib/run.sh @@ -1,7 +1,5 @@ #!/bin/bash run_script() { - bash "$1" 2>>"$ERROR_LOG_FILE" || { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] Failed: $1" >>"$ERROR_LOG_FILE" - } + bash "$1" || true } diff --git a/src/scripts/master.sh b/src/scripts/master.sh index 62abcb5..07e2b4e 100755 --- a/src/scripts/master.sh +++ b/src/scripts/master.sh @@ -13,13 +13,7 @@ ensure_zshrc_login_safe run_script "$DIR/install/preflight/all.sh" run_script "$DIR/config/system/all.sh" run_script "$DIR/config/home/all.sh" -run_script "$DIR/install/cli/all.sh" -run_script "$DIR/install/media/all.sh" -run_script "$DIR/install/productivity/all.sh" -run_script "$DIR/install/dev/all.sh" +run_script "$DIR/install/all.sh" run_script "$DIR/config/dev/all.sh" -run_script "$DIR/install/security/all.sh" run_script "$DIR/config/security/all.sh" -run_script "$DIR/install/shell/all.sh" -run_script "$DIR/install/post-install/all.sh" run_script "$DIR/config/shell/all.sh"