# encoding: utf-8
require 'hashie/mash'
require 'utils/database_helpers'
require 'htmlentities'
require 'rexml/document'
require 'csv'
module Inspec::Resources
# STABILITY: Experimental
# This resource needs further testing and refinement
#
class OracledbSession < Inspec.resource(1)
name 'oracledb_session'
supports platform: 'unix'
supports platform: 'windows'
desc 'Use the oracledb_session InSpec resource to test commands against an Oracle database'
example <<~EXAMPLE
sql = oracledb_session(user: 'my_user', pass: 'password')
describe sql.query(\"SELECT UPPER(VALUE) AS VALUE FROM V$PARAMETER WHERE UPPER(NAME)='AUDIT_SYS_OPERATIONS'\").row(0).column('value') do
its('value') { should eq 'TRUE' }
end
EXAMPLE
attr_reader :user, :password, :host, :service, :as_os_user, :as_db_role
# rubocop:disable Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity
def initialize(opts = {})
@user = opts[:user]
@password = opts[:password] || opts[:pass]
if opts[:pass]
warn '[DEPRECATED] use `password` option to supply password instead of `pass`'
end
@host = opts[:host] || 'localhost'
@port = opts[:port] || '1521'
@service = opts[:service]
# connection as sysdba stuff
return skip_resource "Option 'as_os_user' not available in Windows" if inspec.os.windows? && opts[:as_os_user]
@su_user = opts[:as_os_user]
@db_role = opts[:as_db_role]
# we prefer sqlci although it is way slower than sqlplus, but it understands csv properly
@sqlcl_bin = 'sql' unless opts.key?(:sqlplus_bin) # don't use it if user specified sqlplus_bin option
@sqlplus_bin = opts[:sqlplus_bin] || 'sqlplus'
return fail_resource "Can't run Oracle checks without authentication" if @su_user.nil? && (@user.nil? || @password.nil?)
return fail_resource 'You must provide a service name for the session' if @service.nil?
end
def query(q)
escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"')
# escape tables with $
escaped_query = escaped_query.gsub('$', '\\$')
p = nil
# use sqlplus if sqlcl is not available
if @sqlcl_bin and inspec.command(@sqlcl_bin).exist?
bin = @sqlcl_bin
opts = "set sqlformat csv\nSET FEEDBACK OFF"
p = :parse_csv_result
else
bin = @sqlplus_bin
opts = "SET MARKUP HTML ON\nSET PAGESIZE 32000\nSET FEEDBACK OFF"
p = :parse_html_result
end
query = verify_query(escaped_query)
query += ';' unless query.end_with?(';')
if @db_role.nil?
command = %{#{bin} "#{@user}"/"#{@password}"@#{@host}:#{@port}/#{@service} <