summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-17 08:15:35 +0300
committerPaul Buetow <paul@buetow.org>2026-06-17 08:15:35 +0300
commit50d951ab3bb28861b34bc190911dd76bfb93e71c (patch)
treed78bfe5a1620502fca10e78fc0328092d408742e
parentca5bcf37e40d4dbd41dc9d9d001d6f4b9c6dcd65 (diff)
bn0 guard preview_num arithmetic against non-numeric input
The preview_num next/prev render handlers computed neighbour page numbers with $(( context_value +/- 1 )) but only guarded against an empty value. A non-numeric preview_num context value (e.g. a stray string) slipped past the [ -n ] check and triggered a bash arithmetic syntax error which, under set -e, aborted the whole script. Validate the context value is a non-negative integer ([[ value =~ ^[0-9]+$ ]]) before the arithmetic in both prepare_template_render_var__preview_num_next_html and __preview_num_prev_html. Invalid or missing values now default to an empty render value, matching the existing missing-neighbour behaviour; the valid-numeric path is unchanged. Add test_template_render_var_preview_num_guards_non_numeric in tests/cli.sh, which drives the handlers directly under bash -euo pipefail to prove a bad preview_num no longer crashes and a numeric one still yields the exact +1 / -1 neighbour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
-rwxr-xr-xbin/shuriken14
-rw-r--r--src/lib/template.source.sh14
-rwxr-xr-xtests/cli.sh54
3 files changed, 78 insertions, 4 deletions
diff --git a/bin/shuriken b/bin/shuriken
index 1caacef..216460c 100755
--- a/bin/shuriken
+++ b/bin/shuriken
@@ -1077,7 +1077,12 @@ prepare_template_render_var__preview_num_next_html() {
local context_value
template_context_value_to context_value "$context_name" "$source_name"
- if [ -n "$context_value" ]; then
+ # Guard the arithmetic: only a non-negative integer is safe to feed to
+ # $(( )). An empty or non-numeric context value (e.g. a stray string) would
+ # otherwise throw a bash arithmetic syntax error and, under set -e, abort the
+ # whole script. Treat any invalid/missing preview_num as "no neighbour" and
+ # emit an empty render value, matching the missing-value behaviour.
+ if [[ "$context_value" =~ ^[0-9]+$ ]]; then
html_escape_to out_ref "$(( context_value + 1 ))"
else
out_ref=''
@@ -1093,7 +1098,12 @@ prepare_template_render_var__preview_num_prev_html() {
local context_value
template_context_value_to context_value "$context_name" "$source_name"
- if [ -n "$context_value" ]; then
+ # Guard the arithmetic: only a non-negative integer is safe to feed to
+ # $(( )). An empty or non-numeric context value would otherwise throw a bash
+ # arithmetic syntax error and, under set -e, abort the whole script. Treat
+ # any invalid/missing preview_num as "no neighbour" and emit an empty render
+ # value, mirroring the next-html handler.
+ if [[ "$context_value" =~ ^[0-9]+$ ]]; then
html_escape_to out_ref "$(( context_value - 1 ))"
else
out_ref=''
diff --git a/src/lib/template.source.sh b/src/lib/template.source.sh
index cd44a45..cfa826e 100644
--- a/src/lib/template.source.sh
+++ b/src/lib/template.source.sh
@@ -582,7 +582,12 @@ prepare_template_render_var__preview_num_next_html() {
local context_value
template_context_value_to context_value "$context_name" "$source_name"
- if [ -n "$context_value" ]; then
+ # Guard the arithmetic: only a non-negative integer is safe to feed to
+ # $(( )). An empty or non-numeric context value (e.g. a stray string) would
+ # otherwise throw a bash arithmetic syntax error and, under set -e, abort the
+ # whole script. Treat any invalid/missing preview_num as "no neighbour" and
+ # emit an empty render value, matching the missing-value behaviour.
+ if [[ "$context_value" =~ ^[0-9]+$ ]]; then
html_escape_to out_ref "$(( context_value + 1 ))"
else
out_ref=''
@@ -598,7 +603,12 @@ prepare_template_render_var__preview_num_prev_html() {
local context_value
template_context_value_to context_value "$context_name" "$source_name"
- if [ -n "$context_value" ]; then
+ # Guard the arithmetic: only a non-negative integer is safe to feed to
+ # $(( )). An empty or non-numeric context value would otherwise throw a bash
+ # arithmetic syntax error and, under set -e, abort the whole script. Treat
+ # any invalid/missing preview_num as "no neighbour" and emit an empty render
+ # value, mirroring the next-html handler.
+ if [[ "$context_value" =~ ^[0-9]+$ ]]; then
html_escape_to out_ref "$(( context_value - 1 ))"
else
out_ref=''
diff --git a/tests/cli.sh b/tests/cli.sh
index 859d104..a16cbea 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -4137,6 +4137,57 @@ BASH
fi
}
+# The preview_num next/prev handlers compute neighbour page numbers with $(( )).
+# A non-numeric or empty preview_num context value must NOT crash the script with
+# a bash arithmetic syntax error (which, under set -e, would abort the whole run):
+# such values default to an empty render value. A valid numeric value must still
+# produce the exact +1 / -1 neighbour. We drive the handlers directly under
+# `bash -euo pipefail` so a regressed (unguarded) arithmetic would abort here.
+test_template_render_var_preview_num_guards_non_numeric() {
+ local output
+
+ output=$(
+ bash -euo pipefail -s "$TEST_REPO_ROOT" <<'BASH'
+repo_root="$1"; shift
+
+# shellcheck source=src/lib/config.validate.source.sh
+source "$repo_root/src/lib/config.validate.source.sh"
+# shellcheck source=src/lib/template.source.sh
+source "$repo_root/src/lib/template.source.sh"
+
+declare -A ctx
+out=''
+
+# Non-numeric preview_num must not crash; both handlers default to empty.
+ctx[preview_num]='not-a-number'
+prepare_template_render_var__preview_num_next_html out ctx preview_num
+printf 'bad_next=[%s]\n' "$out"
+prepare_template_render_var__preview_num_prev_html out ctx preview_num
+printf 'bad_prev=[%s]\n' "$out"
+
+# Empty preview_num also defaults to empty (missing-neighbour behaviour).
+ctx[preview_num]=''
+prepare_template_render_var__preview_num_next_html out ctx preview_num
+printf 'empty_next=[%s]\n' "$out"
+
+# A valid numeric preview_num still yields the exact +1 / -1 neighbour.
+ctx[preview_num]='5'
+prepare_template_render_var__preview_num_next_html out ctx preview_num
+printf 'good_next=[%s]\n' "$out"
+prepare_template_render_var__preview_num_prev_html out ctx preview_num
+printf 'good_prev=[%s]\n' "$out"
+BASH
+ )
+
+ if [ "$output" != \
+ $'bad_next=[]\nbad_prev=[]\nempty_next=[]\ngood_next=[6]\ngood_prev=[4]' ]
+ then
+ printf 'FAIL: preview_num handlers mishandle non-numeric input\n' >&2
+ printf 'actual:\n%s\n' "$output" >&2
+ exit 1
+ fi
+}
+
test_render_stats_page_renders_sections_and_escapes() {
local html
local output_file
@@ -5993,6 +6044,9 @@ main() {
'template render var dispatch is extensible (OCP)' \
test_template_render_var_dispatch_is_extensible
test::run_case \
+ 'preview_num render handlers guard non-numeric input' \
+ test_template_render_var_preview_num_guards_non_numeric
+ test::run_case \
'render_stats_page renders sections and escapes EXIF labels' \
test_render_stats_page_renders_sections_and_escapes
test::run_case \