openvibers/openvibe.network Commits

Agents: a grant on the host's own tenant never reaches the agents it hosts (#434)

OP OpenVibers committed 14 days ago · 9cf1103cb3 · 3 files, +7 −5

A service-hosted agent's token names only its project's namespaces that the
host's grant rows cover. Pin the case that matters for Media: a grant on the
host's own tenant (actor) gives the agent no namespace, so Media refuses it.
The principals comment said the opposite; it now says why Actor still holds
no Media grant (its artifacts are owner-only rows in its own database).

Changes

ddiff --git a/server/identity/principals.js b/server/identity/principals.js
iindex ca4389c3..15776652 100644
---- a/server/identity/principals.js
++++ b/server/identity/principals.js
@@@ -113,9 +113,9 @@ const DEFAULT_GRANTS = [
// own tokens on their own tenants, not with app keys. Upload also covers the delete of an object.
['inventory', 'media.object.upload', 'openvibe.media', ['inventory']],
// Codes (C8 proof screenshots, the rich embeds of a task) keeps a person's pictures in Media as private objects on
-- // its own tenant, reached with its own token (10-30). Actor is not granted Media yet: Actor hosts people's agents,
-- // and a hosted agent may hold what its host holds (agent-grants.test.js), so a Media grant on Actor would let every
-- // agent read Actor's tenant. Actor's artifacts wait for a host rule that keeps media.* out of what agents inherit.
++ // its own tenant, reached with its own token (10-30). A grant on a host's own tenant never reaches the agents it
++ // hosts: an agent's token names only its project's namespaces (agent-tokens.test.js), so it gets no `actor`.
++ // Actor holds no Media grant for now all the same: its artifacts are in its own database, owner-only (Actor V2-4).
...['media.object.upload', 'media.object.read'].map((cap) => ['codes', cap, 'openvibe.media', ['codes']]),
['media-hub', 'media.object.upload', 'openvibe.media', ['media-hub']],
['media-hub', 'media.object.read', 'openvibe.media', ['media-hub']],
ddiff --git a/test/agent-tokens.test.js b/test/agent-tokens.test.js
iindex 2e5fd1f7..d4a4233b 100644
---- a/test/agent-tokens.test.js
++++ b/test/agent-tokens.test.js
@@@ -197,6 +197,8 @@ const U = { owner: jwt.sign({ sub: 10, id: 10 }, keys.privateKey, { algorithm: '
assert.ok(validate('identity.service-token-claims@1', sc).valid);
assert.deepStrictEqual([sc.sub, sc.cap, sc.cap_confirm, sc.ns, sc.env, sc.act], [`agent:${S}`, ['media.object.read'], ['media.object.delete'], [P, `app.${P}.*`], 'production', { sub: 'svc:actor' }]);
assert.deepStrictEqual((await mint('actor', S, { scope: 'media.object.read' })).ns, [P], 'only what the read row names');
++ await db.prepare("UPDATE principal_grants SET namespaces = '[\"actor\"]' WHERE client_id = 'actor'").run();
++ assert.deepStrictEqual((await mint('actor', S)).ns, [], "the host's own tenant never reaches the agents it hosts");
await db.prepare("UPDATE principal_grants SET namespaces = '[]' WHERE client_id = 'actor'").run();
assert.deepStrictEqual((await mint('actor', S)).ns, [], 'rows that name no namespace give none');
await refusedGrant('actor', A, 'invalid_grant');
ddiff --git a/test/media-private-grants.test.js b/test/media-private-grants.test.js
iindex 03daf75d..32a19fe7 100644
---- a/test/media-private-grants.test.js
++++ b/test/media-private-grants.test.js
@@@ -1,8 +1,8 @@
/**
* OpenVibe.Codes keeps a person's pictures in Media as private objects (task screenshots, 10-30). Media takes no app
* keys (C-71), so Codes reaches it with its own Network service token: upload and read, on its own tenant only, and
-- * nothing else of Media's. Actor holds no Media grant: it hosts people's agents, and an agent may hold what its host
-- * holds, so a Media grant there would open Actor's whole tenant to every agent.
++ * nothing else of Media's. Actor holds no Media grant: its artifacts live in its own database, owner-only (Actor V2-4).
++ * Were it granted one, the agents it hosts would still not reach its tenant (agent-tokens.test.js).
*
* node test/media-private-grants.test.js
*/