Skip to content

Re-land spacetime lock/unlock to prevent accidental database deletion#4888

Merged
cloutiertyler merged 5 commits into
masterfrom
bot/reopen-database-lock
Jun 17, 2026
Merged

Re-land spacetime lock/unlock to prevent accidental database deletion#4888
cloutiertyler merged 5 commits into
masterfrom
bot/reopen-database-lock

Conversation

@clockwork-labs-bot

Copy link
Copy Markdown
Contributor

Re-lands #4502 on current master after the revert in #4881.

Summary

  • restore spacetime lock / spacetime unlock
  • block deleting locked databases
  • restore the database-lock smoketests

Validation

  • cargo fmt --all --check
  • cargo check -p spacetimedb-cli -p spacetimedb-client-api -p spacetimedb-standalone

…4502)

## Motivation

Feature request: "Is there any way we can lock a module to prevent it
from being deleted? A bit concerned about some fat finger risk of
accidentally deleting prod."

## Solution

Adds a database lock mechanism. A locked database cannot be deleted
until explicitly unlocked.

### New CLI Commands

```bash
# Lock a database to prevent deletion
spacetime lock my-database

# Attempt to delete a locked database (fails with 403)
spacetime delete my-database
# Error: Database is locked and cannot be deleted. Run \`spacetime unlock\` first.

# Unlock when you actually need to delete
spacetime unlock my-database
spacetime delete my-database
```

Both commands support `--server` and `--no-config` flags, and resolve
the database from `spacetime.json` when no argument is given (same as
`spacetime delete`).

### New HTTP API

- `POST /v1/database/:name_or_identity/lock` -- Lock a database
- `POST /v1/database/:name_or_identity/unlock` -- Unlock a database

Both require the same authorization as `DELETE` (owner only).

### Implementation

- Lock state stored in a separate `database_locks` sled tree in the
standalone control DB (avoids changing the `Database` struct and needing
a data migration)
- `ControlStateReadAccess::is_database_locked()` and
`ControlStateWriteAccess::set_database_lock()` added to the trait
- `delete_database` route checks lock state before proceeding; returns
`403 Forbidden` with a descriptive message if locked
- Locking is idempotent (locking an already-locked database is a no-op,
same for unlock)
- Lock only prevents deletion, not publishing updates

### What is NOT locked

- `spacetime publish` (updating module code) still works on locked
databases
- Only `spacetime delete` is blocked

This matches the intent: protect prod from accidental destruction while
allowing normal deployments.

---------

Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>

@cloutiertyler cloutiertyler left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This already landed and just needs to be relanded because we rolled back for unrelated reasons.

@cloutiertyler cloutiertyler enabled auto-merge June 16, 2026 14:26
@cloutiertyler cloutiertyler added this pull request to the merge queue Jun 17, 2026
Merged via the queue into master with commit f8ccbbe Jun 17, 2026
74 of 80 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants