feat(oabctl): programmatic delete API with explicit target contract#1415
feat(oabctl): programmatic delete API with explicit target contract#1415chaodu-agent wants to merge 21 commits into
Conversation
Designs the delete contract deferred by the lib-split review, symmetric
with apply_manifests:
- delete_services(&SdkConfig, &[DeleteTarget], &DeleteOptions)
-> Result<DeleteReport, DeleteError>
- DeleteOptions requires an explicit cluster and shares apply's bucket
resolution chain (explicit -> OAB_CONTROL_PLANE_BUCKET -> account) so
delete always cleans the bucket apply wrote to; never reads CLI config
- Contract guards before any AWS call: non-empty target set, non-empty
cluster, non-blank namespace/name (regression-tested without AWS)
- Typed DeleteError {Validation, Target, Teardown} preserving the report
of targets completed before a failure; teardown remains resumable
- Best-effort ingress skips surface in DeletedService.warnings; S3
cleanup failures still fail the target (safe to retry)
- delete.rs output now routes through the shared progress gate: CLI
behavior unchanged, programmatic calls are silent
- CLI paths (delete <name>, delete -f) unchanged
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
- needless_borrow in apply's registry-detach wait - allow too_many_arguments on validate_checkpoint / prepare_identity / ingress::delete_exact — these deliberately thread the full deployment identity (partition/account/region/cluster/bucket) as separate explicit parameters; bundling them would obscure the F1 ownership contract - box PreparedIdentity::Exact payload (large_enum_variant) No behavior change; 90 tests + doc-test pass, release build clean.
… refactor/oabctl-delete-api # Conflicts: # operator/src/apply.rs # operator/src/delete.rs
- apply: redundant_guards — match empty failures with a slice pattern - ingress: cloud_map_service_id_from_arn became test-only after the exact-identity merge (all production paths use the boundary-pinned parser); mark it #[cfg(test)] with a note instead of carrying dead code Verified with the CI toolchain (rustc 1.97.1): clippy -D warnings clean, 96 tests + doc-test pass.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
chaodu-agent
left a comment
There was a problem hiding this comment.
Important
CHANGES REQUESTED
Consolidated review: #1415 (comment)
GitHub event: COMMENT — self-review delivery only; this is not an approval.
|
Caution This PR has been waiting on the author for more than 2 days (labeled @chaodu-agent — You must add a new comment on this PR to remove the |
This comment has been minimized.
This comment has been minimized.
chaodu-agent
left a comment
There was a problem hiding this comment.
Important
CHANGES REQUESTED
Consolidated review: #1415 (comment)
Contract freeze: RC-1 at 1bd61e825e3f2e1308bde3be6294e10b0e3bead6; SHA-256 a2377a772fc9ba7f4856cea6af2cc6f6596dba919f12256295fd65516de3c674.
GitHub event: COMMENT — self-review delivery only; this is not an approval.
This comment has been minimized.
This comment has been minimized.
chaodu-agent
left a comment
There was a problem hiding this comment.
Important
CHANGES REQUESTED
Consolidated review: #1415 (comment)
GitHub event: COMMENT — self-review delivery only; this is not an approval.
Apply and delete previously validated logical identity independently: the hyphen-free namespace guard existed only in programmatic delete, so apply could still create 'prod-team/bot' while 'prod/team-bot' remained a valid delete target — both resolving to the physical name 'oab-prod-team-bot' (round-3 review finding F1). A new shared module, operator/src/identity.rs, now owns the rule: - Domain rule: validate_injective_identity (non-empty components, hyphen-free namespace) is enforced before any AWS call by manifest validation (CLI apply, fleet expansion, apply_manifests) and by delete_services. - Ownership rule: ensure_exclusive_physical_identity probes the exact control-plane keys (manifest, delete checkpoint, ingress-teardown checkpoint) of every colliding alias pair before mutation, in apply_ecs and in the shared delete choke point run_with_bucket (CLI + programmatic). Contested physical identities fail closed naming the colliding pair. - All physical name and control-plane key derivations (ECS/Cloud Map names, manifest/checkpoint keys, scale, ingress) route through the shared module so probe and mutation cannot drift. - Manifest schema namespace pattern tightened to ^[a-z0-9]+$. BREAKING CHANGE / legacy policy: manifests with hyphenated namespaces are rejected at apply with a migration message. Existing hyphenated-namespace deployments stay deletable via 'oabctl delete' (warning + ownership check); migrate by deleting and re-creating under a hyphen-free namespace. Tests: identity module unit tests plus cross-entry-point regressions in manifest, apply, and delete proving colliding logical pairs cannot overwrite, checkpoint, or delete one another. cargo clippy --all-targets -- -D warnings and cargo test (113 + 1 doctest) pass.
This comment has been minimized.
This comment has been minimized.
chaodu-agent
left a comment
There was a problem hiding this comment.
Note
LGTM ✅ — The exact requested head closes the prior identity-collision and teardown-safety findings; no new in-scope blockers were found.
Consolidated review: #1415 (comment)
GitHub event: COMMENT — self-review delivery only; this is not an approval.
|
Note LGTM ✅ — The round-3 blocker is closed: apply and every delete entry point now share one injective identity rule plus a pre-mutation control-plane ownership check, with an explicit legacy-namespace policy. What This PR DoesAdds a public in-process How It WorksEach target resolves to one live ECS service. Before mutation, delete stores a durable S3 checkpoint (caller boundary, bucket, canonical cluster/service ARNs, ECS New in this revision, a shared
Findings
Finding Details🟢 F1 (round-3) — Shared injective identity/ownership rule, verified per entry pointIndependent exact-SHA audit of
ℹ️ Residual notes (within RC-1's accepted risks, documented)
Baseline Check
VerifiedOn the exact reviewed head
Previous Review and External FeedbackRound-3 consolidated review
✅ Addressed in Prior real-AWS verification
✅ Still valid for the canonical path; this revision adds only pre-mutation validation/probing before that path, plus read-only S3 probes that fail closed. Automated stale-contributor noticeOperational only; superseded by current PR activity. No other external reviewer findings were present on the reviewed head. What's Good (🟢)
5️⃣ Three Reasons We Might Not Need This PR
|
chaodu-agent
left a comment
There was a problem hiding this comment.
Note
LGTM ✅ — Round-3 F1 (non-injective apply/delete identity) is closed on head be006ec by a shared identity module enforced at every apply and delete entry point, with an explicit legacy-namespace policy and cross-entry-point regressions.
Consolidated review: #1415 (comment)
|
CHANGES REQUESTED Important This is the final consolidated review for the exact head What This PR DoesAdds a public How It WorksThe library path requires explicit cluster and bucket resolution, validates targets before AWS mutation, derives a canonical physical identity, probes control-plane keys for collision aliases, persists a checkpoint before destructive work, and retries using exact ARN and service-incarnation data. Apply and delete share identity helpers and an ingress-teardown interlock, while the CLI retains its legacy human-readable path and legacy namespace behavior. Findings
Finding Details🟡 F1: Serialize by canonical physical identityThe alias probe must be paired with a conditional lease/fence keyed by the canonical physical identity and held through mutation, or the documented caller precondition must require serialization across every logical alias that maps to the same physical identity. A non-atomic S3 probe alone does not close the TOCTOU window. 🟡 F2: Reject duplicate batch targetsValidate the complete target set before orchestration and return a deterministic contract error for duplicate or conflicting entries. Add unit coverage for duplicate 🟡 F3: Add AWS mock integration coverageAdd a stub/mock S3 and ECS harness for multi-target teardown, interruption, checkpoint persistence, resume, and eventual-consistency outcomes. Pure-function tests do not establish that the complete orchestration path actually resumes safely. 🟡 F4: Bound Telegram webhook requestsBuild the webhook client with an explicit timeout (for example, 10 seconds) and return a contextual error if client construction fails, so teardown cannot wait forever on the external API. 🟡 F5: Document the public delete APIAdd a 🟡 F6: Refresh exact-head evidenceRe-run or link validation for Baseline Check
Addressing External and Prior Review FeedbackPrior review roundsEarlier rounds identified the need for the programmatic delete contract, exact-resource checkpoints, identity collision protection, and clear caller preconditions. The current head adds the shared identity module, schema restriction, checkpoint/incarnation validation, ingress interlock, and documentation. The alias-concurrency TOCTOU and exact-head validation-label issues remain open as described above. Repository/CI feedbackThe available CI evidence reports the operator, validation, polling/review, change, and check jobs successful. Local Rust execution was unavailable in some review environments because Validation
What's Good (🟢)
5. Three Reasons We Might Not Need This PR
|
|
Important CHANGES REQUESTED What This PR DoesThis PR adds a public, in-process delete API for explicitly identified OAB ECS services. It provides explicit cluster and bucket options, structured partial results, exact-identity checkpoints, fail-closed ownership checks, and a CLI compatibility path. How It WorksDelete validates the shared injective logical identity before AWS calls, records the exact ECS incarnation and dependent resource identifiers before mutation, and performs cleanup from those checkpointed identities. Programmatic deletion uses strict cleanup; the legacy CLI retains best-effort cleanup with warnings and checkpoint retention. Apply and delete document the required caller-side serialization boundary for the same physical identity. Findings
Finding Details🟡 F1: Operator validation remains blockedThe exact-head GitHub checks Requested change: repair the operator CI/compiler failure and rerun the required operator cargo validation before treating the review gate as green. 🟢 F2: Serialization contract documentedThe public apply API, delete API, crate-level Rustdoc, operator README, and 🟢 F3: Regression evidence presentThe current head includes tests for shared collision aliases across entry points, completed partial-report preservation when a later target fails, pending apply ingress-teardown blocking, and ECS phase transitions including DRAINING resume behavior. The exact cleanup path removes the apply-side ingress-teardown checkpoint after successful cleanup and retains retry state on failure. Inline Review Disposition
Baseline Check
Validation
5. Three Reasons We Might Not Need This PR
|
There was a problem hiding this comment.
Important
CHANGES REQUESTED
Consolidated review: #1415 (comment)
The exact-head checks changes, check, validate, and poll-and-review passed. Operator job 89065627641 failed at cargo check; repair and rerun that gate before treating this review as complete.
#1415 feat(oabctl): programmatic delete API with explicit target contract
State: open | Author: chaodu-agent | Branch: refactor/oabctl-delete-api
Summary
Designs and implements the programmatic delete contract that the #1404 review intentionally deferred ("until their programmatic contracts are designed independently"). This PR is stacked on
refactor/oabctl-lib.The API is symmetric with
apply_manifests:DeleteOptionsrequires an explicit cluster; the library path never reads~/.oabctl/config.toml.OAB_CONTROL_PLANE_BUCKET�¢����oab-control-plane-{account}.DeleteError { Validation | Target | Teardown }preserves theDeleteReportfor targets completed before a failure.Review Contract
Contract revision: RC-1
Goal
Provide a public, in-process Rust API that safely deletes one or more explicitly identified OAB ECS deployments without reading CLI home configuration. A successful result must mean that the checkpointed ECS incarnation and its exact ingress dependencies are gone and the target's control-plane manifest/artifacts are removed. Ambiguous ownership or incomplete teardown must fail closed with a structured, retryable error rather than report false success or delete another deployment.
Non-goals
apply_manifestsanddelete_servicescalls for the same logical target; callers must serialize same-target mutations as described under Accepted Residual Risks.apply_manifestsAPI, changing existing CLI UX, or introducing a general distributed workflow engine.Accepted Residual Risks
(AWS account, Region, control-plane bucket, cluster, namespace, name)tuple. The intended NEST control-plane caller uses a per-target single-flight/lock. If this precondition is violated, recovery is to stop concurrent writers, inspect the retained checkpoint, re-apply the intended desired state if apply should win, or retry delete if delete should win. A shared generation fence remains a follow-up.Acceptance Criteria
delete_services,DeleteTarget,DeleteOptions,DeletedService,DeleteReport,DeleteError, andDeleteErrorKindwithout changing the existing CLI command surface.(namespace, name)pairs must not resolve to the same ECS/API/Cloud Map identity.~/.oabctl/config.toml, and resolves the control-plane bucket using the same explicit option �¢���� environment �¢���� caller-account chain as apply.createdAtincarnation, and exact registry/API identifiers when ingress exists.DeleteReportcontains only fully completed targets.DeleteErroridentifies validation/target/teardown phase, preserves prior completed targets, identifies the failed target for teardown failures, and retains the checkpoint whenever retryable cleanup remains.cargo testandcargo clippy --all-targets -- -D warningspass for the operator crate on the reviewed head.Follow-ups
CLI
No intended behavior change:
oabctl deleteandoabctl delete -fretain config-file cluster resolution, printed progress, and aggregate failure reporting.Motivation
NEST's manager needs
/deletefor tenant deprovisioning. Webhook removal and Telegram-side disclosure remain in the control plane, while ECS, ingress, and S3 teardown reuse this API in-process, matching how the manager already consumesapply_manifests.Validation Evidence
18322e16f2b63e5484b800507fe23451bbac1751.Review Contractvalidation andoperatorCI passed before this follow-up; the current head is tracked below.1bd61e8..54bd8f2found all round-2 findings resolved with no new in-scope blocker.Follow-up validation
Follow-up head
18322e16f2b63e5484b800507fe23451bbac1751adds duplicate-target validation, a bounded Telegram webhook client timeout, alias-equivalent physical-identity serialization guidance, bounded ownership probes, CLI cleanup warnings, and S3 path redaction.B4 follow-up preserves CLI best-effort behavior after drain timeout, continues S3 cleanup after individual failures, and treats an absent exact apply service as detached; the strict API remains fail-closed.
B7-B2-B16 follow-up enforces the documented identity charset (with a legacy CLI namespace-hyphen exception), aborts ownership probes before admitting replacements after the first error, and treats ECS INACTIVE apply responses as absent.
B14 fixes resumable DRAINING ECS deletion by reissuing
delete_service(force=true)before polling, extends Cloud Map deletion to 12 attempts with capped 5/10/20/30-second backoff, and documents that manifest-first apply failures are recovered by re-running apply because no apply rollback checkpoint exists.Local
git diff --check, Rustfmt parser checks, and focused B14 static assertions passed. Localcargo checkwas attempted but is blocked by the environment (linker \cc` not found`); GitHub CI for this exact head is the authoritative Rust validation.This head also bounds identity ownership probes to 8 concurrent S3 requests and adds a 201-character/100-alias regression test; GitHub CI for this exact head completed with
changes,check,validate, andpoll-and-reviewsuccessful, butoperatorfailed atcargo check(job89065627641).