import { describe, it, expect } from 'vitest' import { resolveExposedDirs } from '../../bin/schema-exposed-dirs.mjs' const ALLOWED = ['projects', 'contacts', 'documents', 'output', 'uploads', 'quotes', 'sites'] function schema(opts: { allowed?: string[]; ontology?: string; pluginOwned?: string } = {}): string { const allowed = opts.allowed ?? ALLOWED return [ '# Account schema', '', '```allowed-top-level', ...allowed, '```', '', opts.pluginOwned ?? '', '', opts.ontology ?? '', '', ].join('\n') } // The generator writes this region with an ASCII hyphen separator // (account-schema-owned-dirs.py:294). const ONTOLOGY = [ '', '## Domain entity buckets (from the graph ontology)', '', '- `quotes/` - one folder per Quotation record.', '', ].join('\n') // The plugin-owned region uses an EM DASH (account-schema-owned-dirs.py:281). const PLUGIN_OWNED = [ '', '## Plugin-owned top-level workspaces', '', '- `sites/` — Owned by the cloudflare plugin.', '', ].join('\n') describe('resolveExposedDirs', () => { it('exposes ontology buckets plus output', () => { const r = resolveExposedDirs(schema({ ontology: ONTOLOGY })) expect(r.exposed).toEqual(['output', 'quotes']) expect(r.schemaPresent).toBe(true) }) it('exposes output alone when there is no ontology region', () => { expect(resolveExposedDirs(schema()).exposed).toEqual(['output']) }) it('drops a bucket that is absent from the allowed block', () => { const r = resolveExposedDirs(schema({ allowed: ['output', 'documents'], ontology: ONTOLOGY })) expect(r.exposed).toEqual(['output']) }) // The contract that fails silently if got wrong: an em dash in the ontology // region must NOT parse, because the generator never writes one there. it('does not parse an em-dash separator as a domain bucket', () => { const emDash = ONTOLOGY.replace('- one folder per', '— one folder per') expect(resolveExposedDirs(schema({ ontology: emDash })).domainBuckets).toEqual([]) }) it('never exposes operator-data or upload buckets', () => { const r = resolveExposedDirs(schema({ ontology: ONTOLOGY })) for (const d of ['documents', 'contacts', 'projects', 'uploads']) { expect(r.exposed).not.toContain(d) } }) it('does not read a declared file as a plugin-owned dir', () => { // Task 1902 — the plugin-owned region also carries file lines now. This is // the client-facing copy of the parser, kept separately from // platform/lib/account-schema-regions, so it needs its own case: a file must // never enter pluginOwned, and asking to expose one must not expose it. The // trailing slash inside the backticks is the discriminator. const withFile = [ '', '## Plugin-owned top-level entries', '', '- `sites/` — Owned by the cloudflare plugin.', '- `data-portal.json` — the account data-portal index.', '', ].join('\n') const r = resolveExposedDirs(schema({ ontology: ONTOLOGY, pluginOwned: withFile }), [ 'data-portal.json', ]) expect(r.pluginOwned).toEqual(['sites']) expect(r.exposed).not.toContain('data-portal.json') }) it('reports a plugin-owned collision and keeps the dir out of exposed', () => { const collide = ONTOLOGY.replace('`quotes/`', '`sites/`').replace('Quotation', 'Site') const r = resolveExposedDirs(schema({ ontology: collide, pluginOwned: PLUGIN_OWNED })) expect(r.collisions).toEqual(['sites']) expect(r.exposed).toEqual(['output']) }) it('fails closed on a missing schema', () => { const r = resolveExposedDirs(null) expect(r.schemaPresent).toBe(false) expect(r.exposed).toEqual([]) }) it('fails closed when the allowed block is absent', () => { const r = resolveExposedDirs('# no fence here') expect(r.exposed).toEqual([]) }) it('unions an operator-named folder into exposed', () => { const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['inbound-invoices']) expect(r.exposed).toEqual(['inbound-invoices', 'output', 'quotes']) }) it('exposes an extra folder that is absent from the allowed block', () => { // inbound-invoices is deliberately NOT in ALLOWED — extras bypass that intersection. const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['inbound-invoices']) expect(r.exposed).toContain('inbound-invoices') }) it('drops a system folder named as an extra', () => { const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['secrets']) expect(r.exposed).not.toContain('secrets') expect(r.exposed).toEqual(['output', 'quotes']) }) it('drops a traversal or dotted extra', () => { const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['jobs/../secrets', '.git', '..']) expect(r.exposed).toEqual(['output', 'quotes']) }) it('an empty extras list equals today', () => { const base = resolveExposedDirs(schema({ ontology: ONTOLOGY })) expect(resolveExposedDirs(schema({ ontology: ONTOLOGY }), []).exposed).toEqual(base.exposed) }) it('never applies extras when the schema is missing', () => { const r = resolveExposedDirs(null, ['inbound-invoices']) expect(r.exposed).toEqual([]) expect(r.schemaPresent).toBe(false) }) it('never applies extras when the allowed block is absent', () => { const r = resolveExposedDirs('# no fence here', ['inbound-invoices']) expect(r.exposed).toEqual([]) }) it('dedupes an extra that is already an ontology bucket', () => { const r = resolveExposedDirs(schema({ ontology: ONTOLOGY }), ['quotes']) expect(r.exposed).toEqual(['output', 'quotes']) }) })