Back to Blog
API & Supply-Chain Security

Datasette's New Upload API Turns a Bearer Token Into a Production Database Swap

The datasette-upload-dbs 0.5a0 release formalises a POST API for hot-swapping a live SQLite database — a convenient CD primitive that is only as safe as the bearer token and permission scope guarding it.

PyramidLedger Research4 min read
Share

Key Takeaways

  • datasette-upload-dbs 0.5a0 adds a formal HTTP API that lets a bearer-token holder atomically replace a live Datasette database over a simple POST request.
  • Access is gated by a single Datasette permission, `upload-dbs` — whoever holds that permission (or a token scoped to it) can overwrite production data outright.
  • The plugin validates uploads to a temporary file before an atomic move, which protects against a corrupt file — but says nothing about who is allowed to submit one.
  • The realistic risk isn't the plugin's code, it's ordinary CI/CD hygiene: how `$API_TOKEN` is minted, stored, rotated, and scoped in the pipeline that calls it.

Datasette, Simon Willison's open-source tool for publishing and exploring SQLite databases, has long supported the idea of swapping in a fresh database file to update a hosted instance. The datasette-upload-dbs plugin turns that into a self-service upload feature, and its 0.5a0 release formalises it as a proper HTTP API: a POST with an Authorization: Bearer $API_TOKEN header and a multipart file upload replaces — or adds — a named database on a running instance.

A useful continuous-deployment primitive

The workflow this unlocks is a good one: build a fresh SQLite file in a CI job — a GitHub Actions run that scrapes, transforms, or aggregates data — then push it straight to the serving instance without a redeploy. Per the plugin's documentation, uploads are written to a temporary file, validated, and only then atomically moved into place, so a malformed or incomplete upload should never corrupt the database currently being served. That is a sound pattern, and it's the same atomic-swap discipline used in blue/green deploys and CDN cache-busting.

Where the actual risk sits

The plugin's own access control is intentionally minimal: a single Datasette permission, upload-dbs, decides who can call the endpoint. That's a reasonable design for a plugin — fine-grained authorization is the operator's job, not the library's — but it means the entire security boundary of "who can overwrite our production data" collapses onto how that permission is granted and, in the documented API flow, onto the bearer token used to authenticate the request.

That's a familiar risk shape, not a novel one. A bearer token that can replace a production dataset is functionally equivalent to a deploy key or a database credential, and it deserves the same handling: minted with the narrowest scope the CI job actually needs, stored in the CI platform's encrypted secrets store rather than a repo file or workflow log, rotated on a schedule, and never reused across environments. Teams that treat this kind of token as "just an API key for a read-only reporting tool" are the ones who get an unpleasant surprise when it turns out to also hold write access to the live dataset.

Practical checks for teams adopting it

  • Confirm which principals actually hold upload-dbs — audit it the same way you'd audit admin or write scopes elsewhere.
  • Mint the upload token as a dedicated CI secret scoped to one workflow, not a shared automation credential reused across jobs.
  • Log and alert on upload events — an atomic swap is silent by design, so detection has to be built in deliberately.
  • Treat the plugin like any other supply-chain dependency: pin the version, and review the diff before upgrading, since it sits directly in your data-serving path.

None of this is a flaw in datasette-upload-dbs — the plugin does what it says, and the validate-then-atomic-swap approach is a sensible way to avoid a half-written database. The point is broader: any tool that turns "call this endpoint" into "replace production data" is only as trustworthy as the token economy sitting in front of it, and that part is always the operator's responsibility, not the plugin's.

Frequently Asked Questions

What does datasette-upload-dbs actually let you do?

It adds an HTTP API to a hosted Datasette instance that accepts a POST request with a bearer token and a SQLite file, then atomically replaces (or adds) a named database that Datasette is serving.

Is the upload process itself unsafe?

The documented flow validates the uploaded file to a temporary location before atomically moving it into place, which is designed to prevent a bad upload from corrupting the live database — that part of the design looks sound.

What should teams actually worry about before enabling it?

Not the plugin's code, but who holds the `upload-dbs` permission and how the bearer token used to call the API is minted, stored, and scoped in CI/CD — that token is equivalent to write access over production data.

Sources

  1. 1datasette-upload-dbs 0.5a0Simon Willison
  2. 2simonw/datasette-upload-dbsGitHub
Share

Read next