Skip to content

feat(rolling-update): forward EXTRA_ENV as docker -e flags#591

Merged
bootjp merged 12 commits intomainfrom
feat/rolling-update-extra-env
Apr 23, 2026
Merged

feat(rolling-update): forward EXTRA_ENV as docker -e flags#591
bootjp merged 12 commits intomainfrom
feat/rolling-update-extra-env

Conversation

@bootjp
Copy link
Copy Markdown
Owner

@bootjp bootjp commented Apr 23, 2026

Summary

Adds an EXTRA_ENV pass-through to scripts/rolling-update.sh so operators can set container environment variables from deploy.env without editing this script each time.

Motivation

Immediate trigger: enabling ELASTICKV_RAFT_DISPATCHER_LANES=1 (feature flag added in PR #577). We want to flip it on via the deploy envelope, not by rebuilding the image or hand-editing this script.

Post-#575 raft metrics are already healthy, so the 4-lane dispatcher is being enabled as a defensive measure — it keeps heartbeats from being starved by MsgApp / MsgSnap bursts under extreme write load, rather than as a fix for anything actively broken.

Change

  • run_container: if EXTRA_ENV is set, split on whitespace and forward each pair as a single docker run -e KEY=VALUE flag.
  • Comment documents the whitespace-split semantics (pairs must not contain whitespace; values may contain characters bash would otherwise interpret).

Usage

# deploy.env
EXTRA_ENV="ELASTICKV_RAFT_DISPATCHER_LANES=1 ELASTICKV_PEBBLE_CACHE_MB=512"

Test plan

  • bash -n scripts/rolling-update.sh passes
  • shellcheck / make lint — 0 issues
  • Rolling deploy with EXTRA_ENV set; verify via docker inspect elastickv --format '{{.Config.Env}}' on each node

Summary by CodeRabbit

  • New Features
    • Added the ability to pass arbitrary additional environment variables to containers via a new input; these are injected into container runtime.
  • Improvements
    • Extra env entries are validated and safely normalized/escaped for remote transport.
    • Core runtime variables are now sent in escaped/quoted form to the remote execution context for safer handling.

Lets deploy.env expose tunable flags without editing this script. The
immediate trigger is ELASTICKV_RAFT_DISPATCHER_LANES=1, a feature flag
added in elastickv PR #577 that routes raft messages through 4 per-peer
lanes (heartbeat/replication/snapshot/other) to keep heartbeats from
starving under MsgApp/MsgSnap bursts. We want to flip it on without
rebuilding or shipping a new image.

EXTRA_ENV is a whitespace-separated KEY=VALUE list; each pair becomes a
single docker run -e flag. Values may contain characters bash would
otherwise interpret, but pairs themselves must not contain whitespace.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

Warning

Rate limit exceeded

@bootjp has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 32 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 32 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 79eb6005-a6a7-4150-a5f9-c073664dfd25

📥 Commits

Reviewing files that changed from the base of the PR and between acc3ab1 and e871564.

📒 Files selected for processing (1)
  • scripts/rolling-update.sh
📝 Walkthrough

Walkthrough

Normalizes and shell-escapes forwarded runtime variables (including EXTRA_ENV) into quoted *_Q forms for safe SSH transport; run_container parses and validates whitespace-separated KEY=VALUE pairs from EXTRA_ENV, then injects each as -e KEY=VALUE into docker run. Remote invocation receives escaped values.

Changes

Cohort / File(s) Summary
Environment Variable Forwarding & Remote Invocation
scripts/rolling-update.sh
Adds EXTRA_ENV handling: normalizes/shell-escapes forwarded variables into *_Q values for SSH, forwards EXTRA_ENV to remote, parses whitespace-separated KEY=VALUE pairs in run_container, validates format and key names, and emits -e KEY=VALUE flags for docker run. Also sends escaped/quoted forms of core runtime variables over ssh.

Sequence Diagram(s)

sequenceDiagram
    participant Local
    participant SSH
    participant RemoteShell
    participant Docker

    Local->>Local: Read EXTRA_ENV and runtime vars
    Note right of Local: Normalize & shell-escape into *_Q
    Local->>SSH: ssh ... env (sends escaped *_Q and EXTRA_ENV_Q)
    SSH->>RemoteShell: Start remote shell with quoted env
    RemoteShell->>RemoteShell: Parse EXTRA_ENV into KEY=VALUE pairs\nValidate keys and entries
    RemoteShell->>Docker: docker run ... -e KEY=VALUE (for each pair)
    Docker-->>RemoteShell: Container starts
    RemoteShell-->>Local: Exit/status via SSH
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped along the pipeline bright,
Escaped the vars and set them right,
From LOCAL to REMOTE they flew,
KEY=VALUE, each one true,
A tiny rabbit's rolling update cue! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding EXTRA_ENV forwarding as docker -e flags in the rolling-update script.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rolling-update-extra-env

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the ability to pass additional environment variables to the Docker container using the EXTRA_ENV variable. The review feedback highlights a critical issue where the variable is not correctly passed to the remote shell during the SSH call, which would prevent the feature from working. Additionally, it is recommended to document the new variable in the script's usage section and to use read -a for safer word splitting to prevent unintended filename expansion.

Comment thread scripts/rolling-update.sh
# characters that bash would otherwise interpret; pairs themselves must not
# contain whitespace.
local extra_env_flags=()
if [[ -n "${EXTRA_ENV:-}" ]]; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The EXTRA_ENV variable is defined in the local shell (sourced from the environment file) but is not passed to the remote shell. Since the REMOTE heredoc is quoted (<<'REMOTE'), local variables are not expanded within it. You must add EXTRA_ENV="$EXTRA_ENV" to the env command in the ssh call (around line 421) to make it available to the remote run_container function. Without this, the feature will not work as intended.

Comment thread scripts/rolling-update.sh
Comment on lines +668 to +673
# Pass through additional container environment variables from EXTRA_ENV.
# Accepts a whitespace-separated list of KEY=VALUE pairs, e.g.:
# EXTRA_ENV="ELASTICKV_RAFT_DISPATCHER_LANES=1 ELASTICKV_PEBBLE_CACHE_MB=512"
# Each pair is forwarded as a single `-e KEY=VALUE` flag so VALUE may contain
# characters that bash would otherwise interpret; pairs themselves must not
# contain whitespace.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The EXTRA_ENV variable should be documented in the usage() function (lines 7-65) so that users can discover it and understand its format when running the script with --help.

Comment thread scripts/rolling-update.sh Outdated
Comment on lines +676 to +677
# shellcheck disable=SC2206
local -a extra_env_pairs=( ${EXTRA_ENV} )
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using ( ${EXTRA_ENV} ) for word splitting also triggers filename expansion (globbing). If EXTRA_ENV contains characters like * or ?, it may be expanded to local filenames on the remote host. It is safer to use read -a which performs word splitting without globbing.

Suggested change
# shellcheck disable=SC2206
local -a extra_env_pairs=( ${EXTRA_ENV} )
local -a extra_env_pairs
read -r -a extra_env_pairs <<< "${EXTRA_ENV}"

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/rolling-update.sh (1)

395-422: ⚠️ Potential issue | 🔴 Critical

Forward EXTRA_ENV into the remote script.

run_container reads EXTRA_ENV on the remote host, but update_one_node never passes the locally sourced value through the ssh ... env ... bash -s invocation. As written, EXTRA_ENV from deploy.env will usually be empty remotely, so no Docker -e flags are added.

🐛 Proposed fix
       RAFT_TO_REDIS_MAP="$RAFT_TO_REDIS_MAP" \
       RAFT_TO_S3_MAP="$RAFT_TO_S3_MAP" \
+      EXTRA_ENV="${EXTRA_ENV:-}" \
       bash -s <<'REMOTE'

Also applies to: 675-682

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/rolling-update.sh` around lines 395 - 422, The remote ssh env block
in update_one_node fails to forward the locally-sourced EXTRA_ENV so
run_container on the remote host reads an empty value; update the ssh invocation
that constructs the env list (the long ssh "... env IMAGE=... bash -s
<<'REMOTE'") to include EXTRA_ENV="$EXTRA_ENV" so the remote script's
run_container can consume it, and apply the same change to the other ssh/env
block used around lines 675-682; ensure the referenced variable name EXTRA_ENV
is passed exactly as shown so remote run_container and any Docker -e flags are
populated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/rolling-update.sh`:
- Around line 675-681: Validate each token from EXTRA_ENV before adding to
extra_env_flags: in the loop iterating over extra_env_pairs (derived from
EXTRA_ENV) ensure each pair contains an '=' and a non-empty key (e.g. test with
[[ "$pair" == *=* ]] and then check key portion is not empty after splitting),
and if validation fails emit a clear error and exit non-zero to prevent passing
bare names to Docker; keep using the same variables (EXTRA_ENV, extra_env_pairs,
pair, extra_env_flags) and perform trimming/quoting as needed so only
well-formed KEY=VALUE entries are appended with extra_env_flags+=(-e "$pair").

---

Outside diff comments:
In `@scripts/rolling-update.sh`:
- Around line 395-422: The remote ssh env block in update_one_node fails to
forward the locally-sourced EXTRA_ENV so run_container on the remote host reads
an empty value; update the ssh invocation that constructs the env list (the long
ssh "... env IMAGE=... bash -s <<'REMOTE'") to include EXTRA_ENV="$EXTRA_ENV" so
the remote script's run_container can consume it, and apply the same change to
the other ssh/env block used around lines 675-682; ensure the referenced
variable name EXTRA_ENV is passed exactly as shown so remote run_container and
any Docker -e flags are populated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5c918ae6-97d2-4cde-9a07-ce1a99fdbc92

📥 Commits

Reviewing files that changed from the base of the PR and between 3a434c7 and 9beaf6d.

📒 Files selected for processing (1)
  • scripts/rolling-update.sh

Comment thread scripts/rolling-update.sh
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9beaf6dfc0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/rolling-update.sh
# characters that bash would otherwise interpret; pairs themselves must not
# contain whitespace.
local extra_env_flags=()
if [[ -n "${EXTRA_ENV:-}" ]]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Forward EXTRA_ENV to the remote update script

This new block reads EXTRA_ENV on the remote host, but update_one_node's SSH invocation only forwards a fixed set of variables and does not include EXTRA_ENV (see the env ... bash -s assignments around scripts/rolling-update.sh:395-422). In the normal case where EXTRA_ENV is set locally via ROLLING_UPDATE_ENV_FILE, it is not present remotely, so this condition is false and no docker run -e flags are added; the feature effectively does nothing unless the remote environment already defines EXTRA_ENV independently.

Useful? React with 👍 / 👎.

bootjp added 3 commits April 23, 2026 18:53
The SSH invocation forwards a fixed list of variables via `env KEY=VAL bash -s`
with a QUOTED heredoc, so `EXTRA_ENV` referenced by `run_container` inside the
remote block was never populated. Add it to the env pre-command with a default
empty value so run_container's existing null-check works when deploy.env
doesn't set it.
Switch from an unquoted array expansion to `read -r -a` when splitting
EXTRA_ENV so values containing glob metacharacters (*, ?) are not expanded
against the control host's cwd. Also reject entries that do not match
KEY=VALUE with a non-empty KEY, since docker treats `-e NAME` (copy from
environment) differently from `-e NAME=value` and a malformed pair would
silently behave unexpectedly.
Add an EXTRA_ENV entry to the Optional environment section of the script's
help text, with the expected whitespace-separated KEY=VALUE format and an
example, so operators can discover the feature via `./scripts/rolling-update.sh --help`.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Review fixes

Addresses the 5 review items (CRITICAL + 2 medium + 1 minor; codex P1 and gemini CRITICAL are the same bug).

58e6508f fix(rolling-update): forward EXTRA_ENV through SSH env dispatch

CRITICAL. The remote SSH block is invoked via env KEY=VAL ... bash -s <<'REMOTE'. Because the heredoc is quoted, the remote shell only sees env vars explicitly listed in the env pre-command, and EXTRA_ENV was missing — so run_container always saw it unset and no -e flags were ever emitted. Added EXTRA_ENV="${EXTRA_ENV:-}" \ to the dispatch so the feature actually reaches the remote host. The default-empty preserves behaviour when deploy.env doesn't set it; the existing null-check in run_container handles that branch.

350acdc5 fix(rolling-update): glob-safe EXTRA_ENV split and validate KEY=VALUE

  • Replaced local -a extra_env_pairs=( ${EXTRA_ENV} ) (which triggers filename globbing against the remote cwd) with read -r -a extra_env_pairs <<< "${EXTRA_ENV}". A value like WILD=* is now preserved verbatim.
  • Added validation: each pair must contain = and have a non-empty KEY. -e NAME (docker's copy-from-env form) and -e =value are rejected with a clear error instead of being silently forwarded.

b8a448c7 docs(rolling-update): document EXTRA_ENV in usage()

Added an EXTRA_ENV entry to the Optional environment section of the usage() help with the KEY=VALUE [KEY=VALUE ...] format and an example, so it's discoverable via --help.

Verification

  • bash -n scripts/rolling-update.sh passes.
  • shellcheck not available locally (not installed); no new unquoted expansions introduced.
  • Parsing smoke test (standalone): EXTRA_ENV="FOO=bar BAZ=qux" produces docker run -e FOO=bar -e BAZ=qux ...; WILD=* is not globbed; BADONE and =VAL are rejected with invalid EXTRA_ENV entry ....

/gemini review
@codex review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to scripts/rolling-update.sh, allowing users to pass additional environment variables to the remote Docker container. A critical issue was identified regarding the transmission of this variable over SSH; without proper shell escaping, whitespace-separated KEY=VALUE pairs are incorrectly parsed by the remote shell, leading to truncated environment variables. A suggestion was provided to use printf '%q' to ensure the entire string is preserved.

Comment thread scripts/rolling-update.sh Outdated
ALL_NODE_HOSTS_CSV="$all_node_hosts_csv" \
RAFT_TO_REDIS_MAP="$RAFT_TO_REDIS_MAP" \
RAFT_TO_S3_MAP="$RAFT_TO_S3_MAP" \
EXTRA_ENV="${EXTRA_ENV:-}" \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The EXTRA_ENV variable is intended to contain whitespace-separated pairs, but when passed to the remote host via SSH in this manner, the remote shell will split the string before it reaches the env command. For example, if EXTRA_ENV="A=1 B=2", the remote shell executes env ... EXTRA_ENV=A=1 B=2 ..., resulting in EXTRA_ENV being set to only A=1 (and B=2 becoming a separate, likely ignored, environment variable). To ensure the entire string is preserved as a single value for the remote EXTRA_ENV variable, it should be shell-escaped using printf %q.

Suggested change
EXTRA_ENV="${EXTRA_ENV:-}" \
EXTRA_ENV="$(printf '%q' "${EXTRA_ENV:-}")" \

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ssh(1) joins remaining argv into a single command string which the
remote shell re-parses, so a whitespace-containing EXTRA_ENV (its
documented format) was split on the remote side: the remote saw
`EXTRA_ENV=FOO=1 BAR=2 bash -s`, which set EXTRA_ENV to only the first
pair and turned the rest into additional `env` assignments.

Escape EXTRA_ENV with `printf %q` before handing it to ssh so the
remote shell reassembles the original string verbatim. Also escape
S3_CREDENTIALS_FILE defensively — it is a user-supplied path that
could plausibly contain spaces even if no caller does so today.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed gemini HIGH (EXTRA_ENV split across SSH dispatch) in 1a0cc25.

Root cause. ssh host arg1 arg2 ... joins argv into a single remote command string which the remote shell re-parses. So env EXTRA_ENV="FOO=1 BAR=2" bash -s reached the remote as env EXTRA_ENV=FOO=1 BAR=2 bash -s, which set EXTRA_ENV=FOO=1 and treated BAR=2 as a separate env assignment. Local quoting is irrelevant because it only protects argv construction, not the remote-side re-parse.

Fix. Escape with printf %q before handing the value to ssh so the remote shell reassembles the original string verbatim. Also escape S3_CREDENTIALS_FILE defensively (path-like values could grow spaces). Other forwarded vars are CSV/numeric/boolean and structurally whitespace-free today; left as-is per review guidance.

Smoke (local simulation of the remote re-parse via eval):

  • EXTRA_ENV="FOO=1 BAR=2" -> escaped FOO=1\ BAR=2 -> remote sees [FOO=1 BAR=2]
  • EXTRA_ENV="K=*a b*" -> escaped K=\*a\ b\* -> remote sees [K=*a b*] (no glob expansion)
  • EXTRA_ENV="" -> escaped '' -> remote sees empty (same as pre-fix no-op)
  • S3_CREDENTIALS_FILE="/tmp/my creds.json" -> escaped /tmp/my\ creds.json -> remote sees [/tmp/my creds.json]

Pre-fix reproduction for the record: same FOO=1 BAR=2 input printed remote sees: [FOO=1].

bash -n scripts/rolling-update.sh clean.

/gemini review
@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to scripts/rolling-update.sh, allowing users to pass additional environment variables to remote Docker containers. The changes include logic to escape these variables for safe transport over SSH and a parsing mechanism to convert the whitespace-separated list into Docker -e flags. Feedback suggests strengthening the validation of EXTRA_ENV keys by implementing a regex check to ensure they are valid environment variable names, rather than only checking for the presence of an equals sign.

Comment thread scripts/rolling-update.sh
Comment on lines +700 to +703
if [[ "$pair" != *=* || "$pair" == =* ]]; then
echo "invalid EXTRA_ENV entry '$pair'; expected KEY=VALUE" >&2
exit 1
fi
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The validation logic for EXTRA_ENV entries correctly ensures that each pair contains an = and does not start with one. However, it does not validate that the key is a valid environment variable name (e.g., it could start with a digit or contain invalid characters). While docker run -e will likely catch these, adding a basic regex check for the key would improve robustness.

References
  1. Centralize common complex logic, such as validation or retry mechanisms, into shared helper functions to improve maintainability and robustness.

@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed Gemini medium review: EXTRA_ENV now additionally validates each KEY matches the POSIX identifier pattern [A-Za-z_][A-Za-z0-9_]*, rejecting entries like 1X=a or A-B=c before they reach docker run -e.

Smoke tests (local extraction of the validator):

  • EXTRA_ENV="1X=a" -> exit 1 (invalid key '1X')
  • EXTRA_ENV="A-B=c" -> exit 1 (invalid key 'A-B')
  • EXTRA_ENV="VALID_KEY=x" -> OK
  • EXTRA_ENV="_LEADING=x" -> OK

bash -n scripts/rolling-update.sh passes. Commit: 2fd1bf0.

/gemini review
@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to the rolling-update.sh script, allowing users to pass additional environment variables to remote Docker containers. It also implements shell escaping for EXTRA_ENV and S3_CREDENTIALS_FILE to ensure safe transport over SSH. The review feedback suggests extending this escaping to other variables like DATA_DIR and IMAGE for consistency and defense in depth, and recommends moving the escaping logic outside the node iteration loop to improve efficiency.

Comment thread scripts/rolling-update.sh Outdated
Comment on lines +402 to +408
# ssh joins remaining arguments into a single command string which the remote
# shell re-parses, so values containing whitespace or shell metacharacters
# must be escaped before transport. EXTRA_ENV is documented as a
# whitespace-separated list of KEY=VALUE pairs and therefore always needs
# quoting; other forwarded variables are structurally whitespace-free today
# but we still escape the ones most likely to evolve (path-like values) for
# defense in depth.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The comment correctly identifies the need to escape values containing whitespace or shell metacharacters before transport via SSH. However, it mentions escaping "path-like values" for defense in depth but only applies this to S3_CREDENTIALS_FILE. Other path-like variables such as DATA_DIR and SERVER_ENTRYPOINT, as well as IMAGE, are still passed without escaping in the ssh call below. For full defense in depth and consistency, these should also be escaped using printf '%q'.

Comment thread scripts/rolling-update.sh Outdated
Comment on lines +409 to +411
local extra_env_escaped s3_credentials_file_escaped
extra_env_escaped="$(printf '%q' "${EXTRA_ENV:-}")"
s3_credentials_file_escaped="$(printf '%q' "${S3_CREDENTIALS_FILE:-}")"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since EXTRA_ENV and S3_CREDENTIALS_FILE do not change per node, they could be escaped once outside the for node_id in "${ROLLING_NODE_IDS[@]}" loop (around line 857) to avoid redundant printf calls for every node in the cluster. While the performance impact is negligible for small clusters, it improves the script's efficiency.

…ath-vars

Addresses gemini medium review on 2fd1bf0:

- EXTRA_ENV / S3_CREDENTIALS_FILE escaping did not change per node; moved
  from inside update_one_node (ran once per host) to file scope, computed
  once after ensure_remote_raftadmin_binaries.
- For defense in depth, also escape IMAGE, DATA_DIR, SERVER_ENTRYPOINT --
  path-like values forwarded over the SSH re-parse path. Structurally
  whitespace-free today, but cheap to harden against future deploy.env
  values containing metacharacters.
- Non-path-like vars (CSV / numeric / boolean) left unquoted; adding
  printf %q there is inert but adds noise.

Naming: *_Q suffix for the escaped forms to keep the env block readable.

Smoke test:
  IMAGE=ghcr.io/bootjp/elastickv:latest    -> unchanged
  DATA_DIR="/var/lib/my data/kv"            -> remote sees [/var/lib/my data/kv]
  EXTRA_ENV="FOO=1 BAR=2"                   -> remote sees [FOO=1 BAR=2]
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed gemini medium review on 2fd1bf0 in 5415d8f.

Moved escaping outside the per-node loop. EXTRA_ENV and S3_CREDENTIALS_FILE don't change per node, so printf '%q' was running once per host for the same inputs. Hoisted to file scope, computed once after ensure_remote_raftadmin_binaries. The *_Q suffix keeps the env block readable (IMAGE="$IMAGE_Q").

Defense-in-depth escape for path-like vars. Extended printf '%q' to IMAGE, DATA_DIR, and SERVER_ENTRYPOINT — path-like values that transit the same SSH re-parse path. Structurally whitespace-free today, but cheap to harden so a future deploy.env with a space in DATA_DIR (e.g. /var/lib/my data/kv) doesn't silently corrupt the remote command. Kept the CSV / numeric / boolean vars unescaped — adding %q there is inert but adds noise.

Smoke (simulating the remote re-parse with eval):

  • IMAGE=ghcr.io/bootjp/elastickv:latest → unchanged
  • DATA_DIR="/var/lib/my data/kv" → remote sees [/var/lib/my data/kv]
  • EXTRA_ENV="FOO=1 BAR=2" → remote sees [FOO=1 BAR=2]

bash -n scripts/rolling-update.sh passes. make lint clean.

/gemini review
@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to the rolling-update.sh script, allowing users to pass additional environment variables to Docker containers. It also implements shell escaping for several variables transmitted via SSH to prevent parsing errors or security issues with special characters. The review feedback suggests improving the parsing of EXTRA_ENV to handle multi-line strings and extending the escaping logic to other variables like RAFTADMIN_REMOTE_BIN and CONTAINER_NAME for better consistency and robustness.

Comment thread scripts/rolling-update.sh Outdated
if [[ -n "${EXTRA_ENV:-}" ]]; then
# Split on whitespace without triggering filename globbing.
local -a extra_env_pairs=()
read -r -a extra_env_pairs <<< "${EXTRA_ENV}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The read -r -a command with a here-string (<<<) only reads the first line of the input. If EXTRA_ENV is defined as a multi-line string (which is common for long lists of environment variables in .env files), only the first line of variables will be processed, and subsequent lines will be silently ignored. To handle all whitespace including newlines while avoiding globbing, you should replace newlines with spaces before reading.

Suggested change
read -r -a extra_env_pairs <<< "${EXTRA_ENV}"
read -r -a extra_env_pairs <<< "${EXTRA_ENV//$'/\n'/ }"

Comment thread scripts/rolling-update.sh Outdated
Comment on lines +852 to +856
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV:-}")"
S3_CREDENTIALS_FILE_Q="$(printf '%q' "${S3_CREDENTIALS_FILE:-}")"
IMAGE_Q="$(printf '%q' "$IMAGE")"
DATA_DIR_Q="$(printf '%q' "$DATA_DIR")"
SERVER_ENTRYPOINT_Q="$(printf '%q' "$SERVER_ENTRYPOINT")"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is an inconsistency in the escaping of variables passed to the remote shell. While you have correctly escaped IMAGE, DATA_DIR, and others for "defense in depth," you missed RAFTADMIN_REMOTE_BIN (which is a path) and CONTAINER_NAME (which is user-configurable). If these contain spaces or shell metacharacters, the env command in update_one_node will fail or behave unexpectedly. You should escape these as well.

Suggested change
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV:-}")"
S3_CREDENTIALS_FILE_Q="$(printf '%q' "${S3_CREDENTIALS_FILE:-}")"
IMAGE_Q="$(printf '%q' "$IMAGE")"
DATA_DIR_Q="$(printf '%q' "$DATA_DIR")"
SERVER_ENTRYPOINT_Q="$(printf '%q' "$SERVER_ENTRYPOINT")"
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV:-}")"
S3_CREDENTIALS_FILE_Q="$(printf '%q' "${S3_CREDENTIALS_FILE:-}")"
IMAGE_Q="$(printf '%q' "$IMAGE")"
DATA_DIR_Q="$(printf '%q' "$DATA_DIR")"
SERVER_ENTRYPOINT_Q="$(printf '%q' "$SERVER_ENTRYPOINT")"
RAFTADMIN_REMOTE_BIN_Q="$(printf '%q' "$RAFTADMIN_REMOTE_BIN")"
CONTAINER_NAME_Q="$(printf '%q' "$CONTAINER_NAME")"

…IN/CONTAINER_NAME

Addresses two gemini medium review items on 5415d8f:

1. Multi-line EXTRA_ENV values were silently truncated to the first line.
   `read -r -a <<< "$EXTRA_ENV"` consumes only up to the first newline of a
   here-string, so a deploy.env with

     EXTRA_ENV="FOO=1
     BAR=2"

   would set FOO=1 and drop BAR=2 without error. Fix: normalise newlines to
   spaces before the read:

     extra_env_normalised="${EXTRA_ENV//$'\n'/ }"
     read -r -a extra_env_pairs <<< "${extra_env_normalised}"

   Smoke: three pairs spread across 2 lines now parse as 3 entries.

2. Extended `printf %q` defense-in-depth escaping to RAFTADMIN_REMOTE_BIN
   (path-like, may grow spaces) and CONTAINER_NAME (user-configurable).
   CSV / numeric / boolean vars remain unescaped.

`bash -n scripts/rolling-update.sh` clean.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed both gemini medium items on 5415d8f in 2014758.

1. Multi-line EXTRA_ENV silently truncated. read -r -a <<< "$EXTRA_ENV" consumes only up to the first newline of a here-string, so a deploy.env like

EXTRA_ENV="FOO=1
BAR=2"

would set FOO=1 and silently drop BAR=2. Fix: normalise newlines to spaces before the read.

local extra_env_normalised="${EXTRA_ENV//$'\n'/ }"
read -r -a extra_env_pairs <<< "${extra_env_normalised}"

Smoke (input "FOO=1\nBAR=2 BAZ=3"): parses as 3 pairs [FOO=1] [BAR=2] [BAZ=3] ✓.

2. Extended printf %q defense-in-depth escaping to RAFTADMIN_REMOTE_BIN (path-like) and CONTAINER_NAME (user-configurable). CSV / numeric / boolean vars (RAFT_ENGINE, *_PORT, *_SECONDS, ENABLE_S3, etc.) remain unescaped — adding %q there is inert but adds noise.

bash -n scripts/rolling-update.sh clean. make lint clean.

/gemini review
@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2014758cec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/rolling-update.sh Outdated
# quoting; other forwarded variables are structurally whitespace-free today
# but we still escape the path-like ones most likely to evolve for defense
# in depth. Escape once here since these don't change per node.
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV:-}")"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use POSIX-safe escaping for remote EXTRA_ENV values

printf '%q' can emit ANSI-C quotes (for example $'FOO=1\nBAR=2'), but the SSH command string is parsed by the remote account’s login shell before bash -s runs. On hosts where that shell is /bin/sh/dash, $'...' is treated literally, so multiline EXTRA_ENV arrives as a literal $...\n... string and the new KEY=VALUE validator rejects it, aborting the rollout. This means the documented multiline deploy.env format is not portable across common non-bash remote shells.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to scripts/rolling-update.sh, allowing users to pass additional environment variables to the remote Docker container. It also improves the robustness of the script by escaping several variables before they are transmitted via SSH. A potential issue was identified regarding the use of printf '%q' for escaping; this method can produce Bash-specific syntax that may not be correctly interpreted by the remote shell if it is not Bash-compatible, potentially breaking the parsing of multi-line environment variables.

Comment thread scripts/rolling-update.sh Outdated
# quoting; other forwarded variables are structurally whitespace-free today
# but we still escape the path-like ones most likely to evolve for defense
# in depth. Escape once here since these don't change per node.
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV:-}")"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using printf '%q' in Bash 4+ to escape variables containing newlines (like a multi-line EXTRA_ENV) produces the $'...' syntax. While this is valid Bash, the remote shell that initially parses the ssh command line (often /bin/sh, which is dash on Ubuntu/Debian) does not support this syntax. This can result in the literal string $'...' being passed into the remote environment instead of the intended value, which would then break the subsequent parsing logic in run_container.

If multi-line EXTRA_ENV values are expected to be common, consider ensuring the local EXTRA_ENV is normalized (newlines replaced with spaces) before escaping, or use a more portable escaping method.

Addresses gemini medium + codex P2 on 2014758 (same root cause).

`printf '%q'` emits ANSI-C $'...' quoting for strings containing non-
printable characters like newlines. The remote *login* shell re-parses
the SSH command string before exec'ing `bash -s`. On Debian/Ubuntu where
/bin/sh is dash, $'...' is not a special token -- the literal string is
forwarded through, EXTRA_ENV arrives on the remote as `$'FOO=1\nBAR=2'`,
and the KEY=VALUE validator in run_container rejects it, aborting the
rollout.

Fix: normalise newlines to spaces locally *before* printf %q, so the
escape only emits plain backslash quoting which every POSIX shell
understands. Confirms via smoke test:

  pre-fix:  printf %q "FOO=1\nBAR=2"   -> $'FOO=1\nBAR=2'    (bash-only)
  post-fix: printf %q "FOO=1 BAR=2"    -> FOO=1\ BAR=2       (portable)

The existing in-run_container normalisation (also on newlines) is kept
as defense in depth but is now unreachable via the rolling-update path.

`bash -n scripts/rolling-update.sh` clean.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed the combined gemini medium + codex P2 on 2014758 (same bug, portability-of-printf %q) in 8ded4d1.

Root cause. printf '%q' emits ANSI-C $'...' quoting when the input contains non-printable characters like \n. The SSH command string is re-parsed by the remote login shell before bash -s is exec'd. On Debian/Ubuntu where /bin/sh -> dash, $'...' is not a recognised token -- the literal string is forwarded through, so EXTRA_ENV arrives on the remote as $'FOO=1\nBAR=2' and the KEY=VALUE validator rejects the first entry, aborting the rollout.

Fix. Normalise newlines to spaces locally, before printf %q, so the escape only emits plain backslash quoting (portable across every POSIX shell):

EXTRA_ENV_NORMALISED="${EXTRA_ENV//$'\n'/ }"
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV_NORMALISED:-}")"

Smoke (EXTRA_ENV="FOO=1\nBAR=2"):

  • pre-fix: printf %q -> $'FOO=1\nBAR=2' (bash-only)
  • post-fix: normalise to FOO=1 BAR=2, then printf %q -> FOO=1\ BAR=2 (portable; dash-safe)

The existing newline-normalisation inside run_container (remote side) is left in place as belt-and-suspenders -- via this script's SSH path it's now unreachable, but a direct invocation of run_container with multi-line EXTRA_ENV still gets parsed correctly.

bash -n scripts/rolling-update.sh clean. make lint clean.

/gemini review
@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ded4d1ec7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/rolling-update.sh Outdated
Comment on lines +865 to +866
EXTRA_ENV_NORMALISED="${EXTRA_ENV//$'\n'/ }"
EXTRA_ENV_Q="$(printf '%q' "${EXTRA_ENV_NORMALISED:-}")"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize all whitespace before %q escaping EXTRA_ENV

EXTRA_ENV_NORMALISED currently replaces only newlines, but printf '%q' still emits ANSI-C $'...' quoting when EXTRA_ENV contains other non-printable whitespace such as tabs (or \r from CRLF deploy files). On hosts where the SSH login shell is dash, that quoting is treated literally, so EXTRA_ENV reaches run_container as a malformed first token and fails the KEY validator, aborting the rollout. Since the script documents EXTRA_ENV as whitespace-separated, tabs should work as separators too; normalize all relevant whitespace before %q.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to the rolling-update.sh script, allowing users to pass additional environment variables to remote Docker containers. It also enhances the script's robustness by implementing proper shell quoting for variables transmitted via SSH. A review comment correctly identified a potential crash when EXTRA_ENV is unset due to the set -u flag and suggested including carriage return normalization for better cross-platform compatibility.

Comment thread scripts/rolling-update.sh Outdated
# shells (/bin/sh -> dash on Debian/Ubuntu) don't grok $'...' and would
# pass it through as literal characters, breaking the `KEY=VALUE`
# validator in run_container.
EXTRA_ENV_NORMALISED="${EXTRA_ENV//$'\n'/ }"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script uses set -u (via set -euo pipefail on line 2), which causes it to exit immediately if an unset variable is referenced. Since EXTRA_ENV is not initialized with a default value earlier in the script, this line will trigger a fatal error if EXTRA_ENV is not provided in the environment or the env file.

Additionally, while you are normalizing newlines, it is good practice to also normalize carriage returns (\r) to handle deploy.env files that might have been edited on Windows.

Suggested change
EXTRA_ENV_NORMALISED="${EXTRA_ENV//$'\n'/ }"
EXTRA_ENV_NORMALISED="${EXTRA_ENV:-}"
EXTRA_ENV_NORMALISED="${EXTRA_ENV_NORMALISED//[$'\r\n']/ }"

Addresses gemini HIGH + codex P2 on 8ded4d1.

1. Gemini HIGH -- `set -u` crash when EXTRA_ENV is unset.
   `${EXTRA_ENV//$'\n'/ }` dereferences $EXTRA_ENV, which under `set -u`
   aborts the script when the variable is unset (EXTRA_ENV is documented
   as optional in deploy.env). Fixed by going through `${EXTRA_ENV:-}`
   first.

2. Codex P2 -- `printf %q` still emits ANSI-C quoting for tabs and CR.
   Newline was only one of several non-printable characters that trigger
   the $'...' escape form. Tab and \r both do the same thing. Tabs can
   appear as legitimate separators; \r appears when deploy.env is edited
   on Windows. Normalise all three to spaces before %q.

Smoke (all passing; see /tmp/pr591_smoke.sh):
  unset:         [''] -- no crash
  CRLF+tab:      [FOO=1\ \ BAR=2\ BAZ=3] -- dash-portable, no $'...'
  simple:        [ELASTICKV_RAFT_DISPATCHER_LANES=1]
  glob-prone:    [WILD=\*] -- not expanded
  multi-line:    [FOO=1\ BAR=2\ BAZ=3]
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed both items on 8ded4d1 in acc3ab1.

1. Gemini HIGH — set -u crash when EXTRA_ENV is unset.

Correct. EXTRA_ENV_NORMALISED="${EXTRA_ENV//$'\n'/ }" dereferences $EXTRA_ENV, and under set -euo pipefail that aborts the script when the variable is unset. EXTRA_ENV is documented as optional, so production deploys without it would have crashed at this line. Fixed by going through ${EXTRA_ENV:-} first:

EXTRA_ENV_NORMALISED="${EXTRA_ENV:-}"
EXTRA_ENV_NORMALISED="${EXTRA_ENV_NORMALISED//[$'\t\r\n']/ }"

2. Codex P2 — normalise tab and CR, not just newline.

Also correct. printf '%q' emits ANSI-C $'...' quoting for any non-printable character; newline was just one of them. Tabs and \r behave identically — tabs could appear as legitimate separators (script docs EXTRA_ENV as whitespace-separated), and \r appears when deploy.env is edited on Windows. Extended the character class to [$'\t\r\n'].

Smoke tests (5 scenarios, all pass):

case input output
unset (unset) '' (no crash)
CRLF + tab FOO=1\r\nBAR=2\tBAZ=3 FOO=1\ \ BAR=2\ BAZ=3 (dash-portable)
simple ELASTICKV_RAFT_DISPATCHER_LANES=1 ELASTICKV_RAFT_DISPATCHER_LANES=1
glob WILD=* WILD=\* (not expanded remotely)
multi-line FOO=1\nBAR=2\nBAZ=3 FOO=1\ BAR=2\ BAZ=3

Explicitly verified no $'...' in any output; every result is parseable by dash.

bash -n scripts/rolling-update.sh clean. make lint clean.

/gemini review
@codex review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to scripts/rolling-update.sh, enabling the passage of additional environment variables to remote Docker containers. It also enhances the script's robustness by applying shell escaping to several variables before they are transmitted over SSH. The review feedback suggests extending this escaping to RAFT_TO_REDIS_MAP and RAFT_TO_S3_MAP for consistency and improved defense in depth.

Comment thread scripts/rolling-update.sh Outdated
Comment on lines 427 to 428
RAFT_TO_REDIS_MAP="$RAFT_TO_REDIS_MAP" \
RAFT_TO_S3_MAP="$RAFT_TO_S3_MAP" \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with the 'defense in depth' approach taken for other variables in this PR (like IMAGE_Q and DATA_DIR_Q), RAFT_TO_REDIS_MAP and RAFT_TO_S3_MAP should also be escaped using printf %q before being passed to the remote host. These variables contain complex mapping strings that could benefit from the same level of protection against shell re-parsing issues.

Suggested change
RAFT_TO_REDIS_MAP="$RAFT_TO_REDIS_MAP" \
RAFT_TO_S3_MAP="$RAFT_TO_S3_MAP" \
RAFT_TO_REDIS_MAP="$RAFT_TO_REDIS_MAP_Q" \
RAFT_TO_S3_MAP="$RAFT_TO_S3_MAP_Q" \

Comment thread scripts/rolling-update.sh
DATA_DIR_Q="$(printf '%q' "$DATA_DIR")"
SERVER_ENTRYPOINT_Q="$(printf '%q' "$SERVER_ENTRYPOINT")"
RAFTADMIN_REMOTE_BIN_Q="$(printf '%q' "$RAFTADMIN_REMOTE_BIN")"
CONTAINER_NAME_Q="$(printf '%q' "$CONTAINER_NAME")"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Define the escaped versions of the map variables here to support their use in the update_one_node function.

Suggested change
CONTAINER_NAME_Q="$(printf '%q' "$CONTAINER_NAME")"
CONTAINER_NAME_Q="$(printf '%q' "$CONTAINER_NAME")"
RAFT_TO_REDIS_MAP_Q="$(printf '%q' "$RAFT_TO_REDIS_MAP")"
RAFT_TO_S3_MAP_Q="$(printf '%q' "$RAFT_TO_S3_MAP")"

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Addresses gemini medium on acc3ab1.

Both CSV maps are derived (not directly user-supplied) and structurally
contain only `=`, `:`, `,`, digits and identifier chars today -- none
shell-special. `printf %q` is therefore a no-op under the current NODES
format, but adding the escape aligns them with the other forwarded vars
(IMAGE_Q, DATA_DIR_Q, etc.) so future evolution of the NODES schema
can't silently corrupt the remote command line.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed gemini medium on acc3ab1 in 3a4e2be.

Extended printf %q defense-in-depth escaping to RAFT_TO_REDIS_MAP and RAFT_TO_S3_MAP, aligning with the existing IMAGE_Q / DATA_DIR_Q / etc. pattern.

Caveat worth noting: both maps are derived (not user-supplied) — constructed by derive_raft_to_redis_map / derive_raft_to_s3_map from NODES, and structurally contain only =, :, ,, digits, and identifier chars. None are shell-special. So printf %q on today's values is a true no-op. Kept the change for consistency so a future NODES schema evolution can't silently corrupt the remote command line.

bash -n scripts/rolling-update.sh clean. make lint clean.

/gemini review
@codex review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV variable to scripts/rolling-update.sh, enabling the pass-through of additional environment variables to remote Docker containers. It also enhances the script's reliability by properly escaping shell variables before transport over SSH using printf %q. A review comment suggests explicitly defining IFS when parsing EXTRA_ENV to ensure consistent splitting behavior.

Comment thread scripts/rolling-update.sh Outdated
# would be silently dropped.
local -a extra_env_pairs=()
local extra_env_normalised="${EXTRA_ENV//$'\n'/ }"
read -r -a extra_env_pairs <<< "${extra_env_normalised}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Explicitly setting IFS for the read command is a best practice to ensure the splitting logic remains consistent even if the global IFS variable is modified elsewhere in the script. Since EXTRA_ENV is intended to be whitespace-separated, using the default whitespace IFS (space, tab, newline) is appropriate and robust.

Suggested change
read -r -a extra_env_pairs <<< "${extra_env_normalised}"
IFS=$' \t\n' read -r -a extra_env_pairs <<< "${extra_env_normalised}"

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Addresses gemini medium on 3a4e2be.

`read -r -a` inherits the ambient IFS. Default is already space/tab/
newline, but making the splitting deterministic against any future
IFS mutation elsewhere in the script (or sourced file) is cheap
insurance. Smoke-tested: with IFS=":" in the outer scope, the pinned
IFS=$' \t\n' still splits "FOO=1 BAR=2 BAZ=3" into three entries.
@bootjp
Copy link
Copy Markdown
Owner Author

bootjp commented Apr 23, 2026

Addressed gemini medium on 3a4e2be in e871564.

Pinned IFS explicitly on the read -r -a splitting EXTRA_ENV. Bash's default IFS is already $' \t\n', but making the splitting deterministic against any future outer-scope IFS mutation (e.g. a sourced helper that leaves IFS=: or similar) is cheap insurance.

IFS=$' \t\n' read -r -a extra_env_pairs <<< "${extra_env_normalised}"

Smoke: under a perturbed outer IFS=":", the pinned read still splits FOO=1 BAR=2 BAZ=3 into 3 entries as expected.

bash -n scripts/rolling-update.sh clean. make lint clean.

/gemini review
@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the EXTRA_ENV environment variable to the rolling-update.sh script, allowing users to pass additional configuration to the remote Docker container as a whitespace-separated list of KEY=VALUE pairs. The update also improves the script's robustness by implementing proper shell escaping (using printf %q) for variables transmitted via SSH, ensuring that whitespace and shell metacharacters are correctly handled by the remote login shell. I have no feedback to provide.

@bootjp bootjp merged commit 306eb0b into main Apr 23, 2026
8 checks passed
@bootjp bootjp deleted the feat/rolling-update-extra-env branch April 23, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant