Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions GLOSSARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ A React-based web application that lets users visually explore graph databases w

**Graph Database**: The external graph database a user connects to and explores — the source of all vertices and edges, reached over HTTP via a Connection. It is the user's own data, brought along and queried live; distinct from the local app state (connections, schema cache, styles, sessions) that Graph Explorer keeps in the browser's IndexedDB, plus the per-tab View Layout in sessionStorage. _Avoid_: Database (ambiguous — clarify remote graph database vs. local persisted state)

**Connection**: A saved database profile — the **Database URL**, query language, and optional IAM authentication settings. The client reaches the database through the same-origin **Proxy Server**, so no proxy endpoint is configured, unless the Connection is a **Direct Connection**. Users create and manage these in the UI. _Avoid_: Configuration (legacy term being phased out — previously bundled connection + schema + Styles into one object; `Configuration`-prefixed code names like `RawConfiguration` or `ConfigurationId` were renamed to their `Connection`/`SavedConnection` forms, see epic #2296); proxy endpoint (removed — see ADR `unify-docker-image-remove-sagemaker-variant`)
**Connection**: A saved database profile — the **Database URL**, query language, and optional IAM authentication settings. Each Connection is either a **Proxy Connection** (the default) or a **Direct Connection**, and IAM authentication is only available on a Proxy Connection. The Proxy Server is same-origin, so no proxy endpoint is configured. Users create and manage these in the UI. _Avoid_: Configuration (legacy term being phased out — previously bundled connection + schema + Styles into one object; `Configuration`-prefixed code names like `RawConfiguration` or `ConfigurationId` were renamed to their `Connection`/`SavedConnection` forms, see epic #2296); proxy endpoint (removed — see ADR `unify-docker-image-remove-sagemaker-variant`)

**Direct Connection**: A Connection whose requests the browser sends to the **Database URL** itself instead of through the **Proxy Server**. The database must allow cross-origin requests from the Graph Explorer page, and Proxy Server capabilities such as IAM signing don't apply. A supported option for databases that only the browser can reach or that allow CORS. See ADR `unify-docker-image-remove-sagemaker-variant`. _Avoid_: public endpoint, non-proxy connection
**Proxy Connection**: A Connection whose requests go through the same-origin **Proxy Server**, which reaches the **Database URL** on the browser's behalf. The default, and the only kind that can use IAM authentication, because only the Proxy Server can sign a request. _Avoid_: server connection

**Direct Connection**: A Connection whose requests the browser sends to the **Database URL** itself instead of through the **Proxy Server**, so the database must allow cross-origin requests from the Graph Explorer page. A supported option for databases that only the browser can reach or that already allow CORS. _Avoid_: public endpoint, non-proxy connection, browser connection

**Database URL**: The endpoint of a Connection's Graph Database, stored as `graphDbUrl`. The **Proxy Server** sends database requests here, so it must be reachable from the host running Graph Explorer, not from the browser, except for a **Direct Connection**. _Avoid_: Graph Connection URL, graph DB URL

Expand Down
2 changes: 1 addition & 1 deletion docs/adr/20260612-connection-links.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ The form renders in place inside the app shell rather than as a portaled modal.
## Consequences

- The contract other code and external integrators depend on is the parameter set (`graphDbUrl`, `queryEngine`, `awsRegion`, `serviceType`, `name`) and the three-intent model, both in `core/connectionLink`. Parameters are validated with zod: an absent optional param takes its default, while an explicit unsupported value rejects the link, so a link never connects with settings it did not ask for. `queryEngine`'s default is not fixed: it resolves to `openCypher` when `serviceType` is `neptune-graph` and to `gremlin` otherwise, and an explicit `queryEngine` is kept whatever the `serviceType`. `neptune-graph` also requires `awsRegion`, since Neptune Analytics only accepts IAM-signed requests and a region is what turns IAM on. `graphDbUrl` also cannot contain a backslash. URL parsing reads one as a slash, so `https://evil.tld\@prod.neptune.amazonaws.com` would resolve to `evil.tld` while the create form shows what looks like a Neptune host.
- A link never proposes a **Direct Connection**; there is no parameter for one. The user can still opt into one through the checkbox in the pre-filled form, as in any create form.
- A link never proposes a **Direct Connection**; there is no parameter for one. The user can still opt into one through the "Connection method" choice in the pre-filled form, as in any create form.
- A link can switch to or pre-fill a connection, but it can never create or connect to a new database without the user submitting the form. Unless the user opts into a Direct Connection there, connections a link creates route through the **Proxy Server**, so `PROXY_SERVER_ALLOWED_DB_ORIGINS` also bounds what a link can reach when that variable is set. It is unset by default. A link without IAM can still match an existing **Direct Connection** to the same URL, whose requests bypass the proxy as they always do; a link requesting IAM never matches one, because a Direct Connection cannot sign. See [security reference](../references/security.md).
- Parameters are plaintext, not an encoded token. This was deliberate: links are meant to be human-readable and constructible by any integrator. The trust gate is the create form plus the proxy allowlist, not obscurity.
- The active connection is scoped per tab (see [Per-tab Active Connection ADR](20260618-per-tab-active-connection.md)): it lives in that tab's `sessionStorage`, seeded at cold start from a shared, last-writer-wins breadcrumb. A link resolves and activates against the tab it opens in, so it never changes what another open tab is viewing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Eliminate the separate SageMaker image by:

2. **Resolving API routes from the document's own path** — the client builds API routes (sparql, gremlin, openCypher, defaultConnection, etc.) with `apiUrl()`, which cuts the last occurrence of the static mount segment (`STATIC_MOUNT_PATH`, `/explorer`) out of `location.pathname` and joins the endpoint onto what is left, against `location.origin`. The server mounts static files at `/explorer` and API routes at `/`, so removing that segment lands on the API root at any external prefix. A path that has no mount segment at all means a reverse proxy renamed it away, and that throws `ReverseProxyMisconfiguredError` rather than guessing. `fetchDatabaseRequest()` resolves database routes with `apiUrl()` for every connection except a direct one (see decision 3).

3. **Routing through the proxy by default, with direct connections as a supported option** — remove `url` (proxy endpoint) from the connection model. The client sends requests to the same-origin proxy server, and the connection config simplifies to: database endpoint, query engine, and optional IAM settings. Direct connections stay available, marked `proxyConnection: false`, where the browser calls `graphDbUrl` itself without the proxy-only headers. IAM authentication belongs to the proxy route, since only the proxy can sign a request.
3. **Routing through the proxy by default, with direct connections as a supported option** — remove `url` (proxy endpoint) from the connection model. The client sends requests to the same-origin proxy server, and the connection config simplifies to: database endpoint, query engine, and optional IAM settings. Direct connections stay available, marked `proxyConnection: false`, where the browser calls `graphDbUrl` itself without the proxy-only headers. The connection form presents both as a "Connection method" choice, "Via proxy server" (the default) or "Directly via browser", and offers IAM authentication only on the proxy route, since only the proxy can sign a request.

4. **Moving SageMaker defaults to runtime** — `process-environment.sh` reads `NEPTUNE_NOTEBOOK=true` at container startup and writes port/log-style/SSL settings to `.env`. The Dockerfile no longer sets these, allowing the app's built-in defaults (port 80, default log style) to apply when the variable is absent.

Expand All @@ -31,9 +31,9 @@ Eliminate the separate SageMaker image by:
- **Derive the proxy endpoint automatically but keep the field.** Removes the configuration burden without removing the concept, leaving a vestigial field in the Connection model and in every exported file. The exported connection file still writes `url`, but only as a write-only compatibility field for older importers (see Consequences), not as part of the model.
- **Move the database endpoint into server configuration entirely, so the browser never names a database URL.** This would remove the need for `PROXY_SERVER_ALLOWED_DB_ORIGINS`, but it contradicts the client-owns-its-connections model described in `docs/agents/product.md`, and it is a much larger change.

Deprecating direct connections and removing them in a follow-up was the closest alternative. The relative-URL work alone unifies the image, so removal was possible, but it costs users the two things only the direct route offers. A restricted network can let the browser reach a database that the server cannot. A public, CORS-permissive endpoint works from the browser with no server involved. The price of keeping the route is two request paths and the feature gates that give the direct path fewer capabilities than the proxy path.
Deprecating direct connections and removing them in a follow-up was the closest alternative. The relative-URL work alone unifies the image, so removal was possible, but it costs users the two things only the direct route offers. A restricted network can let the browser reach a database that the server cannot. A public, CORS-permissive endpoint works from the browser with no server involved. The price of keeping the route is two request paths and the feature gates that give the direct path fewer capabilities than the proxy path. That price is paid once, in one place, and the form names the main gaps on the "Directly via browser" choice.

Amazon Neptune sends no CORS headers, so a browser could never reach Neptune directly. A maintainer confirms this on issue [#244](https://github.com/aws/graph-explorer/issues/244): the proxy server is required for accessing Neptune, even with local VPC access. That is why the proxy is the default. The direct path still works against public, CORS-permissive SPARQL endpoints, and that was a deliberate investment. See issue [#530](https://github.com/aws/graph-explorer/issues/530) with PR [#529](https://github.com/aws/graph-explorer/pull/529), and issue [#393](https://github.com/aws/graph-explorer/issues/393). A container with internet access can route those endpoints through the proxy, but nothing requires users to.
Amazon Neptune sends no CORS headers, so a browser could never reach Neptune directly. A maintainer confirms this on issue [#244](https://github.com/aws/graph-explorer/issues/244): the proxy server is required for accessing Neptune, even with local VPC access. That is why the proxy is the default and why the proxy card says it works with Amazon Neptune. The direct path still works against public, CORS-permissive SPARQL endpoints, and that was a deliberate investment. See issue [#530](https://github.com/aws/graph-explorer/issues/530) with PR [#529](https://github.com/aws/graph-explorer/pull/529), and issue [#393](https://github.com/aws/graph-explorer/issues/393). A container with internet access can route those endpoints through the proxy, but nothing requires users to.

The direct path does not offer IAM authentication, query cancellation, server-side logging, or `PROXY_SERVER_ALLOWED_DB_ORIGINS` enforcement. Issue [#1599](https://github.com/aws/graph-explorer/issues/1599) treats the direct path firing unintentionally as a bug. The removal tracked by issue [#1618](https://github.com/aws/graph-explorer/issues/1618), with [#1622](https://github.com/aws/graph-explorer/issues/1622), [#1625](https://github.com/aws/graph-explorer/issues/1625), and [#539](https://github.com/aws/graph-explorer/issues/539), is no longer planned.

Expand All @@ -43,7 +43,7 @@ The direct path does not offer IAM authentication, query cancellation, server-si

- One image to build, test, scan, and publish — halves CI time for Docker.
- Users no longer need to figure out or configure the proxy server URL.
- The connection form simplifies to the database endpoint and auth settings, plus a direct option.
- The connection form simplifies to the database endpoint, a "Connection method" choice, and IAM settings that appear only on the proxy route.
- Deployments behind arbitrary reverse proxies (not just Jupyter) work without build-time configuration.
- Removes ~20 lines of conditional Dockerfile logic and the two-path defaultConnection fallback hack in the client.

Expand Down
10 changes: 6 additions & 4 deletions docs/features/connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ For guides on connecting to specific databases, see [Connecting to databases](..
- **Name:** Enter a name for your connection (e.g., `MyNeptuneCluster`).
- **Database URL:** Provide the endpoint URL for your graph database (e.g., `https://[NEPTUNE_ENDPOINT]:8182`). Ensure that the URL does not end with `/`.
- **Query Language:** Choose a query language that corresponds to your graph database.
- **Use AWS IAM authentication:** Check this box if connecting to Amazon Neptune using IAM Auth and SigV4 signed requests. Checking it reveals the **AWS Region** and **Service Type** fields.
- **Connection method:** Choose how requests reach the database.
- **Via proxy server** (default): the Graph Explorer server sends requests to your database. This works with Amazon Neptune, supports IAM authentication, query cancellation, and server-side logging, and needs no CORS setup on the database.
- **Directly via browser:** your browser sends requests to the database itself. The database must allow cross-origin requests (CORS) from the Graph Explorer page, and IAM authentication, query cancellation, and server-side logging aren't available. When Graph Explorer is served over HTTPS, the browser usually blocks an `http://` Database URL unless it points at a loopback host such as `localhost`; see [Insecure Database URL](../guides/troubleshooting.md#insecure-database-url). Use it for databases that only your browser can reach, or that already allow CORS.
- **Use AWS IAM authentication:** Available with **Via proxy server**. Check this box if connecting to Amazon Neptune using IAM Auth and SigV4 signed requests. The Graph Explorer server signs requests with its own AWS credentials, not yours. Checking it reveals the **AWS Region** and **Service Type** fields.
- **AWS Region:** Specify the AWS region where the Neptune cluster is hosted (e.g., us-east-1).
- **Service Type:** Choose the service type: **Neptune DB** or **Neptune Analytics**.

The next three settings are grouped under an **Advanced options** section that you expand to reach. It starts expanded when the connection you are editing already overrides one of them, so an existing override is never hidden from you.
The next two settings are grouped under an **Advanced options** section that you expand to reach. It starts expanded when the connection you are editing already overrides one of them, so an existing override is never hidden from you.

- **Fetch Timeout:** Check **Enable Fetch Timeout** to reveal **Fetch Timeout (ms)**, then specify the timeout for the fetch request.
- **Neighbor Expansion Limit:** Check **Override Default Neighbor Expansion Limit** to reveal this field, then specify the default limit for neighbor expansion. This will override the app setting for neighbor expansion.
- **Connect directly from the browser:** Check this box to have your browser send requests to the database itself instead of through the Graph Explorer server. The database must allow cross-origin requests (CORS) from the Graph Explorer page, and IAM authentication isn't available, so the IAM fields are hidden. When Graph Explorer is served over HTTPS, the browser usually blocks an `http://` Database URL unless it points at a loopback host such as `localhost`. See [Insecure Database URL](../guides/troubleshooting.md#insecure-database-url).

## Available Connections

Expand Down Expand Up @@ -93,7 +95,7 @@ A link matches an existing connection only when its Database URL, query language
- the same `graphDbUrl` (normalized and compared case-insensitively, so a trailing slash or stray whitespace on either side doesn't prevent a match) and the same `queryEngine`, and
- the same auth posture: whether IAM is on (a link enables it by providing `awsRegion`), and when it is on, the same `awsRegion` and `serviceType`.

A direct connection (**Connect directly from the browser**) never uses IAM, so a link with `awsRegion` never matches one, while a link without it can. Its requests then go from your browser to the database as they always do, not through the Graph Explorer server.
A connection that connects **Directly via browser** never uses IAM, so a link with `awsRegion` never matches one, while a link without it can. Its requests then go from your browser to the database as they always do, not through the Graph Explorer server.

Authentication is part of a connection's identity: a link requesting IAM in a region is a _different_ connection from a plaintext one to the same Database URL, and vice versa. A link whose auth posture differs from every existing connection never silently reuses one. It opens the pre-filled create form instead, where you can review the authentication settings before connecting.

Expand Down
1 change: 1 addition & 0 deletions docs/guides/connecting-to-neptune.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Graph Explorer connects to Amazon Neptune through its proxy server, which forwar
- Name: `My Neptune Cluster`
- Database URL: `https://{your-cluster-endpoint}:8182`
- Query Language: Choose the query language for your graph
- Connection method: **Via proxy server**. Amazon Neptune sends no CORS headers, so a browser can't reach it directly.
- Use AWS IAM authentication: checked if IAM authentication is enabled on your cluster. Checking it reveals the AWS Region and Service Type fields.
- AWS Region: your cluster's region (e.g., `us-east-1`)
- Service Type: **Neptune DB** (or **Neptune Analytics**)
Expand Down
Loading
Loading