File Coverage

blib/lib/WebService/ThreatStack.pm
Criterion Covered Total %
statement 29 77 37.6
branch 0 26 0.0
condition n/a
subroutine 10 21 47.6
pod 10 10 100.0
total 49 134 36.5


line stmt bran cond sub pod time code
1             package WebService::ThreatStack;
2              
3 1     1   62919 use 5.10.0;
  1         3  
4 1     1   5 use strict;
  1         2  
  1         19  
5 1     1   4 use warnings;
  1         6  
  1         30  
6 1     1   5 use feature 'switch';
  1         1  
  1         246  
7 1     1   6 use feature 'say';
  1         2  
  1         25  
8              
9 1     1   452 use JSON;
  1         9830  
  1         6  
10 1     1   492 use REST::Client;
  1         36874  
  1         54  
11              
12 1     1   549 use Moose;
  1         502116  
  1         10  
13 1     1   10446 use Moose::Util::TypeConstraints;
  1         5  
  1         13  
14 1     1   3965 use MooseX::Params::Validate;
  1         88991  
  1         9  
15              
16              
17             =head1 NAME
18              
19             WebService::ThreatStack - Threat Stack API client
20              
21              
22             =head1 VERSION
23              
24             Version 1.00
25              
26             =cut
27              
28              
29             our $VERSION = '1.00';
30              
31              
32              
33             has api_key => (
34             is => 'rw',
35             isa => 'Str'
36             );
37              
38             has api_url => (
39             is => 'ro',
40             isa => 'Str',
41             default => 'https://app.threatstack.com/api/v1'
42             );
43              
44             has headers => (
45             is => 'rw',
46             isa => 'Str',
47             );
48              
49             has debug => (
50             is => 'ro',
51             isa => 'Bool',
52             default => 0
53             );
54              
55              
56              
57             =head1 SYNOPSIS
58              
59             Threat Stack is a provider of cloud security management and compliance solutions delivered using a Software as a service model.
60             This API client interfaces with the Threat Stack REST API.
61              
62              
63             =head1 CONFIGURATION
64            
65             use WebService::ThreatStack;
66            
67             my $ts = WebService::ThreatStack->new(
68             api_key => '[your-api-key]',
69             debug => 1
70             );
71              
72              
73             =head1 SUBROUTINES/METHODS
74              
75              
76             =head2 agents
77              
78             List all agents assigned to your active organization.
79              
80             my $agent_list = $ts->agents(
81             page => 0,
82             count => 20,
83             start => '2015-04-01',
84             end => '2017-07-01'
85             );
86              
87             =cut
88              
89             sub agents {
90 0     0 1   my ($self, %params) = validated_hash(
91             \@_,
92             organization => {isa => 'Maybe[Int]', optional => 1},
93             page => {isa => 'Maybe[Int]', optional => 1},
94             count => {isa => 'Maybe[Int]', optional => 1},
95             start => {isa => 'Maybe[Str]', optional => 1},
96             end => {isa => 'Maybe[Str]', optional => 1}
97             );
98              
99 0 0         say '[agents] Get all agents' if $self->debug;
100              
101 0           $self->_call(endpoint => 'agents', args => \%params, method => 'GET');
102             }
103              
104              
105              
106             =head2 agent_by_id
107              
108             Get details of a specific agent resource. The id to use is id, not agent_id.
109              
110             my $agent_info = $ts->agent_by_id(id => $id);
111              
112             =cut
113              
114             sub agent_by_id {
115 0     0 1   my ($self, %params) = validated_hash(
116             \@_,
117             id => {isa => 'Str'}
118             );
119              
120 0 0         say '[agent] Get agent by id' if $self->debug;
121              
122 0           $self->_call(endpoint => "agents/$params{id}", args => {}, method => 'GET');
123             }
124              
125              
126              
127             =head2 alerts
128              
129             This URI retrieves all recent alerts related to your current active organization.
130              
131             my $alerts = $ts->alerts(
132             count => 20,
133             start => "2017-07-01",
134             end => "2017-07-20"
135             );
136              
137             =cut
138              
139             sub alerts {
140 0     0 1   my ($self, %params) = validated_hash(
141             \@_,
142             organization => {isa => 'Maybe[Int]', optional => 1},
143             page => {isa => 'Maybe[Int]', optional => 1},
144             count => {isa => 'Maybe[Int]', optional => 1},
145             start => {isa => 'Maybe[Str]', optional => 1},
146             end => {isa => 'Maybe[Str]', optional => 1}
147             );
148              
149 0 0         say '[alerts] Get all alerts' if $self->debug;
150              
151 0           $self->_call(endpoint => 'alerts', args => \%params, method => 'GET');
152             }
153              
154              
155              
156             =head2 alert_by_id
157              
158             Every alert has a URI to fetch specific information about it. Additionally, each alert has a
159             latest_events and rule attributes that provides events related to that alert and rule triggered
160             respectively.
161              
162             my $alert_info = $ts->alert_by_id(id => $alert_id);
163              
164             =cut
165              
166             sub alert_by_id {
167 0     0 1   my ($self, %params) = validated_hash(
168             \@_,
169             id => {isa => 'Str'}
170             );
171              
172 0 0         say '[alert] Get alert by id' if $self->debug;
173              
174 0           $self->_call(endpoint => "alerts/$params{id}", args => {}, method => 'GET');
175             }
176              
177              
178              
179             =head2 policies
180              
181             Policies object manage the alerts that will be triggered when certain events matches.
182             A default policy is applied to each agent on creation and custom ones can be created or
183             assigned via the User Interface. Note that we’ve introduced the term ruleset to supersede
184             policies – the API will be updated shortly, but any existing references to policies
185             will still work as expected.
186              
187             my $policies = $ts->policies();
188              
189             =cut
190              
191             sub policies {
192 0     0 1   my ($self, %params) = validated_hash(
193             \@_,
194             organization => {isa => 'Maybe[Int]', optional => 1},
195             page => {isa => 'Maybe[Int]', optional => 1},
196             count => {isa => 'Maybe[Int]', optional => 1}
197             );
198              
199 0 0         say '[policies] Get all policies' if $self->debug;
200              
201 0           $self->_call(endpoint => 'policies', args => \%params, method => 'GET');
202             }
203              
204              
205              
206             =head2 policy_by_id
207              
208             Retrieve details of a single policy object.
209              
210             my $policy_info = $ts->policy_by_id(id => $policy_id);
211              
212             =cut
213              
214             sub policy_by_id {
215 0     0 1   my ($self, %params) = validated_hash(
216             \@_,
217             id => {isa => 'Str'}
218             );
219              
220 0 0         say '[policy] Get policy by id' if $self->debug;
221              
222 0           $self->_call(endpoint => "policies/$params{id}", args => {}, method => 'GET');
223             }
224              
225              
226              
227             =head2 organizations
228              
229             This resource retrieve all organizations you own or are part of.
230              
231             my $organizations = $ts->organizations();
232              
233             =cut
234              
235             sub organizations {
236 0     0 1   my $self = shift;
237              
238 0 0         say '[organizations] Get all organizations' if $self->debug;
239              
240 0           $self->_call(endpoint => "organizations", args => {}, method => 'GET');
241             }
242              
243              
244              
245             =head2 organization_users
246              
247             This resource retrieves all users that are part of your default or active (if you
248             use the organization parameter). To change the context just add organization={ORG_ID}
249             to do requests on that organization context.
250              
251             my $organization_users = $ts->organization_users(id => $organization_id);
252              
253             =cut
254              
255             sub organization_users {
256 0     0 1   my ($self, %params) = validated_hash(
257             \@_,
258             id => {isa => 'Str'}
259             );
260              
261 0 0         say '[organization_users] Get organization users' if $self->debug;
262              
263 0           $self->_call(endpoint => "organizations/$params{id}/users", args => {}, method => 'GET');
264             }
265              
266              
267              
268             =head2 audit_logs
269              
270             Get all audit logs
271              
272             my $audit_logs = $ts->audit_logs(
273             page => 0,
274             count => 20,
275             start => "2015-04-01",
276             end => "2017-07-01"
277             );
278              
279             =cut
280              
281             sub audit_logs {
282 0     0 1   my ($self, %params) = validated_hash(
283             \@_,
284             organization => {isa => 'Maybe[Int]', optional => 1},
285             page => {isa => 'Maybe[Int]', optional => 1},
286             count => {isa => 'Maybe[Int]', optional => 1},
287             start => {isa => 'Maybe[Str]', optional => 1},
288             end => {isa => 'Maybe[Str]', optional => 1}
289             );
290              
291 0 0         say '[audit_logs] Get all audit logs' if $self->debug;
292              
293 0           $self->_call(endpoint => 'logs', args => \%params, method => 'GET');
294              
295             }
296              
297              
298              
299             =head2 search_logs
300              
301             Using the q parameter you can do arbitrary search on logs that match that
302             specific string pattern. For example, you can do search of q=queue,
303             q=john.doe@example.com, etc.
304              
305             my $log_results = $ts->search_logs(q => "PCI");
306              
307             =cut
308              
309             sub search_logs {
310 0     0 1   my ($self, %params) = validated_hash(
311             \@_,
312             q => {isa => 'Str'},
313             );
314              
315 0 0         say '[search_logs] Return logs by query' if $self->debug;
316              
317 0           $self->_call(endpoint => 'logs', args => \%params, method => 'GET');
318             }
319              
320              
321              
322             =head2 _call
323              
324             Private method that makes call to API web service.
325              
326             =cut
327              
328             sub _call {
329 0     0     my ($self, %params) = validated_hash(
330             \@_,
331             endpoint => {isa => 'Str'},
332             args => {isa => 'Maybe[HashRef]'},
333             method => {isa => enum([qw(POST GET)])}
334             );
335              
336 0           my $headers = {
337             "Authorization" => $self->api_key
338             };
339              
340 0           my $url = $self->api_url . '/' . $params{endpoint};
341              
342 0           my $client = REST::Client->new();
343              
344 0           for ($params{method}) {
345 0           when ('GET') {
346 0 0         say "[_call]: Making call GET $url" if $self->debug;
347 0 0         my $url_args = keys %{$params{args}} > 0 ? '?' . join('&', map {"$_=$params{args}{$_}"} keys %{$params{args}}) : '';
  0            
  0            
  0            
348 0           $url .= $url_args;
349 0           $client->GET($url, $headers);
350             }
351 0           when ('POST') {
352 0           my $json_args = JSON->new->allow_nonref->utf8->encode($params{args}{data});
353 0 0         say "[_call]: Making call POST $url" if $self->debug;
354 0           $client->POST($url, $json_args, $headers)
355             }
356             }
357              
358             {
359 0           response_code => $client->responseCode(),
360             response_content => $client->responseContent()
361             }
362             }
363              
364              
365              
366              
367             =head1 AUTHOR
368              
369             Dino Simone, C<< <dino at simone.is> >>
370              
371             =head1 BUGS
372              
373             Please report any bugs or feature requests to C<bug-webservice-castleio at rt.cpan.org>, or through
374             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=WebService-CastleIO>. I will be notified, and then you'll
375             automatically be notified of progress on your bug as I make changes.
376              
377              
378              
379              
380             =head1 SUPPORT
381              
382             You can find documentation for this module with the perldoc command.
383              
384             perldoc WebService::ThreatStack
385              
386              
387             You can also look for information at:
388              
389             =over 4
390              
391             =item * RT: CPAN's request tracker (report bugs here)
392              
393             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=WebService-ThreatStack>
394              
395             =item * AnnoCPAN: Annotated CPAN documentation
396              
397             L<http://annocpan.org/dist/WebService-ThreatStack>
398              
399             =item * CPAN Ratings
400              
401             L<http://cpanratings.perl.org/d/WebService-ThreatStack>
402              
403             =item * Search CPAN
404              
405             L<http://search.cpan.org/dist/WebService-ThreatStack/>
406              
407             =back
408              
409              
410             =head1 LICENSE AND COPYRIGHT
411              
412             Copyright 2017 Dino Simone - dinosimone.com
413              
414             This program is distributed under the MIT (X11) License:
415             L<http://www.opensource.org/licenses/mit-license.php>
416              
417             Permission is hereby granted, free of charge, to any person
418             obtaining a copy of this software and associated documentation
419             files (the "Software"), to deal in the Software without
420             restriction, including without limitation the rights to use,
421             copy, modify, merge, publish, distribute, sublicense, and/or sell
422             copies of the Software, and to permit persons to whom the
423             Software is furnished to do so, subject to the following
424             conditions:
425              
426             The above copyright notice and this permission notice shall be
427             included in all copies or substantial portions of the Software.
428              
429             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
430             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
431             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
432             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
433             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
434             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
435             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
436             OTHER DEALINGS IN THE SOFTWARE.
437              
438              
439             =cut
440              
441             1; # End of WebService::ThreatStack