From 533dd3d1e4bca678bc0ecbc6576810c4d973fe71 Mon Sep 17 00:00:00 2001 From: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com> Date: Sat, 16 May 2026 23:12:03 +0200 Subject: [PATCH 1/2] fix(impl-generate): suppress renv stdout in R version probe renv prints its "project out-of-sync" notice on stdout from .Rprofile, so 2>/dev/null leaves it inside the captured value. The polluted multi-line string then breaks the downstream Python heredoc with an unterminated string literal, and a backtick in the notice splits the bash command so --model lands as a standalone token. Setting RENV_CONFIG_STARTUP_QUIET=TRUE silences renv at startup; piping through tail -n1 keeps a single clean version line as a fallback. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/impl-generate.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/impl-generate.yml b/.github/workflows/impl-generate.yml index 404e5f1002..c97df53354 100644 --- a/.github/workflows/impl-generate.yml +++ b/.github/workflows/impl-generate.yml @@ -461,7 +461,11 @@ jobs: # the right language label, so we never mislabel R as "Python". PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}') if [ "$LANGUAGE" = "r" ]; then - LANGUAGE_VERSION=$(Rscript -e 'cat(as.character(getRversion()))' 2>/dev/null || echo "unknown") + # renv's "out-of-sync" notice prints on stdout from .Rprofile, so 2>/dev/null + # leaves it in the captured value. RENV_CONFIG_STARTUP_QUIET silences it; the + # tail -n1 belt keeps a single clean line if anything else ever leaks in. + LANGUAGE_VERSION=$(RENV_CONFIG_STARTUP_QUIET=TRUE Rscript -e 'cat(as.character(getRversion()))' 2>/dev/null | tail -n1) + LANGUAGE_VERSION=${LANGUAGE_VERSION:-unknown} else LANGUAGE_VERSION="$PYTHON_VERSION" fi @@ -473,7 +477,7 @@ jobs: .venv/bin/pip show "$1" 2>/dev/null | grep -i "^Version:" | awk '{print $2}' } get_r_version() { - Rscript -e "cat(as.character(packageVersion('$1')))" 2>/dev/null + RENV_CONFIG_STARTUP_QUIET=TRUE Rscript -e "cat(as.character(packageVersion('$1')))" 2>/dev/null | tail -n1 } if [ "$LANGUAGE" = "r" ]; then From c14889849affd00a26f51559a02e65b6cec0a05d Mon Sep 17 00:00:00 2001 From: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com> Date: Sat, 16 May 2026 23:17:01 +0200 Subject: [PATCH 2/2] fix(impl-generate): validate R version output against version regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply Copilot review feedback on #6948: if Rscript exits non-zero after partial stdout, `tail -n1` would still return that leaked line as LIBRARY_VERSION, defeating the renv-quiet protection. Add an is_version() regex (`^[0-9]+(\.[0-9]+)*$`) and reject anything that doesn't match — empty result falls through to the existing "unknown" fallback. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/impl-generate.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/impl-generate.yml b/.github/workflows/impl-generate.yml index c97df53354..7a764cc337 100644 --- a/.github/workflows/impl-generate.yml +++ b/.github/workflows/impl-generate.yml @@ -460,12 +460,21 @@ jobs: # Python libs, the R version for ggplot2. The frontend renders language_version with # the right language label, so we never mislabel R as "Python". PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}') + # R/Python versions are always dot-separated digits. Anything else + # captured from Rscript (renv leaks, error fragments, status messages) + # would poison metadata and break the downstream Python heredoc, so + # we reject and let the existing "unknown" fallback take over. + is_version() { + [[ "$1" =~ ^[0-9]+(\.[0-9]+)*$ ]] + } + if [ "$LANGUAGE" = "r" ]; then # renv's "out-of-sync" notice prints on stdout from .Rprofile, so 2>/dev/null - # leaves it in the captured value. RENV_CONFIG_STARTUP_QUIET silences it; the - # tail -n1 belt keeps a single clean line if anything else ever leaks in. + # leaves it in the captured value. RENV_CONFIG_STARTUP_QUIET silences renv; + # tail -n1 + is_version reject anything else that might leak in or land if + # Rscript exits non-zero after partial stdout. LANGUAGE_VERSION=$(RENV_CONFIG_STARTUP_QUIET=TRUE Rscript -e 'cat(as.character(getRversion()))' 2>/dev/null | tail -n1) - LANGUAGE_VERSION=${LANGUAGE_VERSION:-unknown} + is_version "$LANGUAGE_VERSION" || LANGUAGE_VERSION="unknown" else LANGUAGE_VERSION="$PYTHON_VERSION" fi @@ -477,7 +486,9 @@ jobs: .venv/bin/pip show "$1" 2>/dev/null | grep -i "^Version:" | awk '{print $2}' } get_r_version() { - RENV_CONFIG_STARTUP_QUIET=TRUE Rscript -e "cat(as.character(packageVersion('$1')))" 2>/dev/null | tail -n1 + local v + v=$(RENV_CONFIG_STARTUP_QUIET=TRUE Rscript -e "cat(as.character(packageVersion('$1')))" 2>/dev/null | tail -n1) + is_version "$v" && printf '%s' "$v" } if [ "$LANGUAGE" = "r" ]; then