openvibers/openvibe.network Commits
Sandbox apps may call Play: openvibe.play joins the default sandbox audiences and play.title.manage, play.result.write and play.player.read the sandbox allowance (Play keeps sandbox- titles apart: guests only, unlisted, at most 3) (#337)
Changes
@@@ -34,7 +34,7 @@ BOOTSTRAP_PROFILE=local-dev# Developer projects (docs/developer-projects.md)# Audiences that accept sandbox app tokens, comma-separated. Leave it UNSET for the code default# (openvibe.media,openvibe.events,openvibe.tools); set it to an empty value to accept none.--# DEV_SANDBOX_AUDIENCES=openvibe.media,openvibe.events,openvibe.tools++# DEV_SANDBOX_AUDIENCES=openvibe.media,openvibe.events,openvibe.tools,openvibe.services,openvibe.ai,openvibe.quest,openvibe.play# Public capabilities every project's SANDBOX apps may hold without staff, comma-separated. Leave it# UNSET for the code default (media.object.upload/read, events.app.publish/read/subscribe,# tools.job.create/read/cancel; ids the installed contracts do not define are skipped); empty = none.@@@ -45,7 +45,7 @@ A new project is `sandbox` only. Staff switch it to `sandbox+production`, which- The only grants that exist are capabilities in the openvibe-contracts catalog, at the version Network has installed.- **The grantability rule.** The contracts `visibility` enum is `public | partner | first-party | internal` (`partner` since the v0.83.0 release; Network pins v0.107.0). Only `active` capabilities with visibility `public` or `partner` may be granted to apps. Staff may put a `partner` capability in one project's allowance by hand, but it never comes from the default or the sandbox allowance. `first-party` and `internal` capabilities are never grantable: staff cannot add them to an allowance, members cannot request them, and token issuance filters them out again.- **The allowance** is the set of grantable capabilities one project's apps may hold. Only staff set it. `DEV_DEFAULT_ALLOWANCE` seeds new projects, with public capabilities only. It is empty by default, so staff decide each project's **production** apps.--- **The sandbox allowance** is added to the allowance for **sandbox apps only**, in every project, without a staff decision. It comes from `DEV_SANDBOX_ALLOWANCE`. When that is unset, the code default is `media.object.upload`, `media.object.read`, `media.object.list`, `media.object.delete`, `events.app.publish`, `events.app.read`, `events.app.subscribe`, `tools.job.create`, `tools.job.read` and `tools.job.cancel`. Only `public` + `active` capabilities of the installed openvibe-contracts catalog count. `partner`, `first-party`, `internal` and unknown ids are dropped. The three `events.app.*` ids are defined from openvibe-contracts v0.28.0 (Network pins v0.107.0); with an older release they would be left out. `media.object.list` and `media.object.delete` (Media's list and delete verbs, WS-G task 2) are left out the same way until the pinned release defines them; until then a sandbox app's upload and read grants cover them at Media. The project view and `GET /catalog` show it as `sandbox_allowance`. Production apps never use it.++- **The sandbox allowance** is added to the allowance for **sandbox apps only**, in every project, without a staff decision. It comes from `DEV_SANDBOX_ALLOWANCE`. When that is unset, the code default is `media.object.upload`, `media.object.read`, `media.object.list`, `media.object.delete`, `events.app.publish`, `events.app.read`, `events.app.subscribe`, `tools.job.create`, `tools.job.read`, `tools.job.cancel`, `tools.tool.read`, `tools.tool.run`, `services.release.manage`, `ai.app.run`, `quest.app_quest.manage`, `play.title.manage`, `play.result.write` and `play.player.read` (`server/developer/policy.js` holds the list). Only `public` + `active` capabilities of the installed openvibe-contracts catalog count. `partner`, `first-party`, `internal` and unknown ids are dropped. The three `events.app.*` ids are defined from openvibe-contracts v0.28.0 (Network pins v0.107.0); with an older release they would be left out. `media.object.list` and `media.object.delete` (Media's list and delete verbs, WS-G task 2) are left out the same way until the pinned release defines them; until then a sandbox app's upload and read grants cover them at Media. The project view and `GET /catalog` show it as `sandbox_allowance`. Production apps never use it.- **A grant never exceeds the allowance** (for a sandbox app: allowance ∪ sandbox allowance). It is checked in three places. Approval refuses with `403 grant.beyond_allowance`. Shrinking the allowance revokes approved grants, and denies requested ones, that fall outside it. A sandbox app's grant that is still inside the sandbox allowance is kept. Token issuance intersects approved grants with the current allowance and with the current grantability.- A developer's grant request waits in `requested`. When an owner or admin makes the request and the capability is inside the allowance, it is approved at once.- `GET /api/v1/projects/catalog` lists what could ever be granted.@@@ -83,7 +83,7 @@ No refresh tokens are issued to apps. A confidential app asks again with its secThe sandbox check works in two layers.--1. **Issuance.** A sandbox app gets a token only for an audience listed in `DEV_SANDBOX_AUDIENCES`. When that is unset, the code default is `openvibe.media`, `openvibe.events` and `openvibe.tools`. Set it to an empty value to turn sandbox tokens off. Any other audience gets `400 invalid_target`. `openvibe.network` is not in the default. This layer protects every receiver today, including ones whose openvibe-contracts `verifyServiceToken` does not know about `env` yet.++1. **Issuance.** A sandbox app gets a token only for an audience listed in `DEV_SANDBOX_AUDIENCES`. When that is unset, the code default is `openvibe.media`, `openvibe.events`, `openvibe.tools`, `openvibe.services`, `openvibe.ai`, `openvibe.quest` and `openvibe.play` (each of them opted in: it keeps sandbox traffic apart from real data). Set it to an empty value to turn sandbox tokens off. Any other audience gets `400 invalid_target`. `openvibe.network` is not in the default. This layer protects every receiver today, including ones whose openvibe-contracts `verifyServiceToken` does not know about `env` yet.2. **Receivers.** A receiver refuses `env: sandbox` with `401 token.sandbox_refused` unless it opted in. Network does this in its own capability guard (`server/identity/principals.js`) and accepts sandbox only if `openvibe.network` is in `DEV_SANDBOX_AUDIENCES`. `server/developer/policy.js` exports `environmentDecision(claims, { acceptSandbox })` for the check. openvibe-contracts (≥ 0.26.0) `verifyServiceToken` / `requireCapability` do the same with an `acceptSandbox` option that defaults to false.An audience opts in when it can keep sandbox traffic apart from real data: for example, test-flagged money in Billing (ADR-012 rule 9), or a sandbox tenant in Media. First-party service tokens carry no `env` and are treated as production. The three default audiences must accept sandbox tokens themselves. Issuance working does not mean they do. Media (sandbox tenants keyed by project id) and Events (env-marked app events) take that on in the same Wave 20 step. Tools must accept `env: sandbox` on `/api/v1/jobs`; until it does, a sandbox app's Tools token is refused with `401 token.sandbox_refused` there.@@@ -312,7 +312,7 @@ Until the relay is turned on in an environment, nobody else receives these event| Env var | Default | Meaning ||---|---|---|--| `DEV_SANDBOX_AUDIENCES` | unset: `openvibe.media,openvibe.events,openvibe.tools` | Audiences that accept sandbox tokens (comma list). Unset means the code default; an empty value means none. |++| `DEV_SANDBOX_AUDIENCES` | unset: `openvibe.media,openvibe.events,openvibe.tools,openvibe.services,openvibe.ai,openvibe.quest,openvibe.play` | Audiences that accept sandbox tokens (comma list). Unset means the code default; an empty value means none. || `DEV_SANDBOX_ALLOWANCE` | unset: `media.object.upload,media.object.read,media.object.list,media.object.delete,events.app.publish,events.app.read,events.app.subscribe,tools.job.create,tools.job.read,tools.job.cancel` | Public capabilities sandbox apps may hold without staff (comma list, filtered to public + active capabilities of the installed catalog). Unset means the code default; an empty value means none. || `OV_EVENTS_INTERNAL_URL` | unset (relay off) | OpenVibe.Events base URL for relaying developer-project events || `DEV_CREDENTIAL_OVERLAP_S` | 86400 | Default rotation overlap (0–604800) |@@@ -49,10 +49,10 @@ function grantableCatalog() {* Audiences that accept sandbox app tokens when DEV_SANDBOX_AUDIENCES is unset. Each of these keeps* sandbox traffic apart from real data: Media in a sandbox tenant, Events with env-marked events,* Tools with sandbox jobs, Codes with sandbox releases (an app managing its own, WS-N task 5), AI with-- * sandbox runs on free and local capacity only (ai.app.run, plan T6). openvibe.network is deliberately-- * not one of them.++ * sandbox runs on free and local capacity only (ai.app.run, plan T6), Play with sandbox- titles of guests only,++ * never listed or counted (OpenVibe.Play's store). openvibe.network is deliberately not one of them.*/--const DEFAULT_SANDBOX_AUDIENCES = Object.freeze(['openvibe.media', 'openvibe.events', 'openvibe.tools', 'openvibe.services', 'openvibe.ai', 'openvibe.quest']);++const DEFAULT_SANDBOX_AUDIENCES = Object.freeze(['openvibe.media', 'openvibe.events', 'openvibe.tools', 'openvibe.services', 'openvibe.ai', 'openvibe.quest', 'openvibe.play']);/*** Capabilities every project's SANDBOX apps may hold without a staff decision when@@@ -70,6 +70,8 @@ const DEFAULT_SANDBOX_ALLOWANCE = Object.freeze(['ai.app.run',// App quests (contracts 0.193.0): a sandbox app may define its quests; Quest counts production events only.'quest.app_quest.manage',++ // Game services: any developer tries Play on sandbox- titles of its own (guests only, unlisted, at most 3).++ 'play.title.manage', 'play.result.write', 'play.player.read',]);/** Public + grantable only (the rule for every allowance that is not set by staff by hand). */@@@ -67,11 +67,11 @@ async function withoutCatalog(hidden, fn) {(async () => {// ── Settings: defaults, env overrides, and the public-only rule ──let s = policy.settings({});-- assert.deepStrictEqual([...s.sandboxAudiences].sort(), ['openvibe.ai', 'openvibe.events', 'openvibe.media', 'openvibe.quest', 'openvibe.services', 'openvibe.tools']);++ assert.deepStrictEqual([...s.sandboxAudiences].sort(), ['openvibe.ai', 'openvibe.events', 'openvibe.media', 'openvibe.play', 'openvibe.quest', 'openvibe.services', 'openvibe.tools']);assert.ok(!s.sandboxAudiences.has('openvibe.network'), 'Network itself never defaults to accepting sandbox tokens');assert.deepStrictEqual(s.sandboxAllowance, ['ai.app.run', 'events.app.publish', 'events.app.read', 'events.app.subscribe',-- 'media.object.delete', 'media.object.list', 'media.object.read', 'media.object.upload', 'quest.app_quest.manage', 'services.release.manage', 'tools.job.cancel', 'tools.job.create', 'tools.job.read', 'tools.tool.read', 'tools.tool.run'],-- 'the default sandbox allowance (openvibe-contracts 0.59.0 defines media.object.list and .delete, 0.109.0 ai.app.run, 0.113.0 services.release.manage, 0.193.0 quest.app_quest.manage)');++ 'media.object.delete', 'media.object.list', 'media.object.read', 'media.object.upload', 'play.player.read', 'play.result.write', 'play.title.manage', 'quest.app_quest.manage', 'services.release.manage', 'tools.job.cancel', 'tools.job.create', 'tools.job.read', 'tools.tool.read', 'tools.tool.run'],++ 'the default sandbox allowance (openvibe-contracts 0.59.0 defines media.object.list and .delete, 0.109.0 ai.app.run, 0.113.0 services.release.manage, 0.193.0 quest.app_quest.manage; Play\'s sandbox- titles since 10-25)');assert.deepStrictEqual(policy.DEFAULT_SANDBOX_ALLOWANCE.filter(id => id.startsWith('events.')), ['events.app.publish', 'events.app.read', 'events.app.subscribe']);s = policy.settings({ developer: { sandboxAudiences: '', sandboxAllowance: '' } });assert.strictEqual(s.sandboxAudiences.size, 0, 'set-but-empty means none');
@@ -34,7 +34,7 @@ BOOTSTRAP_PROFILE=local-dev
@@ -34,7 +34,7 @@ BOOTSTRAP_PROFILE=local-dev
# Developer projects (docs/developer-projects.md)
# Developer projects (docs/developer-projects.md)
# Audiences that accept sandbox app tokens, comma-separated. Leave it UNSET for the code default
# Audiences that accept sandbox app tokens, comma-separated. Leave it UNSET for the code default
# (openvibe.media,openvibe.events,openvibe.tools); set it to an empty value to accept none.
# (openvibe.media,openvibe.events,openvibe.tools); set it to an empty value to accept none.
-# DEV_SANDBOX_AUDIENCES=openvibe.media,openvibe.events,openvibe.tools
+# DEV_SANDBOX_AUDIENCES=openvibe.media,openvibe.events,openvibe.tools,openvibe.services,openvibe.ai,openvibe.quest,openvibe.play
# Public capabilities every project's SANDBOX apps may hold without staff, comma-separated. Leave it
# Public capabilities every project's SANDBOX apps may hold without staff, comma-separated. Leave it
# UNSET for the code default (media.object.upload/read, events.app.publish/read/subscribe,
# UNSET for the code default (media.object.upload/read, events.app.publish/read/subscribe,
# tools.job.create/read/cancel; ids the installed contracts do not define are skipped); empty = none.
# tools.job.create/read/cancel; ids the installed contracts do not define are skipped); empty = none.
@@ -45,7 +45,7 @@ A new project is `sandbox` only. Staff switch it to `sandbox+production`, which
@@ -45,7 +45,7 @@ A new project is `sandbox` only. Staff switch it to `sandbox+production`, which
- The only grants that exist are capabilities in the openvibe-contracts catalog, at the version Network has installed.
- The only grants that exist are capabilities in the openvibe-contracts catalog, at the version Network has installed.
- **The grantability rule.** The contracts `visibility` enum is `public | partner | first-party | internal` (`partner` since the v0.83.0 release; Network pins v0.107.0). Only `active` capabilities with visibility `public` or `partner` may be granted to apps. Staff may put a `partner` capability in one project's allowance by hand, but it never comes from the default or the sandbox allowance. `first-party` and `internal` capabilities are never grantable: staff cannot add them to an allowance, members cannot request them, and token issuance filters them out again.
- **The grantability rule.** The contracts `visibility` enum is `public | partner | first-party | internal` (`partner` since the v0.83.0 release; Network pins v0.107.0). Only `active` capabilities with visibility `public` or `partner` may be granted to apps. Staff may put a `partner` capability in one project's allowance by hand, but it never comes from the default or the sandbox allowance. `first-party` and `internal` capabilities are never grantable: staff cannot add them to an allowance, members cannot request them, and token issuance filters them out again.
- **The allowance** is the set of grantable capabilities one project's apps may hold. Only staff set it. `DEV_DEFAULT_ALLOWANCE` seeds new projects, with public capabilities only. It is empty by default, so staff decide each project's **production** apps.
- **The allowance** is the set of grantable capabilities one project's apps may hold. Only staff set it. `DEV_DEFAULT_ALLOWANCE` seeds new projects, with public capabilities only. It is empty by default, so staff decide each project's **production** apps.
-- **The sandbox allowance** is added to the allowance for **sandbox apps only**, in every project, without a staff decision. It comes from `DEV_SANDBOX_ALLOWANCE`. When that is unset, the code default is `media.object.upload`, `media.object.read`, `media.object.list`, `media.object.delete`, `events.app.publish`, `events.app.read`, `events.app.subscribe`, `tools.job.create`, `tools.job.read` and `tools.job.cancel`. Only `public` + `active` capabilities of the installed openvibe-contracts catalog count. `partner`, `first-party`, `internal` and unknown ids are dropped. The three `events.app.*` ids are defined from openvibe-contracts v0.28.0 (Network pins v0.107.0); with an older release they would be left out. `media.object.list` and `media.object.delete` (Media's list and delete verbs, WS-G task 2) are left out the same way until the pinned release defines them; until then a sandbox app's upload and read grants cover them at Media. The project view and `GET /catalog` show it as `sandbox_allowance`. Production apps never use it.
+- **The sandbox allowance** is added to the allowance for **sandbox apps only**, in every project, without a staff decision. It comes from `DEV_SANDBOX_ALLOWANCE`. When that is unset, the code default is `media.object.upload`, `media.object.read`, `media.object.list`, `media.object.delete`, `events.app.publish`, `events.app.read`, `events.app.subscribe`, `tools.job.create`, `tools.job.read`, `tools.job.cancel`, `tools.tool.read`, `tools.tool.run`, `services.release.manage`, `ai.app.run`, `quest.app_quest.manage`, `play.title.manage`, `play.result.write` and `play.player.read` (`server/developer/policy.js` holds the list). Only `public` + `active` capabilities of the installed openvibe-contracts catalog count. `partner`, `first-party`, `internal` and unknown ids are dropped. The three `events.app.*` ids are defined from openvibe-contracts v0.28.0 (Network pins v0.107.0); with an older release they would be left out. `media.object.list` and `media.object.delete` (Media's list and delete verbs, WS-G task 2) are left out the same way until the pinned release defines them; until then a sandbox app's upload and read grants cover them at Media. The project view and `GET /catalog` show it as `sandbox_allowance`. Production apps never use it.
- **A grant never exceeds the allowance** (for a sandbox app: allowance ∪ sandbox allowance). It is checked in three places. Approval refuses with `403 grant.beyond_allowance`. Shrinking the allowance revokes approved grants, and denies requested ones, that fall outside it. A sandbox app's grant that is still inside the sandbox allowance is kept. Token issuance intersects approved grants with the current allowance and with the current grantability.
- **A grant never exceeds the allowance** (for a sandbox app: allowance ∪ sandbox allowance). It is checked in three places. Approval refuses with `403 grant.beyond_allowance`. Shrinking the allowance revokes approved grants, and denies requested ones, that fall outside it. A sandbox app's grant that is still inside the sandbox allowance is kept. Token issuance intersects approved grants with the current allowance and with the current grantability.
- A developer's grant request waits in `requested`. When an owner or admin makes the request and the capability is inside the allowance, it is approved at once.
- A developer's grant request waits in `requested`. When an owner or admin makes the request and the capability is inside the allowance, it is approved at once.
- `GET /api/v1/projects/catalog` lists what could ever be granted.
- `GET /api/v1/projects/catalog` lists what could ever be granted.
@@ -83,7 +83,7 @@ No refresh tokens are issued to apps. A confidential app asks again with its sec
@@ -83,7 +83,7 @@ No refresh tokens are issued to apps. A confidential app asks again with its sec
The sandbox check works in two layers.
The sandbox check works in two layers.
-1. **Issuance.** A sandbox app gets a token only for an audience listed in `DEV_SANDBOX_AUDIENCES`. When that is unset, the code default is `openvibe.media`, `openvibe.events` and `openvibe.tools`. Set it to an empty value to turn sandbox tokens off. Any other audience gets `400 invalid_target`. `openvibe.network` is not in the default. This layer protects every receiver today, including ones whose openvibe-contracts `verifyServiceToken` does not know about `env` yet.
+1. **Issuance.** A sandbox app gets a token only for an audience listed in `DEV_SANDBOX_AUDIENCES`. When that is unset, the code default is `openvibe.media`, `openvibe.events`, `openvibe.tools`, `openvibe.services`, `openvibe.ai`, `openvibe.quest` and `openvibe.play` (each of them opted in: it keeps sandbox traffic apart from real data). Set it to an empty value to turn sandbox tokens off. Any other audience gets `400 invalid_target`. `openvibe.network` is not in the default. This layer protects every receiver today, including ones whose openvibe-contracts `verifyServiceToken` does not know about `env` yet.
2. **Receivers.** A receiver refuses `env: sandbox` with `401 token.sandbox_refused` unless it opted in. Network does this in its own capability guard (`server/identity/principals.js`) and accepts sandbox only if `openvibe.network` is in `DEV_SANDBOX_AUDIENCES`. `server/developer/policy.js` exports `environmentDecision(claims, { acceptSandbox })` for the check. openvibe-contracts (≥ 0.26.0) `verifyServiceToken` / `requireCapability` do the same with an `acceptSandbox` option that defaults to false.
2. **Receivers.** A receiver refuses `env: sandbox` with `401 token.sandbox_refused` unless it opted in. Network does this in its own capability guard (`server/identity/principals.js`) and accepts sandbox only if `openvibe.network` is in `DEV_SANDBOX_AUDIENCES`. `server/developer/policy.js` exports `environmentDecision(claims, { acceptSandbox })` for the check. openvibe-contracts (≥ 0.26.0) `verifyServiceToken` / `requireCapability` do the same with an `acceptSandbox` option that defaults to false.
An audience opts in when it can keep sandbox traffic apart from real data: for example, test-flagged money in Billing (ADR-012 rule 9), or a sandbox tenant in Media. First-party service tokens carry no `env` and are treated as production. The three default audiences must accept sandbox tokens themselves. Issuance working does not mean they do. Media (sandbox tenants keyed by project id) and Events (env-marked app events) take that on in the same Wave 20 step. Tools must accept `env: sandbox` on `/api/v1/jobs`; until it does, a sandbox app's Tools token is refused with `401 token.sandbox_refused` there.
An audience opts in when it can keep sandbox traffic apart from real data: for example, test-flagged money in Billing (ADR-012 rule 9), or a sandbox tenant in Media. First-party service tokens carry no `env` and are treated as production. The three default audiences must accept sandbox tokens themselves. Issuance working does not mean they do. Media (sandbox tenants keyed by project id) and Events (env-marked app events) take that on in the same Wave 20 step. Tools must accept `env: sandbox` on `/api/v1/jobs`; until it does, a sandbox app's Tools token is refused with `401 token.sandbox_refused` there.
@@ -312,7 +312,7 @@ Until the relay is turned on in an environment, nobody else receives these event
@@ -312,7 +312,7 @@ Until the relay is turned on in an environment, nobody else receives these event
| Env var | Default | Meaning |
| Env var | Default | Meaning |
|---|---|---|
|---|---|---|
-| `DEV_SANDBOX_AUDIENCES` | unset: `openvibe.media,openvibe.events,openvibe.tools` | Audiences that accept sandbox tokens (comma list). Unset means the code default; an empty value means none. |
+| `DEV_SANDBOX_AUDIENCES` | unset: `openvibe.media,openvibe.events,openvibe.tools,openvibe.services,openvibe.ai,openvibe.quest,openvibe.play` | Audiences that accept sandbox tokens (comma list). Unset means the code default; an empty value means none. |
| `DEV_SANDBOX_ALLOWANCE` | unset: `media.object.upload,media.object.read,media.object.list,media.object.delete,events.app.publish,events.app.read,events.app.subscribe,tools.job.create,tools.job.read,tools.job.cancel` | Public capabilities sandbox apps may hold without staff (comma list, filtered to public + active capabilities of the installed catalog). Unset means the code default; an empty value means none. |
| `DEV_SANDBOX_ALLOWANCE` | unset: `media.object.upload,media.object.read,media.object.list,media.object.delete,events.app.publish,events.app.read,events.app.subscribe,tools.job.create,tools.job.read,tools.job.cancel` | Public capabilities sandbox apps may hold without staff (comma list, filtered to public + active capabilities of the installed catalog). Unset means the code default; an empty value means none. |
| `OV_EVENTS_INTERNAL_URL` | unset (relay off) | OpenVibe.Events base URL for relaying developer-project events |
| `OV_EVENTS_INTERNAL_URL` | unset (relay off) | OpenVibe.Events base URL for relaying developer-project events |
| `DEV_CREDENTIAL_OVERLAP_S` | 86400 | Default rotation overlap (0–604800) |
| `DEV_CREDENTIAL_OVERLAP_S` | 86400 | Default rotation overlap (0–604800) |
@@ -49,10 +49,10 @@ function grantableCatalog() {
@@ -49,10 +49,10 @@ function grantableCatalog() {
* Audiences that accept sandbox app tokens when DEV_SANDBOX_AUDIENCES is unset. Each of these keeps
* Audiences that accept sandbox app tokens when DEV_SANDBOX_AUDIENCES is unset. Each of these keeps
* sandbox traffic apart from real data: Media in a sandbox tenant, Events with env-marked events,
* sandbox traffic apart from real data: Media in a sandbox tenant, Events with env-marked events,
* Tools with sandbox jobs, Codes with sandbox releases (an app managing its own, WS-N task 5), AI with
* Tools with sandbox jobs, Codes with sandbox releases (an app managing its own, WS-N task 5), AI with
- * sandbox runs on free and local capacity only (ai.app.run, plan T6). openvibe.network is deliberately
- * not one of them.
+ * sandbox runs on free and local capacity only (ai.app.run, plan T6), Play with sandbox- titles of guests only,
+ * never listed or counted (OpenVibe.Play's store). openvibe.network is deliberately not one of them.
*/
*/
-const DEFAULT_SANDBOX_AUDIENCES = Object.freeze(['openvibe.media', 'openvibe.events', 'openvibe.tools', 'openvibe.services', 'openvibe.ai', 'openvibe.quest']);
+const DEFAULT_SANDBOX_AUDIENCES = Object.freeze(['openvibe.media', 'openvibe.events', 'openvibe.tools', 'openvibe.services', 'openvibe.ai', 'openvibe.quest', 'openvibe.play']);
/**
/**
* Capabilities every project's SANDBOX apps may hold without a staff decision when
* Capabilities every project's SANDBOX apps may hold without a staff decision when
@@ -70,6 +70,8 @@ const DEFAULT_SANDBOX_ALLOWANCE = Object.freeze([
@@ -70,6 +70,8 @@ const DEFAULT_SANDBOX_ALLOWANCE = Object.freeze([
'ai.app.run',
'ai.app.run',
// App quests (contracts 0.193.0): a sandbox app may define its quests; Quest counts production events only.
// App quests (contracts 0.193.0): a sandbox app may define its quests; Quest counts production events only.
'quest.app_quest.manage',
'quest.app_quest.manage',
+ // Game services: any developer tries Play on sandbox- titles of its own (guests only, unlisted, at most 3).
+ 'play.title.manage', 'play.result.write', 'play.player.read',
]);
]);
/** Public + grantable only (the rule for every allowance that is not set by staff by hand). */
/** Public + grantable only (the rule for every allowance that is not set by staff by hand). */
@@ -67,11 +67,11 @@ async function withoutCatalog(hidden, fn) {
@@ -67,11 +67,11 @@ async function withoutCatalog(hidden, fn) {
(async () => {
(async () => {
// ── Settings: defaults, env overrides, and the public-only rule ──
// ── Settings: defaults, env overrides, and the public-only rule ──
let s = policy.settings({});
let s = policy.settings({});
- assert.deepStrictEqual([...s.sandboxAudiences].sort(), ['openvibe.ai', 'openvibe.events', 'openvibe.media', 'openvibe.quest', 'openvibe.services', 'openvibe.tools']);
+ assert.deepStrictEqual([...s.sandboxAudiences].sort(), ['openvibe.ai', 'openvibe.events', 'openvibe.media', 'openvibe.play', 'openvibe.quest', 'openvibe.services', 'openvibe.tools']);
assert.ok(!s.sandboxAudiences.has('openvibe.network'), 'Network itself never defaults to accepting sandbox tokens');
assert.ok(!s.sandboxAudiences.has('openvibe.network'), 'Network itself never defaults to accepting sandbox tokens');
assert.deepStrictEqual(s.sandboxAllowance, ['ai.app.run', 'events.app.publish', 'events.app.read', 'events.app.subscribe',
assert.deepStrictEqual(s.sandboxAllowance, ['ai.app.run', 'events.app.publish', 'events.app.read', 'events.app.subscribe',
- 'media.object.delete', 'media.object.list', 'media.object.read', 'media.object.upload', 'quest.app_quest.manage', 'services.release.manage', 'tools.job.cancel', 'tools.job.create', 'tools.job.read', 'tools.tool.read', 'tools.tool.run'],
- 'the default sandbox allowance (openvibe-contracts 0.59.0 defines media.object.list and .delete, 0.109.0 ai.app.run, 0.113.0 services.release.manage, 0.193.0 quest.app_quest.manage)');
+ 'media.object.delete', 'media.object.list', 'media.object.read', 'media.object.upload', 'play.player.read', 'play.result.write', 'play.title.manage', 'quest.app_quest.manage', 'services.release.manage', 'tools.job.cancel', 'tools.job.create', 'tools.job.read', 'tools.tool.read', 'tools.tool.run'],
+ 'the default sandbox allowance (openvibe-contracts 0.59.0 defines media.object.list and .delete, 0.109.0 ai.app.run, 0.113.0 services.release.manage, 0.193.0 quest.app_quest.manage; Play\'s sandbox- titles since 10-25)');
assert.deepStrictEqual(policy.DEFAULT_SANDBOX_ALLOWANCE.filter(id => id.startsWith('events.')), ['events.app.publish', 'events.app.read', 'events.app.subscribe']);
assert.deepStrictEqual(policy.DEFAULT_SANDBOX_ALLOWANCE.filter(id => id.startsWith('events.')), ['events.app.publish', 'events.app.read', 'events.app.subscribe']);
s = policy.settings({ developer: { sandboxAudiences: '', sandboxAllowance: '' } });
s = policy.settings({ developer: { sandboxAudiences: '', sandboxAllowance: '' } });
assert.strictEqual(s.sandboxAudiences.size, 0, 'set-but-empty means none');
assert.strictEqual(s.sandboxAudiences.size, 0, 'set-but-empty means none');