/** * The host row: the deployment's policy and its lifetime. * * Short, but it is the half that is easiest to leave untested — it has no * interesting logic and one interesting obligation, which is that a grant must * not outlive the session that asked for it. */ import assert from 'node:assert/strict' import { test } from 'node:test' import { apply, Config } from '../index.js' import { configValue } from '../lib/policy.js' /** * The symbol cosmokit marks a volatile config reference with, and the writer it * carries. A settings write reaches a running plugin through exactly this * function — `updateVolatile(target, source)` is `target[write](source.get())` — * so a test can commit an edit the same way the framework does. */ const VOLATILE_WRITE = Symbol.for('cosmokit.volatile.write') /** Whether a field arrived as a live reference rather than a plain value. */ const isReference = (value) => typeof value === 'object' && value !== null && VOLATILE_WRITE in value /** The smallest context this row touches. */ function harness() { const captured = { provided: undefined, onDisposed: undefined } const ctx = { provide: (name, value) => { captured.provided = { name, value } }, on: (event, listener) => { if (event === 'session/disposed') captured.onDisposed = listener }, } apply(ctx, Config({ mode: 'ask' })) return captured } test('the schema fills every default, so a bare row is a working row', () => { const config = Config({}) assert.equal(configValue(config.mode), 'ask') assert.deepEqual(configValue(config.extraRoots), []) assert.equal(config.sectionOrder, 100) assert.equal(config.contextOrder, 105) }) test('the editable fields are volatile, which is the only reason they have a settings card', () => { const config = Config({}) // The framework's form projection keeps only fields under a volatile ancestor // and drops an entry with no such field from `settings.describe` entirely, so // dropping either of these markers silently removes the card from the UI. assert.equal(isReference(config.mode), true) assert.equal(isReference(config.extraRoots), true) // Placement is settled once at load: not settings anyone edits live, and not // on the card. assert.equal(isReference(config.sectionOrder), false) assert.equal(isReference(config.contextOrder), false) }) test('a settings edit is answered on the next call, without the plugin being re-applied', () => { const provided = [] let applies = 0 const config = Config({ mode: 'ask', extraRoots: ['/w/src/shared'] }) apply( { provide: (name, value) => { applies += 1 provided.push({ name, value }) }, on: () => {}, }, config, ) const policy = provided[0].value assert.equal(policy.mode, 'ask') assert.deepEqual(policy.standing, ['/w/src/shared']) // What the framework does on a settings write: it commits into the running // references and deliberately does NOT re-apply the plugin. Everything the // policy reports has to follow from the reference alone. config.mode[VOLATILE_WRITE]('deny') config.extraRoots[VOLATILE_WRITE](['/w/src/shared', '/w/src/types']) assert.equal(applies, 1) assert.equal(policy.mode, 'deny') assert.deepEqual(policy.standing, ['/w/src/shared', '/w/src/types']) assert.deepEqual( policy.scopeFor({ session: { id: 's1', header: { cwd: '/w/src/room' } } }).extras, ['/w/src/shared', '/w/src/types'], ) }) test('a bad mode fails loudly at load rather than at the first file call', () => { assert.throws(() => Config({ mode: 'maybe' })) }) test('the policy is published under the name the guard injects', () => { const captured = harness() assert.equal(captured.provided.name, 'facetPolicy') assert.equal(captured.provided.value.mode, 'ask') }) test('the service reads the configuration it was given', () => { const provided = [] apply( { provide: (name, value) => provided.push({ name, value }), on: () => {} }, Config({ mode: 'deny', extraRoots: ['../../shared'], sectionOrder: 7, contextOrder: 8 }), ) const policy = provided[0].value assert.equal(policy.mode, 'deny') assert.deepEqual(policy.standing, ['../../shared']) assert.equal(policy.sectionOrder, 7) assert.equal(policy.contextOrder, 8) }) test('a disposed session does not leave its grant behind', () => { const captured = harness() const policy = captured.provided.value policy.grant('session-1', ['../../shared'], '/w/src/room') assert.deepEqual(policy.grantsFor('session-1'), ['/w/shared']) assert.equal(typeof captured.onDisposed, 'function') captured.onDisposed({ id: 'session-1' }) assert.deepEqual(policy.grantsFor('session-1'), []) assert.deepEqual(policy.sessions, []) })