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
  ENV.replace(env)
  yield
ensure
  ENV.replace(backup)
end
# 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}"
end
# Run the command with the given ENV
with_env(env) do
  Open3.popen3(env, cmd, options) do |stdin, stdout, stderr, wait_thr|
    # YXES
  end
  # Prints a clean env
  ENV.sort.to_h.each do |key, val|
    puts "#{key} => #{val}"
  end
end

Scripting Cucumber

Tagged cucumber  Languages ruby

POC for scripting Cucumber:

require 'cucumber'
opts = {
  strict: Cucumber::Core::Test::Result::StrictConfiguration.new,
  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 = Cucumber::Configuration.new(opts)
runtime = Cucumber::Runtime.new(configuration)
Cucumber::Cli::Main.new([]).execute!(runtime)

RabbitMQ consumer and publisher (Bunny/Ruby)

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

Create consumer.rb:

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

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 = Bunny.new(amqp_url)
    @@bunny.start
    @@channel = @@bunny.create_channel
    # 'passive = true' means exchange already exists
    @@exchange = @@bunny.channel.topic(exchange, passive: true)
    at_exit { @@bunny.stop }
  end

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

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

ul
  li = ep.name(@episode)
  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)
    else
      raise NoMethodError, method
    end
  end
end

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

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

  def self.director_name(episode)
    "#{episode.director.first_name} #{episode.director.last_name}"
  end
 
  #
  # 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'
    end
  end
end

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 golang.org:443

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 xyz.com.pem ca-file vrk-ca.pem verify optional crt-ignore-err all crl-file vrk-revocation-list.pem
  # See https://www.haproxy.com/blog/ssl-client-certificate-information-in-http-headers-and-logs/
  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 https://tools.ietf.org/html/rfc5246#page-53

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>