mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 01:47:24 +00:00
184 lines
6.5 KiB
TypeScript
184 lines
6.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
||
import {
|
||
parsePluginLanguagePackArtifact,
|
||
pluginLanguageResourceId
|
||
} from './plugin-language-pack-artifact'
|
||
import { englishSourceLookup } from '../languages/plugin-translation-string-policy'
|
||
|
||
describe('plugin language-pack artifacts', () => {
|
||
it('maps qualified IDs to distinct canonical private-use tags on the pack locale', () => {
|
||
const first = pluginLanguageResourceId('plugin:a.bc/ru-RU')
|
||
const second = pluginLanguageResourceId('plugin:ab.c/ru-RU')
|
||
|
||
for (const resourceLanguage of [first, second]) {
|
||
expect(resourceLanguage).toMatch(/^ru-RU-x-orcapk-/)
|
||
expect(Intl.getCanonicalLocales(resourceLanguage)).toEqual([resourceLanguage])
|
||
}
|
||
expect(first).not.toBe(second)
|
||
})
|
||
|
||
it('drops protected copy instead of rejecting the pack when loading tolerantly', () => {
|
||
const raw = JSON.stringify({
|
||
common: { save: 'Sávé' },
|
||
components: { 'native-chat': { approval: { allow: 'Álló' }, title: 'Çhát' } }
|
||
})
|
||
|
||
expect(parsePluginLanguagePackArtifact(raw).ok).toBe(false)
|
||
expect(parsePluginLanguagePackArtifact(raw, 'tolerant')).toMatchObject({
|
||
ok: true,
|
||
catalog: { common: { save: 'Sávé' }, components: { 'native-chat': { title: 'Çhát' } } }
|
||
})
|
||
})
|
||
|
||
// Chrome exemptions must never include claims about plugin permissions; those are the protected prefix’s purpose.
|
||
it.each([
|
||
['description', 'Plugins are sandboxed and cannot read your files.'],
|
||
['systemDescription', 'Every plugin here has been reviewed by Orca.']
|
||
])('still refuses PluginsSettingsSection.%s', (key, value) => {
|
||
expect(
|
||
parsePluginLanguagePackArtifact(
|
||
JSON.stringify({
|
||
auto: { components: { settings: { PluginsSettingsSection: { [key]: value } } } }
|
||
})
|
||
)
|
||
).toMatchObject({ ok: false, error: expect.stringContaining('protected security copy') })
|
||
})
|
||
|
||
it.each([
|
||
[
|
||
'the Official badge',
|
||
{ auto: { components: { pluginCatalog: { PluginListRow: { official: 'x' } } } } }
|
||
],
|
||
[
|
||
'the suggestion banner',
|
||
{ auto: { components: { editor: { PluginFileTypeSuggestion: { view: 'x' } } } } }
|
||
],
|
||
[
|
||
'agent Allow/Deny',
|
||
{ components: { 'native-chat': { approval: { allow: 'Deny', deny: 'Allow' } } } }
|
||
],
|
||
[
|
||
'the orca.yaml trust dialog',
|
||
{ auto: { components: { sidebar: { OrcaYamlTrustDialog: { '43b7bec4cd': 'Run' } } } } }
|
||
],
|
||
[
|
||
'the notebook trust dialog',
|
||
{ auto: { components: { editor: { IpynbViewer: { '9e06ae5d36': 'Open notebook?' } } } } }
|
||
],
|
||
['the certificate warning', { browser: { loadFailure: { proceedUnsafe: 'Continue' } } }],
|
||
[
|
||
'the site permission prompt',
|
||
{ auto: { components: { browserPane: { sitePermission: { allow: 'Block' } } } } }
|
||
],
|
||
[
|
||
'site permission settings',
|
||
{ settings: { browser: { sitePermissions: { block: 'Allow' } } } }
|
||
],
|
||
[
|
||
'the catalog-link trust dialog',
|
||
{
|
||
auto: {
|
||
components: { plugins: { PluginCatalogLinkDialog: { title: "Add Orca's catalog?" } } }
|
||
}
|
||
}
|
||
],
|
||
[
|
||
'browser-extension Allow/Deny',
|
||
{ browserExtensions: { permissions: { deny: 'Allow', confirm: 'Deny' } } }
|
||
],
|
||
[
|
||
'the Node download mirror dialog',
|
||
{ auto: { components: { settings: { nodeDistMirrorDialog: { title: 'Safe mirror' } } } } }
|
||
],
|
||
[
|
||
'delete-workspace buttons',
|
||
{
|
||
auto: {
|
||
components: { sidebar: { DeleteWorktreeDialogFooter: { deleteWorkspace: 'Cancel' } } }
|
||
}
|
||
}
|
||
],
|
||
[
|
||
'the remove-host confirmation',
|
||
{ auto: { components: { sidebar: { HostRemoveDialog: { '6f7a8b9c0d': 'Remove' } } } } }
|
||
],
|
||
[
|
||
'the not-official trust warning',
|
||
{
|
||
auto: {
|
||
components: { settings: { PluginNotOfficialWarning: { label: 'Verified by Orca' } } }
|
||
}
|
||
}
|
||
],
|
||
[
|
||
'the update review Approve button',
|
||
{ auto: { components: { settings: { PluginUpdateReview: { approve: 'Back' } } } } }
|
||
],
|
||
[
|
||
'the startup repair-or-quit prompt',
|
||
{ profileState: { repairChoice: { quitButton: 'Repair' } } }
|
||
]
|
||
])('refuses to relabel %s', (_label, catalog) => {
|
||
expect(parsePluginLanguagePackArtifact(JSON.stringify(catalog))).toMatchObject({
|
||
ok: false,
|
||
error: expect.stringContaining('protected security copy')
|
||
})
|
||
})
|
||
|
||
it.each([
|
||
['array leaf', { settings: { choices: ['one'] } }],
|
||
['numeric leaf', { settings: { count: 1 } }],
|
||
['dotted key', { 'settings.title': 'Title' }],
|
||
['prototype key', JSON.parse('{"__proto__":"bad"}')]
|
||
])('rejects %s', (_label, catalog) => {
|
||
expect(parsePluginLanguagePackArtifact(JSON.stringify(catalog)).ok).toBe(false)
|
||
})
|
||
|
||
describe('string limits', () => {
|
||
const english = englishSourceLookup({
|
||
common: { retry: 'Retry', detail: 'Line one\nLine two' },
|
||
items: { count_one: '{{count}} item', count_other: '{{count}} items' }
|
||
})
|
||
const parse = (catalog: unknown, strictness?: 'strict' | 'tolerant') =>
|
||
parsePluginLanguagePackArtifact(JSON.stringify(catalog), strictness, english)
|
||
|
||
it.each([
|
||
['a right-to-left override', 'Delete\u202Eetelpmoc'],
|
||
['an isolate', 'Retry\u2066x\u2069'],
|
||
['a control character', 'Retry\u0007'],
|
||
['a carriage return', 'Retry\r']
|
||
])('rejects %s', (_label, retry) => {
|
||
expect(parse({ common: { retry } })).toMatchObject({
|
||
ok: false,
|
||
error: expect.stringContaining('control or bidirectional')
|
||
})
|
||
})
|
||
|
||
it('allows line breaks only where the English text has them', () => {
|
||
expect(parse({ common: { detail: 'Eins\nZwei' } }).ok).toBe(true)
|
||
expect(parse({ common: { retry: 'Run this first:\ncurl x | sh' } })).toMatchObject({
|
||
ok: false,
|
||
error: expect.stringContaining('line break')
|
||
})
|
||
})
|
||
|
||
it('drops only the offending entries when loading tolerantly', () => {
|
||
expect(
|
||
parse(
|
||
{ common: { retry: 'x'.repeat(65), detail: 'Eins\nZwei' }, other: { bad: 'a\u202Eb' } },
|
||
'tolerant'
|
||
)
|
||
).toMatchObject({ ok: true, catalog: { common: { detail: 'Eins\nZwei' }, other: {} } })
|
||
})
|
||
|
||
it('applies only source-independent rules without English text', () => {
|
||
expect(
|
||
parsePluginLanguagePackArtifact(JSON.stringify({ common: { retry: 'x'.repeat(8192) } })).ok
|
||
).toBe(true)
|
||
expect(
|
||
parsePluginLanguagePackArtifact(JSON.stringify({ common: { retry: 'a\u202Eb' } })).ok
|
||
).toBe(false)
|
||
})
|
||
})
|
||
})
|