diff --git a/.gitea/workflows/ci-deploy.yml b/.gitea/workflows/ci-deploy.yml index 9030f7f..b2e38ed 100644 --- a/.gitea/workflows/ci-deploy.yml +++ b/.gitea/workflows/ci-deploy.yml @@ -207,6 +207,10 @@ jobs: CI: 'false' GENERATE_SOURCEMAP: 'false' NODE_OPTIONS: --max-old-space-size=4096 + # NEXT_PUBLIC values are embedded during `next build`. The browser smoke + # suite serves this prebuilt export, so it must target its isolated API + # rather than the normal localhost development port. + NEXT_PUBLIC_API_BASE_URL: http://localhost:5302/api # Build once, then make Playwright serve this exact export. A SIGSEGV-only retry preserves # the runner workaround without hiding an ordinary compiler or type-check failure. run: | diff --git a/JobTrackerApi/Program.cs b/JobTrackerApi/Program.cs index 5e5e27e..bff14e7 100644 --- a/JobTrackerApi/Program.cs +++ b/JobTrackerApi/Program.cs @@ -419,6 +419,8 @@ builder.Services.AddAuthorization(options => builder.Services.AddScoped(); builder.Services.AddSingleton(); +var authLoginPermitLimit = builder.Configuration.GetValue("RateLimits:AuthLoginPermitLimit") ?? 10; + builder.Services.AddRateLimiter(options => { options.RejectionStatusCode = StatusCodes.Status429TooManyRequests; @@ -428,7 +430,7 @@ builder.Services.AddRateLimiter(options => partitionKey: $"login:{context.Connection.RemoteIpAddress?.ToString() ?? "unknown"}", factory: _ => new FixedWindowRateLimiterOptions { - PermitLimit = 10, + PermitLimit = authLoginPermitLimit, Window = TimeSpan.FromMinutes(5), QueueProcessingOrder = QueueProcessingOrder.OldestFirst, QueueLimit = 0, diff --git a/job-tracker-ui/e2e/smoke.spec.ts b/job-tracker-ui/e2e/smoke.spec.ts index 3db8f56..b2a5750 100644 --- a/job-tracker-ui/e2e/smoke.spec.ts +++ b/job-tracker-ui/e2e/smoke.spec.ts @@ -175,7 +175,7 @@ test("a saved job can be created through the reviewed UI flow", async ({ page }) await page.goto("/jobs"); await page.getByRole("button", { name: "Add Job" }).click(); await page.getByRole("button", { name: "Enter details manually" }).click(); - await page.getByLabel("Company").fill(`E2E Company ${suffix}`); + await page.getByRole("dialog").getByRole("combobox", { name: "Company" }).fill(`E2E Company ${suffix}`); await page.getByLabel("Job title").fill(title); await page.getByRole("button", { name: "Continue" }).click(); for (let step = 0; step < 3; step += 1) { diff --git a/job-tracker-ui/playwright.config.ts b/job-tracker-ui/playwright.config.ts index 9b3b3a6..6690e45 100644 --- a/job-tracker-ui/playwright.config.ts +++ b/job-tracker-ui/playwright.config.ts @@ -39,6 +39,7 @@ export default defineConfig({ Auth__AdminEmail: "e2e@example.test", Auth__AdminPassword: "E2ePassword123!", Auth__AllowRegistration: "false", + RateLimits__AuthLoginPermitLimit: "100", App__Version: "e2e-verification", App__CommitSha: "e2e1234", Cors__Origins__0: appUrl,