Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: default enable allowDynamicBackends with better unsupported errors #995

Merged
merged 10 commits into from
Oct 15, 2024
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
67 changes: 2 additions & 65 deletions documentation/docs/backend/Backend/Backend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,9 @@ import {Fiddle} from '@site/src/components/fiddle';

The **`Backend` constructor** lets you dynamically create new [Fastly Backends](https://developer.fastly.com/reference/api/services/backend/) for your Fastly Compute service.

Dynamically creating new [Fastly Backends](https://developer.fastly.com/reference/api/services/backend/) is disabled by default for Fastly Services. Please contact [Fastly Support](https://support.fastly.com/hc/requests/new?ticket_form_id=360000269711) to request the feature be enabled on the Fastly Services which require Dynamic Backends.
>**Note**: Dynamic backends are by default disabled at the Fastly service level. Contact [Fastly Support](https://support.fastly.com/hc/en-us/requests/new?ticket_form_id=360000269711) to request dynamic backends on Fastly Services.

By default, Dynamic Backends are disabled within a JavaScript application as it can be a potential avenue for third-party JavaScript code to send requests, potentially including sensitive/secret data, off to destinations that the JavaScript project was not intending, which could be a security issue.

To enable Dynamic Backends the application will need to explicitly allow Dynamic Backends via:

```js
import { allowDynamicBackends } from "fastly:experimental";
allowDynamicBackends(true);
```

**Note**: Backend constructors can only be used when processing requests, not during build-time initialization.
To disable the usage of dynamic backends, see [enforceExplicitBackends](../enforceExplicitBackends.mdx).

## Syntax

Expand Down Expand Up @@ -122,58 +113,8 @@ A new `Backend` object.

## Examples

In this example an implicit Dynamic Backend is created when making the fetch request to <https://www.fastly.com/> and the response is then returned to the client.
<Fiddle config={{
"type": "javascript",
"title": "Implicit Dynamic Backend Example",
"origins": [
"https://http-me.glitch.me"
],
"src": {
"deps": "{\n \"@fastly/js-compute\": \"^1.0.1\"\n}",
"main": `
/// <reference types="@fastly/js-compute" />
import { allowDynamicBackends } from "fastly:experimental";
allowDynamicBackends(true);
async function app() {
// For any request, return the fastly homepage -- without defining a backend!
return fetch('https://www.fastly.com/');
}
addEventListener("fetch", event => event.respondWith(app(event)));
`
},
"requests": [
{
"enableCluster": true,
"enableShield": false,
"enableWAF": false,
"method": "GET",
"path": "/status=200",
"useFreshCache": false,
"followRedirects": false,
"tests": "",
"delay": 0
}
],
"srcVersion": 1
}}>

```js
/// <reference types="@fastly/js-compute" />
import { allowDynamicBackends } from "fastly:experimental";
allowDynamicBackends(true);
async function app() {
// For any request, return the fastly homepage -- without defining a backend!
return fetch('https://www.fastly.com/');
}
addEventListener("fetch", event => event.respondWith(app(event)));
```

</Fiddle>

In this example an explicit Dynamic Backend is created and supplied to the fetch request, the response is then returned to the client.


<Fiddle config={{
"type": "javascript",
"title": "Explicit Dynamic Backend Example",
Expand All @@ -184,9 +125,7 @@ In this example an explicit Dynamic Backend is created and supplied to the fetch
"deps": "{\n \"@fastly/js-compute\": \"^1.0.1\"\n}",
"main": `
/// <reference types="@fastly/js-compute" />
import { allowDynamicBackends } from "fastly:experimental";
import { Backend } from "fastly:backend";
allowDynamicBackends(true);
async function app() {
// For any request, return the fastly homepage -- without defining a backend!
const backend = new Backend({
Expand Down Expand Up @@ -225,9 +164,7 @@ addEventListener("fetch", event => event.respondWith(app(event)));

```js
/// <reference types="@fastly/js-compute" />
import { allowDynamicBackends } from "fastly:experimental";
import { Backend } from "fastly:backend";
allowDynamicBackends(true);
async function app() {
// For any request, return the fastly homepage -- without defining a backend!
const backend = new Backend({
Expand Down
76 changes: 76 additions & 0 deletions documentation/docs/backend/Backend/prototype/name.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
hide_title: false
hide_table_of_contents: false
pagination_next: null
pagination_prev: null
---
import {Fiddle} from '@site/src/components/fiddle';

# name

The read-only **`name`** property of the backend returns the backend name string.

## Value

A `string`.

## Description

Provides the name of the backend.

## Examples

### Using name

The following example logs the string value of a [Backend](../Backend.mdx) object:

<Fiddle config={{
"type": "javascript",
"title": "Backend.prototype.name Example",
"origins": [
"https://http-me.glitch.me"
],
"src": {
"deps": "{\n \"@fastly/js-compute\": \"^1.0.1\"\n}",
"main": `
/// <reference types=\"@fastly/js-compute\" />
import { Backend } from "fastly:backend";
async function app() {
const backend = new Backend({
name: "fastly",
target: "fastly.com",
});
console.log(backend.name); // "fastly"
}
addEventListener("fetch", event => event.respondWith(app(event)));
`
},
"requests": [
{
"enableCluster": true,
"enableShield": false,
"enableWAF": false,
"method": "GET",
"path": "/status=200",
"useFreshCache": false,
"followRedirects": false,
"tests": "",
"delay": 0
}
],
"srcVersion": 1
}}>

```js
import { Backend } from "fastly:backend";
async function app() {
const backend = new Backend({
name: "fastly",
target: "fastly.com",
});
console.log(backend.name); // "fastly"
}
addEventListener("fetch", event => event.respondWith(app(event)));
```

</Fiddle>
6 changes: 6 additions & 0 deletions documentation/docs/backend/Backend/prototype/toName.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ pagination_prev: null

# Backend.prototype.toName()

:::info

This method is deprecated, use [`Backend.prototype.name`](./name.mdx) instead.

:::

The **`toName()`** method returns the name associated with the `Backend` instance.

## Syntax
Expand Down
6 changes: 6 additions & 0 deletions documentation/docs/backend/Backend/prototype/toString.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import {Fiddle} from '@site/src/components/fiddle';

# toString

:::info

This method is deprecated, use [`Backend.prototype.name`](./name.mdx) instead.

:::

The **`toString()`** method returns a string representing the specified Backend value.

## Syntax
Expand Down
38 changes: 38 additions & 0 deletions documentation/docs/backend/allowDynamicBackends.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
hide_title: false
hide_table_of_contents: false
pagination_next: null
pagination_prev: null
---
import {Fiddle} from '@site/src/components/fiddle';

# allowDynamicBackends

:::info

This method is deprecated, and dynamic backends are now always supported when enabled at the service level. See [`enforceExplicitBackends`](./enforceExplicitBackends.mdx) instead.

:::

The **`allowDynamicBackends()`** function is used to control whether or not Dynamic Backends should be allowed within this Fastly Compute Service.

By default, Dynamic Backends are enabled, but can be a potential security concern since third-party JavaScript code may send arbitrary requests, potentially including sensitive/secret data, off to destinations that the JavaScript project was not intending.

Using `allowDynamicBackends(false)` this security property can be restored to only use explicit backend definitions.

>**Note**: By default, while dynamic backends are allowed in the SDK, they are by default disabled at the Fastly service level.

## Syntax

```js
allowDynamicBackends(enabledOrConfig)
```

### Parameters

- `enabled` _: boolean_
- Whether or not to allow Dynamic Backends

### Return value

`undefined`.
43 changes: 43 additions & 0 deletions documentation/docs/backend/enforceExplicitBackends.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
hide_title: false
hide_table_of_contents: false
pagination_next: null
pagination_prev: null
---

# enforceExplicitBackends

Call this function to enforce the security property of explicitly-defined backends, even when dynamic backends are enabled at
the Fastly service level.

By default, if dynamic backends are supported for the Fastly service, they will be automatically used when creating a new
`fetch()` request. This default behaviour for dynamic backends can be a potential security concern since third-party JavaScript
code may send arbitrary requests, including sensitive/secret data, off to destinations that the JavaScript project was not
intending.

When calling this function, an optional default backend name can be provided.

>**Note**: This is a separate option to the service-level dynamic backend support for Fastly services, which is by deault disabled for Fastly services.

The **`enforceExplicitBackends()`** function is used to control whether or not Dynamic Backends should be allowed within this Fastly Compute Service.

By default, Dynamic Backends are enabled, but can be a potential security concern since third-party JavaScript code may send arbitrary requests, potentially including sensitive/secret data, off to destinations that the JavaScript project was not intending.

Using `allowDynamicBackends(false)` this security property can be restored to only use explicit backend definitions.

>**Note**: Dynamic Backends are disabled by default for Fastly Services. Please contact [Fastly Support](https://support.fastly.com/hc/requests/new?ticket_form_id=360000269711) to request the feature be enabled or disabled on Fastly Services.

## Syntax

```js
enforceExplicitBackends(defaultBackend?)
```

### Parameters

- `defaultBackend` _: string_ _**optional**_
- An optional default backend string name to use in `fetch()` requests.

### Return value

`undefined`.
20 changes: 20 additions & 0 deletions documentation/docs/globals/fetch.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ not_ reject on HTTP errors (`404`, etc.). Instead, a
> **Note:** The `fetch()` method's parameters are identical to
> those of the `Request()` constructor.

## Explicit Backends

Internally, Fastly uses named backends to handle fetch requests, which need to be explicitly defined to enable custom HTTP origins to be fetched by the service.

This `backend` option is then a special Fastly-specific fetch option that is provided to the `fetch()` call:

```js
fetch('https://origin.com/path', { backend: 'origin' });
```

Backends are configured using the Fastly service backend configuration, see the [Backend documentation](https://developer.fastly.com/reference/api/services/backend/) for more information.

## Dynamic Backends

Dynamic backends are a compute feature that allow services to define backends for themselves. This is a service-level Fastly feature that must be enabled through [Fastly Support](https://support.fastly.com/hc/en-us/requests/new?ticket_form_id=360000269711).

When dynamic backends are enabled at the service level, the explicit `backend` option is no longer required for `fetch()` requests, and will instead be automatically created.

In addition, custom backend confiuration options can then also be provided through the [`Backend()`](../fastly:backend/Backend/Backend.mdx) constructor.

## Syntax

```js
Expand Down
19 changes: 17 additions & 2 deletions integration-tests/js-compute/fixtures/app/src/dynamic-backend.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/// <reference path="../../../../../types/index.d.ts" />
import { Backend, setDefaultDynamicBackendConfig } from 'fastly:backend';
import { CacheOverride } from 'fastly:cache-override';
import {
Backend,
setDefaultDynamicBackendConfig,
enforceExplicitBackends,
} from 'fastly:backend';
import { allowDynamicBackends } from 'fastly:experimental';
import { CacheOverride } from 'fastly:cache-override';
import {
assert,
assertDoesNotThrow,
Expand Down Expand Up @@ -55,6 +59,10 @@ routes.set('/backend/timeout', async () => {
allowDynamicBackends(true);
await assertResolves(() => fetch('https://http-me.glitch.me/headers'));
await assertResolves(() => fetch('https://www.fastly.com'));
enforceExplicitBackends();
await assertRejects(() => fetch('https://www.fastly.com'));
enforceExplicitBackends('TheOrigin');
await assertResolves(() => fetch('https://www.fastly.com'));
});
routes.set(
'/implicit-dynamic-backend/dynamic-backends-enabled-called-twice',
Expand Down Expand Up @@ -225,6 +233,7 @@ routes.set('/backend/timeout', async () => {
actual = Reflect.ownKeys(Backend.prototype);
expected = [
'constructor',
'name',
'isDynamic',
'target',
'hostOverride',
Expand Down Expand Up @@ -2432,6 +2441,9 @@ routes.set('/backend/timeout', async () => {
{
const backend = createValidFastlyBackend() ?? validFastlyBackend;
strictEqual(backend.isDynamic, true, 'isDymamic');
strictEqual(backend.name, 'fastly');
strictEqual(backend.toString(), 'fastly');
strictEqual(backend.toName(), 'fastly');
strictEqual(backend.target, 'www.fastly.com', 'target');
strictEqual(backend.hostOverride, 'www.fastly.com', 'override');
strictEqual(backend.port, 443, 'port');
Expand Down Expand Up @@ -2466,6 +2478,9 @@ routes.set('/backend/timeout', async () => {
{
const backend = createValidHttpMeBackend() ?? validHttpMeBackend;
strictEqual(backend.isDynamic, true, 'isDynamic');
strictEqual(backend.name, 'http-me');
strictEqual(backend.toString(), 'http-me');
strictEqual(backend.toName(), 'http-me');
strictEqual(backend.target, 'http-me.glitch.me', 'target');
strictEqual(backend.hostOverride, 'http-me.glitch.me', 'hostOverride');
strictEqual(backend.port, 443, 'port');
Expand Down
Loading
Loading