// Row 285 (#1790), mos-1585/1586: only creative-to-creative changes may retain // the same declared service set. No reference is created, moved or minted by a change. import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { instanceSettings } from '../src/instance-settings.mjs'; import { businessDoc, rolesCopy, systemFor, tmp, writeJson } from './helpers.mjs'; function fixture(t) { const root = tmp(); t.after(() => rmSync(root, { recursive: true, force: true })); const rolesDir = rolesCopy(root), dir = join(root, 'config'); const companion = JSON.parse(readFileSync(join(rolesDir, 'companion.json'), 'utf8')); for (const [name, authority, credentials] of [ ['creative-host', companion.authority, [...companion.credentials, { service: 'host' }]], ['plain-gitea', { withinRole: ['message.send'], crossRole: [] }, companion.credentials], ['creative-vikunja', companion.authority, [{ service: 'vikunja', scopes: { tasks: ['read_one'] } }]], ]) writeJson(join(rolesDir, `${name}.json`), { ...companion, name, authority, credentials }); const doc = businessDoc(root); doc.roles.bean = { definition: 'companion', credentials: { gitea: { ...doc.roles.coder.credentials.gitea } } }; const file = writeJson(join(dir, 'businesses/acme.json'), doc); const settings = instanceSettings({ dir, rolesDir, system: systemFor(root) }); const change = definition => settings.set('acme', { revision: settings.read('acme').revision, instance: 'bean', op: 'change', definition }, 'jason'); return { doc, file, settings, change }; } // Keeping the old blanket credential fence breaks this supported change. test('row 285 P: creative equal-service changes preserve every existing credential reference', t => { const f = fixture(t), before = JSON.parse(readFileSync(f.file, 'utf8')).roles.bean.credentials; f.change('ideas'); const after = JSON.parse(readFileSync(f.file, 'utf8')).roles.bean; assert.equal(after.definition, 'ideas'); assert.deepEqual(after.credentials, before); assert.deepEqual(Object.keys(after.credentials), ['gitea']); assert.equal(after.credentials.gitea.store, undefined); }); // Host has no file reference, so ordinary business validation alone cannot guard this set change. test('row 285 P: creative declared-service mismatch refuses even when host has no reference', t => { const f = fixture(t), before = readFileSync(f.file); assert.throws(() => f.change('creative-host'), e => e.code === 'organization-credentials-out-of-scope'); assert.deepEqual(readFileSync(f.file), before); }); // Letting equal sets bypass the non-creative base fence breaks this refusal. test('row 285 P: an equal-service non-creative target keeps the base credential refusal', t => { const f = fixture(t), before = readFileSync(f.file); assert.throws(() => f.change('plain-gitea'), e => e.code === 'organization-credentials-out-of-scope'); assert.deepEqual(readFileSync(f.file), before); }); // Running the credential fence ahead of validation changes the base BusinessError. test('row 285 P: business validation precedes the creative credential fence', t => { const f = fixture(t), before = readFileSync(f.file); assert.throws(() => f.change('security-reviewer'), e => e.name === 'BusinessError'); assert.deepEqual(readFileSync(f.file), before); }); // Removing creative addability, or admitting host/Vikunja there, breaks these literal entries. test('row 285 P: listing derives creative from authority and accepts only existing gitea minting', t => { const f = fixture(t), definitions = f.settings.read('acme').definitions; assert.deepEqual(definitions.companion, { services: ['gitea'], accepted: true }); assert.deepEqual(definitions.ideas, { services: ['gitea'], accepted: true }); assert.deepEqual(definitions['creative-host'], { services: ['gitea', 'host'], accepted: false }); assert.deepEqual(definitions['creative-vikunja'], { services: ['vikunja'], accepted: false }); assert.deepEqual(definitions['plain-gitea'], { services: ['gitea'], accepted: false }); assert.deepEqual(definitions.coder, { services: ['gitea', 'vikunja'], accepted: false }); assert.equal(definitions['chief-of-staff'].accepted, false); });