{"id":20641861,"url":"https://github.com/sergueik/uru_serverspec","last_synced_at":"2025-07-18T18:36:21.061Z","repository":{"id":80959390,"uuid":"77707402","full_name":"sergueik/uru_serverspec","owner":"sergueik","description":"Puppet module to deploy standalone ruby environment and run serverspec on the instance for a network access locked down cloud environment","archived":false,"fork":false,"pushed_at":"2025-01-02T14:52:08.000Z","size":9282,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-09T12:56:56.625Z","etag":null,"topics":["powershell","puppet","ruby","serverspec"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sergueik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-30T19:57:43.000Z","updated_at":"2025-01-02T14:52:12.000Z","dependencies_parsed_at":"2024-06-19T11:30:05.801Z","dependency_job_id":"4fea8436-6041-4bfc-8100-fe6b731b088c","html_url":"https://github.com/sergueik/uru_serverspec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sergueik/uru_serverspec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2Furu_serverspec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2Furu_serverspec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2Furu_serverspec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2Furu_serverspec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sergueik","download_url":"https://codeload.github.com/sergueik/uru_serverspec/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sergueik%2Furu_serverspec/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265810378,"owners_count":23831950,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["powershell","puppet","ruby","serverspec"],"created_at":"2024-11-16T16:07:03.196Z","updated_at":"2025-07-18T18:36:19.941Z","avatar_url":"https://github.com/sergueik.png","language":"Go","readme":"﻿## Uru Serverspec\n\n### Introduction\n\nThere is a challenge to run [serverspec](http://serverspec.org/resource_types.html) on the instance managed\nby Puppet or Chef for a network access locked down cloud environment\nafter the single sign-on (SSO) a.k.a. access management software has been provisioned making remote access impossible.\nFor example review the Enterprise [BokS](http://www.foxt.com/wp-content/uploads/2015/03/BoKS-Server-Control.pdf) \nfor Unix ssh and various vendors-specific authentication schemes e.g.\n[milti factor authentication](https://en.wikipedia.org/wiki/Multi-factor_authentication) (MFA) for Windows logon.\nBy design such software disables ssh and winrm ssh key-based remote access.\nRemote access however is critical transport mechanism the vanilla serverspec / inspec relies on for code delivery.\n\nWith the help of [Ruby Version Manager](https://en.wikipedia.org/wiki/Ruby_Version_Manager) and specifically [uru Ruby Installer](https://rubyinstaller.org/add-ons/uru.html) one can bootstrap a standalone Ruby environment to run serverspec directly on the instance, on either Linux or Windows.\nThe only prerequisite on a Linux system are `openssl-libs`, `libcrypt` and `libyaml` libraries, those are very likely already installed for openssl stack on a generic linux box.\n\nAnother interesting use case is when Puppet provision serves as a driver of a\nmassive deloyment of a list of microservice application stack e.g. Java jars / wars to the cluster of nodes.\nIn this scenario, there would be a [Puppet profile](https://puppet.com/docs/pe/2017.2/r_n_p_intro.html)\nsolely responsibe for deploying the domain specific subset of such\nstack, typically via a massive Puppet `create_resource` [function](https://puppet.com/docs/puppet/5.5/lang_resources_advanced.html#implementing-the-createresources-function)\nfeaturing a heavy hiera-centric configuration lookup to pick the release version, build, checksum and\nvarious application-specific parameters of the microservices:\n```puppet\ncreate_resources('microservice_deployent', lookup('profile::api::microservices'), {\n  path =\u003e $app_root_path,\n  tags =\u003e $tags,\n})\n```\n\nwhere all the details of home brewed `microservice_deployent`\n[defined type](https://puppet.com/docs/puppet/5.5/lang_defined_types.html)\nwould be serialized from [hiera](https://puppet.com/docs/puppet/5.5/hiera.html):\n```yaml\nprofile::api::microservices:\n  account_service:\n    v1:\n      artifact_name: 'account_service.war'\n      build_number: 123\n      artifact_chesksum: 'c4f5c6a37486002f56f269b5e98200a2be84a41498f698bc890b7c255eedeb74'\n      artifact_chesksum_type: 'sha256'\n```\nThere will likely be more than one defined type like that in a real microservices hosting project.\n\nApparently when the serverspec is confgured to run from the development host, this would lead to\nduplication of version/configuration information elsewhere which would be highly undesired.\n\nIdeally one would like to generate a serverspec test(s) for multile Puppet managed components via some template and same hiera data from the same profile through\n[Puppet erb or epp](https://puppet.com/docs/puppet/5.5/lang_template.html) templates:\n```ruby\nrequire 'spec_helper'\n\ncontext '\u003c%= @name -%\u003e' do\n  # define all component configuration, version parameters\n  name = '\u003c%= @name -%\u003e'\n  catalina_home = '\u003c%= @catalina_home -%\u003e'\n  microservices = {\n    \u003c% @microservices.each do |key,data| -%\u003e\n      '\u003c%= @key -%\u003e' =\u003e\n        {\n          'artifact_name' =\u003e '\u003c%= data[\"artifact_name\"] -%\u003e',\n          'artifact_chesksum' =\u003e '\u003c%= data[\"artifact_chesksum\"] -%\u003e',\n        },\n    \u003c% end -%\u003e\n  }\n  microservices.each do |key,data|\n    describe file(\"#{catalina_home}/webapps/#{name}/#{key}/#{data['artifact_name']}.war\") do\n      it {should be_file}\n      its(:sha256sum) { should eq \"data['artifact_chesksum']\" }\n    end\n    describe file(\"#{catalina_home}/webapps/#{name}/#{key}/#{data['artifact_name']}\") do\n      it {should be_directory}\n      # TODO: microservice configuration detail XML lookup\n    end\n    describe command(\"curl http://localhost:8443/#{catalina_home}/webapps/#{name}/health\") do\n      its(:stdout) { should match 'UP' }\n    end\n  end\nend\n```\n\n- the server spec itself is elementary, it builds a valid Ruby hash which mimics the hieradata schema, and\npossibly other Puppet scope variables describing the application comtainer details\nand runs a file, directory, service health and optionally some advanced configuration checks\nfor every deployed microservice.\nIts only complexity arises with integration with the cluster Puppet hieradata - it is not uncommon when hundreds of microservice artifacts are deployed. Every now and then when a new  microservice expectaion is designed there is a moderate complexity task of coverting it into template.\nThere is a little downside of template based serverspec generation - it is of course that the only environment\neverything is assembled fully is the instance itself.\n\nOn Unix, there certainly are alternatives, but on Windows, rvm-like tools are scarcely available.\nThe only alternative found was [pik](https://github.com/vertiginous/pik), and it is not maintained since 2012.\nAlso, installing a full [Cygwin](https://www.cygwin.com/) environment on a Windows instance\njust to enable one to run [rvm](http://blog.developwithpassion.com/2012/03/30/installing-rvm-with-cygwin-on-windows/)\nfeels like an overkill.\n\nIt is no longer necessary, though still possible to run serverspec at the end of provision.\nTo run the same set of tests locally on the insance in uru environment and remotely on the developer host in\n[Vagrant serverspec](https://github.com/jvoorhis/vagrant-serverspec) plugin - see the example below on how to update the Vagrantfile.\n\nA possible alternative is to add the __uru\\_serverspec__ module\nto control repository role / through a dedicated 'test' profile (stage), which will cause Puppet to verify the modules and everything declared in the 'production' profile (stage). This is possible [thanks](https://puppet.com/docs/puppet/5.0/file_serving.html) to a special `modules` mount point a __Puppet server__ serves files from every module directory as if someone had copied the files directory from every module into one big directory, renaming each of them with the name of their module. Note since acording to official [Puppet guidelines](https://puppet.com/docs/pe/2017.3/managing_nodes/the_roles_and_profiles_method.html) role class is supposed to declare profile classes with include, and do nothing else, one is discouraged from creating  files resources in the __role__ and would likely need to place serverspec files (which are in fact, role-specific) under profiles directory.\n\nThe module __uru\\_serverspec__ can be configured to execute `rake spec` with the serverspec files during every provision run (the default) or only when changes are detected in the ruby file or hiera configuration.\n\nThis is different from the regular Puppet module behavior, therefore the full Puppet run will not be idempotent,\nbut this reflects the module purpose.\n\nWhen moving to production, this behavior can be suppressed through module parameters.\nAlternatively, the 'test' stage where the module is declared, can be disabled,\nor the class simply can be managed through [hiera_include](https://docs.puppet.com/hiera/3.2/puppet.html#assigning-classes-to-nodes-with-hiera-hierainclude) to not bepresent in production environment.\n\nOn the other hand, exactly because the module ability of being __not__ idempotent, one can use __uru\\_serverspec__ for the same tasks the\n[Chef Inspec](https://github.com/chef/inspec) is used today.\n\nTo continue running serverspec through [vagrant-serverspec](https://github.com/jvoorhis/vagrant-serverspec)\nplugin, one would have to update the path of the `rspec` files in the `Vagrantfile` pointing it to inside the module `files`\ne.g. since serverspec are strongly platform-specific, use the instance's Vagrant `config.vm.box` or the `arch`\n(defined elsewhere) to choose the correct spec file for the instance:\n\n```ruby\narch = config.vm.box || 'linux'\nconfig.vm.provision :serverspec do |spec|\n  if File.exists?(\"spec/#{arch}\")\n    spec.pattern = \"spec/#{arch}/*_spec.rb\"\n  elseif File.exists?(\"files/serverspec/#{arch}\")\n    spec.pattern = \"files/serverspec/#{arch}/*_spec.rb\"\n  end\nend\n```\nThe __uru\\_serverspec__ module can collect serverspec resources from other modules's via Puppet's `puppet:///modules`\nURI and\nthe Puppet [file](https://docs.puppet.com/puppet/latest/reference/type.html#file-attribute-sourceselect) resource:\n```puppet\nfile {'spec/local':\n  ensure              =\u003e directory,\n  path                =\u003e \"${tool_root}/spec/local\",\n  recurse             =\u003e true,\n  source              =\u003e $::uru_serverspec::covered_modules.map |$name| {\n    \"puppet:///modules/${name}/serverspec/${::osfamily}\"\n  },\n  source_permissions =\u003e ignore,\n  sourceselect        =\u003e all,\n}\n```\n\nAlternatively when using [roles and profiles](http://www.craigdunn.org/2012/05/239/), the `uru` module can collect serverspec files from the profile: `/site/profile/files` which is also accessible via `puppet:///modules` URI.\n```puppet\nfile {'spec/local':\n  ensure              =\u003e directory,\n  path                =\u003e \"${tool_root}/spec/local\",\n  recurse             =\u003e true,\n  source              =\u003e $::uru_serverspec::server_roles.map |$server_role| {\"puppet:///modules/profile//serverspec/roles/${server_role}\" },\n  source_permissions =\u003e ignore,\n  sourceselect       =\u003e all,\n}\n```\n\nThis mechanism relies on Puppet [file type](https://github.com/puppetlabs/puppet/blob/cdf9df8a2ab50bfef77f1f9c6b5ca2dfa40f65f7/lib/puppet/type/file.rb)\nand its 'sourceselect'  attribute.\nRegrettably no similar URI for roles: `puppet:///modules/roles/serverspec/${role}` can be constructed,\nthough logically the serverspec are more appropriate to define per-role, than per-profile.\n\nOne can combine the two globs in one attribute definition:\n```ruby\n  if ($profile_serverspec =~ /\\w+/) {\n    $use_profile = true\n  } else {\n    $use_profile = false\n  }\n  ...\n  #lint:ignore:selector_inside_resource\n  source =\u003e $use_profile ? {\n  true    =\u003e \"puppet:///modules/profile/serverspec/roles/${profile_serverspec}\",\n   default =\u003e $::uru_serverspec::covered_modules.map |$item| { \"puppet:///modules/${item}\" },\n  },\n  #lint:endignore\n```\nand also one can  combine the narrow platform-specific tests and tests common to different platform releases separately to reduce the redundancy like below:\n```ruby\n$serverspec_directories =  unique(flatten([$::uru_serverspec::covered_modules.map |$module_name| { \"${module_name}/serverspec/${osfamily_platform}\" }, $::testing_framework::covered_modules.map |$module_name| { \"${module_name}/serverspec/${::osfamily}\" }]))\n```\n\nThen it does the same with types\n```ruby\n  # Populate the type directory with custom types from all covered modules\n  file { 'spec/type':\n    ensure             =\u003e directory,\n    path               =\u003e \"${tool_root}/spec/type\",\n    recurse            =\u003e true,\n    source             =\u003e $::uru_serverspec::covered_modules.map |$module_name| { \"puppet:///modules/${module_name}/serverspec/type\" },\n    source_permissions =\u003e ignore,\n    sourceselect       =\u003e all,\n  }\n```\nNo equivalent mechanism of scanning the cookbooks is implemented with Chef yet AFAIK.\n\nNote that using Ruby `require_relative` one can make the serverspec file located within the\n[Puppet recommended module directory structure](https://puppet.com/docs/puppet/5.3/modules_fundamentals.html)\nbe included into another serverspec file and executed from the developer host during the node provision through\n[vagrant-serverspec](https://github.com/vvchik/vagrant-serverspec) plugin.\nThe exact instruction varies with the location of the serverspec which is often a non-standard one.\n\n### Providing Versions via Template\nFor extracting the versions one can utilize the following parameter\n\n```ruby\n version_template =\u003e $::uru::version_template ? {\n  /\\w+/   =\u003e $::uru::sut_role ? {\n    /\\w+/   =\u003e $::uru::version_template,\n    default =\u003e ''  \n  },  \n  default =\u003e ''\n  }\n```\n\nPuppet resource\n```ruby\n\n  # Write the versions from caller provided template - only works for roles\n  if $version_template =~ /\\w+/ {   \n    file { 'spec/local/versions.rb':\n      ensure             =\u003e file,\n      path               =\u003e \"${tool_root}/spec/local/versions.rb\",\n      content            =\u003e template($version_template),\n      source_permissions =\u003e ignore,\n      require            =\u003e [File['spec/local']],\n      before             =\u003e [File['runner']],\n    } \n    }\n```\n\ntemplate\n```ruby\n$sut_version = '\u003c%= scope.lookupvar(\"sut_version\") -%\u003e'\n```\nand rspec conditional include:\n```ruby\nif File.exists?( 'spec/local/versions.rb') \n  require_relative 'versions.rb'\n  puts \"defined #{$sut_version}\"\nend\n```\n\n### Internals\nOne could provision __uru\\_serverspec__ environment from a zip/tar archive, one can also construct a Puppet module for the same.\nThis is a lightweight alternative to [DracoBlue/puppet-rvm](https://github.com/dracoblue/puppet-rvm) module,\nwhich is likely need to build Ruby from source anyway.\n\nThe `$URU_HOME` home directory with Ruby runtime plus a handful of gems has the following structure:\n![uru folder](https://raw.githubusercontent.com/sergueik/uru_serverspec/master/screenshots/uru-centos.png)\n![uru folder](https://raw.githubusercontent.com/sergueik/uru_serverspec/master/screenshots/uru-windows.png)\n\nIt has the following  gems and their dependencies installed:\n```\nrake\nrspec\nrspec_junit_formatter\nserverspec\n```\n### Setup\nFor windows, `uru.zip` can be created by doing a fresh install of [uru](https://bitbucket.org/jonforums/uru/wiki/Usage) and binary install of\n[Ruby](http://rubyinstaller.org/downloads/) performed on a node with internet access or on a developer host,\nand installing all dependency gems from a sandbox Ruby instance into the `$URU_HOME` folder:\n```powershell\nuru_rt.exe admin add ruby\\bin\nuru_rx.exe gem install --no-rdoc --no-ri serverspec rspec rake json rspec_junit_formatter\n```\nand zip the directory.\n\nNOTE: running __uru__ in a free Vmware instances provided by [Microsoft for IE/Edge testing](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/),\none may need to add the [ffi.gem](https://rubygems.org/search?utf8=%E2%9C%93\u0026query=ffi) which in turn may require installing [Ruby DevKit](https://rubyinstaller.org/add-ons/devkit.html) within uru environment:\n\n```cmd\ncd c:\\uru\nuru ls\n\u003e\u003e 218p440     : ruby 2.1.8p440 (2015-12-16 revision 53160) [i386-mingw32]\nuru.bat 218p440\ncd c:\\devkit\ndevkitvars.bat\n\u003e\u003e Adding the DevKit to PATH...\ncd c:\\uru\ngem install %USERPROFILE%\\Downloads\\ffi-1.9.18.gem\n```\n\nOn Linux, the tarball creation starts with compiling Ruby from source, configured with a prefix `${URU_HOME}/ruby`:\n```bash\nexport URU_HOME='/uru'\nexport RUBY_VERSION='2.5.1'\nexport RUBY_RELEASE='2.5'\n\ncd $URU_HOME\nwget https://cache.ruby-lang.org/pub/ruby/${RUBY_RELEASE}/ruby-${RUBY_VERSION}.tar.gz\ntar xzvf ruby-${RUBY_VERSION}.tar.gz\n\n```\nfollowed by on Centos\n```sh\nyum groupinstall -y 'Developer Tools'\nyum install -y zlib-devel openssl-devel libyaml-devel\n```\nand on Ubuntu\n\n```sh\napt-get install -y zlib1g-dev libssl-dev libyaml-dev\n```\nfollowed by\n```\npushd ruby-${RUBY_VERSION}\n./configure --prefix=${URU_HOME}/ruby --disable-install-rdoc --disable-install-doc\nmake clean\nmake\nrm -fr  ruby\nsudo make install\n```\nNext one is to \ncheck the page `https://bitbucket.org/jonforums/uru/downloads/` for the latest available\nversion of `uru_rt`:\n```sh\ncurl -L -k   https://bitbucket.org/jonforums/uru/downloads/uru.json  | grep '\"version\":'\n```\nand install binary distribution of `uru`\n```bash\nexport URU_HOME='/uru'\nexport URU_VERSION='0.8.5'\npushd $URU_HOME\nwget https://bitbucket.org/jonforums/uru/downloads/uru-${URU_VERSION}-linux-x86.tar.gz\ntar xzvf uru-${URU_VERSION}-linux-x86.tar.gz\n```\nAfter Ruby and__uru__is installed one switches to the isolated environment\nand installs the required gem dependencies\n```sh\n./uru_rt admin add ruby/bin\n```\n```text\n---\u003e Registered ruby at `/uru/ruby/bin` as `251p57`\n```\n```sh\n./uru_rt ls\n```\n```text\n251p57      : ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]\n```\n```sh\nexport URU_INVOKER=bash\n./uru_rt 251p57\n```\n```text\n---\u003e now using ruby 2.5.1-p57 tagged as `251p57`\n```\n```sh\n./uru_rt gem list\n./uru_rt gem install --no-ri --no-rdoc rspec serverspec rake rspec_junit_formatter yamllint rexml\ncp -R ~/.gem .\n```\nFinally the `$URU_HOME` is converted to an archive, that can be provisioned on a clean system.\n\nNOTE: with `$GEM_HOME` one can make sure gems are installed under `.gems` rather then the\ninto a hidden `$HOME/.gem` directory.\nThis may not work correctly with some releases of `uru`. To verify, run the command on a system `uru` is provisioned from the tarball:\n```bash\n./uru_rt gem list --local --verbose\n```\nIf the list of gems is shorter than expected, e.g. only the following gems are listed,\n```\nbigdecimal (1.2.4)\nio-console (0.4.3)\njson (1.8.1)\nminitest (4.7.5)\npsych (2.0.5)\nrake (13.0.6)\nrdoc (4.1.0)\ntest-unit (2.1.10.0)\n```\nthe `${URU_HOME}\\.gem` directory may need to get copied to `${HOME}`\n\n* update the \n`RAKE_VERSION`, `GEM_VERSION` and `RUBY_VERSION` accordingly.\nAfter installing `rake` gem it may need to get copied\n```sh\ncp -R  ~/.gem/ruby/2.5.0/gems/rake-13.0.6 ruby/lib/ruby/gems/2.5.0/gems/\n```\nIf the error\n```ruby\n\u003cinternal:gem_prelude\u003e:1:in `require': cannot load such file -- rubygems.rb (LoadError)\n```\nis observed, note that you have to unpackage the archive `uru.tar.gz` into the same `$URU_HOME` path which was configured when Ruby was compiled.\nNote: [rvm](http://stackoverflow.com/questions/15282509/how-to-change-rvm-install-location) is known to give the same error if the `.rvm` diredctory location was changed .\n\nIn the `spec` directory there is a trimmed down `windows_spec_helper.rb` and `spec_helper.rb` required for `serverspec` gem:\n```ruby\nrequire 'serverspec'\nset :backend, :cmd\n```\n\nand a vanilla `Rakefile` generated by `serverspec init`\n```ruby\nrequire 'rake'\nrequire 'rspec/core/rake_task'\n\ntask :spec    =\u003e 'spec:all'\ntask :default =\u003e :spec\n\nnamespace :spec do\n  targets = []\n  Dir.glob('./spec/*').each do |dir|\n    next unless File.directory?(dir)\n    target = File.basename(dir)\n    target = \"_#{target}\" if target == 'default'\n    targets \u003c\u003c target\n  end\n\n  task :all     =\u003e targets\n  task :default =\u003e :all\n\n  targets.each do |target|\n    original_target = target == '_default' ? target[1..-1] : target\n    desc \"Run serverspec tests to #{original_target}\"\n    RSpec::Core::RakeTask.new(target.to_sym) do |t|\n      ENV['TARGET_HOST'] = original_target\n      t.rspec_opts = \"--format documentation --format html --out reports/report_#{$host}.html --format json --out reports/report_#{$host}.json\"\n      t.pattern = \"spec/#{original_target}/*_spec.rb\"\n    end\n  end\nend\n\n```\nwith a formatting option added:\n```ruby\nt.rspec_opts = \"--format documentation --format html --out reports/report_#{$host}.html --format json --out reports/report_#{$host}.json\"\n```\nThis would enforce verbose formatting of rspec result [logging](http://stackoverflow.com/questions/8785358/how-to-have-junitformatter-output-for-rspec-run-using-rake) and let rspec generate standard HTML and json rspec reports.\nOne can use to produce junit XML reports.\n\nThe `spec/local` directory can contain arbitrary number of domain-specific spec files, as explained above.\nThe `uru` module contains a basic serverspec file `uru_spec.rb` that serves as a smoke test of the `uru` environment:\n\nLinux:\n```ruby\nrequire 'spec_helper'\ncontext 'uru smoke test' do\n  context 'basic os' do\n    describe port(22) do\n      it { should be_listening.with('tcp')  }\n    end\n  end\n  context 'detect uru environment' do\n    uru_home = '/uru'\n    gem_version='2.1.0'\n    user_home = '/root'\n    describe command('echo $PATH') do\n      its(:stdout) { should match Regexp.new(\"_U1_:#{user_home}/.gem/ruby/#{gem_version}/bin:#{uru_home}/ruby/bin:_U2_:\") }\n    end\n  end\nend\n```\n\nWindows:\n```ruby\nrequire 'spec_helper'\ncontext 'basic tests' do\n  describe port(3389) do\n    it do\n     should be_listening.with('tcp')\n     should be_listening.with('udp')\n    end\n  end\n\n  describe file('c:/windows') do\n    it { should be_directory }\n  end\nend\ncontext 'detect uru environment through a custom PATH prefix' do\n  describe command(\u003c\u003c-EOF\n   pushd env:\n   dir 'PATH' | format-list\n   popd\n    EOF\n  ) do\n    its(:stdout) { should match Regexp.new('_U1_;c:\\\\\\\\uru\\\\\\\\ruby\\\\\\\\bin;_U2_;', Regexp::IGNORECASE) }\n  end\nend\n```\nbut any domain-specific serverspec files can be placed into the `spec/local` folder.\n\nThere should be no nested subdirectories in `spec/local`. If there are subdirectories, their contents will be silently ignored.\n\nFinally in `${URU_HOME}` there is a platform-specific  bootstrap script:\n\n`runner.ps1` for Windows:\n```powershell\n$URU_HOME = 'c:/uru'\n$GEM_VERSION = '2.1.0'\n$RAKE_VERSION = '10.1.0'\npushd $URU_HOME\nuru_rt.exe admin add ruby\\bin\n$env:URU_INVOKER = 'powershell'\n.\\uru_rt.exe ls --verbose\n$TAG = (invoke-expression -command 'uru_rt.exe ls') -replace '^\\s+\\b(\\w+)\\b.*$', '$1'\n.\\uru_rt.exe $TAG\n.\\uru_rt.exe ruby ruby\\lib\\ruby\\gems\\${GEM_VERSION}\\gems\\rake-${RAKE_VERSION}\\bin\\rake spec\n```\n\n`runner.sh` for Linux:\n```bash\n#!/bin/sh\nexport URU_HOME=/uru\nexport GEM_VERSION='2.1.0'\nexport RAKE_VERSION='10.1.0'\n\nexport URU_INVOKER=bash\npushd $URU_HOME\n./uru_rt admin add ruby/bin\n./uru_rt ls --verbose\nexport TAG=$(./uru_rt ls 2\u003e\u0026 1|awk -e '{print $1}')\n./uru_rt $TAG\n./uru_rt gem list\n./uru_rt ruby ruby/lib/ruby/gems/${GEM_VERSION}/gems/rake-${RAKE_VERSION}/bin/rake spec\n```\n\nThe results are nicely formatted in a standalone [HTML report](https://coderwall.com/p/gfmeuw/rspec-test-results-in-html):\n\n![resultt](https://raw.githubusercontent.com/sergueik/uru_serverspec/master/screenshots/result.png)\n\nand as json:\n```javascript\n{\n    \"version\": \"3.5.0.beta4\",\n    \"examples\": [{\n        \"description\": \"should be directory\",\n        \"full_description\": \"File \\\"c:/windows\\\" should be directory\",\n        \"status\": \"passed\",\n        \"file_path\": \"./spec/local/windows_spec.rb\",\n        \"line_number\": 4,\n        \"run_time\": 0.470411,\n        \"pending_message\": null\n    }, {\n        \"description\": \"should be file\",\n        \"full_description\": \"File \\\"c:/test\\\" should be file\",\n        \"status\": \"failed\",\n        \"file_path\": \"./spec/local/windows_spec.rb\",\n        \"line_number\": 8,\n        \"run_time\": 0.545683,\n        \"pending_message\": null,\n        \"exception\": {\n            \"class\": \"RSpec::Expectations::ExpectationNotMetError\",\n            ...\n        }\n    }],\n    \"summary\": {\n        \"duration\": 1.054691,\n        \"example_count\": 2,\n        \"failure_count\": 1,\n        \"pending_count\": 0\n    },\n    \"summary_line\": \"2 examples, 1 failure\"\n}\n```\n\nOne can easily extract the stats by spec file, descriptions of the failed tests and the overall `summary_line` from the json to stdout to get it captured in the console log useful for CI:\n```ruby\nreport_json = File.read('results/report_.json')\nreport_obj = JSON.parse(report_json)\n\nputs 'Failed tests':\nreport_obj['examples'].each do |example|\n  if example['status'] !~ /passed|pending/i\n    pp [example['status'],example['full_description']]\n  end\nend\n\nstats = {}\nresult_obj[:examples].each do |example|\n  file_path = example[:file_path]\n  unless stats.has_key?(file_path)\n    stats[file_path] = { :passed =\u003e 0, :failed =\u003e 0, :pending =\u003e 0 }\n  end\n  stats[file_path][example[:status].to_sym] = stats[file_path][example[:status].to_sym] + 1\nend\nputs 'Stats:'\nstats.each do |file_path,val|\n  puts file_path + ' ' + (val[:passed] / (val[:passed] + val[:pending] + val[:failed])).floor.to_s + ' %'\nend\n\nputs 'Summary:'\npp result_obj[:summary_line]\n```\n\nTo execute these one has to involve `uru_rt`.\nLinux:\n```bash\n./uru_rt admin add ruby/bin/ ; ./uru_rt ruby processor.rb --no-warnings --maxcount 100\n```\n\nWindows:\n```cmd\nC:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -executionpolicy remotesigned  ^\n-Command \"\u0026 {  \\$env:URU_INVOKER = 'powershell'; invoke-expression -command 'uru_rt.exe admin add ruby/bin/' ; invoke-expression -command 'uru_rt.exe ruby processor.rb --no-warnings --maxcount 100'}\"\n```\nAlternatively on Windows one can process the `result.json` in pure Powewrshell:\n```powershell\nparam(\n  [Parameter(Mandatory = $false)]\n  [string]$name = 'result.json',\n  [Parameter(Mandatory = $false)]\n  [string]$directory = 'results',\n  [Parameter(Mandatory = $false)]\n  [string]$serverspec = 'spec\\local',\n  [int]$maxcount = 100,\n  [switch]$warnings\n)\n\n$statuses = @('passed')\n\nif ( -not ([bool]$PSBoundParameters['warnings'].IsPresent )) {\n  $statuses += 'pending'\n}\n\n$statuses_regexp = '(?:' + ( $statuses -join '|' ) +')'\n\n$results_path = (\"${directory}/${name}\" -replace '/' , '\\');\nif (-not (Test-Path $results_path)) {\n  write-output ('Results is unavailable: \"{0}\"' -f $results_path )\n  exit 0\n}\nif ($host.Version.Major -gt 2) {\n  $results_obj = Get-Content -Path $results_path | ConvertFrom-Json ;\n  $count = 0\n  foreach ($example in $results_obj.'examples') {\n    if ( -not ( $example.'status' -match $statuses_regexp )) {\n      # get few non-blank lines of the description\n      # e.g. when the failed test is an inline command w/o a wrapping context\n      $full_description = $example.'full_description'\n      if ($full_description -match '\\n|\\\\n' ){\n        $short_Description = ( $full_description -split '\\n|\\\\n' | where-object { $_ -notlike '\\s*' } |select-object -first 2 ) -join ' '\n      } else {\n        $short_Description = $full_description\n      }\n      Write-Output (\"Test : {0}`r`nStatus: {1}\" -f $short_Description,($example.'status'))\n      $count++;\n      if (($maxcount -ne 0) -and ($maxcount -lt $count)) {\n        break\n      }\n    }\n  }\n  # compute stats -\n  # NOTE: there is no outer context information in the `result.json`\n  $stats = @{}\n  $props =  @{\n    Passed = 0\n    Failed = 0\n    Pending = 0\n  }\n  foreach ($example in $results_obj.'examples') {\n    $spec_path = $example.'file_path'\n    if (-not $stats.ContainsKey($spec_path)) {\n      $stats.Add($spec_path, (New-Object -TypeName PSObject -Property $props ))\n    }\n    # Unable to index into an object of type System.Management.Automation.PSObject\n    $stats[$spec_path].$($example.'status') ++\n\n  }\n\n  write-output 'Stats:'\n  $stats.Keys | ForEach-Object {\n    $spec_path = $_\n    # extract outermost context from spec:\n    $context_line = select-string -pattern @\"\ncontext ['\"].+['\"] do\n\"@ -path $spec_path | select-object -first 1\n    $context = $context_line -replace @\"\n^.+context\\s+['\"]([^\"']+)['\"]\\s+do\\s*$\n\"@, '$1'\n    # NOTE: single quotes needed in the replacement\n    $number_examples = $stats[$spec_path]\n    # not counting pending examples\n    # $total_number_examples = $number_examples.Passed + $number_examples.Pending + $number_examples.Failed\n    $total_number_examples = $number_examples.Passed + $number_examples.Failed\n    Write-Output (\"{0}`t{1}%`t{2}\" -f ( $spec_path -replace '^.+[\\\\/]','' ),([math]::round(100.00 * $number_examples.Passed / $total_number_examples,2)), $context)\n  }\n  write-output 'Summary:'\n  Write-Output ($results_obj.'summary_line')\n} else {\n  Write-Output (((Get-Content -Path $results_path) -replace '.+\\\"summary_line\\\"' , 'serverspec result: ' ) -replace '}', '' )\n}\n```\n\nFor convenience the `processor.ps1` and `processor.rb`, and `processor.sh` are provided. Finding and converting to a better structured HTML report layout with the help of additional gems is a work in progress.\n\nThe Puppet module is available in a sibling directory:\n * [exec_uru.pp](https://github.com/sergueik/puppetmaster_vagrant/blob/master/modules/custom_command/manifests/exec_uru.pp)\n * [uru_runner_ps1.erb](https://github.com/sergueik/puppetmaster_vagrant/blob/master/modules/custom_command/templates/uru_runner_ps1.erb)\n\n### Specifying filename of the serverspec Report\n\nAs default, the report file names results are saved are `results_.json` and `results.html`. The argument allows overriding this:\nOn Linux:\n```sh\n./runner.sh myresult.json\n```\n```\nResults in results/myresult.json\n```\nthen\n```sh\n./processor.sh myresult.json\n```\n```sh\nNo failed tests.\nSummary: \"3 examples, 0 failures\"\n```\nor\n```sh\n./uru_rt ruby processor.rb --results_filename myresult.json\nReading: results/myresult.json\n\"3 examples, 0 failures\"\n```\nOn Windows:\n```cmd\n. .\\runner.ps1 myresult.json\n```\n```cmd\nDEBUG: results in results/myresult.json\n```\nand\n```cmd\n. .\\processor.ps1 -results_filename myresult.json\n```\nor, alternatively\n```cmd\n .\\uru_rt.exe ruby .\\processor.rb --results_filename myresult.json\n```\n#### Specifying user-sensitive tests\nThe most natural use case ofspecfying the file name of the serverpsec report is \nwhen there are user sensitive validations.\nThe fragment below demonstrates this:\n```ruby\nrequire 'spec_helper'\n\ncontext 'user sensitive' do\n  root_home = '/root'\n  # condition at the 'describe' level\n  context 'home directory' do\n    describe command('echo $HOME'), :if =\u003e ENV.fetch('USER').eql?('root') do\n      its(:stdout) { should match Regexp.new(root_home) }\n    end\n    describe command('echo $HOME'), :unless =\u003e ENV.fetch('USER').eql?('root') do\n      its(:stdout) { should_not match Regexp.new(root_home) }\n    end\n  end\n  # condition at the 'context' level\n  context 'home directory', :if =\u003e ENV.fetch('USER').eql?('root') do\n    describe command('echo $HOME') do\n      its(:stdout) { should match Regexp.new(root_home) }\n    end\n  end\n  context 'home directory', :unless =\u003e ENV.fetch('USER').eql?('root') do\n    describe command('echo $HOME') do\n      its(:stdout) { should_not match Regexp.new(root_home) }\n    end\n  end\n  # include branch condition in the 'title' property\n  context \"home directory of #{ENV.fetch('USER')}\" do\n    describe command('echo $HOME') do\n      its(:stdout) { should_not be_empty }\n    end\n  end\nend\n```\nthe equivalent code for Windows is awork in progress.\n### Migration\nTo migrate serverspec from a the [vagrant-serverspec](https://github.com/jvoorhis/vagrant-serverspec) default directory, one may use\n`require_relative`. Also pay attention to use a conditional\n```ruby\nif File.exists?( 'spec/windows_spec_helper.rb')\n  require_relative '../windows_spec_helper'\nend\n```\nin the serverspec in the Ruby sandbox if the same rspec test is about to be run from Vagrant and from the instance\n\n### Useful modifiers\n\n#### To detect Vagrant run :\n```ruby\nuser_home = ENV.has_key?('VAGRANT_EXECUTABLE') ? 'c:/users/vagrant' : ( 'c:/users/' + ENV['USER'] )\n```\nThis will assign a hard coded user name versus target instance environment value to Ruby variable.\nNote:  `ENV['HOME']` was not used - it is defined in both cygwin (`C:\\cygwin\\home\\vagrant`)\nand Windows environments (`C:\\users\\vagrant`)\n\n#### To detect__uru__runtime:\n```ruby\ncontext 'URU_INVOKER environment variable', :if =\u003e ENV.has_key?('URU_INVOKER')  do\n  describe command(\u003c\u003c-EOF\n   pushd env:\n   dir 'URU_INVOKER' | format-list\n   popd\n    EOF\n  ) do\n    its(:stdout) { should match /powershell|bash/i }\n  end\nend\n```\n\nAs usual, one can provide custom types in the spec/type directory - that directory is excluded from the spec run.\nFor example one can define the following class `property_file.rb` to inspect property files:\n```ruby\nrequire 'serverspec'\nrequire 'serverspec/type/base'\nmodule Serverspec::Type\n  class PropertyFile \u003c Base\n\n    def initialize(name)\n      @name = name\n      @runner = Specinfra::Runner\n    end\n\n    def has_property?(propertyName, propertyValue)\n      properties = {}\n      IO.foreach(@name) do |line|\n        if (!line.start_with?('#'))\n          properties[$1.strip] = $2 if line =~ /^([^=]*)=(?: *)(.*)/\n        end\n      end\n      properties[propertyName] == propertyValue\n    end\n  end\n\n  def property_file(name)\n    PropertyFile.new(name)\n  end\nend\n\ninclude Serverspec::Type\n```\nand create the test\n```ruby\nrequire 'type/property_file'\ncontext 'Custom Type' do\n  property_file_path = \"#{user_home}/sample.properties\"\n  describe property_file(property_file_path) do\n    it { should have_property('package.class.property', 'value' ) }\n  end\nend\n```\n\n### Parameters\n\nTo pass parameters to the serverspec use [hieradata](https://docs.puppet.com/hiera/3.2/puppet.html)\n```yaml\n---\nuru::parameters:\n  dummy1:\n    key: 'key1'\n    value: 'value1'\n    comment: 'comment'\n  dummy2:\n    key: 'key2'\n    value:\n    - 'value2'\n    - 'value3'\n    - 'value4'\n  dummy3:\n    key: 'key3/key4'\n    value: 'value5'\n```\nThe processing of the hieradata is implemented in the standard way:\n\n```ruby\n  $default_attributes = {\n    target  =\u003e \"${toolspath}/spec/config/parameters.yaml\",\n    require =\u003e File[\"${toolspath}/spec/multiple\"],\n  }\n\n  $parameters = hiera_hash('uru::parameters')\n  $parameters.each |$key, $values| {\n    create_resources('yaml_setting',\n      {\n        $key =\u003e delete($values, ['comment'])\n      },\n      $default_attributes\n    )\n  }\n\n```\nThis will produce the file `/uru/spec/config/parameters.yaml` on the instance with the following contents:\n```yaml\n---\nkey1: 'value1'\nkey2:\n- 'value2'\n- 'value3'\n- 'value4'\nkey3:\n  key4: 'value5'\n```\nThe unique `dummy*` keys from `hieradata/common.yaml` disappear - they exist for Puppet `create_resources` needs only.\nThe optional `comment` key is ignored. Note usage of [yamlfile](https://github.com/reidmv/puppet-module-yamlfile) Puppet module syntax for nested keys.\n\nThe following fragment demonstrates the use `spec/config/parameters.yaml` in serverspec:\n\n```ruby\nif ENV.has_key?('URU_INVOKER')\n  parameters = YAML.load_file(File.join(__dir__, '../config/parameters.yaml'))\n  value1 = parameters['key1']\nend\n```\nNote: the Rspec metadata-derived [serverspec syntax](http://serverspec.org/advanced_tips.html)\n\n```ruby\ncontext 'Uru-specific context', :if =\u003e ENV.has_key?('URU_INVOKER') do\n  # uru-specific code\nend\n```\ndoes not block `YAML.load_file` execution outside of uru-specific context and not to be used for this case -\na plain Ruby conditon will do.\n\n### Compiling from the source\n\nTo compile uru package\ndownload ruby source from https://www.ruby-lang.org/en/downloads/, build and install Ruby into `/uru/ruby`:\n```shell\npushd /uru/ruby-2.3.6\n./configure --disable-install-capi --disable-install-rdoc --disable-install-doc --without-tk  --prefix=/uru/ruby\n```\n```shell\nmake; make install\n```\nthen register with __uru__ package\n```shell\n./uru_rt admin add /uru/ruby/bin\n---\u003e Registered ruby at `/uru/ruby/bin` as `236p384`\n```\nand update the `runner.sh`\n\ne.g. for Ruby __2.3.6__ add\n\n```shell\nGEM_VERSION='2.3.0'\nRAKE_VERSION='10.4.2'\nRUBY_VERSION='2.3.6'\nRUBY_VERSION_LONG='2.3.6p384'\nRUBY_TAG_LABEL='236p384'\n```\n\nand install the gems:\n```shell\n ./uru_rt gem install --no-rdoc --no-ri specinfra serverspec rake rspec rspec_junit_formatter json nokogiri\n```\nFinally package the directory, and verify it works on a vanila node:\n\n```shell\ncd /\ntar czvf ~sergueik/Downloads/uru_ruby_236.tar.gz /uru\nrm -rv -f uru/\nwhich ruby\ntar xzvf ~sergueik/Downloads/uru_ruby_236.tar.gz\npushd /uru/\n./runner.sh\n# will report test passed\n```\n\n### Note\nThe RSpec `format` [options](https://relishapp.com/rspec/rspec-core/docs/command-line/format-option) provided in the `Rakefile`\n```ruby\nrspec_opts = \"--require spec_helper --format documentation --format html --out results/result_#{$host}.html --format json --out results/result_#{$host}.json\"\n```\nare not compatible with [Vagrant serverspc plugin](https://github.com/jvoorhis/vagrant-serverspec), leading to the following error:\n```ruby\nThe\nserverspec provisioner:\n* The following settings shouldn't exist: rspec_opts\n```\n### Inspec\n\nIt is possible to install the `inspec.gem` for [Chef Inspec](https://github.com/chef/inspec)\nin the __uru__ environment and repackage and use in the similar fashion, use case as with serverspec. Note for `mixlib-shellout` you will need to use Ruby __2.2.x__\nTo build dependency gems one will need to execute\n```sh\nsudo apt-get install build-essential\n```\n\nor\n```sh\nsudo yum install make automake gcc gcc-c++ kernel-devel\n```\nNote: serverspec and inspec appear to use very similar `Rakefile` and auxiliary Ruby files. Switch from one to the other was not fully tested yet.\n\nyou can run `inspec-bin` as a Ruby script in a similar manner to running rake using ruby with the specific path to the gem's executable.\n\nTo run inspec-bin directly as a Ruby script, you would follow this structure:\n\n```\nruby ${RubyPath}/lib/ruby/gems/${GEM_VERSION}/gems/inspec-bin-${INSPEC_BIN_VERSION}/bin/inspec\n```\n\n\n\n###  Puppet Beaker Integration testing tool\n\nRecently, Puppet switched to use Beaker to wrap Vagrant(Docker) and Serverspec to provision the instance(s),\niterate across supported target platforms\noften performing mutiple consecutive puppet agent runs, and inspect the catalogs compilation and catalogs themselves\nusing [core Beaker DSL](https://www.rubydoc.info/gems/beaker/2.4.1/Beaker/DSL/Helpers)\nand various extentions to produce tests\nwhich are\n* geared to deal more with catalog than with the system\n* good for module developers by exploring methods like  `apply_manifests` `get_last_applied_resources`\nand apparently somewhat heavily Rails metaprogramming-style expectations like:\n\n```ruby\nrequire 'spec_helper_acceptance'\nit 'should run without any errors' do\n  base_pp = \u003c\u003c-EOF\n    include stdlib\n  EOF\n  {\n    1 =\u003e 2,\n    2 =\u003e 0,\n  }.eacho do |run, status|\n    apply_manifest(base_pp,\n    :modulepath =\u003e '/etc/puppetlabs/code/modules',\n    :debug      =\u003e true,\n    :catch_failures =\u003e true).exit_code).to eq status\n  end\nend\n```\n* sampling valid, generic but really vague expectation, that conveys nothing about the error\nit might find and producing result that would only be legible to the developer of the module in question\n* somewhat formal and focused entirely on the Puppet catalog, prone of overlooking creation of damaged target systems\n\n### Non-root account\n\nThe initial version of __uru\\_serverspec__ module the Ruby has been compiled and packaged by the root account. To switch __uru\\_serverspec__ module to operate under a non-root user the simpest way is to\n\n* Copy the `.gem` folder into the target user home directory:\n```sh\nURU_USER='uru_user'\nadduser $URU_USER\ncp -R /root/.gem/ ~$URU_USER/\n```\n* Adjust files and directories ownership:\n```sh\nchown -R $URU_USER:$URU_USER ~$URU_USER/.gem/\nchown -R $URU_USER:$URU_USER $URU_HOME\n```\nNow the spec can be run by `$URU_USER`.\n\n### Alternatives and comparison\n\nThe well-known technology that existed already by the time the __uru\\_serverspec__ module was designed\nis [vagrant-serverspec](https://github.com/vvchik/vagrant-serverspec) Vagrant plugin.\n\nThe __vagrant-serverspec__ Vagrant plugin is at the low level simply a ruby package\nbehaving and designed like a regular Ruby gem,\nbut housed under Vagrant application directory and installed / removed via designed `vagrant plugin` command.\n\nThe execution of the server spec is integrated in Vagrant workflow to take place after the provision:\n```ruby\nconfig.vm.provision :serverspec do |spec|\n  spec.pattern = '*_spec.rb'\n  # configuration details omitted\nend\n```\nThis automates running serverspec from the Ruby runtime installed on the host machine remotely into the node.\nThis only possible if the remoting (ssh or winrm) is still enabled after the node provision. To rerun a fixed spec one has to switch to command line and run\n```sh\nrake spec\n```\ndirectly, which is not much different then running the uru launcher shell script.\nAlso, the __vagrant-serverspec__ Vagrant plugin does not run tests after every failing provision, though this may be configurable matter.\nThe second  important difference is the spec files exercised through __uru\\_serverspec__ module  can be easier generated by the configuration management framework responsible for the node provision, usign the same inputs, therefore validation of the criteria like catalina jar/war artifact checksums can be integrated.\nThe same effect may be achieved via retrofitting the vagrant-serverspec directory structure and making the outside-of module serverspec directory spec file `some_spec.rb`\neffectively a loader of the inside of module `real_spec.rb` :\n\n```ruby\nrequire_relative '../../files/serverspec/rhel/real_spec'\n```\nA similar approach is often taken when refactoring similar tests into a smaller number of redundant files.\nFinally, it turns out quite often, the target node is the best way to develop the spec in question, especially when it aevaluates some application stack specific detail that only exists in its final form on the node, inside the application.\nThis is especially true with configuration management tools that are prone\nto segregate the templates and variables (like [Puppet](https://puppet.com) or [Chef](https://en.wikipedia.org/wiki/Chef_(software))).\n\n### See Also\n\n * [\"Ruby Version Manager\" chapter of \"Ruby on Windows Guides\" book by Boško Ivanišević](http://rubyonwindowsguides.github.io/book/ch02-03.html)\n * the original __uru__ project on [bitbucket](https://bitbucket.org/jonforums/uru)\n * [mirror](https://github.com/preetpalS/uru)\n * [skeleton Vagrantfile that installs and runs ruby, gem, serverspec after provision](https://github.com/andrewwardrobe/PuppetIntegration)\n * [skeleton Vagrantfile for puppet provision](https://github.com/wstinkens/example_puppet-serverspec/)\n * [sensu-plugins-serverspec](https://github.com/sensu-plugins/sensu-plugins-serverspec)\n * [automating serversped](http://annaken.blogspot.com/2015/07/automated-serverspec-logstash-kibana-part2.html)\n * [danger-junit Junit XML to HTML convertor](https://github.com/orta/danger-junit)\n * [loading spec](http://stackoverflow.com/questions/5061179/how-to-load-a-spec-helper-rb-automatically-in-rspec-2)\n * [enable checkboxes in the html-formatted report generated by rspec-core](https://github.com/rspec/rspec-core) and [rspec_junit_formatter](https://github.com/sj26/rspec_junit_formatter) rendered in Interner Explorer, make sure to confirm ActiveX popup. If this does not work, one may have to apply a patch explained in [how  IE generates the onchange event](http://krijnhoetmer.nl/stuff/javascript/checkbox-onchange/) and run the `apply_filters()`  on `onclick`  instead of `onchange`.\n * [filtering RSpec log](https://www.relishapp.com/rspec/rspec-core/docs/configuration/excluding-lines-from-the-backtrace)\n * [specialist](https://github.com/ustream/Specialist)\n * [vincentbernat/serverspec-example](https://github.com/vincentbernat/serverspec-example)\n * [puppet/yamlfile](https://github.com/reidmv/puppet-module-yamlfile)\n * [cucumber-reporting](https://github.com/damianszczepanik/cucumber-reporting)\n * [cucumber-html](https://github.com/cucumber/cucumber-html)\n * [cucumberjs-junitxml](https://github.com/sonyschan/cucumberjs-junitxml)\n * [cucumber-reports](https://github.com/mkolisnyk/cuc umber-reports)\n * [serverspec to inspec conversion example](https://github.com/bonusbits/example_serverspec_to_inspec)\n * [vagrant execute](https://github.com/rgl/vagrant-execute)\n * [winrm CLI](https://github.com/masterzen/winrm-cli)\n * [notes on using uru on Windows](http://www.neverletdown.net/2015/08/managing-multiple-ruby-versions-with-uru.html)\n * __DSC Environment Analyzer__ [overview](https://microsoft.github.io/DSCEA/), another [introduction](https://blogs.technet.microsoft.com/ralphkyttle/2017/03/21/introducing-dscea/) and [source code](https://github.com/Microsoft/DSCEA)\n * [uzyexe/serverspec Docker build env](https://github.com/uzyexe/dockerfile-serverspec)\n * [vagrant-serverspec](https://github.com/vvchik/vagrant-serverspec) Vagrant plugin\n\nNOTE: the operations does not (and actually cannot) directly follow a \"Patch README document\" which typically reads like below:\n\n - Shutdown the server if you have already\n - Copy patch files into their destinations (like `$APP_HOME/repository/components/patches`\n - Inject specific entries so configurations\n - Modify command line options to launchers\n - Do specific changes to systemd unit files\n - Restart the service with a provided command\n\nThis does not directly translate into the Puppet (Chef, Ansible, Powershell DSC, name your provision schema) workflow for many reasons\n  - vendor specific API / DSL for connecting resourcesand for code / parameter segregation (members of your team are all Puppet certified, aren't they)\n  - In-house best practices for structuring the configurations hierarchically\n  - If the __Patch101__ *was already puppetized*, the __Patch102__ will most likely be a a copy paste of __Patch101__\n\n### Author\n[Serguei Kouzmine](kouzmine_serguei@yahoo.com)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergueik%2Furu_serverspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsergueik%2Furu_serverspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsergueik%2Furu_serverspec/lists"}