Class: Tenable::Resources::WebAppScans

Inherits:
Base
  • Object
show all
Defined in:
lib/tenable/resources/web_app_scans.rb

Overview

Provides access to the Tenable.io Web Application Scanning (WAS) endpoints.

Constant Summary collapse

TERMINAL_STATUSES =
%w[completed failed cancelled error].freeze
FORMAT_CONTENT_TYPES =

Supported scan export formats and their MIME types.

{
  'json' => 'application/json',
  'csv' => 'text/csv',
  'xml' => 'application/xml',
  'html' => 'text/html',
  'pdf' => 'application/pdf'
}.freeze
SUPPORTED_EXPORT_FORMATS =

Supported scan export formats.

FORMAT_CONTENT_TYPES.keys.freeze
DEFAULT_POLL_INTERVAL =

Returns default seconds between status polls.

Returns:

  • (Integer)

    default seconds between status polls

2
DEFAULT_EXPORT_POLL_INTERVAL =

Returns default seconds between export status polls.

Returns:

  • (Integer)

    default seconds between export status polls

5
DEFAULT_SCAN_TIMEOUT =

Returns default timeout in seconds for waiting on scan completion.

Returns:

  • (Integer)

    default timeout in seconds for waiting on scan completion

3600
DEFAULT_EXPORT_TIMEOUT =

Returns default timeout in seconds for waiting on export completion.

Returns:

  • (Integer)

    default timeout in seconds for waiting on export completion

600

Instance Method Summary collapse

Methods inherited from Base

#initialize

Methods included from Pollable

#poll_until

Constructor Details

This class inherits a constructor from Tenable::Resources::Base

Instance Method Details

#create_config(name:, target:) ⇒ Hash

Creates a new web application scan configuration.

Examples:

client.web_app_scans.create_config(name: "My App", target: "https://example.com")

Parameters:

  • name (String)

    name for the scan configuration

  • target (String)

    the target URL to scan

Returns:

  • (Hash)

    the created configuration data

Raises:



42
43
44
# File 'lib/tenable/resources/web_app_scans.rb', line 42

def create_config(name:, target:)
  post('/was/v2/configs', { 'name' => name, 'target' => target })
end

#delete_config(config_id) ⇒ Hash?

Returns parsed response or nil.

Parameters:

  • config_id (String)

    the scan configuration ID

Returns:

  • (Hash, nil)

    parsed response or nil



63
64
65
66
# File 'lib/tenable/resources/web_app_scans.rb', line 63

def delete_config(config_id)
  validate_path_segment!(config_id, name: 'config_id')
  delete("/was/v2/configs/#{config_id}")
end

#delete_scan(scan_id) ⇒ Hash?

Deletes a WAS scan.

Parameters:

  • scan_id (String)

    the scan ID

Returns:

  • (Hash, nil)

    parsed response or nil



146
147
148
149
# File 'lib/tenable/resources/web_app_scans.rb', line 146

def delete_scan(scan_id)
  validate_path_segment!(scan_id, name: 'scan_id')
  delete("/was/v2/scans/#{scan_id}")
end

#download_scan_export(scan_id, format:) ⇒ String

Downloads a completed WAS scan export as raw binary data.

Parameters:

  • scan_id (String)

    the scan ID

  • format (String)

    export format — one of “json”, “csv”, “xml”, “html”, or “pdf”

Returns:

  • (String)

    raw binary content of the export



221
222
223
224
225
226
227
228
229
230
# File 'lib/tenable/resources/web_app_scans.rb', line 221

def download_scan_export(scan_id, format:)
  validate_path_segment!(scan_id, name: 'scan_id')
  content_type = validate_export_format!(format)
  response = @connection.faraday.get("/was/v2/scans/#{scan_id}/report") do |req|
    req.headers['Accept'] = content_type
    req.headers['Content-Type'] = content_type
  end
  raise_for_status(response)
  response.body
end

#export(scan_id, format:, save_path: nil, timeout: DEFAULT_EXPORT_TIMEOUT, poll_interval: DEFAULT_EXPORT_POLL_INTERVAL) ⇒ String

Convenience method: requests an export, waits for completion, and downloads the result.

Examples:

Download PDF to disk

client.web_app_scans.export('scan-123', format: 'pdf', save_path: '/tmp/report.pdf')

Get raw binary content

binary = client.web_app_scans.export('scan-123', format: 'csv')

Parameters:

  • scan_id (String)

    the scan ID

  • format (String)

    export format — one of “json”, “csv”, “xml”, “html”, or “pdf”

  • save_path (String, nil) (defaults to: nil)

    if provided, writes binary content to this file path. The caller is responsible for ensuring the path is safe and writable. This value is used as-is with File.binwrite — no sanitization is performed.

  • timeout (Integer) (defaults to: DEFAULT_EXPORT_TIMEOUT)

    maximum seconds to wait (default: 600)

  • poll_interval (Integer) (defaults to: DEFAULT_EXPORT_POLL_INTERVAL)

    seconds between status checks (default: 5)

Returns:

  • (String)

    the save_path if given, otherwise the raw binary content



265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/tenable/resources/web_app_scans.rb', line 265

def export(scan_id, format:, save_path: nil, timeout: DEFAULT_EXPORT_TIMEOUT,
           poll_interval: DEFAULT_EXPORT_POLL_INTERVAL)
  validate_path_segment!(scan_id, name: 'scan_id')
  export_scan(scan_id, format: format)
  wait_for_scan_export(scan_id, format: format, timeout: timeout, poll_interval: poll_interval)
  content = download_scan_export(scan_id, format: format)

  if save_path
    File.binwrite(save_path, content)
    save_path
  else
    content
  end
end

#export_findings(body = {}) ⇒ Hash

Initiates a bulk WAS findings export.

Parameters:

  • body (Hash) (defaults to: {})

    export request parameters

Returns:

  • (Hash)

    response containing the export UUID



284
285
286
# File 'lib/tenable/resources/web_app_scans.rb', line 284

def export_findings(body = {})
  post('/was/v1/export/vulns', body)
end

#export_findings_cancel(export_uuid) ⇒ Hash

Cancels an in-progress WAS findings export.

Parameters:

  • export_uuid (String)

    the export UUID

Returns:

  • (Hash)

    cancellation response



312
313
314
315
# File 'lib/tenable/resources/web_app_scans.rb', line 312

def export_findings_cancel(export_uuid)
  validate_path_segment!(export_uuid, name: 'export_uuid')
  post("/was/v1/export/vulns/#{export_uuid}/cancel")
end

#export_findings_chunk(export_uuid, chunk_id) ⇒ Array<Hash>

Downloads a single chunk of WAS findings export data.

Parameters:

  • export_uuid (String)

    the export UUID

  • chunk_id (Integer)

    the chunk identifier

Returns:

  • (Array<Hash>)

    array of finding records



302
303
304
305
306
# File 'lib/tenable/resources/web_app_scans.rb', line 302

def export_findings_chunk(export_uuid, chunk_id)
  validate_path_segment!(export_uuid, name: 'export_uuid')
  validate_path_segment!(chunk_id, name: 'chunk_id')
  get("/was/v1/export/vulns/#{export_uuid}/chunks/#{chunk_id}")
end

#export_findings_status(export_uuid) ⇒ Hash

Retrieves the status of a WAS findings export.

Parameters:

  • export_uuid (String)

    the export UUID

Returns:

  • (Hash)

    status data



292
293
294
295
# File 'lib/tenable/resources/web_app_scans.rb', line 292

def export_findings_status(export_uuid)
  validate_path_segment!(export_uuid, name: 'export_uuid')
  get("/was/v1/export/vulns/#{export_uuid}/status")
end

#export_scan(scan_id, format:) ⇒ Hash

Initiates a report export for a specific WAS scan.

The format is specified via the Content-Type header per the Tenable API.

Parameters:

  • scan_id (String)

    the scan ID

  • format (String)

    export format — one of “json”, “csv”, “xml”, “html”, or “pdf”

Returns:

  • (Hash)

    export initiation response

Raises:

  • (ArgumentError)

    if the format is not supported



184
185
186
187
188
189
190
191
# File 'lib/tenable/resources/web_app_scans.rb', line 184

def export_scan(scan_id, format:)
  validate_path_segment!(scan_id, name: 'scan_id')
  content_type = validate_export_format!(format)
  response = @connection.faraday.put("/was/v2/scans/#{scan_id}/report") do |req|
    req.headers['Content-Type'] = content_type
  end
  handle_response(response)
end

#export_scan_status(scan_id, format:) ⇒ Hash

Checks the status of a WAS scan report by attempting to fetch it.

The WAS report API has no separate status endpoint. A 404 response indicates the report is still being generated.

Parameters:

  • scan_id (String)

    the scan ID

  • format (String)

    export format — one of “json”, “csv”, “xml”, “html”, or “pdf”

Returns:

  • (Hash)

    status data with “status” key (“ready” or “loading”)



201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/tenable/resources/web_app_scans.rb', line 201

def export_scan_status(scan_id, format:)
  validate_path_segment!(scan_id, name: 'scan_id')
  content_type = validate_export_format!(format)
  response = @connection.faraday.get("/was/v2/scans/#{scan_id}/report") do |req|
    req.headers['Accept'] = content_type
    req.headers['Content-Type'] = content_type
  end
  if response.status == 404
    { 'status' => 'loading' }
  else
    raise_for_status(response)
    { 'status' => 'ready' }
  end
end

#get_config(config_id) ⇒ Hash

Returns the configuration data.

Parameters:

  • config_id (String)

    the scan configuration ID

Returns:

  • (Hash)

    the configuration data



48
49
50
51
# File 'lib/tenable/resources/web_app_scans.rb', line 48

def get_config(config_id)
  validate_path_segment!(config_id, name: 'config_id')
  get("/was/v2/configs/#{config_id}")
end

#get_scan(scan_id) ⇒ Hash

Retrieves details of a specific WAS scan.

Parameters:

  • scan_id (String)

    the scan ID

Returns:

  • (Hash)

    scan details



128
129
130
131
# File 'lib/tenable/resources/web_app_scans.rb', line 128

def get_scan(scan_id)
  validate_path_segment!(scan_id, name: 'scan_id')
  get("/was/v2/scans/#{scan_id}")
end

#launch(config_id) ⇒ Hash

Launches a scan for the given configuration.

Parameters:

  • config_id (String)

    the scan configuration ID

Returns:

  • (Hash)

    response containing the scan ID



78
79
80
81
# File 'lib/tenable/resources/web_app_scans.rb', line 78

def launch(config_id)
  validate_path_segment!(config_id, name: 'config_id')
  post("/was/v2/configs/#{config_id}/scans")
end

#search_configs(**params) ⇒ Hash

Returns search results with items and pagination.

Parameters:

  • params (Hash)

    search parameters

Returns:

  • (Hash)

    search results with items and pagination



70
71
72
# File 'lib/tenable/resources/web_app_scans.rb', line 70

def search_configs(**params)
  post('/was/v2/configs/search', params)
end

#search_scan_vulnerabilities(scan_id, **params) ⇒ Hash

Searches vulnerabilities for a specific scan.

Examples:

client.web_app_scans.search_scan_vulnerabilities(scan_id, severity: "high")

Parameters:

  • scan_id (String)

    the scan ID

  • params (Hash)

    search parameters

Returns:

  • (Hash)

    search results with vulnerabilities and pagination



102
103
104
105
# File 'lib/tenable/resources/web_app_scans.rb', line 102

def search_scan_vulnerabilities(scan_id, **params)
  validate_path_segment!(scan_id, name: 'scan_id')
  post("/was/v2/scans/#{scan_id}/vulnerabilities/search", params)
end

#search_scans(config_id, **params) ⇒ Hash

Searches scans for a specific configuration.

Parameters:

  • config_id (String)

    the scan configuration ID

  • params (Hash)

    search parameters

Returns:

  • (Hash)

    search results with items and pagination



156
157
158
159
# File 'lib/tenable/resources/web_app_scans.rb', line 156

def search_scans(config_id, **params)
  validate_path_segment!(config_id, name: 'config_id')
  post("/was/v2/configs/#{config_id}/scans/search", params)
end

#search_vulnerabilities(**params) ⇒ Hash

Returns search results with items and pagination.

Parameters:

  • params (Hash)

    search parameters

Returns:

  • (Hash)

    search results with items and pagination



163
164
165
# File 'lib/tenable/resources/web_app_scans.rb', line 163

def search_vulnerabilities(**params)
  post('/was/v2/vulnerabilities/search', params)
end

#status(config_id, scan_id) ⇒ Hash

Retrieves the status of a specific scan.

Parameters:

  • config_id (String)

    the scan configuration ID

  • scan_id (String)

    the scan ID

Returns:

  • (Hash)

    scan status data



88
89
90
91
92
# File 'lib/tenable/resources/web_app_scans.rb', line 88

def status(config_id, scan_id)
  validate_path_segment!(config_id, name: 'config_id')
  validate_path_segment!(scan_id, name: 'scan_id')
  get("/was/v2/configs/#{config_id}/scans/#{scan_id}")
end

#stop_scan(scan_id) ⇒ Hash

Stops a running WAS scan.

Parameters:

  • scan_id (String)

    the scan ID

Returns:

  • (Hash)

    the updated scan status



137
138
139
140
# File 'lib/tenable/resources/web_app_scans.rb', line 137

def stop_scan(scan_id)
  validate_path_segment!(scan_id, name: 'scan_id')
  patch("/was/v2/scans/#{scan_id}", { 'requested_action' => 'stop' })
end

#update_config(config_id, params) ⇒ Hash

Returns the updated configuration data.

Parameters:

  • config_id (String)

    the scan configuration ID

  • params (Hash)

    configuration parameters to update

Returns:

  • (Hash)

    the updated configuration data



56
57
58
59
# File 'lib/tenable/resources/web_app_scans.rb', line 56

def update_config(config_id, params)
  validate_path_segment!(config_id, name: 'config_id')
  put("/was/v2/configs/#{config_id}", params)
end

#vulnerability_details(vuln_id) ⇒ Hash

Retrieves details for a specific WAS vulnerability.

Parameters:

  • vuln_id (String)

    the vulnerability ID

Returns:

  • (Hash)

    vulnerability details



171
172
173
174
# File 'lib/tenable/resources/web_app_scans.rb', line 171

def vulnerability_details(vuln_id)
  validate_path_segment!(vuln_id, name: 'vuln_id')
  get("/was/v2/vulnerabilities/#{vuln_id}")
end

#wait_for_scan_export(scan_id, format:, timeout: DEFAULT_EXPORT_TIMEOUT, poll_interval: DEFAULT_EXPORT_POLL_INTERVAL) ⇒ Hash

Polls until a WAS scan export is ready for download.

Parameters:

  • scan_id (String)

    the scan ID

  • format (String)

    export format — one of “json”, “csv”, “xml”, “html”, or “pdf”

  • timeout (Integer) (defaults to: DEFAULT_EXPORT_TIMEOUT)

    maximum seconds to wait (default: 600)

  • poll_interval (Integer) (defaults to: DEFAULT_EXPORT_POLL_INTERVAL)

    seconds between status checks (default: 5)

Returns:

  • (Hash)

    the final status data when export is ready

Raises:



240
241
242
243
244
245
246
247
# File 'lib/tenable/resources/web_app_scans.rb', line 240

def wait_for_scan_export(scan_id, format:, timeout: DEFAULT_EXPORT_TIMEOUT,
                         poll_interval: DEFAULT_EXPORT_POLL_INTERVAL)
  validate_path_segment!(scan_id, name: 'scan_id')
  poll_until(timeout: timeout, poll_interval: poll_interval, label: "WAS scan export for #{scan_id}") do
    status_data = export_scan_status(scan_id, format: format)
    status_data if status_data['status'] == 'ready'
  end
end

#wait_until_complete(config_id, scan_id, timeout: DEFAULT_SCAN_TIMEOUT, poll_interval: DEFAULT_POLL_INTERVAL) ⇒ Hash

Polls until the scan reaches a terminal status.

Parameters:

  • config_id (String)

    the scan configuration ID

  • scan_id (String)

    the scan ID

  • timeout (Integer) (defaults to: DEFAULT_SCAN_TIMEOUT)

    maximum seconds to wait (default: 3600)

  • poll_interval (Integer) (defaults to: DEFAULT_POLL_INTERVAL)

    seconds between status checks (default: 2)

Returns:

  • (Hash)

    the final scan status data

Raises:



115
116
117
118
119
120
121
122
# File 'lib/tenable/resources/web_app_scans.rb', line 115

def wait_until_complete(config_id, scan_id, timeout: DEFAULT_SCAN_TIMEOUT, poll_interval: DEFAULT_POLL_INTERVAL)
  validate_path_segment!(config_id, name: 'config_id')
  validate_path_segment!(scan_id, name: 'scan_id')
  poll_until(timeout: timeout, poll_interval: poll_interval, label: "WAS scan #{scan_id}") do
    result = status(config_id, scan_id)
    result if TERMINAL_STATUSES.include?(result['status'])
  end
end