From 9337cef95a41dcf83cb3de36ffa37d3239ae8980 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:34:03 +0000 Subject: [PATCH 01/17] build_module: add missing colon in INFO log messages for download cases --- build_module.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_module.sh b/build_module.sh index b0811b1c..66375692 100755 --- a/build_module.sh +++ b/build_module.sh @@ -302,14 +302,14 @@ else git clone --recursive $1 $MODULE_DIR ;; "zip") - echo "$ME: INFO Downloading module source" + echo "$ME: INFO: Downloading module source" try_n_times 3 "wget -O $BUILD_DIR/module.zip $1" "rm -f $BUILD_DIR/module.zip" ARCHIVE_DIR=`zipinfo -1 $BUILD_DIR/module.zip | head -n 1 | cut -f1 -d/` unzip $BUILD_DIR/module.zip -d $BUILD_DIR mv $BUILD_DIR/$ARCHIVE_DIR $MODULE_DIR ;; *) - echo "$ME: INFO Downloading module source" + echo "$ME: INFO: Downloading module source" # Assume tarball of some kind try_n_times 3 "wget -O $BUILD_DIR/module.tgz $1" "rm -f $BUILD_DIR/module.tgz" ARCHIVE_DIR=`tar tfz $BUILD_DIR/module.tgz | head -n 1 | cut -f1 -d/` From 9328b4d7747016f5c1fbc616a5c4250e217065fd Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:34:14 +0000 Subject: [PATCH 02/17] build_module: exit on git clone failure when fetching NGINX packaging tool --- build_module.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build_module.sh b/build_module.sh index 66375692..64a98506 100755 --- a/build_module.sh +++ b/build_module.sh @@ -385,7 +385,10 @@ cd $BUILD_DIR PKG_OSS_URL="https://github.com/nginx/pkg-oss" -git clone $PKG_OSS_URL +if ! git clone $PKG_OSS_URL; then + echo "$ME: ERROR: Unable to clone NGINX packaging tool - quitting" + exit 1 +fi if [ "$BUILD_PLATFORM" = "OSS" ]; then if [ "$OSS_VER" != "" ]; then From be0160673a481dc4bd13a66c2b96f55f80bb0b8d Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:34:28 +0000 Subject: [PATCH 03/17] build_module: exit on git checkout failure for OSS version and Plus release --- build_module.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build_module.sh b/build_module.sh index 64a98506..f9815179 100755 --- a/build_module.sh +++ b/build_module.sh @@ -392,10 +392,16 @@ fi if [ "$BUILD_PLATFORM" = "OSS" ]; then if [ "$OSS_VER" != "" ]; then - ( cd pkg-oss && git checkout `git tag -l | grep "^$OSS_VER" | head -1 | awk '{print $1}'` ) + if ! ( cd pkg-oss && git checkout `git tag -l | grep "^$OSS_VER" | head -1 | awk '{print $1}'` ); then + echo "$ME: ERROR: Unable to checkout NGINX OSS version $OSS_VER - quitting" + exit 1 + fi fi else - ( cd pkg-oss && git checkout target-plus-r$PLUS_REL ) + if ! ( cd pkg-oss && git checkout target-plus-r$PLUS_REL ); then + echo "$ME: ERROR: Unable to checkout NGINX Plus release $PLUS_REL - quitting" + exit 1 + fi fi cd pkg-oss/$PACKAGING_DIR if [ $? -ne 0 ]; then From f3b2405f87d0aa08c0c1935ee03ba779ee580d3a Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:34:40 +0000 Subject: [PATCH 04/17] build_module: exit if NGINX version cannot be determined from packaging tool --- build_module.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build_module.sh b/build_module.sh index f9815179..e5295e04 100755 --- a/build_module.sh +++ b/build_module.sh @@ -418,6 +418,10 @@ if [ -d pkg-oss/contrib ]; then else VERSION=`grep "^BASE_VERSION=" pkg-oss/$PACKAGING_DIR/Makefile | cut -f2 -d= | tr -d "[:blank:]"` fi +if [ -z "$VERSION" ]; then + echo "$ME: ERROR: Could not determine NGINX version from packaging tool - quitting" + exit 1 +fi echo "$ME: INFO: Archiving module source for $VERSION" mv $MODULE_NAME $MODULE_NAME-$VERSION tar cf - $MODULE_NAME-$VERSION | gzip -1 > $MODULE_NAME-$VERSION.tar.gz From 0749abae9b100a7eb3db3edcd0b681997e442bbf Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:34:50 +0000 Subject: [PATCH 05/17] build_module: suppress stderr from apk --version on non-Alpine systems --- build_module.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_module.sh b/build_module.sh index e5295e04..59fdb77e 100755 --- a/build_module.sh +++ b/build_module.sh @@ -182,7 +182,7 @@ elif [ `whereis apt-get 2>/dev/null | grep -c "^apt-get: /"` -eq 1 ]; then PACKAGING_DIR=debian PACKAGE_SOURCES_DIR=extra PACKAGE_OUTPUT_DIR="debuild-module-*/" -elif [ `apk --version | grep -c "^apk-tools"` -eq 1 ]; then +elif [ `apk --version 2>/dev/null | grep -c "^apk-tools"` -eq 1 ]; then PKG_MGR_INSTALL="apk add" PKG_MGR_UPDATE="apk update" PKG_FMT=apk From ccd347a4adfd7be4402d8600eebaa1a09a9cffc6 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:43:30 +0000 Subject: [PATCH 06/17] build_module: quote variables throughout to handle paths with spaces --- build_module.sh | 124 ++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/build_module.sh b/build_module.sh index 59fdb77e..62365a76 100755 --- a/build_module.sh +++ b/build_module.sh @@ -53,7 +53,7 @@ __EOF__ # # Check command line parameters # -ME=`basename $0` +ME=`basename "$0"` if [ $# -eq 0 ]; then echo "USAGE: $ME [options] " echo "" @@ -110,7 +110,7 @@ while [ $# -gt 1 ]; do ;; "-r") BUILD_PLATFORM=Plus - if [ `echo -n $2 | tr -d '[0-9p.]' | wc -c` -gt 0 ]; then + if [ `echo -n "$2" | tr -d '[0-9p.]' | wc -c` -gt 0 ]; then echo "$ME: ERROR: NGINX Plus release must be in the format NN[pN] or NN.N[.N] - quitting" exit 1 elif [ "`echo "10^$2" | tr '^' '\n' | sort -nr | head -1`" = "10" ]; then @@ -118,12 +118,12 @@ while [ $# -gt 1 ]; do exit 1 fi # Normalize NN.N.N to NN.N for git branch naming - PLUS_REL=`echo $2 | sed 's/^\([0-9]*\.[0-9]*\)\.[0-9]*$/\1/'` + PLUS_REL=`echo "$2" | sed 's/^\([0-9]*\.[0-9]*\)\.[0-9]*$/\1/'` shift; shift ;; "-v") BUILD_PLATFORM=OSS - if [ `echo -n .$2 | tr -d '[0-9\.]' | wc -c` -eq 0 ]; then + if [ `echo -n ".$2" | tr -d '[0-9\.]' | wc -c` -eq 0 ]; then OSS_VER=$2 shift fi @@ -134,7 +134,7 @@ while [ $# -gt 1 ]; do shift ;; "-o") - OUTPUT_DIR=`realpath $2` + OUTPUT_DIR=`realpath "$2"` if [ $? -ne 0 ]; then echo "$ME: ERROR: Could not access output directory $2 - quitting" exit 1 @@ -151,8 +151,8 @@ done # # Create package output directory # -if [ ! -d $OUTPUT_DIR ]; then - mkdir -p $OUTPUT_DIR +if [ ! -d "$OUTPUT_DIR" ]; then + mkdir -p "$OUTPUT_DIR" if [ $? -ne 0 ]; then echo "$ME: ERROR: Could not create output directory $OUTPUT_DIR - quitting" exit 1 @@ -221,7 +221,7 @@ if [ "$MODULE_NAME" = "" ]; then # # Construct a reasonable nickname from the module source location # - MODULE_NAME=`basename $1 | tr '[:blank:][:punct:]' '\n' | tr '[A-Z]' '[a-z]' | grep -ve nginx -e ngx -e http -e stream -e module -e plus -e tar -e zip -e gz -e git | tr -d '\n'` + MODULE_NAME=`basename "$1" | tr '[:blank:][:punct:]' '\n' | tr '[A-Z]' '[a-z]' | grep -ve nginx -e ngx -e http -e stream -e module -e plus -e tar -e zip -e gz -e git | tr -d '\n'` if [ -z "$SAY_YES" ]; then echo -n "$ME: INPUT: Enter module nickname [$MODULE_NAME]: " read -r REPLY @@ -237,10 +237,10 @@ fi # Sanitize module nickname (this is a debbuild requirement, probably needs to check for more characters) # while true; do - MODULE_NAME_CLEAN=`echo $MODULE_NAME | tr '[A-Z]' '[a-z]' | tr '[/_\-\.\t ]' '\n' | grep -ve nginx | tr -d '\n'` - if [ "$MODULE_NAME_CLEAN" != "$MODULE_NAME" ] || [ -z $MODULE_NAME ]; then + MODULE_NAME_CLEAN=`echo "$MODULE_NAME" | tr '[A-Z]' '[a-z]' | tr '[/_\-\.\t ]' '\n' | grep -ve nginx | tr -d '\n'` + if [ "$MODULE_NAME_CLEAN" != "$MODULE_NAME" ] || [ -z "$MODULE_NAME" ]; then echo "$ME: WARNING: Removed illegal characters from module nickname - using \"$MODULE_NAME_CLEAN\"" - if [ -z $SAY_YES ]; then + if [ -z "$SAY_YES" ]; then echo -n "$ME: INPUT: Confirm module nickname [$MODULE_NAME_CLEAN]: " read -r MODULE_NAME if [ "$MODULE_NAME" = "" ]; then @@ -285,12 +285,12 @@ try_n_times() { BUILD_DIR=/tmp/$ME.$$ MODULE_DIR=$BUILD_DIR/$MODULE_NAME echo "$ME: INFO: Creating $BUILD_DIR build area" -mkdir $BUILD_DIR +mkdir "$BUILD_DIR" -if [ -d $1 ]; then - mkdir -v $MODULE_DIR +if [ -d "$1" ]; then + mkdir -v "$MODULE_DIR" echo "$ME: INFO: Building $MODULE_NAME from $MODULE_DIR" - cp -a $1/* $MODULE_DIR + cp -a "$1"/* "$MODULE_DIR" else # # Module sources string is not a local directory so assume it is a URL. @@ -299,23 +299,23 @@ else case "${1##*.}" in "git") echo "$ME: INFO: Cloning module source" - git clone --recursive $1 $MODULE_DIR + git clone --recursive "$1" "$MODULE_DIR" ;; "zip") echo "$ME: INFO: Downloading module source" try_n_times 3 "wget -O $BUILD_DIR/module.zip $1" "rm -f $BUILD_DIR/module.zip" - ARCHIVE_DIR=`zipinfo -1 $BUILD_DIR/module.zip | head -n 1 | cut -f1 -d/` - unzip $BUILD_DIR/module.zip -d $BUILD_DIR - mv $BUILD_DIR/$ARCHIVE_DIR $MODULE_DIR + ARCHIVE_DIR=`zipinfo -1 "$BUILD_DIR/module.zip" | head -n 1 | cut -f1 -d/` + unzip "$BUILD_DIR/module.zip" -d "$BUILD_DIR" + mv "$BUILD_DIR/$ARCHIVE_DIR" "$MODULE_DIR" ;; *) echo "$ME: INFO: Downloading module source" # Assume tarball of some kind try_n_times 3 "wget -O $BUILD_DIR/module.tgz $1" "rm -f $BUILD_DIR/module.tgz" - ARCHIVE_DIR=`tar tfz $BUILD_DIR/module.tgz | head -n 1 | cut -f1 -d/` - cd $BUILD_DIR + ARCHIVE_DIR=`tar tfz "$BUILD_DIR/module.tgz" | head -n 1 | cut -f1 -d/` + cd "$BUILD_DIR" tar xfz module.tgz - mv $ARCHIVE_DIR $MODULE_DIR + mv "$ARCHIVE_DIR" "$MODULE_DIR" cd - ;; esac @@ -324,7 +324,7 @@ fi # # Check the module sources look OK # -if [ ! -f $MODULE_DIR/config ]; then +if [ ! -f "$MODULE_DIR/config" ]; then echo "$ME: ERROR: Cannot locate module config file - quitting" exit 1 fi @@ -332,22 +332,22 @@ fi # # Check/convert module config # -if [ `grep -c "\.[[:space:]]auto/module" $MODULE_DIR/config` -eq 0 ]; then +if [ `grep -c "\.[[:space:]]auto/module" "$MODULE_DIR/config"` -eq 0 ]; then if [ $DO_DYNAMIC_CONVERT = 1 ]; then echo "$ME: WARNING: This is a static module, attempting to convert to dynamic (experimental)" - grep -ve HTTP_MODULES -e STREAM_MODULES -e NGX_ADDON_SRCS $MODULE_DIR/config > $MODULE_DIR/config.dynamic - echo "ngx_module_name=`grep ngx_addon_name= $MODULE_DIR/config | cut -f2 -d=`" >> $MODULE_DIR/config.dynamic - if [ `grep -c "HTTP_AUX_FILTER_MODULES=" $MODULE_DIR/config` -gt 0 ]; then - echo "ngx_module_type=HTTP_AUX_FILTER" >> $MODULE_DIR/config.dynamic - elif [ `grep -c "STREAM_MODULES=" $MODULE_DIR/config` -gt 0 ]; then - echo "ngx_module_type=Stream" >> $MODULE_DIR/config.dynamic + grep -ve HTTP_MODULES -e STREAM_MODULES -e NGX_ADDON_SRCS "$MODULE_DIR/config" > "$MODULE_DIR/config.dynamic" + echo "ngx_module_name=`grep ngx_addon_name= "$MODULE_DIR/config" | cut -f2 -d=`" >> "$MODULE_DIR/config.dynamic" + if [ `grep -c "HTTP_AUX_FILTER_MODULES=" "$MODULE_DIR/config"` -gt 0 ]; then + echo "ngx_module_type=HTTP_AUX_FILTER" >> "$MODULE_DIR/config.dynamic" + elif [ `grep -c "STREAM_MODULES=" "$MODULE_DIR/config"` -gt 0 ]; then + echo "ngx_module_type=Stream" >> "$MODULE_DIR/config.dynamic" else - echo "ngx_module_type=HTTP" >> $MODULE_DIR/config.dynamic + echo "ngx_module_type=HTTP" >> "$MODULE_DIR/config.dynamic" fi - echo "ngx_module_srcs=\"`grep NGX_ADDON_SRCS= $MODULE_DIR/config | cut -f2 -d\\" | sed -e 's/^\$NGX_ADDON_SRCS \(\$ngx_addon_dir\/.*$\)/\1/'`\"" >> $MODULE_DIR/config.dynamic - echo ". auto/module" >> $MODULE_DIR/config.dynamic - mv $MODULE_DIR/config $MODULE_DIR/config.static - cp $MODULE_DIR/config.dynamic $MODULE_DIR/config + echo "ngx_module_srcs=\"`grep NGX_ADDON_SRCS= "$MODULE_DIR/config" | cut -f2 -d\\" | sed -e 's/^\$NGX_ADDON_SRCS \(\$ngx_addon_dir\/.*$\)/\1/'`\"" >> "$MODULE_DIR/config.dynamic" + echo ". auto/module" >> "$MODULE_DIR/config.dynamic" + mv "$MODULE_DIR/config" "$MODULE_DIR/config.static" + cp "$MODULE_DIR/config.dynamic" "$MODULE_DIR/config" else echo "$ME: ERROR: This is a static module and should be updated to dynamic configuration. To attempt automatic conversion to dynamic module configuration use the '--force-dynamic' option. This will not modify the original configuration. Quitting." exit 1 @@ -358,30 +358,30 @@ fi # Get the internal module name(s) from the module config so we can write # the .so files into the postinstall banner. # -touch $BUILD_DIR/postinstall.txt -for MODULE_SO_NAME in $(grep ngx_module_name= $MODULE_DIR/config | cut -f2 -d= | cut -f2 -d\"); do - if [ "`echo $MODULE_SO_NAME | cut -c1`" = "$" ]; then +touch "$BUILD_DIR/postinstall.txt" +for MODULE_SO_NAME in $(grep ngx_module_name= "$MODULE_DIR/config" | cut -f2 -d= | cut -f2 -d\"); do + if [ "`echo "$MODULE_SO_NAME" | cut -c1`" = "$" ]; then # Dereference variable - SOURCE_VAR=`echo $MODULE_SO_NAME | cut -f2 -d\$` - MODULE_SO_NAME=`grep $SOURCE_VAR= $MODULE_DIR/config | cut -f2 -d= | cut -f2 -d\"` + SOURCE_VAR=`echo "$MODULE_SO_NAME" | cut -f2 -d\$` + MODULE_SO_NAME=`grep "$SOURCE_VAR=" "$MODULE_DIR/config" | cut -f2 -d= | cut -f2 -d\"` fi # Only write load_module line when no backslash present (can't cope with multi-line values) - echo $MODULE_SO_NAME | grep -c '\\' > /dev/null + echo "$MODULE_SO_NAME" | grep -c '\\' > /dev/null if [ $? -eq 1 ]; then - echo " load_module modules/$MODULE_SO_NAME.so;" >> $BUILD_DIR/postinstall.txt + echo " load_module modules/$MODULE_SO_NAME.so;" >> "$BUILD_DIR/postinstall.txt" fi done -if [ ! -s $BUILD_DIR/postinstall.txt ]; then +if [ ! -s "$BUILD_DIR/postinstall.txt" ]; then # Didn't find any .so names so this is a final attempt to extract from config file - MODULE_SO_NAME=`grep ngx_addon_name= $MODULE_DIR/config | cut -f2 -d= | cut -f2 -d\"` - echo " load_module modules/$MODULE_SO_NAME.so;" >> $BUILD_DIR/postinstall.txt + MODULE_SO_NAME=`grep ngx_addon_name= "$MODULE_DIR/config" | cut -f2 -d= | cut -f2 -d\"` + echo " load_module modules/$MODULE_SO_NAME.so;" >> "$BUILD_DIR/postinstall.txt" fi # # Get NGINX OSS packaging tool # echo "$ME: INFO: Downloading NGINX packaging tool" -cd $BUILD_DIR +cd "$BUILD_DIR" PKG_OSS_URL="https://github.com/nginx/pkg-oss" @@ -412,7 +412,7 @@ fi # # Archive the module source for use with packaging tool using the base OSS version # -cd $BUILD_DIR +cd "$BUILD_DIR" if [ -d pkg-oss/contrib ]; then VERSION=`grep "^NGINX_VERSION :=" pkg-oss/contrib/src/nginx/version | cut -f2 -d= | tr -d "[:blank:]"` else @@ -423,17 +423,17 @@ if [ -z "$VERSION" ]; then exit 1 fi echo "$ME: INFO: Archiving module source for $VERSION" -mv $MODULE_NAME $MODULE_NAME-$VERSION -tar cf - $MODULE_NAME-$VERSION | gzip -1 > $MODULE_NAME-$VERSION.tar.gz +mv "$MODULE_NAME" "$MODULE_NAME-$VERSION" +tar cf - "$MODULE_NAME-$VERSION" | gzip -1 > "$MODULE_NAME-$VERSION.tar.gz" if [ -d pkg-oss/contrib ]; then - cp $MODULE_NAME-$VERSION.tar.gz pkg-oss/contrib/tarballs/ + cp "$MODULE_NAME-$VERSION.tar.gz" pkg-oss/contrib/tarballs/ else - cp $MODULE_NAME-$VERSION.tar.gz $OLDPWD/$PACKAGE_SOURCES_DIR/ + cp "$MODULE_NAME-$VERSION.tar.gz" "$OLDPWD/$PACKAGE_SOURCES_DIR/" fi cd - echo "$ME: INFO: Creating changelog" -cd $BUILD_DIR +cd "$BUILD_DIR" cat << __EOF__ >pkg-oss/docs/nginx-module-$MODULE_NAME.xml @@ -492,9 +492,9 @@ endef export MODULE_POST_$MODULE_NAME __EOF__ -cp Makefile.module-$MODULE_NAME $BUILD_DIR/pkg-oss/rpm/SPECS/ -cp Makefile.module-$MODULE_NAME $BUILD_DIR/pkg-oss/debian/ -cp Makefile.module-$MODULE_NAME $BUILD_DIR/pkg-oss/alpine/ +cp "Makefile.module-$MODULE_NAME" "$BUILD_DIR/pkg-oss/rpm/SPECS/" +cp "Makefile.module-$MODULE_NAME" "$BUILD_DIR/pkg-oss/debian/" +cp "Makefile.module-$MODULE_NAME" "$BUILD_DIR/pkg-oss/alpine/" # # Build! @@ -502,11 +502,11 @@ cp Makefile.module-$MODULE_NAME $BUILD_DIR/pkg-oss/alpine/ echo "$ME: INFO: Building" if [ "$PKG_FMT" = "rpm" ]; then - cd $BUILD_DIR/pkg-oss/rpm/SPECS + cd "$BUILD_DIR/pkg-oss/rpm/SPECS" elif [ "$PKG_FMT" = "deb" ]; then - cd $BUILD_DIR/pkg-oss/debian + cd "$BUILD_DIR/pkg-oss/debian" else - cd $BUILD_DIR/pkg-oss/alpine + cd "$BUILD_DIR/pkg-oss/alpine" fi if [ "$BUILD_PLATFORM" = "Plus" ]; then @@ -520,14 +520,14 @@ if [ $? -ne 0 ]; then else echo "" echo "$ME: INFO: Module binaries created" - find $BUILD_DIR/$PACKAGING_ROOT -type f -name "*.so" -print + find "$BUILD_DIR/$PACKAGING_ROOT" -type f -name "*.so" -print echo "$ME: INFO: Module packages created" if [ "$PKG_FMT" = "apk" ]; then - find ~/packages -type f -name "*.$PKG_FMT" -exec $COPY_CMD -v {} $OUTPUT_DIR/ \; + find ~/packages -type f -name "*.$PKG_FMT" -exec $COPY_CMD -v {} "$OUTPUT_DIR/" \; else - find $BUILD_DIR/$PACKAGING_ROOT$PACKAGE_OUTPUT_DIR -type f -name "*.$PKG_FMT" -exec $COPY_CMD -v {} $OUTPUT_DIR/ \; + find "$BUILD_DIR/$PACKAGING_ROOT$PACKAGE_OUTPUT_DIR" -type f -name "*.$PKG_FMT" -exec $COPY_CMD -v {} "$OUTPUT_DIR/" \; fi echo "$ME: INFO: Removing $BUILD_DIR" - rm -fr $BUILD_DIR + rm -fr "$BUILD_DIR" fi From 4ed3b0adf876bfdb44515a4bbc93d3738f89027d Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:44:02 +0000 Subject: [PATCH 07/17] build_module: add error handling for all cd invocations --- build_module.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build_module.sh b/build_module.sh index 62365a76..e9a53e78 100755 --- a/build_module.sh +++ b/build_module.sh @@ -313,10 +313,10 @@ else # Assume tarball of some kind try_n_times 3 "wget -O $BUILD_DIR/module.tgz $1" "rm -f $BUILD_DIR/module.tgz" ARCHIVE_DIR=`tar tfz "$BUILD_DIR/module.tgz" | head -n 1 | cut -f1 -d/` - cd "$BUILD_DIR" + cd "$BUILD_DIR" || { echo "$ME: ERROR: Could not enter build directory - quitting"; exit 1; } tar xfz module.tgz mv "$ARCHIVE_DIR" "$MODULE_DIR" - cd - + cd - > /dev/null || { echo "$ME: ERROR: Could not return from build directory - quitting"; exit 1; } ;; esac fi @@ -381,7 +381,7 @@ fi # Get NGINX OSS packaging tool # echo "$ME: INFO: Downloading NGINX packaging tool" -cd "$BUILD_DIR" +cd "$BUILD_DIR" || { echo "$ME: ERROR: Could not enter build directory - quitting"; exit 1; } PKG_OSS_URL="https://github.com/nginx/pkg-oss" @@ -412,7 +412,7 @@ fi # # Archive the module source for use with packaging tool using the base OSS version # -cd "$BUILD_DIR" +cd "$BUILD_DIR" || { echo "$ME: ERROR: Could not enter build directory - quitting"; exit 1; } if [ -d pkg-oss/contrib ]; then VERSION=`grep "^NGINX_VERSION :=" pkg-oss/contrib/src/nginx/version | cut -f2 -d= | tr -d "[:blank:]"` else @@ -430,10 +430,10 @@ if [ -d pkg-oss/contrib ]; then else cp "$MODULE_NAME-$VERSION.tar.gz" "$OLDPWD/$PACKAGE_SOURCES_DIR/" fi -cd - +cd - > /dev/null || { echo "$ME: ERROR: Could not return from build directory - quitting"; exit 1; } echo "$ME: INFO: Creating changelog" -cd "$BUILD_DIR" +cd "$BUILD_DIR" || { echo "$ME: ERROR: Could not enter build directory - quitting"; exit 1; } cat << __EOF__ >pkg-oss/docs/nginx-module-$MODULE_NAME.xml @@ -502,11 +502,11 @@ cp "Makefile.module-$MODULE_NAME" "$BUILD_DIR/pkg-oss/alpine/" echo "$ME: INFO: Building" if [ "$PKG_FMT" = "rpm" ]; then - cd "$BUILD_DIR/pkg-oss/rpm/SPECS" + cd "$BUILD_DIR/pkg-oss/rpm/SPECS" || { echo "$ME: ERROR: Could not enter packaging directory - quitting"; exit 1; } elif [ "$PKG_FMT" = "deb" ]; then - cd "$BUILD_DIR/pkg-oss/debian" + cd "$BUILD_DIR/pkg-oss/debian" || { echo "$ME: ERROR: Could not enter packaging directory - quitting"; exit 1; } else - cd "$BUILD_DIR/pkg-oss/alpine" + cd "$BUILD_DIR/pkg-oss/alpine" || { echo "$ME: ERROR: Could not enter packaging directory - quitting"; exit 1; } fi if [ "$BUILD_PLATFORM" = "Plus" ]; then From 1eb4b75f5866b19caaa74c418949ec14999b0f5f Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Fri, 15 May 2026 00:44:14 +0000 Subject: [PATCH 08/17] build_module: add early validation for arguments --- build_module.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build_module.sh b/build_module.sh index e9a53e78..1069727b 100755 --- a/build_module.sh +++ b/build_module.sh @@ -148,6 +148,20 @@ while [ $# -gt 1 ]; do esac done +# +# Validate remaining argument is the module source, not a dangling option +# +if [ $# -ne 1 ] || [ -z "$1" ]; then + echo "$ME: ERROR: Missing module source - quitting" + exit 1 +fi +case "$1" in + -*) + echo "$ME: ERROR: Missing argument for option or missing module source - quitting" + exit 1 + ;; +esac + # # Create package output directory # From 61bf0823a69741c79e154461299d9c4b6df37777 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 2 Jun 2026 23:51:31 +0000 Subject: [PATCH 09/17] build_module: validate archive top-level directory to prevent path traversal --- build_module.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/build_module.sh b/build_module.sh index 1069727b..90136593 100755 --- a/build_module.sh +++ b/build_module.sh @@ -319,6 +319,12 @@ else echo "$ME: INFO: Downloading module source" try_n_times 3 "wget -O $BUILD_DIR/module.zip $1" "rm -f $BUILD_DIR/module.zip" ARCHIVE_DIR=`zipinfo -1 "$BUILD_DIR/module.zip" | head -n 1 | cut -f1 -d/` + case "$ARCHIVE_DIR" in + "" | . | ..) + echo "$ME: ERROR: Unsafe path in module zip archive - quitting" + exit 1 + ;; + esac unzip "$BUILD_DIR/module.zip" -d "$BUILD_DIR" mv "$BUILD_DIR/$ARCHIVE_DIR" "$MODULE_DIR" ;; @@ -327,6 +333,12 @@ else # Assume tarball of some kind try_n_times 3 "wget -O $BUILD_DIR/module.tgz $1" "rm -f $BUILD_DIR/module.tgz" ARCHIVE_DIR=`tar tfz "$BUILD_DIR/module.tgz" | head -n 1 | cut -f1 -d/` + case "$ARCHIVE_DIR" in + "" | . | ..) + echo "$ME: ERROR: Unsafe path in module tar archive - quitting" + exit 1 + ;; + esac cd "$BUILD_DIR" || { echo "$ME: ERROR: Could not enter build directory - quitting"; exit 1; } tar xfz module.tgz mv "$ARCHIVE_DIR" "$MODULE_DIR" From 0999e183c92382b8d3d5f547174e84feafce249a Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 2 Jun 2026 23:59:26 +0000 Subject: [PATCH 10/17] build_module: replace try_n_times with wget_n_times and check the exit code --- build_module.sh | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/build_module.sh b/build_module.sh index 90136593..e655a6c9 100755 --- a/build_module.sh +++ b/build_module.sh @@ -270,20 +270,20 @@ while true; do done # -# A generic helper function to retry any command with a backoff strategy +# Download a URL to a file, retrying up to 3 times with exponential backoff # -try_n_times() { +wget_n_times() { MAX_ATTEMPTS=$1 - CMD=$2 - CLEAN_CMD=$3 + OUTPUT="$2" + URL="$3" i=0 WAIT_TIME=1 - while ! $CMD; do + while ! wget -O "$OUTPUT" "$URL"; do i=$(expr $i + 1) if [ $i -le $MAX_ATTEMPTS ]; then echo "Attempt $i failed! Waiting $WAIT_TIME seconds before retry..." sleep $WAIT_TIME - test -n "$CLEAN_CMD" && $CLEAN_CMD + rm -f "$OUTPUT" WAIT_TIME=$(expr $WAIT_TIME \* 2) else echo "$MAX_ATTEMPTS attempts failed!" @@ -317,7 +317,10 @@ else ;; "zip") echo "$ME: INFO: Downloading module source" - try_n_times 3 "wget -O $BUILD_DIR/module.zip $1" "rm -f $BUILD_DIR/module.zip" + if ! wget_n_times 3 "$BUILD_DIR/module.zip" "$1"; then + echo "$ME: ERROR: Failed to download module source from $1 - quitting" + exit 1 + fi ARCHIVE_DIR=`zipinfo -1 "$BUILD_DIR/module.zip" | head -n 1 | cut -f1 -d/` case "$ARCHIVE_DIR" in "" | . | ..) @@ -331,7 +334,10 @@ else *) echo "$ME: INFO: Downloading module source" # Assume tarball of some kind - try_n_times 3 "wget -O $BUILD_DIR/module.tgz $1" "rm -f $BUILD_DIR/module.tgz" + if ! wget_n_times 3 "$BUILD_DIR/module.tgz" "$1"; then + echo "$ME: ERROR: Failed to download module source from $1 - quitting" + exit 1 + fi ARCHIVE_DIR=`tar tfz "$BUILD_DIR/module.tgz" | head -n 1 | cut -f1 -d/` case "$ARCHIVE_DIR" in "" | . | ..) From 13d85d12da9595871222efa011c9a1b3df22ddd8 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 2 Jun 2026 18:51:55 -0700 Subject: [PATCH 11/17] build_module: correct wget_n_times retry count --- build_module.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_module.sh b/build_module.sh index e655a6c9..8ebf6a27 100755 --- a/build_module.sh +++ b/build_module.sh @@ -280,7 +280,7 @@ wget_n_times() { WAIT_TIME=1 while ! wget -O "$OUTPUT" "$URL"; do i=$(expr $i + 1) - if [ $i -le $MAX_ATTEMPTS ]; then + if [ $i -lt $MAX_ATTEMPTS ]; then echo "Attempt $i failed! Waiting $WAIT_TIME seconds before retry..." sleep $WAIT_TIME rm -f "$OUTPUT" From caa410bc04f417e8761e6774a2e43db5535940e1 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 3 Jun 2026 00:10:04 +0000 Subject: [PATCH 12/17] build_module: use mktemp -d for unpredictable temporary build directory --- build_module.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build_module.sh b/build_module.sh index 8ebf6a27..2657109a 100755 --- a/build_module.sh +++ b/build_module.sh @@ -296,10 +296,9 @@ wget_n_times() { # # Create temporary build area, with working copy of module source # -BUILD_DIR=/tmp/$ME.$$ +BUILD_DIR=$(mktemp -d) MODULE_DIR=$BUILD_DIR/$MODULE_NAME echo "$ME: INFO: Creating $BUILD_DIR build area" -mkdir "$BUILD_DIR" if [ -d "$1" ]; then mkdir -v "$MODULE_DIR" From e146feaa93ea9bf634fbdd6955b02a0ca761c20c Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 2 Jun 2026 17:47:52 -0700 Subject: [PATCH 13/17] build_module: fix artifacts collection for debian-based distros --- build_module.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_module.sh b/build_module.sh index 2657109a..f6e68048 100755 --- a/build_module.sh +++ b/build_module.sh @@ -557,7 +557,7 @@ else if [ "$PKG_FMT" = "apk" ]; then find ~/packages -type f -name "*.$PKG_FMT" -exec $COPY_CMD -v {} "$OUTPUT_DIR/" \; else - find "$BUILD_DIR/$PACKAGING_ROOT$PACKAGE_OUTPUT_DIR" -type f -name "*.$PKG_FMT" -exec $COPY_CMD -v {} "$OUTPUT_DIR/" \; + find "$BUILD_DIR/$PACKAGING_ROOT" -type f -name "*.$PKG_FMT" -path "*/$PACKAGE_OUTPUT_DIR*" -exec $COPY_CMD -v {} "$OUTPUT_DIR/" \; fi echo "$ME: INFO: Removing $BUILD_DIR" rm -fr "$BUILD_DIR" From 95176bb750fbdaf5c32bf1413400ef3d3da42be4 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 2 Jun 2026 18:10:59 -0700 Subject: [PATCH 14/17] build_module: replace non-POSIX echo invocations with printf --- build_module.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build_module.sh b/build_module.sh index f6e68048..196b908e 100755 --- a/build_module.sh +++ b/build_module.sh @@ -110,7 +110,7 @@ while [ $# -gt 1 ]; do ;; "-r") BUILD_PLATFORM=Plus - if [ `echo -n "$2" | tr -d '[0-9p.]' | wc -c` -gt 0 ]; then + if [ `printf '%s' "$2" | tr -d '[0-9p.]' | wc -c` -gt 0 ]; then echo "$ME: ERROR: NGINX Plus release must be in the format NN[pN] or NN.N[.N] - quitting" exit 1 elif [ "`echo "10^$2" | tr '^' '\n' | sort -nr | head -1`" = "10" ]; then @@ -123,7 +123,7 @@ while [ $# -gt 1 ]; do ;; "-v") BUILD_PLATFORM=OSS - if [ `echo -n ".$2" | tr -d '[0-9\.]' | wc -c` -eq 0 ]; then + if [ `printf '%s' ".$2" | tr -d '[0-9\.]' | wc -c` -eq 0 ]; then OSS_VER=$2 shift fi @@ -237,7 +237,7 @@ if [ "$MODULE_NAME" = "" ]; then # MODULE_NAME=`basename "$1" | tr '[:blank:][:punct:]' '\n' | tr '[A-Z]' '[a-z]' | grep -ve nginx -e ngx -e http -e stream -e module -e plus -e tar -e zip -e gz -e git | tr -d '\n'` if [ -z "$SAY_YES" ]; then - echo -n "$ME: INPUT: Enter module nickname [$MODULE_NAME]: " + printf '%s' "$ME: INPUT: Enter module nickname [$MODULE_NAME]: " read -r REPLY if [ "$REPLY" != "" ]; then MODULE_NAME=$REPLY @@ -255,7 +255,7 @@ while true; do if [ "$MODULE_NAME_CLEAN" != "$MODULE_NAME" ] || [ -z "$MODULE_NAME" ]; then echo "$ME: WARNING: Removed illegal characters from module nickname - using \"$MODULE_NAME_CLEAN\"" if [ -z "$SAY_YES" ]; then - echo -n "$ME: INPUT: Confirm module nickname [$MODULE_NAME_CLEAN]: " + printf '%s' "$ME: INPUT: Confirm module nickname [$MODULE_NAME_CLEAN]: " read -r MODULE_NAME if [ "$MODULE_NAME" = "" ]; then MODULE_NAME=$MODULE_NAME_CLEAN From 10f2bbb280385ed56937beb66cb3cdbad05fd8c5 Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Tue, 2 Jun 2026 18:13:13 -0700 Subject: [PATCH 15/17] build_module: exit on git clone failure for module source --- build_module.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build_module.sh b/build_module.sh index 196b908e..e691c51c 100755 --- a/build_module.sh +++ b/build_module.sh @@ -312,7 +312,10 @@ else case "${1##*.}" in "git") echo "$ME: INFO: Cloning module source" - git clone --recursive "$1" "$MODULE_DIR" + if ! git clone --recursive "$1" "$MODULE_DIR"; then + echo "$ME: ERROR: Failed to clone module source from $1 - quitting" + exit 1 + fi ;; "zip") echo "$ME: INFO: Downloading module source" From 3350e869ed9ebd18377c4fdc4a7cd7cbd5c461de Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 3 Jun 2026 17:09:40 -0700 Subject: [PATCH 16/17] build_module: use /. to copy directory contents including dotfiles --- build_module.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_module.sh b/build_module.sh index e691c51c..0a8c5ab0 100755 --- a/build_module.sh +++ b/build_module.sh @@ -303,7 +303,7 @@ echo "$ME: INFO: Creating $BUILD_DIR build area" if [ -d "$1" ]; then mkdir -v "$MODULE_DIR" echo "$ME: INFO: Building $MODULE_NAME from $MODULE_DIR" - cp -a "$1"/* "$MODULE_DIR" + cp -a "$1"/. "$MODULE_DIR" else # # Module sources string is not a local directory so assume it is a URL. From 344c036ebf30c6a5d554ad2206ba22da24fb5ace Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Wed, 3 Jun 2026 00:32:41 +0000 Subject: [PATCH 17/17] CI: add build_module.sh test workflow Tests build_module.sh against: - AlmaLinux 9, Ubuntu 26.04, Alpine 3.23 - NGINX OSS (latest mainline) and NGINX Plus R37.0 --- .github/workflows/build-module.yml | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .github/workflows/build-module.yml diff --git a/.github/workflows/build-module.yml b/.github/workflows/build-module.yml new file mode 100644 index 00000000..38ff3285 --- /dev/null +++ b/.github/workflows/build-module.yml @@ -0,0 +1,52 @@ +name: build_module.sh CI + +on: + pull_request: + push: + workflow_dispatch: + +defaults: + run: + shell: sh -e {0} + +jobs: + build-module: + name: build-module (${{ matrix.os.container }}, ${{ matrix.nginx.flavor }}) + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + os: + - container: almalinux:9 + pre_install: | + dnf install -y git + - container: ubuntu:26.04 + pre_install: | + apt-get update + apt-get install -y --no-install-recommends git ca-certificates + - container: alpine:3.23 + pre_install: | + apk add --no-cache git + printf "#!/bin/sh\\nSETFATTR=true /usr/bin/abuild -F \"\$@\"\\n" > /usr/local/bin/abuild + chmod +x /usr/local/bin/abuild + nginx: + - flavor: oss + build_args: "" + - flavor: plus + build_args: "-r 37.0" + container: ${{ matrix.os.container }} + + steps: + - name: Install prerequisites + run: ${{ matrix.os.pre_install }} + + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Build echo-nginx-module (${{ matrix.nginx.flavor }}) + run: | + sh build_module.sh -y -n echo ${{ matrix.nginx.build_args }} -V 0.64 \ + https://github.com/openresty/echo-nginx-module/archive/v0.64.tar.gz + + - name: List built packages + if: always() + run: find build-module-artifacts -type f | xargs ls -ld