Skip to content

Commit

Permalink
restructured v1 methods
Browse files Browse the repository at this point in the history
  • Loading branch information
walter-iriusrisk committed Nov 22, 2023
1 parent 31387f1 commit 849c570
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 112 deletions.
6 changes: 3 additions & 3 deletions Integrations/ApiShell/MODULE-README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ calls.

For further information, install this module locally and run the following:

python3 -c 'from iriusrisk.v1 import *'
python3 -c 'import iriusrisk.auto_initialize' --help

This describes in greater detail how to call the program shell.

## Usage example
* Create the file main.py file, consisting of the following:
* Create the file main.py, consisting of the following:

import iriusrisk.auto_initialize
from iriusrisk.v1 import *
from iriusrisk.v1.facade import do_get

(resp, json) = do_get("products")
for i in json:
Expand Down
13 changes: 4 additions & 9 deletions Integrations/ApiShell/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,16 @@ you to provide them in a file once across multiple script calls.

For further information, clone this subdirectory and execute the following:

python3 -c 'import iriusrisk.v1' --help
python3 -c 'import iriusrisk.auto_initialize' --help

This describes in greater detail how to call the program shell.

### TODO
* Need to look for ini files in multiple locations
* Need to add a toolkit to ease HTTP calls

This will describe in detail how to call the program shell.

## Usage example
* clone or branch this repository
* Edit the main.py file, appending the following lines to it:
* Create the file main.py, consisting of the following:

from iriusrisk.v1.facade import do_get
import iriusrisk.auto_initialize
from iriusrisk.v1 import *

(resp, json) = do_get("products")
for i in json:
Expand Down
30 changes: 17 additions & 13 deletions Integrations/ApiShell/iriusrisk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,35 @@
import logging
import sys

__all__=["config,parse_arguments,get_commandline_parser"]
__all__=["get_config", "get_commandline_parser", "do_initialization"]

config = None
parse_args_on_load = True
_config_holder = [ None ]

_log = logging.getLogger('iriusrisk')
_parser = iriusrisk.commandline.get_parser()

"""Call this method before loading any sub-modules of iriusrisk. This then
prevents the automatic parsing of the configuration files and command line,
which is normally done following initialization of the sub-modules.
"""
def suppress_parse_args_on_load():
parse_args_on_load = False
def get_config():
if not _config_holder[0]:
raise Exception("Configuration file not initialized. iriusrisk.parse_arguments() must be called first.")

return _config_holder[0]

"""This returns the instance of the argparse class used by this method. Use
this to add needed command line parameters prior to calling parse_arguments().
"""
def get_commandline_parser():
return _parser

"""Parse the command line arguments, and load in any config files. By default,
this method is called after any sub-module of iriusrisk is initialized.
"""Parse the command line and load in any initialization files.
"""
def parse_arguments():
global config
def do_initialization():
global _config_holder
if _config_holder[0]:
_log.info("iriusrisk.parse_arguments() called multiple times")
return

config = _parser.parse_args()
_config_holder[0] = config

if config.verbose:
logging.basicConfig(level=logging.DEBUG)
Expand Down Expand Up @@ -82,6 +84,7 @@ def parse_arguments():
_check_url(config.url)

def _get_url(config_file):
config = get_config()
full_url = _get_item(config_file, config.full_url, "full-url", None)
if full_url:
_log.info("Using the --full-url option. No URL will be derived from domain or subdomain.")
Expand Down Expand Up @@ -116,6 +119,7 @@ def _check_url(url):
_log.warn("You must supply one of subdomain, domain or url on the command line or in the ini file")
_log.warn("Get extended help (--help) from the program for more information")

config = get_config()
if not config.dryrun:
_log.info("Making a call to the given URL as a fail-fast test")
_log.debug("Note that this does not test the security key's validity, but just whether")
Expand Down
6 changes: 6 additions & 0 deletions Integrations/ApiShell/iriusrisk/auto_initialize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Loading this module automatically causes the command line to be parsed and
the initialization files to be loaded.
"""
import iriusrisk

iriusrisk.do_initialization()
3 changes: 3 additions & 0 deletions Integrations/ApiShell/iriusrisk/commandline.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,7 @@ def get_parser():
parser.add_argument("-v", "--verbose", help="Output extended log information", action='store_true')
parser.add_argument("-q", "--quiet", help="Only output log messages indicating errors", action='store_true')
parser.add_argument("--dryrun", help="Do everything but actual HTTP calls", action='store_true')

parser.add_argument("-k", "--key", help="API Key to use when accessing the v1 API")
# parser.add_argument("-t", "--token", help="OAuth2 Token to use when accessing the v2 API")
return parser
99 changes: 89 additions & 10 deletions Integrations/ApiShell/iriusrisk/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,91 @@
"""This module provides helper methods for accessing IriusRisk API version v1.
It also adds the --key command line parser, which expects the IriusRisk v1 API
key as it's argument.
Specific methods for calling into the API are provided in the iriusrisk.v1.facade
module.
"""This module contains helper methods for calling the IriusRisk API.
"""
import iriusrisk

iriusrisk.get_commandline_parser().add_argument("-k", "--key", help="API Token to use when accessing the API")
if (iriusrisk.parse_args_on_load):
iriusrisk.parse_arguments()
import http.client
import json
import logging
from urllib.parse import quote
from iriusrisk import get_config

__all__=["do_get","call_endpoint"]

# Provides helper methods that make accessing the IriusRisk v1 API easier.
_log = logging.getLogger('iriusrisk.v1')

def _build_path(path, encode_path):
if type(path) is str:
if encode_path:
path = path.split("/")
else:
return path

if encode_path:
elements = []

for element in path:
elements.append(quote(element))

path = elements

return "/".join(path)

def call_endpoint(path, verb, headers={}, params={}, convert_response=True, encode_path=False):
"""Call a named endpoint of the IriusRisk API.
Arguments:
path : the endpoint path. May be a collection of strings, each element
another call depth. So to call the URL
"/api/v1/products/:productid/threats," you would pass three
elements in the collection, ["products", f"{productid}", "threats"]
verb : the verb when calling the endpoint, for instance GET, PUT, POST etc
headers : (optional) any headers to include on the call
params : (optional) any parameters to include on the call
convert_response: (default: True): whether the response should be converted to JSON
encode_path : (default: False): whether URL encoding should be applied to the
various elements of the path.
The method returns a tuple containing the HTTP response and data returned as the body
of the response. The type of the data depends on two things. First, if convert_response
is False, plain text is returned. Otherwise, it depends on the return type of the
API call. If (for instance) the return type is "application/json," then a json object
is returned.
"""
path = _build_path(path, encode_path)
_log.info(f"Calling endpoint {path} with verb {verb}")

config = get_config()

if not "api-token" in headers:
if config.key:
headers["api-token"] = config.key
else:
_log.info("No API key was provided to this application; API call will likely fail")

if not "accept" in headers:
headers["accept"] = "application/json"

path = f"/api/v1/{path}"
_log.debug(f"Making a {verb} call to {path} at {config.url}")
conn = http.client.HTTPSConnection(config.url)

if config.dryrun:
resp = None
else :
conn.request(verb, path, params, headers)
resp = conn.getresponse()

result = None
if convert_response and not config.dryrun:
data = resp.read().decode("utf-8")
if resp.status == 200 and headers["accept"] == "application/json":
result = json.loads(data)
else:
result = data

return (resp, result)

"""Call the specified endpoint using "GET."
"""
def do_get(path, headers={}, params={}, convert_response=True, encode_path=False):
"""Call the indicated endpoint via GET. See call_endpoint for more details."""
return call_endpoint(path, "GET", headers, params, convert_response, encode_path)
96 changes: 21 additions & 75 deletions Integrations/ApiShell/iriusrisk/v1/facade.py
Original file line number Diff line number Diff line change
@@ -1,87 +1,33 @@
"""This module contains helper methods for calling the IriusRisk API.
"""This module is deprecated. Use the methods in the iriusrisk.v1 module instead.
"""

import http.client
import json
import iriusrisk
import logging
from urllib.parse import quote
from iriusrisk import config

# Provides helper methods that make accessing the IriusRisk v1 API easier.
_log = logging.getLogger('iriusrisk.v1')
_log = logging.getLogger("iriusrisk.v1.facade")

def _build_path(path, encode_path):
if type(path) is str:
if encode_path:
path = path.split("/")
else:
return path
_deprected_do_get_reported = False
_deprected_call_endpoint_reported = False

if encode_path:
elements = []
_log.warning("""Program is using deprecated module iriusrisk.v1.facade. It needs to use the same-named
methods in iriusrisk.v1 instead. Note that loading this module automatically initializes the application
by loading the init files and parsing the command line arguments.
""")

for element in path:
elements.append(quote(element))
iriusrisk.do_initialization()

path = elements
def do_get(path, headers={}, params={}, convert_response=True, encode_path=False):
global _deprected_do_get_reported
if not _deprected_do_get_reported:
_log.warning("Calling deprecated method iriusrisk.v1.facade.do_get; call iriusrisk.v1.do_get instead")
_deprected_do_get_reported = True

return "/".join(path)
return iriusrisk.v1.do_get(path, headers, params, convert_response, encode_path)

def call_endpoint(path, verb, headers={}, params={}, convert_response=True, encode_path=False):
"""Call a named endpoint of the IriusRisk API.
Arguments:
path : the endpoint path. May be a collection of strings, each element
another call depth. So to call the URL
"/api/v1/products/:productid/threats," you would pass three
elements in the collection, ["products", f"{productid}", "threats"]
verb : the verb when calling the endpoint, for instance GET, PUT, POST etc
headers : (optional) any headers to include on the call
params : (optional) any parameters to include on the call
convert_response: (default: True): whether the response should be converted to JSON
encode_path : (default: False): whether URL encoding should be applied to the
various elements of the path.
The method returns a tuple containing the HTTP response and data returned as the body
of the response. The type of the data depends on two things. First, if convert_response
is False, plain text is returned. Otherwise, it depends on the return type of the
API call. If (for instance) the return type is "application/json," then a json object
is returned.
"""
path = _build_path(path, encode_path)
_log.info(f"Calling endpoint {path} with verb {verb}")

if not "api-token" in headers:
if config.key:
headers["api-token"] = config.key
else:
_log.info("No API key was provided to this application; API call will likely fail")

if not "accept" in headers:
headers["accept"] = "application/json"

path = f"/api/v1/{path}"
_log.debug(f"Making a {verb} call to {path} at {config.url}")
conn = http.client.HTTPSConnection(config.url)
global _deprected_call_endpoint_reported
if not _deprected_call_endpoint_reported:
_log.warning("Calling deprecated method iriusrisk.v1.facade.call_endpoint; call iriusrisk.v1.call_endpoint instead")
_deprected_call_endpoint_reported = True

if config.dryrun:
resp = None
else :
conn.request(verb, path, params, headers)
resp = conn.getresponse()

result = None
if convert_response and not config.dryrun:
data = resp.read().decode("utf-8")
if resp.status == 200 and headers["accept"] == "application/json":
result = json.loads(data)
else:
result = data

return (resp, result)

"""Call the specified endpoint using "GET."
"""
def do_get(path, headers={}, params={}, convert_response=True, encode_path=False):
"""Call the indicated endpoint via GET. See call_endpoint for more details."""
return call_endpoint(path, "GET", headers, params, convert_response, encode_path)
return iriusrisk.v1.call_endpoint(path, verb, headers, params, convert_response, encode_path)
2 changes: 1 addition & 1 deletion Integrations/ApiShell/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ includes=["iriusrisk/"]

[project]
name = "iriusrisk_apishell_v1"
version = "0.3.1"
version = "0.3.2"
authors = [
{ name="Walter Gildersleeve", email="[email protected]"},
]
Expand Down
2 changes: 1 addition & 1 deletion Integrations/OutputLibraryInfo/output-library-info.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
#
# python3 -c 'from iriusrisk.v1 import *' --help
#
import iriusrisk.auto_initialize
from iriusrisk.v1 import *
from iriusrisk.v1.facade import do_get

import datetime
import logging
Expand Down

0 comments on commit 849c570

Please sign in to comment.