chore: bump to v0.9.19-rc.1 and add local OpenAPI build support
- Add release candidate (rc) support to release.sh with latestRC tagging - Bump VERSION, backend pyproject.toml, and frontend package.json to 0.9.19-rc.1 - Add local frontend/openapi.json so build no longer needs running backend - Update generate:types and validate-types.sh to use local openapi.json - Fix frontend tests: remove unused imports/variables and update mock data
This commit is contained in:
10343
frontend/openapi.json
Normal file
10343
frontend/openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bangui-frontend",
|
||||
"private": true,
|
||||
"version": "0.9.19",
|
||||
"version": "0.9.19-rc.1",
|
||||
"description": "BanGUI frontend — fail2ban web management interface",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"generate:types": "openapi-typescript http://localhost:8000/api/openapi.json -o src/types/generated.ts",
|
||||
"generate:types": "openapi-typescript ./openapi.json -o src/types/generated.ts",
|
||||
"validate:types": "bash scripts/validate-types.sh",
|
||||
"build": "npm run generate:types && tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
|
||||
@@ -17,17 +17,23 @@ GENERATED_FILE="${TYPES_DIR}/generated.ts"
|
||||
TEMP_FILE=$(mktemp)
|
||||
trap "rm -f $TEMP_FILE" EXIT
|
||||
|
||||
# Check if backend is accessible
|
||||
# Determine OpenAPI source: local file or backend URL
|
||||
BACKEND_URL="${BANGUI_BACKEND_URL:-http://localhost:8000}"
|
||||
if ! curl -sf "${BACKEND_URL}/api/openapi.json" > /dev/null 2>&1; then
|
||||
echo "❌ Backend not accessible at ${BACKEND_URL}/api/openapi.json" >&2
|
||||
OPENAPI_SOURCE=""
|
||||
|
||||
if [[ -f "${FRONTEND_DIR}/openapi.json" ]]; then
|
||||
OPENAPI_SOURCE="${FRONTEND_DIR}/openapi.json"
|
||||
echo "📋 Validating OpenAPI schema types (local openapi.json)..."
|
||||
elif curl -sf "${BACKEND_URL}/api/openapi.json" > /dev/null 2>&1; then
|
||||
OPENAPI_SOURCE="${BACKEND_URL}/api/openapi.json"
|
||||
echo "📋 Validating OpenAPI schema types (backend ${BACKEND_URL})..."
|
||||
else
|
||||
echo "❌ Backend not accessible at ${BACKEND_URL}/api/openapi.json and no local openapi.json found" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "📋 Validating OpenAPI schema types..."
|
||||
|
||||
# Generate types to a temporary file
|
||||
if ! npx openapi-typescript "${BACKEND_URL}/api/openapi.json" -o "$TEMP_FILE" 2>&1; then
|
||||
if ! npx openapi-typescript "${OPENAPI_SOURCE}" -o "$TEMP_FILE" 2>&1; then
|
||||
echo "❌ Failed to generate types from OpenAPI schema" >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { ErrorBoundary } from "../ErrorBoundary";
|
||||
import * as telemetry from "../../utils/telemetry";
|
||||
|
||||
// Mock telemetry to verify it's called
|
||||
vi.mock("../../utils/telemetry");
|
||||
|
||||
@@ -468,13 +468,10 @@ describe("useFetchData", () => {
|
||||
});
|
||||
|
||||
it("last subscriber abort cancels underlying request", async () => {
|
||||
let resolveFirst: ((value: { value: string }) => void) | null = null;
|
||||
const abortSignals: AbortSignal[] = [];
|
||||
const fetcher = vi.fn().mockImplementation((signal: AbortSignal) => {
|
||||
abortSignals.push(signal);
|
||||
return new Promise((resolve) => {
|
||||
resolveFirst = resolve;
|
||||
});
|
||||
return new Promise(() => {});
|
||||
});
|
||||
const selector = vi.fn((response: { value: string }) => response.value);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ describe("useJailBannedIps", () => {
|
||||
const fetchMock = vi.mocked(api.fetchJailBannedIps);
|
||||
const unbanMock = vi.mocked(api.unbanIp);
|
||||
|
||||
fetchMock.mockResolvedValue({ items: [{ ip: "1.2.3.4", jail: "sshd", banned_at: "2025-01-01T10:00:00+00:00", expires_at: "2025-01-01T10:10:00+00:00", ban_count: 1, country: "US" }], total: 1, page: 1, page_size: 25 });
|
||||
fetchMock.mockResolvedValue({ items: [{ ip: "1.2.3.4", jail: "sshd", banned_at: "2025-01-01T10:00:00+00:00", expires_at: "2025-01-01T10:10:00+00:00", ban_count: 1, country: "US" }], total: 1, page: 1, page_size: 25, total_pages: 1, pagination_mode: "offset" });
|
||||
unbanMock.mockResolvedValue({ message: "ok", jail: "sshd", success: true });
|
||||
|
||||
const { result } = renderHook(() => useJailBannedIps("sshd"));
|
||||
|
||||
@@ -34,8 +34,6 @@ describe("usePolledData", () => {
|
||||
vi.runAllTimersAsync();
|
||||
});
|
||||
|
||||
const callCountAfterInitial = fetcher.mock.calls.length;
|
||||
|
||||
// Reset timer and advance to ensure no more polls
|
||||
vi.clearAllTimers();
|
||||
fetcher.mockClear();
|
||||
@@ -66,8 +64,6 @@ describe("usePolledData", () => {
|
||||
vi.advanceTimersByTime(100);
|
||||
});
|
||||
|
||||
const initialCalls = fetcher.mock.calls.length;
|
||||
|
||||
// Clear for clean test
|
||||
fetcher.mockClear();
|
||||
|
||||
@@ -135,7 +131,6 @@ describe("usePolledData", () => {
|
||||
vi.advanceTimersByTime(100);
|
||||
});
|
||||
|
||||
const initialCalls = fetcher.mock.calls.length;
|
||||
fetcher.mockClear();
|
||||
|
||||
// Call refresh
|
||||
|
||||
@@ -177,11 +177,6 @@ export interface paths {
|
||||
* On success the token is also set as an ``HttpOnly`` ``SameSite=Lax``
|
||||
* cookie so the browser SPA benefits from automatic credential handling.
|
||||
*
|
||||
* Rate limiting: Exponential backoff on failed attempts. Each wrong password
|
||||
* incurs an increasing delay (0.5s, 1s, 2s, 4s, 5s max per IP address).
|
||||
* Requests during the penalty period return ``429 Too Many Requests`` with
|
||||
* a ``Retry-After`` header.
|
||||
*
|
||||
* Cache invalidation: On successful login, any existing cached sessions for
|
||||
* the same user are invalidated so that stale tokens (e.g., from a stolen
|
||||
* device) cannot be reused beyond the cache TTL window.
|
||||
@@ -192,7 +187,6 @@ export interface paths {
|
||||
* request: The incoming HTTP request (used to extract client IP).
|
||||
* session_ctx: Session service context containing db and repository.
|
||||
* settings: Application settings (used for session duration and trusted proxies).
|
||||
* rate_limiter: The login rate limiter (per IP).
|
||||
* session_cache: Session cache for invalidating old sessions on login.
|
||||
*
|
||||
* Returns:
|
||||
@@ -200,7 +194,6 @@ export interface paths {
|
||||
*
|
||||
* Raises:
|
||||
* AuthenticationError: if the password is incorrect.
|
||||
* RateLimitError: if the rate limit is exceeded.
|
||||
*/
|
||||
post: operations["login_api_v1_auth_login_post"];
|
||||
delete?: never;
|
||||
@@ -6274,13 +6267,6 @@ export interface operations {
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Too many login attempts, retry after delay */
|
||||
429: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Setup not complete */
|
||||
503: {
|
||||
headers: {
|
||||
|
||||
Reference in New Issue
Block a user