diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-17 08:15:35 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-17 08:15:35 +0300 |
| commit | 50d951ab3bb28861b34bc190911dd76bfb93e71c (patch) | |
| tree | d78bfe5a1620502fca10e78fc0328092d408742e | |
| parent | ca5bcf37e40d4dbd41dc9d9d001d6f4b9c6dcd65 (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-x | bin/shuriken | 14 | ||||
| -rw-r--r-- | src/lib/template.source.sh | 14 | ||||
| -rwxr-xr-x | tests/cli.sh | 54 |
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 \ |
