Skip to content

[l10n/automation] Add comment renderer and manifest validator#941

Open
Chaitanya-Keyal wants to merge 1 commit into
SeedSigner:devfrom
Chaitanya-Keyal:l10n/comment-tools
Open

[l10n/automation] Add comment renderer and manifest validator#941
Chaitanya-Keyal wants to merge 1 commit into
SeedSigner:devfrom
Chaitanya-Keyal:l10n/comment-tools

Conversation

@Chaitanya-Keyal

@Chaitanya-Keyal Chaitanya-Keyal commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Note

One of the l10n source-string automation PRs (#940, #941, #942, #943, #944). The manifest schema this validates against, and the tests' conftest, are added in #940.

Description

Problem or Issue being addressed

The review manifest is produced by untrusted PR code but rendered into a PR comment by a trusted job. We need to
(a) validate the manifest before trusting it and
(b) render it without letting attacker-controlled source strings break out of the comment.

Solution

Adds two tools:

  • validate_manifest.py -- validates a manifest against the schema and checks two trust anchors GitHub sets authoritatively (the repository, and the head SHA the triggering run was built from). This is the security boundary between the untrusted producer and the trusted consumer.
  • render_comment.py -- renders the advisory comment. Source strings are shown inside a ```diff``` fence with newlines flattened and a +/- prefix on every line, so no msgid can start a line and break the fence or inject markup. A test feeds a hostile msgid and proves no breakout.

This pull request is categorized as a:

  • Other (l10n automation)

Checklist

I ran pytest locally

  • All tests passed before submitting the PR

(python -m pytest l10n/automation/tests -- these tests live outside the project's default testpaths and are run explicitly.)


I included screenshots of any new or modified screens

  • N/A

I added or updated tests

  • Yes

I tested this PR hands-on on the following platform(s):

  • Github Actions

I have reviewed these notes:

  • Keep your changes limited in scope.
  • If you uncover other issues or improvements along the way, ideally submit those as a separate PR.
  • The more complicated the PR, the harder it is to review, test, and merge.
  • We appreciate your efforts, but we're a small team of volunteers so PR review can be a very slow process.
  • Please only "@" mention a contributor if their input is truly needed to enable further progress.
  • I understand

render_comment.py renders the advisory comment from a validated manifest;
untrusted source strings are contained in a diff code fence, with a test
proving fence-breakout is not possible. validate_manifest.py checks a
manifest against the schema and the repository / head-SHA trust anchors
before the trusted comment job acts on it. Includes tests.

These tests rely on the diff engine's conftest for import-path setup, so
merge after the diff engine.
Comment on lines +64 to +68
for e in impact["changed"]:
now_plural = bool(e.get("plural"))
ctx = _annotations(e, include_plural=False)
lines.append(_row("-", e.get("msgid", ""), ctx + [f"was {'singular' if now_plural else 'plural'} form"]))
lines.append(_row("+", e.get("msgid", ""), ctx + [f"now {'plural' if now_plural else 'singular'} form"]))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

pot_diff.py flags a string as "changed" if the singular/plural state toggles, OR if just the plural text is edited.

This block incorrectly assumes every change is a toggle. If a developer just edits a plural text (e.g. from "apples" to "apple pieces"), it falsely outputs - [was singular form] and + [now plural form].

Since the manifest drops the old state, Maybe use a generic label like [plural form or text changed]?

Comment on lines +24 to +27
with open(manifest_path, encoding="utf-8") as fh:
manifest = json.load(fh)
with open(schema_path, encoding="utf-8") as fh:
schema = json.load(fh)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Currently, if manifest.json is corrupted or empty, these lines will crash with a raw JSONDecodeError or FileNotFoundError traceback.

Wrapping this file I/O in a try/except block and appending a clean message to the errors list might make the CI failure logs much cleaner

Comment on lines +123 to +129
body = render(manifest)
if args.out == "-":
print(body)
else:
with open(args.out, "w", encoding="utf-8") as fh:
fh.write(body)
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Similar to the script in PR #940, body can contain raw non-ASCII characters from the translated strings. If this script is run with --out - in a CI environment where sys.stdout is bound to ASCII, print(body) will crash with a UnicodeEncodeError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Summer of Bitcoin

Development

Successfully merging this pull request may close these issues.

2 participants