mirror of
https://github.com/mgeeky/decode-spam-headers.git
synced 2026-02-22 05:23:31 +01:00
MAESTRO: fix linting and formatting
This commit is contained in:
@@ -20,7 +20,7 @@ This phase performs final integration, accessibility audit, responsive testing,
|
|||||||
- [x] T046 Wire all components together in `frontend/src/app/page.tsx` — integrate HeaderInput, FileDropZone, AnalysisControls, AnalyseButton, ProgressIndicator, ReportContainer, CaptchaChallenge into the single-view application with correct data flow. Ensure: input feeds to analysis hook, progress hook drives progress indicator, result feeds to report container, 429 errors trigger CAPTCHA modal, cache hook restores state on mount. Notes: added AnalysisControls + CAPTCHA retry flow, extended analysis hook for bypass token handling, confirmed cache restore.
|
- [x] T046 Wire all components together in `frontend/src/app/page.tsx` — integrate HeaderInput, FileDropZone, AnalysisControls, AnalyseButton, ProgressIndicator, ReportContainer, CaptchaChallenge into the single-view application with correct data flow. Ensure: input feeds to analysis hook, progress hook drives progress indicator, result feeds to report container, 429 errors trigger CAPTCHA modal, cache hook restores state on mount. Notes: added AnalysisControls + CAPTCHA retry flow, extended analysis hook for bypass token handling, confirmed cache restore.
|
||||||
- [x] T047 Verify WCAG 2.1 AA compliance across all components (NFR-03) — ARIA labels, keyboard nav order, focus indicators, colour contrast ratios (dark theme). Fix violations. Test with screen reader simulation. Ensure all interactive elements have visible focus states. Notes: added keyboard-accessible file picker with ARIA descriptions, focus-visible outlines on drop zone/summary/search fields, boosted low-contrast text from 40% to 60%, linked CAPTCHA dialog description, added file picker tests; ran `npx vitest run src/__tests__/FileDropZone.test.tsx`.
|
- [x] T047 Verify WCAG 2.1 AA compliance across all components (NFR-03) — ARIA labels, keyboard nav order, focus indicators, colour contrast ratios (dark theme). Fix violations. Test with screen reader simulation. Ensure all interactive elements have visible focus states. Notes: added keyboard-accessible file picker with ARIA descriptions, focus-visible outlines on drop zone/summary/search fields, boosted low-contrast text from 40% to 60%, linked CAPTCHA dialog description, added file picker tests; ran `npx vitest run src/__tests__/FileDropZone.test.tsx`.
|
||||||
- [x] T048 [P] Verify responsive layout 320px–2560px (NFR-04) at breakpoints: 320px, 768px, 1024px, 1440px, 2560px. No horizontal scroll, no overlapping elements, readable text. Fix any layout issues discovered. Notes: stacked control cards on small screens, added min-w-0 + flex-wrap on report UI, and break-words handling for long header values, hop chain hostnames/IPs, and search pills to prevent overflow.
|
- [x] T048 [P] Verify responsive layout 320px–2560px (NFR-04) at breakpoints: 320px, 768px, 1024px, 1440px, 2560px. No horizontal scroll, no overlapping elements, readable text. Fix any layout issues discovered. Notes: stacked control cards on small screens, added min-w-0 + flex-wrap on report UI, and break-words handling for long header values, hop chain hostnames/IPs, and search pills to prevent overflow.
|
||||||
- [ ] T049 [P] Run full linting pass — `ruff check backend/` and `ruff format backend/` zero errors; `npx eslint src/` and `npx prettier --check src/` zero errors; no `any` types in TypeScript. Fix all violations
|
- [x] T049 [P] Run full linting pass — `ruff check backend/` and `ruff format backend/` zero errors; `npx eslint src/` and `npx prettier --check src/` zero errors; no `any` types in TypeScript. Fix all violations. Notes: ruff formatted backend files, removed unsupported `aria-invalid` on file drop button, ran prettier on CAPTCHA + analysis tests.
|
||||||
- [ ] T050 [P] Run full test suites and verify coverage — `pytest backend/tests/ --cov` ≥80% new modules (NFR-06); `npx vitest run --coverage` ≥80% new components (NFR-07). Add missing tests if coverage is below threshold
|
- [ ] T050 [P] Run full test suites and verify coverage — `pytest backend/tests/ --cov` ≥80% new modules (NFR-06); `npx vitest run --coverage` ≥80% new components (NFR-07). Add missing tests if coverage is below threshold
|
||||||
- [ ] T051 [P] Verify initial page load <3s on simulated 4G (constitution P7). Use Lighthouse with Slow 4G preset. Target score ≥90. Fix blocking resources or missing lazy-loading if score is below target
|
- [ ] T051 [P] Verify initial page load <3s on simulated 4G (constitution P7). Use Lighthouse with Slow 4G preset. Target score ≥90. Fix blocking resources or missing lazy-loading if score is below target
|
||||||
- [ ] T052 [P] Benchmark analysis performance — full analysis of `backend/tests/fixtures/sample_headers.txt` completes within 10s (NFR-01). Profile slow scanners. Document results. Optimise if any scanner exceeds acceptable threshold
|
- [ ] T052 [P] Benchmark analysis performance — full analysis of `backend/tests/fixtures/sample_headers.txt` completes within 10s (NFR-01). Profile slow scanners. Document results. Optimise if any scanner exceeds acceptable threshold
|
||||||
|
|||||||
@@ -68,9 +68,7 @@ class Settings(BaseSettings):
|
|||||||
parsed = json.loads(text)
|
parsed = json.loads(text)
|
||||||
if isinstance(parsed, list):
|
if isinstance(parsed, list):
|
||||||
return [
|
return [
|
||||||
str(item).strip()
|
str(item).strip() for item in parsed if str(item).strip()
|
||||||
for item in parsed
|
|
||||||
if str(item).strip()
|
|
||||||
]
|
]
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -114,9 +114,7 @@ class Logger:
|
|||||||
colored = colorizingFunc(c, txt)
|
colored = colorizingFunc(c, txt)
|
||||||
|
|
||||||
if not colored:
|
if not colored:
|
||||||
raise ValueError(
|
raise ValueError(f"Could not strip colors from phrase: ({patt})!")
|
||||||
f"Could not strip colors from phrase: ({patt})!"
|
|
||||||
)
|
|
||||||
|
|
||||||
s = s.replace(patt, colored)
|
s = s.replace(patt, colored)
|
||||||
pos = 0
|
pos = 0
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
"""Scanner implementations grouped by vendor or function."""
|
"""Scanner implementations grouped by vendor or function."""
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ def _normalize_payload(payload: object) -> tuple[str, str, str, str] | None:
|
|||||||
|
|
||||||
|
|
||||||
def _combine_payloads(
|
def _combine_payloads(
|
||||||
payloads: list[tuple[str, str, str, str]]
|
payloads: list[tuple[str, str, str, str]],
|
||||||
) -> tuple[str, str, str, str]:
|
) -> tuple[str, str, str, str]:
|
||||||
headers: list[str] = []
|
headers: list[str] = []
|
||||||
values: list[str] = []
|
values: list[str] = []
|
||||||
|
|||||||
@@ -79,9 +79,7 @@ async def analyse(request: Request) -> StreamingResponse:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if len(headers) > MAX_HEADERS_LENGTH:
|
if len(headers) > MAX_HEADERS_LENGTH:
|
||||||
return JSONResponse(
|
return JSONResponse(status_code=413, content={"error": "Headers exceed 1 MB"})
|
||||||
status_code=413, content={"error": "Headers exceed 1 MB"}
|
|
||||||
)
|
|
||||||
|
|
||||||
headers = _sanitize_headers(headers)
|
headers = _sanitize_headers(headers)
|
||||||
if not headers.strip():
|
if not headers.strip():
|
||||||
@@ -120,9 +118,7 @@ async def analyse(request: Request) -> StreamingResponse:
|
|||||||
elapsed_ms = (perf_counter() - start) * 1000
|
elapsed_ms = (perf_counter() - start) * 1000
|
||||||
percentage = 0.0
|
percentage = 0.0
|
||||||
if total_tests > 0:
|
if total_tests > 0:
|
||||||
percentage = min(
|
percentage = min(100.0, (current_index + 1) / total_tests * 100.0)
|
||||||
100.0, (current_index + 1) / total_tests * 100.0
|
|
||||||
)
|
|
||||||
payload = AnalysisProgress(
|
payload = AnalysisProgress(
|
||||||
current_index=current_index,
|
current_index=current_index,
|
||||||
total_tests=total_tests,
|
total_tests=total_tests,
|
||||||
@@ -168,9 +164,7 @@ async def analyse(request: Request) -> StreamingResponse:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
await send_stream.send(
|
await send_stream.send(("result", final_result.model_dump(by_alias=True)))
|
||||||
("result", final_result.model_dump(by_alias=True))
|
|
||||||
)
|
|
||||||
await send_stream.send(("done", {}))
|
await send_stream.send(("done", {}))
|
||||||
|
|
||||||
async def event_stream() -> Any:
|
async def event_stream() -> Any:
|
||||||
|
|||||||
@@ -245,9 +245,7 @@ def _b64decode(data: str) -> bytes:
|
|||||||
def _prune_challenges_locked() -> None:
|
def _prune_challenges_locked() -> None:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
expired = [
|
expired = [
|
||||||
token
|
token for token, record in _CHALLENGES.items() if record.expires_at <= now
|
||||||
for token, record in _CHALLENGES.items()
|
|
||||||
if record.expires_at <= now
|
|
||||||
]
|
]
|
||||||
for token in expired:
|
for token in expired:
|
||||||
_CHALLENGES.pop(token, None)
|
_CHALLENGES.pop(token, None)
|
||||||
|
|||||||
@@ -42,4 +42,4 @@ def test_analyzer_runs_selected_tests_and_reports_progress() -> None:
|
|||||||
assert progress_events
|
assert progress_events
|
||||||
assert all(total == 2 for _, total, _ in progress_events)
|
assert all(total == 2 for _, total, _ in progress_events)
|
||||||
assert progress_events[0][0] == 0
|
assert progress_events[0][0] == 0
|
||||||
assert progress_events[-1][0] == 1
|
assert progress_events[-1][0] == 1
|
||||||
|
|||||||
@@ -48,4 +48,4 @@ def test_parser_preserves_content_type_boundary(sample_headers: str) -> None:
|
|||||||
headers = parser.parse(sample_headers)
|
headers = parser.parse(sample_headers)
|
||||||
|
|
||||||
content_type = next(header for header in headers if header.name == "Content-Type")
|
content_type = next(header for header in headers if header.name == "Content-Type")
|
||||||
assert "boundary=\"boundary-123\"" in content_type.value
|
assert 'boundary="boundary-123"' in content_type.value
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ def test_registry_filters_by_ids_and_lists_tests() -> None:
|
|||||||
|
|
||||||
assert lookup[1].category
|
assert lookup[1].category
|
||||||
assert lookup[12].category
|
assert lookup[12].category
|
||||||
assert lookup[66].category
|
assert lookup[66].category
|
||||||
|
|||||||
@@ -105,8 +105,16 @@ const timeoutReport: AnalysisReport = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AnalysisHarness = ({ request, onStatusChange }: HarnessProps) => {
|
const AnalysisHarness = ({ request, onStatusChange }: HarnessProps) => {
|
||||||
const { status, progress, result, error, submit, cancel, captchaChallenge, clearCaptchaChallenge } =
|
const {
|
||||||
useAnalysis();
|
status,
|
||||||
|
progress,
|
||||||
|
result,
|
||||||
|
error,
|
||||||
|
submit,
|
||||||
|
cancel,
|
||||||
|
captchaChallenge,
|
||||||
|
clearCaptchaChallenge,
|
||||||
|
} = useAnalysis();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onStatusChange?.(status);
|
onStatusChange?.(status);
|
||||||
|
|||||||
@@ -105,8 +105,7 @@ export default function CaptchaChallenge({
|
|||||||
),
|
),
|
||||||
).filter(
|
).filter(
|
||||||
(element) =>
|
(element) =>
|
||||||
!element.hasAttribute("disabled") &&
|
!element.hasAttribute("disabled") && element.getAttribute("aria-hidden") !== "true",
|
||||||
element.getAttribute("aria-hidden") !== "true",
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (focusableElements.length === 0) {
|
if (focusableElements.length === 0) {
|
||||||
|
|||||||
@@ -167,7 +167,6 @@ export default function FileDropZone({ onFileContent }: FileDropZoneProps) {
|
|||||||
role="button"
|
role="button"
|
||||||
aria-label="Drop or select an EML or TXT file"
|
aria-label="Drop or select an EML or TXT file"
|
||||||
aria-describedby={describedBy}
|
aria-describedby={describedBy}
|
||||||
aria-invalid={error ? "true" : undefined}
|
|
||||||
>
|
>
|
||||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full border border-info/30 bg-background/40">
|
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full border border-info/30 bg-background/40">
|
||||||
<FontAwesomeIcon icon={faArrowUpFromBracket} className="text-sm text-info" />
|
<FontAwesomeIcon icon={faArrowUpFromBracket} className="text-sm text-info" />
|
||||||
|
|||||||
Reference in New Issue
Block a user