Safety

Dynomate classifies each operation as destructive or not. It asks you before it deletes or truncates a table, or uses a request-defined endpoint. It refuses HTTP to remote endpoints.

These rules add to AWS permissions. A request can do only what its AWS profile permits.

Destructive Operations

A destructive operation can remove or replace data, or it runs statements that DNML cannot analyze. Not destructive does not mean read-only. For example, dynamodb.createTable writes, but it cannot remove data.

For these operations, the resolved values decide:

OperationDestructive ifNot destructive if
dynamodb.put Any other condition, or no condition. The condition is exactly attribute_not_exists(<partition key>) for the partition key of the table.
dynamodb.executeStatement Other statements. The first word is SELECT, in any letter case.
dynamodb.import conflictMode = "overwrite", the default. conflictMode = "skip-existing".
dynamodb.updateTimeToLive ttlEnabled = true, because DynamoDB then deletes expired items. ttlEnabled = false.

This put is not destructive if accountId is the partition key:

[[dynamodb.put]]
name = "Create order"
tableArn = "arn:aws:dynamodb:ap-southeast-2:111122223333:table/Orders"
conditionExpression = "attribute_not_exists(accountId)"

[dynamodb.put.item]
accountId = "account#42"
orderId = "order-1"
  • dynamodb.batchWrite is always destructive, because a put can overwrite an item.
  • athena.query is always destructive, because Dynomate does not parse SQL. IAM permissions and workgroup settings control what a query can do.
  • Dynomate classifies an operation after it applies defaults and templates. For a value from an earlier result, this happens before the AWS call.
  • Each outcome records if the operation was destructive.

The allowDestructive Key

allowDestructive = true only records that the author knows about the destructive operations. It does not change a classification, a confirmation, an approval or a permission. In the app, it is Acknowledge destructive operations.

Confirmation

The app asks for confirmation, and the CLI asks for approval, one time before a request runs if it contains:

Disabled operations, and operations that depend on them, do not count. Item writes, saved-profile endpoints and the profile or region do not need confirmation or approval.

A confirmation or approval applies only to one run of the request, exactly as prepared. If you change the draft, inputs, environments, file or saved profile settings, Dynomate asks again. Dynomate never saves it.

Confirmation and approval do not skip validation, endpoint rules or guards.

In the app, the Confirm request dialog asks. Select Confirm and run to continue. In the CLI, --approval sets when the CLI asks:

  • auto, the default: the CLI asks in the cases above.
  • always: the CLI asks for each valid request.
  • never: the CLI does not ask, and the run counts as approved. Automation uses this value.

Guards

dynamodb.deleteTable and dynamodb.truncate accept a guard. Dynomate checks it before it deletes data:

[[dynamodb.truncate]]
name = "Clear development users"
tableArn = "arn:aws:dynamodb:ap-southeast-2:123456789012:table/Users-dev"
guard = { expectTableName = "Users-dev", expectItemCountAtMost = 100000 }
  • expectTableName must be the same as the resolved table name.
  • expectItemCountAtMost must be equal to or more than the item count that DynamoDB reports.

If a guard fails, the operation fails with DNML_GUARD_FAILED and makes no destructive AWS call. Use a guard when the table ARN comes from a variable or an environment.

Endpoints

By default, an operation uses the standard AWS endpoint of its region. A custom endpoint, such as DynamoDB Local, comes from the request or a saved AWS profile.

[defaults]
profileName = "local"
endpointUrl = "http://localhost:8000"

[[dynamodb.scan]]
name = "All orders"
tableArn = "arn:aws:dynamodb:us-east-1:000000000000:table/Orders"

Precedence

Dynomate uses the first endpoint that is set:

  1. The endpointUrl of the operation.
  2. endpointUrl in [defaults].
  3. The endpoint of the selected AWS profile. See Local profiles.
  4. The standard AWS endpoint.

HTTPS and Loopback

All custom endpoints must obey these rules:

  • The URL uses http or https and has a host name. It has no spaces, credentials or # fragment.
  • HTTPS works for all host names.
  • HTTP works only for localhost, localhost., an IPv4 loopback address such as 127.0.0.1, or ::1. Subdomains such as dynamodb.localhost do not work.

An HTTP endpoint that breaks these rules causes DNML_INSECURE_ENDPOINT. If Dynomate knows the endpoint before the run, no operation runs. If it comes from an earlier result, the operation that uses it fails before it connects.

Request and Saved-Profile Endpoints

  • Request-defined endpoints are in the file, and anyone who edits the file can change them. They need confirmation or approval, also if a saved profile has the same value.
  • Saved profile endpoints come from your AWS profile settings. They do not need confirmation or approval.

The app shows each endpoint and its source under Effective endpoints. The CLI prints them on each run. Each outcome records the endpoint that the operation used.

Athena Query Ownership

An athena.query continues in AWS after Dynomate submits it. The owner of the query decides what Dynomate does on a timeout or a cancellation:

clientRequestTokenOwnerOn timeout or cancellation
Not set Dynomate makes a token, and this run owns the query. After Dynomate knows the query ID, it tries to stop the query.
Set in the file Not known. Another run or tool can use the same token. Dynomate stops the wait. The query continues in Athena.
[[athena.query]]
name = "Nightly rollup"
region = "ap-southeast-2"
database = "commerce"
clientRequestToken = "rollup-2026-09-23"
sql = "INSERT INTO daily_totals SELECT ..."

If Dynomate knows the query ID, the failed outcome gives it in error.details.queryExecutionId. Use it to examine or stop the query in the Athena console.

maxRows limits the rows that Dynomate gets, not the data that Athena scans or the cost of the query.