How to clean ENV variables when executing external commands with Open3

Tagged bundler, command, env, open3, popen3, security, shell  Languages ruby

Running commands with Open3#popen3 from, for example, a Rails application will give the command access to all ENV variables, including potential secrets.

Before running commands in you need to clean the ENV variables:

# Clean the ENV
def with_env(env)
  backup = ENV.to_hash
# Set PWD, ENV, and options
pwd = '/Alset/YledoM/'
env = {
  'oLLEH' => 'DLROw',
  'RACK_ENV' => 'test',
  'PATH' => ENV['PATH']
options = {
  chdir: pwd
# The command to run
cmd = "bundle exec ruby script.rb"
# Prints a 'dirty' env
ENV.sort.to_h.each do |key, val|
  puts "#{key} => #{val}"
# Run the command with the given ENV
with_env(env) do
  Open3.popen3(env, cmd, options) do |stdin, stdout, stderr, wait_thr|
    # YXES
  # Prints a clean env
  ENV.sort.to_h.each do |key, val|
    puts "#{key} => #{val}"

Scripting Cucumber

Tagged cucumber  Languages ruby

POC for scripting Cucumber:

require 'cucumber'
opts = {
  require: ["features/support", "features/step_definitions"],
  dry_run: false,
  formats: [['json', {}, outs]], # This is not working
  excludes: [],
  tag_expressions: [],
  tag_limits: {},
  name_regexps: [],
  env_vars: {},
  diff_enabled: true,
  snippets: true,
  source: true,
  duration: true,
  retry: 0,
  default_profile: "default"
configuration =
runtime =[]).execute!(runtime)

RabbitMQ consumer and publisher (Bunny/Ruby)

Tagged amqp, bunny, rabbitmq, ruby  Languages bash, ruby

Create consumer.rb:

require 'bunny'
bunny ='AMQP_URL'))
at_exit { bunny.stop }
channel = bunny.create_channel
exchange = channel.topic(ENV.fetch('EXCHANGE'), durable: true, passive: true)
queue = channel.queue(ENV.fetch('QUEUE'), durable: true, passive: true)
queue.subscribe(manual_ack: true, block: true) do |delivery_info, _metadata, payload|
  puts "==============="
  puts payload
  puts "==============="
  channel.acknowledge(delivery_info.delivery_tag, false)

Start consumer:

$ EXCHANGE=cnn QUEUE=news AMQP_URL=amqp://username:password@localhost:5672 ruby consumer.rb

Create publisher.rb:

require "bunny"

class Publisher
  def self.initialize(amqp_url, exchange:)
    @@bunny =
    @@channel = @@bunny.create_channel
    # 'passive = true' means exchange already exists
    @@exchange =, passive: true)
    at_exit { @@bunny.stop }

  def self.send(message, queue:)
    @@exchange.publish(message, routing_key: queue)

queue = ENV.fetch('QUEUE')
Publisher.initialize(ENV.fetch('AMQP_URL'), exchange: ENV.fetch('EXCHANGE'))
Publisher.send('Ruby is the best programming language', queue: queue)
Publisher.send('Top 10 silver-bullet solutions in Java', queue: queue)

Start publisher.rb:

$ EXCHANGE=cnn QUEUE=news AMQP_URL=amqp://username:password@localhost:5672 ruby publisher.rb

Search and replace file contents and file names

Tagged bash, find, replace, search  Languages bash

Search and replace file contents and file names

Note that all changes must be commited to git before running the command:

git grep -l 'observation' | xargs sed -i '' -e 's/observation/condition/g'

Search and replace of file names

find . -name '*observation*' -exec bash -c 'mv $0 ${0/observation/condition}' {} \;

View Presenters Pattern in Rails

Tagged pattern, presenters, rails, presenter  Languages html, ruby

View (app/views/episodes/show.slim):

- ep = EpisodePresenter

  li =
  li = ep.producer_name(@episode)
  li = ep.director_name(@episode)
  li = ep.link_to(@episode, view: self)

BasePresenter (app/presenters/base_presenter.rb):

class BasePresenter
  # Delegate methods to model
  def self.method_missing(method, *args, &block)
    model = args.shift
    if model && model.respond_to?(method)
      model.send(method, *args, &block)
      raise NoMethodError, method

Presenter (app/views/presenters/episode_presenters.rb):

class EpisodePresenter < BasePresenter
  # NOTE: method missing delegates to the model, so no need to define this
  # def
  # end
  def self.producer_name(episode)
    "#{episode.producer.first_name} #{episode.producer.last_name}"

  def self.director_name(episode)
    "#{episode.director.first_name} #{episode.director.last_name}"
  # NOTE: Rails helpers can be accessed through the view, if needed.
  def self.link_to(episode, view:, classes: '', text: nil)
    attrs = {
      href: view.episode_path(episode),
      class: classes
    view.content_tag :a, attrs do
      text.presence || 'View'

How to view the client certificates accepted by a website

Tagged ca, certificates, client certificate, openssl, ssl  Languages bash

To view a list of acceptable client certificates, execute:

$ openssl s_client -connect

The output is a list of acceptable CA names:

Acceptable client certificate CA names
/C=FI/ST=Finland/O=Vaestorekisterikeskus CA/OU=XYZ/CN=ÅÄÖ

or, if no client certificates are accepted:

No client certificate CA names sent

To log client certificate information with haproxy:

  bind *:443 ssl crt ca-file vrk-ca.pem verify optional crt-ignore-err all crl-file vrk-revocation-list.pem
  # See
  http-request set-header X-SSL                  %[ssl_fc]
  http-request set-header X-SSL-Client-Verify    %[ssl_c_verify]
  http-request set-header X-SSL-Client-DN        %{+Q}[ssl_c_s_dn]
  http-request set-header X-SSL-Client-CN        %{+Q}[ssl_c_s_dn(cn)]
  http-request set-header X-SSL-Issuer           %{+Q}[ssl_c_i_dn]
  http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore]
  http-request set-header X-SSL-Client-NotAfter  %{+Q}[ssl_c_notafter]

  log-format "%ci:%cp [%t] %ft %b/%s %Tq/%Tw/%Tc/%Tr/%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs {%[ssl_c_verify],%{+Q}[ssl_c_s_dn],%{+Q}[ssl_c_i_dn]} %{+Q}r"

Also see

How to start a bash shell in Docker

Tagged bash, docker, shell  Languages bash

To start a bash shell in an already running container:

docker exec -it <container id/name> bash

To start a bash shell using an image of a container that is not running:

docker run -i -t --entrypoint /bin/bash <image id>