Skip to content

fix: reject trailing input in beacon, gnomAD and SPDI translators - #670

Merged
korikuzma merged 2 commits into
ga4gh:mainfrom
syahra712:fix-anchor-translator-regexes
Oct 19, 2026
Merged

korikuzma merged 2 commits into
ga4gh:mainfrom
syahra712:fix-anchor-translator-regexes

Conversation

@syahra712

Copy link
Copy Markdown
Contributor

Bug

AlleleTranslator silently accepts beacon, gnomAD and SPDI expressions that have extra content after the variant, and translates only the leading part. For example:

tlr.translate_from("1-55516888-G-GA,GT", fmt="gnomad")

returns the allele for G>GA and quietly drops the second ALT. A caller passing a multi-allelic VCF-style record therefore gets a wrong but plausible-looking variant back, with no error. The same thing happens with 19-44908822-C-T;foo (gnomAD), NC_000019.10:44908821:1:T:extra (SPDI) and 19 : 44908822 C > T,G (beacon).

Root cause

_from_beacon, _from_gnomad and _from_spdi apply beacon_re, gnomad_re and spdi_re with re.match(). That anchors only at the start of the string, and none of the patterns end with $, so any matching prefix is enough.

Fix

Use fullmatch() in all three parsers. Input with trailing content now fails to parse, and the parser returns None before it makes any data proxy call. translate_from(..., fmt=...) then raises the usual ValueError: Unable to parse data as <fmt> variation, and format auto-detection falls through as it does for any other unparseable string. Well-formed input is unaffected.

Test

Adds test_from_trailing_input_rejected in tests/extras/test_allele_translator.py, parametrized over the four inputs above. It needs no cassette because rejection happens before any data proxy lookup. All four cases fail on main and pass with this change.

Locally, with SEQREPO_ROOT_DIR=./tests/data/seqrepo/latest pytest --vcr-record=none, the full suite gives 153 passed. ruff check and ruff format --check (ruff 0.9.4) are clean.

The translator regexes were applied with re.match, which only anchors
at the start. Input with trailing content was silently truncated, so a
multi-allelic gnomAD expression like 1-55516888-G-GA,GT was translated
as G>GA. Use fullmatch so such input is rejected as unparseable.
@syahra712
syahra712 requested review from a team as code owners October 18, 2026 11:27

@korikuzma korikuzma left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @syahra712 for the great catch (surprised it's gone this long unnoticed)

Changes related to this PR look good. Requesting that the generated test files be removed from this PR (I have a fix in #671 so that these files are written to temp dirs)

Comment thread tests/extras/data/test_rle_output.pkl Outdated
Comment thread tests/extras/data/test_rle_output.vcf Outdated
@syahra712

Copy link
Copy Markdown
Contributor Author

Thanks! Both generated files are removed in 47ef310, so the PR now only touches translator.py and its tests.

@korikuzma korikuzma left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much!

@korikuzma
korikuzma merged commit 44e6db4 into ga4gh:main Oct 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants