Packages
altworx_runbox
21.2.0
25.0.0
24.0.0
23.1.0
23.0.0
22.2.0
22.1.0
22.0.0
21.2.0
21.1.2
21.1.1
21.1.0
21.0.0
20.0.0
19.0.0
18.0.0
17.2.0
17.1.0
17.0.1
17.0.0
16.2.0
16.1.0
16.0.0
15.0.0
14.1.0
14.0.1
14.0.0
13.0.3
13.0.2
13.0.1
13.0.0
12.1.0
12.0.0
11.0.1
11.0.0
10.0.0
9.0.0
8.0.0
7.0.1
7.0.0
6.0.0
5.0.0
4.0.0
3.0.0
2.1.0
2.0.0
1.4.1
1.4.0
1.3.0
1.2.0
1.1.0
1.0.0
0.1.3
0.1.2
0.1.1
0.1.0
Runbox is a library for running Altworx scenarios.
Current section
Files
Jump to
Current section
Files
lib/runbox/runtime/output_action.ex
defmodule Runbox.Runtime.OutputAction do
@moduledoc group: :internal
@moduledoc """
Output Action for internal use by Runtime
"""
alias Runbox.Runtime.OABody
alias Runbox.Scenario.OutputAction, as: ScenarioOA
alias __MODULE__, as: OA
defstruct [:body, :timestamp, :scenario_id, :run_id]
@typedoc "Runtime Output Action"
@type t :: %__MODULE__{
body: ScenarioOA.oa_params() | ScenarioOA.BadOutputAction.t(),
timestamp: integer(),
scenario_id: String.t(),
run_id: String.t()
}
@doc """
Creates a new output action.
To produce a valid output action, the `params` have to be one of the accepted
structs. See the documentation of the particular structs for details.
If the `params` are not one of the accepted structs or some of the fields do
not pass validation, it returns an output action with body set to
`t:Runbox.Scenario.OutputAction.BadOutputAction.t/0` with original params
inside.
"""
@spec new(params :: ScenarioOA.oa_params(), integer(), String.t(), String.t()) :: t()
def new(params, timestamp, scenario_id, run_id) do
if oa_body?(params) and valid_body?(params) do
%OA{body: params, timestamp: timestamp, scenario_id: scenario_id, run_id: run_id}
else
body = %ScenarioOA.BadOutputAction{params: params}
%OA{body: body, timestamp: timestamp, scenario_id: scenario_id, run_id: run_id}
end
end
@doc """
Returns `true` if valid output action.
"""
@spec valid?(OA.t() | any()) :: boolean()
def valid?(%OA{body: body, timestamp: ts, scenario_id: sid, run_id: rid}) do
oa_body?(body) and valid_body?(body) and is_integer(ts) and is_binary(sid) and is_binary(rid)
end
def valid?(_) do
false
end
@doc """
Returns `true` if valid output action body.
"""
@spec oa_body?(ScenarioOA.oa_params() | any()) :: boolean()
def oa_body?(params) do
not is_nil(OABody.impl_for(params))
end
defp valid_body?(params) do
OABody.valid?(params)
end
@doc """
Returns `true` if provided attributes access tags are valid.
"""
@spec attributes_access_tags_valid?(ScenarioOA.access_tags()) :: boolean()
def attributes_access_tags_valid?(access_tags) do
attributes_valid? =
fn access_tags ->
access_tags
|> Map.keys()
|> Enum.all?(fn attribute ->
(is_list(attribute) and Enum.all?(attribute, &is_binary/1)) or
attribute == :all or
is_binary(attribute)
end)
end
tag_definitions_valid? =
fn access_tags ->
access_tags
|> Map.values()
|> Enum.all?(&attribute_tag_definition_valid?/1)
end
is_map(access_tags) and attributes_valid?.(access_tags) and
tag_definitions_valid?.(access_tags)
end
defp attribute_tag_definition_valid?(tag_def) do
(is_list(tag_def) and Enum.all?(tag_def, &(is_binary(&1) and String.trim(&1) == &1))) or
(is_binary(tag_def) and String.trim(tag_def) == tag_def)
end
end
defprotocol Runbox.Runtime.OABody do
@moduledoc false
@spec valid?(t) :: boolean()
def valid?(body)
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.UpsertAssetAttributes do
def valid?(%Runbox.Scenario.OutputAction.UpsertAssetAttributes{
type: type,
id: id,
attributes: attributes,
access_tags: access_tags
}) do
is_binary(type) and
id_valid?(id) and
is_map(attributes) and
Runbox.Runtime.OutputAction.attributes_access_tags_valid?(access_tags)
end
defp id_valid?(id), do: is_binary(id) and not String.contains?(id, "/")
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.DeleteAssetAttributes do
def valid?(%Runbox.Scenario.OutputAction.DeleteAssetAttributes{
type: type,
id: id,
attributes: attributes,
access_tags: access_tags
}) do
is_binary(type) and
is_binary(id) and
is_map(attributes) and
Runbox.Runtime.OutputAction.attributes_access_tags_valid?(access_tags)
end
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.DeleteAllAssetAttributes do
def valid?(%Runbox.Scenario.OutputAction.DeleteAllAssetAttributes{
type: type,
id: id,
access_tags: access_tags
}) do
is_binary(type) and is_binary(id) and
Runbox.Runtime.OutputAction.attributes_access_tags_valid?(access_tags)
end
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.UpsertEdge do
def valid?(%Runbox.Scenario.OutputAction.UpsertEdge{
from_type: from_type,
from_id: from_id,
to_type: to_type,
to_id: to_id,
type: type,
access_tags: access_tags
}) do
is_binary(from_type) and is_binary(from_id) and
is_binary(to_type) and is_binary(to_id) and
is_binary(type) and is_list(access_tags) and
Enum.all?(access_tags, &(is_binary(&1) and String.trim(&1) == &1))
end
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.DeleteEdge do
def valid?(%Runbox.Scenario.OutputAction.DeleteEdge{
from_type: from_type,
from_id: from_id,
to_type: to_type,
to_id: to_id,
type: type,
access_tags: access_tags
}) do
is_binary(from_type) and is_binary(from_id) and
is_binary(to_type) and is_binary(to_id) and
is_binary(type) and is_list(access_tags) and
Enum.all?(access_tags, &(is_binary(&1) and String.trim(&1) == &1))
end
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.Notification do
alias Runbox.Scenario.OutputAction.Notification
alias Runbox.Scenario.OutputAction.Notification.AssetActor
alias Runbox.Scenario.OutputAction.Notification.IncidentActor
def valid?(%Notification{
type: type,
primary_actor: primary_actor,
actors: actors,
aqls: aqls,
priority: priority,
metadata: metadata,
direct_subscriptions: direct_subscriptions,
attachments: attachments,
email_reply_to: reply_to
}) do
type_valid?(type) and
actors_valid?(actors) and
is_map(aqls) and
is_map(metadata) and
priority_valid?(priority) and
direct_subscriptions_valid?(direct_subscriptions) and
primary_actor_valid?(primary_actor) and
attachments_valid?(attachments) and
email_reply_to_valid?(reply_to)
end
defp type_valid?(type), do: is_binary(type) or (is_atom(type) and not is_nil(type))
defp priority_valid?(priority), do: priority in [:low, :medium, :high, "low", "medium", "high"]
defp actors_valid?(actors), do: is_list(actors) and Enum.all?(actors, &ref_valid?/1)
defp direct_subscriptions_valid?(ds), do: is_nil(ds) or is_list(ds)
defp primary_actor_valid?(pa), do: is_nil(pa) or ref_valid?(pa)
defp attachments_valid?(at), do: is_nil(at) or is_list(at)
defp email_reply_to_valid?(rt), do: is_nil(rt) or is_map(rt)
defp ref_valid?(%AssetActor{type: type, id: id}) when is_binary(type) and is_binary(id), do: true
defp ref_valid?(%IncidentActor{type: type, id: id}) when is_binary(type) and is_binary(id),
do: true
defp ref_valid?(_), do: false
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.Event do
alias Runbox.Scenario.OutputAction.Event
def valid?(%Event{
type: type,
template: template,
actors: actors,
incident_actors: incident_actors,
params: params,
origin_messages: origin_messages
}) do
valid_type?(type) and
is_binary(template) and
is_map(actors) and
(is_nil(incident_actors) or is_map(incident_actors)) and
is_map(params) and
is_list(origin_messages)
end
defp valid_type?(type), do: is_binary(type) or (is_atom(type) and not is_nil(type))
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.ExecuteSQL do
alias Runbox.Scenario.OutputAction.ExecuteSQL
def valid?(%ExecuteSQL{
db_connection: db_connection,
sql_query: sql_query,
data: data,
type: type
}) do
is_map(db_connection) and
is_binary(sql_query) and
is_list(data) and
type in [:postgresql, "postgresql"]
end
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.Incident do
alias Runbox.Scenario.OutputAction.Incident
alias Runbox.Scenario.OutputAction.IncidentActor
alias Runbox.Scenario.OutputAction.IncidentFuture
alias Runbox.Scenario.OutputAction.IncidentHistory
def valid?(%Incident{
id: id,
future: future,
history: history,
actors: actors
}) do
id_valid?(id) and
future_valid?(future) and
history_valid?(history) and
actors_valid?(actors)
end
defp id_valid?(id), do: is_binary(id) and not String.contains?(id, "/")
defp future_valid?(future),
do: is_list(future) and Enum.all?(future, &match?(%IncidentFuture{}, &1))
defp history_valid?(history),
do: is_list(history) and Enum.all?(history, &match?(%IncidentHistory{}, &1))
defp actors_valid?(nil), do: true
defp actors_valid?(actors), do: is_list(actors) and Enum.all?(actors, &actor_valid?/1)
defp actor_valid?(%IncidentActor{type: type, id: id}), do: is_binary(type) and is_binary(id)
defp actor_valid?(_actor), do: false
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.IncidentPatch do
alias Runbox.Scenario.OutputAction.IncidentPatch
alias Runbox.Scenario.OutputAction.IncidentActor
alias Runbox.Scenario.OutputAction.IncidentFuture
alias Runbox.Scenario.OutputAction.IncidentHistory
def valid?(%IncidentPatch{
future: future,
history: history,
actors: actors
}) do
future_valid?(future) and
history_valid?(history) and
actors_valid?(actors[:add]) and
actors_valid?(actors[:remove])
end
defp future_valid?(nil), do: true
defp future_valid?(future),
do: is_list(future) and Enum.all?(future, &match?(%IncidentFuture{}, &1))
defp history_valid?(nil), do: true
defp history_valid?(history),
do: is_list(history) and Enum.all?(history, &match?(%IncidentHistory{}, &1))
defp actors_valid?(nil), do: true
defp actors_valid?(actors),
do: is_list(actors) and Enum.all?(actors, &match?(%IncidentActor{}, &1))
end
defimpl Runbox.Runtime.OABody, for: Runbox.Scenario.OutputAction.BadOutputAction do
def valid?(_), do: true
end