Actions
Actions allow you to define custom self-serve actions, including customizable input fields, that can send payloads from Cortex to any API (internal, external, or webhook). Actions can be tied to entities, or can be standalone. Some example actions you can build are:
- Deploy action that asks the user for target environment and announcement channel, and triggers a build on GitHub for the service
- Bug file action that creates a correctly formatted Jira ticket in the right project
- One-click temporary access token provisioning for devs
- Automatic AWS resource provisioning
Configurations
Admins can create and edit Actions. For the HTTP request, you'll be able to configure the:
- HTTP method
- URL (with templating)
- Headers (this can store secrets/credentials, as we encrypt this header configuration at rest)
- Default Payload (can be templated)
- Response Template
Inputs
You're also able to define an optional list of inputs for the Action that the user will see when executing it.
Inputs can be text inputs, dropdowns, or toggles. You can configure the default value, placeholder, required/optional, and (for text inputs) regex validation.
Filtering
Actions can either be standalone, or connected to entities. If connected to an entity, the action will be executable from the catalog pages for those entities.
For entity-connected actions, you can apply filters to limit which entities the action will show up for.
Permissions
You're also able to configure the access control for who can trigger the action. Regardless of execution permissions, only admins are able to edit the Action configuration, view global execution history, and view decrypted header contents.
Templating
One of the most powerful features of Cortex Actions is their ability to be fully templated.
You can use Mustache templating to access the inputs provided by the user: {{context.inputs.KEY_NAME}}
You can also access your configured secrets by tag: {{context.secrets.SECRET_TAG}}
If the Action is being run in the context of a catalog entity, the template context will also contain data about the entity.
tag
name
descriptor
(this is thecortex.yaml
, as an object)
These can be accessed under the {{context.entity}}
key, for example {{context.entity.tag}}
or {{context.entity.descriptor.info.x-cortex-git.github.repository}}
The context object also has the following keys:
{{context.initiatedAtIso8601Timestamp}}
: The timestamp at which this action was initiated{{context.initiatedBy}}
: The user object of the initiatorrole
: The Cortex role this user is authorized withemail
: The user's email
All of this templating is available for the URL and Payload fields of the Action configuration.
Example Payload:
{
"ref": "{{context.inputs.ref}}",
"auto_merge": "{{context.inputs.merge}}"
}
Under the hood, we use the Java mustache library.
Response template
The response template can reference the body of the response that is returned. The response can be accessed under the {{content.response.body}}
key.
One use of the response body would be to contruct different responses if the Action is successful or not. For example, if you created an Action that used
the Cortex API to update custom data, a successful response would include an attribute named id
that could be accessed at {{context.response.body.id}}
.
Please note that a body in the response is not guaranteed, depending on the endpoint and HTTP status.
Using the Mustache concept of Inverted Sections, you could create different responses in your response template like this:
{{#context.response.body.id}}
Successfully updated custom data.
{{/context.response.body.id}}
{{^context.response.body.id}}
Unable to update custom data.
{{/context.response.body.id}}
Execution
Once you have configured an action, you can run it directly from the Action page, or from the Actions tab in the entity page if it's an entity-connected Action.
Based on your configuration, you'd be asked to
- Select a Catalog Entity if applicable
- Input all the required fields
At this point, just hit the Run Action
button and Cortex will templatize & populate your payload and send the request to the defined URL. You'll be able to see the result directly in the execution modal.
We have a 30 second time out for all Actions.
Execution History
For auditing and debugging purposes, we store the history of all previous Action runs, who ran them, and their HTTP request/responses. You'll be able to see your execution history in the Actions list or the history for a specific Action in the Action page.
Security
Security is a core principle at Cortex and we provide strong security guarantees for Actions.
Everything is encrypted in transit. Headers in the Action configuration, as well as final request/responses post-execution, are encrypted at rest and only visible to admins.
Request Signing
If you're using Actions as a way to trigger hooks into internal tooling, we recommend validating that the request is actually originating from Cortex using request signing.
To get started, you'll need to configure a Signing Secret
under Settings → Secrets in the Request Signing Secret section.
Using this, we add the following headers to each request made by Cortex:
x-cortex-timestamp
(current timestamp is millis, used to prevent replay attacks)x-cortex-signature
x-cortex-signature-256
These headers can be used to verify that the request in-fact is valid and originated from Cortex.
x-cortex-signature
contains the SHA1 hash of the request and exists for backward compatibility. SHA1 has been broken and this signature should be considered deprecated. It is highly recommended to use x-cortex-signature-256
, which contains the SHA256 hash.
To calculate the signature:
1. Create a string with the value "$timestamp.$requestBody" if the request body is non-null OR "$timestamp" if the request body is null.
2. Calculate the SHA256 hash of this string using the Secret you provided to Cortex.
3. Verify that the x-cortex-signature-256 matches sha256=$calculatedSha256