fix(evaluations): bypass Cloudflare 403 with browser headers + hardcoded fallback rounds
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- Add browser User-Agent and Referer headers to all evals.mitre.org requests
- fetch_rounds_with_status() returns api_reachable flag + rounds list
- Fallback to 5 known public CrowdStrike rounds (APT29/R2 through OilRig/R6)
when live API is blocked, so UI always shows something actionable
- Router returns {rounds, api_reachable, api_error} instead of plain array
- Frontend shows orange warning banner when using fallback data
- Remove 502 HTTPException - rounds are always returned (live or fallback)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,12 @@ export interface EvaluationRound {
|
||||
techniques_covered: number | null;
|
||||
}
|
||||
|
||||
export interface EvaluationRoundsResponse {
|
||||
rounds: EvaluationRound[];
|
||||
api_reachable: boolean;
|
||||
api_error: string | null;
|
||||
}
|
||||
|
||||
export interface EvaluationImportResult {
|
||||
message: string;
|
||||
created: number;
|
||||
@@ -70,8 +76,8 @@ export interface NewRoundCheckResult {
|
||||
}
|
||||
|
||||
/** List all public CrowdStrike evaluation rounds with import status. */
|
||||
export async function listEvaluationRounds(): Promise<EvaluationRound[]> {
|
||||
const { data } = await client.get<EvaluationRound[]>("/system/attck-evaluations/rounds");
|
||||
export async function listEvaluationRounds(): Promise<EvaluationRoundsResponse> {
|
||||
const { data } = await client.get<EvaluationRoundsResponse>("/system/attck-evaluations/rounds");
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
type SyncMitreResponse,
|
||||
type IntelScanResponse,
|
||||
type EvaluationRound,
|
||||
type EvaluationRoundsResponse,
|
||||
type EvaluationImportResult,
|
||||
type NewRoundCheckResult,
|
||||
} from "../api/system";
|
||||
@@ -164,14 +165,18 @@ export default function SystemPage() {
|
||||
|
||||
// ── ATT&CK Evaluations queries & mutations ───────────────────────
|
||||
const {
|
||||
data: evalRounds,
|
||||
data: evalRoundsData,
|
||||
isLoading: evalRoundsLoading,
|
||||
refetch: refetchEvalRounds,
|
||||
} = useQuery<EvaluationRound[]>({
|
||||
} = useQuery<EvaluationRoundsResponse>({
|
||||
queryKey: ["eval-rounds"],
|
||||
queryFn: listEvaluationRounds,
|
||||
});
|
||||
|
||||
const evalRounds = evalRoundsData?.rounds;
|
||||
const evalApiReachable = evalRoundsData?.api_reachable ?? true;
|
||||
const evalApiError = evalRoundsData?.api_error ?? null;
|
||||
|
||||
const checkNewRoundMutation = useMutation({
|
||||
mutationFn: checkNewEvaluationRound,
|
||||
onSuccess: (data) => {
|
||||
@@ -433,6 +438,19 @@ export default function SystemPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* API fallback warning */}
|
||||
{!evalApiReachable && evalApiError && (
|
||||
<div className="mb-4 flex items-start gap-3 rounded-lg border border-orange-500/30 bg-orange-900/10 p-3">
|
||||
<AlertCircle className="h-4 w-4 text-orange-400 flex-shrink-0 mt-0.5" />
|
||||
<div className="text-xs text-orange-300">
|
||||
<span className="font-medium">Live API unavailable</span>
|
||||
{" — "}showing known public rounds (hardcoded). Importing will attempt to fetch
|
||||
live results and may also fail if the API remains unreachable.
|
||||
<span className="block mt-1 text-orange-400/70 font-mono truncate">{evalApiError}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* New round check result */}
|
||||
{evalCheckResult && (
|
||||
<div className={`mb-4 rounded-lg border p-3 ${
|
||||
@@ -608,9 +626,11 @@ export default function SystemPage() {
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center gap-2 py-8 text-gray-500 text-sm">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<span>Unable to load evaluation rounds. Check network connectivity to evals.mitre.org.</span>
|
||||
<div className="py-8 text-center">
|
||||
<p className="text-sm text-gray-500">No evaluation rounds available.</p>
|
||||
{evalApiError && (
|
||||
<p className="mt-1 text-xs text-orange-400/70 font-mono">{evalApiError}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user