@open-everywhere/create 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +21 -0
- package/README.md +69 -0
- package/bin/create-open-everywhere.js +57 -0
- package/package.json +57 -0
- package/src/cli.ts +241 -0
- package/src/deploy-probe.ts +99 -0
- package/src/engine.ts +106 -0
- package/src/env-file.ts +53 -0
- package/src/scaffold.ts +188 -0
- package/src/steps/build-deploy.ts +78 -0
- package/src/steps/database.ts +85 -0
- package/src/steps/env-checklist.ts +55 -0
- package/src/steps/index.ts +49 -0
- package/src/steps/prerequisites.ts +50 -0
- package/src/steps/repo.ts +69 -0
- package/src/steps/roster.ts +111 -0
- package/src/steps/slack.ts +74 -0
- package/src/steps/vercel.ts +40 -0
- package/src/steps/verify.ts +119 -0
- package/src/version.ts +20 -0
- package/template/.env.example +58 -0
- package/template/.mcp.json +8 -0
- package/template/AGENTS.md +62 -0
- package/template/CLAUDE.md +1 -0
- package/template/README.md +87 -0
- package/template/agent/access/access-requests.ts +69 -0
- package/template/agent/access/browser-hosts.ts +28 -0
- package/template/agent/access/bundles.ts +78 -0
- package/template/agent/access/connector-credentials.ts +74 -0
- package/template/agent/access/credential-bindings.generated.ts +17 -0
- package/template/agent/access/credential-bindings.ts +28 -0
- package/template/agent/access/grants.generated.ts +18 -0
- package/template/agent/access/grants.ts +30 -0
- package/template/agent/access/network-access.ts +32 -0
- package/template/agent/agent.ts +125 -0
- package/template/agent/blob/hosting.ts +42 -0
- package/template/agent/identity/authors.ts +79 -0
- package/template/agent/identity/groups-overlay.ts +24 -0
- package/template/agent/identity/groups.generated.ts +17 -0
- package/template/agent/identity/groups.ts +84 -0
- package/template/agent/identity/principals.ts +37 -0
- package/template/agent/identity/surfaces.ts +48 -0
- package/template/agent/instructions/access.ts +11 -0
- package/template/agent/instructions.md +295 -0
- package/template/agent/instrumentation.ts +6 -0
- package/template/agent/lib/memory-grants.ts +52 -0
- package/template/agent/lib/register-adapters.ts +286 -0
- package/template/agent/lib/register-config.ts +185 -0
- package/template/agent/memory/config/agents-overlay.ts +26 -0
- package/template/agent/memory/config/agents.generated.ts +21 -0
- package/template/agent/memory/config/domains/dm.ts +10 -0
- package/template/agent/memory/config/domains/index.ts +125 -0
- package/template/agent/memory/config/domains/org.ts +27 -0
- package/template/agent/memory/config/domains.ts +165 -0
- package/template/agent/model/models.ts +60 -0
- package/template/agent/model/policy.ts +19 -0
- package/template/agent/model/stacks.ts +75 -0
- package/template/agent/plugins/generated/index.ts +13 -0
- package/template/agent/plugins/registry.ts +16 -0
- package/template/agent/plugins/skill-content.ts +13 -0
- package/template/agent/roles/roles.ts +146 -0
- package/template/agent/routines/collectors.ts +89 -0
- package/template/agent/sandbox/backend-select.ts +16 -0
- package/template/agent/sandbox/sandbox.ts +242 -0
- package/template/agent/sandbox/workspace/.keep +6 -0
- package/template/agent/settings/settings.ts +19 -0
- package/template/agent/spend/budgets.ts +25 -0
- package/template/agent/spend/checkpoints.ts +51 -0
- package/template/agent/spend/model-pricing.ts +25 -0
- package/template/agent/webhooks/hooks-overlay.ts +34 -0
- package/template/agent/webhooks/hooks.generated.ts +17 -0
- package/template/agent/webhooks/hooks.ts +133 -0
- package/template/claude/skills/quickstart-open-everywhere/SKILL.md +167 -0
- package/template/claude/skills/upgrade-open-everywhere/SKILL.md +160 -0
- package/template/gitignore +42 -0
- package/template/package.json +62 -0
- package/template/roster.config.ts +39 -0
- package/template/roster.lock.json +182 -0
- package/template/scripts/env-pipe.mjs +74 -0
- package/template/scripts/ops-mcp.ts +35 -0
- package/template/tsconfig.json +23 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Copy to .env.local (it is gitignored) and fill in. eve loads .env and .env.local.
|
|
2
|
+
#
|
|
3
|
+
# Variable NAMES only. Never commit a value. .env.local never ships: the deployment reads its OWN
|
|
4
|
+
# environment. The full setup path, including which variables the deployment needs and how to copy
|
|
5
|
+
# each one without printing it, is the generated reference page:
|
|
6
|
+
# https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/setup-steps.md
|
|
7
|
+
# (README.md § "Set it up" is the one-screen version.) Two routes are supported: Vercel and Docker.
|
|
8
|
+
|
|
9
|
+
# --- Models: the Vercel AI Gateway ---
|
|
10
|
+
# A deployed VERCEL project authenticates to the gateway with OIDC and needs no key. Everything
|
|
11
|
+
# else does: a local run, and the DOCKER route, where there is no OIDC. Running a different model
|
|
12
|
+
# backend instead is an adapter swap in app code, not an env setting (docs/extending/adapter-model.md).
|
|
13
|
+
# Create a key at: Vercel dashboard -> AI Gateway -> API Keys.
|
|
14
|
+
AI_GATEWAY_API_KEY=
|
|
15
|
+
|
|
16
|
+
# --- The operational store, memory and the credential store ---
|
|
17
|
+
# A DEPLOYMENT needs ONE value here: DATABASE_URL. On Vercel a function's disk is ephemeral, and a
|
|
18
|
+
# replaced Docker container starts from an empty volume, so without it core throws at the first
|
|
19
|
+
# store or DM-memory use. On the Vercel route add Neon from the Marketplace
|
|
20
|
+
# (`npx vercel install neon`, or project -> Storage -> Neon -> Connect): it sets DATABASE_URL on the
|
|
21
|
+
# project. Copy the same value here so the operator tools (`npx oe secret`, the ops server's
|
|
22
|
+
# `secret_set`) write the store the deployment reads. A local run needs nothing: it uses an embedded
|
|
23
|
+
# database under .open-everywhere-data/.
|
|
24
|
+
DATABASE_URL=
|
|
25
|
+
# 🔴 NOT REQUIRED (OPE-2230). A present DATABASE_URL resolves BOTH stores to postgres on its own, so
|
|
26
|
+
# there is no selector to set and nothing to push to the deployment. These two are an OVERRIDE only
|
|
27
|
+
# — and a selector pointing AWAY from postgres is the one thing that breaks the resolution.
|
|
28
|
+
# OE_OPERATIONAL_PROVIDER=postgres
|
|
29
|
+
# OE_MEMORY_PROVIDER=postgres
|
|
30
|
+
# A base64-encoded 32-byte AES-256 key that encrypts stored credentials. The deployment and the
|
|
31
|
+
# operator tools need the same value. This command appends a fresh one to .env.local without printing it:
|
|
32
|
+
# node -e "console.log('OE_CREDENTIAL_ENCRYPTION_KEY=' + require('crypto').randomBytes(32).toString('base64'))" >> .env.local
|
|
33
|
+
# OE_CREDENTIAL_ENCRYPTION_KEY= (append it with the command above; do not type it here)
|
|
34
|
+
# Set this only for a custom domain. On Vercel the deployment reads its production host itself.
|
|
35
|
+
# OE_PUBLIC_BASE_URL=https://agent.example.com
|
|
36
|
+
#
|
|
37
|
+
# After DATABASE_URL and the key are set, `npx oe secret set <NAME>` (value on stdin) stores a secret
|
|
38
|
+
# whose credential names `broker: "db"` in the encrypted store. The Slack variables and
|
|
39
|
+
# GITHUB_WEBHOOK_SECRET below are read from the ENVIRONMENT only, so they stay environment variables.
|
|
40
|
+
|
|
41
|
+
# --- Slack (https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/surfaces/slack.md) ---
|
|
42
|
+
# Slack app -> OAuth & Permissions -> Bot User OAuth Token (xoxb-…).
|
|
43
|
+
SLACK_BOT_TOKEN=
|
|
44
|
+
# Slack app -> Basic Information -> Signing Secret. Verifies every inbound event.
|
|
45
|
+
SLACK_SIGNING_SECRET=
|
|
46
|
+
|
|
47
|
+
# --- GitHub (https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/surfaces/github.md) ---
|
|
48
|
+
# The GitHub App that receives webhooks and replies as the app.
|
|
49
|
+
# GITHUB_APP_ID=
|
|
50
|
+
# GITHUB_APP_PRIVATE_KEY=
|
|
51
|
+
# GITHUB_APP_SLUG=
|
|
52
|
+
# Verifies inbound deliveries. If it is unset, the route refuses every delivery.
|
|
53
|
+
# GITHUB_WEBHOOK_SECRET=
|
|
54
|
+
|
|
55
|
+
# --- Notion (https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/surfaces/notion.md) ---
|
|
56
|
+
# Notion shows the webhook verification token once, at subscription time. Store it here or with
|
|
57
|
+
# `npx oe secret set NOTION_WEBHOOK_SECRET` (the stored value wins over this variable).
|
|
58
|
+
# NOTION_WEBHOOK_SECRET=
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This is an **Open Everywhere app**: an autonomous teammate for Slack, Notion and GitHub. The runtime
|
|
4
|
+
is the `@open-everywhere/*` npm packages on the `eve` agent framework. This repository holds only
|
|
5
|
+
the app's configuration.
|
|
6
|
+
|
|
7
|
+
## Setting it up
|
|
8
|
+
|
|
9
|
+
Setup is yours to drive, with the user's consent at every command. Use the
|
|
10
|
+
`quickstart-open-everywhere` skill (`.claude/skills/`) and the `open-everywhere-ops` MCP server
|
|
11
|
+
(`.mcp.json`).
|
|
12
|
+
|
|
13
|
+
- **Step 1 is to ask which route**: **Vercel** (the `vercel` CLI plus Marketplace Neon) or
|
|
14
|
+
**Docker** (self-host against the deployment contract,
|
|
15
|
+
`https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/contract.md`). These
|
|
16
|
+
are the two supported routes. Do not invent a third, and do not pick one for the user.
|
|
17
|
+
- **Never propose a local run as a setup step.** `npm run dev` is the development loop after the
|
|
18
|
+
deploy — changing tools and skills, evals, debugging a turn. A local run has no public HTTPS URL
|
|
19
|
+
for Slack to reach and a different store, so it proves little about the deployment.
|
|
20
|
+
- **Never ask the user to paste a secret into the chat.** They paste it where a tool reads it; you
|
|
21
|
+
write it with `scaffold_env`, or mint it with `scaffold_credential_key`, which never prints it.
|
|
22
|
+
- `npx @open-everywhere/create --check --json` is the status report: every step, with `satisfied`,
|
|
23
|
+
`detail` and a `next` command. Add `--route docker` for the Docker route and
|
|
24
|
+
`--host https://<host>` to probe a deployment. The human-readable version of the same step list is
|
|
25
|
+
`https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/setup-steps.md`.
|
|
26
|
+
|
|
27
|
+
## Where things live
|
|
28
|
+
|
|
29
|
+
- `roster.config.ts` — what the agent can do. `roster.lock.json` is the reviewed roll-call of every
|
|
30
|
+
contribution. Both are committed.
|
|
31
|
+
- `agent/agent.ts` — the eve agent definition.
|
|
32
|
+
- `agent/` — the config: access bundles, identity and trust, memory domains, models, settings, spend
|
|
33
|
+
caps, webhooks. Each file's header says what it controls.
|
|
34
|
+
- `agent/tools/`, `agent/channels/`, `agent/hooks/`, `agent/schedules/`, `agent/skills/`,
|
|
35
|
+
`agent/connections/` and `agent/lib/providers.generated.ts` — `oe build` output. Never edit or
|
|
36
|
+
commit them.
|
|
37
|
+
- `*.generated.ts` — machine-owned overlays that the agent's own approval flows write by pull
|
|
38
|
+
request. Never edit them by hand.
|
|
39
|
+
- `scripts/ops-mcp.ts` — the ops MCP server. `scripts/env-pipe.mjs` — `npm run -s env:pipe`, which
|
|
40
|
+
pipes one `.env.local` value into `vercel env add`. Always pipe it; never run it bare.
|
|
41
|
+
|
|
42
|
+
## The pipeline
|
|
43
|
+
|
|
44
|
+
- `npm install` runs the `postinstall` script, `oe-eve-patch`. It applies the Open Everywhere patch
|
|
45
|
+
to the installed `eve` and verifies it. The app refuses to boot on an unpatched `eve`.
|
|
46
|
+
- `npm run build` runs `oe build` (writes the slot tree from the roster), then `eve build`.
|
|
47
|
+
`npm run dev` and `npm start` run `oe build` first too.
|
|
48
|
+
- `oe build` refuses a contribution the lock has not reviewed. Decide about it in
|
|
49
|
+
`roster.config.ts`, then run `npx oe build --accept`, and review the lock diff.
|
|
50
|
+
- `npm run typecheck` type-checks the app.
|
|
51
|
+
- Deploy is a separate, explicit step. On the Vercel route that is `npx vercel deploy --prod`; a
|
|
52
|
+
`git push` does NOT deploy.
|
|
53
|
+
|
|
54
|
+
## Rules
|
|
55
|
+
|
|
56
|
+
- Never commit a secret, a token, an `.env` value or a credential. Secrets go in `.env.local`
|
|
57
|
+
(gitignored), and the deployment reads them from its own environment. A credential whose
|
|
58
|
+
`broker` is `"db"` goes in the encrypted credential store instead (`npx oe secret set <NAME>`).
|
|
59
|
+
- Upgrade every `@open-everywhere/*` package together, to one version. Keep `eve` at the exact
|
|
60
|
+
version `@open-everywhere/core` declares as its peer. A `devDependencies` key that still reads
|
|
61
|
+
`create-open-everywhere` is replaced by `@open-everywhere/create`, not bumped: the unscoped name is
|
|
62
|
+
retired. `npx oe upgrade` does that rename.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Read [AGENTS.md](./AGENTS.md): it describes this Open Everywhere app, where its config lives, and the rules.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Open Everywhere app
|
|
2
|
+
|
|
3
|
+
This is an [Open Everywhere](https://github.com/open-everywhere/open-everywhere) app: an
|
|
4
|
+
autonomous teammate you tag in Slack, Notion and GitHub. The runtime comes from the
|
|
5
|
+
`@open-everywhere/*` npm packages; this repository holds only your configuration.
|
|
6
|
+
|
|
7
|
+
## Set it up
|
|
8
|
+
|
|
9
|
+
**Open this folder in your coding agent and ask it to set up Open Everywhere.**
|
|
10
|
+
|
|
11
|
+
It reads `AGENTS.md`, `.mcp.json` gives it the `open-everywhere-ops` MCP server, and
|
|
12
|
+
`.claude/skills/quickstart-open-everywhere/` is the runbook it follows. It will ask you to pick a
|
|
13
|
+
route first:
|
|
14
|
+
|
|
15
|
+
- **Vercel** — the `vercel` CLI plus Marketplace Neon. The deployment authenticates to the AI
|
|
16
|
+
Gateway with OIDC, so it needs no gateway key.
|
|
17
|
+
- **Docker** — self-host a container that satisfies the
|
|
18
|
+
[deployment contract](https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/contract.md).
|
|
19
|
+
|
|
20
|
+
These are the two supported routes. Some steps stay with you: creating the Slack app, approving
|
|
21
|
+
each deploy, and pasting each secret where the agent's tools can read it but the chat cannot.
|
|
22
|
+
|
|
23
|
+
Want the whole path on one page, or doing a step by hand? Read the
|
|
24
|
+
[setup steps reference](https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/setup-steps.md).
|
|
25
|
+
It is generated from the same step list the status check reports, so it cannot drift from it.
|
|
26
|
+
|
|
27
|
+
## Check where you are
|
|
28
|
+
|
|
29
|
+
`npx @open-everywhere/create --check` reports every setup step and the next command for each
|
|
30
|
+
unsatisfied one. It changes nothing. Add `--json` for the report as data, `--route docker` to judge
|
|
31
|
+
against the Docker route, and `--host https://<host>` to probe a deployment.
|
|
32
|
+
|
|
33
|
+
## Develop locally
|
|
34
|
+
|
|
35
|
+
After the deploy, `npm run dev` runs the agent on this machine and talks to it in a terminal UI.
|
|
36
|
+
That is the loop for changing tools and skills, running evals, and debugging a turn — not a way to
|
|
37
|
+
set the app up. It needs `AI_GATEWAY_API_KEY` in `.env.local` (Vercel → AI Gateway → API Keys), and
|
|
38
|
+
it keeps its state in an embedded database under `.open-everywhere-data/`. Slack cannot reach it
|
|
39
|
+
without a public tunnel.
|
|
40
|
+
|
|
41
|
+
## What is in this repository
|
|
42
|
+
|
|
43
|
+
| Path | What it is |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `roster.config.ts` | What the agent can do: which packages contribute, and which eve built-ins it takes away. |
|
|
46
|
+
| `roster.lock.json` | The reviewed roll-call of every contribution. `npx oe build --accept` updates it. Review its diff. |
|
|
47
|
+
| `agent/agent.ts` | The eve agent definition. |
|
|
48
|
+
| `agent/access/` | Bundles and bindings (what the agent may reach, and where), connector credentials, browser hosts. |
|
|
49
|
+
| `agent/identity/` | Trusted surfaces, principals and groups. |
|
|
50
|
+
| `agent/memory/config/` | Memory domains and silos. |
|
|
51
|
+
| `agent/model/` | Model stacks and the org model policy. |
|
|
52
|
+
| `agent/settings/settings.ts` | Behaviour settings. Empty means the shipped defaults. |
|
|
53
|
+
| `agent/spend/` | Spend caps and model pricing. |
|
|
54
|
+
| `agent/webhooks/hooks.ts` | Inbound webhook triggers. |
|
|
55
|
+
| `AGENTS.md`, `CLAUDE.md` | The guide a coding agent reads in this repository. |
|
|
56
|
+
| `.mcp.json`, `scripts/ops-mcp.ts` | The `open-everywhere-ops` MCP server: setup status, `.env.local` values and stored secrets, for a coding agent. |
|
|
57
|
+
| `scripts/env-pipe.mjs` | `npm run -s env:pipe`: writes one `.env.local` value to a pipe for `vercel env add`. It refuses a terminal or a file. Never run it bare. |
|
|
58
|
+
| `.claude/skills/quickstart-open-everywhere/` | The setup skill that drives that server. |
|
|
59
|
+
|
|
60
|
+
`agent/tools/`, `agent/channels/`, `agent/hooks/`, `agent/schedules/`, `agent/skills/`,
|
|
61
|
+
`agent/connections/` and `agent/lib/providers.generated.ts` are `oe build` output. They are not
|
|
62
|
+
committed. The `*.generated.ts` files are machine-owned overlays that the agent's own approval flows
|
|
63
|
+
write by pull request. Do not edit them by hand.
|
|
64
|
+
|
|
65
|
+
## Add a surface
|
|
66
|
+
|
|
67
|
+
Notion and GitHub are in the roster. Each one needs its own setup before it answers:
|
|
68
|
+
|
|
69
|
+
- **Notion** — create an internal integration, subscribe its webhook to
|
|
70
|
+
`https://<host>/eve/v1/notion`, and put the pages it may act on in a memory domain's `reach`. See the
|
|
71
|
+
[Notion guide](https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/surfaces/notion.md).
|
|
72
|
+
- **GitHub** — create a GitHub App, point its webhook at `https://<host>/eve/v1/github`, and set
|
|
73
|
+
`GITHUB_WEBHOOK_SECRET`. See the
|
|
74
|
+
[GitHub guide](https://github.com/open-everywhere/open-everywhere/blob/main/docs/deploy/surfaces/github.md).
|
|
75
|
+
|
|
76
|
+
Discord, Microsoft Teams and Linear are installed too. To add one, add it under `providers` in
|
|
77
|
+
`roster.config.ts`, then run `npx oe build --accept`.
|
|
78
|
+
|
|
79
|
+
## Upgrade
|
|
80
|
+
|
|
81
|
+
Bump every `@open-everywhere/*` package to the same version, run `npm install`, then
|
|
82
|
+
`npx oe build --accept`, and review the `roster.lock.json` diff before you deploy. Keep `eve` at the
|
|
83
|
+
version `@open-everywhere/core` declares as its peer.
|
|
84
|
+
|
|
85
|
+
If `devDependencies` still names `create-open-everywhere`, replace that key with
|
|
86
|
+
`@open-everywhere/create` at the same version. The unscoped name is retired and publishes no further
|
|
87
|
+
version. `npx oe upgrade` does this rename for you.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Access-request flow config (docs/how-it-works/access-requests.md in the Open Everywhere repository) — the deployer's
|
|
2
|
+
// knobs for the widen-slow path: request card → deterministic codemod → bot-PR →
|
|
3
|
+
// ADMIN MERGES IN GITHUB (that merge is the approval; there is no admin card).
|
|
4
|
+
//
|
|
5
|
+
// FAIL-CLOSED: with either env var below unset, the `request_access` tool refuses
|
|
6
|
+
// politely and the flow is simply OFF — nothing else changes. Both values are
|
|
7
|
+
// operator-specific (a private channel id, YOUR fork's repo), so they live in env,
|
|
8
|
+
// never in this committed file (AGENTS.md security rules).
|
|
9
|
+
//
|
|
10
|
+
// OE_ACCESS_ADMIN_CHANNEL Slack channel id that hears "PR opened — merge to grant".
|
|
11
|
+
// OE_ACCESS_CONFIG_REPO "owner/repo" of THIS deployment's config repo (the one
|
|
12
|
+
// the grants overlay lives in). The GitHub App needs write on it.
|
|
13
|
+
// OE_ACCESS_CONFIG_BASE Base branch (default "main").
|
|
14
|
+
// OE_ACCESS_GRANTS_PATH Overlay path (default "agent/access/grants.generated.ts").
|
|
15
|
+
// OE_WEBHOOK_HOOKS_PATH Webhook-declaration overlay path (default
|
|
16
|
+
// "agent/webhooks/hooks.generated.ts") — the `declare_webhook` flow (OPE-208)
|
|
17
|
+
// rides this same repo/branch/credential, only the file differs.
|
|
18
|
+
// OE_ACCESS_DRY_RUN=1 e2e/test mode: a tap validates + reports, no branch/PR.
|
|
19
|
+
//
|
|
20
|
+
// baseBundles/baseBindings hand core the CODE-ONLY baseline (overlay excluded) so the
|
|
21
|
+
// execute path can re-validate a CANDIDATE grants file merged against it before any PR
|
|
22
|
+
// opens — the runtime resolver keeps using the merged loaders.
|
|
23
|
+
|
|
24
|
+
import type { AccessRequestsConfig } from "@open-everywhere/core/agent/access/config.js";
|
|
25
|
+
import { emptyAgentsFile } from "@open-everywhere/core/agent/memory/agents-codemod.js";
|
|
26
|
+
import { loadBaseBundles, loadBaseBindings } from "./bundles.js";
|
|
27
|
+
import { loadBaseConnectorCredentials } from "./connector-credentials.js";
|
|
28
|
+
import { loadBaseWebhooks } from "../webhooks/hooks.js";
|
|
29
|
+
import { loadBaseDomains, loadBaseSilos, loadDomains } from "../memory/config/domains.js";
|
|
30
|
+
import { loadGroups } from "../identity/groups.js";
|
|
31
|
+
|
|
32
|
+
export function loadAccessRequests(): AccessRequestsConfig | null {
|
|
33
|
+
return {
|
|
34
|
+
adminChannel: process.env.OE_ACCESS_ADMIN_CHANNEL,
|
|
35
|
+
configRepo: process.env.OE_ACCESS_CONFIG_REPO,
|
|
36
|
+
configBase: process.env.OE_ACCESS_CONFIG_BASE || undefined,
|
|
37
|
+
grantsPath: process.env.OE_ACCESS_GRANTS_PATH || undefined,
|
|
38
|
+
dryRun: process.env.OE_ACCESS_DRY_RUN === "1",
|
|
39
|
+
baseBundles: loadBaseBundles,
|
|
40
|
+
baseBindings: loadBaseBindings,
|
|
41
|
+
// The MEMORY-DOMAIN registry — the MERGED one (code config ∪ generated agents), because a
|
|
42
|
+
// domain-scoped request freezes the domain name at proposal and must prove that exact name
|
|
43
|
+
// still resolves when a member taps. Never retarget a stale request to a different domain.
|
|
44
|
+
domainRegistry: loadDomains,
|
|
45
|
+
// The PERSON-GROUP registry (C.1) — the MERGED one (hand-written ∪ the IdP-group overlay),
|
|
46
|
+
// deliberately not a code-only baseline: this flow never writes agent/identity/groups*.ts, so
|
|
47
|
+
// the honest thing to validate a `group`-scoped candidate binding against is what the
|
|
48
|
+
// deployment actually resolves. It is what makes a self-serve DM/group grant naming an unknown
|
|
49
|
+
// group refuse BEFORE a PR opens instead of at the next config load.
|
|
50
|
+
groupRegistry: loadGroups,
|
|
51
|
+
// The stage-5 credential-binding PR path re-validates the merged catalogue set (base ⊕ candidate
|
|
52
|
+
// override) before opening a PR against this SAME config repo.
|
|
53
|
+
baseConnectorCredentials: loadBaseConnectorCredentials,
|
|
54
|
+
// The `declare_webhook` PR path (OPE-208) rides this SAME config repo, branch and bot
|
|
55
|
+
// credential — only the machine-written file differs. `baseWebhooks` is the code-declared
|
|
56
|
+
// baseline a candidate overlay is validated against before any PR opens.
|
|
57
|
+
hooksPath: process.env.OE_WEBHOOK_HOOKS_PATH || undefined,
|
|
58
|
+
baseWebhooks: loadBaseWebhooks,
|
|
59
|
+
// The `create_agent` PR path (create_agent flow, increment 2) rides this SAME config repo, branch
|
|
60
|
+
// and bot credential — only the machine-written file differs (the agents overlay). `baseAgents` is
|
|
61
|
+
// the code-declared agents baseline (empty — agents live only in the overlay); `baseDomains` /
|
|
62
|
+
// `baseSilos` are the code-only memory baseline a candidate overlay is validated against (ring ②)
|
|
63
|
+
// before any PR opens. `agentsPath` defaults to "agent/memory/config/agents.generated.ts".
|
|
64
|
+
agentsPath: process.env.OE_AGENTS_PATH || undefined,
|
|
65
|
+
baseAgents: emptyAgentsFile,
|
|
66
|
+
baseDomains: loadBaseDomains,
|
|
67
|
+
baseSilos: loadBaseSilos,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// The in-sandbox browser's whole reach. A host reaches this list by pull request, and the diff is
|
|
2
|
+
// the review. Each row is a security decision:
|
|
3
|
+
// host — where the browser may go.
|
|
4
|
+
// methods — which HTTP verbs the sandbox firewall admits there. `["GET", "HEAD"]` cannot
|
|
5
|
+
// submit a form. Adding `POST` permits one, with no per-call approval card.
|
|
6
|
+
// credential — optional: the egress connection (agent/access/bundles.ts) whose secret the
|
|
7
|
+
// firewall stamps on requests to this host. The browser never holds it.
|
|
8
|
+
// evaluate — optional: arm `browser_evaluate` (model-written JavaScript) for this host.
|
|
9
|
+
//
|
|
10
|
+
// The browser is OFF until `browser.enabled` is true in agent/settings/settings.ts. Nothing in this
|
|
11
|
+
// file is a secret, and nothing in it may be.
|
|
12
|
+
|
|
13
|
+
import { registerBrowserHosts, type BrowserHostDeclaration } from "@open-everywhere/core/agent/access/browser-hosts.js";
|
|
14
|
+
|
|
15
|
+
const browserHosts: BrowserHostDeclaration[] = [
|
|
16
|
+
{
|
|
17
|
+
host: "localhost",
|
|
18
|
+
methods: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
|
|
19
|
+
why: "The in-sandbox dev server a worker boots to see its own UI change.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
host: "127.0.0.1",
|
|
23
|
+
methods: ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
|
|
24
|
+
why: "The same in-sandbox dev server, reached by loopback address instead of by name.",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
registerBrowserHosts(browserHosts);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Access bundles and bindings — WHAT the agent may reach, and WHERE.
|
|
2
|
+
//
|
|
3
|
+
// A bundle is a named set of capabilities: egress hosts (`domains`), repositories (`repos`),
|
|
4
|
+
// connectors, egress connections and plugins, plus instructions the model reads when the bundle
|
|
5
|
+
// applies. A binding attaches a bundle to a scope: the whole org, one domain, one surface, or one
|
|
6
|
+
// principal. Nothing is reachable until a binding grants it.
|
|
7
|
+
//
|
|
8
|
+
// Start small. Add a bundle when a room needs a capability, and bind it as narrowly as you can.
|
|
9
|
+
// The configuration reference is docs/deploy/configuration-reference.md in the Open Everywhere repository.
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
assertBindingsValid,
|
|
13
|
+
assertBundlesValid,
|
|
14
|
+
defineBinding,
|
|
15
|
+
defineBundle,
|
|
16
|
+
type Binding,
|
|
17
|
+
type Bundle,
|
|
18
|
+
} from "@open-everywhere/core/agent/access/bundle.js";
|
|
19
|
+
import { loadGrantsOverlay } from "./grants.js";
|
|
20
|
+
import { loadAgentsOverlay } from "../memory/config/agents-overlay.js";
|
|
21
|
+
import { loadGroups } from "../identity/groups.js";
|
|
22
|
+
|
|
23
|
+
const bundles: Bundle[] = [
|
|
24
|
+
defineBundle({
|
|
25
|
+
name: "org-default",
|
|
26
|
+
// Credential-less egress that is safe org-wide.
|
|
27
|
+
domains: ["raw.githubusercontent.com"],
|
|
28
|
+
instructions: "Never act outside the access granted to this room.",
|
|
29
|
+
}),
|
|
30
|
+
// Example — let one domain open pull requests on one repository:
|
|
31
|
+
//
|
|
32
|
+
// defineBundle({
|
|
33
|
+
// name: "coding",
|
|
34
|
+
// repos: ["your-org/your-repo"],
|
|
35
|
+
// domains: [...PACKAGE_REGISTRY_HOSTS], // import it from "@open-everywhere/core/agent/access/bundle.js"
|
|
36
|
+
// instructions: "Changes go via branch + open_pull_request; never push to main.",
|
|
37
|
+
// }),
|
|
38
|
+
//
|
|
39
|
+
// Example — the Notion MCP connector on the shared workspace credential:
|
|
40
|
+
//
|
|
41
|
+
// defineBundle({
|
|
42
|
+
// name: "notion",
|
|
43
|
+
// connectors: [{ name: "notion", credential: "workspace-oauth", contentOrigin: "internal" }],
|
|
44
|
+
// }),
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const bindings: Binding[] = [
|
|
48
|
+
defineBinding({ bundle: "org-default", scope: { level: "org" } }),
|
|
49
|
+
// defineBinding({ bundle: "coding", scope: { level: "domain", domain: "org" } }),
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// The machine-owned overlays: access requests the agent raised and an admin approved by merging a
|
|
53
|
+
// pull request (grants.generated.ts), and agent-authored domains (agents.generated.ts).
|
|
54
|
+
const overlay = loadGrantsOverlay();
|
|
55
|
+
const agentsOverlay = loadAgentsOverlay();
|
|
56
|
+
const mergedBundles: readonly Bundle[] = [...bundles, ...overlay.bundles, ...agentsOverlay.bundles];
|
|
57
|
+
const mergedBindings: readonly Binding[] = [...bindings, ...overlay.bindings, ...agentsOverlay.bindings];
|
|
58
|
+
|
|
59
|
+
assertBundlesValid(mergedBundles);
|
|
60
|
+
assertBindingsValid(mergedBindings, mergedBundles, loadGroups());
|
|
61
|
+
|
|
62
|
+
/** Code config plus the overlays. */
|
|
63
|
+
export function loadBundles(): readonly Bundle[] {
|
|
64
|
+
return mergedBundles;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function loadBindings(): readonly Binding[] {
|
|
68
|
+
return mergedBindings;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Code config only — the base the access-request codemod writes its overlay against. */
|
|
72
|
+
export function loadBaseBundles(): readonly Bundle[] {
|
|
73
|
+
return bundles;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function loadBaseBindings(): readonly Binding[] {
|
|
77
|
+
return bindings;
|
|
78
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Connector credential catalogues — HOW each connector authenticates.
|
|
2
|
+
//
|
|
3
|
+
// One catalogue per connector. Each credential names its type, where its secret lives
|
|
4
|
+
// (`secretRef` + `broker`: `env` reads an environment variable by NAME, `db` reads the encrypted
|
|
5
|
+
// credential store), and the endpoints it may be presented to. A bundle grant
|
|
6
|
+
// (agent/access/bundles.ts) picks a credential by `id`. A credential nobody grants is inert.
|
|
7
|
+
//
|
|
8
|
+
// The secret VALUES never live in this file — only the names they are stored under.
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
assertConnectorCredentialsValid,
|
|
12
|
+
defineConnectorCredentials,
|
|
13
|
+
vercelConnectorHome,
|
|
14
|
+
type ConnectorCredentials,
|
|
15
|
+
} from "@open-everywhere/core/agent/access/connector-credentials.js";
|
|
16
|
+
import { applyOverridesToConnectorCredentials } from "@open-everywhere/core/agent/access/credential-bindings-codemod.js";
|
|
17
|
+
import { loadCredentialBindingsOverlay } from "./credential-bindings.js";
|
|
18
|
+
|
|
19
|
+
const catalogues: ConnectorCredentials[] = [
|
|
20
|
+
defineConnectorCredentials({
|
|
21
|
+
description: "Notion workspace (host-side MCP) — read and write the team knowledge base.",
|
|
22
|
+
connector: "notion",
|
|
23
|
+
allows: ["api-key", "service-oauth", "user-oauth"],
|
|
24
|
+
credentials: [
|
|
25
|
+
{ id: "team-key", type: "api-key", secretRef: "db:notion:team-key", broker: "db", endpoints: { hosts: ["api.notion.com"], pathPrefixes: ["/v1/"], methods: ["GET", "POST"] } },
|
|
26
|
+
// The Notion CHAT surface posts its replies with this credential.
|
|
27
|
+
{
|
|
28
|
+
id: "channel-key",
|
|
29
|
+
type: "api-key",
|
|
30
|
+
secretRef: "db:notion:channel-key",
|
|
31
|
+
broker: "db",
|
|
32
|
+
intake: false,
|
|
33
|
+
endpoints: { hosts: ["api.notion.com"], pathPrefixes: ["/v1/"], methods: ["GET", "POST"] },
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "memory",
|
|
37
|
+
type: "api-key",
|
|
38
|
+
secretRef: "db:notion:memory",
|
|
39
|
+
broker: "db",
|
|
40
|
+
intake: false,
|
|
41
|
+
endpoints: { hosts: ["api.notion.com"], pathPrefixes: ["/v1/blocks/"], methods: ["GET"] },
|
|
42
|
+
},
|
|
43
|
+
{ id: "user-oauth", type: "user-oauth", home: vercelConnectorHome("mcp.notion.com/notion-mcp"), endpoints: { hosts: ["mcp.notion.com"] } },
|
|
44
|
+
{ id: "workspace-oauth", type: "service-oauth", home: vercelConnectorHome("mcp.notion.com/notion-mcp"), endpoints: { hosts: ["mcp.notion.com"] } },
|
|
45
|
+
],
|
|
46
|
+
}),
|
|
47
|
+
defineConnectorCredentials({
|
|
48
|
+
description: "Slack workspace — the WORK surface a granted domain's delegated workers read conversations on.",
|
|
49
|
+
connector: "slack",
|
|
50
|
+
allows: ["api-key"],
|
|
51
|
+
credentials: [
|
|
52
|
+
{ id: "work-token", type: "api-key", secretRef: "SLACK_BOT_TOKEN", broker: "env", intake: false },
|
|
53
|
+
{ id: "chat-token", type: "api-key", secretRef: "SLACK_BOT_TOKEN", broker: "env", intake: false },
|
|
54
|
+
],
|
|
55
|
+
}),
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
assertConnectorCredentialsValid(catalogues);
|
|
59
|
+
|
|
60
|
+
// Custody moves (env → db) land as a machine-owned overlay (credential-bindings.generated.ts).
|
|
61
|
+
const merged: readonly ConnectorCredentials[] = applyOverridesToConnectorCredentials(
|
|
62
|
+
catalogues,
|
|
63
|
+
loadCredentialBindingsOverlay().overrides,
|
|
64
|
+
);
|
|
65
|
+
assertConnectorCredentialsValid(merged);
|
|
66
|
+
|
|
67
|
+
export function loadConnectorCredentials(): readonly ConnectorCredentials[] {
|
|
68
|
+
return merged;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The code catalogues only — the base the credential-bindings codemod writes against. */
|
|
72
|
+
export function loadBaseConnectorCredentials(): readonly ConnectorCredentials[] {
|
|
73
|
+
return catalogues;
|
|
74
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// GENERATED + MACHINE-OWNED — DO NOT HAND-EDIT.
|
|
2
|
+
//
|
|
3
|
+
// The credential-bindings overlay: DATA ONLY. Written exclusively by the deterministic codemod
|
|
4
|
+
// (packages/core/agent/access/credential-bindings-codemod.ts) on a bot-PR branch; the PR merge is the approval gate.
|
|
5
|
+
//
|
|
6
|
+
// The codemod re-emits this file from its own parsed content and refuses to rewrite it when the
|
|
7
|
+
// bytes differ, so a hand-edit stops the next machine PR. Before a merge, nothing checks that the
|
|
8
|
+
// file is still data only unless the repository runs its own check: the person who merges the PR
|
|
9
|
+
// is the gate. Read a PR to this file as code, because it is code.
|
|
10
|
+
//
|
|
11
|
+
// To change it by hand, edit only the data below and keep the layout exactly as emitted.
|
|
12
|
+
|
|
13
|
+
import type { CredentialBindingsFile } from "@open-everywhere/core/agent/access/credential-bindings-codemod.js";
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
"overrides": []
|
|
17
|
+
} satisfies CredentialBindingsFile;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// The credential-bindings OVERLAY loader — the runtime half of the stage-5 credential-binding flow
|
|
2
|
+
// (task #113; docs/security/credentials-and-planes.md in the Open Everywhere repository). `credential-bindings.generated.ts` (next to
|
|
3
|
+
// this file) is a MACHINE-OWNED, DATA-ONLY overlay of custody re-stamps (connector credential → new
|
|
4
|
+
// broker + secretRef) that merges over the config-as-code catalogue set in connector-credentials.ts
|
|
5
|
+
// at load. Each override names its `connector` and `credential` (the codemod refuses the old
|
|
6
|
+
// `provider` spelling at load — OPE-598). Nothing edits it by hand in the normal flow: the deterministic codemod (core
|
|
7
|
+
// access/credential-bindings-codemod.ts) writes it on a `credential-binding/<connector>-<credential>`
|
|
8
|
+
// branch, a bot-PR carries the diff, and GitHub's merge button — with CODEOWNERS on this path +
|
|
9
|
+
// branch protection — is the approval gate.
|
|
10
|
+
//
|
|
11
|
+
// WHY a static import (not an fs read): Eve's bundler inlines the module into the deploy artifact,
|
|
12
|
+
// so the overlay can never be silently absent at runtime. Parsing is STRICT + fail-loud
|
|
13
|
+
// (parseCredentialBindingsFile): a malformed overlay refuses to boot rather than loading half-right,
|
|
14
|
+
// and Vercel keeps the previous deployment live on a failed build/boot (the build-then-promote
|
|
15
|
+
// backstop) — worst case a red pipeline, never a downed agent. Mirrors grants.ts exactly, including
|
|
16
|
+
// the reason the DATA lives in a `.ts` module (OPE-256): one authoring language. Nothing in this
|
|
17
|
+
// app checks that the file stays data only: the person who merges the codemod's PR is the gate.
|
|
18
|
+
|
|
19
|
+
import { parseCredentialBindingsFile, type CredentialBindingsFile } from "@open-everywhere/core/agent/access/credential-bindings-codemod.js";
|
|
20
|
+
import bindingsOverlay from "./credential-bindings.generated.js";
|
|
21
|
+
|
|
22
|
+
const overlay: CredentialBindingsFile = parseCredentialBindingsFile(bindingsOverlay);
|
|
23
|
+
|
|
24
|
+
/** The parsed credential-bindings overlay — merged over loadConnectorCredentials() by
|
|
25
|
+
* connector-credentials.ts. */
|
|
26
|
+
export function loadCredentialBindingsOverlay(): CredentialBindingsFile {
|
|
27
|
+
return overlay;
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// GENERATED + MACHINE-OWNED — DO NOT HAND-EDIT.
|
|
2
|
+
//
|
|
3
|
+
// The grants overlay: DATA ONLY. Written exclusively by the deterministic codemod
|
|
4
|
+
// (packages/core/agent/access/grants-codemod.ts) on a bot-PR branch; the PR merge is the approval gate.
|
|
5
|
+
//
|
|
6
|
+
// The codemod re-emits this file from its own parsed content and refuses to rewrite it when the
|
|
7
|
+
// bytes differ, so a hand-edit stops the next machine PR. Before a merge, nothing checks that the
|
|
8
|
+
// file is still data only unless the repository runs its own check: the person who merges the PR
|
|
9
|
+
// is the gate. Read a PR to this file as code, because it is code.
|
|
10
|
+
//
|
|
11
|
+
// To change it by hand, edit only the data below and keep the layout exactly as emitted.
|
|
12
|
+
|
|
13
|
+
import type { GrantsFile } from "@open-everywhere/core/agent/access/grants-codemod.js";
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
"bundles": [],
|
|
17
|
+
"bindings": []
|
|
18
|
+
} satisfies GrantsFile;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// The grants OVERLAY loader — the runtime half of the access-request flow's widen path
|
|
2
|
+
// (docs/how-it-works/access-requests.md in the Open Everywhere repository). `grants.generated.ts` (next to this file) is a
|
|
3
|
+
// MACHINE-OWNED, DATA-ONLY overlay of extra bundles + channel-scoped bindings that merges
|
|
4
|
+
// into the config-as-code baseline in bundles.ts at load. Nothing edits it by hand in the
|
|
5
|
+
// normal flow: the deterministic codemod (core access/grants-codemod.ts) writes it on an
|
|
6
|
+
// `access-request/<id>` branch, a bot-PR carries the diff, and GitHub's merge button is
|
|
7
|
+
// the approval gate.
|
|
8
|
+
//
|
|
9
|
+
// WHY a static import (not an fs read): Eve's bundler inlines the module into the deploy
|
|
10
|
+
// artifact, so the overlay can never be silently absent at runtime the way a stripped file
|
|
11
|
+
// path could be — a grant that merged is a grant that ships. Parsing is STRICT + fail-loud
|
|
12
|
+
// (parseGrantsFile): a malformed overlay (a bad merge) refuses to boot rather than loading
|
|
13
|
+
// as "roughly right" — and Vercel keeps the previous deployment live on a failed build/boot,
|
|
14
|
+
// so the worst case is a red pipeline, never a downed agent (the build-then-promote backstop).
|
|
15
|
+
//
|
|
16
|
+
// WHY THE DATA LIVES IN A `.ts` MODULE AND NOT JSON (OPE-256): one authoring language for the
|
|
17
|
+
// whole deployer config. The split that is load-bearing is not JSON-vs-TS but MACHINE-OWNED vs
|
|
18
|
+
// human-authored. A module IS executable at load, and this parse only sees the value, so this
|
|
19
|
+
// loader does not prove the file is data. In this app no check before the merge does: whoever merges the
|
|
20
|
+
// codemod's PR is the only gate on the file staying data only. Review that PR as code.
|
|
21
|
+
|
|
22
|
+
import { parseGrantsFile, type GrantsFile } from "@open-everywhere/core/agent/access/grants-codemod.js";
|
|
23
|
+
import grantsOverlay from "./grants.generated.js";
|
|
24
|
+
|
|
25
|
+
const overlay: GrantsFile = parseGrantsFile(grantsOverlay);
|
|
26
|
+
|
|
27
|
+
/** The parsed grants overlay — merged into loadBundles()/loadBindings() by bundles.ts. */
|
|
28
|
+
export function loadGrantsOverlay(): GrantsFile {
|
|
29
|
+
return overlay;
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Network-access LEVEL configuration — config-as-code (OPE-509), the "environment" axis
|
|
2
|
+
// alongside bundles.ts's capability axis. Declare a named level ("trusted" | "none" | "full")
|
|
3
|
+
// per scope on the container ladder (org < tenant < domain < surface); an unpinned scope
|
|
4
|
+
// inherits the nearest wider pin, and a scope no pin reaches at all resolves "none" — the same
|
|
5
|
+
// egress posture every scope already has today. See docs/how-it-works/access-and-scoping.md in the Open Everywhere repository
|
|
6
|
+
// (§ Network-access levels) and packages/core/agent/access/network-access.ts for the resolution
|
|
7
|
+
// doctrine and exactly what "trusted" opens.
|
|
8
|
+
//
|
|
9
|
+
// LEFT EMPTY, DELIBERATELY. This ticket adds the CONFIG SHAPE — it does not widen this
|
|
10
|
+
// deployment's live egress by default. The commented example below shows the intended usage:
|
|
11
|
+
// it would let the "coding" bundle in agent/access/bundles.ts drop its hand-copied
|
|
12
|
+
// `domains: [...PACKAGE_REGISTRY_HOSTS]` line in favour of a reviewable, named level, but
|
|
13
|
+
// switching that bundle over is a separate, deliberate config change — not a side effect of
|
|
14
|
+
// shipping the mechanism.
|
|
15
|
+
|
|
16
|
+
import { assertNetworkAccessValid, defineNetworkAccess, type NetworkAccessBinding } from "@open-everywhere/core/agent/access/network-access.js";
|
|
17
|
+
|
|
18
|
+
const networkAccess: NetworkAccessBinding[] = [
|
|
19
|
+
// Example: give the coding channel the curated "trusted" set (package registries +
|
|
20
|
+
// developer hosts) instead of the hand-copied PACKAGE_REGISTRY_HOSTS domains grant on the
|
|
21
|
+
// "coding" bundle in ../access/bundles.ts — same effective egress, named and reviewable at
|
|
22
|
+
// the scope instead of buried in a bundle's host list.
|
|
23
|
+
// defineNetworkAccess({ scope: { level: "surface", surface: "slack/<team-id>/<channel-id>" }, level: "trusted" }),
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// Validate at module load (fail loud), same doctrine as bundles.ts's assertBundlesValid.
|
|
27
|
+
assertNetworkAccessValid(networkAccess);
|
|
28
|
+
|
|
29
|
+
/** The seam a DB/dashboard would swap behind, same shape as bundles.ts's loadBundles(). */
|
|
30
|
+
export function loadNetworkAccess(): readonly NetworkAccessBinding[] {
|
|
31
|
+
return networkAccess;
|
|
32
|
+
}
|