Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Travis Insights integration #1218

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,32 @@ logs/
log/

.yardoc
.coverage
*.env
.ruby-gemset
.history

#IDEs
.idea

.history
.byebug_history

# Ignore Rubocop files
.rubocop-*

# Ignore coverage reports
coverage/
.coverage/

# Ignore editor specific configs
/.idea
/.vscode
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
.generators
.rakeTasks

# System Files
.DS_Store
Thumbs.db
266 changes: 266 additions & 0 deletions lib/travis/api/v3/insights_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
# frozen_string_literal: true

module Travis::API::V3
class InsightsClient
class ConfigurationError < StandardError; end

def initialize(user_id)
@user_id = user_id
end

def user_notifications(filter, page, active, sort_by, sort_direction)
query_string = query_string_from_params(
value: filter,
page: page || '1',
active: active,
order: sort_by,
order_dir: sort_direction
)
response = connection.get("/user_notifications?#{query_string}")

handle_errors_and_respond(response) do |body|
notifications = body['data'].map do |notification|
Travis::API::V3::Models::InsightsNotification.new(notification)
end

Travis::API::V3::Models::InsightsCollection.new(notifications, body.fetch('total_count'))
end
end

def toggle_snooze_user_notifications(notification_ids)
response = connection.put('/user_notifications/toggle_snooze', snooze_ids: notification_ids)

handle_errors_and_respond(response)
end

def user_plugins(filter, page, active, sort_by, sort_direction)
query_string = query_string_from_params(
value: filter,
page: page || '1',
active: active,
order: sort_by,
order_dir: sort_direction
)
response = connection.get("/user_plugins?#{query_string}")

handle_errors_and_respond(response) do |body|
plugins = body['data'].map do |plugin|
Travis::API::V3::Models::InsightsPlugin.new(plugin)
end

Travis::API::V3::Models::InsightsCollection.new(plugins, body.fetch('total_count'))
end
end

def create_plugin(params)
response = connection.post("/user_plugins", user_plugin: params)
handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsPlugin.new(body['plugin'])
end
end

def toggle_active_plugins(plugin_ids)
response = connection.put('/user_plugins/toggle_active', toggle_ids: plugin_ids)

handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsCollection.new([], 0)
end
end

def delete_many_plugins(plugin_ids)
response = connection.delete('/user_plugins/delete_many', delete_ids: plugin_ids)

handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsCollection.new([], 0)
end
end

def run_scan
response = connection.get('/user_plugins/run_scan')

handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsCollection.new([], 0)
end
end

def generate_key(plugin_name, plugin_type)
response = connection.get('/user_plugins/generate_key', name: plugin_name, plugin_type: plugin_type)

handle_errors_and_respond(response) do |body|
body
end
end

def authenticate_key(params)
response = connection.post('/user_plugins/authenticate_key', params)

handle_errors_and_respond(response) do |body|
body
end
end

def template_plugin_tests(plugin_type)
response = connection.get("/user_plugins/#{plugin_type}/template_plugin_tests")

handle_errors_and_respond(response) do |body|
body
end
end

def get_scan_logs(plugin_id, last_id)
params = last_id ? { last: last_id, poll: true } : {}
response = connection.get("/user_plugins/#{plugin_id}/get_scan_logs", params)

handle_errors_and_respond(response) do |body|
body
end
end

def probes(filter, page, active, sort_by, sort_direction)
query_string = query_string_from_params(
value: filter,
page: page || '1',
active: active,
order: sort_by,
order_dir: sort_direction
)
response = connection.get("/probes?#{query_string}")

handle_errors_and_respond(response) do |body|
probes = body['data'].map do |probe|
Travis::API::V3::Models::InsightsProbe.new(probe)
end

Travis::API::V3::Models::InsightsCollection.new(probes, body.fetch('total_count'))
end
end

def create_probe(params)
response = connection.post("/probes", test_template: params)
handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsProbe.new(body)
end
end

def update_probe(params)
response = connection.patch("/probes/#{params['probe_id']}", params)
handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsProbe.new(body)
end
end

def get_probe(params)
response = connection.get("/probes/#{params['probe_id']}/template_test", params)
handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsProbe.new(body)
end
end

def toggle_active_probes(probe_ids)
response = connection.put('/probes/toggle_active', toggle_ids: probe_ids)

handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsCollection.new([], 0)
end
end

def delete_many_probes(probe_ids)
response = connection.delete('/probes/delete_many', delete_ids: probe_ids)

handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsCollection.new([], 0)
end
end

def sandbox_plugins(plugin_type)
response = connection.post('/sandbox/plugins', plugin_type: plugin_type)

handle_errors_and_respond(response) do |body|
body
end
end

def sandbox_plugin_data(plugin_id)
response = connection.post('/sandbox/plugin_data', plugin_id: plugin_id)

handle_errors_and_respond(response) do |body|
body
end
end

def sandbox_run_query(plugin_id, query)
response = connection.post('/sandbox/run_query', plugin_id: plugin_id, query: query)

handle_errors_and_respond(response) do |body|
body
end
end

def public_key
response = connection.get('/api/v1/public_keys/latest.json')

handle_errors_and_respond(response) do |body|
Travis::API::V3::Models::InsightsPublicKey.new(body)
end
end

def search_tags
response = connection.get('/tags')

handle_errors_and_respond(response) do |body|
tags = body.map do |tag|
Travis::API::V3::Models::InsightsTag.new(tag)
end
end
end

private

def handle_errors_and_respond(response)
case response.status
when 200, 201
yield(response.body) if block_given?
when 202
true
when 204
true
when 400
raise Travis::API::V3::ClientError, response.body&.fetch('error', '')
when 403
raise Travis::API::V3::InsufficientAccess, response.body&.fetch('rejection_code', '')
when 404
raise Travis::API::V3::NotFound, response.body&.fetch('error', '')
when 422
raise Travis::API::V3::UnprocessableEntity, response.body&.fetch('error', '')
else
raise Travis::API::V3::ServerError, 'Insights API failed'
end
end

def connection(timeout: 20)
@connection ||= Faraday.new(url: insights_url, ssl: { ca_path: '/usr/lib/ssl/certs' }) do |conn|
conn.headers[:Authorization] = "Token token=\"#{insights_auth_token}\""
conn.headers['X-Travis-User-Id'] = @user_id.to_s
conn.headers['Content-Type'] = 'application/json'
conn.request :json
conn.response :json
conn.options[:open_timeout] = timeout
conn.options[:timeout] = timeout
conn.use OpenCensus::Trace::Integrations::FaradayMiddleware if Travis::Api::App::Middleware::OpenCensus.enabled?
conn.adapter :net_http
end
end

def insights_url
Travis.config.new_insights.insights_url || raise(ConfigurationError, 'No Insights API URL configured!')
end

def insights_auth_token
Travis.config.new_insights.insights_auth_token || raise(ConfigurationError, 'No Insights Auth Token configured!')
end

def query_string_from_params(params)
params.delete_if { |_, v| v.nil? || v.empty? }.to_query
end
end
end
32 changes: 32 additions & 0 deletions lib/travis/api/v3/models/insights_collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

module Travis::API::V3
class Models::InsightsCollection
def initialize(collection, total_count)
@collection = collection
@total_count = total_count
end

def count(*)
@total_count
end

def limit(*)
self
end

def offset(*)
self
end

def map
return @collection.map unless block_given?

@collection.map { |x| yield x }
end

def to_sql
"insights_query:#{Time.now.to_i}"
end
end
end
19 changes: 19 additions & 0 deletions lib/travis/api/v3/models/insights_notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Travis::API::V3
class Models::InsightsNotification
attr_reader :id, :type, :active, :weight, :message, :plugin_name, :plugin_type, :plugin_category, :probe_severity, :description, :description_link

def initialize(attributes = {})
@id = attributes.fetch('id')
@type = attributes.fetch('type')
@active = attributes.fetch('active')
@weight = attributes.fetch('weight')
@message = attributes.fetch('message')
@plugin_name = attributes.fetch('plugin_name')
@plugin_type = attributes.fetch('plugin_type')
@plugin_category = attributes.fetch('plugin_category')
@probe_severity = attributes.fetch('probe_severity')
@description = attributes.fetch('description', '')
@description_link = attributes.fetch('description_link', '')
end
end
end
17 changes: 17 additions & 0 deletions lib/travis/api/v3/models/insights_plugin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Travis::API::V3
class Models::InsightsPlugin
attr_reader :id, :name, :public_id, :plugin_type, :plugin_category, :last_scan_end, :scan_status, :plugin_status, :active

def initialize(attributes = {})
@id = attributes.fetch('id')
@name = attributes.fetch('name')
@public_id = attributes.fetch('public_id')
@plugin_type = attributes.fetch('plugin_type')
@plugin_category = attributes.fetch('plugin_category')
@last_scan_end = attributes.fetch('last_scan_end')
@scan_status = attributes.fetch('scan_status')
@plugin_status = attributes.fetch('plugin_status')
@active = attributes.fetch('active')
end
end
end
Loading