How to build a Copilot for Security API Plugin – Part 2 (2024)

How to build a Copilot for Security API Plugin – Part II

Copilot for Security (Copilot) is a large language model (LLM) based Generative Artificial Intelligence (GAI) system for cybersecurity, compliance, identity and management use cases. Copilot is not a monolithic system but is an ecosystem running on a platform that allows data requests from multiple sources using a unique plugin mechanism. Plugins allow Copilot to not only reason on data from Microsoft products but also from third-parties.

In part-1 of this series, we discussed building an API plugin using a single GET call. In this article, we expand on Part-I and look at building API plugins that make more advanced GET calls using parameters. If you have not read part-I, we encourage you to do so first, as several parts in this article assumes familiarity with the code and other details that were mentioned in part-I. In this blog, we will only discuss API plugins and more information on the other types of Copilot plugins can be found here.

GET calls with Query Parameters

Let us add another function to the Flask website we had first created in part-I. While we can use any standard application that exposes a REST API, it is easier and clearer from the server-side if we have full control of the REST service. The new function will be used for a GET call that will take in three parameters, two of them in the query and one in the path. A new Class is required to handle this additional data, code for which is given below:

# Use this class to reflect back the parameters passed via GET query class ReflectorJson:     def __init__(self,data,json,ip,useragent‌‌         self.object = "Reflector Json"         self.userdata = data         self.value1 = json["value1"]         self.value2 = json["value2"]         self.sourceip = ip         self.useragent=useragent     def getDict(self‌‌         return self.__dict__ # This method accepts query parameters, passes them to create a ReflectorJson JSON object @app.route('/params/<data>', methods=['GET']) def get_params_data(data‌‌     args = request.args     jsonData = args     obj = ReflectorJson(data,jsonData,request.remote_addr,request.user_agent.string)     response = jsonify(obj.getDict())     return response 

ReflectorJson assigns the passed values to internal properties and returns a dictionary of properties in the ReflectorJson.getDict() function. The dictionary is converted to a JSON by the jsonify() function and returned as a HTTP response. Hence the get_params_data()function returns the JSON serialization of the ReflectorJson object with the serialization including the values passed to it.To better understand the output, let us run this site manually in a local machine. We have bind the webservice to all network interfaces and will run it on port 5000. When we see the following log output in the Python console the webserver is up and ready to service requests.

How to build a Copilot for Security API Plugin – Part 2 (1)

Since we are passing in multiple parameters it will be easier if we use a REST client like Boomerang or Postman. Since Boomerang has an easy-to-use interface available as a plugin for Microsoft Edge we will use that.

In Boomerang, we add the two values (they should be named ‘value1’ and ‘value2’ as the Flask app extracts their value based on these names), and call the path http://127.0.0.1:5000/params/testData, where ‘testData’ is the value that will be assigned to the ‘data’ variable inside the ‘get_params_data’ function.

How to build a Copilot for Security API Plugin – Part 2 (2)

When we send this request, the Flask website returns the response in a JSON which is shown in Boomerang’s Response tab:

How to build a Copilot for Security API Plugin – Part 2 (3)

The variables “userdata”, “value1” and “value2” are the ones explicitly passed by our GET call and reflected back by the Flask webservice. With our REST endpoint now working, we are ready to make a plugin that will make a GET call and pass in the 3 variables. Note that as in part-I, if you intend on using the Flask webservice to test this plugin we must host the Flask website where it’s accessible from the Internet allowing Copilot can communicate with it. This can be done either by hosting the Flask webservice as an Azure App Service, Azure VM or some other means. We can also use other webservices that service GET calls, but make sure to change the plugin YAML files given in next section accordingly.

Plugin YAML files

The main plugin file in YAML format is given below:

#Filename: API_Plugin_Reflection_GET_Params.yaml Descriptor:   Name: Elman's Reflection API plug-in using GET params v1   DisplayName: Elman's Reflection API plug-in using GET params v1   Description: Skills for getting a GET REST API call reflection based on parameters that are passed v1   DescriptionForModel: Skills for getting a GET REST API call reflection based on parameters that are passed. This can be called with a prompt like "Get Elman's Reflection Data for data1 with value1 and value2 SkillGroups:   - Format: API     Settings:       # Replace this with your own URL where the OpenAPI spec file is located.       OpenApiSpecUrl:  http://<URL>/file/API_Plugin_Reflection_OAI_GET_Params.yaml 

We give the plugin a unique name starting with ‘Elman’ in honor of Jeff Elman who designed the first Recurrent Neural Network. The above description will use the OpenAPI specification defined in the file ‘API_Plugin_Reflection_OAI_GET_Params.yaml’.

To generate the OpenAPI specification, we will use the same approach as we did in part-I, which is to use Bing Copilot. However, this time we will give a more detailed prompt which contains the output JSON so Bing Copilot has all the nuanced details to generate the file. The prompt to give Bing Copilot to generate the OpenAPI specification is given below:

Write an OpenAPI spec document that takes a GET call to http://127.0.0.1:5000/params/{data} where {data} is a variable, along with two query parameters value1 and value2, and returns the following JSON output. The JSON schema should be defined in a separate schema section in path /components/schemas/ReflectionDataParamsPluginResponse that is referenced with $ref. JSON schema should only contains the type and description properties for each value:

{

"object": "Reflector Json",

"sourceip": "127.0.0.1",

"useragent": "",

"userdata": "testData",

"value1": "This is Value 1",

"value2": "This is Value 2"

}

Partial output for the above prompt in Bing Copilot is shown below:

How to build a Copilot for Security API Plugin – Part 2 (4)

After copying the above OpenAPI generated file and making slight modifications (mainly in title and description fields) the final OpenAPI specification is given below. We upload this OpenAPI specification in the location specified in the ‘OpenAPISpecURL’ field of the main YAML document. Remember that this location should be publicly accessible over the Internet.

The OpenAPI spec file is given below:

openapi: 3.0.0 info:     title: REST API Reflection using GET params     description: Skills for getting reflection input for a GET REST API call using Params     version: "v1" servers:     # Replace this with your own URL where the OpenAPI spec file is located.     - url: http://172.13.112.25:5000 paths:     /params/{input}:         get:             operationId: ReflectionDataGETParams             summary: A Reflection Data Plugin that reads values from URL Params and returns them             parameters:                 - in: path                   name: input                   schema:                       type: string                   required: true                   description: Parameter Input                 - in: query                   name: value1                   schema:                       type: string                   required: true                   description: Value Parameter 1                 - in: query                   name: value2                   schema:                       type: string                   required: true                   description: Value Parameter 2             responses:                 "200":                     description: OK                     content:                         application/json:                             schema:                                 $ref: "#/components/schemas/ReflectionDataParamsPluginResponse" # This is referred to by $ref components:     schemas:         ReflectionDataParamsPluginResponse:             type: object             properties:                 objecttype:                     type: string                     description: Object type                 userdata:                     type: string                     description: Userdata                 value1:                     type: string                     description: Reflected Parameter 1                 value2:                     type: string                     description: Reflected Parameter 2                 sourceip:                     type: string                     description: The Source IP                 useragent:                     type: string                     description: The User Agent 

With the OpenAPI specification file ready let us now upload the plugin. Click on the sources icon as highlighted in red circle below:

How to build a Copilot for Security API Plugin – Part 2 (5)

In Custom section, select ‘Upload Plugin’:

How to build a Copilot for Security API Plugin – Part 2 (6)

Select the ’Copilot for Security Plugin':

How to build a Copilot for Security API Plugin – Part 2 (7)

After selecting the main YAML file for the plugin, press the ‘Add’ button to complete the upload:

How to build a Copilot for Security API Plugin – Part 2 (8)

Note: If you would like your API custom plugin to be used by others within your tenant, please change the “Who can use this plugin?” from ‘Just Me’ to ‘Everyone’. For more information, see Copilot for Security Authentication.

If the plugin upload is successful, a Plugin added confirmation will be shown. If the plugin fails to upload an error message that may be accompanied by a code will be displayed. Incorrectly formatted YAML files are one of the common causes of error, and if you have an error code more information is available here:

How to build a Copilot for Security API Plugin – Part 2 (9)

Since we have used the Flask API to also serve the OpenAPI specification file we can see the call made by Copilot to download it from the URL given for ‘OpenAPISpecURL’ field, in the server logs.

How to build a Copilot for Security API Plugin – Part 2 (10)

With the plugin uploaded, now it’s time to validate it. When a new plugin is added it is more efficient to invoke its skill directly and manually pass the parameters, rather than giving a prompt and have Copilot parse the prompt (prompt engineering comes into play to make sure correct parameters are extracted from your prompt!).

To invoke a skill directly click on the ‘Prompts’ icon as shown below:

How to build a Copilot for Security API Plugin – Part 2 (11)

A popup comes up showing all Promptbooks and Skills available, select ‘See all system capabilities’ to view all the skills:

How to build a Copilot for Security API Plugin – Part 2 (12)

For API plugins the values specified in the ‘operationId’ and the ‘summary’ or ’description’ fields assigned to each skill (each skill corresponds to a unique REST API endpoint) are displayed in system capabilities. We can search by the 'operationId', which in our case is ‘ReflectionDataGETParams’ as seen in the OpenAPI specification. Searching by the first few keywords brings it up, we then can click on the name.

How to build a Copilot for Security API Plugin – Part 2 (13)

This brings a new window where you can directly enter the values of the parameters that we want to pass to the skill (these values will then be passed to the REST API):

How to build a Copilot for Security API Plugin – Part 2 (14)

After entering the values for the parameters, click the ‘Submit’ button:

How to build a Copilot for Security API Plugin – Part 2 (15)

Copilot will invoke the skill directly and make a REST call with the parameters to our server, which we can verify on the server logs:

How to build a Copilot for Security API Plugin – Part 2 (16)

The REST call will return a JSON similar to the one we get when making the call directly from Boomerang. Copilot formats the JSON in a nicely formed paragraph:

How to build a Copilot for Security API Plugin – Part 2 (17)

Now we invoke the skill via a prompt that contains all the fields required by the API call. The prompt is:

Get reflection data for newTestInput, newParamValue1 and newParamValue2

How to build a Copilot for Security API Plugin – Part 2 (18)

Copilot passes the correct parameter values to the API which we verify in the server:

How to build a Copilot for Security API Plugin – Part 2 (19)

The output JSON is also nicely formatted in bulleted form.

One observation from the previous prompt is that Copilot assigns the parameters values in a sequential order. In the prompt we can also specify the input field each value corresponds with, which leads to a better prompt by removing ambiguity on value assignment (hint: this is prompt engineering!).

In the following prompt, we reverse the order of passing values but have the prompt explicitly specify the value corresponding to each input parameter.

Get reflection data where value2 is newParamValue2, value1 is newParamValue1 and input is TestInput

How to build a Copilot for Security API Plugin – Part 2 (20)

From the prompt output we can see even though TestInput was passed last, it was correctly assigned to the ‘user data’ output variable. We can also verify the order of parameters by looking at the GET call in the server:

How to build a Copilot for Security API Plugin – Part 2 (21)

So far, we have been passing all the required inputs in our prompts. What happens if our prompt does not include all the parameters? Let us run the following prompt in a new session and find out:

Get reflection data for TestInput

How to build a Copilot for Security API Plugin – Part 2 (22)

The above prompt is missing the values for ‘value1’ and ‘value2’, Copilot correctly passes the TestInput value but the values for ‘Value 1’ and ‘Value 2’ are random and obviously not correct. Server log shows the raw GET call.

How to build a Copilot for Security API Plugin – Part 2 (23)

Since we did not specify the 3 parameters that are required by the ‘ReflectionDataGETParams’ skills, Copilot uses other values from the prompt or from the current session to fill those values. In certain cases, it is possible that the skill is not even selected since the number of required inputs are missing.

Note that in this case we ran the prompt in a new session. If we run it in an existing session some of the previous outputs can be inserted in for value1 and value2. This may lead either to a correct or a completely incorrect result depending on what previous values were picked up. This is why prompt engineering is important, as it requires framing the prompt correctly so that required inputs for a skill is present in the prompt or the session.

One way to mitigate arbitrary values to be passed for missing values, is to assign default values for each input.

Using default values for parameters

Copilot for Security allows assignment of a default value and one of the ways to do that is specifying the default value in natural language for the ‘description’ field of the input. To set default values for ‘value1’ we change the description field to ‘Value Parameter 1, default to "Dummy Value 1"’ (original description was ‘Value Parameter 1’). This sets the string “Dummy value 1” as default for ‘value1’, similarly the ‘description’ field for ‘value2’ is ‘Value Parameter 1, default to "Dummy Value 1"’. These are the only changes required and the updated OpenAPI specification file is given below:

openapi: 3.0.0 info:     title: REST API Reflection using GET params     description: Skills for getting reflection input for a GET REST API call using Params     version: "v1" servers:     # Replace this with your own URL where the OpenAPI spec file is located.     - url: http://172.13.112.25:5000 paths:     /params/{input}:         get:             operationId: ReflectionDataGETParams             summary: A Reflection Data Plugin that reads values from URL Params and returns them             parameters:                 - in: path                   name: input                   schema:                       type: string                   required: true                   description: Parameter Input                 - in: query                   name: value1                   schema:                       type: string                   required: true description: Value Parameter 1, default is "Dummy Value 1"                 - in: query                   name: value2                   schema:                       type: string                   required: true description: Value Parameter 2,default is "Dummy Value 2"             responses:                 "200":                     description: OK                     content:                         application/json:                             schema:                                 $ref: "#/components/schemas/ReflectionDataParamsPluginResponse" # This is referred to by $ref components:     schemas:         ReflectionDataParamsPluginResponse:             type: object             properties:                 objecttype:                     type: string                     description: Object type                 userdata:                     type: string                     description: Userdata                 value1:                     type: string                     description: Reflected Parameter 1                 value2:                     type: string                     description: Reflected Parameter 2                 sourceip:                     type: string                     description: The Source IP                 useragent:                     type: string                     description: The User Agent 

Delete the current plugin and reimport it, so the new OpenAPI specification document is used.

How to build a Copilot for Security API Plugin – Part 2 (24)

In a new session, let us give the same prompt as last time, where only one of the three required inputs are specified:

Get reflection data for TestInput

How to build a Copilot for Security API Plugin – Part 2 (25)

The only input present in the prompt is assigned to ‘User Data’ while Value 1 and Value 2 are assigned their respective default values. Server log shows the REST call made with the default values.

How to build a Copilot for Security API Plugin – Part 2 (26)

In this article, we showed how to make GET calls with parameters. So far, we have not discussed making REST API calls with authentication or API and that will be the topic of discussion in part-III, stay tuned.

How to build a Copilot for Security API Plugin – Part 2 (2024)

References

Top Articles
Latest Posts
Article information

Author: Barbera Armstrong

Last Updated:

Views: 6432

Rating: 4.9 / 5 (59 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Barbera Armstrong

Birthday: 1992-09-12

Address: Suite 993 99852 Daugherty Causeway, Ritchiehaven, VT 49630

Phone: +5026838435397

Job: National Engineer

Hobby: Listening to music, Board games, Photography, Ice skating, LARPing, Kite flying, Rugby

Introduction: My name is Barbera Armstrong, I am a lovely, delightful, cooperative, funny, enchanting, vivacious, tender person who loves writing and wants to share my knowledge and understanding with you.