openvibers/openvibe.bot Commits

OpenVibe.AI lists a person's machines whose models their AI may use, with its own capability (bot.machine.ai), for a node credential with machine any (contracts 0.221.0) (#192)

OP OpenVibers committed 17 days ago · 37a31c572f · 2 files, +9 −2

Changes

ddiff --git a/server/api/v1.js b/server/api/v1.js
iindex 2dd29e2..d36ba07 100644
---- a/server/api/v1.js
++++ b/server/api/v1.js
@@@ -449,8 +449,11 @@ function v1Router({ domain, apiAuth, limits, hub, jobs: jobService, config, subm
const subject = actedFor(req, req.query.owner);
const svc = req.principal.kind === 'service' ? MACHINE_SERVICES[req.principal.sub] : null;
if (req.principal.kind === 'service') {
-- if (!svc) fail(403, 'bot.forbidden', 'machines are listed for their owner, their agent and their watches');
-- if (!apiAuth.granted(req.principal, CAP.computer)) fail(403, 'capability.denied', `${CAP.computer} not granted`);
++ if (!svc) fail(403, 'bot.forbidden', 'machines are listed for their owner, their agent, their watches and their AI');
++ // Each service with its own capability: OpenVibe.AI lists those whose models the owner's AI may use
++ // (a node credential with machine `any`, contracts 0.221.0).
++ const cap = svc.cap || CAP.computer;
++ if (!apiAuth.granted(req.principal, cap)) fail(403, 'capability.denied', `${cap} not granted`);
}
const rows = await domain.machines.list(subject);
const mine = svc ? rows.filter((d) => d[svc.flag]) : rows;
ddiff --git a/test/machine-computer.test.js b/test/machine-computer.test.js
iindex c54ea0e..3145ab5 100644
---- a/test/machine-computer.test.js
++++ b/test/machine-computer.test.js
@@@ -411,9 +411,13 @@ const { boot, check, done } = require('./helpers/app');
const asAi = (subject) => ({ token: ai, headers: { 'X-OV-Subject': subject } });
const before = await cmd(gpu.deviceId, ask, asAi(alex.subject));
assert.deepStrictEqual([before.status, before.json.code], [403, 'bot.agent_not_allowed'], 'off until the owner turns it on');
++ const listAi = async () => (await t.call('GET', '/api/v1/machines', asAi(alex.subject))).json.machines.map((m) => m.id);
++ assert.ok(!(await listAi()).includes(gpu.deviceId), 'OpenVibe.AI lists only machines whose models it may use');
const on = await t.call('POST', `/api/v1/machines/${gpu.deviceId}/ai-models`, { user: alex, body: { on: true } });
assert.strictEqual(on.json.machine.ai_models, true);
assert.deepStrictEqual(on.json.machine.computer.ai.models, ['llama3.1:8b']);
++ assert.deepStrictEqual(await listAi(), [gpu.deviceId], 'once on, it is listed to OpenVibe.AI (a node credential with machine any)');
++ assert.strictEqual((await t.call('GET', '/api/v1/machines', { token: t.network.signService({ sub: 'svc:ai', cap: ['bot.computer.control'] }), headers: { 'X-OV-Subject': alex.subject } })).status, 403, 'with its own capability only');
const viaAi = await cmd(gpu.deviceId, ask, asAi(alex.subject));
assert.strictEqual(viaAi.json.result, 'ack', viaAi.text);
// Nobody else: another person through OpenVibe.AI, a service without the capability, another service, another kind.