Skip to content

fix(plugin): find a shell's -c script after its options and behind env - #40

Merged
junior merged 1 commit into
p10node:mainfrom
junior:plugin-shell-script
Nov 12, 2026
Merged

junior merged 1 commit into
p10node:mainfrom
junior:plugin-shell-script

Conversation

@junior

@junior junior commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to the review of #28. SECURITY.md says a shell's -c script gets plugin values through the environment, but ExecCommand did that only when the script was the argument right after the first short option group containing c, and only when the command itself was the shell. Two kinds of plugin got values pasted into the script as text:

  • sh -c -x '...', sh -c -o errexit '...', sh -c -- '...': a shell reads options up to the first argument that does not start with - or +, so the script comes after -x, -o errexit or --;
  • env bash -c '...', busybox sh -c '...': the command's own name is not a shell.

shellCode now reads the options the way the shells do (POSIX sh -c [options] script [name [args]], plus bash's long options), finds the shell behind env (its options read as getopt does) and busybox, and gives values through the environment to the script and the options before it. Arguments after the script ($0, $1, ...) still get them as text, so sh -c '... "$1"' sh $NAME keeps working. Where the shells read an option differently, or k10s does not know it (bash's -O, o inside a group, a lone +, other long options, an env option it does not know), every argument gets the environment: safe, though a value meant for $1 then arrives as the variable's name.

env -S is not a way to a shell: it builds a command line of its own from a string and expands ${VAR} in it, so the environment would not keep a value out of it. It is treated as a program that reads its own command line, like python3 -c, and SECURITY.md now lists it next to python3 -c. SECURITY.md also names env and busybox, and docs/plugins.md says how values reach a -c script.

Tests: TestShellCodeMarksWhatTheShellMayRunAsCode (37 command lines), and TestShellOptionsAfterDashCDoNotLetValuesIntoTheScript, which runs sh, bash and env with a value that creates a file if the shell parses it. On main, 4 of its 6 cases fail (sh -c -x, sh -c -o errexit, sh -c --, env sh -c). gofmt, vet and go test -short ./... pass on Go 1.26.11 and 1.27.4.

A plugin whose command is a POSIX shell gets plugin values in its -c
script through the environment, so a value from the cluster is never read
as shell syntax (SECURITY.md). ExecCommand took the argument right after
the first short option group containing c as the script, and only when the
command itself was one of the five shells, so values were pasted as text
into the script the shell really runs in:

- sh -c -x '...', sh -c -o errexit '...' and sh -c -- '...': a shell reads
  options up to the first argument that does not start with - or +, or up
  to --, so the script comes after -x, -o errexit or --;
- env bash -c '...' and busybox sh -c '...': the command is not a shell.

shellCode now reads the options as the shells do: groups that start with -
or + (c turns on -c, +c too), o taking the next argument when it ends its
group, -- or a lone - ending the options, and bash's long options. It finds
the shell behind env, whose options it reads as getopt does, and behind
busybox's sh, ash, hush and bash. The script and the options before it get
values through the environment; arguments after the script ($0, $1, ...)
still get them as text. Where the shells read an option differently, or
k10s does not know it (bash's -O, o inside a group, a lone +, other long
options, an env option it does not know), every argument gets the
environment: safe, though a value meant for $1 then arrives as the
variable's name. A Windows build of a shell (bash.exe) counts as the shell.

env -S is not a way to a shell: it builds a command line of its own from a
string and expands ${VAR} in it, so the environment would not keep a value
out of it. It stays a program that reads its own command line, as
python3 -c is, and gets values as text.

SECURITY.md names env and busybox, and puts env -S with python3 -c;
docs/plugins.md says how values reach a -c script.

From the review of p10node#28.

Signed-off-by: Adao Oliveira Jr <junior@users.noreply.github.com>
@junior
junior requested a review from pierreneter as a code owner November 12, 2026 00:30
@junior
junior merged commit ed98435 into p10node:main Nov 12, 2026
3 checks passed
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.

2 participants