diff --git a/scripts/validate-pkg.sh b/scripts/validate-pkg.sh index 01d5458..9eed683 100755 --- a/scripts/validate-pkg.sh +++ b/scripts/validate-pkg.sh @@ -85,8 +85,9 @@ validate_pkg() { if ! echo "$tag_version_regex" | grep -qE '\([^)]*\)'; then log_err "$file: upstream.tag_version_regex must contain a capture group (): $tag_version_regex" ((errors++)) - # Then check valid regex syntax - elif ! echo "test" | sed -nE "s|${tag_version_regex}|\\1|p" >/dev/null 2>&1; then + # Then check valid regex syntax. The regex can close the s command; + # --sandbox refuses e, r and w + elif ! echo "test" | sed --sandbox -nE "s|${tag_version_regex}|\\1|p" >/dev/null 2>&1; then log_err "$file: upstream.tag_version_regex is not valid ERE regex: $tag_version_regex" ((errors++)) fi @@ -201,7 +202,7 @@ validate_pkg() { else # Validate regex syntax: grep exits 2 on invalid regex local grep_rc=0 - echo "" | grep -qE "$pattern" 2>/dev/null || grep_rc=$? + echo "" | grep -qE -e "$pattern" 2>/dev/null || grep_rc=$? if [[ "$grep_rc" -eq 2 ]]; then log_err "$file: upstream.pattern is not valid ERE regex: $pattern" ((errors++)) diff --git a/strategies/github-nightly.sh b/strategies/github-nightly.sh index 3e10e90..f246291 100755 --- a/strategies/github-nightly.sh +++ b/strategies/github-nightly.sh @@ -76,7 +76,8 @@ case "$version_source" in tag) version=$(echo "$release" | yq -r '.tag_name') if [[ -n "$tag_version_regex" ]]; then - extracted=$(echo "$version" | sed -nE "s|${tag_version_regex}|\\1|p" | head -1) + # The regex can close the s command; --sandbox refuses e, r and w + extracted=$(echo "$version" | sed --sandbox -nE "s|${tag_version_regex}|\\1|p" | head -1) if [[ -z "$extracted" ]]; then echo "tag_version_regex '${tag_version_regex}' did not match tag '${version}'" >&2 exit 1 @@ -96,7 +97,7 @@ case "$version_source" in exit 1 fi body=$(echo "$release" | yq -r '.body') - version=$(echo "$body" | grep -oP "$version_pattern" | head -1) + version=$(echo "$body" | grep -oP -e "$version_pattern" | head -1) # Clean up: replace - with + for pacman compatibility version="${version//-/+}" ;; diff --git a/strategies/github-release.sh b/strategies/github-release.sh index 2968fc8..15e6839 100755 --- a/strategies/github-release.sh +++ b/strategies/github-release.sh @@ -34,7 +34,8 @@ fi # Extract version from tag if [[ -n "$tag_version_regex" ]]; then - extracted=$(echo "$version" | sed -nE "s|${tag_version_regex}|\\1|p" | head -1) + # The regex can close the s command; --sandbox refuses e, r and w + extracted=$(echo "$version" | sed --sandbox -nE "s|${tag_version_regex}|\\1|p" | head -1) if [[ -z "$extracted" ]]; then echo "tag_version_regex '${tag_version_regex}' did not match tag '${version}'" >&2 exit 1 diff --git a/strategies/github-tag.sh b/strategies/github-tag.sh index 59d8a6f..c4bfa8e 100755 --- a/strategies/github-tag.sh +++ b/strategies/github-tag.sh @@ -42,7 +42,8 @@ fi # Extract version from tags if [[ -n "$tag_version_regex" ]]; then - version=$(echo "$tags" | sed -nE "s|${tag_version_regex}|\\1|p" | sort -V | tail -1) + # The regex can close the s command; --sandbox refuses e, r and w + version=$(echo "$tags" | sed --sandbox -nE "s|${tag_version_regex}|\\1|p" | sort -V | tail -1) else # Default: strip v prefix, sort semver, take latest version=$(echo "$tags" | sed 's/^v//' | sort -V | tail -1) diff --git a/strategies/webpage-scrape.sh b/strategies/webpage-scrape.sh index 2cd4246..440e622 100755 --- a/strategies/webpage-scrape.sh +++ b/strategies/webpage-scrape.sh @@ -43,8 +43,9 @@ page=$(curl -sfL --max-time "$TIMEOUT" --max-redirs 5 --max-filesize "$MAX_SIZE" exit 1 } -# Extract versions using ERE, capture group via sed -versions=$(echo "$page" | grep -oE "$pattern" | sed -E "s/$pattern/\\1/" | sort -Vu) +# Extract versions using ERE, capture group via sed. The pattern can close +# the s command; --sandbox refuses e, r and w +versions=$(echo "$page" | grep -oE -e "$pattern" | sed --sandbox -E "s/$pattern/\\1/" | sort -Vu) if [[ -z "$versions" ]]; then echo "No versions matched pattern '$pattern' at $url" >&2 diff --git a/tests/strategies.bats b/tests/strategies.bats index d926ccd..c8108fd 100644 --- a/tests/strategies.bats +++ b/tests/strategies.bats @@ -273,6 +273,75 @@ teardown() { [ "$output" = "3.5.0" ] } +# === YAML regex fields === + +# A regex field closes the s command of sed and adds the e flag, which +# runs the pattern space as a command +@test "github-release: tag_version_regex runs no command" { + create_test_package "test-regex-exec" "github-release" "upstream: + project: custom-prefix/repo + tag_version_regex: '.*|touch $TEST_TMPDIR/pwned|e;s|(x)|y|;#'" + + run "$TEST_TMPDIR/strategies/github-release.sh" "test-regex-exec" + [ "$status" -ne 0 ] + [ ! -e "$TEST_TMPDIR/pwned" ] +} + +@test "github-tag: tag_version_regex runs no command" { + create_test_package "test-regex-exec" "github-tag" "upstream: + project: custom-prefix/repo + tag_version_regex: '.*|touch $TEST_TMPDIR/pwned|e;s|(x)|y|;#'" + + run "$TEST_TMPDIR/strategies/github-tag.sh" "test-regex-exec" + [ "$status" -ne 0 ] + [ ! -e "$TEST_TMPDIR/pwned" ] +} + +@test "github-nightly: tag_version_regex runs no command" { + create_test_package "test-regex-exec" "github-nightly" "upstream: + project: custom-nightly/repo + nightly_tag: nightly + version_source: tag + tag_version_regex: '.*|touch $TEST_TMPDIR/pwned|e;s|(x)|y|;#'" + + run "$TEST_TMPDIR/strategies/github-nightly.sh" "test-regex-exec" + [ "$status" -ne 0 ] + [ ! -e "$TEST_TMPDIR/pwned" ] +} + +@test "webpage-scrape: pattern runs no command" { + create_test_package "test-scrape-exec" "webpage-scrape" "upstream: + url: https://example.com/releases + pattern: 'test-scrape-(7)|/touch pwned/e;s/(x)'" + + cd "$TEST_TMPDIR" + run "$TEST_TMPDIR/strategies/webpage-scrape.sh" "test-scrape-exec" + [ "$status" -ne 0 ] + [ ! -e "$TEST_TMPDIR/pwned" ] +} + +@test "webpage-scrape: a pattern may start with a dash" { + create_test_package "test-scrape-dash" "webpage-scrape" "upstream: + url: https://example.com/releases + pattern: '-([0-9]+\\.[0-9]+\\.[0-9]+)\\.tar\\.gz'" + + run "$TEST_TMPDIR/strategies/webpage-scrape.sh" "test-scrape-dash" + [ "$status" -eq 0 ] + [ "$output" = "7.0.0" ] +} + +@test "github-nightly: a version_pattern may start with a dash" { + create_test_package "test-nightly-dash" "github-nightly" "upstream: + project: owner/nightly-repo + nightly_tag: nightly + version_source: release_body + version_pattern: '-\\K[a-z]+'" + + run "$TEST_TMPDIR/strategies/github-nightly.sh" "test-nightly-dash" + [ "$status" -eq 0 ] + [ "$output" = "dev" ] +} + # === github-asset === @test "github-asset: single asset, version is its updated_at as YYYYMMDD" { diff --git a/tests/validate-pkg.bats b/tests/validate-pkg.bats index bca0183..ad67c97 100644 --- a/tests/validate-pkg.bats +++ b/tests/validate-pkg.bats @@ -381,6 +381,14 @@ EOF [ "$status" -eq 0 ] } +@test "validate: webpage-scrape accepts a pattern that starts with a dash" { + create_test_package "mypkg" "webpage-scrape" "upstream: + url: https://example.com/releases + pattern: '-([0-9]+\\.[0-9]+)\\.tar\\.gz'" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -eq 0 ] +} + @test "validate: webpage-scrape rejects invalid regex pattern" { create_test_package "mypkg" "webpage-scrape" "upstream: url: https://example.com/releases @@ -426,6 +434,17 @@ EOF [[ "$output" == *"not valid ERE regex"* ]] } +# The field closes the s command of sed and adds the e flag, which runs the +# pattern space as a command +@test "validate: tag_version_regex runs no command" { + create_test_package "mypkg" "github-release" "upstream: + project: owner/repo + tag_version_regex: '.*|touch $TEST_TMPDIR/pwned|e;s|(x)|y|;#'" + run "$TEST_TMPDIR/scripts/validate-pkg.sh" "mypkg" + [ "$status" -ne 0 ] + [ ! -e "$TEST_TMPDIR/pwned" ] +} + @test "validate: tag_version_regex without capture group rejected" { create_test_package "mypkg" "github-release" "upstream: project: owner/repo