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
11 changes: 7 additions & 4 deletions docs/vendor-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ its own `base-bash-libs.lock`, so consumers can verify it independently:
scripts/vendor verify dist/app/vendor/base-bash-libs
```

Both framework copies carry the same `MANIFEST.sha256`, version, and source commit from
the input bundle. Standalone creation stages the complete payload and its lock
before one atomic move. No command downloads, executes, or evaluates remote
content.
Both framework copies carry the same framework version, source commit, and
canonical manifest before the application payload is restored. The root copy's
manifest then records the application's user-visible `VERSION`, while
`BASE_BASH_STANDALONE.release` binds `framework_lock` to the canonical manifest
in `vendor/base-bash-libs`. Standalone creation stages the complete payload and
its lock before one atomic move. No command downloads, executes, or evaluates
remote content.
28 changes: 28 additions & 0 deletions scripts/bundle-manifest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

# Shared validation for paths named by MANIFEST.sha256 files. Callers retain
# responsibility for reporting the context-specific failure message.

bundle_manifest_path_is_safe() {
local path="${1-}"

[[ "$path" =~ ^[A-Za-z0-9_./-]+$ ]] || return 1
[[ -n "$path" && "$path" != /* && "$path" != */ && "$path" != *//* ]] || return 1
case "$path" in
. | .. | ./* | ../* | */./* | */../* | */. | */..)
return 1
;;
esac
}

bundle_manifest_path_has_no_symlink_component() {
local root="$1" relative="$2" candidate component
local -a components=()

IFS='/' read -r -a components <<< "$relative"
candidate="$root"
for component in "${components[@]}"; do
candidate="$candidate/$component"
[[ ! -L "$candidate" ]] || return 1
done
}
10 changes: 8 additions & 2 deletions scripts/library-bundle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)" || exit 1

# shellcheck source=bundle-manifest.sh
source "$repo_root/scripts/bundle-manifest.sh" || exit 1

usage() {
cat >&2 << 'EOF'
Usage:
Expand Down Expand Up @@ -167,8 +170,7 @@ verify_bundle() {
}
expected="${BASH_REMATCH[1]}"
path="${BASH_REMATCH[2]}"
[[ "$path" != /* && "$path" != ./* && "$path" != */ && "$path" != *'//'* &&
"$path" != *'/../'* && "$path" != ../* && "$path" != *'/./'* && "$path" != ./ ]] || {
bundle_manifest_path_is_safe "$path" || {
error "unsafe checksum path: $path"
return 1
}
Expand All @@ -185,6 +187,10 @@ verify_bundle() {
error "bundle file must not be a symlink: $path"
return 1
}
bundle_manifest_path_has_no_symlink_component "$root" "$path" || {
error "bundle path traverses a symlink: $path"
return 1
}
actual="$(hash_file "$root/$path")"
[[ "$actual" == "$expected" ]] || {
error "bundle hash mismatch: $path"
Expand Down
Loading
Loading