Repository navigation
Conversation
The protected-translation prefix covers 214 keys across 16 modules, but the security tests name 8 of them; the other 104 are protected as a side effect of the prefix. Section titles, empty states and Refresh sit behind a rule written for consent copy, so the plugins pane reads half-translated in every locale. Add an allowlist of 35 exact paths that carry no trust decision. The prefix still matches first, so anything new stays protected until it is added here.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe change adds an explicit allowlist for translatable plugin Chrome paths. The language-pack parser uses the allowlist for exact paths and protected containers. Tests verify catalog coverage, exclusion of security-related paths, rejection of failure messages, and preservation of protected security claims. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/shared/plugins/plugin-translatable-chrome.ts (1)
1-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winShorten the allowlist policy comment.
Keep one non-obvious invariant beside the allowlist. Remove the repeated examples and explanatory prose.
For example:
// Only exact non-security plugin chrome paths are translatable; new paths remain protected by default.As per coding guidelines, “Comments must be concise, limited to non-obvious information, and preferably one line.”
Source: Coding guidelines
src/renderer/src/i18n/plugin-chrome-allowlist.test.ts (1)
13-22: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winProtect destructive-dialog paths in the regression fixtures.
SECURITY_COPY_COMPONENTSomitsPluginRemoveDialogandPluginRollbackDialog. A future allowlist path below either component will pass this guard. Add both names here and to the matching component fixture insrc/shared/plugins/plugin-language-pack-artifact.test.ts.Proposed fixture update
const SECURITY_COPY_COMPONENTS = [ 'PluginConsentDialog', + 'PluginRemoveDialog', + 'PluginRollbackDialog', 'PluginConsentProvenance',src/shared/plugins/plugin-language-pack-artifact.test.ts (1)
60-72: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winCover the nested settings-search path.
The success table only traverses one protected component container. It does not exercise
auto.components.settings.plugins.search.title, which requires bothpluginsandplugins.searchto remain walkable. Add a successful parse case for that path.Proposed test
+ it('lets a language pack translate nested settings-search chrome', () => { + expect( + parsePluginLanguagePackArtifact( + JSON.stringify({ + auto: { + components: { + settings: { plugins: { search: { title: 'Плагины' } } } + } + } + }) + ).ok + ).toBe(true) + })
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 778c5af1-5ff8-47ed-8ea1-abf5da8c4802
📒 Files selected for processing (4)
src/renderer/src/i18n/plugin-chrome-allowlist.test.tssrc/shared/plugins/plugin-language-pack-artifact.test.tssrc/shared/plugins/plugin-language-pack-artifact.tssrc/shared/plugins/plugin-translatable-chrome.ts
|
@nwparker — this one has no reviewer: Short version of the change, since the boundary is yours to defend:
The prefix rule is unchanged. The PR adds an allowlist of 35 exact paths — section titles, empty states, What I deliberately left protected is probably the more interesting half of the review: anything that promises something about plugin behavior ( 35 is the conservative floor, not a claim about the remaining 69. Verified against a real pack as well: an 11,742-string Russian catalog parses today, parses with the chrome translated, and is still rejected when it rewrites |
|
@coderabbitai Addressed in c4f7122:
Not applied: shortening the policy comment in
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
git show --stat --oneline c4f71221a
git show --format=fuller --find-renames -- \
src/renderer/src/i18n/plugin-chrome-allowlist.test.ts \
src/shared/plugins/plugin-language-pack-artifact.test.ts \
c4f71221a
printf '\n--- Relevant assertions on the PR branch ---\n'
rg -n -C 5 \
'PluginRemoveDialog|PluginRollbackDialog|auto\.components\.settings\.plugins\.search\.title|SECURITY_COPY_COMPONENTS|pinned' \
src/renderer/src/i18n/plugin-chrome-allowlist.test.ts \
src/shared/plugins/plugin-language-pack-artifact.test.tsLength of output: 7274
The new Keeping the policy comment is appropriate. It documents the security boundary and the deliberate exclusions. ✏️ Learnings added
If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! You are interacting with an AI system. |
protectedTranslation refused every language-pack key under auto.components.settings.plugin*, which caught 104 keys that carry no trust meaning — section titles, empty states, Refresh, Add path. A 35-path exact allowlist opens those while consent, provenance, and every *Failed string stay protected; anything new stays protected until it is added deliberately. PluginsSettingsSection.experimental is held back from the contributed allowlist: the "Experimental" chip is a trust badge, which the module's own boundary comment places out of scope. Co-authored-by: Evgenii <kumiro@me.com>
|
Merged into Closing this in favour of that. Thank you for the fix, and sorry it took as long as it did to get through. |
Summary
protectedTranslationrefuses any language-pack key underauto.components.settings.whose module starts withplugin. The breadth is deliberate and the comment says why — a consent surface added tomorrow is covered the day it lands, the lesson fromPluginConsentProvenance. That reasoning is sound and this PR keeps it.The side effect is that the prefix also catches copy that carries no security meaning. 214 keys sit behind the rule across 16 modules. The existing test names 8 of those modules as security copy:
Those 8 modules hold 110 keys. The other 104 are protected as a side effect of the prefix, not because anyone classified them as a trust surface — section titles, empty states,
Refresh,Add path.The boundary is visibly accidental in one place:
PluginMarketplaceBrowser.tsxis protected and rendersPluginCatalogLayoutfromcomponents/plugin-catalog/, which is not. One pane, nested components, and translatability decided by which folder the file lives in. In a localized build the inner list translates while the frame around it stays English.What changed
A narrow allowlist of 35 exact paths, in
plugin-translatable-chrome.ts. Exact paths rather than a pattern on purpose: anything new stays protected until someone deliberately adds it, so the fail-safe survives.A protected container stays walkable only when exempt chrome sits below it — every leaf is still matched against its own full path, so
PluginsSettingsSection.titleresolves whilePluginsSettingsSection.descriptionright next to it does not.PluginsSettingsSectionExperimental,Plugin system, list statesdescription,systemDescription,featureOff, every*FailedPluginMarketplaceBrowserManage sourcesnoSources(names the official/community tiers), every*FailedPluginDevelopmentSectionDevelopmenthelp,saveFailedplugins.searchWhat deliberately stays protected
A path qualifies only if rewriting it cannot mislead the person deciding whether to trust a plugin. Reading every one of the 104 keys, these do not qualify:
PluginsSettingsSection.systemDescriptionsays "Nothing runs until you review and enable it";.descriptionsays "Plugins run on this computer";.featureOffsays installed plugins "stay disabled while the system is off";PluginDevelopmentSection.helpsays "Dev plugins still require permission review". Swapping any of these for reassuring text is the attack, so they stay behind the rule even though they read like plain descriptions.PluginMarketplaceBrowser.installFailedis "The reviewed source may have changed". Rather than judge each message, the whole*Failedfamily stays protected — a test enforces that, so the boundary is a rule and not a case-by-case call.PluginSettingsRow.blocked,PluginMarketplaceListingRow.official,.blocked.PluginRemoveDialog,PluginRollbackDialog.Two follow-ups I did not take unilaterally:
PluginMarketplaceListingRow.installedand.checkUpdateare procedural, but they live besideofficialandblocked, so splitting that module is your call. Same forPluginInstallDialog, which mixes a button label with consent copy.Screenshots
No visual change in English — no English string is added, removed, or reworded.
Settings → Plugins in a build with a Russian language pack, today. The inner list (
pluginCatalog) is translated; the frame around it (settings.Plugin*) is not:With this change the frame resolves too, while every string listed above stays English by design.
Testing
pnpm lintpnpm typecheckpnpm testpnpm buildNew coverage in
plugin-language-pack-artifact.test.ts: chrome keys parse, and the trust promises above are still refused — including a pack that rewritessystemDescriptionto "Every plugin here has been reviewed by Orca." and one that rewritesinstallFailedto "Installed successfully."plugin-chrome-allowlist.test.tsguards the list itself against rot in both directions: every exempt path must still exist inen.json, none may belong to a module the security tests pin, and none may be*Failed.Verified against a real pack as well — the 11,742-string
smwbev.russiancatalog parses today, parses with the chrome translated, and is still rejected when it reaches for a trust promise.AI Review Report
Reviewed for security-boundary correctness first, then for the walk semantics.
PluginsSettingsSectionwas rejected as a container before any leaf was reached. Fixed by letting a protected container stay walkable only when exempt chrome sits below it; leaves are unchanged and still matched on their full path. Without this the feature silently did nothing.systemDescription,description,featureOff,help, andnoSourcesout of the list — they read as chrome but assert something about plugin behavior or trust tiers.PluginDevelopmentSection.placeholdercontains both POSIX and Windows example paths and is exempt as a label; it is illustrative text, not a path the code consumes.Security Audit
systemDescriptioncases.Notes
The 35 paths are the conservative floor, not a claim that the remaining 69 side-effect keys must stay protected forever. If you would rather split
PluginMarketplaceListingRowandPluginInstallDialogso their procedural labels move too, I am happy to extend this in the same shape.