Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions lib/bash/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ Reusable Bash libraries for command wrappers and other Bash tooling.
The Base runtime shell files and Base version helpers remain in
`basefoundry/base`. This repository carries only sourceable reusable library
modules.

## Naming Contract

Public helpers that write through caller-supplied variable or array names
reserve the `__` prefix for library-internal state. Passing an output name that
begins with `__` fails before the helper changes caller state. Use a regular
Bash variable name for public output values and arrays.
19 changes: 19 additions & 0 deletions lib/bash/arg/tests/lib_arg.bats
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,25 @@ EOF
[ "${positionals_name[0]}" = "item" ]
}

@test "arg_parse rejects reserved internal output names" {
local -A __arg_options=([sentinel]="keep")
local -a __arg_positionals=(sentinel)
local -a specs_name=("verbose|flag|--verbose|-v")
local stderr_file="$TEST_TMPDIR/arg-reserved-output.err"
local rc

if arg_parse __arg_options __arg_positionals specs_name -- -v 2>"$stderr_file"; then
rc=0
else
rc=$?
fi

[ "$rc" -eq 1 ]
[ "${__arg_options[sentinel]}" = "keep" ]
[ "${__arg_positionals[0]}" = "sentinel" ]
[[ "$(cat "$stderr_file")" == *"uses the reserved '__' internal namespace"* ]]
}

@test "arg_parse accepts long option equals values and repeated options" {
local -a specs=(
"verbose|flag|--verbose|-v"
Expand Down
7 changes: 4 additions & 3 deletions lib/bash/gh/lib_gh.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ gh_infer_repo_from_origin() {
local __gh_infer_repo_dir="$1"
local __gh_infer_result_name="${2:-}"
local __gh_infer_optional=0
local __gh_infer_repo __gh_infer_remote_url
local gh_infer_parsed_repo __gh_infer_remote_url

if [[ -z "$__gh_infer_repo_dir" || -z "$__gh_infer_result_name" ]]; then
log_error -l base_bash_libs.gh "Usage: gh_infer_repo_from_origin <repo_dir> <result_variable_name> [--optional]"
Expand All @@ -110,7 +110,8 @@ gh_infer_repo_from_origin() {
fi

__gh_infer_remote_url="$(git -C "$__gh_infer_repo_dir" remote get-url origin 2>/dev/null || true)"
if [[ -z "$__gh_infer_remote_url" ]] || ! gh_repo_from_remote_url "$__gh_infer_remote_url" __gh_infer_repo; then
if [[ -z "$__gh_infer_remote_url" ]] ||
! gh_repo_from_remote_url "$__gh_infer_remote_url" gh_infer_parsed_repo; then
if ((__gh_infer_optional)); then
printf -v "$__gh_infer_result_name" '%s' ""
return 0
Expand All @@ -119,7 +120,7 @@ gh_infer_repo_from_origin() {
return 1
fi

printf -v "$__gh_infer_result_name" '%s' "$__gh_infer_repo"
printf -v "$__gh_infer_result_name" '%s' "$gh_infer_parsed_repo"
}

gh_repo_default_branch() {
Expand Down
5 changes: 5 additions & 0 deletions lib/bash/std/lib_std.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,11 @@ __is_valid_variable_name__() {
__std_assert_writable_output__() {
local function_name="${1-}" output_name="${2-}" declaration attributes

if [[ "$output_name" == __* ]]; then
log_error -l base_bash_libs.std "$function_name: result variable '$output_name' uses the reserved '__' internal namespace."
return 1
fi

declaration="$(declare -p "$output_name" 2>/dev/null || true)"
[[ -n "$declaration" ]] || return 0
attributes="${declaration#declare -}"
Expand Down
16 changes: 16 additions & 0 deletions lib/bash/str/tests/lib_str.bats
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,22 @@ EOF
[ "$joined" = "left|right" ]
}

@test "str_lower rejects reserved internal output names" {
local __str_var_name="Mixed Case"
local stderr_file="$TEST_TMPDIR/str-reserved-output.err"
local rc

if str_lower __str_var_name 2>"$stderr_file"; then
rc=0
else
rc=$?
fi

[ "$rc" -eq 1 ]
[ "$__str_var_name" = "Mixed Case" ]
[[ "$(cat "$stderr_file")" == *"uses the reserved '__' internal namespace"* ]]
}

@test "str_join rejects invalid variable names" {
local script="$TEST_TMPDIR/str-join-invalid-array.sh"

Expand Down
Loading