Your career → Other languages: any string is taken as a language and saved, however long #620

Closed
opened 2026-10-01 10:48:26 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the translation screen and trying it against the test settings.

Related to #337.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The cited lines have not moved. The language rules (normalise, TRANSLATABLE) are now in resume/translatable.py, which translating still hands out (#248), so the shared check named in the fix belongs there.

The screen that translates a career entry takes its language from ?language= or the posted language and saves under whatever it is given. It only lowercases the value and replaces underscores. AddLanguageForm offers the valid choices but nothing uses it to check a value. The candidate-file importer checks the same value against LANGUAGE_TAG and a 10-character limit; this screen does neither.

  • Where: resume/views.py:174-175 (ResumeItemTranslationsView.chosen_language), used by get (:211) and post (:223); resume/forms.py:266-289 (TranslationForm.save); resume/models.py:363 (Translation.language, max_length=10); compare resume/candidate.py:101-102 and :778-786 (LANGUAGE_TAG, MAX_LANGUAGE_LENGTH, _language).
  • What happens: a stale or edited address such as ?language=portuguese-brazil, or a form sent with any other value, is accepted. Tried on the test settings: posting language=Not A Language At All answered 302 and stored four Translation rows under not a language at all (21 characters in a 10-character column). The entry then lists a "language" of that name, and no CV can match it. SQLite does not enforce the column length; on PostgreSQL the insert fails with DataError, and the person gets a server error.
  • Why it matters: rows are stored under codes nothing can use, and on PostgreSQL a mistyped address causes a server error.
  • Fix: validate in chosen_language(): accept a value that matches candidate.LANGUAGE_TAG and fits MAX_LANGUAGE_LENGTH (moved into translating so both paths share one check). Rows the candidate importer wrote under tags outside languages.LANGUAGES stay editable. Answer anything else with a 404 or with the page and no form, and never save it.

Done when

  • A test in tests/test_career_languages.py posts a language that is not a tag, and one longer than ten characters, and finds no Translation rows and no 500; the same for GET ?language=.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the translation screen and trying it against the test settings. Related to #337. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The cited lines have not moved. The language rules (`normalise`, `TRANSLATABLE`) are now in `resume/translatable.py`, which `translating` still hands out (#248), so the shared check named in the fix belongs there. The screen that translates a career entry takes its language from `?language=` or the posted `language` and saves under whatever it is given. It only lowercases the value and replaces underscores. `AddLanguageForm` offers the valid choices but nothing uses it to check a value. The candidate-file importer checks the same value against `LANGUAGE_TAG` and a 10-character limit; this screen does neither. - **Where:** `resume/views.py:174-175` (`ResumeItemTranslationsView.chosen_language`), used by `get` (`:211`) and `post` (`:223`); `resume/forms.py:266-289` (`TranslationForm.save`); `resume/models.py:363` (`Translation.language`, `max_length=10`); compare `resume/candidate.py:101-102` and `:778-786` (`LANGUAGE_TAG`, `MAX_LANGUAGE_LENGTH`, `_language`). - **What happens:** a stale or edited address such as `?language=portuguese-brazil`, or a form sent with any other value, is accepted. Tried on the test settings: posting `language=Not A Language At All` answered 302 and stored four `Translation` rows under `not a language at all` (21 characters in a 10-character column). The entry then lists a "language" of that name, and no CV can match it. SQLite does not enforce the column length; on PostgreSQL the insert fails with `DataError`, and the person gets a server error. - **Why it matters:** rows are stored under codes nothing can use, and on PostgreSQL a mistyped address causes a server error. - **Fix:** validate in `chosen_language()`: accept a value that matches `candidate.LANGUAGE_TAG` and fits `MAX_LANGUAGE_LENGTH` (moved into `translating` so both paths share one check). Rows the candidate importer wrote under tags outside `languages.LANGUAGES` stay editable. Answer anything else with a 404 or with the page and no form, and never save it. ## Done when - A test in `tests/test_career_languages.py` posts a language that is not a tag, and one longer than ten characters, and finds no `Translation` rows and no 500; the same for `GET ?language=`.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:48:26 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#620
No description provided.