From 9cd69ce4af65cf2f0f1bd720e2a6e1af2d838c9d Mon Sep 17 00:00:00 2001 From: Nolan Davidson Date: Mon, 1 May 2017 14:02:15 -0400 Subject: [PATCH 1/5] Add an oracle_session resource This adds an oracle_session resource similar to the existing resource for MySQL and MSSQL. It assumes the sqlplus tool is installed and in the path of the user InSpec connects as. Signed-off-by: Nolan Davidson --- docs/resources/oracle_session.md.erb | 63 ++++++++++++++++++++++++++++ lib/inspec/resource.rb | 1 + lib/resources/oracle_session.rb | 39 +++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 docs/resources/oracle_session.md.erb create mode 100644 lib/resources/oracle_session.rb diff --git a/docs/resources/oracle_session.md.erb b/docs/resources/oracle_session.md.erb new file mode 100644 index 000000000..649171b97 --- /dev/null +++ b/docs/resources/oracle_session.md.erb @@ -0,0 +1,63 @@ +--- +title: About the oracle_session Resource +--- + +# oracle_session + +Use the `oracle_session` InSpec audit resource to test SQL commands run against a Oracle database. + +## Syntax + +A `oracle_session` resource block declares the username and password to use for the session with an optional service to connect to, and then the command to be run: + + describe oracle_session('username', 'password').query('QUERY') do + its('output') { should eq('') } + end + +where + +* `oracle_session` declares a username and password with permission to run the query, and an optional service name. If none is specifed, it will use the default service on the instance. +* `query('QUERY')` contains the query to be run +* `its('output') { should eq('') }` compares the results of the query against the expected result in the test + +## Matchers + +This InSpec audit resource has the following matchers: + +### be + +<%= partial "/shared/matcher_be" %> + +### cmp + +<%= partial "/shared/matcher_cmp" %> + +### eq + +<%= partial "/shared/matcher_eq" %> + +### include + +<%= partial "/shared/matcher_include" %> + +### match + +<%= partial "/shared/matcher_match" %> + +### output + +The `output` matcher tests the results of the query: + + its('output') { should eq(/^0/) } + +## Examples + +The following examples show how to use this InSpec audit resource. + +### Test for matching databases + + sql = oracle_session('my_user','password') + + describe sql.query('SELECT NAME FROM v$database;') do + its('stdout') { should_not match(/test/) } + end diff --git a/lib/inspec/resource.rb b/lib/inspec/resource.rb index 7dd16f54a..aea96eda3 100644 --- a/lib/inspec/resource.rb +++ b/lib/inspec/resource.rb @@ -114,6 +114,7 @@ require 'resources/mysql_session' require 'resources/npm' require 'resources/ntp_conf' require 'resources/oneget' +require 'resources/oracle_session' require 'resources/os' require 'resources/os_env' require 'resources/package' diff --git a/lib/resources/oracle_session.rb b/lib/resources/oracle_session.rb new file mode 100644 index 000000000..48180e37e --- /dev/null +++ b/lib/resources/oracle_session.rb @@ -0,0 +1,39 @@ +# encoding: utf-8 +# author: Nolan Davidson +# license: All rights reserved + +module Inspec::Resources + class OracleSession < Inspec.resource(1) + name 'oracle_session' + desc 'Use the oracle_session InSpec resource to test commands against an Oracle database' + example " + sql = oracle_session('my_user','password') + describe sql.query('SELECT NAME FROM v$database;') do + its('stdout') { should_not match(/test/) } + end + " + + def initialize(user = nil, pass = nil, service = nil) + @user = user + @pass = pass + @service = service + return skip_resource("Can't run Oracle checks without authentication") if user.nil? or pass.nil? + end + + def query(q) + escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$') + + cmd = inspec.command("echo \"#{q}\" | sqlplus -s #{@user}/#{@pass}@localhost/#{@service}") + out = cmd.stdout + "\n" + cmd.stderr + if out.downcase =~ /^error/ + skip_resource("Can't connect to Oracle instance for SQL checks.") + end + + cmd + end + + def to_s + 'Oracle Session' + end + end +end \ No newline at end of file From 57731e1e50f1a46eb906f438daf5b7362fab7541 Mon Sep 17 00:00:00 2001 From: Nolan Davidson Date: Tue, 2 May 2017 11:03:45 -0400 Subject: [PATCH 2/5] Changing oracle_session back to using escaped query. Signed-off-by: Nolan Davidson --- lib/resources/oracle_session.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/resources/oracle_session.rb b/lib/resources/oracle_session.rb index 48180e37e..fd8363b43 100644 --- a/lib/resources/oracle_session.rb +++ b/lib/resources/oracle_session.rb @@ -23,7 +23,7 @@ module Inspec::Resources def query(q) escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$') - cmd = inspec.command("echo \"#{q}\" | sqlplus -s #{@user}/#{@pass}@localhost/#{@service}") + cmd = inspec.command("echo \"#{escaped_query}\" | sqlplus -s #{@user}/#{@pass}@localhost/#{@service}") out = cmd.stdout + "\n" + cmd.stderr if out.downcase =~ /^error/ skip_resource("Can't connect to Oracle instance for SQL checks.") @@ -36,4 +36,4 @@ module Inspec::Resources 'Oracle Session' end end -end \ No newline at end of file +end From fbe7b8ddf838a9cfc66cfb31ba625737f5aaa5de Mon Sep 17 00:00:00 2001 From: Nolan Davidson Date: Fri, 5 May 2017 09:29:38 -0400 Subject: [PATCH 3/5] Refactor to options hash and add unit tests Switched the oracle_session resource to take an option hash and allow for configuring hostname, DB_SID, and sqlplus binary path. Added unit tests. Signed-off-by: Nolan Davidson --- docs/resources/oracle_session.md.erb | 14 +++++++++++--- lib/resources/oracle_session.rb | 21 ++++++++++++--------- test/unit/resources/oracle_session_test.rb | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 test/unit/resources/oracle_session_test.rb diff --git a/docs/resources/oracle_session.md.erb b/docs/resources/oracle_session.md.erb index 649171b97..89d4e848c 100644 --- a/docs/resources/oracle_session.md.erb +++ b/docs/resources/oracle_session.md.erb @@ -10,13 +10,13 @@ Use the `oracle_session` InSpec audit resource to test SQL commands run against A `oracle_session` resource block declares the username and password to use for the session with an optional service to connect to, and then the command to be run: - describe oracle_session('username', 'password').query('QUERY') do + describe oracle_session(user: 'username', pass: 'password').query('QUERY') do its('output') { should eq('') } end where -* `oracle_session` declares a username and password with permission to run the query, and an optional service name. If none is specifed, it will use the default service on the instance. +* `oracle_session` declares a username and password with permission to run the query (required), and an optional parameters for host (default: `localhost`), SID (default: `nil`, which uses the default SID, and path to the sqlplus binary (default: `sqlplus`). * `query('QUERY')` contains the query to be run * `its('output') { should eq('') }` compares the results of the query against the expected result in the test @@ -56,7 +56,15 @@ The following examples show how to use this InSpec audit resource. ### Test for matching databases - sql = oracle_session('my_user','password') + sql = oracle_session(user: 'my_user', pass: 'password') + + describe sql.query('SELECT NAME FROM v$database;') do + its('stdout') { should_not match(/test/) } + end + +### Test for matching databases with custom host, SID and sqlplus binary location + + sql = oracle_session(user: 'my_user', pass: 'password', host: 'oraclehost', sid: 'mysid', sqlplus_bin: '/u01/app/oracle/product/12.1.0/dbhome_1/bin/sqlplus') describe sql.query('SELECT NAME FROM v$database;') do its('stdout') { should_not match(/test/) } diff --git a/lib/resources/oracle_session.rb b/lib/resources/oracle_session.rb index fd8363b43..58d5db3fb 100644 --- a/lib/resources/oracle_session.rb +++ b/lib/resources/oracle_session.rb @@ -7,23 +7,26 @@ module Inspec::Resources name 'oracle_session' desc 'Use the oracle_session InSpec resource to test commands against an Oracle database' example " - sql = oracle_session('my_user','password') + sql = oracle_session(user: 'my_user', pass: 'password') describe sql.query('SELECT NAME FROM v$database;') do its('stdout') { should_not match(/test/) } end " - def initialize(user = nil, pass = nil, service = nil) - @user = user - @pass = pass - @service = service - return skip_resource("Can't run Oracle checks without authentication") if user.nil? or pass.nil? + attr_reader :user, :pass, :host, :sid, :sqlplus_bin + + def initialize(opts = {}) + @user = opts[:user] + @pass = opts[:pass] + @host = opts[:host] || "localhost" + @sid = opts[:sid] + @sqlplus_bin = opts[:sqlplus_bin] || "sqlplus" + return skip_resource("Can't run Oracle checks without authentication") if @user.nil? or @pass.nil? end def query(q) - escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$') - - cmd = inspec.command("echo \"#{escaped_query}\" | sqlplus -s #{@user}/#{@pass}@localhost/#{@service}") + escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"') + cmd = inspec.command("echo \"#{escaped_query}\" | #{@sqlplus_bin} -s #{@user}/#{@pass}@#{@host}/#{@sid}") out = cmd.stdout + "\n" + cmd.stderr if out.downcase =~ /^error/ skip_resource("Can't connect to Oracle instance for SQL checks.") diff --git a/test/unit/resources/oracle_session_test.rb b/test/unit/resources/oracle_session_test.rb new file mode 100644 index 000000000..440f800fa --- /dev/null +++ b/test/unit/resources/oracle_session_test.rb @@ -0,0 +1,15 @@ +# encoding: utf-8 +# author: Nolan Davidson + +require 'helper' + +describe 'Inspec::Resources::OracleSession' do + it 'verify oracle_session configuration' do + resource = load_resource('oracle_session', user: 'myuser', pass: 'mypass', host: 'oraclehost', sid: 'mysid') + _(resource.user).must_equal 'myuser' + _(resource.pass).must_equal 'mypass' + _(resource.host).must_equal 'oraclehost' + _(resource.sid).must_equal 'mysid' + _(resource.sqlplus_bin).must_equal 'sqlplus' + end +end From 55beed4bc826247fa628121b5217b540611aa6d3 Mon Sep 17 00:00:00 2001 From: Nolan Davidson Date: Fri, 5 May 2017 10:11:53 -0400 Subject: [PATCH 4/5] Resolving rubucop issues Signed-off-by: Nolan Davidson --- lib/resources/oracle_session.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/resources/oracle_session.rb b/lib/resources/oracle_session.rb index 58d5db3fb..e1ea5ecfd 100644 --- a/lib/resources/oracle_session.rb +++ b/lib/resources/oracle_session.rb @@ -18,9 +18,9 @@ module Inspec::Resources def initialize(opts = {}) @user = opts[:user] @pass = opts[:pass] - @host = opts[:host] || "localhost" + @host = opts[:host] || 'localhost' @sid = opts[:sid] - @sqlplus_bin = opts[:sqlplus_bin] || "sqlplus" + @sqlplus_bin = opts[:sqlplus_bin] || 'sqlplus' return skip_resource("Can't run Oracle checks without authentication") if @user.nil? or @pass.nil? end From ba6745444eb25ce9352b005ae067b97f0adca80f Mon Sep 17 00:00:00 2001 From: Nolan Davidson Date: Fri, 5 May 2017 13:11:07 -0400 Subject: [PATCH 5/5] Renaming oracle_session to oracledb_session Signed-off-by: Nolan Davidson --- ...le_session.md.erb => oracledb_session.md.erb} | 16 ++++++++-------- lib/inspec/resource.rb | 2 +- .../{oracle_session.rb => oracledb_session.rb} | 8 ++++---- ..._session_test.rb => oracledb_session_test.rb} | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) rename docs/resources/{oracle_session.md.erb => oracledb_session.md.erb} (54%) rename lib/resources/{oracle_session.rb => oracledb_session.rb} (81%) rename test/unit/resources/{oracle_session_test.rb => oracledb_session_test.rb} (57%) diff --git a/docs/resources/oracle_session.md.erb b/docs/resources/oracledb_session.md.erb similarity index 54% rename from docs/resources/oracle_session.md.erb rename to docs/resources/oracledb_session.md.erb index 89d4e848c..878218ed7 100644 --- a/docs/resources/oracle_session.md.erb +++ b/docs/resources/oracledb_session.md.erb @@ -1,22 +1,22 @@ --- -title: About the oracle_session Resource +title: About the oracledb_session Resource --- -# oracle_session +# oracledb_session -Use the `oracle_session` InSpec audit resource to test SQL commands run against a Oracle database. +Use the `oracledb_session` InSpec audit resource to test SQL commands run against a Oracle database. ## Syntax -A `oracle_session` resource block declares the username and password to use for the session with an optional service to connect to, and then the command to be run: +A `oracledb_session` resource block declares the username and password to use for the session with an optional service to connect to, and then the command to be run: - describe oracle_session(user: 'username', pass: 'password').query('QUERY') do + describe oracledb_session(user: 'username', pass: 'password').query('QUERY') do its('output') { should eq('') } end where -* `oracle_session` declares a username and password with permission to run the query (required), and an optional parameters for host (default: `localhost`), SID (default: `nil`, which uses the default SID, and path to the sqlplus binary (default: `sqlplus`). +* `oracledb_session` declares a username and password with permission to run the query (required), and an optional parameters for host (default: `localhost`), SID (default: `nil`, which uses the default SID, and path to the sqlplus binary (default: `sqlplus`). * `query('QUERY')` contains the query to be run * `its('output') { should eq('') }` compares the results of the query against the expected result in the test @@ -56,7 +56,7 @@ The following examples show how to use this InSpec audit resource. ### Test for matching databases - sql = oracle_session(user: 'my_user', pass: 'password') + sql = oracledb_session(user: 'my_user', pass: 'password') describe sql.query('SELECT NAME FROM v$database;') do its('stdout') { should_not match(/test/) } @@ -64,7 +64,7 @@ The following examples show how to use this InSpec audit resource. ### Test for matching databases with custom host, SID and sqlplus binary location - sql = oracle_session(user: 'my_user', pass: 'password', host: 'oraclehost', sid: 'mysid', sqlplus_bin: '/u01/app/oracle/product/12.1.0/dbhome_1/bin/sqlplus') + sql = oracledb_session(user: 'my_user', pass: 'password', host: 'oraclehost', sid: 'mysid', sqlplus_bin: '/u01/app/oracle/product/12.1.0/dbhome_1/bin/sqlplus') describe sql.query('SELECT NAME FROM v$database;') do its('stdout') { should_not match(/test/) } diff --git a/lib/inspec/resource.rb b/lib/inspec/resource.rb index aea96eda3..71da56fef 100644 --- a/lib/inspec/resource.rb +++ b/lib/inspec/resource.rb @@ -114,7 +114,7 @@ require 'resources/mysql_session' require 'resources/npm' require 'resources/ntp_conf' require 'resources/oneget' -require 'resources/oracle_session' +require 'resources/oracledb_session' require 'resources/os' require 'resources/os_env' require 'resources/package' diff --git a/lib/resources/oracle_session.rb b/lib/resources/oracledb_session.rb similarity index 81% rename from lib/resources/oracle_session.rb rename to lib/resources/oracledb_session.rb index e1ea5ecfd..52ae0c099 100644 --- a/lib/resources/oracle_session.rb +++ b/lib/resources/oracledb_session.rb @@ -3,11 +3,11 @@ # license: All rights reserved module Inspec::Resources - class OracleSession < Inspec.resource(1) - name 'oracle_session' - desc 'Use the oracle_session InSpec resource to test commands against an Oracle database' + class OracledbSession < Inspec.resource(1) + name 'oracledb_session' + desc 'Use the oracledb_session InSpec resource to test commands against an Oracle database' example " - sql = oracle_session(user: 'my_user', pass: 'password') + sql = oracledb_session(user: 'my_user', pass: 'password') describe sql.query('SELECT NAME FROM v$database;') do its('stdout') { should_not match(/test/) } end diff --git a/test/unit/resources/oracle_session_test.rb b/test/unit/resources/oracledb_session_test.rb similarity index 57% rename from test/unit/resources/oracle_session_test.rb rename to test/unit/resources/oracledb_session_test.rb index 440f800fa..78c6317a0 100644 --- a/test/unit/resources/oracle_session_test.rb +++ b/test/unit/resources/oracledb_session_test.rb @@ -3,9 +3,9 @@ require 'helper' -describe 'Inspec::Resources::OracleSession' do - it 'verify oracle_session configuration' do - resource = load_resource('oracle_session', user: 'myuser', pass: 'mypass', host: 'oraclehost', sid: 'mysid') +describe 'Inspec::Resources::OracledbSession' do + it 'verify oracledb_session configuration' do + resource = load_resource('oracledb_session', user: 'myuser', pass: 'mypass', host: 'oraclehost', sid: 'mysid') _(resource.user).must_equal 'myuser' _(resource.pass).must_equal 'mypass' _(resource.host).must_equal 'oraclehost'