mirror of
https://github.com/zdharma-continuum/zinit.git
synced 2026-09-10 07:36:38 -04:00
fix: trust archive permissions instead of file(1) heuristics in ziextract (#771)
This commit is contained in:
parent
f82d91ccac
commit
1334994f20
|
|
@ -2,6 +2,21 @@
|
|||
|
||||
@setup {
|
||||
ZPLUGINS=$ZINIT[PLUGINS_DIR]
|
||||
function _zunit_assert_not_executable(){
|
||||
local pathname=$1 filepath
|
||||
|
||||
# If filepath is relative, prepend the test directory
|
||||
if [[ "${pathname:0:1}" != "/" ]]; then
|
||||
filepath="$testdir/${pathname}"
|
||||
else
|
||||
filepath="$pathname"
|
||||
fi
|
||||
|
||||
[[ ! -x "$filepath" ]] && return 0
|
||||
|
||||
echo "'$pathname' is executable but should not be"
|
||||
exit 1
|
||||
}
|
||||
function _zunit_assert_not_exists(){
|
||||
local file_path=$1
|
||||
if [[ "${file_path:0:1}" != "/" ]]; then # relative path - prepend the test directory
|
||||
|
|
@ -119,5 +134,38 @@
|
|||
assert "$workdir/test.zip" is_file
|
||||
rm -rf "$workdir"
|
||||
}
|
||||
@test 'ziextract-permissions' {
|
||||
# Build a zip with known permissions, call ziextract directly, and verify
|
||||
# that only files with +x in the archive come out executable.
|
||||
local srcdir workdir
|
||||
srcdir=$(mktemp -d)
|
||||
workdir=$(mktemp -d)
|
||||
|
||||
# run_me.sh: +x in archive, has shebang → must be executable
|
||||
printf '#!/bin/sh\necho run\n' > "$srcdir/run_me.sh"
|
||||
chmod +x "$srcdir/run_me.sh"
|
||||
|
||||
# also_run.py: no +x in archive, has shebang → must NOT be executable (shebang alone is not enough)
|
||||
printf '#!/usr/bin/env python3\nprint("hi")\n' > "$srcdir/also_run.py"
|
||||
|
||||
# library.py: no +x, no shebang → must NOT be executable
|
||||
printf 'def foo(): pass\n' > "$srcdir/library.py"
|
||||
|
||||
# pre_marked.sh: +x in archive, no shebang → must be executable (archive bit)
|
||||
printf 'echo pre\n' > "$srcdir/pre_marked.sh"
|
||||
chmod +x "$srcdir/pre_marked.sh"
|
||||
|
||||
# Build zip preserving permissions, then extract via ziextract
|
||||
( cd "$srcdir" && zip -q "$workdir/test.zip" run_me.sh also_run.py library.py pre_marked.sh )
|
||||
(( ${+functions[ziextract]} )) || builtin source "${ZINIT[BIN_DIR]}/zinit-install.zsh"
|
||||
( builtin cd "$workdir" && ziextract test.zip )
|
||||
|
||||
assert "$workdir/run_me.sh" is_executable
|
||||
assert "$workdir/pre_marked.sh" is_executable
|
||||
assert "$workdir/also_run.py" not_executable
|
||||
assert "$workdir/library.py" not_executable
|
||||
|
||||
rm -rf "$srcdir" "$workdir"
|
||||
}
|
||||
|
||||
# vim:ft=zsh:sw=2:sts=2:et:foldmarker=\ {,}:foldmethod=marker
|
||||
|
|
|
|||
|
|
@ -1514,9 +1514,9 @@ builtin source "${ZINIT[BIN_DIR]}/zinit-side.zsh" || {
|
|||
} # ]]]
|
||||
# FUNCTION: ziextract [[[
|
||||
# If the file is an archive, it is extracted by this function.
|
||||
# Next stage is scanning of files with the common utility file
|
||||
# to detect executables. They are given +x mode. There are also
|
||||
# messages to the user on performed actions.
|
||||
# Executable permissions are determined solely by the execute bit already
|
||||
# stored in the archive — i.e. whatever the package author intended.
|
||||
# No heuristics (file(1), shebang scanning, etc.) are applied.
|
||||
#
|
||||
# $1 - url
|
||||
# $2 - file
|
||||
|
|
@ -1757,13 +1757,21 @@ ziextract() {
|
|||
}
|
||||
unfunction -- .zinit-extract-wrapper
|
||||
|
||||
# Glob qualifier legend:
|
||||
# (DN-.) — D=include dotfiles, N=null glob (no error if empty),
|
||||
# -=no symlinks, .=regular files → all regular files
|
||||
# (DN-*.) — same plus *=has execute bit set → files already marked
|
||||
# executable by the archive extractor
|
||||
local -aU execs
|
||||
execs=( **/*~(._zinit(|/*)|.git(|/*)|.svn(|/*)|.hg(|/*)|._backup(|/*))(DN-.) )
|
||||
if [[ ${#execs} -gt 0 && -n $execs ]] {
|
||||
execs=( ${(@f)"$( file ${execs[@]} )"} )
|
||||
execs=( "${(M)execs[@]:#[^(:]##:*executable*}" )
|
||||
execs=( "${execs[@]/(#b)([^(:]##):*/${match[1]}}" )
|
||||
}
|
||||
# Collect files that already have the execute bit set in the archive.
|
||||
# This is the authoritative signal: if the package author wanted a file
|
||||
# executable, they set +x when creating the archive. Any file that lacks
|
||||
# +x in the archive (library, documentation, data file, …) should stay
|
||||
# non-executable regardless of its content or extension.
|
||||
# If a poorly maintained package fails to set permissions correctly,
|
||||
# the user can fix it with the atclone/atpull ices — there is no need
|
||||
# for zinit to second-guess the archive on every install.
|
||||
execs=( **/*~(._zinit(|/*)|.git(|/*)|.svn(|/*)|.hg(|/*)|._backup(|/*))(DN-*.) )
|
||||
|
||||
builtin print -rl -- ${execs[@]} >! ${TMPDIR:-/tmp}/zinit-execs.$$.lst
|
||||
if [[ ${#execs} -gt 0 ]] {
|
||||
|
|
|
|||
Loading…
Reference in a new issue