Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1339,18 +1339,8 @@ export async function runInitCommand(rawOptions: InitCommandOptions): Promise<vo
}
// Clean up existing directory
try {
await Bun.write(projectPath + "/.keep", "");
const files = await Bun.file(projectPath).ls();
await Promise.all(
files.map(async (f) => {
const fullPath = path.resolve(projectPath, f.name);
await Bun.write(fullPath, "");
}),
);
await Bun.file(projectPath)
.delete()
.catch(() => {});
await Bun.mkdir(projectPath, { recursive: true }).catch(() => {});
await rm(projectPath, { recursive: true, force: true });
await mkdir(projectPath, { recursive: true });
} catch (err) {
logger.error(`Failed to clean directory: ${err}`);
}
Expand Down
19 changes: 11 additions & 8 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,16 +568,19 @@ export function createProgram(): Command {
const { runApiKeyLogin } = await import("./commands/login");
let password = process.env.ADMIN_PASSWORD;
if (!password) {
const { default: prompts } = await import("prompts");
const result = await prompts({
type: "password",
name: "password",
message: "Admin password:",
validate: (p: string) => p.length >= 1,
});
const { default: inquirer } = await import("inquirer");
const result = await inquirer.prompt<{ password: string }>([
{
type: "password",
name: "password",
message: "Admin password:",
mask: "*",
validate: (value: string) => value.length >= 1 || "Password is required",
},
]);
password = result.password;
}
await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password });
await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password: password ?? "" });
Comment on lines 569 to +583

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Tighten the password type narrowing instead of ?? "".

password ?? "" is only there to satisfy TS narrowing (process.env.ADMIN_PASSWORD is string | undefined). With the inquirer validate enforcing length ≥ 1, an empty string is logically unreachable — but if the env-var branch ever sets ADMIN_PASSWORD="", the truthy check on Line 570 sends control into the prompt block, so that's also covered. The ?? "" therefore silently swallows any future bug where password legitimately becomes undefined and forwards "" to the server, which will fail z.string().min(1) with an opaque 400.

Prefer narrowing explicitly so a regression surfaces locally rather than as a server-side validation error:

Proposed narrowing
-			if (opts.email) {
-				const { runApiKeyLogin } = await import("./commands/login");
-				let password = process.env.ADMIN_PASSWORD;
-				if (!password) {
+			if (opts.email) {
+				const { runApiKeyLogin } = await import("./commands/login");
+				let password: string | undefined = process.env.ADMIN_PASSWORD;
+				if (!password) {
 					const { default: inquirer } = await import("inquirer");
 					const result = await inquirer.prompt<{ password: string }>([
 						{
 							type: "password",
 							name: "password",
 							message: "Admin password:",
 							mask: "*",
 							validate: (value: string) => value.length >= 1 || "Password is required",
 						},
 					]);
 					password = result.password;
 				}
-				await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password: password ?? "" });
+				if (!password) {
+					logger.error("Password is required");
+					process.exit(1);
+				}
+				await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password });
 			} else {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let password = process.env.ADMIN_PASSWORD;
if (!password) {
const { default: prompts } = await import("prompts");
const result = await prompts({
type: "password",
name: "password",
message: "Admin password:",
validate: (p: string) => p.length >= 1,
});
const { default: inquirer } = await import("inquirer");
const result = await inquirer.prompt<{ password: string }>([
{
type: "password",
name: "password",
message: "Admin password:",
mask: "*",
validate: (value: string) => value.length >= 1 || "Password is required",
},
]);
password = result.password;
}
await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password });
await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password: password ?? "" });
let password: string | undefined = process.env.ADMIN_PASSWORD;
if (!password) {
const { default: inquirer } = await import("inquirer");
const result = await inquirer.prompt<{ password: string }>([
{
type: "password",
name: "password",
message: "Admin password:",
mask: "*",
validate: (value: string) => value.length >= 1 || "Password is required",
},
]);
password = result.password;
}
if (!password) {
logger.error("Password is required");
process.exit(1);
}
await runApiKeyLogin({ serverUrl: opts.url, email: opts.email, password });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/index.ts` around lines 569 - 583, The code should not
silently coerce password to "" before calling runApiKeyLogin; instead, after the
inquirer prompt or env check ensure password is a non-empty string and surface a
local error if it's missing. Replace the `password ?? ""` usage by explicitly
validating the `password` variable (the value read from
process.env.ADMIN_PASSWORD or from the inquirer prompt) and if it is undefined
or an empty string throw or exit with a clear message like "Admin password is
required" so the issue is caught locally, then pass the validated password into
runApiKeyLogin (use the validated variable directly, e.g., password or password!
after the explicit check).

} else {
await runLoginCommand({ serverUrl: opts.url });
}
Expand Down
9 changes: 7 additions & 2 deletions packages/server/src/lib/audit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,14 @@ export async function writeAuditLog(entry: AuditEntry): Promise<void> {

// Helper: extract IP from Hono context
export function getClientIp(headers: Headers): string {
const fromProxy = headers.get("x-real-ip") ?? headers.get("x-forwarded-for")?.split(",")[0]?.trim();
if (fromProxy) return fromProxy;
const fromForwardedFor = headers.get("x-forwarded-for")?.split(",")[0]?.trim();
if (fromForwardedFor) return fromForwardedFor;

const fromRealIp = headers.get("x-real-ip")?.trim();
if (fromRealIp) return fromRealIp;

const ua = headers.get("user-agent") ?? "";
if (!ua) return "unknown";
const fp = createHash("sha256").update(ua).digest("hex").slice(0, 16);
return `ua:${fp}`;
}
Loading