ProductPromotion
Logo

Ruby

made by https://0x3d.site

GitHub - thoughtbot/terrapin: Run shell commands safely, even with user-supplied values
Run shell commands safely, even with user-supplied values - thoughtbot/terrapin
Visit Site

GitHub - thoughtbot/terrapin: Run shell commands safely, even with user-supplied values

GitHub - thoughtbot/terrapin: Run shell commands safely, even with user-supplied values

Terrapin Build Status

Run shell commands safely, even with user-supplied values

API reference

Usage

The basic, normal stuff:

line = Terrapin::CommandLine.new("echo", "hello 'world'")
line.command # => "echo hello 'world'"
line.run # => "hello world\n"

Interpolated arguments:

line = Terrapin::CommandLine.new("convert", ":in -scale :resolution :out")
line.command(in: "omg.jpg",
             resolution: "32x32",
             out: "omg_thumb.jpg")
# => "convert 'omg.jpg' -scale '32x32' 'omg_thumb.jpg'"

It prevents attempts at being bad:

line = Terrapin::CommandLine.new("cat", ":file")
line.command(file: "haha`rm -rf /`.txt") # => "cat 'haha`rm -rf /`.txt'"

line = Terrapin::CommandLine.new("cat", ":file")
line.command(file: "ohyeah?'`rm -rf /`.ha!") # => "cat 'ohyeah?'\\''`rm -rf /`.ha!'"

NOTE: It only does that for arguments interpolated via run, NOT arguments passed into new (see 'Security' below):

line = Terrapin::CommandLine.new("echo", "haha`whoami`")
line.command # => "echo haha`whoami`"
line.run # => "hahawebserver\n"

This is the right way:

line = Terrapin::CommandLine.new("echo", "haha:whoami")
line.command(whoami: "`whoami`") # => "echo haha'`whoami`'"
line.run(whoami: "`whoami`") # => "haha`whoami`\n"

You can ignore the result:

line = Terrapin::CommandLine.new("noisy", "--extra-verbose", swallow_stderr: true)
line.command # => "noisy --extra-verbose 2>/dev/null"

# ... and on Windows...
line.command # => "noisy --extra-verbose 2>NUL"

If your command errors, you get an exception:

line = Terrapin::CommandLine.new("git", "commit")
begin
  line.run
rescue Terrapin::ExitStatusError => e
  e.message # => "Command 'git commit' returned 1. Expected 0"
end

If your command might return something non-zero, and you expect that, it's cool:

line = Terrapin::CommandLine.new("/usr/bin/false", "", expected_outcodes: [0, 1])
begin
  line.run
rescue Terrapin::ExitStatusError => e
  # => You never get here!
end

You don't have the command? You get an exception:

line = Terrapin::CommandLine.new("lolwut")
begin
  line.run
rescue Terrapin::CommandNotFoundError => e
  e # => the command isn't in the $PATH for this process.
end

But don't fear, you can specify where to look for the command:

Terrapin::CommandLine.path = "/opt/bin"
line = Terrapin::CommandLine.new("lolwut")
line.command # => "lolwut", but it looks in /opt/bin for it.

You can even give it a bunch of places to look:

FileUtils.rm("/opt/bin/lolwut")
File.open('/usr/local/bin/lolwut') { |f| f.write('echo Hello') }
Terrapin::CommandLine.path = ["/opt/bin", "/usr/local/bin"]
line = Terrapin::CommandLine.new("lolwut")
line.run # => prints 'Hello', because it searches the path

Or just put it in the command:

line = Terrapin::CommandLine.new("/opt/bin/lolwut")
line.command # => "/opt/bin/lolwut"

You can see what's getting run. The 'Command' part it logs is in green for visibility! (where applicable)

line = Terrapin::CommandLine.new("echo", ":var", logger: Logger.new(STDOUT))
line.run(var: "LOL!") # => Logs this with #info -> Command :: echo 'LOL!'

Or log every command:

Terrapin::CommandLine.logger = Logger.new(STDOUT)
Terrapin::CommandLine.new("date").run # => Logs this -> Command :: date

Security

Short version: Only pass user-generated data into the run method and NOT new.

As shown in examples above, Terrapin will only shell-escape what is passed in as interpolations to the run method. It WILL NOT escape what is passed in to the second argument of new. Terrapin assumes that you will not be manually passing user-generated data to that argument and will be using it as a template for your command line's structure.

Runners

Terrapin will choose from among a couple different ways of running commands. The simplest is Process.spawn, which is also the default. Terrapin can also just use backticks, so if for some reason you'd prefer that, you can ask Terrapin to use that:

Terrapin::CommandLine.runner = Terrapin::CommandLine::BackticksRunner.new

And if you really want to, you can define your own Runner, though I can't imagine why you would.

Terrapin::CommandLine.runner = Terrapin::CommandLine::BackticksRunner.new

And if you really want to, you can define your own Runner, though I can't imagine why you would.

JRuby issues

Caveat

If you get Error::ECHILD errors and are using JRuby, there is a very good chance that the error is actually in JRuby. This was brought to our attention in https://github.com/thoughtbot/terrapin/issues/24 and probably fixed in http://jira.codehaus.org/browse/JRUBY-6162. You will want to use the BackticksRunner if you are unable to update JRuby.

Spawn warning

If you get unsupported spawn option: out warning (like in issue 38), try to use PopenRunner:

Terrapin::CommandLine.runner = Terrapin::CommandLine::PopenRunner.new

Thread Safety

Terrapin should be thread safe. As discussed here, in this climate_control thread, climate_control, which modifies the environment under which commands are run for the BackticksRunner and PopenRunner, is thread-safe but not reentrant. Please let us know if you find this is ever not the case.

Feedback

Security concerns must be privately emailed to [email protected].

Question? Idea? Problem? Bug? Comment? Concern? Like using question marks?

GitHub Issues For All!

Credits

Thank you to all the contributors!

License

Copyright © 2011 Jon Yurek and thoughtbot, inc. This is free software, and may be redistributed under the terms specified in the LICENSE file.

About thoughtbot

thoughtbot

This repo is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.

We love open source software! See our other projects. We are available for hire.

More Resources
to explore the angular.

mail [email protected] to add your project or resources here 🔥.

Related Articles
to learn about angular.

FAQ's
to learn more about Angular JS.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory