Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/check-linux.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,8 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y zsh
- name: "⚙️ Generate checksums"
run: sh ./public/sh/generate-checksums.sh
- name: "⚙️ Check: unit fixtures"
run: sh ./tests/installers.sh
- name: "⚙️ Check: install.sh -- -i skip"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/check-macos.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,6 +47,8 @@ jobs:
- name: ⚙️ Prepare dependencies
run: |
brew install zsh
- name: "⚙️ Generate checksums"
run: sh ./public/sh/generate-checksums.sh
- name: "⚙️ Check: unit fixtures"
run: sh ./tests/installers.sh
- name: "⚙️ Check: install.sh -- -i skip"
Expand Down
10 changes: 2 additions & 8 deletions .github/workflows/checksum.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,6 +3,7 @@ name: Checksum
on:
push:
paths:
- "public/sh/generate-checksums.sh"
- "public/sh/install_zpmod.sh"
- "public/sh/install.sh"
- "public/sh/sync-init.sh"
Expand All@@ -25,14 +26,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: "🆗 Generate checksum"
uses: jmgilman/actions-generate-checksum@3ea6dc9bf8eecf28e2ecc982fab683484a1a8561 # v1.0.1
with:
patterns: |
public/sh/install_zpmod.sh
public/sh/install.sh
public/sh/sync-init.sh
public/zsh/init.zsh
- run: mv checksum.txt public/
run: sh ./public/sh/generate-checksums.sh
- name: "🆗 Commit"
uses: z-shell/.github/actions/commit@3222f53692e448ed6e2caf8b8722e74fb2ca2461 # v1.1.1
with:
Expand Down
2 changes: 1 addition & 1 deletion public/checksum.txt
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
0140801e80b2d8767e95d215850b6feab3642ee2b6fd70fbf4aab09afcfe7fca public/sh/install_zpmod.sh
0cca0bb9f95101b4bf392d6aa3c23123602d99a7cbb0decacaa72973e016d89d public/sh/install.sh
f9d8ef697ba682bdfe66fdd67d4517caa4e62bb8baf2868ec8ed9932809b76aa public/sh/install.sh
08cc893ceb982fc99d17db1966c6c30790cc571e16e4f5392352d995f5252952 public/sh/sync-init.sh
5c7af31d7fc848d80f9fedf69c75e6844503f550a3d5e020bc7cdfdaca624763 public/zsh/init.zsh
45 changes: 45 additions & 0 deletions public/sh/generate-checksums.sh
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env sh
# -*- mode: sh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*-
# vim: ft=sh sw=2 ts=2 et
#
# generate-checksums.sh — regenerate public/checksum.txt
#
# Usage (from any directory):
# sh public/sh/generate-checksums.sh
#
# This script is also invoked by the CI workflows before running
# tests/installers.sh so that public/checksum.txt is always current.

set -eu

ROOT="$(
unset CDPATH
cd "$(dirname "$0")/../.." 2>/dev/null && pwd
)" || { printf '%s\n' "generate-checksums: cannot determine repository root" >&2; exit 1; }
Comment thread
Copilot marked this conversation as resolved.

CHECKSUM_FILE="${ROOT}/public/checksum.txt"

sha256_file() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
else
printf '%s\n' "generate-checksums: sha256sum or shasum is required" >&2
exit 1
fi
}

# Clear (or create) the checksum file before writing fresh entries with `: > file`.
: > "${CHECKSUM_FILE}"
for f in \
public/sh/install_zpmod.sh \
public/sh/install.sh \
public/sh/sync-init.sh \
public/zsh/init.zsh
do
hash="$(sha256_file "${ROOT}/${f}")"
printf '%s %s\n' "${hash}" "${f}" >> "${CHECKSUM_FILE}"
done

printf '%s\n' "Checksums written to ${CHECKSUM_FILE}"
25 changes: 25 additions & 0 deletions public/sh/install.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,6 +36,17 @@ while getopts ":i:a:b:" opt; do
done
shift $((OPTIND - 1))

# Validate BOPT to prevent sed delimiter injection when building init.zsh.
# | is the sed delimiter used in the substitution; \ and & are special in
# sed replacement expressions. The *[\\]* pattern matches a single backslash.
case "${BOPT}" in
# [\\] is a bracket expression for a literal backslash.
*'|'* | *[\\]* | *'&'* )
printf '%s\n' "-- ERROR -- Invalid -b value: branch name must not contain '|', '\\', or '&'." >&2
exit 1
;;
esac

SCRIPT_DIR=""
LOCAL_INIT_ZSH=""
LOCAL_INSTALL_ZPMOD=""
Expand DownExpand Up@@ -147,6 +158,20 @@ fi
command chmod a+x /tmp/zi/git-process-output.zsh

if test -d "${ZI_HOME}/${ZI_BIN_DIR_NAME}/.git"; then
_zi_valid=0
if test -f "${ZI_HOME}/${ZI_BIN_DIR_NAME}/zi.zsh"; then
# Canonical zi remote URLs (HTTPS and SSH, with and without .git suffix)
case "$(command git -C "${ZI_HOME}/${ZI_BIN_DIR_NAME}" remote get-url origin 2>/dev/null || true)" in
https://github.com/z-shell/zi | https://github.com/z-shell/zi.git \
| git@github.com:z-shell/zi | git@github.com:z-shell/zi.git)
_zi_valid=1 ;;
esac
fi
if [ "${_zi_valid}" -ne 1 ]; then
printf '%s\n' "▓▒░ ${ZI_HOME}/${ZI_BIN_DIR_NAME} contains a .git directory but does not appear to be a zi repository." >&2
printf '%s\n' "▓▒░ Expected zi.zsh and a z-shell/zi remote origin. Unset ZI_HOME/ZI_BIN_DIR_NAME or remove the directory to install fresh." >&2
exit 1
fi
cd "${ZI_HOME}/${ZI_BIN_DIR_NAME}" || exit 1
printf '%s\n' "▓▒░ Updating (z-shell/zi) plugin manager at ${ZI_HOME}/${ZI_BIN_DIR_NAME}"
command git clean -d -f -f
Expand Down
90 changes: 88 additions & 2 deletions tests/installers.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -139,6 +139,12 @@ EOF
#!/usr/bin/env sh
set -eu

# Strip -C <dir> flag if present (used by install.sh to check remote URL)
if [ "${1:-}" = "-C" ]; then
[ -n "${2:-}" ] || { printf '%s\n' "installers.sh git test double: -C requires a directory argument" >&2; exit 64; }
shift 2
fi

cmd="${1:-}"
[ "$#" -gt 0 ] && shift

Expand All@@ -148,7 +154,7 @@ case "${cmd}" in
for arg do
dest="${arg}"
done
[ -n "${dest}" ] || { printf '%s\n' "git test double: missing clone destination" >&2; exit 64; }
[ -n "${dest}" ] || { printf '%s\n' "installers.sh git test double: missing clone destination" >&2; exit 64; }
mkdir -p "${dest}/.git" "${dest}/lib"
printf '%s\n' '# fake zi.zsh' > "${dest}/zi.zsh"
printf '%s\n' '# fake _zi completion' > "${dest}/lib/_zi"
Expand All@@ -158,8 +164,21 @@ case "${cmd}" in
log)
printf '%s\n' 'abcdef0 - fake zi commit (now) <test>'
;;
remote)
# After -C strip (if any) and cmd shift, $1/$2 hold the remote subcommand args
if [ "${1:-}" != "get-url" ]; then
printf '%s\n' "installers.sh git test double: expected remote subcommand 'get-url', got '${1:-<missing>}'" >&2
exit 65
fi
if [ "${2:-}" != "origin" ]; then
printf '%s\n' "installers.sh git test double: expected remote name 'origin', got '${2:-<missing>}'" >&2
exit 65
fi
# Return a zi remote URL; override via ZI_SRC_TEST_FAKE_REMOTE env var
printf '%s\n' "${ZI_SRC_TEST_FAKE_REMOTE:-https://github.com/z-shell/zi}"
;;
*)
printf '%s\n' "git test double: unexpected command ${cmd}" >&2
printf '%s\n' "installers.sh git test double: unexpected command ${cmd}" >&2
exit 65
;;
esac
Expand DownExpand Up@@ -226,6 +245,70 @@ test_standalone_zpmod_delegation() {
pass "standalone install.sh fetches zpmod helper"
}

test_update_valid_zi_clone() {
home="${TMP_ROOT}/update-valid-home"
data="${TMP_ROOT}/update-valid-data"
zi_bin="${data}/zi/bin"
command mkdir -p "${home}" "${zi_bin}/.git"
printf '%s\n' '# fake zi.zsh' >"${zi_bin}/zi.zsh"

HOME="${home}" \
ZDOTDIR="${home}" \
XDG_DATA_HOME="${data}" \
ZI_SRC_TEST_ROOT="${ROOT}" \
PATH="${FAKE_BIN}:${PATH}" \
sh "${ROOT}/public/sh/install.sh" -i skip >/dev/null

pass "update path accepts a valid zi clone"
}

test_update_rejects_foreign_repo() {
home="${TMP_ROOT}/update-foreign-home"
data="${TMP_ROOT}/update-foreign-data"
zi_bin="${data}/zi/bin"
command mkdir -p "${home}" "${zi_bin}/.git"
# Deliberately no zi.zsh: this simulates an unrelated git repo
err="${TMP_ROOT}/update-foreign-err"

set +e
HOME="${home}" \
ZDOTDIR="${home}" \
XDG_DATA_HOME="${data}" \
ZI_SRC_TEST_ROOT="${ROOT}" \
PATH="${FAKE_BIN}:${PATH}" \
sh "${ROOT}/public/sh/install.sh" -i skip >/dev/null 2>"${err}"
exit_code="$?"
set -e

[ "${exit_code}" -ne 0 ] || fail "install.sh should have rejected a foreign git repository"
contains "${err}" "does not appear to be a zi repository"
pass "update path rejects an unrecognised git repository"
}

test_update_rejects_wrong_remote() {
home="${TMP_ROOT}/update-wrong-remote-home"
data="${TMP_ROOT}/update-wrong-remote-data"
zi_bin="${data}/zi/bin"
command mkdir -p "${home}" "${zi_bin}/.git"
printf '%s\n' '# fake zi.zsh' >"${zi_bin}/zi.zsh"
err="${TMP_ROOT}/update-wrong-remote-err"

set +e
HOME="${home}" \
ZDOTDIR="${home}" \
XDG_DATA_HOME="${data}" \
ZI_SRC_TEST_ROOT="${ROOT}" \
ZI_SRC_TEST_FAKE_REMOTE="https://github.com/unrelated/project" \
PATH="${FAKE_BIN}:${PATH}" \
sh "${ROOT}/public/sh/install.sh" -i skip >/dev/null 2>"${err}"
exit_code="$?"
set -e

[ "${exit_code}" -ne 0 ] || fail "install.sh should have rejected a repo with a non-zi remote"
contains "${err}" "does not appear to be a zi repository"
pass "update path rejects a repository with a non-zi remote origin"
}

test_sync_init() {
local_file="${TMP_ROOT}/local-init.zsh"
remote_file="${TMP_ROOT}/remote-init.zsh"
Expand DownExpand Up@@ -265,4 +348,7 @@ write_fake_tools
test_loader_install
test_xdg_data_home_install
test_standalone_zpmod_delegation
test_update_valid_zi_clone
test_update_rejects_foreign_repo
test_update_rejects_wrong_remote
test_sync_init
Loading