Repository navigation
feat: support operations on push deployments without an Operator - #821
Conversation
- Reserve the `operations-worker` command target alongside `operator`: only an operations capability may address it, and single-target shorthand never selects it. - Let a deployment store supply the stacks to deploy (`supplied_stacks`). The deployment loop uses them instead of re-reading the release, so a control plane can add deployment-specific resources. - CLI: read `approvalChannels` from access-request coordinates and only wait for kubectl approval when that channel applies. - Platform client SDK: approval channels and the access-request queue authorization.
|
This comment has been minimized.
This comment has been minimized.
…rt-push-mode-model-for-operations # Conflicts: # client-sdks/platform/openapi.json # client-sdks/platform/rust/openapi-3.0.json # client-sdks/platform/rust/openapi.json # crates/alien-cli/src/commands/access_requests.rs # crates/alien-manager/src/loops/deployment.rs
- Cap the Cloud Run worker's push subscription acknowledgement deadline at Pub/Sub's 10 to 600 second range, as the Terraform emitter already does. A worker timeout above 600s made the subscription fail to create. - Enable the Pub/Sub API for stacks with a commands-enabled worker, not only for stacks with a queue.
|
@greptile-apps review |
- Revert enabling the Pub/Sub API for commands-enabled GCP workers. It adds a setup-owned resource, so every installed GCP deployment with such a worker would need a setup rerun on its next update. Commands- enabled workers already relied on the API being on, as it is by default. - Document that a same-release supplied-stack change must arrive as UpdatePending. - Move the misplaced coordinates doc comment to its function and rename it `fetch_approval_instructions`.
|
@greptile-apps review |
…rt-push-mode-model-for-operations # Conflicts: # client-sdks/platform/openapi.json # client-sdks/platform/rust/openapi-3.0.json # client-sdks/platform/rust/openapi.json # crates/alien-manager/src/traits/mod.rs
Adds Stack.operations_enabled (operationsEnabled in JSON, omitted when false) and the enableOperations() builder method in Rust and TypeScript. Deployments without an Operator get an operations worker and its permission profile only when the stack sets it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replaces enableOperations() with operations({...}): built-in plugins by
name with settings and approval rules, and published custom plugins
pinned by name@version. Plugin manifests declare the settings they
accept. An Operator installed without a release reads the same JSON
from OPERATOR_OPERATIONS (Helm value remoteOperator.operations), resolves
{ env: NAME } settings locally, and reports the declaration without
values in sync. Bundle targets carry each plugin's settings env, kept in
memory only. The Manager forwards the reported declaration.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rt-push-mode-model-for-operations # Conflicts: # client-sdks/platform/openapi.json # client-sdks/platform/rust/openapi-3.0.json # client-sdks/platform/rust/openapi.json # crates/alien-core/src/lib.rs # packages/core/src/generated/schemas/stack.json
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Removing the last vault-backed worker drops the secrets vault, and setup revokes the management role's write access with it. The secret sync then tried to delete the values it wrote earlier and was denied. Forget them instead of deleting them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The update keeps setup-owned frozen resources in its target, so the secrets vault stays in the stack after its last worker is removed. Check the management role's vault grant instead of the vault's presence. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An update that only removes grants runs with the installed identities and leaves trimming them to the next setup. The removed grants are what the update needs to delete the resources and secrets they covered; requiring setup first revoked them, so those deletes were denied. - compatibility checks accept profiles, management permissions and frozen service accounts that only lost grants (dropping a role guard still widens access and still needs setup) - the update keeps a narrowed frozen service account's installed definition - a denied secret delete leaves the value in place instead of failing - a delete denied during an update fails; only teardown counts an unreachable resource as deleted Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rt-push-mode-model-for-operations # Conflicts: # crates/alien-preflights/src/compatibility/frozen_resources_unchanged.rs
The setup re-import check refuses settings that change the management permissions setup installed. It now compares exactly; only update preflights allow narrowing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…churn - the settings env on a bundle is stored in the Operator's encrypted state; say so instead of claiming it is never persisted - approval rules match an operation name or *, as implemented - the stack field describes the declaration, not a consumer of it - test that only teardown counts an unreachable resource as deleted - revert formatting-only hunks in unrelated preflight files Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Takes main's executor delete rule (access denied ends a delete except during a replace) and drops this branch's teardown-only variant: with permission narrowing deferred to the next setup, an update still holds the grants it needs to delete what a release removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@greptile-apps review |
2 similar comments
|
@greptile-apps review |
|
@greptile-apps review |
- a service account losing its last resource grant narrows when its profile holds no resource grants either; the uncaptured legacy format still needs setup - plugin manifests may not declare a setting named approval, which operations() uses for approval rules - only 403 or access denied lets a removed secret go; a 401 can be a transient credential failure and still fails the sync - CLI approval text no longer says approval always happens on the customer's side Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@greptile-apps review |
…rt-push-mode-model-for-operations
…rt-push-mode-model-for-operations # Conflicts: # client-sdks/platform/openapi.json # client-sdks/platform/rust/openapi-3.0.json # client-sdks/platform/rust/openapi.json # crates/alien-manager/src/registry_access.rs # crates/alien-manager/src/traits/deployment_store.rs
Stack operations and the operations sync types appear in many schemas, so the filtered client grew to about 240,000 lines, just past the cap. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lilienblum
left a comment
There was a problem hiding this comment.
One blocker remains: removing an Operator's final locally declared plugin does not report an empty declaration, so the control plane cannot clear its previously reported plugins and approval rules. See the inline finding.
Verdict: request changes.
Coverage: reviewed head a31dd7b against main at 78fa58c, merge base 093d0b5. Inspected the full 105-file change, operations types/builders, sync reporting, reserved command targets and capabilities, supplied-stack selection, permission narrowing, setup re-import strictness, secret cleanup and Helm generation. Ran cargo test -p alien-operations-sdk --lib (75 passed) and cargo test -p alien-preflights --lib compatibility (42 passed). CI still has a worker integration failure and a cancelled Rust job; the failed worker test reports a port-bind error, and I have not attributed it to this change. No live cloud deployment or full manager/deployment test suite was run. The documented API-before-CLI release order still applies.
Removing the last plugin from OPERATOR_OPERATIONS left operationsConfig out of sync, so the platform kept the previous declaration. A current Operator now always reports one, empty when it declares nothing; only an older Operator omits the field. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@greptile-apps review Note for this review: the remaining blocker (a denied AWS read during deletion marking a still-existing resource gone) is in the delete-probe flow added on main by #935 (6f44ca0), which reached this branch through a merge. This PR does not change that flow; its only |
|
@greptile-apps review The remaining blocker (a denied AWS read during deletion clearing a resource that may still exist) is in the delete-probe flow added on main by #935 and reached this branch through a merge; this PR does not change that code. It is tracked separately in #949 to be fixed against main. |
…rt-push-mode-model-for-operations # Conflicts: # client-sdks/platform/openapi.json # client-sdks/platform/rust/openapi-3.0.json # client-sdks/platform/rust/openapi.json
|
@greptile-apps review |
…rt-push-mode-model-for-operations # Conflicts: # crates/alien-manager/src/traits/mod.rs
|
@greptile-apps review |
…ut the plugins key (ALIEN-1358) (#968) ## What changes Since #821, `OPERATOR_OPERATIONS` (the `remoteOperator.operations` Helm value) uses the `OperationsConfig` shape: ```json {"plugins": {"kubernetes": {"approval": {"get-pods": "auto"}}}} ``` Before #821, the value was the plugin map itself: ```json {"kubernetes": {"approval": {"get-pods": "auto"}}} ``` Values written in the earlier shape still deserialize, but serde ignores the unknown top-level key. The Operator then starts with an empty declaration and runs no operations. Nothing reports the problem: the Operator logs no error, and it never requests an operations bundle. An installation upgraded to an Operator built after #821 silently loses every operation. `parse_operator_operations` now reads a non-empty JSON object that has neither a `plugins` nor a `custom` key as the plugin map, and logs a warning naming the shape. Objects in the current shape, and `{}`, parse exactly as before. Setting validation is unchanged. The format probe only chooses whether to add the `plugins` wrapper. Typed deserialization uses the original JSON text, so duplicate known fields remain errors in both formats. ## What the next maintainer inherits `with_plugins_key` in `alien-operator/src/cli.rs` is the only place the earlier shape is accepted. It can go once no installation sets `remoteOperator.operations` without `plugins`. ## Verification - New test `operator_operations_read_a_plugin_map_without_the_plugins_key`. It fails on main, where the earlier shape yields no config, and passes with this change. It also checks that both shapes parse to the same config. - Original-head validation: `cargo test -p alien-operator --lib operator_operations`: 2 passed. - `operator_operations_reject_duplicate_fields` rejects duplicate `plugins`, `custom`, `approval`, `settings`, custom plugin name, and custom plugin version fields. It fails on the original PR head and passes with the fix. - An isolated harness compiled the exact production parser, configuration types, error types, and parser tests with lockfile dependency versions: 4 tests passed, including all eight duplicate-field cases. Formatting and diff checks passed.

Summary
Operations are declared in
alien.ts, and push deployments can run them without an Operator.Declaring operations
Stack.operations(OperationsConfig) and the TypeScript.operations({...})builder. Built-in plugins are keyed by name with their settings andapprovalrules (an operation name or*; no rule means approval is needed). Published custom plugins go underpluginsasname@versionor an object. Changing operations takes a new release.settings: a plugin declares the settings it accepts (string,secret, orresources, with the env variable it reads).approvalis reserved for approval rules and cannot be a setting key.OperationsBundleDownloadcarries the plugin's settings asenv(redacted inDebug).SyncRequest.operationsConfigreports an Operator's own declaration without setting values.OPERATOR_OPERATIONS(values are literals or{ "env": "NAME" }). The Helm chart sets it fromremoteOperator.operations, andremoteOperator.operationsEnvadds env entries (for examplesecretKeyRef) for those values.alien operations list --deployment <id>lists a deployment's operations.byoc-databasedeclarescloudwatchandaws-vpc;custom-operationsdeclares its settings.Push deployments without an Operator
operations-workeris reserved next tooperator. Only an operations capability may address it, single-target shorthand never selects it, and its results follow the same rules asoperator.DeploymentRecord.supplied_stackslets a deployment store that receives stacks from its control plane deploy those instead of re-reading the release by id. A same-release change must arrive asUpdatePending. Records without supplied stacks behave as before.approvalChannelsfrom the coordinates and only waits for kubectl approval when that channel applies.Removing permissions no longer requires setup
Platform client SDK
The spec copies are regenerated: stack
operations,operationsConfigon sync,approvalChannelson access requests, and removal of the per-project operations enablement and policy endpoints.Release condition
approvalChannelsis required on the coordinates response, andoperations list --deploymentuses a new API route. Do not cut a CLI release from this until the API that serves both is deployed.Follow-up
operations-workeris reserved as a command target but not rejected as a stack resource id here; the control plane rejects the name at release creation.Test plan
cargo test -p alien-preflights --lib compatibility(narrowing, guards, legacy capture, re-import strictness)cargo test -p alien-manager --test stack_importcargo test -p alien-deployment --lib(secret sync tolerance)cargo test -p alien-operations-sdk --lib(settings, reservedapproval)cargo test -p alien-manager --lib loops::deployment(supplied-stack selection)OPERATOR_OPERATIONSwith realhelm