Skip to content

Commit fc8181a

Browse files
fix(db): validate database name length before create (#126)
* fix(db): validate database name length before create * validate inline values * tidy comments
1 parent 27a1929 commit fc8181a

4 files changed

Lines changed: 21 additions & 1 deletion

File tree

.changeset/shaky-horses-like.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bunny.net/cli": patch
3+
---
4+
5+
fix(db): validate database name length before create

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,7 @@ The manifest path mirrors `bunny scripts link` — both write to `.bunny/<resour
13091309

13101310
**Lifecycle integration:**
13111311

1312-
- `bunny db create`after creating the database, prompts "Link this directory to <name>?" and (on yes) writes the manifest. If a link already exists it shows what will be replaced. The follow-up flow (link → token → save-env) exposes three flags for non-interactive control: `--link`/`--no-link`, `--token`/`--no-token`, `--save-env`/`--no-save-env`. When a flag is provided the prompt is skipped; in `--output json` mode prompts are suppressed entirely so flags become the only way to opt in. The JSON output then includes `linked`, `token`, and `saved_to_env` fields reflecting what happened.
1312+
- `bunny db create`the name is validated client-side against `DB_NAME_MAX_LENGTH` (16) before any API call, since longer names make the backend 500 instead of returning a validation error. After creating the database, prompts "Link this directory to <name>?" and (on yes) writes the manifest. If a link already exists it shows what will be replaced. The follow-up flow (link → token → save-env) exposes three flags for non-interactive control: `--link`/`--no-link`, `--token`/`--no-token`, `--save-env`/`--no-save-env`. When a flag is provided the prompt is skipped; in `--output json` mode prompts are suppressed entirely so flags become the only way to opt in. The JSON output then includes `linked`, `token`, and `saved_to_env` fields reflecting what happened.
13131313
- `bunny db delete` — after deleting the database, if `.bunny/database.json` points at the deleted ID it is removed silently via `removeManifest()` (no prompt — a manifest pointing at a deleted DB is unambiguously stale).
13141314

13151315
### `bunny.jsonc` (app config)

packages/cli/src/commands/db/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export const DATABASE_MANIFEST = "database.json";
1313
/** Page size used when paginating the database list endpoint. */
1414
export const DB_PAGE_SIZE = 100;
1515

16+
/** Maximum length the backend accepts for a database name. */
17+
export const DB_NAME_MAX_LENGTH = 16;
18+
1619
/** Default lifetime for tokens minted by `db shell` / `db studio`. */
1720
export const TOKEN_TTL_MINUTES = 30;
1821

packages/cli/src/commands/db/create.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { fetchRegionConfig, generateToken } from "./api.ts";
1414
import {
1515
DATABASE_MANIFEST,
1616
type DatabaseManifest,
17+
DB_NAME_MAX_LENGTH,
1718
ENV_DATABASE_AUTH_TOKEN,
1819
ENV_DATABASE_URL,
1920
} from "./constants.ts";
@@ -33,6 +34,14 @@ async function getCdnServerToken(): Promise<string | null> {
3334
}
3435
}
3536

37+
/** Validate a database name; returns an error message, or null when valid. */
38+
function validateDbName(name: string): string | null {
39+
if (name.length > DB_NAME_MAX_LENGTH) {
40+
return `Database name must be ${DB_NAME_MAX_LENGTH} characters or fewer (got ${name.length}).`;
41+
}
42+
return null;
43+
}
44+
3645
const COMMAND = "create";
3746
const DESCRIPTION = "Create a new database.";
3847

@@ -138,10 +147,13 @@ export const dbCreateCommand = defineCommand<CreateArgs>({
138147
type: "text",
139148
name: "value",
140149
message: "Database name:",
150+
validate: (v: string) => validateDbName(v) ?? true,
141151
});
142152
name = value;
143153
}
144154
if (!name) throw new UserError("Database name is required.");
155+
const nameError = validateDbName(name);
156+
if (nameError) throw new UserError(nameError);
145157

146158
// Fetch available regions from config
147159
const configSpin = spinner("Fetching available regions...");

0 commit comments

Comments
 (0)