Commits
-
SECURITY.md: how to report a vulnerability ([email protected], 7-day reply, scope, supported versions)OpenVibers · 24 Sept 2026
26c0395d -
openvibe-contracts v0.34.1 (Tools platform S7): sandbox apps hold tools.tool.read and tools.tool.run by default (the run API is live); the self-service catalog lists public capabilities only (partner ones like tools.net.probe are staff-granted); the publishing library joins the registry's libraries; realtime is retired (ADR-005) in the registry testsOpenVibers · 24 Sept 2026
1664d042 -
Follow notification links to the follower's channel (openvibe.live/@<username>); it linked to openvibe.network/user/<name>, a page Network never had (a 404 since unknown paths stopped answering the account page)OpenVibers · 24 Sept 2026
43dd0c53 -
Admin settings: the 'prefer the environment variable' hint shows only for provider secrets, not for the VAPID public key (read environment-first too, but not a secret); the settings row says secret: true|falseOpenVibers · 24 Sept 2026
d063df17 -
Registry (roadmap W2 D4, §5.1, §5.3): /api/v1/registry/categories and /featured answered 404. categories[/:id] groups every service by what it is, each with its rule, from Network's exposure overlay and site list: site, platform, library, repository, planned. featured lists the open sites whose last check (not stale) was up or degraded, in the navigation's usage order (7-day page views plus 14-day signed-in history, the chrome service's ranking, now exposed as ranking()), with ranked_at and stale; the hub is not listed and nothing is picked by hand. Hand-kept maps: site hosts now come from each manifest's publicOrigin (only chat, whose manifest has none, names its host; the derived list is identical); READY_PATHS drops tools, whose manifest carries ready, and a test keeps only entries whose manifest lacks one; INTERNAL takes OV_<ID>_INTERNAL_URL overrides (loopback URLs only, others ignored and logged). What cannot come from the manifests yet has a TODO with its plan section: INTERNAL (no internal address in service-manifest@1), EXPOSURE (the override half: what a domain serves today), the sites' presentation fields. Tests: registry-ecosystem (categories, featured, READY_PATHS, env overrides, hosts), chrome (ranking), unknown-paths (both routes answer on the real server)OpenVibers · 24 Sept 2026
9e64f600 -
openvibe-contracts v0.33.1: tools.tool.read is active (Tools serves GET /api/v1/tools on the gateway and every satellite), so the registry and /status show it as such; tools.tool@1 1.1.0 adds optional keywords and examples. Additive; pins only (npm install on the host rewrites package-lock.json with npm 9: git checkout -- package-lock.json after)OpenVibers · 24 Sept 2026
9a59212a -
Principals: openre, media and community hold live.lineage.resolve for audience openvibe.live (roadmap §10.5/§15.10, D20-R1), so OpenRe, Media and Community's Pulse can ask Live's canonical channel/owner resolver (GET|POST /internal/lineage/resolve, token only) instead of keeping their own channel mappings; production had no grant for it. Seeded at boot like every default grant. test/principals.test.js: each of the three gets a token for openvibe.live carrying it, and nobody else holds itOpenVibers · 24 Sept 2026
80a841cd -
Internal-key retirement (register C-50/C-52): GET /internal/url-registry/resolved, GET /internal/coins/stats, POST /internal/resolve-anon, POST /internal/identity/legacy-map and POST /internal/link-account (the routes principal_usage still shows called with X-Internal-Key) now also take a service token through principals.guard, and keep the key so callers switch on their own schedule. Capabilities are existing contracts names: identity.subject.resolve for the registry read, anon resolution, legacy-map writes and account links, network.coins.credit for the coin totals. A token may only map ids of its own source_system and only report links for its own service (capability.owner_denied); the key keeps its old behaviour. resolve-batch was already guarded. No grant was added: the only caller of the five is Live, which already holds both capabilities on openvibe.network (Media's resolve-batch grant landed in c3b7cf3; Chat calls none of them, Tools none). docs/retirement.md lists every token route with its capability, rule and holders, and what Live changes (TOKEN_PATHS in server/net/network-principal.js). test/principals.test.js: token, narrow token, ownership, key and usage rows for eachOpenVibers · 24 Sept 2026
829dafa5 -
secrets-out-of-db.js --copy-to-env [--apply]: moves each provider secret the database holds and the env file does not set (an empty VAR= counts as unset) into /etc/openvibe/network.env as VAR=value, after keeping the previous file as network.env.bak-<time> with its mode, so the operator never has to read a value out of sqlite. The database is read by a child process running as its owner and the values reach the file through a pipe, never a terminal; a value that would need quoting is left to add by hand, and a variable the file already sets is left as it is (the dry run says whether it matches). README: the full procedureOpenVibers · 24 Sept 2026
11e716d0 -
Provider secrets from the environment first (roadmap §18.2(12)): the Resend API key and webhook secret, the Discord bot token and OAuth client secret, and the VAPID private key were read only from site_settings in plaintext. Each now has a variable (RESEND_API_KEY, RESEND_WEBHOOK_SECRET, DISCORD_BOT_TOKEN, DISCORD_OAUTH_CLIENT_SECRET, VAPID_PRIVATE_KEY; server/secrets.js) that db.getSetting reads first, so every reader is environment-first; the database row stays the fallback, so nothing changes until the operator moves a value. Which source each uses is reported by name only: the boot line [Secrets] key=env|database|unset, GET /api/admin/secrets (owner), api_key_source in the email status and sources in the Discord settings. The admin panel shows an environment-provided secret as set in the environment (input disabled), and the email, settings and Discord endpoints never save one into the database while its variable is set. Web push derives the VAPID public key from the private key, so a private key in the environment (or a stale public key beside it) still gives a matching pair and no new pair is generated over it. scripts/secrets-out-of-db.js lists the secret setting names with their variable, whether the env file sets it to the same value and whether the running service has it (never a value); --apply --backup <new file> blanks only the copies the environment and the restarted service already provide (a different value only with --allow-different) plus the settings Network never reads (net.* tokens, old ses_* keys); --restore-from <backup> [--apply] rolls back. Run with sudo, it reads the env file and /proc/<pid>/environ, then becomes the database owner. test/provider-secrets.test.jsOpenVibers · 24 Sept 2026
70050bca -
Refresh tokens (roadmap §18.2(2)): oauth_tokens held each refresh token in clear, and presenting a rotated token again only failed. Now only its SHA-256 is stored; every token belongs to the family of the sign-in that issued it (family_id) and carries a generation (0 at sign-in, +1 per rotation); presenting an already rotated token revokes every live token of its family (revoked_reason reuse) and writes an oauth_refresh_reuse audit row with the presented and current generation, never a token. A second use within 10 seconds of the rotation is refused without revoking the family (two tabs refreshing through Live's cookie at once). Boot adds the columns only. Rows written before keep working: a raw row is matched and hashed on first use, and a stored hash presented as a token matches nothing. scripts/hash-refresh-tokens.js hashes the rest in place, one-way: dry run by default, --apply requires --backup <new file> (online, 0600, quick_check), --restore-from <backup> [--apply] puts the raw values back for a rollback to the previous release; run as root it becomes the database owner first (scripts/lib/db-ops.js). server/auth/refresh-tokens.js; test/refresh-tokens.test.jsOpenVibers · 24 Sept 2026
1cf0191c -
OpenID Connect discovery at the issuer (roadmap §4.1, §15.4): https://openvibe.network/.well-known/openid-configuration answered with the account page; discovery lived only at /oauth/.well-known/openid-configuration. The document is now served at the issuer's root, at RFC 8414's /.well-known/oauth-authorization-server and still at the old path, and /.well-known/openvibe points at the standard one. The metadata is made true rather than aspirational: it advertised scope openid and RS256 id tokens while none was ever issued, and named /api/auth/me (not OIDC-shaped) as userinfo. Scope openid now adds an RS256 id_token to the code grant (kid ov-network-1 as the JWKS publishes, aud = client, sub = the Network id as a string like access tokens, subject_id, and the authorize nonce, threaded through the account chooser and stored with the code in oauth_codes.nonce); /oauth/userinfo returns the same claims for an unexpired access token. Without openid the token response is unchanged. server/auth/oidc.js; test/oidc-discovery.test.js boots the real server for the documents and runs the code flow for id_token and userinfoOpenVibers · 24 Sept 2026
abee5dc1 -
Unknown paths answer 404 (roadmap §2.5, D44): the apex sent the account hub (my.html) with 200 for any path, so openvibe.network/<anything> looked like a page. Every real page keeps its own route; the account hub answers only at its own sections (server/not-found.js ACCOUNT_HUB_PATHS) and /admin/* stays the admin SPA. Anything else, any method, gets a 404: JSON under /api, /internal and /oauth, otherwise a small noindex page with links home, to the account, sign-in and status. test/unknown-paths.test.js boots the real server (test/helpers/boot-server.js: scratch database, loopback, ephemeral keys, no egress) and checks both sidesOpenVibers · 24 Sept 2026
f87b5149 -
Principals: media holds identity.subject.resolve (openvibe.network), so Media can record each object's owner as a canonical subject. Its owner_subject backfill and reconcile job resolve the Live user ids Media is given (X-OV-User-Id) through POST /internal/identity/resolve-batch with a service token instead of the shared X-Internal-Key. The principals test now uses openre as the client with no Network grants, and checks Media's token resolves Live ids (an unknown id answers null) and moves no coinsOpenVibers · 23 Sept 2026
c3b7cf38 -
Chrome page-view beacon: POST /api/chrome/hit answers Cross-Origin-Resource-Policy: cross-origin. navigator.sendBeacon is a no-cors request, and helmet's same-origin policy made every page of every site log the (empty) answer as blocked; counting was never affectedOpenVibers · 23 Sept 2026
34e76789 -
openvibe-shared v1.5.1, openvibe-contracts v0.33.0OpenVibers · 23 Sept 2026
f76130d5 -
Registry: the libraries' current release (sdk, shared, contracts) is the version Network installs, read from each package.json, instead of hand-written numbers that were three releases stale (v0.4.0 / v1.3.0 / v0.30.1). /status labels and /api/v1/registry/releases drift follow the pins; the tests compare against the installed versionsOpenVibers · 23 Sept 2026
7991a590 -
CORS: a refused origin gets a 403 JSON answer (code cors.origin_denied) instead of Express's default 500 with a stack trace on every request, and is logged once an hour per origin (a local test page on a random 127.0.0.1 port produced ~800 stack traces an hour). Still refused server-side, so a cross-site form post never runs the route. public-cors.js originGuard() is the one implementation index.js and the test useOpenVibers · 23 Sept 2026
ca59964c -
openvibe-shared v1.5.0 (Track R release manifest), openvibe-contracts v0.32.0, openvibe-sdk v0.5.0OpenVibers · 23 Sept 2026
0b756833 -
Roadmap baseline: D20 canonical resolver is partial, no longer not met (lineage contract in openvibe-contracts v0.32.0, resolver deployed in Live 2026-09-23 21:36 UTC, display-name test, production 401 check); remaining: consumers' grants, OpenRe session lineage, Media owner_subject backfill. Ledger: 3 met, 36 partial, 0 not met, 7 blocked on owner; all 46 verified (EC6 passes; EC7 waits on the owner's hazard review). Regenerated from origin/mainOpenVibers · 23 Sept 2026
e99a80fa -
Chat may manage its own OpenVibe.Events subscriptions: default grant chat events.subscription.manage on openvibe.events (seeded at boot like the others). Chat subscribes to live.release.deployed (the deploy card; register C-84, so the Live bridge's deployNotice can go after one clean deploy) and network.module.updated (its chat.preferences cache drops a changed record at once instead of within 60 s). Events checks only this capability for a service subscription; it has no per-topic read grants. test/module-events.test.js: the chat client gets a token for audience openvibe.events with that scopeOpenVibers · 23 Sept 2026
09bf748b -
Go-live links open the channel: notifications (Live's direct call and the live.stream.started consumer) and the Discord go-live post linked to https://openvibe.live/<username>, which is not a page on Live (it showed the home page). stream-live.js channelUrl() builds /@<username>, and canonicalChannelUrl() rewrites an old-style link an event still carries; other Live links pass throughOpenVibers · 23 Sept 2026
951e7b1c -
User modules (roadmap Wave 1 item 24): every change emits network.module.updated, account removal and merge handle module rows, onOwnerRemoved is enforced, and chat.preferences belongs to Chat. Events: server/identity/module-events.js builds the envelope (source network, visibility internal, subject { type user_module, id <owner>:<namespace>, revision }, actor = the person, the owning service or system:network) and writes it into network_event_outbox in the transaction that makes the change; payload owner, namespace, namespace_owner, schema_version, revision, change (created|updated|deleted), reason (write|delete|owner_delete|subject_removed|subject_merged), keys (changed top-level field names), public (new values of changed public fields only; never a value of a private namespace), merged_into/merged_from. event-relay.js writerFor() enqueues into the running relay's outbox or, when this process relays nothing (OV_EVENTS_INTERNAL_URL unset, or a script), a passive one on the same table, so rows wait there and the relay sends them; the table is created at boot. Revisions only grow per (subject, namespace): user_module_revisions keeps the last one issued, so a delete has a revision and a re-created record continues after it. Owner services get DELETE /internal/modules/:ns/:subject (token only, If-Match optional). Accounts: onSubjectRemoved() deletes a subject's records and revisions with one event each; onSubjectMerged() moves each record to the survivor where it has none and drops it where it has one (updated_by svc:network), events on both sides. Network has no account deletion or merge today, so triggers refuse deleting a users/anon_users row or changing its subject_id while module rows remain; the one merge that exists, POST /api/auth/anon/:token/link, now moves the guest's records to the account. onOwnerRemoved (contract modules.namespace@1): when the owner's service manifest says retired the namespace is read-only (409 modules.namespace_retired, userWritable false), and a daily sweepRetired() empties delete-after-retention namespaces retentionDays after Network first saw the retirement (user_module_retirements). chat.preferences: OWNER_HANDOFFS makes Chat its owner while the installed manifest (0.30.x) still names live ("moves to OpenVibe.Chat in Wave 6"); Chat gets network.modules.read/write on chat.preferences, Live keeps reading it and its default write grant narrows to chat.tts_defaults and live.profile at boot (only a row still as seeded). The registry lists network.module.updated as an observed Network topic. test/module-events.test.js covers all of it plus the relay publishing rows written while it was off; test/developer-defaults.test.js now checks that nothing is queued while the relay is off (the table exists from boot). README: User modules section and tables.OpenVibers · 23 Sept 2026
ea29f8e8 -
Wave 0 baseline regenerated with the 18 services added since 2026-09-22, route and job ownership, and the D01-D46 requirement ledger (roadmap §22.4/§25). The generator now scans Events, Chat, OpenRe, Billing, Tips, VIP, AI, Search, Sources, Wiki, Blog, News, Reviews, Deals, Coupons, Trade, Codes, Host and Examples (26 repos, 612 tables, 2055 routes, 145 jobs, 97 call sites). Every route and job carries an owner and a target authority from ownership-rules.json (`routes`, `jobs`; Live has no catch-all rule, so a new Live route or job must be classified) and the exit criteria fail on any unclassified one; table rules record the moves (Live chat tables are Chat's read mirror, Live comments frozen, Chat's staged copies). scan-root.sh builds origin/main clones so the scan never reads a sibling's stale branch or uncommitted work. collect-prod.sh also reads /opt/openre.stream (release layout) and the /var/lib state directories, opening each database as its owner and reading table names only; only the databases services.json declares count as live schema, and snapshots, backups and stale files are listed as discrepancies. data/requirement-ledger.json replaces d-status.json: one row per requirement with status, acceptance artifacts, what remains and the owner action. generate.js re-verifies every artifact on each run (file and quoted text at origin/main, commit on origin/main, snapshot checks, dated read-only production observations) and marks a row UNVERIFIED if it is met without a test, production check or drill, met with work remaining, or blocked without the owner action; 09-d-status.md is derived from it. Result: 3 met, 35 partial, 1 not met, 7 blocked on owner; families 21 partial, 1 blocked on owner. Hazards refreshed from production facts with an ownerReview field (10 need the owner), H16-H18 added (backup key escrow, pre-ADR-021 backups holding IPs, Cloudflare token expiry). EC7, the owner's review of the hazard register, stays open.OpenVibers · 23 Sept 2026
b3c3e289 -
Analytics comes from openvibe-shared/analytics (v1.4.0; retires C-80): server/analytics/ keeps only network.js, the service specifics (SERVICE, PARAM_PREFIXES, PATH_RULES, and PATH_OPTS = { paramPrefixes, pathRules }); openAnalytics keeps its own connection to network.db and returns the package's AnalyticsTracker with retention: false and those path options, so the NetworkAnalyticsTracker subclass, preReducePath and prescrub are gone (the package applies pathRules in the tracker and in the scrub); schedulePrune is retention.schedulePrune. The hand-copied index/privacy/retention/schema/tracker files are deleted. scripts/analytics-prune.js is a wrapper over openvibe-shared/analytics/prune-cli with Network's path options, repo-root-relative paths, the defaultDbPath export and the VACUUM warning in its help. test/analytics-privacy.test.js tests the package with Network's options, checks every written row against analytics/event.v1, and sends a Sec-GPC and a DNT request through Network's routers that leave nothing. New with v1.4.0: a request with Sec-GPC: 1 or DNT: 1 is not recorded at all (no raw row, visitor hash, session id or rate counter); README notes itOpenVibers · 23 Sept 2026
9bbd90f7 -
Registry exposure: search.openvibe.network serves Search (public page and query API); sources.openvibe.network says it is internalOpenVibers · 23 Sept 2026
dcc6b5fd -
VIP grants: chat vip.entitlement.check (subscriber badge), community and blog vip.resource.policy.evaluate (members-only content), live vip.entitlement.checkOpenVibers · 23 Sept 2026
50552b6d -
Go-live notifications from Events: POST /internal/events consumes live.stream.started (source live) and notifies every follower of payload.channel.subject once (STREAM_LIVE, category stream, so the person's mute and email choice apply), plus everyone with stream_live_all, never the streamer; the Discord live alert runs after the commit. Live owns the follow graph, so before the inbox transaction Network reads it from Live's GET /internal/followers?stream_id=&limit=&after= with a self-signed service token (sub svc:network, aud openvibe.live, cap live.follower.read; server/notifications/live-followers.js), resolving followers by usr_ subject, then Network user id; if Live cannot answer the delivery gets 503 and nothing is recorded, so Events retries. A redelivery is a duplicate before Live is asked. A start more than 30 minutes old announces nothing. The per-streamer window (1/hour, 8/day) moves to server/notifications/stream-live.js and is shared with POST /internal/events/stream-live, so Live's direct call and the event cannot both announce during the switch. scripts/subscribe-events.js subscribes the new topic too (--topic to add it alone). test/events-consumer.test.js: followers notified once, preference applies, duplicate ignored without asking Live, v1-only refused, Live down then retried, stale/foreign/mismatched/unknown streams ignoredOpenVibers · 23 Sept 2026
2a95548a -
Registry completeness: /api/v1/registry/topics lists every event type from the manifests' eventsProduced/eventsConsumed and the v0.30 payload contracts (producers, consumers with the Events-syntax pattern that matched, payload contract with its $id and status; filters service/producer/consumer/prefix, plus /topics/:topic). Live and Media list no eventsProduced in contracts 0.30.1, so server/registry/topics.js OBSERVED declares what their code publishes (live.stream.started/ended from stream-events.js; media.vod/clip ready|failed, media.object.uploaded, media.storage.alert|recovered from Media server/events.js), marked observed on the service row, and Network's consumed topics come from its own Events consumer TOPICS. New /releases (each running service's /release.json from the loopback health poll, now keeping contracts_version and openvibe-* package versions, with drift against the libraries' current releases), /health and /search?q=. Payload schemas are served at their $id (/contracts/events/payloads/<type>.v1.json) and are CORS-public. scripts/contracts-drift.js warns (::warning:: in Actions, exit 0 unless --strict) about services pinning an older openvibe-contracts/sdk/shared than the latest tag or an unpublished tag, from GitHub, local checkouts (--dir) or the running registry (--registry); CI runs it as a continue-on-error step and weekly. test/registry-topics.test.jsOpenVibers · 23 Sept 2026
5ad26eca -
CI: run the shared security workflow (gitleaks secret scan + dependency audit, Track Q)OpenVibers · 23 Sept 2026
53f24b7d