اصلاح مشکل CORS
Verify / test (push) Failing after 17s

This commit is contained in:
2026-11-05 18:49:21 +03:30
والد 56c5ee23d3
کامیت 407b213222
3فایلهای تغییر یافته به همراه72 افزوده شده و 1 حذف شده
+9
مشاهده پرونده
@@ -10,6 +10,7 @@ from pathlib import Path
from typing import Annotated, Literal
from fastapi import FastAPI, File, Form, Header, HTTPException, Request, UploadFile
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse, Response
from sqlalchemy import func, select, text
from sqlalchemy.exc import SQLAlchemyError
@@ -80,6 +81,14 @@ async def security(request, call_next):
})
return response
# Register after security so CORS also decorates its early authentication errors.
app.add_middleware(
CORSMiddleware,
allow_origins=['https://git.sadentel.net'],
allow_methods=['GET', 'POST', 'OPTIONS'],
allow_headers=['X-API-Key', 'X-Viewer-Token', 'Content-Type'],
)
@app.exception_handler(HTTPException)
async def http_error(request, exc):
detail = exc.detail if isinstance(exc.detail, dict) else {'code': 'http_error', 'message': str(exc.detail)}
@@ -163,3 +163,65 @@ def test_parser_wall_timeout_is_reported(client,ascii_schematic,monkeypatch):
process(job)
status=client.get(f"/api/v1/schematics/{body['id']}/status",headers={'X-API-Key':KEY}).json()
assert status['status']=='failed' and status['error']['code']=='parse_timeout'
CORS_ORIGIN = 'https://git.sadentel.net'
@pytest.mark.parametrize('requested_headers', ['x-api-key', 'X-API-Key, Content-Type'])
def test_gitea_preflight_without_api_key(client, requested_headers):
response = client.options('/api/v1/schematics/render', headers={
'Origin': CORS_ORIGIN,
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': requested_headers,
})
assert response.status_code == 200, response.text
assert response.headers['access-control-allow-origin'] == CORS_ORIGIN
assert {'POST', 'OPTIONS'} <= set(response.headers['access-control-allow-methods'].split(', '))
allowed = {h.strip().lower() for h in response.headers['access-control-allow-headers'].split(',')}
assert {'x-api-key', 'content-type'} <= allowed
assert 'Origin' in response.headers['vary']
assert 'access-control-allow-credentials' not in response.headers
@pytest.mark.parametrize('origin', ['https://evil.example', 'https://git.sadentel.net.evil.example', 'http://git.sadentel.net'])
def test_cors_rejects_other_origins(client, origin):
response = client.options('/api/v1/schematics/render', headers={
'Origin': origin,
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'x-api-key',
})
assert response.status_code == 400
assert 'access-control-allow-origin' not in response.headers
@pytest.mark.parametrize('key', [None, 'invalid-key', KEY])
def test_gitea_post_retains_authentication_and_cors(client, ascii_schematic, key):
headers = {'Origin': CORS_ORIGIN}
if key is not None: headers['X-API-Key'] = key
response = client.post('/api/v1/schematics/render', headers=headers,
files={'file': ('design.SchDoc', ascii_schematic)}, data={'access': 'private'})
assert response.status_code == (202 if key == KEY else 401)
assert response.headers['access-control-allow-origin'] == CORS_ORIGIN
def test_gitea_private_status_read(client, ascii_schematic):
created = upload(client, ascii_schematic).json()
endpoint = f"/api/v1/schematics/{created['id']}/status"
preflight = client.options(endpoint, headers={
'Origin': CORS_ORIGIN, 'Access-Control-Request-Method': 'GET',
'Access-Control-Request-Headers': 'x-viewer-token',
})
assert preflight.status_code == 200
response = client.get(endpoint, headers={'Origin': CORS_ORIGIN, 'X-Viewer-Token': created['viewer_token']})
assert response.status_code == 200
assert response.headers['access-control-allow-origin'] == CORS_ORIGIN
assert client.get(endpoint, headers={'Origin': CORS_ORIGIN}).status_code == 404
def test_cors_rejects_unneeded_methods_and_headers(client):
for method, header in [('DELETE', 'x-api-key'), ('POST', 'x-unapproved-header')]:
response = client.options('/api/v1/schematics/render', headers={
'Origin': CORS_ORIGIN, 'Access-Control-Request-Method': method,
'Access-Control-Request-Headers': header,
})
assert response.status_code == 400