Cordial Scripting Language
Cordial Scripting Language (CSL) has a syntax vaguely reminiscent of HCL and SQL.
Names
Compared to the URL-friendly names of resources, CSL uses a more human-readable approach
<resource-type-singular> <id> [for <parent-id>] [with <extension-id>]
resource-type-singular
isaddress
,credential
,user
, etc.id
is the resource IDparent-id
is required if the resource is nestedextension-id
is allowed if the resource has extendable names
Examples:
user 19
symbol USDC for SOL
credential 3 for eddie
However, note that when filtering (see List
below), name fields must still be matched against their API form. For example: list users | name = "users/risk-agent"
, or users | name = "*/risk-*"
The singular and plural resource types can be written with or without dashes:
access rule 13
access-rule 13
client key 1
list client keys
(seeList
below)
Get
[get] (<name> | $<variable>)
- specifying the string "get" is optional
name
is the full name of a resource, orvariable
is a variable name (see below), dereferenced with$
Examples:
get user 19
symbol USDC for SOL
get $u
(u
assumed bound user variable)
List
[(get|list)] <resource-type-plural> [for <parent-id>] [ | <filter>]
- specifying one of the strings "get" or "list" is optional
resource-type-plural
isaddresses
,credentials
,users
, etc.parent-id
is allowed if the resource is nested, in which case only resources under the given parent are listedfilter
optionally filters results
The filtering language is an instantiation of API 160 (grammar) and will be documented in more detail.
Examples:
users
addresses for SOL
list roles
operations | request.action = "update" request.resource = "Account"
Create
create [<variant>] <resource-type-singular> [<resource-id>] [for <parent-id>] [with <extension-id>] [ { <data> } ]
resource-type-singular
isaddress
,credential
,user
, etc.variant
is required if the resource has variantsparent-id
is required if the resource is nestedextension-id
is allowed if the resource has extendable namesdata
is an optional TOML inline table (subset of the corresponding resource as per API documentation)
The interpreter hangs until
- either the resource is successfully created (which may require another user to approve),
- or the request fails.
Examples:
create human user
create internal address for SOL
create role fancy-role { credentials = ["cosmos"], users = ["human"] }
create human user fancy-user { roles = ["roles/fancy-role"] }
Note that the data
may contain fields of variables, see below.
Update
update (<name> | $<variable>) <data>
name
orvariable
are full names of resources or variable names, as inGet
data
is a TOML inline table with the new values for fields that are to be changed
The engine currently implements "replace" semantics (as per HTTP PUT
). Here, we implement an equivalent of JSON Merge Patch (RFC 7396). This has the downside that we can't delete fields, as TOML has no null values. In the future, we might implement an equivalent of JSON Patch (RFC 6902) instead.
To avoid the "lost update" problem, the engine requires setting the expected next value of version; this is handled automatically.
Examples:
update user eddie { roles = ["roles/admin"] }
update $us { roles = ["roles/admin"] }
(us
assumed bound user variable)update credential 3 for hilda { notes.description = "The red Solo 2" }
Delete
delete (<name> | $<variable>) <data>
name
orvariable
are full names of resources or variable names, as inGet
andUpdate
Examples:
delete symbol USDC for SOL
delete access rule 123
delete $user
(user
assumed bound user variable)
Variable Assignment
<variable> = ( <name> | <create> )
variable
is a valid identifier (not a reserved keyword). The variable name_
is special, in that it cannot be referenced later.name
is the name of a resource in the form<resource-type-singular> <id> [for <parent-id>] [with <extension-id>]
used in Get.create
is a create command as above
A variable is a binding of an identifier to the name of a resource, either explicitly stated, or as the result of creating a resource (if creation is successful).
Examples:
user1 = create human user
admin1 = user admin-1
Variables may later be used (prefixed by $
) as argument to Get
, or anywhere its name is required.
Example:
addr1 = create internal address for SOL
get $addr1
create internal account warm { addresses = [$addr1] }
The values of the resource corresponding to the variable may also be used wherever such values are required. In this case, the then current value of the resource is used.
Example:
create human user invitee
i1 = create invite client key i1 { code = "1" }
create invite credential for invitee { public_key = $i1.public_key }
Fallible Variable Assignment
<variable>, <err> = ( <create> | <update> | <delete> )
variable
is a valid identifier. The variable name_
is special, in that it cannot be referenced later.err
is a valid identifier. The variable name_
is special, in that it cannot be referenced later.create
is a create command as aboveupdate
is a update command as abovedelete
is a delete command as above
If the mutation fails, err
has a value, and it may be asserted. This is mostly for testing purposes: To prove an operation is denied is to attempt it and fail.
The variable
is only bound if creation succeeds.
Example:
a = create internal address for SOL
b = create internal address for SOL
_, err = create transfer { from = $a, to = $b, asset = "SOL", amount = "1" }
assert err
create allow transfer-rule { asset = "SOL", from = $a, to = $b }
t = create transfer { from = $a, to = $b, asset = "SOL", amount = "1" }
Assertions
assert <error>
error
is a valid identifier
This command fails if error
is not bound to an error.
For Loops
for <variable> in <list> { <command> }
variable
is a valid identifierlist
is a valid list command (potentially filtered)command
is any command, it can make use of the variable
Examples:
for user in users | name = "legacy-machine*" { delete $user }
for address in addresses | variant = "external" { update $address { labels.verified = "false" }}
Settings
set <setting> = <value>
The interpreter has several settings that maybe modified.
Examples:
set sign.with = <client-key>
: theclient-key
will be used in the followingset display.strip = (true|false)
: iftrue
, the create/update times and and states of variables will be suppressed when resources are output