diff --git a/.config/nvim/lua/rc/plugins/init.lua b/.config/nvim/lua/rc/plugins/init.lua index 77abc54..22fe5b7 100644 --- a/.config/nvim/lua/rc/plugins/init.lua +++ b/.config/nvim/lua/rc/plugins/init.lua @@ -1,10 +1,18 @@ local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not (vim.uv or vim.loop).fs_stat(lazypath) then local lazyrepo = "https://github.com/folke/lazy.nvim.git" - local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + -- Supply-chain hardening: pin to a specific commit instead of --branch=stable + -- Commit from lazy-lock.json; update both when upgrading lazy.nvim + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--single-branch", lazyrepo, lazypath }) + if vim.v.shell_error == 0 then + local co_out = vim.fn.system({ "git", "-C", lazypath, "checkout", "306a05526ada86a7b30af95c5cc81ffba93fef97" }) + if vim.v.shell_error ~= 0 then + out = co_out + end + end if vim.v.shell_error ~= 0 then vim.api.nvim_echo({ - { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { "Failed to install lazy.nvim:\n", "ErrorMsg" }, { out, "WarningMsg" }, { "\nPress any key to exit..." }, }, true, {}) diff --git a/.config/zsh/rc/pluginlist.zsh b/.config/zsh/rc/pluginlist.zsh index cd939b9..7bef88d 100644 --- a/.config/zsh/rc/pluginlist.zsh +++ b/.config/zsh/rc/pluginlist.zsh @@ -7,7 +7,9 @@ fi if ! test -d "$ZPLG_HOME"; then mkdir -p "$ZPLG_HOME" chmod g-rwX "$ZPLG_HOME" - git clone --depth 10 https://github.com/zdharma-continuum/zinit.git ${ZPLG_HOME}/bin + # Supply-chain hardening: pin zinit to commit corresponding to v3.14.0 + git clone --depth 1 https://github.com/zdharma-continuum/zinit.git "${ZPLG_HOME}/bin" + (cd "${ZPLG_HOME}/bin" && git checkout --detach 412ff3b6d9c0cd9ceb4b4f17aea39dda9e1abad5) fi typeset -gAH ZPLGM ZPLGM[HOME_DIR]="${ZPLG_HOME}" @@ -23,16 +25,20 @@ autoload -Uz _zinit #--------------------------------# # history #--------------------------------# +# Supply-chain hardening: pin each plugin to a specific commit via ver"" zinit wait'1' lucid \ if"(( ${ZSH_VERSION%%.*} > 4.4))" \ + ver"14c8d2e0ffaee98f2df9850b19944f32546fdea5" \ light-mode for @zsh-users/zsh-history-substring-search zinit wait'1' lucid \ if"(( ${ZSH_VERSION%%.*} > 4.4))" \ + ver"9bc52fed2900460fc4bef0a77c9382d6175eb63a" \ light-mode for @zdharma/history-search-multi-word zinit wait'1' lucid \ if"(( ${ZSH_VERSION%%.*} > 4.4))" \ + ver"598675303044df8e9d04722f3adff4f63a238922" \ light-mode for @mollifier/anyframe autoload -Uz chpwd_recent_dirs cdr add-zsh-hook add-zsh-hook chpwd chpwd_recent_dirs @@ -54,10 +60,12 @@ zinit wait'1' lucid \ #--------------------------------# zinit wait'0' lucid \ if"(( ${ZSH_VERSION%%.*} > 4.4))" \ + ver"85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5" \ light-mode for @zsh-users/zsh-autosuggestions zinit wait'1' lucid \ if"(( ${ZSH_VERSION%%.*} > 4.4))" \ + ver"adad765241061b9b63485991f268b2771524ed42" \ light-mode for @zsh-users/zsh-completions #--------------------------------# @@ -65,6 +73,7 @@ zinit wait'1' lucid \ # --------------------------------# zinit wait'1' lucid \ if"(( ${ZSH_VERSION%%.*} > 4.4))" \ + ver"1d85c692615a25fe2293bdd44b34c217d5d2bf04" \ light-mode for @zsh-users/zsh-syntax-highlighting #--------------------------------# diff --git a/.github/workflows/gitguardian.yml b/.github/workflows/gitguardian.yml index dda6da5..a6b6d49 100644 --- a/.github/workflows/gitguardian.yml +++ b/.github/workflows/gitguardian.yml @@ -8,11 +8,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + # Supply-chain hardening: pin actions to full commit SHA + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 # fetch all history so multiple commits can be scanned - name: GitGuardian scan - uses: GitGuardian/ggshield-action@v1 + uses: GitGuardian/ggshield-action@8fc5e12b83a2f2a9f71b88bb12d0d5cf152b1689 # v1.49.0 env: GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }} GITHUB_PUSH_BASE_SHA: ${{ github.event.base }} diff --git a/.github/workflows/lua-lint.yml b/.github/workflows/lua-lint.yml index 506db67..fb1f247 100644 --- a/.github/workflows/lua-lint.yml +++ b/.github/workflows/lua-lint.yml @@ -14,11 +14,12 @@ jobs: env: CI: true steps: - - uses: actions/checkout@v4 + # Supply-chain hardening: pin actions to full commit SHA + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Cache lint tools id: cache-tools - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.local/bin key: lint-tools-stylua-0.20.0-selene-0.27.1 @@ -27,11 +28,18 @@ jobs: if: steps.cache-tools.outputs.cache-hit != 'true' run: | mkdir -p ~/.local/bin + + # Supply-chain hardening: verify checksums of downloaded binaries + STYLUA_SHA256="28eddb9257bf85b20b1c337e536b7a3d16ba308863f067d447c1f4d24c6dec64" curl -LO https://github.com/JohnnyMorganz/StyLua/releases/download/v0.20.0/stylua-linux-x86_64.zip + echo "${STYLUA_SHA256} stylua-linux-x86_64.zip" | sha256sum -c - unzip stylua-linux-x86_64.zip -d ~/.local/bin chmod +x ~/.local/bin/stylua rm stylua-linux-x86_64.zip + + SELENE_SHA256="22dabfe070c6d10cbb0b8ae56a82abfa131fbb902bff03d9924f0f73fd3d3318" curl -LO https://github.com/Kampfkarren/selene/releases/download/0.27.1/selene-0.27.1-linux.zip + echo "${SELENE_SHA256} selene-0.27.1-linux.zip" | sha256sum -c - unzip selene-0.27.1-linux.zip -d ~/.local/bin chmod +x ~/.local/bin/selene rm selene-0.27.1-linux.zip diff --git a/.github/workflows/neovim-health.yml b/.github/workflows/neovim-health.yml index cf6f67a..ac7e3b9 100644 --- a/.github/workflows/neovim-health.yml +++ b/.github/workflows/neovim-health.yml @@ -17,16 +17,17 @@ jobs: env: CI: true steps: - - uses: actions/checkout@v4 + # Supply-chain hardening: pin actions to full commit SHA + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Install Neovim - uses: rhysd/action-setup-vim@v1 + uses: rhysd/action-setup-vim@febef33995d6649302e9d88dda81e071b68f16a7 # v1.6.1 with: neovim: true version: ${{ matrix.channel }} - name: Cache lazy.nvim directories - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ${{ github.workspace }}/.local/share/nvim diff --git a/install_scripts/lib/dotinstaller/install-brewfile.sh b/install_scripts/lib/dotinstaller/install-brewfile.sh index 2bef9e2..60ce9b5 100755 --- a/install_scripts/lib/dotinstaller/install-brewfile.sh +++ b/install_scripts/lib/dotinstaller/install-brewfile.sh @@ -6,6 +6,14 @@ function is_brewfile_installed() { command -v brew-file >/dev/null 2>&1 } +_sha256() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + else + shasum -a 256 "$1" | awk '{print $1}' + fi +} + function main() { local current_dir current_dir=$(dirname "${BASH_SOURCE[0]:-$0}") @@ -16,11 +24,29 @@ function main() { fi echo "Brewfile is not installed. Installing Brewfile..." - # Brewfileのインストール - curl -o install.sh -fsSL https://raw.github.com/rcmdnk/homebrew-file/install/install.sh - chmod 755 ./install.sh - ./install.sh - rm -f install.sh + + # Supply-chain hardening: pin to a specific commit on the install branch + local brewfile_commit="723acc6f3e0db4677c03bb87c4ea33157d549e26" + local expected_sha256="464d39329e5e13939861dab96fbaf64e30513ef4a0666b7edaf7784079ba6fa7" + local install_script + install_script=$(mktemp "${TMPDIR:-/tmp}/brewfile-install.XXXXXX") + trap 'rm -f "$install_script"' EXIT + + curl -fsSL -o "$install_script" \ + "https://raw.githubusercontent.com/rcmdnk/homebrew-file/${brewfile_commit}/install.sh" + + # Verify SHA256 checksum before execution (update hash when bumping commit) + local actual_sha256 + actual_sha256=$(_sha256 "$install_script") + if [ "$actual_sha256" != "$expected_sha256" ]; then + echo "🚨ERROR🚨 homebrew-file install script checksum mismatch!" + echo " expected: ${expected_sha256}" + echo " actual: ${actual_sha256}" + exit 1 + fi + + chmod 755 "$install_script" + "$install_script" # インストールが成功したか再確認 if is_brewfile_installed; then diff --git a/install_scripts/lib/dotinstaller/install-fonts.sh b/install_scripts/lib/dotinstaller/install-fonts.sh index a15fe90..618f123 100755 --- a/install_scripts/lib/dotinstaller/install-fonts.sh +++ b/install_scripts/lib/dotinstaller/install-fonts.sh @@ -2,25 +2,58 @@ set -ue +# Supply-chain hardening: pin font releases and verify checksums +_sha256() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + else + shasum -a 256 "$1" | awk '{print $1}' + fi +} + +verify_checksum() { + local file="$1" expected="$2" + local actual + actual=$(_sha256 "$file") + if [ "$actual" != "$expected" ]; then + echo "🚨ERROR🚨 Checksum mismatch for ${file}!" + echo " expected: ${expected}" + echo " actual: ${actual}" + rm -f "$file" + exit 1 + fi +} + +FONT_TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/dotinstaller-fonts.XXXXXX") +trap 'rm -rf "$FONT_TMPDIR"' EXIT + mkdir -p ~/.local/share/fonts -# udev gothic +# udev gothic — pinned to v2.2.0 +UDEV_GOTHIC_VERSION="v2.2.0" +UDEV_GOTHIC_SHA256="c104c171f6ed8922ca52d74cd915a271e427f1e884e51431aae71d99e8b3b47b" mkdir -p ~/.local/share/fonts/UDEVGothic -UDEV_GOTHIC_RELEASES_URL="https://api.github.com/repos/yuru7/udev-gothic/releases" -curl -sfL "${UDEV_GOTHIC_RELEASES_URL}" | jq -r '.[0].assets | .[].browser_download_url' | xargs -I{} curl -fL -o /tmp/UDEVGothic.zip "{}" -(cd /tmp && unzip -j -o UDEVGothic.zip -d ~/.local/share/fonts/UDEVGothic) +curl -fL -o "$FONT_TMPDIR/UDEVGothic.zip" \ + "https://github.com/yuru7/udev-gothic/releases/download/${UDEV_GOTHIC_VERSION}/UDEVGothic_${UDEV_GOTHIC_VERSION}.zip" +verify_checksum "$FONT_TMPDIR/UDEVGothic.zip" "$UDEV_GOTHIC_SHA256" +(cd "$FONT_TMPDIR" && unzip -j -o UDEVGothic.zip -d ~/.local/share/fonts/UDEVGothic) -# Hack Nerd Font +# Hack Nerd Font — pinned to v3.4.0 +HACK_NERD_FONT_VERSION="v3.4.0" +HACK_NERD_FONT_SHA256="8ca33a60c791392d872b80d26c42f2bfa914a480f9eb2d7516d9f84373c36897" mkdir -p ~/.local/share/fonts/HackNerdFont -HACK_NERD_FONT_RELEASES_URL="https://api.github.com/repos/ryanoasis/nerd-fonts/releases" -curl -sfL "${HACK_NERD_FONT_RELEASES_URL}" | jq -r '.[0].assets | .[].browser_download_url' | grep Hack.zip | xargs -I{} curl -fL -o /tmp/HackNerdFont.zip "{}" -(cd /tmp && unzip -j -o HackNerdFont.zip -d ~/.local/share/fonts/HackNerdFont) +curl -fL -o "$FONT_TMPDIR/HackNerdFont.zip" \ + "https://github.com/ryanoasis/nerd-fonts/releases/download/${HACK_NERD_FONT_VERSION}/Hack.zip" +verify_checksum "$FONT_TMPDIR/HackNerdFont.zip" "$HACK_NERD_FONT_SHA256" +(cd "$FONT_TMPDIR" && unzip -j -o HackNerdFont.zip -d ~/.local/share/fonts/HackNerdFont) -# Fira Code +# Fira Code — pinned to 6.2 +FIRA_CODE_VERSION="6.2" +FIRA_CODE_SHA256="0949915ba8eb24d89fd93d10a7ff623f42830d7c5ffc3ecbf960e4ecad3e3e79" mkdir -p ~/.local/share/fonts/FiraCode -FIRA_CODE_RELEASES_URL="https://api.github.com/repos/tonsky/FiraCode/releases" -LATEST_ZIP_URL=$(curl -sfL "${FIRA_CODE_RELEASES_URL}" | jq -r '.[0].assets[] | select(.name | contains(".zip")) | .browser_download_url') -curl -fL -o /tmp/FiraCode.zip "${LATEST_ZIP_URL}" -(cd /tmp && unzip -j -o FiraCode.zip -d ~/.local/share/fonts/FiraCode) +curl -fL -o "$FONT_TMPDIR/FiraCode.zip" \ + "https://github.com/tonsky/FiraCode/releases/download/${FIRA_CODE_VERSION}/Fira_Code_v${FIRA_CODE_VERSION}.zip" +verify_checksum "$FONT_TMPDIR/FiraCode.zip" "$FIRA_CODE_SHA256" +(cd "$FONT_TMPDIR" && unzip -j -o FiraCode.zip -d ~/.local/share/fonts/FiraCode) fc-cache -vf diff --git a/install_scripts/lib/dotinstaller/install-homebrew.sh b/install_scripts/lib/dotinstaller/install-homebrew.sh index b2bd0fc..c4b75f0 100755 --- a/install_scripts/lib/dotinstaller/install-homebrew.sh +++ b/install_scripts/lib/dotinstaller/install-homebrew.sh @@ -6,6 +6,14 @@ function is_homebrew_installed() { command -v brew >/dev/null 2>&1 } +_sha256() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + else + shasum -a 256 "$1" | awk '{print $1}' + fi +} + function main() { local current_dir current_dir=$(dirname "${BASH_SOURCE[0]:-$0}") @@ -16,8 +24,28 @@ function main() { fi echo "Homebrew is not installed. Installing Homebrew..." - # Homebrewのインストール - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + # Supply-chain hardening: pin to a specific commit instead of HEAD + local brew_commit="6d5e2670d07961e7985d2079a2f0a484420f3c38" + local expected_sha256="dfd5145fe2aa5956a600e35848765273f5798ce6def01bd08ecec088a1268d91" + local brew_script + brew_script=$(mktemp -t brew_install.XXXXXX) + trap 'rm -f "$brew_script"' EXIT + + curl -fsSL "https://raw.githubusercontent.com/Homebrew/install/${brew_commit}/install.sh" \ + -o "$brew_script" + + # Verify SHA256 checksum before execution (update hash when bumping brew_commit) + local actual_sha256 + actual_sha256=$(_sha256 "$brew_script") + if [ "$actual_sha256" != "$expected_sha256" ]; then + echo "🚨ERROR🚨 Homebrew install script checksum mismatch!" + echo " expected: ${expected_sha256}" + echo " actual: ${actual_sha256}" + exit 1 + fi + + /bin/bash "$brew_script" # インストールが成功したか再確認 if is_homebrew_installed; then diff --git a/install_scripts/lib/dotinstaller/install-skk.sh b/install_scripts/lib/dotinstaller/install-skk.sh index 586ecc2..d5515b2 100755 --- a/install_scripts/lib/dotinstaller/install-skk.sh +++ b/install_scripts/lib/dotinstaller/install-skk.sh @@ -1,8 +1,9 @@ #!/bin/bash # install yaskkserv2 -if ! command -v yaskkserv2 >/dev/temp/null; then - cargo install --git https://github.com/wachikun/yaskkserv2 --locked --bins +# Supply-chain hardening: pin to a specific release tag +if ! command -v yaskkserv2 >/dev/null 2>&1; then + cargo install --git https://github.com/wachikun/yaskkserv2 --tag 0.1.7 --locked --bins fi # setup launch agent