rotate_secret
Generated automatically from the published contract sources.
Build metadata: Registered in this build. Registration describes the default dispatcher in this build. It does not guarantee that a caller has the required credential or grant, that a tool is listed for that connection, or that the required service is configured.
A script calls this action over HTTPS at POST https://turnzero.ai/api/v1/actions/rotate_secret, with a bearer credential and the action's payload as the JSON body.
Contract description
Replace a stored secret's value in place, under the same name and scope. This tool takes no value, since a host may record a tool's arguments in its transcript. A call naming a secret name you stored rotates nothing: it answers the state `awaiting_value` with `command`, one line that sends the new value from the developer's machine, and `command_windows`, the same line for Windows. Run the one for your system once, as given, before the answer's `expires_at`.
Name `value_file`, a file on that machine that holds the new value, and your tool can run the line itself; name none, and the builder runs it in a terminal of their own, where the command asks for the value.
Nothing that refers to the name changes. A value an upstream names is used from the gateway's next call. A value the manifest's `settings` bind reaches the container at the environment's next deploy or promote, and at a `restart_application` where the running copy already carries the binding. The restart is a separate call: the line that writes the value can do nothing else.
This tool creates no value: to replace a value `store_secret` created with `generate` by a new created one, store a new name with `generate`, bind the setting (environment variable) to it, and delete the old name.
The `environment` argument chooses the application's environment scope as for `store_secret`. The rest is on the page /cloud/reference/actions/rotate-secret/, which `read_documentation` reads as `page` and the platform's origin serves.
More about this action
The line pipes a short-lived grant for that one write to the turnzero-cloud command, which reads the value on that machine and sends `POST /api/v1/actions/rotate_secret` on the origin this server answers at. The write's answer, which the command prints on its `rotated:` line, names the settings it feeds.
On the development scope alone the wire route also re-mints the two platform-minted credentials, `database-<application id>` and `credential-<application id>`, answering the new value once. For the database name the answer also carries the connection facts and the plan's `connection_limit`. This surface refuses those two names `local_route_required`, because it answers no platform-minted credential value. The line a `submit_manifest` call naming `local_run` answers makes the call on the developer's machine.
The restart is a separate call, `restart_application`, because the line that writes the value runs under a grant that can do nothing else: a copied line could not then make a running application read a value.
Access and action metadata
{
"name": "rotate_secret",
"resource": "secret",
"tier": "reversible",
"clients": [
"bearer",
"browser_session"
],
"summary": "Replace a named value without a code change. The new value travels as `POST /api/v1/actions/rotate_secret` on the origin this server answers at, never as a tool's argument. A call naming a name of your own and no `value`, through a tool or on that route under a bearer credential of your own, rotates nothing. It answers `command`, one line that sends the new value from the developer's machine under a short-lived grant, and `command_windows`, the same line for Windows. Where the running copy of the rotated scope's environment carries a binding of the name, that answer's `next` names the `restart_application` call to make once the line ends 0. The write's answer, which the command prints, names that environment as `restart_environment`, whose copy keeps the previous value until a `restart_application` of it.",
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"openWorldHint": false
}
}
MCP catalog entry
{
"name": "rotate_secret",
"tier": "reversible",
"scenario": "CHI-L0-08",
"summary": "Replace a stored secret's value in place, under the same name and scope. This tool takes no value, since a host may record a tool's arguments in its transcript. A call naming a secret name you stored rotates nothing: it answers the state `awaiting_value` with `command`, one line that sends the new value from the developer's machine, and `command_windows`, the same line for Windows. Run the one for your system once, as given, before the answer's `expires_at`.\n\nName `value_file`, a file on that machine that holds the new value, and your tool can run the line itself; name none, and the builder runs it in a terminal of their own, where the command asks for the value.\n\nNothing that refers to the name changes. A value an upstream names is used from the gateway's next call. A value the manifest's `settings` bind reaches the container at the environment's next deploy or promote, and at a `restart_application` where the running copy already carries the binding. The restart is a separate call: the line that writes the value can do nothing else.\n\nThis tool creates no value: to replace a value `store_secret` created with `generate` by a new created one, store a new name with `generate`, bind the setting (environment variable) to it, and delete the old name.\n\nThe `environment` argument chooses the application's environment scope as for `store_secret`. The rest is on the page /cloud/reference/actions/rotate-secret/, which `read_documentation` reads as `page` and the platform's origin serves.",
"owners": [
"SEC-L0-07",
"SCRT-L0-05",
"SCRT-L0-08",
"MAN-14",
"SEC-L0-20"
]
}
request
| JSON pointer | Description and constraints |
|---|---|
| "" (root) | Type: object Required fields: ["name"] |
| / |
The name of an existing secret. Type: string Pattern: ^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$ |
| / |
The new value. Sent once; never read back. The two platform-minted names on the development scope read none: the platform generates the value and answers it once as `value`. Taken on the HTTP action route alone: the MCP tool declares no `value`. A call naming a name of your own and no `value`, through the MCP tool or on the HTTP route under your own credential, rotates nothing: it answers the state `awaiting_value` and the command that sends the value from your machine. A browser session's call must carry it. Type: string Minimum length: 1 Maximum length: 20000 HTTP action route only, never an MCP tool argument: true |
| / |
Optional, on a call naming a name of your own and no `value` alone: the file on your machine that holds the new value, absolute or relative to the folder the command runs in, which the answered command reads. Absent, the command asks for the value at a terminal. The platform never reads the path. Keep the file outside the application's folder, which a deploy zips, and delete it once the command ends 0. A path holding a control character, a double quote, `$`, a backtick, `%`, `!`, `&`, `|`, `<`, `>`, `^`, a typographic double quote, a doubled backslash, or a trailing backslash is refused `invalid_request`. So is `~` or a path opening with `~/` or `~\`, which no shell expands in double quotes. So is one named beside `value`. Type: string Minimum length: 1 Maximum length: 1024 Pattern: ^(?:[^"$`%!&\|<>^\u201c-\u201e\u0000-\u001f\u007f\\]|\\[^"$`%!&\|<>^\u201c-\u201e\u0000-\u001f\u007f\\])+$ |
| / |
The application id whose scope holds the secret; omitted, the account scope. Type: string |
| / |
Optional, and it rides `application`: the environment whose scope of that application holds the secret, `development` or `production`; absent, `production`. On the development scope alone the two platform-minted names, `database-<application id>` and `credential-<application id>`, are admitted and re-minted, the new value answered once as `value`; on the production scope they are refused `platform_minted_name`. Type: string Pattern: ^(development|production)$ |
response
| JSON pointer | Description and constraints |
|---|---|
| "" (root) | Type: object Required fields: ["contract_version","secret"] |
| / |
Required value: 1 |
| / |
The short reference the platform recorded this call under, ten lowercase hexadecimal characters, the value the call’s record row carries; quote it when reporting the call. Type: string Pattern: ^[0-9a-f]{10}$ |
| / |
Type: object Required fields: ["name","scope","rotated"] |
| / |
Type: string |
| / |
Type: string |
| / |
True on the answer to a call that rotated the value. False with the state `awaiting_value`, where nothing is rotated until the answered command runs. Type: boolean |
| / |
Type: ["string","null"] |
| / |
The environment of the application scope that holds the value; null at the account scope. Type: ["string","null"] |
| / |
Present exactly when a platform-minted name was re-minted on the development scope: the new value, answered once and never read back (SEC-L0-07; DBS-L0-02). Type: string |
| / |
Present on the answer to a call naming a name of your own and no `value` alone: `awaiting_value`. The call rotated nothing and minted a short-lived grant for the one write the answered command makes. Type: string Pattern: ^awaiting_value$ |
| / |
Present with the state `awaiting_value`: when the grant in the command stops serving, as an ISO 8601 instant. A command run after it is refused `secret_grant_expired`, or `authentication_required` once the platform has removed the grant's record, and a new call naming no `value` answers a new one. Type: string |
| / |
Present with the state `awaiting_value`: one line, for macOS and Linux. It reads `echo <grant> | npx -y <origin>/packages/turnzero-cloud-<version>.tgz secret rotate --name <name>`, then `--application <application id> --environment <environment>` where the call named an application, and `--origin <origin>` where the origin is not `https://turnzero\.ai\`\. It ends with `--value-file "<value_file>"`, or with `--value-prompt` where the call named no `value_file`. Run it once, as given, from the folder a relative `value_file` is relative to. The turnzero-cloud command reads the grant on its standard input, reads the value from the file or at the terminal, and sends it once. It ends 0 where the value was written, 2 where that is unknown, and 3 where nothing was written. Its one write spends the grant; a second write under it is refused `secret_grant_spent`, and a write naming another name or scope `secret_grant_not_admitted`. Type: string |
| / |
Present with `command`: the same line for every Windows shell, with `npx.cmd` where its head says `npx`. On Windows, run this one in `command`'s place, once, as given. The two are one command line, so a run of either spends the grant. Type: string |
| / |
Present with the state `awaiting_value` where the tool call's arguments carried a `value`. It says that the platform neither read nor stored that value, that a host may keep a tool call's arguments in its transcript, and that the builder should treat the value as exposed. It names neither the value nor its length. Type: string |
| / |
Present with the state `awaiting_value` where the running copy of the named environment carries a binding of the name. It is the exact `restart_application` call to make once the command ends 0, since that copy keeps the previous value until it restarts (MAN-14; PLD-L0-84). Type: object Required fields: ["action","arguments"] Additional properties: false |
| / |
Required value: restart_application |
| / |
Type: object Required fields: ["application","environment"] Additional properties: false |
| / |
Type: string |
| / |
Type: string Pattern: ^(development|production)$ |
| / |
Type: string |
| / |
$ref: #/shapes/page |
| / |
Present on the wire surface when the re-minted name is the development database credential `database-<application id>`: the development database's connection facts in the shape `submit_manifest` answers them, and the plan's `connection_limit` beside them (DBS-L0-02; DBS-L0-04). From this answer alone a script composes `APP_DATABASE_URL`, with the password in `value`, and writes `APP_DATABASE_CONNECTION_LIMIT`. Never answered on the MCP surface, which refuses the re-mint `local_route_required` (SEC-L0-07). Type: object Required fields: ["host","dbName","roleName","connection_setting","connection_limit"] |
| / |
Type: string |
| / |
Type: string |
| / |
Type: string |
| / |
Required value: APP_DATABASE_URL |
| / |
the plan's served `database-connection-limit` quantity, read at the call: the connections each process holds open at once, the client pool's maximum, never the role's limit of twice it. The local run's line writes it as `APP_DATABASE_CONNECTION_LIMIT`, the setting a deploy, a promote, and a restart inject (DBS-L0-04; PLD-L0-63). Type: integer Minimum: 0 |
| / |
Present where the application's manifest binds the rotated name to settings: the settings it feeds. The new value reaches the container at the environment's next deploy or promote, and at a `restart_application` for a setting the running copy already carries; the running container keeps the previous value until then (MAN-14; SCRT-L0-05). Type: array |
| / |
Type: string |
| / |
Present where the serving row of the one environment whose application scope the rotation wrote binds the name: that environment, whose running copy keeps the previous value until a `restart_application` of it applies the new one (MAN-14; PLD-L0-84). The other environment is never named. Absent at the account scope, which no binding reads, and where only an act in flight binds the name, since a restart is refused while it runs; `read_status`'s `rotated_since_read` answers such a row once it ends. Allowed values: ["development","production"] |
Complete payload contract
{
"request": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"pattern": "^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$",
"description": "The name of an existing secret."
},
"value": {
"type": "string",
"minLength": 1,
"maxLength": 20000,
"x-wire-only": true,
"description": "The new value. Sent once; never read back. The two platform-minted names on the development scope read none: the platform generates the value and answers it once as `value`. Taken on the HTTP action route alone: the MCP tool declares no `value`. A call naming a name of your own and no `value`, through the MCP tool or on the HTTP route under your own credential, rotates nothing: it answers the state `awaiting_value` and the command that sends the value from your machine. A browser session's call must carry it."
},
"value_file": {
"type": "string",
"minLength": 1,
"maxLength": 1024,
"pattern": "^(?:[^\"$`%!&\\|<>^\\u201c-\\u201e\\u0000-\\u001f\\u007f\\\\]|\\\\[^\"$`%!&\\|<>^\\u201c-\\u201e\\u0000-\\u001f\\u007f\\\\])+$",
"description": "Optional, on a call naming a name of your own and no `value` alone: the file on your machine that holds the new value, absolute or relative to the folder the command runs in, which the answered command reads. Absent, the command asks for the value at a terminal. The platform never reads the path. Keep the file outside the application's folder, which a deploy zips, and delete it once the command ends 0. A path holding a control character, a double quote, `$`, a backtick, `%`, `!`, `&`, `|`, `<`, `>`, `^`, a typographic double quote, a doubled backslash, or a trailing backslash is refused `invalid_request`. So is `~` or a path opening with `~/` or `~\\`, which no shell expands in double quotes. So is one named beside `value`."
},
"application": {
"type": "string",
"description": "The application id whose scope holds the secret; omitted, the account scope."
},
"environment": {
"type": "string",
"pattern": "^(development|production)$",
"description": "Optional, and it rides `application`: the environment whose scope of that application holds the secret, `development` or `production`; absent, `production`. On the development scope alone the two platform-minted names, `database-<application id>` and `credential-<application id>`, are admitted and re-minted, the new value answered once as `value`; on the production scope they are refused `platform_minted_name`."
}
}
},
"response": {
"type": "object",
"required": [
"contract_version",
"secret"
],
"properties": {
"contract_version": {
"const": 1
},
"reference": {
"type": "string",
"pattern": "^[0-9a-f]{10}$",
"description": "The short reference the platform recorded this call under, ten lowercase hexadecimal characters, the value the call’s record row carries; quote it when reporting the call."
},
"secret": {
"type": "object",
"required": [
"name",
"scope",
"rotated"
],
"properties": {
"name": {
"type": "string"
},
"scope": {
"type": "string"
},
"rotated": {
"type": "boolean",
"description": "True on the answer to a call that rotated the value. False with the state `awaiting_value`, where nothing is rotated until the answered command runs."
},
"application": {
"type": [
"string",
"null"
]
},
"environment": {
"type": [
"string",
"null"
],
"description": "The environment of the application scope that holds the value; null at the account scope."
}
}
},
"value": {
"type": "string",
"description": "Present exactly when a platform-minted name was re-minted on the development scope: the new value, answered once and never read back (SEC-L0-07; DBS-L0-02)."
},
"state": {
"type": "string",
"pattern": "^awaiting_value$",
"description": "Present on the answer to a call naming a name of your own and no `value` alone: `awaiting_value`. The call rotated nothing and minted a short-lived grant for the one write the answered command makes."
},
"expires_at": {
"type": "string",
"description": "Present with the state `awaiting_value`: when the grant in the command stops serving, as an ISO 8601 instant. A command run after it is refused `secret_grant_expired`, or `authentication_required` once the platform has removed the grant's record, and a new call naming no `value` answers a new one."
},
"command": {
"type": "string",
"description": "Present with the state `awaiting_value`: one line, for macOS and Linux. It reads `echo <grant> | npx -y <origin>/packages/turnzero-cloud-<version>.tgz secret rotate --name <name>`, then `--application <application id> --environment <environment>` where the call named an application, and `--origin <origin>` where the origin is not `https://turnzero.ai`. It ends with `--value-file \"<value_file>\"`, or with `--value-prompt` where the call named no `value_file`. Run it once, as given, from the folder a relative `value_file` is relative to. The turnzero-cloud command reads the grant on its standard input, reads the value from the file or at the terminal, and sends it once. It ends 0 where the value was written, 2 where that is unknown, and 3 where nothing was written. Its one write spends the grant; a second write under it is refused `secret_grant_spent`, and a write naming another name or scope `secret_grant_not_admitted`."
},
"command_windows": {
"type": "string",
"description": "Present with `command`: the same line for every Windows shell, with `npx.cmd` where its head says `npx`. On Windows, run this one in `command`'s place, once, as given. The two are one command line, so a run of either spends the grant."
},
"note": {
"type": "string",
"description": "Present with the state `awaiting_value` where the tool call's arguments carried a `value`. It says that the platform neither read nor stored that value, that a host may keep a tool call's arguments in its transcript, and that the builder should treat the value as exposed. It names neither the value nor its length."
},
"next": {
"type": "object",
"required": [
"action",
"arguments"
],
"properties": {
"action": {
"const": "restart_application"
},
"arguments": {
"type": "object",
"required": [
"application",
"environment"
],
"properties": {
"application": {
"type": "string"
},
"environment": {
"type": "string",
"pattern": "^(development|production)$"
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"description": "Present with the state `awaiting_value` where the running copy of the named environment carries a binding of the name. It is the exact `restart_application` call to make once the command ends 0, since that copy keeps the previous value until it restarts (MAN-14; PLD-L0-84)."
},
"detail": {
"type": "string"
},
"page": {
"$ref": "#/shapes/page"
},
"development_database": {
"type": "object",
"description": "Present on the wire surface when the re-minted name is the development database credential `database-<application id>`: the development database's connection facts in the shape `submit_manifest` answers them, and the plan's `connection_limit` beside them (DBS-L0-02; DBS-L0-04). From this answer alone a script composes `APP_DATABASE_URL`, with the password in `value`, and writes `APP_DATABASE_CONNECTION_LIMIT`. Never answered on the MCP surface, which refuses the re-mint `local_route_required` (SEC-L0-07).",
"required": [
"host",
"dbName",
"roleName",
"connection_setting",
"connection_limit"
],
"properties": {
"host": {
"type": "string"
},
"dbName": {
"type": "string"
},
"roleName": {
"type": "string"
},
"connection_setting": {
"const": "APP_DATABASE_URL"
},
"connection_limit": {
"type": "integer",
"minimum": 0,
"description": "the plan's served `database-connection-limit` quantity, read at the call: the connections each process holds open at once, the client pool's maximum, never the role's limit of twice it. The local run's line writes it as `APP_DATABASE_CONNECTION_LIMIT`, the setting a deploy, a promote, and a restart inject (DBS-L0-04; PLD-L0-63)."
}
}
},
"settings": {
"type": "array",
"items": {
"type": "string"
},
"description": "Present where the application's manifest binds the rotated name to settings: the settings it feeds. The new value reaches the container at the environment's next deploy or promote, and at a `restart_application` for a setting the running copy already carries; the running container keeps the previous value until then (MAN-14; SCRT-L0-05)."
},
"restart_environment": {
"enum": [
"development",
"production"
],
"description": "Present where the serving row of the one environment whose application scope the rotation wrote binds the name: that environment, whose running copy keeps the previous value until a `restart_application` of it applies the new one (MAN-14; PLD-L0-84). The other environment is never named. Absent at the account scope, which no binding reads, and where only an act in flight binds the name, since a restart is refused while it runs; `read_status`'s `rotated_since_read` answers such a row once it ends."
}
}
}
}
Shared contracts
- Refusals: every refusal, by surface, with its cause and its remedy
- schemas/wire_error.schema.json
- schemas/wire_errors.json
- schemas/action_payloads.json (includes shared shapes)
- management_api_contract.md