openvibers/openvibe.network Commits
Grants: Tours' place photos (Media) and cited summaries (AI) (#690)
Changes
@@@ -776,6 +776,10 @@ const DEFAULT_GRANTS = [['tours', 'events.subscription.manage', 'openvibe.events', []],// Tours publishes its places, cities and walks to OpenVibe.Search as tours.index_document.* (contracts 0.274.0).['tours', 'events.event.publish', 'openvibe.events', []],++ // Tours copies licensed Commons/Openverse thumbnails into its own Media tenant (no hotlinking), and asks OpenVibe.AI++ // for a cited place summary (Tours #106, 2026-11-08). New rows: no RESTORED_GRANTS or CHANGED_DEFAULT_NAMESPACES entry.++ ['tours', 'media.object.upload', 'openvibe.media', ['tours']],++ ...['ai.run.create', 'ai.run.read'].map((cap) => ['tours', cap, 'openvibe.ai', ['ai.summarize']]),['shoes', 'events.subscription.manage', 'openvibe.events', []],// Shoes publishes its model pages to OpenVibe.Search as shoes.index_document.* (contracts 0.273.0, through its own// outbox and openvibe-publishing/search-feed).nnew file mode 100644@@@ -0,0 +1,22 @@++/**++ * OpenVibe.Tours' grants for its place guides (Tours #106): it uploads licensed place photos into its own Media++ * tenant only, and runs OpenVibe.AI's ai.summarize workflow only. Each is a capability the pinned contracts offer,++ * active.++ *++ * node test/tours-grants.test.js++ */++'use strict';++const assert = require('assert');++const contracts = require('openvibe-contracts');++const principals = require('../server/identity/principals');++++const tours = principals.DEFAULT_GRANTS.filter((g) => g[0] === 'tours');++const media = tours.filter((g) => g[2] === 'openvibe.media');++assert.deepStrictEqual(media.map((g) => [g[1], g[3]]), [['media.object.upload', ['tours']]], 'Tours uploads into its own tenant, nothing else of Media');++const ai = tours.filter((g) => g[2] === 'openvibe.ai');++assert.deepStrictEqual(ai.map((g) => [g[1], g[3]]).sort(), [['ai.run.create', ['ai.summarize']], ['ai.run.read', ['ai.summarize']]], 'Tours runs and reads only ai.summarize');++for (const g of [...media, ...ai]) {++ const cap = contracts.capabilities.get(g[1]);++ assert.ok(cap && cap.status === 'active', `${g[1]} is an active capability`);++}++console.log('Tours grants: its own Media tenant and ai.summarize only');
@@ -776,6 +776,10 @@ const DEFAULT_GRANTS = [
@@ -776,6 +776,10 @@ const DEFAULT_GRANTS = [
['tours', 'events.subscription.manage', 'openvibe.events', []],
['tours', 'events.subscription.manage', 'openvibe.events', []],
// Tours publishes its places, cities and walks to OpenVibe.Search as tours.index_document.* (contracts 0.274.0).
// Tours publishes its places, cities and walks to OpenVibe.Search as tours.index_document.* (contracts 0.274.0).
['tours', 'events.event.publish', 'openvibe.events', []],
['tours', 'events.event.publish', 'openvibe.events', []],
+ // Tours copies licensed Commons/Openverse thumbnails into its own Media tenant (no hotlinking), and asks OpenVibe.AI
+ // for a cited place summary (Tours #106, 2026-11-08). New rows: no RESTORED_GRANTS or CHANGED_DEFAULT_NAMESPACES entry.
+ ['tours', 'media.object.upload', 'openvibe.media', ['tours']],
+ ...['ai.run.create', 'ai.run.read'].map((cap) => ['tours', cap, 'openvibe.ai', ['ai.summarize']]),
['shoes', 'events.subscription.manage', 'openvibe.events', []],
['shoes', 'events.subscription.manage', 'openvibe.events', []],
// Shoes publishes its model pages to OpenVibe.Search as shoes.index_document.* (contracts 0.273.0, through its own
// Shoes publishes its model pages to OpenVibe.Search as shoes.index_document.* (contracts 0.273.0, through its own
// outbox and openvibe-publishing/search-feed).
// outbox and openvibe-publishing/search-feed).
new file mode 100644
new file mode 100644
@@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
+/**
+ * OpenVibe.Tours' grants for its place guides (Tours #106): it uploads licensed place photos into its own Media
+ * tenant only, and runs OpenVibe.AI's ai.summarize workflow only. Each is a capability the pinned contracts offer,
+ * active.
+ *
+ * node test/tours-grants.test.js
+ */
+'use strict';
+const assert = require('assert');
+const contracts = require('openvibe-contracts');
+const principals = require('../server/identity/principals');
+
+const tours = principals.DEFAULT_GRANTS.filter((g) => g[0] === 'tours');
+const media = tours.filter((g) => g[2] === 'openvibe.media');
+assert.deepStrictEqual(media.map((g) => [g[1], g[3]]), [['media.object.upload', ['tours']]], 'Tours uploads into its own tenant, nothing else of Media');
+const ai = tours.filter((g) => g[2] === 'openvibe.ai');
+assert.deepStrictEqual(ai.map((g) => [g[1], g[3]]).sort(), [['ai.run.create', ['ai.summarize']], ['ai.run.read', ['ai.summarize']]], 'Tours runs and reads only ai.summarize');
+for (const g of [...media, ...ai]) {
+ const cap = contracts.capabilities.get(g[1]);
+ assert.ok(cap && cap.status === 'active', `${g[1]} is an active capability`);
+}
+console.log('Tours grants: its own Media tenant and ai.summarize only');