diff --git a/content/cli/connect.md b/content/cli/connect.md index 10c7ab4..8dd7d12 100644 --- a/content/cli/connect.md +++ b/content/cli/connect.md @@ -174,10 +174,12 @@ to `/`. The project a command uses comes from, in order: -1. `VOLCANO_PROJECT_ID`, which is deprecated and will be removed in a future +1. `--project `, on `volcano cloud` commands. It applies to that + one command and changes neither the link nor the saved project. +2. `VOLCANO_PROJECT_ID`, which is deprecated and will be removed in a future release. A command that uses it prints a warning on stderr. -2. The directory's link -3. The project `volcano use` saved +3. The directory's link +4. The project `volcano use` saved `volcano use` run inside a linked directory updates the link. Elsewhere it saves the project for every directory without a link. Inside a linked diff --git a/content/cli/functions.md b/content/cli/functions.md index 3667c5a..879842f 100644 --- a/content/cli/functions.md +++ b/content/cli/functions.md @@ -44,6 +44,43 @@ scope it declared, giving it every project variable. With no `volcano-config.yaml` at all there is nothing to declare and deploy runs normally. +## Function layout + +Each supported file or directory directly under `volcano/functions` is one function. +Names starting with `_`, such as `_lib/`, hold shared code that every function +archive includes. + +| Entry | Function | Entry file | +|---|---|---| +| `hello.js`, `hello.mjs`, `hello.py`, `hello.rb` | `hello` | the file itself | +| `hello.ts`, `hello.mts`, `hello.cts` | `hello` | the file itself, compiled by Volcano | +| `checkout/` | `checkout` | `index.js`, else `main.py` or `main.rb`, else `index.cts`, `index.mts` or `index.ts`, the first found | + +### TypeScript + +The CLI uploads a TypeScript handler as source, and Volcano compiles it to +JavaScript during the build, in the cloud and in local mode: + +- Types are removed without being checked, so a type error doesn't fail the + deploy. Run `tsc --noEmit` in your own CI to catch type errors. +- `.mts` compiles to an ES module and `.cts` to CommonJS. `.ts` is an ES module + when the function's `package.json` sets `"type": "module"`, CommonJS otherwise. +- Imports through `paths` in a `tsconfig.json` inside the function's directory + resolve. Packages from `package.json` load from the installed dependencies. +- TypeScript never changes what an existing function deploys: `hello.js` or + `hello.py` beside `hello.ts` or `hello/index.ts`, or `checkout/index.js`, + `index.mjs`, `index.cjs`, `main.py` or `main.rb` beside `checkout/index.ts`, + deploys that file instead. A `hello/` directory beside `hello.ts` deploys the + directory. +- Two TypeScript files with one name and no JavaScript, such as `hello.ts` and + `hello.mts`, stop the deploy until you keep one. +- `.tsx` and declaration files such as `types.d.ts` aren't functions. A + directory needs its handler at its top, such as `checkout/index.ts`, not + `checkout/src/index.ts`. + +See [TypeScript](/platform/functions/creating-functions#typescript) for how the +build compiles it. + ## CLI operations | Operation | Command | diff --git a/content/cli/index.md b/content/cli/index.md index 6538e87..abab5a8 100644 --- a/content/cli/index.md +++ b/content/cli/index.md @@ -146,6 +146,19 @@ suggests `volcano projects create `. Inside a directory linked with `volcano connect`, commands use the linked project. See [connect.md](connect.md#linked-directories). +To run one `volcano cloud` command against another project, pass +`--project `. Every `volcano cloud` subcommand accepts it, and it +leaves the active project and any link unchanged: + +```bash +volcano cloud functions list --project my-app +volcano cloud lavaflow status --project eac37d5a-5f6f-42d8-acf6-0f2ae9c7a550 +``` + +`--project` takes an exact project name or ID, like `volcano use`. A project +it does not find fails the command before it runs, and exits `4`. Local +commands refuse `--project`: local development has one project. + ### Create a project from a cloud template Use `--template` to install a complete app in a new cloud project: diff --git a/content/cli/scripting.md b/content/cli/scripting.md index 86ea5a3..644282b 100644 --- a/content/cli/scripting.md +++ b/content/cli/scripting.md @@ -21,6 +21,22 @@ failures apart without parsing the error text. process's exit code instead, and `124` on timeout. See [sandboxes.md](sandboxes.md). +## Choose the project per command + +`volcano cloud` commands take `--project ` to run against a project +for that one command, without changing the active project. A script or agent +can check several projects in a row without `volcano use` between them: + +```bash +for project in app-staging app-production; do + volcano cloud lavaflow status --project "$project" --json +done +``` + +A project `--project` does not find exits `4`. See +[connect.md](connect.md#linked-directories) for how the CLI picks a project +otherwise. + ## JSON output Commands that support `--json` print machine-readable JSON on stdout. These diff --git a/content/platform/api-reference/functions.md b/content/platform/api-reference/functions.md index 8ab8047..127a871 100644 --- a/content/platform/api-reference/functions.md +++ b/content/platform/api-reference/functions.md @@ -135,7 +135,7 @@ Direct API clients may upload ZIP or `tar.gz`; the API stores a normalized `tar. After dependencies are installed and the final image is built, the build rejects an image larger than 4096 MB. -For direct API uploads, Volcano generates `.volcano/function-build.json` automatically. It infers `function_root` from the single runtime entry file (`index.js`/`index.mjs`, `main.py`, or `main.rb`), or from the only top-level directory when the archive has one. A Node.js archive with no JavaScript entry counts `index.ts`, `index.mts` and `index.cts` instead, unless the root found without them already holds the handler as `index.cjs`, an extensionless `index` file or an `index` directory holding a `package.json` or an index file, the `handler` names its own module (such as `src/handler.main`), or the project sets `NODE_PATH`. It selects `install_root` from the closest dependency manifest directory containing the effective handler module, relative to `function_root`. When no manifest contains the module and `function_root` is `.`, the fallback selects the longest nested manifest directory path. With no containing manifest or applicable fallback, installation uses `function_root`. See [direct-upload layout inference](../functions/upload-api.md#direct-upload-layout-inference) for handler resolution and tie-breaking. +For direct API uploads, Volcano generates `.volcano/function-build.json` automatically. It infers `function_root` from the single runtime entry file (`index.js`/`index.mjs`, `main.py`, or `main.rb`), or from the only top-level directory when the archive has one. A Node.js archive with no JavaScript entry counts `index.ts`, `index.mts` and `index.cts` instead, unless the root found without them already holds the handler as `index.cjs`, an extensionless `index` file or an `index` directory holding a `package.json` or an index file, the `handler` names its own module (such as `src/handler.main`), or the project's `NODE_PATH` names a directory inside the function, where the handler could load from after the install. A `NODE_PATH` that names only directories outside the function doesn't count. It selects `install_root` from the closest dependency manifest directory containing the effective handler module, relative to `function_root`. When no manifest contains the module and `function_root` is `.`, the fallback selects the longest nested manifest directory path. With no containing manifest or applicable fallback, installation uses `function_root`. See [direct-upload layout inference](../functions/upload-api.md#direct-upload-layout-inference) for handler resolution and tie-breaking. **Runtimes** ([List Runtimes](#list-runtimes) returns the current set): @@ -488,6 +488,35 @@ refused one deploys nothing. > forwards requests with no credential, and `http` + `none` serves its DNS > endpoint without a token. +## Previews + +A preview (the API calls it a Candidate) is a copy of an ordinary function +built from an uploaded source with the function's variables, run on its own +runtime and invoked at `https://.` with the +project's service key only, whatever the function's visibility. See +[Function previews](../functions/previews.md). + +| Method | Path | What it does | +| -------- | ---------------------------------------------------------------------------- | ------------------------------------------------------ | +| `GET` | `/projects/{id}/functions/{functionId}/candidates` | List previews with their latest deployment | +| `POST` | `/projects/{id}/functions/{functionId}/candidates` | Create a preview from `name`, `code` and `ttl_seconds` | +| `GET` | `/projects/{id}/functions/{functionId}/candidates/{candidateId}` | Read one preview | +| `DELETE` | `/projects/{id}/functions/{functionId}/candidates/{candidateId}` | Delete a preview | +| `GET` | `/projects/{id}/functions/{functionId}/candidates/{candidateId}/deployments` | List a preview's deployments | +| `POST` | `/projects/{id}/functions/{functionId}/candidates/{candidateId}/deployments` | Deploy new `code` to a preview | +| `POST` | `/projects/{id}/functions/{functionId}/candidates/{candidateId}/promote` | Point the function's traffic at the preview's runtime | +| `GET` | `/projects/{id}/functions/{functionId}/serving` | Read what the function runs | +| `POST` | `/projects/{id}/functions/{functionId}/serving/rollback` | Roll back, or with `to_production` return to its build | + +Promote and rollback require the `expected_revision` read from `serving` and +answer `200` once the pointer moved; nothing is deployed. Delete answers `202` +with no body. Creating, deploying to and promoting answer `404` with code +`feature_unavailable` while the `functions.candidates` capability is +unavailable. Refusals answer `409` with the codes listed in the +[guide](../functions/previews.md#error-codes). Fields that do not apply yet, +such as a preview's `url` before its first deployment, are absent. A function's +`serving_candidate_id` is the preview it runs, or null. + ## Function Status - `provisioning` - Being deployed @@ -498,6 +527,8 @@ Useful deployment fields in responses: - `invoke_url` - canonical DNS invoke URL for this function - `deployed_regions` - regions where the function is currently deployed +- `serving_candidate_id` - the promoted preview whose runtime receives the + function's traffic, or null while it runs its own build ## See Also diff --git a/content/platform/api-reference/openapi.yaml b/content/platform/api-reference/openapi.yaml index 745824b..d9d9c55 100644 --- a/content/platform/api-reference/openapi.yaml +++ b/content/platform/api-reference/openapi.yaml @@ -2526,9 +2526,11 @@ paths: Volcano app is installed in: it is listed to the person who installed it there, and to anyone with a Slack identity in that workspace connected to their Volcano account. Add one with - `POST /user/slack/installations`. The list answers whether or not - reporting problems from Slack is available in this environment, so - turning it off strands no connector. + `POST /user/slack/installations`. An `aikido` connector is an Aikido + workspace the caller connected with `POST /connectors`; it holds their + Aikido credentials, so it is listed to them alone. The list answers + whether or not reporting problems from either service is available in + this environment, so turning it off strands no connector. operationId: listConnectors security: - UserToken: [] @@ -2546,6 +2548,83 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + post: + tags: + - Connectors + summary: Connect a service + description: | + Connects an outside service with credentials the caller created there, + and answers `201` with the connector. Today that is an `aikido` + workspace, so LavaFlow can fix the security issues Aikido finds on the + caller's projects. Install the Volcano Slack app with + `POST /user/slack/installations` instead: it needs the browser. + + For Aikido, create a REST API client in Aikido's settings with read + access to issues, repositories and the workspace, and a webhook + signing secret on its webhooks page. Volcano checks the client with + Aikido, reads which workspace it belongs to, and stores all three + values encrypted; it never returns them. Then point an Aikido webhook + for new issues at `https:///webhooks/aikido`, and bind + projects with `POST /lavaflow/connector-bindings`. Volcano writes + nothing back to Aikido. A workspace connects to one Volcano account at + a time. + + Connecting Aikido needs LavaFlow and Aikido reports to be available in + this environment, as the `lavaflow.aikido` capability reports; + otherwise this answers `404` with code `feature_unavailable`. + operationId: createConnector + security: + - UserToken: [] + - AuthUserAccessToken: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ConnectorCreate' + responses: + '201': + description: The service is connected + content: + application/json: + schema: + $ref: '#/components/schemas/Connector' + '400': + description: The body is invalid + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Code `feature_unavailable` means Aikido reports are not available in this environment. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: The Aikido workspace is already connected, by the caller or another Volcano account. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '422': + description: Aikido refused the client ID and secret, or the client cannot read the workspace. Check the region, the credentials and the client's read access. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '502': + description: Aikido did not answer; nothing was saved, so try again + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /connectors/{connector_id}: get: tags: @@ -2598,8 +2677,13 @@ paths: Slack. The workspace's channels stop reporting problems at their next check, which also cancels reports still queued. The channel bindings stay, and report again if the app is installed in the workspace again. - It works whether or not reporting problems from Slack is available in - this environment. + + Removing an `aikido` connector deletes its credentials and its project + bindings, and cancels its queued reports at their next check. Remove + the webhook in Aikido too: Volcano refuses its deliveries from then on. + + Removing works whether or not reporting problems from either service + is available in this environment. operationId: deleteConnector security: - UserToken: [] @@ -3465,6 +3549,12 @@ paths: pattern: ^[a-f0-9]{64}$ description: SHA-256 of the sorted unique current shared names joined by a newline. Use instead of expected_shared_variables for a compact conditional replacement. responses: + '200': + description: 'Shared list replaced and synchronization started for every affected function except the ones listed, which a promoted preview serves (`code: function_served_by_candidate`). The preview keeps the variables it was built with, so their variables were not synchronized; a rollback of a listed function to production synchronizes its own build, and so does deploying it.' + content: + application/json: + schema: + $ref: '#/components/schemas/SharedVariablesReplaceResult' '204': description: Shared list replaced and affected function synchronization started. '400': @@ -3656,7 +3746,11 @@ paths: `missing`. Validation failures (including plan-gate violations) return 422 and nothing is applied. Set `dry_run=true` to get the projected report without applying changes. Applies are serialized per project; - a concurrent apply returns 409. + a concurrent apply returns 409. A function a promoted preview serves + keeps the variables the preview was built with: when the apply's + variable changes would reach it, it is reported as `unchanged` with + `code: function_served_by_candidate` and a `notice`, while every other + resource is applied and synchronized. That entry is not an error. operationId: applyProjectConfig security: - UserToken: [] @@ -3864,7 +3958,7 @@ paths: The source has already been exported, the repository has already taken over as the source of truth, the confirmed production branch or repository is stale, a function or frontend deployment is still in progress, - a preview is serving one of the project's frontends, or the project + a promoted preview is serving one of the project's functions or frontends, or the project has no stored source to export content: application/json: @@ -6152,8 +6246,8 @@ paths: of `public` or out of HTTP invocation mode. The request is refused before the deploy starts, so nothing is deployed. The message `project variables changed during the upload; retry` means - `NODE_PATH` was created or deleted while the upload was processed; - send the same request again. + `NODE_PATH` was created, changed or deleted while the upload was + processed; send the same request again. content: application/json: schema: @@ -7410,8 +7504,8 @@ paths: function cannot change kind — or the project's source is managed by Git, where deploys come from a push to the production branch. The message `project variables changed during the upload; retry` means - `NODE_PATH` was created or deleted while the upload was processed; - nothing was deployed, so send the same request again. + `NODE_PATH` was created, changed or deleted while the upload was + processed; nothing was deployed, so send the same request again. content: application/json: schema: @@ -7844,6 +7938,636 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /projects/{id}/functions/{functionId}/candidates: + get: + tags: + - Functions + summary: List a function's previews + description: | + Returns the function's previews, oldest first, each with its latest deployment. A function has at most + 20 live previews. Reading never depends on the `functions.candidates` capability. A durable function has no previews: reading its previews answers an empty list, and reading its serving state answers its own build. + operationId: listFunctionCandidates + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + responses: + '200': + description: The function's previews + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionCandidateList' + '400': + description: Bad request - invalid identifier + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + tags: + - Functions + summary: Create a function preview + description: | + Builds the uploaded source with the function's runtime, handler and variables, and deploys it to a + runtime of its own in every region the function deploys to. The preview is invoked at + `https://.` and is always private, whatever the function's own + visibility: only the project's service key, with `functions.invoke`, can invoke it, and signed-in + users, anon keys and access tokens are refused. It gets none of the function's schedules or warmers. + The response is `202` while the first deployment runs; read the preview for its `status` and `url`. + + While the `functions.candidates` capability is unavailable, including on the local development server, it answers `404` with code `feature_unavailable`. Reading and deleting existing previews, and rolling the function back to its own build, keep + working. + + A preview builds like any deploy and spends the project's build minutes. A function has at most 20 + live previews, and each name is unique within the function. Without `ttl_seconds` a preview is kept + until it is deleted. Durable functions have no previews. + operationId: createFunctionCandidate + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: + - name + - code + properties: + name: + type: string + minLength: 1 + maxLength: 128 + description: Names the preview within the function. Cannot be `production`. + ttl_seconds: + type: integer + minimum: 1 + maximum: 2592000 + description: Deletes the preview this many seconds after it is created, at most 30 days. Omit to keep it until deleted. + code: + type: string + format: binary + description: The function's source archive, as for deploying the function. Built with the function's runtime and handler. + responses: + '202': + description: Preview created; its first deployment is running + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionCandidate' + '400': + description: Bad request - invalid name, expiry, identifier or source archive, or a variable the source reads has no value the function can give it + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function not found, or the capability is unavailable (code `feature_unavailable`) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: 'Conflict. `code: durable_function_unsupported` - the function is durable. `code: candidate_name_taken` - the function has a preview with this name. `code: candidate_limit_reached` - the function has the maximum previews. `code: function_deleting` or `code: project_deleting` - the function or project is being deleted.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '413': + description: Request body exceeds the function source archive limit + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '429': + description: Too many requests - the project's build minutes for the billing cycle are used up (code `build_minutes_exceeded`) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '503': + description: Service unavailable - function deployments are not configured + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/functions/{functionId}/candidates/{candidateId}: + get: + tags: + - Functions + summary: Get a function preview + description: | + Returns the preview with its latest deployment. Never depends on the `functions.candidates` capability. + operationId: getFunctionCandidate + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + - $ref: '#/components/parameters/FunctionCandidateId' + responses: + '200': + description: The preview + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionCandidate' + '400': + description: Bad request - invalid identifier + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function or preview not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + tags: + - Functions + summary: Delete a function preview + description: | + Starts removing the preview's runtime, URL, builds and stored source once any running deployment + finishes; the preview reads `deleting` until that is done, and answers `404` once it is gone. Asking + again for a preview that is already being deleted is the same request. + + A preview the function runs cannot be deleted: roll back first. Deleting one the function only keeps + for a rollback gives that rollback up; the function's own build stays one `to_production` rollback + away. Never depends on the `functions.candidates` capability. + operationId: deleteFunctionCandidate + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + - $ref: '#/components/parameters/FunctionCandidateId' + responses: + '202': + description: Deletion started + '400': + description: Bad request - invalid identifier + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function or preview not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: '`code: candidate_in_use` - the function runs this preview; roll it back first.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/functions/{functionId}/candidates/{candidateId}/deployments: + get: + tags: + - Functions + summary: List a function preview's deployments + description: | + Returns the preview's deployments, newest first, at most 100. Never depends on the + `functions.candidates` capability. + operationId: listFunctionCandidateDeployments + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + - $ref: '#/components/parameters/FunctionCandidateId' + responses: + '200': + description: The preview's deployments + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionCandidateDeploymentList' + '400': + description: Bad request - invalid identifier + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function or preview not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + tags: + - Functions + summary: Deploy new source to a function preview + description: | + Builds the uploaded source and deploys it to the preview, which keeps serving its previous + deployment until this one succeeds. A preview takes one deployment at a time, and one the function + runs, or keeps for a rollback, takes none. While the `functions.candidates` capability is unavailable, including on the local development server, it answers `404` with code `feature_unavailable`. + + A deployment builds like any deploy and spends the project's build minutes. + operationId: redeployFunctionCandidate + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + - $ref: '#/components/parameters/FunctionCandidateId' + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: + - code + properties: + code: + type: string + format: binary + description: The function's source archive, as for deploying the function. Built with the function's runtime and handler. + responses: + '202': + description: The deployment is running + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionCandidateDeployment' + '400': + description: Bad request - invalid identifier or source archive, or a variable the source reads has no value the function can give it + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function or preview not found, or the capability is unavailable (code `feature_unavailable`) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: 'Conflict. `code: durable_function_unsupported` - the function is durable. `code: deployment_in_progress` - a deployment of the preview is running; retry once it finishes. `code: candidate_not_deployable` - the preview is being deleted. `code: candidate_in_use` - the function runs this preview or keeps it for a rollback. `code: function_deleting` - the function is being deleted.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '413': + description: Request body exceeds the function source archive limit + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '429': + description: Too many requests - the project's build minutes for the billing cycle are used up (code `build_minutes_exceeded`) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '503': + description: Service unavailable - function deployments are not configured + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/functions/{functionId}/candidates/{candidateId}/promote: + post: + tags: + - Functions + summary: Promote a function preview + description: | + Points the function's traffic at the preview's runtime. Nothing is deployed or rebuilt, so it + takes effect at once: every call to the function, through its own URL, the invoke route, a + schedule or a frontend route, runs the preview's code, while the function keeps its ID, URL, + visibility, schedules, metering and logs. The function's own build is kept as it is for a + rollback, and what the function ran becomes what a rollback returns to. + + The preview must be serving a successful deployment built with the variables, runtime and handler + the function has now, in every region the function deploys to, and the function must have a + successful deployment of its own. It is refused while a deployment of the function, or a + synchronization of its variables, runs. Promotion names the `revision` the caller read from + `serving`; a competing promotion or rollback makes it fail with `409`. Once the project's + repository is the source of truth, promotion is refused with `409`, as a direct deploy is. + While the `functions.candidates` capability is unavailable, including on the local development server, it answers `404` with code `feature_unavailable`. + operationId: promoteFunctionCandidate + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + - $ref: '#/components/parameters/FunctionCandidateId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionPromotionRequest' + responses: + '200': + description: The function's traffic now runs on the preview + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionServing' + '400': + description: Bad request - invalid identifier or body + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function or preview not found, or the capability is unavailable (code `feature_unavailable`) + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: 'Conflict. `code: durable_function_unsupported` - the function is durable. `code: stale_revision` - the revision is stale; read `serving` again. `code: already_serving` - the function already runs this preview. `code: candidate_not_ready` - the preview serves no successful deployment, or its latest redeploy failed; redeploy it successfully first. `code: configuration_changed` - the preview was built with other variables, runtime or handler than the function has now; redeploy it. `code: candidate_regions_changed` - the function deploys to a region the preview was not built in; redeploy it. `code: deployment_in_progress` - a deployment of the preview or of the function, or a synchronization of the function''s variables, is running; retry once it finishes. `code: function_not_deployed` - the function has no successful deployment of its own to roll back to. `code: function_deleting` - the function is being deleted. `code: source_managed_by_git` - the project''s repository is the source of truth; deploy from it.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '413': + description: The request body is larger than 4 KiB + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/functions/{functionId}/serving: + get: + tags: + - Functions + summary: Get what a function runs + description: | + Returns whether the function runs its own build or a promoted preview's, what a rollback returns + to, and its latest promotion or rollback. Never depends on the `functions.candidates` capability. + A durable function always runs its own build. + operationId: getFunctionServing + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + responses: + '200': + description: What the function runs + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionServing' + '400': + description: Bad request - invalid identifier + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: Function not found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /projects/{id}/functions/{functionId}/serving/rollback: + post: + tags: + - Functions + summary: Roll back what a function runs + description: | + Points the function's traffic back at what served it before its last promotion or rollback, or at + its own build with `to_production`. A rollback is a new activation, so what it leaves becomes what + a further rollback returns to, and it can itself be undone. Nothing is deployed, so it takes effect + at once. It names the `revision` the caller read; a competing activation makes it fail with `409`. + + Rolling back to a preview promotes it again and is refused with `409` when promoting it would be, + and with `404` code `feature_unavailable` while the capability is unavailable. Rolling back to the + function's own build is not: it never depends on the capability, the project's source mode, or a + running deployment of the function. + operationId: rollbackFunctionServing + security: + - UserToken: [] + - ProjectAccessToken: [] + parameters: + - $ref: '#/components/parameters/ProjectId' + - $ref: '#/components/parameters/FunctionId' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionRollbackRequest' + responses: + '200': + description: The function's traffic now runs on what it was rolled back to + content: + application/json: + schema: + $ref: '#/components/schemas/FunctionServing' + '400': + description: Bad request - invalid identifier or body + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized - invalid or missing token + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Forbidden - project ownership required + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: 'Function not found, or `code: feature_unavailable` while the `functions.candidates` capability is unavailable and the rollback would make a preview serve again' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '409': + description: 'Conflict. `code: durable_function_unsupported` - the function is durable. `code: stale_revision` - the revision is stale; read `serving` again. `code: nothing_to_roll_back` - the function runs its own build and keeps no preview to return to. `code: rollback_unavailable` - the preview to roll back to is gone or serves no successful deployment. `code: function_not_deployed` - the function has no successful deployment of its own. `code: function_deleting` - the function is being deleted. A rollback to a preview is also refused like a promotion: `code: candidate_not_ready`, `code: configuration_changed`, `code: candidate_regions_changed`, `code: deployment_in_progress` and `code: source_managed_by_git`.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '413': + description: The request body is larger than 4 KiB + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /projects/{id}/durable-functions: get: tags: @@ -8020,8 +8744,9 @@ paths: Name is held by a standard function, or a deletion is queued or running. The request is refused before the deploy starts, so nothing is deployed. The message `project variables changed during - the upload; retry` means `NODE_PATH` was created or deleted while - the upload was processed; send the same request again. + the upload; retry` means `NODE_PATH` was created, changed or + deleted while the upload was processed; send the same request + again. content: application/json: schema: @@ -9418,8 +10143,10 @@ paths: | `lavaflow` | LavaFlow is released, offered to the project's owner, and included in the owner's plan | | `lavaflow.merge` | `lavaflow` is, and LavaFlow's merging is released in this environment | | `lavaflow.lineage` | `lavaflow` is, and fix lineage is released in this environment | + | `lavaflow.open_pr_ci_start` | `lavaflow` is, and LavaFlow's one CI start for fixes a person merges is released in this environment | | `lavaflow.code_quality` | `lavaflow` is, Code Quality is released in this environment, and the owner's plan allows Code Quality findings; with an allowance of 0 it is `unavailable` with `code` `plan_required` | | `lavaflow.slack` | `lavaflow` is, the Volcano Slack app is set up in this environment, and Slack reports have launched in it | + | `lavaflow.aikido` | `lavaflow` is, and Aikido reports have launched in this environment | Where `lavaflow` isn't available, a project with LavaFlow settings or runs lists it `read_only`: its LavaFlow reads answer, and its owner can @@ -9928,7 +10655,8 @@ paths: summary: Bind a connector to the project description: | Binds a place in a connector to the project, so problems reported - there reach LavaFlow for it, and answers `201`. For a `slack` + there reach LavaFlow for it, and answers `201`. Send `slack` for a + `slack` connector and `aikido` for an `aikido` one. For a `slack` connector the place is a channel. Binding a channel that is already bound answers `200` with that binding, and makes the current owner the one who bound it, so a retry is safe. One of the Slack identities the @@ -9939,10 +10667,18 @@ paths: app is in, and not archived, a Slack Connect channel, or shared across an organization. + For an `aikido` connector the place is the workspace's new code + (SAST) issues on the project's GitHub repository, at or above + `min_severity`. The caller must have + connected the workspace. Binding it again answers `200` and sets the + new minimum. Each issue starts a LavaFlow run that stops at a pull + request for review. + Only the project's owner can bind, with a platform token. A project access token, or a request made through MCP, gets `403` with code `person_required`. Binding a Slack channel needs the project's - `lavaflow.slack` capability: where it is unavailable, this answers + `lavaflow.slack` capability, and binding Aikido its + `lavaflow.aikido` capability: where it is unavailable, this answers `404` with code `feature_unavailable`, or `403` with code `plan_required` when the owner's plan does not include LavaFlow. operationId: createLavaflowConnectorBinding @@ -9956,7 +10692,7 @@ paths: $ref: '#/components/schemas/LavaflowConnectorBindingCreate' responses: '200': - description: The channel was already bound for the project + description: The channel, or the Aikido workspace, was already bound for the project content: application/json: schema: @@ -9968,7 +10704,7 @@ paths: schema: $ref: '#/components/schemas/LavaflowConnectorBinding' '400': - description: 'The body is invalid, the connector is not one the caller can use, the caller''s sign-in session signed in as no Slack identity in its workspace, the channel cannot report problems (it is archived, a Slack Connect channel, or shared across an organization), or the Volcano app is not in the channel yet: invite it, then bind again.' + description: 'The body is invalid or names the wrong connector type, the connector is not one the caller can use or connected, the caller''s sign-in session signed in as no Slack identity in its workspace, the channel cannot report problems (it is archived, a Slack Connect channel, or shared across an organization), or the Volcano app is not in the channel yet: invite it, then bind again.' content: application/json: schema: @@ -9986,7 +10722,7 @@ paths: schema: $ref: '#/components/schemas/Error' '404': - description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does a channel that no Slack identity the caller's sign-in session signed in as is a member of, and a private channel the Volcano app is not in, which the app cannot see. Code `feature_unavailable` means the project's `lavaflow.slack` capability is unavailable. + description: Not found. A project the caller can't read answers exactly like one that doesn't exist, and so does a channel that no Slack identity the caller's sign-in session signed in as is a member of, and a private channel the Volcano app is not in, which the app cannot see. Code `feature_unavailable` means the project's `lavaflow.slack`, or for Aikido its `lavaflow.aikido`, capability is unavailable. content: application/json: schema: @@ -10003,8 +10739,8 @@ paths: - LavaFlow summary: Remove a connector binding description: | - Stops a bound place, such as a Slack channel, reporting problems for - its project. Reports from it still queued are canceled at their next + Stops a bound place, such as a Slack channel or an Aikido workspace, + reporting problems for its project. Reports from it still queued are canceled at their next check. The binding's own project authorizes the request. Only the project's owner can remove one, with a platform token. A project access token or MCP gets `403` with code `person_required` for a @@ -10061,7 +10797,9 @@ paths: that went live since the last scan, with `status: waiting` and the bound it waits at in `waiting_reason`. A bound never drops a deploy: the waiting scan covers every commit since the last one when it - starts. + starts. A platform publication pause is reported as `feature_paused` + and does not spend the scan's retry allowance. With publication enabled, + a separate pause on starting runs is reported as `feature_unavailable`. Each scan shows the commits it compared, the resources whose deploys it covers, what it did with what it found, and the findings whose @@ -10113,15 +10851,26 @@ paths: - LavaFlow summary: Get LavaFlow stats description: | - Counts the issues LavaFlow took on and the pull requests it opened per - UTC day, oldest first, with every day in the window present. Merges - never count. The window ends today, which is partial. The totals equal - the sum of `days` and of the per-resource counts from + The activity counts report issues LavaFlow took on and pull requests it + opened per UTC day, oldest first, with every day in the window present. + Merges do not count toward these activity fields. The window ends + today, which is partial. The activity `totals` equal the sum of the + activity `days` and of the per-resource counts from `GET /lavaflow/resources` for the same project, `days` and `category`. - `category` counts only runs in that category. These counts are issues - taken on and pull requests opened, while `GET /lavaflow/runs` counts - runs, so the two need not match. + `category` filters these activity counts to runs in that category. + Activity counts measure issues taken on and pull requests opened, + while `GET /lavaflow/runs` counts runs, so the two need not match. + + The optional `outcomes` object separately reports confirmed merges, + improvements observed live and actual automatic issue-resolution + episodes. `category` filters its merge and live counts; its primary + issue-resolution count includes every category. Outcome counts use + their own event dates and do not contribute to the activity totals. + Older servers omit `outcomes`; its absence means unavailable, not + zero. Null outcome counts mean unknown, not zero. Read the per-metric + coverage alongside the counts: partial coverage and retained + confirmations do not establish a complete total. operationId: getLavaflowStats security: - UserToken: [] @@ -13710,6 +14459,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + '409': + description: '`code: function_served_by_candidate` - a promoted preview serves a function whose environment this write changes; the preview keeps the variables it was built with and the write would reach only the function''s own build, so roll the function back to its own build, or deploy it, first.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '503': description: Private variable membership writes are disabled during rollout content: @@ -16161,6 +16916,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + '409': + description: '`code: function_served_by_candidate` - a promoted preview serves a function whose environment this write changes; the preview keeps the variables it was built with and the write would reach only the function''s own build, so roll the function back to its own build, or deploy it, first.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '503': description: Private variable membership writes are disabled during rollout content: @@ -16190,6 +16951,12 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + '409': + description: '`code: function_served_by_candidate` - a promoted preview serves a function whose environment this write changes; the preview keeps the variables it was built with and the write would reach only the function''s own build, so roll the function back to its own build, or deploy it, first.' + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /auth/password-policy: get: tags: @@ -21831,8 +22598,10 @@ paths: | `lavaflow` | LavaFlow, which diagnoses a project's issues and opens pull requests that fix them. Here it reports only whether LavaFlow is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | | `lavaflow.merge` | LavaFlow merging its fixes, with `autonomy: merge`. Here it reports only whether merging is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | | `lavaflow.lineage` | LavaFlow following up its fixes: linking a fix's recurrence or a new issue its deploy caused to the fix, the follow-up runs, and the lineage holds. Here it reports only whether fix lineage is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | + | `lavaflow.open_pr_ci_start` | A fix a person merges, as under `autonomy: open_pr`, opening ready for review with LavaFlow running its CI once, unless the repository may run CI outside GitHub Actions; unavailable, such a fix opens as a draft whose commit skips CI. Here it reports only whether this is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | | `lavaflow.code_quality` | LavaFlow Code Quality, which reviews the code each frontend production deploy changes. Here it reports only whether Code Quality is released in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | | `lavaflow.slack` | Reporting problems to LavaFlow from Slack: installing the Volcano Slack app, connecting Slack identities, and binding channels to projects. Here it reports whether LavaFlow is released, the Slack app is set up, and Slack reports have launched in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | + | `lavaflow.aikido` | LavaFlow fixing the security issues Aikido finds: connecting an Aikido workspace and binding projects to it. Here it reports whether LavaFlow is released and Aikido reports have launched in this environment; whether a project has it comes from `GET /projects/{id}/capabilities` | | `functions.response_streaming` | Streaming an HTTP-mode function's response on its own URL as the function writes it | | `frontend_routes` | Creating and changing Frontend routes; listing, deleting, and serving existing ones work either way | | `frontends.candidates` | Creating, redeploying, promoting and rolling back to a frontend Candidate; reading, deleting and rolling back to the frontend's own runtime always work | @@ -22374,6 +23143,14 @@ components: type: string format: uuid description: Frontend Candidate ID + FunctionCandidateId: + name: candidateId + in: path + required: true + schema: + type: string + format: uuid + description: Function preview (Candidate) ID FrontendFunctionRouteId: name: routeId in: path @@ -23180,6 +23957,10 @@ components: - ready - unavailable - deleting + x-enum-varnames: + - SandboxTemplateStatusReady + - SandboxTemplateStatusUnavailable + - SandboxTemplateStatusDeleting created_at: type: string format: date-time @@ -23989,6 +24770,10 @@ components: - available - unavailable - read_only + x-enum-varnames: + - CapabilityStatusAvailable + - CapabilityStatusUnavailable + - CapabilityStatusReadOnly description: '`available` means the capability accepts new work; a temporary outage still answers `503`. `unavailable` means requests that start new work answer `404` or `400` with code `feature_unavailable`, or with the capability''s `code` when it has one; while the owner''s plan can''t be read, they answer `403` without a code. `read_only` means the capability takes no new work for the project, but what the project already has stays readable; only a project''s list reports it. Treat any other value as `unavailable`.' CapabilityList: type: object @@ -26915,6 +27700,42 @@ components: - impact - message - remediation + SharedVariablesReplaceResult: + type: object + additionalProperties: false + required: + - skipped_functions + properties: + skipped_functions: + type: array + description: Functions the replacement changes whose variables were not synchronized. + items: + $ref: '#/components/schemas/SkippedServedFunction' + SkippedServedFunction: + type: object + additionalProperties: false + required: + - id + - name + - code + - message + properties: + id: + type: string + format: uuid + description: Function ID. + name: + type: string + description: Function name. + code: + type: string + description: | + Why the function was left out. Clients must accept codes not listed here. + `function_served_by_candidate` - a promoted preview serves the function and keeps the + variables it was built with. + message: + type: string + description: What brings the function in line. ProjectImportSummary: type: object properties: @@ -27100,9 +27921,10 @@ components: description: The outside service a connector links to. enum: - slack + - aikido Connector: type: object - description: A link from Volcano to an outside service. A `slack` connector is a Slack workspace the Volcano app is installed in, shared by every Volcano account with a Slack identity connected there. + description: A link from Volcano to an outside service. A `slack` connector is a Slack workspace the Volcano app is installed in, shared by every Volcano account with a Slack identity connected there. An `aikido` connector is an Aikido workspace one Volcano account connected with its own credentials. properties: id: type: string @@ -27111,12 +27933,14 @@ components: $ref: '#/components/schemas/ConnectorType' name: type: string - description: The connector's name in its service, such as the Slack workspace's name. + description: The connector's name in its service, such as the Slack or Aikido workspace's name. slack: $ref: '#/components/schemas/SlackConnector' + aikido: + $ref: '#/components/schemas/AikidoConnector' removable: type: boolean - description: Whether the caller can remove the connector. Only the person who installed the Volcano app in a Slack workspace can. + description: Whether the caller can remove the connector. Only the person who installed the Volcano app in a Slack workspace can; an `aikido` connector is always the caller's own. created_at: type: string format: date-time @@ -27134,6 +27958,74 @@ components: $ref: '#/components/schemas/SlackTeamId' required: - team_id + AikidoConnector: + type: object + description: An `aikido` connector's workspace. Present when `type` is `aikido`. + properties: + region: + $ref: '#/components/schemas/AikidoRegion' + workspace_id: + type: integer + format: int64 + description: The workspace's ID in Aikido, which its webhook deliveries name. + required: + - region + - workspace_id + AikidoRegion: + type: string + description: 'The Aikido region the workspace lives in: `eu` for app.aikido.dev, `us` for app.us.aikido.dev, `au` for app.au.aikido.dev, and `me` for app.me.aikido.dev.' + enum: + - eu + - us + - au + - me + AikidoSeverity: + type: string + description: An Aikido issue severity, lowest first. + enum: + - low + - medium + - high + - critical + ConnectorCreate: + type: object + additionalProperties: false + properties: + type: + type: string + description: The service to connect. Slack installs with `POST /user/slack/installations`. + enum: + - aikido + aikido: + $ref: '#/components/schemas/AikidoConnectorCreate' + required: + - type + - aikido + AikidoConnectorCreate: + type: object + additionalProperties: false + description: The Aikido workspace's REST API client and webhook signing secret. + properties: + region: + $ref: '#/components/schemas/AikidoRegion' + client_id: + type: string + minLength: 1 + maxLength: 512 + client_secret: + type: string + minLength: 1 + maxLength: 512 + webhook_secret: + type: string + minLength: 1 + maxLength: 512 + description: The signing secret from Aikido's webhooks page, which verifies its deliveries. + required: + - region + - client_id + - client_secret + - webhook_secret ConnectorsResponse: type: object properties: @@ -27145,7 +28037,7 @@ components: - connectors LavaflowConnectorBinding: type: object - description: A place in a connector, such as a Slack channel, that reports problems to LavaFlow for a project. + description: 'A place in a connector that reports problems to LavaFlow for a project: a Slack channel, or an Aikido workspace''s issues on the project''s repository.' properties: id: type: string @@ -27162,6 +28054,8 @@ components: description: The connector the binding reports through. Omitted while the Volcano app is not installed in the binding's Slack workspace; the binding reports again once it is. slack: $ref: '#/components/schemas/LavaflowSlackBinding' + aikido: + $ref: '#/components/schemas/LavaflowAikidoBinding' created_at: type: string format: date-time @@ -27185,6 +28079,17 @@ components: - team_id - team_name - channel_id + LavaflowAikidoBinding: + type: object + description: The Aikido workspace a binding reports issues from. Present when `connector_type` is `aikido`. + properties: + workspace_name: + type: string + min_severity: + $ref: '#/components/schemas/AikidoSeverity' + required: + - workspace_name + - min_severity LavaflowConnectorBindingsResponse: type: object properties: @@ -27208,10 +28113,17 @@ components: description: The connector to bind, from `GET /connectors`. slack: $ref: '#/components/schemas/LavaflowSlackBindingTarget' + aikido: + $ref: '#/components/schemas/LavaflowAikidoBindingTarget' required: - project_id - connector_id - - slack + description: Send exactly one of `slack` and `aikido`, matching the connector's type. + oneOf: + - required: + - slack + - required: + - aikido LavaflowSlackBindingTarget: type: object additionalProperties: false @@ -27221,6 +28133,15 @@ components: $ref: '#/components/schemas/SlackChannelId' required: - channel_id + LavaflowAikidoBindingTarget: + type: object + additionalProperties: false + description: What an `aikido` connector reports for the project. Send `aikido`, not `slack`, for an `aikido` connector. + properties: + min_severity: + allOf: + - $ref: '#/components/schemas/AikidoSeverity' + description: 'The lowest severity that starts a LavaFlow run. Defaults to `high`: each run counts against the project''s LavaFlow runs.' GitConnectStartResponse: type: object properties: @@ -28548,6 +29469,312 @@ components: - status - created_at - updated_at + FunctionCandidate: + type: object + additionalProperties: false + description: | + A copy of an ordinary function built from an uploaded source with the function's own variables, + run on a runtime of its own and invoked at its own host with the project's service key only, so it + can be checked before it is promoted. It has none of the function's schedules or warmers. Fields + that do not apply yet are absent. + properties: + id: + type: string + format: uuid + function_id: + type: string + format: uuid + name: + type: string + maxLength: 128 + slug: + type: string + status: + type: string + enum: + - creating + - ready + - deleting + - error + description: | + `creating` until its first deployment succeeds, `ready` while it serves, `deleting` while its + runtime is removed, and `error` when its deletion gave up and needs an operator. A deleted + preview answers `404`. + exposure: + type: string + enum: + - private + description: A function preview is always private. Only the project's service key, with `functions.invoke`, can invoke it; signed-in users, anon keys and access tokens are refused. + url: + type: string + format: uri + description: Where the preview is invoked. Absent until its first deployment succeeds. + expires_at: + type: string + format: date-time + description: When the preview is deleted on its own. Absent when it is kept until deleted. A preview the function runs, or keeps for a rollback, is not deleted then; it expires once it is neither. + created_by: + type: string + description: The user who created the preview, when a user did. + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + current_deployment_id: + type: string + format: uuid + description: | + The deployment the preview serves. Absent until its first deployment succeeds. It differs from + `deployment` while a redeploy runs or after one failed. + deployment: + $ref: '#/components/schemas/FunctionCandidateDeployment' + configuration_status: + type: string + enum: + - current + - changed + description: | + Present while the preview serves a deployment. `current` means that deployment was built with + the variables, runtime and handler the function would give that source now; `changed` means + they differ, or can no longer be resolved. Promotion refuses a preview whose status is + `changed`. + serving: + type: boolean + description: The function runs this preview's build. + kept_for_rollback: + type: boolean + description: A rollback of the function returns to this preview's build. + required: + - id + - function_id + - name + - slug + - status + - exposure + - created_at + - updated_at + - serving + - kept_for_rollback + FunctionCandidateList: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/FunctionCandidate' + required: + - data + FunctionCandidateDeployment: + type: object + additionalProperties: false + properties: + id: + type: string + format: uuid + status: + type: string + enum: + - provisioning + - active + - failed + description: | + `provisioning` while the build and deploy run, `active` once the preview serves this + deployment, and `failed` when it could not be built or deployed. A failed deployment of a + preview that already served keeps the previous deployment serving. + operation: + type: string + enum: + - deploy + - redeploy + image_digests: + type: array + description: | + The digest of the image this deployment published, per region. Present once the deployment + succeeded. A promotion points the function at this image and deploys nothing. + items: + $ref: '#/components/schemas/FunctionImageDigest' + configuration_digest: + type: string + pattern: ^sha256:[0-9a-f]{64}$ + description: Identifies the variables the build used without carrying any value. + regions: + type: array + items: + type: string + error_message: + type: string + description: Why a failed deployment failed. + created_at: + type: string + format: date-time + completed_at: + type: string + format: date-time + description: Set once the deployment is no longer provisioning. + required: + - id + - status + - operation + - configuration_digest + - regions + - created_at + FunctionCandidateDeploymentList: + type: object + additionalProperties: false + properties: + data: + type: array + items: + $ref: '#/components/schemas/FunctionCandidateDeployment' + required: + - data + FunctionServing: + type: object + additionalProperties: false + description: | + What a function runs. Until a preview is promoted it runs its own build and `candidate_id` is + null. After a promotion, the function's traffic runs on that preview's runtime, nothing is rebuilt + or deployed, and `previous_candidate_id` is what a rollback returns to (null when that is the + function's own build). A preview the function runs cannot be deleted and does not expire. One kept + only as what a rollback returns to does not expire either, but it can be deleted, which gives up + that rollback; the function's own build stays one `to_production` rollback away. + properties: + revision: + type: integer + format: int64 + minimum: 0 + description: Counts changes to what the function runs or can roll back to — promotions, rollbacks, a deployment that returns the traffic to the function's own build, and deleting the preview kept for a rollback. A promotion or rollback names the revision it read, so one that read before such a change fails with `409` (`stale_revision`) instead of overwriting it; read the serving state again and retry. + candidate_id: + type: string + format: uuid + nullable: true + description: The preview whose build the function runs; null for its own. + previous_candidate_id: + type: string + format: uuid + nullable: true + description: The preview a rollback returns to; null for the function's own build. + activation: + $ref: '#/components/schemas/FunctionServingActivation' + production_environment: + $ref: '#/components/schemas/FunctionProductionEnvironment' + required: + - revision + - candidate_id + - previous_candidate_id + - production_environment + FunctionServingActivation: + type: object + additionalProperties: false + description: | + The latest change to what serves the function's traffic: a promotion, a rollback, or a deployment + of the function that returned its traffic to its own build. Each takes effect at once. Absent until + the function's first promotion. + properties: + id: + type: string + format: uuid + kind: + type: string + enum: + - promotion + - rollback + - deploy + x-enum-varnames: + - FunctionServingActivationKindPromotion + - FunctionServingActivationKindRollback + - FunctionServingActivationKindDeploy + description: '`deploy`: a successful deployment of the function cleared the preview pointers.' + status: + type: string + enum: + - applied + description: '`applied`: the change takes effect when it is recorded.' + revision: + type: integer + format: int64 + minimum: 1 + candidate_id: + type: string + format: uuid + description: The preview the activation pointed the function at. Absent for the function's own build. + image_digests: + type: array + description: The digests of the image the activation pointed the function at. Absent for the function's own build. + items: + $ref: '#/components/schemas/FunctionImageDigest' + required: + - id + - kind + - status + - revision + FunctionProductionEnvironment: + type: object + additionalProperties: false + description: | + Whether the function's own build has the project's current variables. While a preview serves the + function, `volcano config deploy` and replacing the shared variable list skip the function, so its + own build keeps the values it had. A rollback to the function's own build starts synchronizing them + as it returns the traffic, and the status reads `current` once that synchronization completes or a + deployment of the function activates. A synchronization that fails leaves it `out_of_date`. + properties: + status: + type: string + enum: + - current + - out_of_date + x-enum-varnames: + - FunctionProductionEnvironmentStatusCurrent + - FunctionProductionEnvironmentStatusOutOfDate + description: '`out_of_date`: a stored variable change skipped the function while a preview served it.' + out_of_date_since: + type: string + format: date-time + description: When the latest skipped change was stored. Absent while `status` is `current`. + required: + - status + FunctionImageDigest: + type: object + additionalProperties: false + description: The content digest of a function image in one region. It names no registry or account. + properties: + region: + type: string + description: The region the image was published to. Absent when the build published one image for every region. + digest: + type: string + pattern: ^sha256:[0-9a-f]{64}$ + required: + - digest + FunctionPromotionRequest: + type: object + additionalProperties: false + required: + - expected_revision + properties: + expected_revision: + type: integer + format: int64 + minimum: 0 + description: The `revision` the caller read from `serving`. Refuses the promotion with `stale_revision` unless what the function runs is still at this revision. + FunctionRollbackRequest: + type: object + additionalProperties: false + required: + - expected_revision + properties: + expected_revision: + type: integer + format: int64 + minimum: 0 + description: The `revision` the caller read from `serving`. Refuses the rollback with `stale_revision` unless what the function runs is still at this revision, so a retried rollback cannot undo itself. + to_production: + type: boolean + default: false + description: Return to the function's own build whatever it ran before. FrontendCandidateDeployment: type: object additionalProperties: false @@ -29421,6 +30648,16 @@ components: type: string format: uuid description: Newest queued deployment that will run after the current operation + serving_candidate_id: + type: string + format: uuid + nullable: true + readOnly: true + description: | + The promoted preview whose runtime receives this function's traffic, the same as + `candidate_id` in `serving`. Null when the function runs its own build. While it is set, + `current_deployment_id` and `status` describe the function's own build, which receives no + traffic until the function is rolled back. last_invoked_at: type: string format: date-time @@ -29443,6 +30680,7 @@ components: - openapi_spec - has_openapi_spec - deployed_regions + - serving_candidate_id - created_at - updated_at DurableFunction: @@ -31478,17 +32716,17 @@ components: - merged - held - stopped - description: '`waiting_for_checks`: LavaFlow waits for the checks on the fix''s commit. `queued`: the fix is in the repository''s merge queue. `merged`: the pull request merged. `held`: something in `hold_reasons` needs a person. LavaFlow commented on the pull request once and never merges, pushes to, rebases or dequeues it again; review it and merge it yourself if you want it. `stopped`: LavaFlow left the pull request open for you, for `reason`.' + description: '`waiting_for_checks`: LavaFlow waits for the checks on the fix''s commit. `queued`: the fix is in the repository''s merge queue. `merged`: the pull request merged. `held`: something in `hold_reasons` needs a person. LavaFlow commented on the pull request once and never merges, pushes to, rebases or dequeues it again; review it and merge it yourself if you want it. A fix a person merges (its autonomy is `open_pr`, merging was unavailable when it opened, or its run may only open a pull request) is always `held` for `person_merges` once LavaFlow has started its CI, or found it may not. `stopped`: LavaFlow left the pull request open for you, for `reason`.' LavaflowMergeReason: type: string - description: 'Why the merge stopped, or what a waiting merge is paused for. A stopped merge leaves the pull request open for you, and LavaFlow never merges, pushes to, rebases or dequeues it again; unless a reason says otherwise, review the change, then merge or close the pull request yourself. `review_unresolved`: LavaFlow''s review didn''t pass the fix; the run''s `review` says why. `checks_failed`: a check on the fix failed. `checks_timed_out`: the checks didn''t all finish within 24 hours. `blocked_by_rules`: a rule of the repository that LavaFlow can''t satisfy blocks the merge. `not_mergeable`: GitHub can''t merge the pull request, for example because it conflicts with its base branch; resolve the conflict first. `branch_behind`: the base branch requires the fix to be up to date with it, and LavaFlow doesn''t update fix branches; update the branch first. `removed_from_queue`: the fix isn''t in the merge queue, and LavaFlow can''t tell why, for example because its checks failed there or someone removed it. `reads_failed`: LavaFlow failed to read the pull request for about an hour while the fix may have been queued, so it took the fix out of the merge queue, when it could still reach it, and stopped, or failed to read the project''s settings or repository for about a day while merging was paused. `handed_off`: someone drafted or closed the pull request, or moved it to another branch, so LavaFlow stopped; nothing to do. `unreadable`: the pull request has more checks, reviews, labels or commits than LavaFlow reads, so it can''t judge the fix. `permission_missing`: the Volcano GitHub App, or the project owner''s GitHub account, lacks a permission the merge needs; grant the App''s requested permissions and make sure the owner can push. `repository_changed`: the project now deploys from another repository. `settings_changed`: the project''s settings no longer let LavaFlow merge: LavaFlow was turned off, `autonomy` is no longer `merge`, the owner''s plan no longer includes LavaFlow, or the project is being deleted. `request_rejected`: GitHub refused LavaFlow''s request to start the checks on the fix. `ci_start_commit_mismatch`: GitHub reports a different commit from the one LavaFlow made to start the checks. `branch_refused`: LavaFlow didn''t start the fix''s checks because the pull request was no longer open, or its branch isn''t a LavaFlow branch of a pull request LavaFlow opened; LavaFlow never starts checks on the default or production branch. `head_unverified`: GitHub doesn''t report the fix''s head as the signed commit LavaFlow pushed, so LavaFlow didn''t start its checks. `checks_not_started`: LavaFlow couldn''t give the fix a commit message that runs CI. `queue_carries_ci_skip`: the repository''s merge queue could carry an instruction to skip checks, from the fix''s commits or its pull request''s title or description, into the base branch; reword LavaFlow''s commit to drop it and force-push, and take any such instruction out of the title and description, before you queue the fix. `merge_carries_ci_skip`: merging would carry an instruction to skip checks into the base branch, for example because the repository allows no squash merge; reword LavaFlow''s commit to drop it and force-push before you merge. After `request_rejected`, `ci_start_commit_mismatch` or `checks_not_started`, the fix''s CI didn''t start: push a commit to its branch to run it. `paused_too_long`: merging stayed paused for more than 7 days. `cancelled`: the project is being deleted, so LavaFlow stopped waiting on the merge; nothing to do. `manual_deploy`: the fix merged and waits for you to deploy it. `paused`: merging is paused, and the merge waits. LavaFlow takes a queued fix out of the merge queue, so it shows `waiting_for_checks`, and queues it again when merging resumes. New reasons may appear.' + description: 'Why the merge stopped, or what a waiting merge is paused for. A stopped merge leaves the pull request open for you, and LavaFlow never merges, pushes to, rebases or dequeues it again; unless a reason says otherwise, review the change, then merge or close the pull request yourself. `review_unresolved`: LavaFlow''s review didn''t pass the fix; the run''s `review` says why. `checks_failed`: a check on the fix failed. `checks_timed_out`: the checks didn''t all finish within 24 hours. `blocked_by_rules`: a rule of the repository that LavaFlow can''t satisfy blocks the merge. `not_mergeable`: GitHub can''t merge the pull request, for example because it conflicts with its base branch; resolve the conflict first. `branch_behind`: the base branch requires the fix to be up to date with it, and LavaFlow doesn''t update fix branches; update the branch first. `removed_from_queue`: the fix isn''t in the merge queue, and LavaFlow can''t tell why, for example because its checks failed there or someone removed it. `reads_failed`: LavaFlow failed to read the pull request for about an hour while the fix may have been queued, so it took the fix out of the merge queue, when it could still reach it, and stopped, or failed to read the project''s settings or repository for about a day while merging was paused. For a fix a person merges, which LavaFlow never queues, it means only the latter, with its CI start paused instead of merging. `handed_off`: someone drafted or closed the pull request, or moved it to another branch, so LavaFlow stopped; nothing to do. `unreadable`: the pull request has more checks, reviews, labels or commits than LavaFlow reads, so it can''t judge the fix. `permission_missing`: the Volcano GitHub App, or the project owner''s GitHub account, lacks a permission the merge needs; grant the App''s requested permissions and make sure the owner can push. `repository_changed`: the project now deploys from another repository. `settings_changed`: the project''s settings no longer let LavaFlow merge, or, for a fix a person merges, start its CI: LavaFlow was turned off, `autonomy` is no longer `merge` (no longer `open_pr` or `merge` for a fix a person merges), the owner''s plan no longer includes LavaFlow, or the project is being deleted. `request_rejected`: GitHub refused LavaFlow''s request to start the checks on the fix. `ci_start_commit_mismatch`: GitHub reports a different commit from the one LavaFlow made to start the checks. `branch_refused`: LavaFlow didn''t start the fix''s checks because the pull request was no longer open, or its branch isn''t a LavaFlow branch of a pull request LavaFlow opened; LavaFlow never starts checks on the default or production branch. `head_unverified`: GitHub doesn''t report the fix''s head as the signed commit LavaFlow pushed, so LavaFlow didn''t start its checks. `checks_not_started`: LavaFlow couldn''t give the fix a commit message that runs CI. `queue_carries_ci_skip`: the repository''s merge queue could carry an instruction to skip checks, from the fix''s commits or its pull request''s title or description, into the base branch; reword LavaFlow''s commit to drop it and force-push, and take any such instruction out of the title and description, before you queue the fix. `merge_carries_ci_skip`: merging would carry an instruction to skip checks into the base branch, for example because the repository allows no squash merge; reword LavaFlow''s commit to drop it and force-push before you merge. After `request_rejected`, `ci_start_commit_mismatch` or `checks_not_started`, the fix''s CI didn''t start: push a commit to its branch to run it. `paused_too_long`: merging stayed paused for more than 7 days, or, for a fix a person merges, LavaFlow''s CI start for such fixes did. `cancelled`: the project is being deleted, so LavaFlow stopped waiting on the merge; nothing to do. `manual_deploy`: the fix merged and waits for you to deploy it. `paused`: merging is paused, and the merge waits. LavaFlow takes a queued fix out of the merge queue, so it shows `waiting_for_checks`, and queues it again when merging resumes. For a fix a person merges, LavaFlow''s CI start for such fixes is paused instead, whatever merging does, and LavaFlow never takes it out of a queue. New reasons may appear.' LavaflowHoldReason: type: object description: One reason LavaFlow holds the fix for a person. properties: code: type: string - description: 'Why the fix is held. `client_reported_commit`: the fix is built on a commit Volcano can''t tie to a push. `path`: it changes a path in `human_review_paths`, or deploy or infrastructure configuration Volcano always holds, such as `volcano-config.yaml`, Terraform files, a YAML or JSON file that declares a resource, a YAML template that mentions `apiVersion` or `kind`, a file in a Helm chart or Kustomize directory, or, in a repository too large to read in full, any file no other path reason holds. `sensitive_path`: it changes another path Volcano always holds: authentication or authorization code, Next.js middleware included; secret, key, certificate or cryptography files; a coding agent''s instructions or settings, or Git hook configuration; CI configuration; a dependency manifest or lockfile, or a `package.json` change to what installs or its install scripts; or runtime, container or other configuration files. `label`: the pull request has the `needs-human-review` label. `no_checks`: no CI ran on it. `required_check_skipped`: a required check was skipped. `no_required_checks`: the base branch requires no check, so passing checks alone don''t vouch for the fix. `changes_requested`: a reviewer requested changes. `repository_requires_approval`: the repository requires an approving review. `person_commits`: someone other than LavaFlow pushed to the fix''s branch. `rules_bypass`: the Volcano GitHub App can bypass a ruleset on the base branch. `unchecked_rules`: the base branch has a rule LavaFlow doesn''t check, such as required signatures. `commit_convention`: no title can meet the repository''s commit convention. `ungated_workflows`: the fix opened past workflows that can run it with the repository''s secrets before a person approves it, as the project''s owner allowed, or LavaFlow couldn''t check its workflows, or, when LavaFlow was about to start its CI or add it to a merge queue, a workflow could run it with those secrets before a person approves it or couldn''t be read, so LavaFlow takes it no further and never merges it. A fix held for another reason before its CI starts lists it too when that check, run without starting CI, finds such a workflow or can''t finish. `ci_outside_actions`: when LavaFlow was about to start the fix''s CI, the repository could run CI, a build or a preview outside GitHub Actions: the root of the fix''s tree or its base branch''s holds another service''s configuration, such as `.travis.yml`, `.circleci/` or `netlify.toml`, which `paths` names, another app reported checks or statuses on the base branch, or LavaFlow couldn''t read them in full. LavaFlow starts CI only when it finds no sign of CI outside GitHub Actions, so it never starts this fix''s CI or merges it. `lineage_undoes_parent`: the fix follows up an earlier LavaFlow fix and deletes or changes lines that fix added, which could undo it. `lineage_cap`: the fix''s lineage opened as many pull requests as it may. `lineage_held`: an earlier pull request in the fix''s lineage was held, stopped or closed. `recent_regressions`: fixes LavaFlow merged in the project recently caused new errors. `no_test`: the fix changes code the repository tests and adds no test, because testing it needs test infrastructure the repository doesn''t have or the change has no effect a test can observe. Other codes name a concern LavaFlow''s reviewers raised. New codes may appear.' + description: 'Why the fix is held. `client_reported_commit`: the fix is built on a commit Volcano can''t tie to a push. `path`: it changes a path in `human_review_paths`, or deploy or infrastructure configuration Volcano always holds, such as `volcano-config.yaml`, Terraform files, a YAML or JSON file that declares a resource, a YAML template that mentions `apiVersion` or `kind`, a file in a Helm chart or Kustomize directory, or, in a repository too large to read in full, any file no other path reason holds. `sensitive_path`: it changes another path Volcano always holds: authentication or authorization code, Next.js middleware included; secret, key, certificate or cryptography files; a coding agent''s instructions or settings, or Git hook configuration; CI configuration; a dependency manifest or lockfile, or a `package.json` change to what installs or its install scripts; or runtime, container or other configuration files. `label`: the pull request has the `needs-human-review` label. `no_checks`: no CI ran on it. `required_check_skipped`: a required check was skipped. `no_required_checks`: the base branch requires no check, so passing checks alone don''t vouch for the fix. `changes_requested`: a reviewer requested changes. `repository_requires_approval`: the repository requires an approving review. `person_commits`: someone other than LavaFlow pushed to the fix''s branch. `rules_bypass`: the Volcano GitHub App can bypass a ruleset on the base branch. `unchecked_rules`: the base branch has a rule LavaFlow doesn''t check, such as required signatures. On a fix a person merges it names only rules that kept LavaFlow from starting the fix''s CI, such as `code_scanning` or `workflows`, or that LavaFlow couldn''t read them. `commit_convention`: no title can meet the repository''s commit convention. `ungated_workflows`: the fix opened past workflows that can run it with the repository''s secrets before a person approves it, as the project''s owner allowed, or LavaFlow couldn''t check its workflows, or, when LavaFlow was about to start its CI or add it to a merge queue, a workflow could run it with those secrets before a person approves it or couldn''t be read, so LavaFlow takes it no further and never merges it. A fix held for another reason before its CI starts lists it too when that check, run without starting CI, finds such a workflow or can''t finish. `ci_outside_actions`: when LavaFlow was about to start the fix''s CI, the repository could run CI, a build or a preview outside GitHub Actions: the root of the fix''s tree or its base branch''s holds another service''s configuration, such as `.travis.yml`, `.circleci/` or `netlify.toml`, which `paths` names, another app reported checks or statuses on the base branch, or LavaFlow couldn''t read them in full. LavaFlow starts CI only when it finds no sign of CI outside GitHub Actions, so it never starts this fix''s CI or merges it. `lineage_undoes_parent`: the fix follows up an earlier LavaFlow fix and deletes or changes lines that fix added, which could undo it. `lineage_cap`: the fix''s lineage opened as many pull requests as it may. `lineage_held`: an earlier pull request in the fix''s lineage was held, stopped or closed; one a person merges holds it only when closed. `recent_regressions`: fixes LavaFlow merged in the project recently caused new errors. `no_test`: the fix changes code the repository tests and adds no test, because testing it needs test infrastructure the repository doesn''t have or the change has no effect a test can observe. `choices_to_confirm`: the fix states behavior it decides beyond stopping the error, listed in the run''s `choices` and, on a private repository, under Choices to confirm in the pull request''s description, for a person to confirm, and LavaFlow''s reviewers didn''t all mark each choice as needing no person. It never applies alongside `person_merges`: the person confirms the choices while reviewing the fix. `risky_change`: the fix adds or removes a line that converts a value, such as with `float()` or `parseInt()`, in a file that names a rate limit or quota, authentication or authorization, or money, so values such as NaN, Infinity or a negative number could get past a check there; `paths` names the files. `review_notes`: LavaFlow''s reviewers passed the fix, but its review''s last round left notes, findings below `major` that a later round no longer sends back for revision, such as a decision the fix makes without stating it. `person_merges`: a person reviews and merges the fix, because the project''s autonomy is `open_pr`, merging was unavailable when it opened, or its run may only open a pull request; LavaFlow ran the fix''s CI once first unless another reason, or the CI start''s own checks, stopped it. Other codes name a concern LavaFlow''s reviewers raised. New codes may appear.' question: type: string description: Why LavaFlow holds the fix and what to check before you merge it, in one or two sentences to show as given. A reviewer's reason is a question for you to answer. Reads `LavaFlow left this question out because it may contain a credential` when it holds one of the project's secret values, a value shaped like a credential, or a path `paths` leaves out, or is over 4,000 characters, and, for a question LavaFlow's reviewers wrote, when it may contain a credential. Every question reads so, LavaFlow's fixed sentences too, on a run whose `pull_request_skipped` is `possible_credential`. @@ -31503,7 +32741,7 @@ components: - paths LavaflowMerge: type: object - description: Where the run's merge stands. Present for a run that may merge its fix, once its pull request opens. + description: 'Where the run''s merge stands. Present for a run that may merge its fix, once its pull request opens, and for a run whose fix a person merges (its autonomy is `open_pr`, merging was unavailable when it opened, or the run may only open a pull request) that opened ready for review: LavaFlow starts that fix''s CI once, then holds it for `person_merges` and never merges it.' properties: status: $ref: '#/components/schemas/LavaflowMergeStatus' @@ -31786,6 +33024,8 @@ components: description: One entry per UTC day, oldest first, zeros included. items: $ref: '#/components/schemas/LavaflowDayCounts' + outcomes: + $ref: '#/components/schemas/LavaflowOutcomes' totals: type: object properties: @@ -31920,7 +33160,7 @@ components: type: string format: date-time nullable: true - description: 'When the merged fix went live: the first live deployment of the issue''s resource that includes it finished. When more than 20 deployments went live between the merge and the one LavaFlow found the fix in, LavaFlow can''t tell which first included it, and this is the merge time. Null until LavaFlow finds the fix live, and for a pull request that didn''t merge. LavaFlow watches the resource''s deployments for a week after the merge.' + description: 'When the merged fix went live: the first live deployment of the issue''s resource that includes it finished. When more than 20 deployments went live between the merge and the one LavaFlow found the fix in, LavaFlow can''t tell which first included it, and this is the merge time. Null until LavaFlow finds the fix live, and for a pull request that didn''t merge. A later live deployment can be verified even more than a week after the merge. Unverifiable or exhausted evidence remains unknown.' draft: type: boolean nullable: true @@ -31966,7 +33206,7 @@ components: - LavaflowDraftReasonOpenPr - LavaflowDraftReasonReviewUnresolved - LavaflowDraftReasonConvertedToDraft - description: 'Why a run''s pull request is a draft. `open_pr`: LavaFlow doesn''t merge the fix, because the project''s autonomy is `open_pr`, merging was unavailable when it opened, LavaFlow started the run on its own under settings saved with automatic runs off before this API (sending `autonomy: merge` again as the owner lifts that), or it was already a draft when the run took it on; it waits for a person to review it and mark it ready. `review_unresolved`: LavaFlow''s review didn''t pass the fix, so LavaFlow never merges it; a person decides whether to finish it. `converted_to_draft`: LavaFlow opened it ready for review, and someone made it a draft since.' + description: 'Why a run''s pull request is a draft. `open_pr`: LavaFlow doesn''t merge the fix, because the project''s autonomy is `open_pr`, merging was unavailable when it opened, or the run may only open a pull request (as runs LavaFlow started on its own under settings saved with automatic runs off before this API do; sending `autonomy: merge` again as the owner lifts that), and its review didn''t pass, LavaFlow''s CI start for fixes a person merges wasn''t available when it opened, or the repository may run CI or previews outside GitHub Actions (or LavaFlow couldn''t check whether it does) when it opened; or it was already a draft when the run took it on. It waits for a person to review it and mark it ready. `review_unresolved`: LavaFlow''s review didn''t pass the fix, so LavaFlow never merges it; a person decides whether to finish it. `converted_to_draft`: LavaFlow opened it ready for review, and someone made it a draft since.' LavaflowSkipReason: type: string enum: @@ -32007,7 +33247,7 @@ components: - LavaflowSkipReasonReviewUnresolved - LavaflowSkipReasonDuplicateInRepository - LavaflowSkipReasonSecurityFinding - description: 'Why a finished run opened no pull request, with what you can do next. `diagnose_only`: the project''s `autonomy` was `diagnose_only` when the run was queued, or became it before the pull request opened, so LavaFlow only diagnosed the issue; read the diagnosis. For later runs to open pull requests, send `"autonomy": "open_pr"` to `PATCH /lavaflow/settings`, or run `volcano cloud lavaflow settings set --autonomy open_pr`. `not_fixable`: the diagnosis found no change in the code that fixes the error, for example because the cause is outside it; read the diagnosis. `low_confidence`: the diagnosis is not confident enough to propose a fix; read the diagnosis. `no_patch`: LavaFlow proposed no change; read the diagnosis. `possible_credential`: the fix or its description held what looks like a credential or a project secret, so LavaFlow pushed nothing; apply the fix yourself from the diagnosis. `possible_personal_data`: the fix adds an email address the repository lacks, and the repository isn''t private, so LavaFlow pushed nothing; apply the fix yourself. `ungated_workflows`: a workflow could run the fix with the repository''s secrets before a person approves it; gate the workflow on a label a person adds, or turn on `allow_ungated_workflows`. `convention_unsatisfiable`: LavaFlow would merge the fix, but no title can meet the repository''s commit convention, so it kept the fix on the run; apply the fix yourself, or relax the convention. `pull_request_open`: when the run checked, before opening a pull request, another LavaFlow pull request for the issue was open, or merged and not yet deployed, so this run opened none; a fix it wrote stays on the run. That pull request may have closed since; find it with `GET /lavaflow/runs?project_id=…&issue_id=…`, whose runs carry their `pull_request`. Review it, or close it if you don''t want it. `source_unavailable`: LavaFlow couldn''t read, or open a fix on, the code that served the error; the run''s `source_unavailable` says why and what to do. `permission_missing`: the Volcano GitHub App, or the project owner''s GitHub account, lacks a permission LavaFlow needs; grant the App''s requested permissions and make sure the owner can push to the repository. `repository_changed`: the project no longer deploys from the repository the run read; a new run uses the current one. `publish_failed`: opening the pull request failed; a new run tries again. `lineage_cap`: LavaFlow opened as many pull requests in this fix''s lineage as it may; review the lineage''s pull requests and fix the rest yourself. `lineage_held`: an earlier pull request in this fix''s lineage was held, stopped or closed, so LavaFlow opens no more in it; apply the fix yourself from the diagnosis. `review_unresolved`: LavaFlow''s review didn''t pass a Code Quality fix; read the diagnosis. `duplicate_in_repository`: when the run checked, another project on the repository already had the Code Quality pull request for the same finding; review that pull request in the repository. `security_finding`: the finding has security impact and the repository isn''t private, so the fix would disclose it; fix it yourself. New reasons may appear.' + description: 'Why a finished run opened no pull request, with what you can do next. `diagnose_only`: the project''s `autonomy` was `diagnose_only` when the run was queued, or became it before the pull request opened, so LavaFlow only diagnosed the issue; read the diagnosis. For later runs to open pull requests, send `"autonomy": "open_pr"` to `PATCH /lavaflow/settings`, or run `volcano cloud lavaflow settings set --autonomy open_pr`. `not_fixable`: the diagnosis found no change in the code that fixes the error, for example because the cause is outside it; read the diagnosis. `low_confidence`: the diagnosis is not confident enough to propose a fix; read the diagnosis. `no_patch`: LavaFlow proposed no change; read the diagnosis. `possible_credential`: the fix or its description held what looks like a credential or a project secret, so LavaFlow pushed nothing; apply the fix yourself from the diagnosis. `possible_personal_data`: the fix adds an email address the repository lacks, and the repository isn''t private, so LavaFlow pushed nothing; apply the fix yourself. `ungated_workflows`: a workflow could run the fix with the repository''s secrets before a person approves it; gate the workflow on a label a person adds, or turn on `allow_ungated_workflows`. `convention_unsatisfiable`: LavaFlow would merge the fix, but no title can meet the repository''s commit convention, so it kept the fix on the run; apply the fix yourself, or relax the convention. `pull_request_open`: when the run checked, before opening a pull request, another LavaFlow pull request for the issue was open, or merged and not yet deployed, so this run opened none; a fix it wrote stays on the run. That pull request may have closed since; find it with `GET /lavaflow/runs?project_id=…&issue_id=…`, whose runs carry their `pull_request`. Review it, or close it if you don''t want it. `source_unavailable`: LavaFlow couldn''t read, or open a fix on, the code that served the error; the run''s `source_unavailable` says why and what to do. `permission_missing`: the Volcano GitHub App, or the project owner''s GitHub account, lacks a permission LavaFlow needs; grant the App''s requested permissions and make sure the owner can push to the repository. `repository_changed`: the project no longer deploys from the repository the run read; a new run uses the current one. `publish_failed`: opening the pull request failed; a new run tries again. `lineage_cap`: LavaFlow opened as many pull requests in this fix''s lineage as it may; review the lineage''s pull requests and fix the rest yourself. `lineage_held`: an earlier pull request in this fix''s lineage was held, stopped or closed (one a person merges holds it only when closed), so LavaFlow opens no more in it; apply the fix yourself from the diagnosis. `review_unresolved`: LavaFlow''s review didn''t pass a Code Quality fix; read the diagnosis. `duplicate_in_repository`: when the run checked, another project on the repository already had the Code Quality pull request for the same finding; review that pull request in the repository. `security_finding`: the finding has security impact and the repository isn''t private, so the fix would disclose it; fix it yourself. New reasons may appear.' LavaflowRunSummary: type: object properties: @@ -32084,7 +33324,7 @@ components: allOf: - $ref: '#/components/schemas/LavaflowFixOutcome' nullable: true - description: How the run's merged fix fared once it went live. Null until a merged fix goes live with the `lavaflow.lineage` capability on. + description: How the run's merged fix fared once it went live. Null until a merged fix goes live with the `lavaflow.lineage` capability on. Also null, meaning unknown, when the fix is first found live only after its 14-day watch ended and its issue neither resolved as of go-live nor was last seen inside the watch. required: - id - project_id @@ -32165,13 +33405,19 @@ components: x-go-type-skip-optional-pointer: true items: $ref: '#/components/schemas/LavaflowReviewFinding' - description: The findings the review saved with the fix left open. Absent when the review passed the fix, left none open, or the run saved no fix. + description: 'The findings the review saved with the fix left open. When the review passed the fix, the notes its last round left: findings below `major` that a later round no longer sends back, which hold a fix under `autonomy: merge` with `review_notes`. Absent when the review left none open, or the run saved no fix.' person_reasons: type: array x-go-type-skip-optional-pointer: true items: $ref: '#/components/schemas/LavaflowReviewPersonReason' description: What the review saved with the fix asks a person to decide before the fix merges. Absent when it asks nothing or the run saved no fix. + observations: + type: array + x-go-type-skip-optional-pointer: true + items: + type: string + description: 'The reviewers'' observations on the fix saved with the run: follow-ups that don''t hold the fix, such as bad data stored before it or a related problem elsewhere. They aren''t findings, unlike a minor finding that blocks nothing. When LavaFlow withholds an observation, a sentence that says why stands in: `LavaFlow left this observation out because it may contain a credential` when it may contain a credential or holds one of the project''s secret values; `… because it''s too long to check for a credential` when it is over 4,000 characters; and `… because the fix may add a credential` when the run is held with `possible_credential`. Absent when there are none or the run saved no fix.' required: - verdict - rounds @@ -32213,7 +33459,7 @@ components: properties: kind: type: string - description: '`irreversible`: the fix deletes or migrates data, or does what a revert can''t undo. `trust_boundary`: it changes authentication, authorization, secrets, or who can reach what. `breaks_contract`: it changes an interface other code or users depend on. `billing`: it touches payments, pricing, metering, or charges. `unexplained`: it changes behavior its context doesn''t explain. `not_reviewable`: it couldn''t be reviewed closely. New kinds may appear.' + description: '`irreversible`: merging the fix itself does what a revert can''t undo, such as deleting or migrating stored data. `trust_boundary`: it changes authentication, authorization, secrets, who can reach what, or rate limits, quotas or other abuse controls, including whether they fail open. `breaks_contract`: it removes or renames an existing field, status, event, or accepted input that other code or users rely on, or changes what one means. `billing`: it touches payments, pricing, metering, or charges. `unexplained`: it changes behavior that neither the diagnosis nor the fix''s stated choices justify, and that the code doesn''t support. `not_reviewable`: it couldn''t be reviewed closely. New kinds may appear.' question: type: string description: What the person decides, written to show as given. @@ -32332,6 +33578,16 @@ components: items: type: string description: The files whose changes `diff` leaves out, by path, as its `# LavaFlow withheld` lines name them; an empty string for a file whose path may itself hold a credential. Empty when `diff` shows every file, or is null. + choices: + type: array + x-go-type-skip-optional-pointer: true + items: + type: string + description: 'The behavior the saved fix says it decides beyond stopping the error, one plain sentence each. Under `autonomy: merge`, a fix is held with `choices_to_confirm` for a person to confirm these only when LavaFlow''s reviewers didn''t all mark each one as needing no person; a fix they all cleared merges without a person. A person who merges the fix confirms them as they review it. When LavaFlow withholds a choice, a sentence that says why stands in: `LavaFlow left this statement out because it may contain a credential` when it may contain a credential or holds one of the project''s secret values; `… because it''s too long to check for a credential` when it is over 4,000 characters; and `… because the fix may add a credential` when the run is held with `possible_credential`. Absent when the fix states none or the run saved no fix.' + not_fixed: + type: string + nullable: true + description: Where the saved fix says the defect starts outside its changes, such as code that writes records in the wrong shape, and why the fix leaves it, in one plain sentence. Masked as `choices` is. Null when the fix says nothing is left or the run saved no fix. review: allOf: - $ref: '#/components/schemas/LavaflowReview' @@ -32380,6 +33636,7 @@ components: - diff_sha256 - diff_truncated - diff_withheld + - not_fixed - review - repository_checks - failure @@ -32892,7 +34149,7 @@ components: - data LavaflowRunProgress: type: object - description: 'How far an active run has come. The steps are `queued`, `diagnosing`, `fixing`, `reviewing`, `waiting_for_checks` and `merge_queued`, in that order, and a run takes as many as its autonomy when it was queued allows: 2 for `diagnose_only`, 4 for `open_pr` (opening the pull request ends it), 6 for `merge` (the merge ends it).' + description: 'How far an active run has come. The steps are `queued`, `diagnosing`, `fixing`, `reviewing`, `waiting_for_checks` and `merge_queued`, in that order, and a run takes as many as its autonomy when it was queued allows: 2 for `diagnose_only`, 4 for `open_pr` (opening the pull request ends it, unless LavaFlow starts the fix''s CI once, when it shows `waiting_for_checks` as step 5 until LavaFlow has), 6 for `merge` (the merge ends it).' properties: stage: type: string @@ -33177,7 +34434,7 @@ components: waiting_reason: type: string nullable: true - description: 'The bound a waiting scan waits at: `findings_limit`, `pull_request_limit`, `spend_limit`, `scan_limit` or `feature_unavailable`. Null while it only waits out its settle window, and for a scan that started. A waiting scan skips no deploy: it covers every commit since the last scan when it starts.' + description: 'The bound a waiting scan waits at: `findings_limit`, `pull_request_limit`, `spend_limit`, `scan_limit` or `feature_unavailable`; `feature_paused` means a platform publication pause is holding the scan without spending its retry allowance. Null while it only waits out its settle window, and for a scan that started. A waiting scan skips no deploy: it covers every commit since the last scan when it starts.' repository_id: type: integer format: int64 @@ -33730,6 +34987,13 @@ components: error: type: string description: Error detail when action is `error`. + code: + type: string + description: | + Machine-readable reason for a `notice`, when it has one. Clients must accept codes not listed + here. `function_served_by_candidate` - a promoted preview serves the function and keeps the + variables it was built with, so the apply did not synchronize the function's variables; the + entry's action is `unchanged`, and the rest of the apply succeeded. notice: type: string description: Optional operational note (e.g. disabling realtime drops active connections). @@ -36811,6 +38075,169 @@ components: - review - 'off' description: What LavaFlow will do with a skill it learns from a writer's correction of one of its fixes, once learning ships in a later release. `auto`, the default, activates it at once. `review` keeps it `proposed` until the owner activates it. `off` learns none and loads no project skill; the project's skills stay readable and deletable. A writer of the repository can steer LavaFlow through what it learns, outside the repository's history and branch protection, so a repository that protects its guidance, or relays CI output through a bot account with write access, should use `review`. Turning learning up needs the project's `lavaflow.skills` capability. + LavaflowOutcomeValues: + type: object + description: Exact counts only when collection coverage is complete. Null means unknown, including days with no retained observations. + properties: + pull_requests_merged: + type: integer + format: int64 + minimum: 0 + nullable: true + improvements_observed_live: + type: integer + format: int64 + minimum: 0 + nullable: true + issue_resolutions: + type: integer + format: int64 + minimum: 0 + nullable: true + required: + - pull_requests_merged + - improvements_observed_live + - issue_resolutions + LavaflowOutcomeCounts: + type: object + description: Retained confirmations in the requested interval. These are lower bounds when collection coverage is incomplete. + properties: + pull_requests_merged: + type: integer + format: int64 + minimum: 0 + improvements_observed_live: + type: integer + format: int64 + minimum: 0 + issue_resolutions: + type: integer + format: int64 + minimum: 0 + required: + - pull_requests_merged + - improvements_observed_live + - issue_resolutions + LavaflowOutcomeDay: + type: object + properties: + date: + type: string + format: date + counts: + $ref: '#/components/schemas/LavaflowOutcomeValues' + confirmed_counts: + $ref: '#/components/schemas/LavaflowOutcomeCounts' + required: + - date + - counts + - confirmed_counts + LavaflowOutcomeCoverage: + type: object + description: Collection coverage for one metric. A migration or the earliest retained event establishes no complete interval. Undated observations are not assigned to the requested dates or totals. + properties: + status: + type: string + enum: + - complete + - partial + - unavailable + x-enum-varnames: + - LavaflowOutcomeCoverageStatusComplete + - LavaflowOutcomeCoverageStatusPartial + - LavaflowOutcomeCoverageStatusUnavailable + complete_from: + type: string + format: date-time + nullable: true + complete_through: + type: string + format: date-time + nullable: true + reason: + type: string + event_time_basis: + type: string + enum: + - confirmed_merge_time + - first_recorded_live_confirmation + - recorded_automatic_resolution + supported_sources: + type: array + items: + type: string + undated_confirmed_events: + type: integer + format: int64 + minimum: 0 + required: + - status + - complete_from + - complete_through + - reason + - event_time_basis + - supported_sources + - undated_confirmed_events + LavaflowOutcomeCurrent: + type: object + description: Current known open critical Code Quality findings, including findings without a fix run. The historical window and run-category filter do not narrow this inventory. Zero is not an exhaustive security assessment. + properties: + known_open_critical_count: + type: integer + format: int64 + minimum: 0 + scope: + type: string + enum: + - confirmed_code_quality + inventory_not_exhaustive: + type: boolean + category_filter_applied: + type: boolean + required: + - known_open_critical_count + - scope + - inventory_not_exhaustive + - category_filter_applied + LavaflowOutcomes: + type: object + description: Separate confirmed merges, live improvements and actual automatic issue-resolution episodes. A live improvement is counted once per project, repository and pull request when inclusion is first durably confirmed on a tracked function or frontend. Resolution includes automatic open or ignored to resolved transitions, preserves the reason and category, and excludes manual actions. The primary issue resolution count includes every category, even when a category filter narrows merge and live counts. Only the first qualifying automatic resolution of a metric episode contributes a count. Recurrence and manual reopen start new metric episodes without erasing previous resolutions; moving resolved to ignored does not start an episode. Existing activity counts remain separate. Older servers omit this object; absence is unavailable, never zero. + properties: + as_of: + type: string + format: date-time + description: The UTC timestamp of the consistent database snapshot. + days: + type: array + description: The same ordered UTC date domain as the activity series, with unknown counts distinct from zero retained confirmations. + items: + $ref: '#/components/schemas/LavaflowOutcomeDay' + totals: + $ref: '#/components/schemas/LavaflowOutcomeValues' + confirmed_totals: + $ref: '#/components/schemas/LavaflowOutcomeCounts' + coverage: + type: object + properties: + pull_requests_merged: + $ref: '#/components/schemas/LavaflowOutcomeCoverage' + improvements_observed_live: + $ref: '#/components/schemas/LavaflowOutcomeCoverage' + issue_resolutions: + $ref: '#/components/schemas/LavaflowOutcomeCoverage' + required: + - pull_requests_merged + - improvements_observed_live + - issue_resolutions + current: + $ref: '#/components/schemas/LavaflowOutcomeCurrent' + required: + - as_of + - days + - totals + - confirmed_totals + - coverage + - current LavaflowRunReference: type: object description: Another LavaFlow run of the same project. diff --git a/content/platform/api-reference/overview.md b/content/platform/api-reference/overview.md index 6611d04..a30833d 100644 --- a/content/platform/api-reference/overview.md +++ b/content/platform/api-reference/overview.md @@ -202,7 +202,9 @@ curl "https://api.volcano.dev/capabilities" { "id": "lavaflow", "status": "unavailable" }, { "id": "lavaflow.merge", "status": "unavailable" }, { "id": "lavaflow.lineage", "status": "unavailable" }, + { "id": "lavaflow.open_pr_ci_start", "status": "unavailable" }, { "id": "lavaflow.slack", "status": "unavailable" }, + { "id": "lavaflow.aikido", "status": "unavailable" }, { "id": "lavaflow.skills", "status": "unavailable" }, { "id": "functions.response_streaming", "status": "available" }, { "id": "frontend_routes", "status": "available" }, @@ -213,24 +215,27 @@ curl "https://api.volcano.dev/capabilities" } ``` -| ID | Covers | -| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `sandboxes` | The Sandbox API: presets, templates, sessions, and executions | -| `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions | -| `sandboxes.custom_templates` | Deploying a custom template; its validation waits while `sandboxes.sessions` is unavailable | -| `sandboxes.network_isolation` | Creating [sessions with no outbound network](../guides/sandboxes.md#turn-off-outbound-network); existing ones work either way | -| `sandboxes.output_not_kept` | [Commands that keep no output](../guides/sandboxes.md#keep-no-command-output); commands that keep output work either way | -| `issues` | The Issues API: listing, reading, and updating grouped runtime errors | -| `lavaflow` | LavaFlow, which diagnoses a project's issues, opens pull requests that fix them, and can merge them. This list says only whether it's released in the environment; a project's list says whether that project has it | -| `lavaflow.merge` | Letting LavaFlow [merge its fixes](../guides/lavaflow.md#merge-fixes): `autonomy: merge` and changing `merge_policy`; reading merges works either way | -| `lavaflow.lineage` | LavaFlow [following up its fixes](../guides/lavaflow.md#fix-lineage): follow-up runs and the lineage holds; lineage fields already stored read either way | -| `lavaflow.slack` | [Reporting problems from Slack](../guides/lavaflow-slack.md): installing Volcano's Slack app, connecting Slack accounts, the channel picker, and binding channels; reading and removing connections and bindings work either way | -| `lavaflow.skills` | [Learned skills](../guides/lavaflow.md#learned-skills): changing a skill other than retiring it, turning `skill_learning` up, and Volcano's global skills; reading, retiring and deleting skills, and turning learning off, work either way | -| `functions.response_streaming` | [Streaming a response](../functions/invoking-functions.md#stream-a-response) on a function's own URL | -| `frontend_routes` | Creating and changing [Frontend routes](../frontends/frontend-routes.md); listing, deleting, and serving existing ones work either way | -| `frontends.candidates` | Creating, deploying to, promoting and rolling back to [frontend previews](../frontends/previews.md); listing, reading and deleting them, and rolling back to the frontend's own build, work either way | -| `databases.migrations` | Starting [migration runs](../guides/migrations.md), recording a baseline, and turning on `apply_migrations` for [Git deploy](../projects/git-deploy.md#apply-migrations-on-push); reading history and runs works either way | -| `shares` | [Sharing and forking](../projects/sharing.md): sharing a project and forking a share; listing, reading, switching off, deleting, and counting existing shares work either way | +| ID | Covers | +| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `sandboxes` | The Sandbox API: presets, templates, sessions, and executions | +| `sandboxes.sessions` | Starting and resuming sessions, and one-shot executions | +| `sandboxes.custom_templates` | Deploying a custom template; its validation waits while `sandboxes.sessions` is unavailable | +| `sandboxes.network_isolation` | Creating [sessions with no outbound network](../guides/sandboxes.md#turn-off-outbound-network); existing ones work either way | +| `sandboxes.output_not_kept` | [Commands that keep no output](../guides/sandboxes.md#keep-no-command-output); commands that keep output work either way | +| `issues` | The Issues API: listing, reading, and updating grouped runtime errors | +| `lavaflow` | LavaFlow, which diagnoses a project's issues, opens pull requests that fix them, and can merge them. This list says only whether it's released in the environment; a project's list says whether that project has it | +| `lavaflow.merge` | Letting LavaFlow [merge its fixes](../guides/lavaflow.md#merge-fixes): `autonomy: merge` and changing `merge_policy`; reading merges works either way | +| `lavaflow.lineage` | LavaFlow [following up its fixes](../guides/lavaflow.md#fix-lineage): follow-up runs and the lineage holds; lineage fields already stored read either way | +| `lavaflow.open_pr_ci_start` | A fix you [review and merge yourself](../guides/lavaflow.md#review-and-merge-fixes-yourself) opening ready for review, with LavaFlow running its CI once unless your repository may run CI outside GitHub Actions; unavailable, it opens as a draft whose commit skips CI | +| `lavaflow.slack` | [Reporting problems from Slack](../guides/lavaflow-slack.md): installing Volcano's Slack app, connecting Slack accounts, the channel picker, and binding channels; reading and removing connections and bindings work either way | +| `lavaflow.aikido` | [Fixing Aikido issues](../guides/lavaflow-aikido.md): connecting an Aikido workspace and binding projects to it; reading and removing connectors and bindings work either way | +| `lavaflow.skills` | [Learned skills](../guides/lavaflow.md#learned-skills): changing a skill other than retiring it, turning `skill_learning` up, and Volcano's global skills; reading, retiring and deleting skills, and turning learning off, work either way | +| `functions.response_streaming` | [Streaming a response](../functions/invoking-functions.md#stream-a-response) on a function's own URL | +| `frontend_routes` | Creating and changing [Frontend routes](../frontends/frontend-routes.md); listing, deleting, and serving existing ones work either way | +| `frontends.candidates` | Creating, deploying to, promoting and rolling back to [frontend previews](../frontends/previews.md); listing, reading and deleting them, and rolling back to the frontend's own build, work either way | +| `functions.candidates` | Creating, deploying to, promoting and rolling back to [function previews](../functions/previews.md); listing, reading and deleting them, and rolling back to the function's own build, work either way | +| `databases.migrations` | Starting [migration runs](../guides/migrations.md), recording a baseline, and turning on `apply_migrations` for [Git deploy](../projects/git-deploy.md#apply-migrations-on-push); reading history and runs works either way | +| `shares` | [Sharing and forking](../projects/sharing.md): sharing a project and forking a share; listing, reading, switching off, deleting, and counting existing shares work either way | The endpoint needs no token, and every caller in an environment gets the same answer. While a capability is `unavailable`, requests that start new work @@ -282,9 +287,13 @@ says what the project can still do: `lavaflow.merge` is `available` when `lavaflow` is and LavaFlow may merge fixes in the environment. `lavaflow.lineage` is `available` when `lavaflow` is -and fix lineage is released in the environment. `lavaflow.slack` is +and fix lineage is released in the environment. `lavaflow.open_pr_ci_start` +is `available` when `lavaflow` is and the one CI start for fixes you merge is +released in the environment. `lavaflow.slack` is `available` when `lavaflow` is and reporting problems from Slack is available in the environment, which is rolling out environment by environment. +`lavaflow.aikido` is `available` when `lavaflow` is and Aikido reports have +launched in the environment. `lavaflow.skills` is `available` when `lavaflow` is and learned skills are released in the environment. `read_only` appears only in a project's list, and has no `code`. On an @@ -407,7 +416,7 @@ Issues are in preview. See [Issues](../guides/issues.md). | `GET` | `/lavaflow/settings` | Get a project's LavaFlow settings | | `PATCH` | `/lavaflow/settings` | Change a project's LavaFlow settings; the owner only, except that a full-scope project access token may turn Code Quality or skill learning off | | `PUT` | `/lavaflow/settings` | Deprecated; does what `PATCH` does for a person, and refuses every project access token | -| `GET` | `/lavaflow/stats` | Count issues LavaFlow took on and pull requests it opened; filter with `category` | +| `GET` | `/lavaflow/stats` | Count issues LavaFlow took on and pull requests it opened, and its confirmed outcomes; filter with `category` | | `GET` | `/lavaflow/resources` | List each resource's LavaFlow activity and anomalies; filter with `category` | | `GET` | `/lavaflow/runs` | List LavaFlow runs; filter with `status`, `category`, `resource_id`, `involved_resource_id`, `issue_id`, `pull_request_state` and `days`, sort with `order`, and count with `include=counts` | | `POST` | `/lavaflow/runs` | Start a run on an issue; the owner only | diff --git a/content/platform/functions/creating-functions.md b/content/platform/functions/creating-functions.md index 6cd68e6..690fa0d 100644 --- a/content/platform/functions/creating-functions.md +++ b/content/platform/functions/creating-functions.md @@ -86,10 +86,40 @@ How the build compiles it: `main.py` or `main.rb` beside `index.ts` stays the entry, with its runtime. - `.tsx` files aren't compiled. -[Git deploy](../projects/git-deploy.md) and the -[upload API](./upload-api.md) compile TypeScript, in the cloud and in local -mode. The CLI doesn't find `.ts` files yet, so compile a function to JavaScript -before you deploy it with the CLI. +Errors name your TypeScript. The build writes a source map beside the compiled +handler and turns on Node.js source maps before the handler loads, so a stack +trace in your function's logs, in [Issues](../guides/issues.md), and in your +own `error.stack` names the `.ts` file and line, such as `lib/billing.ts:4`, +by its path under the function's root. Frames in installed packages stay as +the package ships them. + +- The compiled handler is `index.cjs` or `index.mjs`, and it loads + `index.bundle.cjs` or `index.bundle.mjs`, which holds your code. Your code's + `__dirname` and `import.meta.url` stay the directory `index.ts` is in. +- Source maps cost CPU when a stack trace is read; a stack nothing reads costs + nothing. The first one in each running instance parses the map, and later + ones cost about three times an unmapped stack. Measured on Node.js 24 with a + 98 KiB map, the first stack took about 0.6 s at 128 MB of memory and 0.05 s + at 1024 MB, and the parsed map used about 12 to 17 MB more memory. The cost + grows with the map, so a map over 256 KiB isn't + written; a map at that limit costs about 1 s at 128 MB, extrapolated from + measurements of 98 KiB and 1.9 MiB maps. +- Set `NODE_OPTIONS=--no-enable-source-maps` to turn source maps off, or + `NODE_OPTIONS=--enable-source-maps` to turn them on for installed packages + too; Volcano leaves your setting as it is. +- A handler compiles without a source map, so its frames name `index.cjs` or + `index.mjs`, when its map would pass 256 KiB, when a file in the function + already has the bundle's or the + map's name, when it bundles a file from outside the function's directory or + a JavaScript file whose own source map points outside it or to a URL, or + when an ES module handler re-exports everything from an installed package, + as `export * from "package"` does. The build log says which. + +Volcano compiles TypeScript deployed with [Git deploy](../projects/git-deploy.md), +the [upload API](./upload-api.md) or the [CLI](/cli/functions), in the cloud and +in local mode. The CLI uploads TypeScript handlers from version 0.76.0; older +versions skip `.ts` files, so upgrade first. See +[CLI project layout](#cli-project-layout) for the TypeScript files it finds. ### Python @@ -146,6 +176,7 @@ These are the simplest option. The filename becomes the function name. ```text volcano/functions/hello.js +volcano/functions/greet.ts volcano/functions/notes.py volcano/functions/worker.rb ``` @@ -153,6 +184,7 @@ volcano/functions/worker.rb Examples: - `volcano/functions/hello.js` -> function name `hello` +- `volcano/functions/greet.ts` -> function name `greet` (also `.mts` and `.cts`) - `volcano/functions/notes.py` -> function name `notes` - `volcano/functions/worker.rb` -> function name `worker` @@ -162,6 +194,7 @@ Use a directory when a function needs multiple files. ```text volcano/functions/api/index.js +volcano/functions/checkout/index.ts volcano/functions/jobs/main.py volcano/functions/reports/main.rb ``` @@ -170,14 +203,24 @@ The directory name becomes the function name. Discovery rules: -- The CLI first looks for `index.*` inside the directory. -- If no `index.*` file exists, it falls back to the first supported runtime file it finds. +- The entry is the runtime's handler file at the top of the directory: + `index.js`, `main.py` or `main.rb`. A directory with none of them, and no + TypeScript index, isn't a function. +- A TypeScript directory function needs its handler at the top of the + directory as `index.ts`, `index.mts` or `index.cts`. An `index.js`, `main.py` + or `main.rb` beside it deploys instead; other files, such as `helpers.js`, + don't. Examples: - `volcano/functions/api/index.js` -> function name `api` +- `volcano/functions/checkout/index.ts` -> function name `checkout` - `volcano/functions/jobs/main.py` -> function name `jobs` +TypeScript needs CLI 0.76.0 or later. The CLI doesn't find `.tsx` files or +declaration files such as `types.d.ts`. It doesn't find a handler nested below +the function's directory, such as `volcano/functions/checkout/src/index.ts`. + ### Shared code Any file or directory whose basename starts with `_` is treated as shared code and @@ -192,6 +235,45 @@ volcano/functions/_helpers/ This is useful for shared utilities without requiring each function to duplicate them. +Once deployed, shared code sits next to the function's entry file under its own +name, whether it came from `volcano/` or `volcano/functions/`. Import it from +there in every function, including directory functions. From the entry file: + +| Runtime | Import `volcano/functions/_helpers/db.*` as | +| ------- | ------------------------------------------------------- | +| Node.js | `require('./_helpers/db')` or `from './_helpers/db.js'` | +| Python | `from _helpers.db import connect` | +| Ruby | `require_relative '_helpers/db'` | + +A file in a subdirectory of a directory function, such as +`volcano/functions/api/lib/orders.js`, adds one `../` per level in Node.js and +Ruby: `require('../_helpers/db')`. Python's import is the same from any file. + +A directory function's entry file that imports `../_helpers/db` works in your +repository but fails once deployed, in Node.js with `Cannot find module`. A +[Git deploy](../projects/git-deploy.md) warns about it in the function's +[build log](logs.md#deployment-logs), with the file, the line, and the import +to use instead. + +The same goes for a single-file function and shared code directly under +`volcano/`: `volcano/functions/hello.js` imports `volcano/_shared/utils.js` as +`./_shared/utils`, and `../_shared/utils` fails once deployed. Keep shared code +under `volcano/functions/` instead, and a single-file function's `./_shared` +import resolves in your repository too. + +To make your tests resolve the same imports in your repository, link the +shared directory into the function's directory: + +```bash +ln -s ../_helpers volcano/functions/api/_helpers +``` + +For shared code directly under `volcano/`, link `../../_name` instead. Node.js +and Ruby then resolve `./_helpers/db` from `volcano/functions/api/`. Python +resolves `_helpers.db` once the function's directory is on `sys.path`, as it is +for a test file in that directory run with pytest or `python`. Deploys skip +symbolic links, so the function still gets the real `_helpers/`. + ### Dependencies Cloud deployments upload source plus dependency manifests. Volcano installs dependencies during the function compile build using the selected runtime. Do not include installed dependency directories in cloud uploads. diff --git a/content/platform/functions/environment-variables.md b/content/platform/functions/environment-variables.md index f8cfad3..cc51ea1 100644 --- a/content/platform/functions/environment-variables.md +++ b/content/platform/functions/environment-variables.md @@ -142,6 +142,26 @@ Dashboard clients can replace the list with `PUT /projects/{id}/shared-variables ``` The operation returns `204` after saving membership and starting synchronization. +When a [promoted preview](previews.md#while-a-preview-serves) serves a function +the change would reach, that function keeps the variables the preview was built +with: the operation still saves membership and synchronizes every other +function, and returns `200` with a `skipped_functions` list naming each skipped +function's `id` and `name`, a `code` (`function_served_by_candidate`; accept +codes not listed here) and a `message`: + +```json +{ + "skipped_functions": [ + { + "id": "8f8c1d1e-4a3b-4c55-9e7a-2f4b8a7c6d10", + "name": "api", + "code": "function_served_by_candidate", + "message": "a promoted preview serves this function and keeps the variables it was built with; ..." + } + ] +} +``` + Request bodies larger than 4 MiB return `413` before decoding. Unknown names or an oversized final function environment return `400` before any membership, sync, or deployment changes. The final list is validated as a diff --git a/content/platform/functions/logs.md b/content/platform/functions/logs.md index c1df309..fb1bbe7 100644 --- a/content/platform/functions/logs.md +++ b/content/platform/functions/logs.md @@ -140,6 +140,22 @@ curl -X POST "https://api.volcano.dev/projects/PROJECT_ID/logs/search" \ -d '{"resource":{"type":"function"},"limit":100,"cursor":"eyJwayI6..."}' ``` +## While a Preview Serves + +While a function is promoted to one of its [previews](previews.md), its runtime +logs include the lines the preview wrote while it served, and for 15 +minutes after, under the function's ID and name. + +- `resource.id:FUNC_ID` in `q` matches those lines too, and `resource.id:PREVIEW_ID` + matches none of them in the function's logs. To read the preview's own lines, + select its ID in `resource.ids`. +- A cursor reads what its first page read. A promotion or rollback made while + you page shows from the next search without a cursor. +- A search of every function (`resource.ids` omitted) by `invocation.id` alone + reads the project's log index without looking up the functions, so it reports + a line the preview wrote while serving under the preview's ID. Select + the function's ID to read it as the function's. + ## Activity Count logs over time to draw a histogram. The request takes the same diff --git a/content/platform/functions/previews.md b/content/platform/functions/previews.md new file mode 100644 index 0000000..9211166 --- /dev/null +++ b/content/platform/functions/previews.md @@ -0,0 +1,216 @@ +--- +title: 'Function previews' +description: "Deploy a build of a function to its own runtime and URL, check it with production's variables, point the function's traffic at it, and roll back." +--- + +A preview is a copy of an ordinary function that you deploy to its own URL +before it replaces what the function runs. Use it to check a change against +your real project variables, then point the function's traffic at the build +you checked, without rebuilding or redeploying anything. + +## Deploy a preview + +```bash +volcano cloud functions preview create api --name checkout-v2 --path ./functions/api +``` + +`--name` is required and unique within the function, and a function can have +at most 20 live previews. `--ttl` deletes the preview after that long, up to 720 +hours; without it the preview lives until you delete it. The build uses the +function's runtime and handler and spends the project's build minutes, as a +deploy of the function does: every build is charged by the time it ran, whether +it succeeds or fails, and a create or redeploy is refused with `429` once the +project's build minutes are used up. Read the URL when the first deployment is +ready: + +```bash +volcano cloud functions preview get api checkout-v2 +volcano cloud functions preview list api +``` + +Deploy a new build to the same preview with `preview deploy api checkout-v2 +--path ./functions/api`. The preview keeps serving its previous build until the +new one succeeds. + +## Invoke a preview + +A preview runs on a runtime of its own in every region the function deploys to, +and is invoked at `https://.`, as a function is at +its own ID. A preview is always private, whatever the function's own +visibility: only the project's service key, with the `functions.invoke` +permission, can invoke it. Signed-in users, anon keys and access tokens are +refused, the project owner's included. The function's invocation mode (RPC or +HTTP) carries over; its unauthenticated HTTP setting does not. + +A preview gets none of the function's [schedules](scheduled-invocations.md) or +warmers, and calls to `/functions/{id}/invoke` and the schedule API do not reach +it: only its own host does. Frontend function routes keep pointing at the +function. + +## What a preview runs with + +A preview builds with the function's variables as they are when you deploy it: +its variable scope and declared names, the names its source reads, and the +project's values, secrets included. It keeps them: changing a variable +afterwards does not reach a running preview. `preview get` reports +`Variables: changed` once the function would give that source different values. + +A preview is not a sandbox. It runs with production's values, so it reaches +production databases and services. Deploy only code you would deploy to the +function itself, and delete a preview you no longer need. + +## Promote a preview + +```bash +volcano cloud functions preview promote api checkout-v2 +``` + +Promotion points the function's traffic at the preview's runtime. Nothing is +deployed or rebuilt, so it takes effect at once: every call to the function, +through its own URL, `/functions/{id}/invoke`, a schedule or a frontend route, +runs the preview's code, and the function's warmer warms the preview's runtime. +The function keeps its ID, URL, visibility, schedules, rate limits, usage and +invocation records. Its own build is left running as it is, so rolling back is just as +quick. + +Promotion is refused with `409` when the preview is not serving a successful +deployment built with the function's current variables, runtime and handler in +every region, while a deployment of the function or a synchronization of its +variables runs, and once the project's repository is the source of truth. See +[Error codes](#error-codes) for each refusal. + +Once the project's repository is the source of truth, promotion is refused +(`source_managed_by_git`) because the repository does not have the preview's +code and its next deploy would replace it. Previews can still be created, +deployed and deleted. + +`volcano cloud functions serving api` shows what the function runs. + +### While a preview serves + +- The function's logs (`volcano cloud functions logs api`, and project log + search and streams for the function) include the code's output from the + preview for as long as it serves, under the function's ID, in one + timeline with the function's own lines. After a rollback, the preview's + lines stay in that timeline for up to 15 minutes, so calls still running at + the switch are not lost. The log activity chart counts the function's own + build only. +- Search with the preview's ID to read the preview's own logs. They include + every line it wrote, those written while it served the function too. +- The preview keeps the variables it was built with. Setting or deleting a + single variable that would change the function's environment is refused with + `409` and `code: function_served_by_candidate` before anything is stored, + because it would reach only the function's own build, which receives no + traffic. Roll back or deploy first, then write it again. +- `volcano config deploy` and replacing the shared variable list store the + change for the whole project at once, so they are not refused: every other + function and frontend gets the change, and the served function is reported as + skipped (`code: function_served_by_candidate`). The report is a notice, not an + error: `config deploy` exits successfully, and the shared list replacement + answers `200` naming each skipped function. `volcano cloud functions serving + api` then reports its own build's environment as out of date. A rollback to + its own build starts synchronizing it with the current values as it returns + the traffic, and the synchronization is retried in the background if it + cannot start; `serving` reports the environment out of date until that + synchronization completes or a deploy of the function activates. +- Deploying the function itself is allowed: once the deployment succeeds, the + function's traffic returns to its own, new build, and the preview is no + longer held for a rollback. +- The preview cannot be deleted, redeployed or expired. +- If the project's regions change, the function is not redeployed to them: + that deployment would return its traffic to its own build and undo the + promotion. Every other function and frontend moves. The function moves to the + new regions after a rollback to its own build, or when you deploy it. +- Reading the function returns the preview's ID as `serving_candidate_id`. + While it is set, the function's `status` and `current_deployment_id` describe + its own build, which receives no traffic. + +## Roll back + +```bash +volcano cloud functions rollback api +volcano cloud functions rollback api --to-production +``` + +A rollback points the function back at what served it before its last +promotion or rollback, so a second rollback undoes the first. With +`--to-production` it returns to the function's own build. It takes effect at +once. A rollback that would make a preview serve again is a promotion, and is +refused like one. A rollback to the function's own build is not: it works +while previews are unavailable to the project, while a deployment of the function runs, and +once the project's repository is the source of truth. + +Every promotion and rollback names the serving `revision` it read, and is +refused with `stale_revision` if someone promoted or rolled back since. The CLI +reads it for you, so retrying a rollback that already applied is refused rather +than undoing it. + +Rollback restores code and configuration only. Database changes and other side +effects of the promoted code are not undone. + +## Delete a preview + +```bash +volcano cloud functions preview delete api checkout-v2 +``` + +This removes the preview's runtime, its URL, its builds and its stored source. A +preview the function runs cannot be deleted (`409`, `candidate_in_use`): roll +back first. Deleting a preview kept for a rollback gives that rollback up. +Deleting the function deletes its previews first. + +The lines a preview wrote while it served the function stay in the function's +logs after the preview is deleted, until your plan's log retention ends. + +## Git-managed projects + +Once a project's repository is the source of truth, its functions deploy from +pushes to the production branch, and a preview, built from an uploaded source, +cannot replace what a function runs: promoting one, and rolling back to one, +are refused with `409` and `code: source_managed_by_git`. Rolling back to the +function's own build still works, so a preview that serves when the handover +starts can always be taken out of traffic. + +## Error codes + +The API answers these codes. `409` is a conflict with the state of the +function, the preview or the project; read it again before retrying. + +| Status | Code | Answered by | Why | +| ------ | ------------------------------ | --------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `400` | - | create, deploy, promote, rollback | An invalid name, expiry, identifier, source archive or body, or a variable the source reads has no value. | +| `404` | `feature_unavailable` | create, deploy, promote, rollback | Previews are not available to the project. A rollback answers it only when it would make a preview serve again. | +| `409` | `durable_function_unsupported` | create, deploy, promote, rollback | The function is durable. Durable functions have no previews; reading them answers none. | +| `409` | `candidate_name_taken` | create | The function has a preview with this name. | +| `409` | `candidate_limit_reached` | create | The function has 20 live previews. | +| `409` | `function_deleting` | create, deploy, promote, rollback | The function is being deleted. | +| `409` | `project_deleting` | create | The project is being deleted. | +| `409` | `deployment_in_progress` | deploy, promote, rollback | A deployment of the preview, or of the function, or a synchronization of the function's variables, is running. | +| `409` | `candidate_not_deployable` | deploy | The preview is being deleted. | +| `409` | `candidate_in_use` | deploy, delete | The function runs the preview, or keeps it for a rollback (deploy only). Roll back first. | +| `409` | `candidate_not_ready` | promote, rollback | The preview is not serving a successful deployment, or its latest redeploy failed; redeploy it successfully first. | +| `409` | `configuration_changed` | promote, rollback | The function's variables, runtime or handler changed since the preview was built. Redeploy it. | +| `409` | `candidate_regions_changed` | promote, rollback | The function deploys to a region the preview was not built in. Redeploy it. | +| `409` | `function_not_deployed` | promote, rollback | The function has no successful deployment of its own to roll back to. | +| `409` | `stale_revision` | promote, rollback | Someone promoted or rolled back since the revision the request named. | +| `409` | `already_serving` | promote | The function already runs this preview. | +| `409` | `source_managed_by_git` | promote, rollback | The project's repository is the source of truth. A rollback answers it only when it would make a preview serve again. | +| `409` | `nothing_to_roll_back` | rollback | The function runs its own build and keeps no preview to return to. | +| `409` | `rollback_unavailable` | rollback | The preview a rollback would return to is gone or no longer serves a successful deployment. | +| `409` | `function_served_by_candidate` | variable writes | A promoted preview serves a function the write would change. Roll back or deploy the function first. | +| `429` | `build_minutes_exceeded` | create, deploy | The project's build minutes for the billing cycle are used up. | + +## Availability + +Creating, deploying to and promoting a preview are behind a release gate and +answer `404` with code `feature_unavailable` while it is off for your +environment. `GET /capabilities` lists `functions.candidates` as `available` +when it is on. Listing, reading and deleting previews, and rolling back to the +function's own build, work either way. + +A deployment reports the image it published by its `sha256` digest, per region, +never by its registry path. The local development server does not +run function previews yet and answers `feature_unavailable`. + +The API calls a preview a Candidate. See +[Function endpoints](../api-reference/functions.md#previews). diff --git a/content/platform/functions/upload-api.md b/content/platform/functions/upload-api.md index 4b213a9..7340eeb 100644 --- a/content/platform/functions/upload-api.md +++ b/content/platform/functions/upload-api.md @@ -223,7 +223,7 @@ When you upload directly to the API, Volcano generates `.volcano/function-build. Volcano infers build roots deterministically: -- `function_root` is the directory containing the single runtime entry file when exactly one is found: `index.js` or `index.mjs` for Node.js, `main.py` for Python, or `main.rb` for Ruby. Git deploy uses the same entry names. A Node.js archive with no JavaScript entry counts `index.ts`, `index.mts` and `index.cts` instead, unless the root found without them already holds the handler as `index.cjs`, an extensionless `index` file or an `index` directory holding a `package.json` or an index file, the `handler` names its own module (such as `src/handler.main`), or the project sets `NODE_PATH`. So an archive holding `src/index.ts` and its compiled `dist/index.js` gets `dist`, and one holding `index.cjs` beside `src/index.ts` keeps `.`. +- `function_root` is the directory containing the single runtime entry file when exactly one is found: `index.js` or `index.mjs` for Node.js, `main.py` for Python, or `main.rb` for Ruby. Git deploy uses the same entry names. A Node.js archive with no JavaScript entry counts `index.ts`, `index.mts` and `index.cts` instead, unless the root found without them already holds the handler as `index.cjs`, an extensionless `index` file or an `index` directory holding a `package.json` or an index file, the `handler` names its own module (such as `src/handler.main`), or the project's `NODE_PATH` names a directory inside the function, where the handler could load from after the install. A `NODE_PATH` that names only directories outside the function doesn't count. So an archive holding `src/index.ts` and its compiled `dist/index.js` gets `dist`, and one holding `index.cjs` beside `src/index.ts` keeps `.`. - If there is no root-level file and all files are under one top-level directory, that top-level directory becomes `function_root`. - Otherwise, `function_root` is the archive root (`.`). - `install_root` prefers the closest dependency manifest directory containing the runtime handler module, resolved relative to `function_root`. @@ -297,7 +297,7 @@ Your source archive exceeds the 256 MB limit. Common solutions: ### "project variables changed during the upload; retry" -The project's `NODE_PATH` variable was created or deleted while Volcano processed the upload. `function_root` depends on whether the project sets `NODE_PATH`, so the request returns `409 Conflict` and deploys nothing. Send the same request again. +The project's `NODE_PATH` variable was created, changed or deleted while Volcano processed the upload. `function_root` depends on the directories `NODE_PATH` names, so the request returns `409 Conflict` and deploys nothing. Send the same request again. ### Function image too large diff --git a/content/platform/guides/issues.md b/content/platform/guides/issues.md index 1d520aa..27d49bc 100644 --- a/content/platform/guides/issues.md +++ b/content/platform/guides/issues.md @@ -164,6 +164,19 @@ fresh LavaFlow run budget. After that, redeploys keep it. A function or project at its open-issue bound records the moved errors only once it has room; resolve the old issues to make room. +A function written in +[TypeScript](../functions/creating-functions.md#typescript) groups by the +frames of its `.ts` files, which its stack traces name through source maps. +A TypeScript function built before Volcano wrote source maps named its compiled +`index.cjs` or `index.mjs` instead, so its first redeploy since moves each of +its existing issues once to a new issue, as above. The old issues, named by +the compiled module, stay open and count toward the open-issue bounds until +you resolve them, so resolve them after that redeploy. A TypeScript function that +[compiles without a source map](../functions/creating-functions.md#typescript), +or that sets `NODE_OPTIONS=--no-enable-source-maps`, groups by its compiled +module, so a change that switches it between the two moves its issues the same +way. + Issues are kept per function or frontend: the same error in two functions is two issues. diff --git a/content/platform/guides/lavaflow-aikido.md b/content/platform/guides/lavaflow-aikido.md new file mode 100644 index 0000000..2c9e233 --- /dev/null +++ b/content/platform/guides/lavaflow-aikido.md @@ -0,0 +1,137 @@ +--- +title: 'Fix Aikido issues with LavaFlow' +description: 'Connect an Aikido workspace so LavaFlow opens fix pull requests for the code issues Aikido finds.' +--- + +Connect your [Aikido](https://www.aikido.dev) workspace, bind a project, and +each new code (SAST) issue Aikido finds on the project's GitHub repository +starts a [LavaFlow](lavaflow.md) run. LavaFlow +reads the issue, diagnoses it, and opens a pull request with the fix for you +to review. It never merges an Aikido fix, and it writes nothing back to +Aikido: follow the run in Volcano. + +Aikido reports need the project's `lavaflow.aikido` capability. They are +rolling out environment by environment, so check it first. It is available +where the project's `lavaflow` capability is and Aikido reports have launched +in the environment: + +```bash +curl "https://api.volcano.dev/projects/$PROJECT_ID/capabilities" \ + -H "Authorization: Bearer $VOLCANO_TOKEN" +``` + +## Set up + +Set up Aikido with the API; the dashboard and the CLI do not manage it yet. + +### 1. Create credentials in Aikido + +As an Aikido workspace admin: + +1. In **Settings → Integrations → REST API**, create an API client. Volcano + reads issues, code repositories and the workspace, so read access is + enough. Copy its client ID and secret. +2. In **Settings → Integrations → Webhooks**, choose **Add secret** and copy + the signing secret. Aikido shows it once. + +### 2. Connect the workspace + +Send the three values and your workspace's region: `eu` for app.aikido.dev, +`us` for app.us.aikido.dev, `au` for app.au.aikido.dev, or `me` for +app.me.aikido.dev. + +```bash +curl -X POST "https://api.volcano.dev/connectors" \ + -H "Authorization: Bearer $VOLCANO_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "type": "aikido", + "aikido": { + "region": "eu", + "client_id": "'"$AIKIDO_CLIENT_ID"'", + "client_secret": "'"$AIKIDO_CLIENT_SECRET"'", + "webhook_secret": "'"$AIKIDO_WEBHOOK_SECRET"'" + } + }' +``` + +Volcano checks the client with Aikido, reads which workspace it belongs to, +and stores the three values encrypted. It never returns them: + +```json +{ + "id": "2d7c0f4e-8a51-4d0b-9a3e-1f6c2b9d4e70", + "type": "aikido", + "name": "Acme", + "aikido": { "region": "eu", "workspace_id": 123 }, + "removable": true, + "created_at": "2026-11-10T12:00:00Z" +} +``` + +| Status | Meaning | +| ------ | --------------------------------------------------------------------------------------- | +| `409` | The workspace is already connected to Volcano. Remove that connector first. | +| `422` | Aikido refused the client, or it can't read the workspace. Check the region and scopes. | +| `502` | Aikido didn't answer. Nothing was saved; try again. | + +A workspace connects to one Volcano account, and only that account sees its +connector. + +### 3. Point Aikido's webhook at Volcano + +In Aikido's webhooks settings, add a webhook for new issues +(`issue.open.created`) with the URL `https://api.volcano.dev/webhooks/aikido`. + +### 4. Bind a project + +As the project's owner, bind the connector. `min_severity` is the lowest +severity that starts a run, and defaults to `high`, since each run counts +against the project's LavaFlow runs: + +```bash +curl -X POST "https://api.volcano.dev/lavaflow/connector-bindings" \ + -H "Authorization: Bearer $VOLCANO_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "project_id": "'"$PROJECT_ID"'", + "connector_id": "2d7c0f4e-8a51-4d0b-9a3e-1f6c2b9d4e70", + "aikido": { "min_severity": "high" } + }' +``` + +Binding again changes the minimum. The project must be connected to the GitHub +repository Aikido scans. + +## What reaches LavaFlow + +A new issue starts a run when all of these hold: + +- It is a code finding (`sast`). Vulnerable dependencies (`open_source`) + are ignored for now: their fixes usually need a lockfile change, which + LavaFlow doesn't make. Secrets, cloud, IaC and other issues need more than + a code change, so they are ignored too. +- Its severity is at or above a bound project's `min_severity`. +- It is still open when LavaFlow picks it up. +- Its code repository is on GitHub, and is the bound project's repository. + +LavaFlow reads the issue's title, rule, file and lines, and Aikido's advice +for fixing it, then runs its usual diagnosis, fix and review. The run stops at +a pull request, whatever the project's own autonomy. +If several bound projects share the repository, the first one bound that +LavaFlow can run on gets the issue. + +Each run counts against the project's LavaFlow run limits, which bound how +many Aikido issues start runs in a day. A workspace holds at most 25 issues +waiting to be picked up, including issues on repositories no project binds, +and LavaFlow reads Aikido at its limit of 20 calls a minute. While 25 are +waiting, Volcano answers a new issue with `503` and `Retry-After`, and Aikido +sends it again; it retries a delivery five times. + +## Remove Aikido + +Remove a project's binding with +`DELETE /lavaflow/connector-bindings/{binding_id}`. Remove the connector with +`DELETE /connectors/{connector_id}`: its credentials and bindings are deleted, +and issues still waiting are canceled. Then delete the webhook in Aikido, +since Volcano refuses its deliveries from then on. diff --git a/content/platform/guides/lavaflow-slack.md b/content/platform/guides/lavaflow-slack.md index 3a24b6e..05920db 100644 --- a/content/platform/guides/lavaflow-slack.md +++ b/content/platform/guides/lavaflow-slack.md @@ -82,8 +82,13 @@ its limit of open issues is refused in the thread, and so is one that has used its LavaFlow runs for the day; that reply says when to mention Volcano again. While LavaFlow is paused, it keeps a report for up to 10 days after it arrives, -and picks it up if LavaFlow resumes in that time. A reporter who may report for -no project is refused even while LavaFlow is paused. +and picks it up if LavaFlow resumes in that time. A reporter without an +authorized project can still be refused during a run-execution pause. During a +publication maintenance pause, outgoing notices also wait, including pause and +refusal notices; the pause does not use the report's retry allowance. +Authorization and retention still apply. A capped or unauthorized report ends +without a channel notice. Its text is cleared unless it was already kept as a +clarification; previously clarified text keeps its existing retention period. Answers and fix pull request links are posted in the channel, where everyone in it can see them. diff --git a/content/platform/guides/lavaflow.md b/content/platform/guides/lavaflow.md index bc72f44..2018a69 100644 --- a/content/platform/guides/lavaflow.md +++ b/content/platform/guides/lavaflow.md @@ -73,8 +73,10 @@ This project links `acme/storefront`. A project with no linked repository reports `repository_required` in `fix_blocker`; see [Link a repository](#link-a-repository). -At the default autonomy, `open_pr`, LavaFlow opens a draft pull request with -each fix. Send `"autonomy": "diagnose_only"` to stop at the diagnosis. +At the default autonomy, `open_pr`, LavaFlow opens a pull request with each +fix and leaves the merge to you; see +[Review and merge fixes yourself](#review-and-merge-fixes-yourself). Send +`"autonomy": "diagnose_only"` to stop at the diagnosis. LavaFlow works on the repository the project points at when you turn it on, or, turned on with none, on the first one the project points at afterwards. @@ -311,7 +313,8 @@ tests that changes no test and gives one of these reasons: it holds the fix for you with `no_test` (see [Waiting and held](#waiting-and-held)), and may start its CI once as it holds it. A fix of code nothing in your repository tests, as in a repository with no tests, merges as before, whatever reason it -gives. With `open_pr`, every fix opens as a draft, as before. +gives. LavaFlow holds no fix you merge yourself, such as any under `open_pr`, +for `no_test`, since it never merges one. Code nothing in your repository tests needs no test, and LavaFlow doesn't add one. The pull request's description says which case applies under **Tests**: @@ -670,27 +673,135 @@ starts a new run when it's seen again a few minutes after the deploy; see ## Read a fix's pull request On a private repository, the pull request's description holds the diagnosis, -the suggested fix and the review. On any other repository, the description -leaves the diagnosis out: read it in the Volcano dashboard, with -`volcano cloud lavaflow show `, or from +what the fix decides for you to confirm, and the review. The pull request's +changes are the fix, so the description doesn't repeat a suggested fix. On any +other repository, the description leaves the diagnosis out: read it in the +Volcano dashboard, with `volcano cloud lavaflow show `, or from [`GET /lavaflow/runs/{run_id}`](#follow-runs). +A fix restores the behavior your code, tests and docs intend, and adds no +capability they don't: for input your code was never meant to handle, such as +a new date format, it rejects that input rather than start accepting +it. Where the fix must decide behavior your code leaves open, such as a +response shape, a date, money or validation policy, which records to keep or +drop, or wording your users read, it picks the option that changes least for +existing callers and stored data, and lists each decision under +**Choices to confirm**. A fix that only stops the error has no such section. +When bad data comes from code the fix doesn't change, such as a function that +writes records in the wrong shape, **Not fixed here** names that code and why +the fix leaves it: + +```markdown +**Not fixed here.** The cart writer still stores carts without a total; this fix only guards the reader. + +## Choices to confirm + +This fix decides behavior beyond stopping the error. A person who merges it confirms each choice first; LavaFlow merges it itself only when its reviewers cleared every choice: + +- A cart with no total now reads as an empty cart instead of failing the request. +``` + +LavaFlow's reviewers send back a fix that decides behavior without listing it, +or that adds a capability a narrower change wouldn't need. A listed choice +covers only the behavior it describes: a reviewer still asks you about any +other change in behavior that nothing justifies. A later round's `minor` +problem, such as a decision the revision still doesn't list, doesn't send +the fix back again, so the review can pass and the pull request opens. With +`autonomy: merge`, LavaFlow then holds the fix for you with `review_notes` +rather than merging it. + +Each of LavaFlow's reviewers marks every listed choice as needing a person or +not. A choice needs a person when it isn't the option that changes least, or +when it changes a status, a response shape, input your code accepts, or +another contract callers or users rely on, such as a new error that rejects a +whole request your code used to process. A choice that only says how the fix +stops the error, such as treating a missing optional value as absent where +your code crashed reading it, doesn't. A choice a reviewer doesn't mark needs a +person. + +With `autonomy: merge`, LavaFlow doesn't merge a fix that lists a choice its +reviewers didn't all mark as needing no person, including when a reviewer +couldn't finish: it holds the fix for you with `choices_to_confirm` (see [Waiting and held](#waiting-and-held)), and +may start its CI once as it holds it. Confirm each choice, then merge the fix. +A fix whose reviewers all marked every choice as needing no person, or that +lists none, merges as before, and its description still lists its choices. A +fix you merge yourself, held with `person_merges` as under `open_pr`, isn't +also held for its choices: confirm them as you review it. + +A public or internal repository's description shows nothing LavaFlow's models +wrote, so it lists no choice: it says the fix has choices to confirm and to +read them with `volcano cloud lavaflow show --json`. The run's +`choices` and `not_fixed` (see [Read a review's findings](#read-a-reviews-findings)) +serve them on every repository, masked as review questions and observations are, and +the hold's question says where to read them. + If the review didn't pass, a warning leads the description. On a private repository, it counts the open findings by severity and points to **Review** below. On a public or internal repository, it gives the command to read the review instead. The warning gives the CI steps once; the footer doesn't repeat -them. The review table counts blocking findings from both reviewers and -LavaFlow's own test check. **For a person to decide** labels each question with +them. **Review** says in one sentence how the review went, such as +"LavaFlow's 2 reviewers checked this fix. The last round had no blocking +finding." When LavaFlow's own checks found problems in a fix that didn't +pass, the sentence says what they found, such as a missing test. The description doesn't print the model's +confidence label: a low-confidence diagnosis opens no pull request, and a +medium-confidence one adds a caution to check the root cause before you +merge. **For a person to decide** labels each question with what to check, such as its effect on payments or access. If a saved question -ends mid-sentence, LavaFlow shows only complete sentences and asks you to review -the change in **Files changed**. +ends mid-sentence, LavaFlow shows only complete sentences, never cutting +inside inline code, and asks you to review the change in **Files changed**. + +A reviewer asks a person to decide only about what merging this fix does, +compared with your code's behavior before it, and cites the line of the change +that raises the question. With `autonomy: merge`, every question holds the +fix. **Reviewer observations** lists what they noticed that doesn't hold the fix, +such as bad data stored before the fix or a related problem elsewhere. A +public or internal repository's description shows no observations: it counts them +and says to read them with `volcano cloud lavaflow show --json`. The diagnosis can quote your logs, so LavaFlow checks each field before -publishing it. When masking would replace a value, the description leaves -the whole field out and points to the pull request changes and run details. -If either an evidence item's location or its detail needs masking, the -whole item is left out. Other readable fields, the review verdict and test -status stay present. Run details may also withhold credentials. +publishing it, and the fix's choices, its **Not fixed here** line and +reviewer observations too. A value it masks shows in place as a mark, such +as `` for a quoted value, `` for a number or `