# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
# frozen_string_literal: true

require_relative './lib/contrast/agent/version'

lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)

# Add the team as authors of the Agent
def self.add_authors spec
  spec.authors = %w[
    galen.palmer@contrastsecurity.com
    harold.mcginnis@contrastsecurity.com
    donald.propst@contrastsecurity.com
    alex.macdonald@contrastsecurity.com
    mark.petersen@contrastsecurity.com
    joshua.reed@contrastsecurity.com
  ]
end

# Add those dependencies required to develop or test the Agent
def self.add_dev_dependencies spec
  add_builders(spec)
  add_debuggers(spec)
  add_linters(spec)
  add_specs(spec)
  add_custom_dependencies(spec)
end

# Dependencies used to build the agent during development.
def self.add_builders spec
  spec.add_development_dependency 'bundler'
  spec.add_development_dependency 'rake', '>= 12.3.3'
  spec.add_development_dependency 'rake-compiler', '~> 0'
end

# Dependencies that are required during testing in actual application
def self.add_custom_dependencies spec
  spec.add_development_dependency 'zlib'
end

# Dependencies used for local debugging during development.
def self.add_debuggers spec
  spec.add_development_dependency 'pry'
  spec.add_development_dependency 'pry-byebug', '>= 3.9'
  spec.add_development_dependency 'ruby-debug-ide'
end

# Dependencies used for framework testing.
def self.add_frameworks spec
  spec.add_development_dependency 'grape', '~> 1.5', '>= 1.5.2'
  spec.add_development_dependency 'rack-protection', '>= 2'
  spec.add_development_dependency 'rails', '~> 7'
  spec.add_development_dependency 'sinatra', '>= 2'
end

# Dependencies used for linting prior to commit.
def self.add_linters spec
  spec.add_development_dependency 'debride', '1.8.2'
  spec.add_development_dependency 'fasterer', '0.9.0'
  spec.add_development_dependency 'flay', '2.12.1'
  spec.add_development_dependency 'steep', '0.47.0'
  add_rubocop(spec)
end

# Dependencies used to run our current RSpec test suite.
def self.add_specs spec
  add_coverage(spec)
  add_frameworks(spec)
  add_tested_gems(spec)

  spec.add_development_dependency 'benchmark-ips'
  spec.add_development_dependency 'benchmark-memory', '~> 0.1'
  spec.add_development_dependency 'climate_control' # mock ENV
  spec.add_development_dependency 'factory_bot'
  spec.add_development_dependency 'fake_ftp'
  spec.add_development_dependency 'openssl'
  spec.add_development_dependency 'parallel_tests', '~> 3.0'
  spec.add_development_dependency 'rspec', '~> 3.0'
  spec.add_development_dependency 'rspec-benchmark'
  spec.add_development_dependency 'rspec_junit_formatter', '0.3.0'
  spec.add_development_dependency 'rspec-rails', '5.0'
  spec.add_development_dependency 'tzinfo-data' # Alpine rspec-rails requirement.
  spec.add_development_dependency 'warning'
  spec.add_development_dependency 'typhoeus', '~> 1.4'
  spec.add_development_dependency 'excon', '~> 0.92.3'
end

def self.add_coverage spec
  spec.add_development_dependency 'simplecov', '0.21.2'
end

# Dependencies used to run all of our Rubocop during the linting phase.
def self.add_rubocop spec
  spec.add_development_dependency 'rubocop', '1.37.1'
  spec.add_development_dependency 'rubocop-performance', '1.15.0'
  spec.add_development_dependency 'rubocop-rails', '2.17.2'
  spec.add_development_dependency 'rubocop-rake', '0.6.0'
  spec.add_development_dependency 'rubocop-rspec', '2.14.2'
end

# Dependencies not mocked out during RSpec that we test real code of, beyond just frameworks.
def self.add_tested_gems spec
  if RUBY_VERSION < '3.0.0'
    spec.add_development_dependency 'async', '~> 1.30.3'
  else
    spec.add_development_dependency 'async'
  end
  spec.add_development_dependency 'execjs'
  spec.add_development_dependency 'rhino'
  spec.add_development_dependency 'sqlite3'
  spec.add_development_dependency 'tilt'
  spec.add_development_dependency 'xpath'
end

# Add those dependencies required to run the Agent in customer applications.
#
# Note: If you add a runtime dependency to the Agent, you'll need to update the
# dependencies.csv in this directory to indicate that and create a
# corresponding update to the fake gem server data in TeamServer.
def self.add_dependencies spec
  spec.add_dependency 'ougai', '>= 1.8', '< 3.0.0'
  spec.add_dependency 'rack', '~> 2.0'
  spec.add_dependency 'contrast-agent-lib',  '~> 0.1.0', '>= 0.1.3'
  spec.add_dependency 'ffi', '~> 1.0'
end

# Enumerate the files required to build the Agent.
def self.add_files spec
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
    # Directories used for testing:
    f.match(%r{^(spec|test)/}) ||
        # Directories used in pipelines
        f.match(%r{^(\.github|bin|internal_resources|sig|vendor)/}) ||
        # Configuration and other files that don't belong to one directory
        f.match(/(Dockerfile)/)  ||
        f.match(/(.*\.csv)/)     ||
        f.match(/(.*\.md)/)      ||
        f.match(/(.*\.sh)/)      ||
        f.match(/(.*\.xml)/)     ||
        f.match(/(.*\.ya?ml)/)
  end

  spec.files += Dir['funchook/**/*']
  spec.files += Dir['shared_libraries/**/*']

  # Clean up compiled funchook files that may have been generated during
  # testing. Only a concern locally, but better than leaving it to chance.
  spec.files.delete_if do |file|
    file.end_with?('ext/libfunchook.dylib',
                   'ext/libfunchook.so',
                   'ext/funchook.h',
                   'shared_libraries/libfunchook.dylib',
                   'shared_libraries/libfunchook.so',
                   'shared_libraries/funchook.h',
                   'funchook/src/libfunchook.dylib',
                   'funchook/src/libfunchook.so',
                   '.secrets.baseline')
  end
end

def self.add_metadata spec
  spec.metadata['changelog_uri'] =        'https://docs.contrastsecurity.com/en/ruby-agent-release-notes-and-archive.html'
  spec.metadata['support_uri'] =          'https://support.contrastsecurity.com'
  spec.metadata['trouble_shooting_uri'] = 'https://support.contrastsecurity.com/hc/en-us/search?utf8=%E2%9C%93&query=Ruby'
  spec.metadata['wiki_uri'] =             'https://docs.contrastsecurity.com/'
end

Gem::Specification.new do |spec|
  spec.name    = 'contrast-agent'
  spec.version = Contrast::Agent::VERSION

  spec.email = %w[ruby@contrastsecurity.com]

  spec.summary      = 'Contrast Security\'s agent for rack-based applications.'
  spec.description  = 'This gem instantiates a Rack middleware for rack-based ' \
                      'web applications in order to provide Interactive Application Security ' \
                      'Testing and Protection.'
  spec.homepage     = 'https://www.contrastsecurity.com'
  spec.license      = 'CONTRAST SECURITY (see license file)'
  spec.required_ruby_version = ['>= 2.7.0', '< 3.2.0']

  spec.bindir        = 'exe'
  # Keep cs__common first, it handles funchook.h right now.
  spec.extensions = Dir['ext/cs__common/extconf.rb', 'ext/**/extconf.rb']
  spec.require_paths = ['lib']

  unless File.exist?(File.join(Dir.pwd, 'contrast_security.yaml'))
    spec.post_install_message = 'To generate the required contrast_security.yaml file you can run: '\
                                'bundle exec rake contrast:config:create'
  end

  add_authors(spec)
  add_files(spec)
  add_dev_dependencies(spec)
  add_dependencies(spec)
  add_metadata(spec)
end