Python plugin customize output schema

How do I customize the output schema for a Python 3 plugin step?

That editing must be intended by the plugin author, since not only do the default output steps have a description “Sample output result1 (delete or edit)” but also when I click the Edit button for the Output section…

image

I see:

Power Users Only You can edit the JSON Output Schema by editing it below. This could have an impact on variables used in following steps, so please use with care!

Where is that editing possible? I don’t see any JSON to edit. I’ve even used browser dev tools to see if I can figure out where “below” is, but nada.

Using the dialog below, it’s possible to add new outputs, delete and rename existing ones, as well as change the data type, but how do I edit the description?

image

I suppose I could export the .icon file, edit the output variable descriptions in a text editor, and reload it, but I don’t think that’s what is intended here.

I’ve never been able to edit the output as a JSON, just through the GUI either modifying what is there or adding additional variables. From what I’ve seen though this does not modify the actual output, it is just a JSON template of the returned data for use in following Steps.

1 Like

Huh. Thanks. Reasonable to say it looks like it should be possible though. As I note above, it’s strongly implied more than once in the UI.

Maybe @tyler_terenzoni knows…?

Editing of the output is only possible through the GUI referenced above as @brandon_mcclure stated.

This only involves editing of the output variable names and types though. The descriptions are not editable.

The way this works in practice is you would write your python function to return whatever data you would like to use later in the workflow. You would then use the GUI to update the output of the step to match your returned data from the python function. You can just delete the default values using that GUI. From there, in later steps your new output variables will be available in the variable picker.

1 Like

Thanks. Maybe I was putting 2+2 together and getting 5. It just seems odd to me that the default is two output variables, each with a description like “Sample output result (delete or edit)” which can’t actually be edited. Not a big problem though.

Hi,

Instead of configuring the output schema within the plugin step, I’ve found that the easiest way to use Python output as input in following steps is to create a loop and add your Python 3 plugin step within the loop:
2


Return the GraphQL data you want to use in following steps:

def run(params={}):
    import json
    from falconpy import IdentityProtection
    falcon = IdentityProtection(client_id='{{$workflow.[cs_id]}}',client_secret=secret_key)
    # When default values are provided for all variables, you can call the query without passing any variables.
    idp_query = '''
        query($primaryDisplayNames: [String!] = \"{{["Parse Username"].[output]}}\")
        {entities(primaryDisplayNames: $primaryDisplayNames first:1) {
            nodes {
                primaryDisplayName
                secondaryDisplayName
                riskScoreSeverity 
                riskScore 
                roles {
                    type
                }
                riskFactors {
                    type 
                    score 
                    severity
                }
                accounts {
                    description
                    ... on ActiveDirectoryAccountDescriptor {
                        ou
                        department
                        samAccountName
                    }
                }
                openIncidents(first:5 sortKey:START_TIME sortOrder:DESCENDING) {
                    nodes {
                        type 
                        startTime
                        alertEvents {
                            eventSeverity 
                            startTime 
                            alertType
                        }
                    }
                }
            }
        }}'''
    response = falcon.graphql(query=idp_query)
    r = json.dumps(response)
    rr = json.loads(r)
    return {'idpAzureUser': rr['body']['data']['entities']['nodes'][0]['riskScore'], 'idpAzureSamAcctName': rr['body']['data']['entities']['nodes'][0]['accounts'][0]['samAccountName']}

3


Configure a loop output variable with Output type = array, and Value to include in array = your python step:
4


Exit this loop. Add a new loop and select your output variable you just configured as the variable to repeat over:
5


After running the workflow we can see in the “Loop Output Variables” section the entire output from the Python step. Everything is now available from your Python step as input in following steps:
6


If I want to look at the response headers, I’d access it like this:
7


Instead of returning everything, if I want to return just 2 variables from the Python script: the account’s risk score (idpAzureUser) and SAM account name (idpAzureSamAcctName):

return {'idpAzureUser': rr['body']['data']['entities']['nodes'][0]['riskScore'], 'idpAzureSamAcctName': rr['body']['data']['entities']['nodes'][0]['accounts'][0]['samAccountName']}

Screenshot 2023-02-12 231632
8


I can then use the “idpAzureSamAcctName” loop output variable in my next loop:
9a
9


If I want to grab a failed login count for the SAM account name, I could pass “idpAzureSamAcctName” to another Python step and return a total failed login count:

def run(params={}):
    from falconpy import Discover
    falcon = Discover(client_id='{{$workflow.[cs_id]}}',client_secret=secret_key)
    max_rows = 10
    all_ids = []
    login_ts = '{{["Set Datetime Range - 1"].[date]}}'
    filter_string = "{{["Loop Azure"].[$item].[idpAzureSamAcctName]}}"
    logins_lookup = falcon.query_logins(limit=max_rows,filter=f"username:'{filter_string}'+login_timestamp:>'{login_ts}'")
    if logins_lookup["status_code"] == 200:
        identified_logins = logins_lookup["body"]["resources"]
        if not identified_logins:
            return {'CS_Discover_FailedLogins_Count': 0}
        else:
            logins_detail = falcon.get_logins(ids=identified_logins)["body"]["resources"]
            # loop over the results and append all failed logins to our list
            for login in logins_detail:
                if login["login_status"] == "Failed":
                    all_ids.append(login)
                else:
                    continue
            # return total fail count using the len function
            return {'CS_Discover_FailedLogins_Count': len(all_ids)}
    else:
        error_detail = logins_lookup["body"]["errors"]
        for err in error_detail:
            ecode = err["code"]
            emsg = err["message"]
            return {'ecode': ecode, 'emsg': emsg}

10


There is probably a better way to do all this but this works for me!

Chris

Can you plz tell how to made the connection secret_key. How to hide the keys in python code?
image

If you add the API secret key into the python connection configuration, then you can reference it within a workflow by using the variable “secret_key”.