---
title: "Custom Integration Scripts"
---
<!-- license: community, platform -->

To set up the ((custom integration)) script, you will need to:

1. Write the script.
1. Optionally add credentials.
1. Create an integration task.

## Step 1: Write integration script
The script can be written in [((Starlark))](https://github.com/google/starlark-go/blob/master/doc/spec.md#starlark-in-go-language-definition), a Python-like language with some notable differences:
1. There is no exception handling (`try/catch`)
1. There is no f-string `f'{var}'` formatting - `"{}".format(var)` is the supported method of string interpolation.


### Step 1a: Entrypoint
The ((script)) needs an entrypoint, a function that gets called by the runZero service and returns the Inventory Assets discovered by the script.

1. The entrypoint must accept a variadic `*args` and `**kwargs` for parameters to be passed in.
1. The entrypoint must return a `list` of `ImportAsset`s to be imported.
1. The entrypoint (function name) of the script will default to `main`, but can be set depending on the integration type [scan probe or a connector task](integrations-inbound.md#integration-probe-connector).

```python
load('runzero.types', 'ImportAsset')
def main(*args, **kwargs):
    asset_one = ImportAsset(
            id=1,
            os='custom import os',
            osVersion='0.0.0.0.0.0.1-pre-alphabetazed',
            manufacturer='Name of manufacturer',
            model='Model of asset',
        )
    asset_two = ImportAsset(
            id=2,
            os='custom import os 2',
            osVersion='0.0.0.0.0.0.2-prezed',
            manufacturer='Name of manufacturer',
            model='model of asset',
        )
    return [asset_one, asset_two]
```


## Step 2: Add the custom script Credential to runZero
The credential used for the script is a key-value pair passed into the script function as `kwargs` and can be used as username and password or for anything requiring a secret.

```python
def main(*args, **kwargs):
    client_id = kwargs['access_key']
    client_secret = kwargs['access_secret']
```

1. Go to the [Credentials page](https://console.runzero.com/credentials) in the runZero console and click **Add Credential**.
1. Choose **Custom Script Secret** from the list of credential types.
1. Provide a name for the credential, like `Script Secret` for the service being integrated with.
1. Provide the following information:
    * **Access Key** - The username or client id that will be passed into the script as a `kwargs` named `access_key`.
    * **Access Secret** - The secret that will be passed into the script as a `kwargs` named `access_secret`.
1. If you want other organizations to be able to use this credential, select the _Make this a global credential_ option. Otherwise, you can configure access on a per organization basis.
1. Save the credential.

## Step 3: Create a new task
1. Go to **Tasks**, click the **Integrate** button, and select **Custom Scripts** under **Custom integrations** from the dropdown.
1. Provide a name for the task
1. Select or create a custom integration 
1. Select or create credentials for the script
1. Select an explorer
	* Custom integration scripts must be run on a hosted explorer
1. Select Site, Task description, and Schedule as appropriate.
1. Click Activate Connection to start the task.


## Using the CLI

The `runzero` CLI includes a `script` sub-command to help in writing and debugging Starlark
scripts that use the [runZero Types](custom-integration-scripts.md#runzero-types) and
[Libraries](custom-integration-scripts.md#libraries) outlined below.

### Running scripts

Hello World
```python
def main(*args, **kwargs):
	print("Hello world!")
```
Save the file as `print.star` so it can be run from the CLI

```sh
$ runzero script --filename print.star
Dec 12 12:59:07.099 [INFO] script: Hello world
None
```

Running the script with `args`
```python
def main(*args, **kwargs):
	print("Hello {}".format(args[0]))
```

```sh
$ runzero script --filename print.star --args Dave
Dec 12 13:01:20.707 [INFO] script: Hello Dave
None
```

Running the script with `kwargs`
```python
def main(*args, **kwargs):
	print("Hello {}".format(kwargs["name"]))
```

```sh
runzero script --filename print.star --kwargs name=Dave
Dec 12 13:28:56.933 [INFO] script: Hello Dave
None
```

`args` and `kwargs` can be called multiple times to pass in as many arguments as needed
```python
def main(*args, **kwargs):
	print("{} {}".format(args[0], args[1]))
	print("{} {}".format(kwargs["access_key"], kwargs["access_secret"]))
```

```sh
runzero script --filename print.star --args Hello --args Dave --kwargs access_key=foo --kwargs access_secret=bar
Dec 12 13:45:50.284 [INFO] script: Hello Dave
Dec 12 13:45:50.284 [INFO] script: foo bar
None
```

### REPL
The sub-command `script repl` can be useful for larger scripts with multiple functions.  The REPL will allow setting variables, calling functions, printing variables, and anything else that can be done in Starlark.
```python
runzero script repl --filename print.star
>>> main(*("hello", "dave"), **{"access_key": "foo", "access_secret": "bar"})
Dec 12 14:53:42.384 [INFO] script: hello dave
Dec 12 14:53:42.384 [INFO] script: foo bar
>>> print("Hello {}".format("dave"))
Dec 12 14:57:28.961 [INFO] script: Hello dave
>>> args = ("hello", "dave")
>>> kwargs = {"access_key": "foo", "access_secret": "bar"}
>>> main(*args, **kwargs)
Dec 12 14:58:57.567 [INFO] script: hello dave
Dec 12 14:58:57.567 [INFO] script: foo bar
>>>  
```
`^D` To exit the REPL

## runZero Types
Resource types are implemented in Starlark and are equivalent with the [Python SDK](https://github.com/runZeroInc/runzero-sdk-py) types:
* `load('runzero.types', 'ImportAsset', 'NetworkInterface', 'Service', 'ServiceProtocolData', 'Software', 'Vulnerability')`

The types can be run from the CLI or loaded into the REPL.
```python
runzero script repl --filename print.star
>>> load('json', json_encode='encode', json_decode='decode')
>>> greeter = json_decode('{"greeting":"hello", "name":"dave"}')
>>> print(greeter)
Dec 12 15:13:00.971 [INFO] script: {"greeting": "hello", "name": "dave"}
>>> ^D
```

### Libraries
runZero provides some additional libraries for basic functionality to make web requests.

_Sample usage can be found on the [Starlark library usage examples](custom-integration-starlark-libraries.md) page._

* requests
	* `load('requests', 'Session', 'Cookie')`
	    * `Session(skip_insecure_verify)`
			* `skip_insecure_verify` `bool`
				* Optional: yes
				* Default: `False`
				[InsecureSkipVerify](https://pkg.go.dev/crypto/tls#Config) controls whether a client verifies the server's certificate chain and host name. If `skip_insecure_verify` is `True`, crypto/tls accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to machine-in-the-middle attacks unless custom verification is used. This should be used only for testing or in combination with VerifyConnection or VerifyPeerCertificate.
	    * `Cookie`
* http
	* `load('http', http_post='post', http_get='get', http_patch='patch', http_delete='delete', 'url_encode')`
		* `url_encode({})`
			* Optional: no
			* Default: `{}`
			Key value pairs of url parameters to encode.
		* `post(url, headers, params, body, timeout, insecure_skip_verify)`
			*  `url` `string`
				* Optional: yes
				* Default: `""` (empty String)
				The url to post to.
			* `headers` `dict`
				* Optional: yes
				* Default: `{}`
				Headers to send as part of the request.
			* `params` `dict`
				* Optional: yes
				* Default: `{}`
				URL parameters to add to request.
			* `body` `bytes`
				* Optional: yes
				* Default: None
				Body of the request.
			* `timeout`: `int`
				* Optional: yes
				* Default: 30 seconds
				Timeout in seconds for the maximum the request should take.
			* `insecure_skip_verify` `bool`
				* Optional: yes
				* Default `False`
				[InsecureSkipVerify](https://pkg.go.dev/crypto/tls#Config) controls whether a client verifies the server's certificate chain and host name. If `skip_insecure_verify` is `True`, crypto/tls accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to machine-in-the-middle attacks unless custom verification is used. This should be used only for testing or in combination with VerifyConnection or VerifyPeerCertificate.
		* `get(url, headers, params, timeout, insecure_skip_verify)`
			*  `url` `string`
				* Optional: yes
				* Default: `""` (empty String)
				The url to post to.
			* `headers` `dict`
				* Optional: yes
				* Default: `{}`
				Headers to send as part of the request.
			* `params` `dict`
				* Optional: yes
				* Default: `{}`
				URL parameters to add to request.
			* `timeout`: `int`
				* Optional: yes
				* Default: 30 seconds
				Timeout in seconds for the maximum the request should take.
			* `insecure_skip_verify` `bool`
				* Optional: yes
				* Default `False`
				[InsecureSkipVerify](https://pkg.go.dev/crypto/tls#Config) controls whether a client verifies the server's certificate chain and host name. If `skip_insecure_verify` is `True`, crypto/tls accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to machine-in-the-middle attacks unless custom verification is used. This should be used only for testing or in combination with VerifyConnection or VerifyPeerCertificate.
        * `patch(url, headers, params, body, timeout, insecure_skip_verify)`
			*  `url` `string`
				* Optional: yes
				* Default: `""` (empty String)
				The url to post to.
			* `headers` `dict`
				* Optional: yes
				* Default: `{}`
				Headers to send as part of the request.
			* `params` `dict`
				* Optional: yes
				* Default: `{}`
				URL parameters to add to request.
			* `body` `bytes`
				* Optional: yes
				* Default: None
				Body of the request.
			* `timeout`: `int`
				* Optional: yes
				* Default: 30 seconds
				Timeout in seconds for the maximum the request should take.
			* `insecure_skip_verify` `bool`
				* Optional: yes
				* Default `False`
				[InsecureSkipVerify](https://pkg.go.dev/crypto/tls#Config) controls whether a client verifies the server's certificate chain and host name. If `skip_insecure_verify` is `True`, crypto/tls accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to machine-in-the-middle attacks unless custom verification is used. This should be used only for testing or in combination with VerifyConnection or VerifyPeerCertificate.
        * `delete(url, headers, params, body, timeout, insecure_skip_verify)`
			*  `url` `string`
				* Optional: yes
				* Default: `""` (empty String)
				The url to post to.
			* `headers` `dict`
				* Optional: yes
				* Default: `{}`
				Headers to send as part of the request.
			* `params` `dict`
				* Optional: yes
				* Default: `{}`
				URL parameters to add to request.
			* `body` `bytes`
				* Optional: yes
				* Default: None
				Body of the request.
			* `timeout`: `int`
				* Optional: yes
				* Default: 30 seconds
				Timeout in seconds for the maximum the request should take.
			* `insecure_skip_verify` `bool`
				* Optional: yes
				* Default `False`
				[InsecureSkipVerify](https://pkg.go.dev/crypto/tls#Config) controls whether a client verifies the server's certificate chain and host name. If `skip_insecure_verify` is `True`, crypto/tls accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to machine-in-the-middle attacks unless custom verification is used. This should be used only for testing or in combination with VerifyConnection or VerifyPeerCertificate.
* net
	* `load('net', 'ip_address')`
		* `ip_address`
* json
	* `load('json', json_encode='encode', json_decode='decode')`
		* `encode`
		* `decode`
* time
	* `load('time', 'parse_time')`
		* `parse_time` 
* uuid
	* `load('uuid', 'new_uuid')`
		* `new_uuid`
* gzip
  * `load('gzip', gzip_decompress='decompress', gzip_compress='compress')`
      * `gzip_decompress`
      * `gzip_compress`
* base64
  * `load('base64', base64_encode='encode', base64_decode='decode')`
      * `base64_encode`
      * `base64_decode`
* crypto
  * `load('crypto', 'sha256', 'sha512', 'sha1', 'md5')`
      * `sha256`
      * `sha512`
      * `sha1`
      * `md5`
* flatten
  * `load('flatten_json', 'flatten')`
      * `flatten`


## Existing Custom Integrations

<!-- include customIntegrations-->