fix: drain Identity error body (keep-alive); reject whitespace-only credential fields in form
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -118,6 +118,9 @@ func (c *Client) authenticate(ctx context.Context, cr Creds) (string, time.Time,
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
|
||||||
|
// Drain the body so the underlying connection can be reused by the
|
||||||
|
// transport's keep-alive pool; the error itself stays generic.
|
||||||
|
io.Copy(io.Discard, resp.Body)
|
||||||
return "", time.Time{}, fmt.Errorf("selectel: identity auth failed: %d", resp.StatusCode)
|
return "", time.Time{}, fmt.Errorf("selectel: identity auth failed: %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
tok := resp.Header.Get("X-Subject-Token")
|
tok := resp.Header.Get("X-Subject-Token")
|
||||||
|
|||||||
@@ -60,6 +60,26 @@ test("сабмит с пустыми полями показывает zod-ош
|
|||||||
expect(createSpy).not.toHaveBeenCalled()
|
expect(createSpy).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("сабмит с пробельным вводом в обязательных полях показывает zod-ошибки и не вызывает createAccount", async () => {
|
||||||
|
const createSpy = vi.spyOn(api, "createAccount")
|
||||||
|
const user = userEvent.setup()
|
||||||
|
renderPage()
|
||||||
|
|
||||||
|
await screen.findByText("Main")
|
||||||
|
|
||||||
|
await user.type(screen.getByLabelText(/имя сервисного пользователя/i), " ")
|
||||||
|
await user.type(screen.getByLabelText(/пароль/i), "some-password")
|
||||||
|
await user.type(screen.getByLabelText(/номер аккаунта/i), " ")
|
||||||
|
await user.type(screen.getByLabelText(/имя проекта/i), " ")
|
||||||
|
|
||||||
|
await user.click(screen.getByRole("button", { name: /добавить учётку/i }))
|
||||||
|
|
||||||
|
expect(await screen.findByText("Укажите имя сервисного пользователя")).toBeInTheDocument()
|
||||||
|
expect(screen.getByText("Укажите номер аккаунта")).toBeInTheDocument()
|
||||||
|
expect(screen.getByText("Укажите имя проекта")).toBeInTheDocument()
|
||||||
|
expect(createSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
test("заполнение 4 полей и сабмит вызывает createAccount с secret в snake_case и не показывает пароль после", async () => {
|
test("заполнение 4 полей и сабмит вызывает createAccount с secret в snake_case и не показывает пароль после", async () => {
|
||||||
const createSpy = vi.spyOn(api, "createAccount").mockResolvedValue({
|
const createSpy = vi.spyOn(api, "createAccount").mockResolvedValue({
|
||||||
id: "acc3",
|
id: "acc3",
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ import { useAccounts, useCreateAccount, useDeleteAccount } from "@/hooks/useApi"
|
|||||||
|
|
||||||
const createAccountSchema = z.object({
|
const createAccountSchema = z.object({
|
||||||
provider: z.literal("selectel"),
|
provider: z.literal("selectel"),
|
||||||
username: z.string().min(1, "Укажите имя сервисного пользователя"),
|
username: z.string().trim().min(1, "Укажите имя сервисного пользователя"),
|
||||||
password: z.string().min(1, "Укажите пароль"),
|
password: z.string().min(1, "Укажите пароль"),
|
||||||
accountId: z.string().min(1, "Укажите номер аккаунта"),
|
accountId: z.string().trim().min(1, "Укажите номер аккаунта"),
|
||||||
projectName: z.string().min(1, "Укажите имя проекта"),
|
projectName: z.string().trim().min(1, "Укажите имя проекта"),
|
||||||
comment: z.string(),
|
comment: z.string(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user