Files
orca/config/scripts/project-catalog-read-boundary.test.mjs
T
Brennan Benson 29a5f89b8a Keep same-machine folders with matching Git remotes in separate projects (#32272)
* WIP: same-host same-remote checkouts keep their own project id

* WIP: claim the shared project id per checkout surface; drop the display-only clone split

* WIP: index derived ids by repo in the hydration normalizer

* Resolve workspace project affiliation from current checkout owners

* fix: preserve concrete project ownership across catalogs and operations

* fix: combine recent project selector imports

* fix: enforce canonical catalog reads and preserve search continuity

* fix: scope catalog lint exceptions to renderer files

* Resolve project search ownership before native candidate limits

* Combine duplicate session scope imports

* fix: derive returned history row ownership on the host

* Reconcile full session history replies by content

* Require authoritative project catalogs for terminal snapshots

* Preserve registered project claims and partial history results

* test: check orphaned setup cleanup state without assertions

* fix: align catalog callers and native search fixture contracts

* test: check full repo shapes in runtime routing fixtures

* Fix checked catalog inputs in compiler regression fixtures

* Keep checked PTY fixture repos mutable

* test: align catalog fixtures with canonical readers

* test: check catalog and runtime fixture inputs

* test: check catalog fixtures without outer assertions

* test: follow persistence harness relocation

* Adapt catalog test inputs to integrated main checks

* Test History hashing across cached depth revalidation

* test(settings): expect host-qualified setup removal

* test: capture host split listings and scope relay recovery

* ci: regenerate merge ref

* test: type host-split listing diagnostics
2026-10-26 19:07:06 -07:00

103 lines
4.1 KiB
JavaScript

import { readFileSync, mkdtempSync, realpathSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { resolve, join, dirname } from 'node:path'
import { spawnSync } from 'node:child_process'
import { expect, it } from 'vitest'
import { resolveOxcCliInvocation } from './oxc-cli-invocation.mjs'
it('enforces five raw catalog forms with the actual config and narrow file exceptions', () => {
const config = JSON.parse(readFileSync(resolve('.oxlintrc.json'), 'utf8'))
const jsPluginConfig = JSON.parse(readFileSync(resolve('config/oxlint-js-plugins.json'), 'utf8'))
expect(config.ignorePatterns.every((pattern) => typeof pattern === 'string')).toBe(true)
const folder = realpathSync(mkdtempSync(join(tmpdir(), 'sta-10541-catalog-rule-')))
const source = `
const key = 'projects';
function read(state) {
state.endpointProjects;
state?.endpointProjectHostSetups;
const { endpointProjects: projects } = state;
state['endpointProjectHostSetups'];
const key = 'endpointProjects'; state[key];
{ const key = 'projects'; state[key]; }
function shadow(key) { return state[key]; }
const unrelated = 'projectHostSetups'; state[unrelated];
state.projects;
state.projectHostSetups;
return projects;
}
`
try {
writeFileSync(join(folder, 'config.json'), JSON.stringify(config))
writeFileSync(
join(folder, 'js-config.json'),
JSON.stringify({
...jsPluginConfig,
jsPlugins: jsPluginConfig.jsPlugins.map((plugin) => ({
...plugin,
specifier: resolve('config', plugin.specifier)
}))
})
)
const lint = (file, content = source) => {
const target = join(folder, file)
mkdirSync(dirname(target), { recursive: true })
writeFileSync(target, content)
return ['config.json', 'js-config.json'].flatMap((configFile) => {
const invocation = resolveOxcCliInvocation('oxlint', 'oxlint')
const result = spawnSync(
invocation.command,
[
...invocation.prefixArgs,
'--config',
join(folder, configFile),
'--format',
'json',
file
],
{ cwd: folder, encoding: 'utf8' }
)
expect(result.error).toBeUndefined()
const diagnostics = JSON.parse(result.stdout).diagnostics
expect(result.stderr).toBe('')
expect(JSON.parse(result.stdout).number_of_files, result.stdout).toBe(1)
return diagnostics.filter(
(entry) =>
entry.code.includes('no-restricted-properties') ||
entry.code.includes('no-raw-project-catalog-computed')
)
})
}
for (const file of [
'src/renderer/src/hooks/useActiveProjectSkillRuntime.ts',
'src/renderer/src/store/repos/repo-state.ts'
]) {
const forbidden = lint(file)
expect(forbidden).toHaveLength(5)
expect(
forbidden.filter((entry) => entry.code.includes('no-restricted-properties'))
).toHaveLength(4)
expect(
forbidden.filter((entry) => entry.code.includes('no-raw-project-catalog-computed'))
).toHaveLength(1)
}
const allowed = 'src/renderer/src/store/project-host-setup-selector.ts'
expect(lint(allowed)).toEqual([])
const uuid = lint(allowed, 'crypto.randomUUID()')
expect(uuid).toHaveLength(1)
expect(uuid[0].message).toContain('randomUUID')
for (const file of [
'src/main/native-chat/agent-session-wire/structured-agent-session-host-test-harness.ts',
'src/main/runtime/rpc/methods/structured-chat-tab-table.test-fixture.ts',
'mobile/src/test-support/rpc-recording/native-mounting-substitutes.test.ts',
'tests/e2e/worktree-smart-sort.spec.ts'
]) {
expect(lint(file, 'crypto.randomUUID()')).toEqual([])
}
const sharedUuid = lint('src/shared/tmux-status.test-fixture.ts', 'crypto.randomUUID()')
expect(sharedUuid).toHaveLength(1)
expect(sharedUuid[0].help).toContain('src/shared is compiled into the web bundle')
} finally {
rmSync(folder, { recursive: true, force: true })
}
})