ci: add CodeQL security scanning and Dependabot
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ac002131d6
commit
3866c6d6f0
90 changed files with 40 additions and 1 deletions
86
app/services/arxiv/guards.py
Normal file
86
app/services/arxiv/guards.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from app.services.domains.arxiv.constants import (
|
||||
ARXIV_STRONG_IDENTIFIER_CONFIDENCE,
|
||||
ARXIV_TITLE_MIN_ALPHA_TOKENS,
|
||||
ARXIV_TITLE_MIN_TOKENS,
|
||||
ARXIV_TITLE_TOKEN_MIN_LENGTH,
|
||||
)
|
||||
from app.services.domains.doi.normalize import normalize_doi
|
||||
from app.services.domains.publication_identifiers.normalize import normalize_arxiv_id
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from app.services.domains.publications.types import PublicationListItem, UnreadPublicationItem
|
||||
|
||||
_TITLE_TOKEN_RE = re.compile(r"[a-z0-9]+")
|
||||
|
||||
|
||||
def arxiv_skip_reason_for_item(
|
||||
*,
|
||||
item: PublicationListItem | UnreadPublicationItem,
|
||||
has_strong_doi: bool = False,
|
||||
has_existing_arxiv: bool = False,
|
||||
) -> str | None:
|
||||
if has_existing_arxiv or _has_arxiv_identifier_evidence(item):
|
||||
return "arxiv_identifier_present"
|
||||
if has_strong_doi or _has_strong_doi_evidence(item):
|
||||
return "strong_doi_present"
|
||||
if not _title_passes_quality_guard(item.title):
|
||||
return "title_quality_below_threshold"
|
||||
return None
|
||||
|
||||
|
||||
def _has_arxiv_identifier_evidence(item: PublicationListItem | UnreadPublicationItem) -> bool:
|
||||
if _display_identifier_matches(item, expected_kind="arxiv"):
|
||||
return True
|
||||
return _has_normalized_identifier(item, normalizer=normalize_arxiv_id)
|
||||
|
||||
|
||||
def _has_strong_doi_evidence(item: PublicationListItem | UnreadPublicationItem) -> bool:
|
||||
if _display_identifier_matches(item, expected_kind="doi"):
|
||||
return True
|
||||
return _has_normalized_identifier(item, normalizer=normalize_doi)
|
||||
|
||||
|
||||
def _display_identifier_matches(
|
||||
item: PublicationListItem | UnreadPublicationItem,
|
||||
*,
|
||||
expected_kind: str,
|
||||
) -> bool:
|
||||
display = getattr(item, "display_identifier", None)
|
||||
if display is None:
|
||||
return False
|
||||
if str(display.kind).lower() != expected_kind:
|
||||
return False
|
||||
return float(display.confidence_score) >= ARXIV_STRONG_IDENTIFIER_CONFIDENCE
|
||||
|
||||
|
||||
def _has_normalized_identifier(
|
||||
item: PublicationListItem | UnreadPublicationItem,
|
||||
*,
|
||||
normalizer,
|
||||
) -> bool:
|
||||
if normalizer(item.pub_url):
|
||||
return True
|
||||
return normalizer(item.pdf_url) is not None
|
||||
|
||||
|
||||
def _title_passes_quality_guard(title: str | None) -> bool:
|
||||
tokens = _normalized_tokens(title or "")
|
||||
if len(tokens) < ARXIV_TITLE_MIN_TOKENS:
|
||||
return False
|
||||
alpha_tokens = [token for token in tokens if _is_alpha_token(token)]
|
||||
return len(alpha_tokens) >= ARXIV_TITLE_MIN_ALPHA_TOKENS
|
||||
|
||||
|
||||
def _normalized_tokens(value: str) -> list[str]:
|
||||
return [token for token in _TITLE_TOKEN_RE.findall(value.lower()) if token]
|
||||
|
||||
|
||||
def _is_alpha_token(token: str) -> bool:
|
||||
if len(token) < ARXIV_TITLE_TOKEN_MIN_LENGTH:
|
||||
return False
|
||||
return any(char.isalpha() for char in token)
|
||||
Loading…
Add table
Add a link
Reference in a new issue