computerd: let the caller choose the exec shell - #139
Merged
Conversation
Every exec command runs through a hardcoded /bin/sh. On a Debian-family image that is dash, where bash-only syntax is a parse error rather than a missing feature, so the whole command aborts instead of degrading. That matters most for the PIPESTATUS array: a caller that filters a command's output, such as piping git through sed to redact a credential from the URL, gets the pipeline's last exit status and reads a failed push as a success. PIPESTATUS is how the real status is recovered, and under dash reaching for it is worse than the problem it was reached for. Add an optional shell to the runner options, defaulting to /bin/sh, and read the same value from EXEC_SHELL so a deployed daemon can set it without a rebuild. Existing callers are unaffected. The previous workaround was to repoint /bin/sh inside the image, which changes echo semantics for every other script there and is unavailable when the image is prebuilt.
🦋 Changeset detectedLatest commit: 2bc75d1 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every command from
execruns through a hardcoded/bin/sh. On a Debian-family image that isdash, where the syntax a caller reaches for whendashis not enough fails as a parse error rather than as a missing feature, so the whole command stops instead of carrying on.This matters most for
PIPESTATUS. A pipeline reports the exit status of its last stage, so a caller that filters output through another command loses the real result. Redacting a credential out of a push is the common case, and it quietly reports success when the push failed:The usual way to recover the real status is
${PIPESTATUS[0]}, whichbashhas anddashdoes not. Underdashit is worse than the problem it was reached for:dashdoes${PIPESTATUS[@]}Bad substitution, and the rest of the command never runsa=(1 2 3)[[ 1 == 1 ]][[: not found<(some command)There was no way to change this. The runner had no option for it,
SHELLis deliberately left out of the environment passed to children, and the only workaround was repointing/bin/shinside the image, which changes howechotreats backslashes for every other script there and is impossible with a prebuilt image.The runner now takes the interpreter as an option and the daemon reads the same value from
EXEC_SHELL. Both default to/bin/sh, so nothing changes for existing callers unless they ask for something else. The path must be absolute, and a relative one is refused when the runner is built rather than failing later on every command.Picking an interpreter is the caller's choice and nothing about pipelines changes on its own. Turning on
pipefailby default would alter the exit status of existing callers, because agrepthat matches nothing or adiffthat finds a difference would start reporting failure. Callers who want that can putset -o pipefailat the top of their command on either interpreter.To see it work, run the daemon as
EXEC_SHELL=/usr/bin/bash computerdand send this throughexec:Four tests cover it: the default is still
/bin/sh, a chosen interpreter is the one that runs,PIPESTATUSresolves under it instead of stopping the command, and a relative path is refused. The two that needbashskip themselves when it is missing, so the suite still passes without it. The default test is what shows existing callers are unaffected, and it passes both before and after the change.The
computerdreadme now documentsEXEC_SHELLalongside the other environment variables it accepts.