Skip to content

Commit ad7b5ec

Browse files
authored
Execute Playground code on a separate origin (#285)
Why We want to execute Playground code on a separate origin, so that scripts are completely isolated from the main origin. In particular, scripts loaded through the "share" feature are not controlled by us, and often are written by another user to the person running it. On a site that has access to e.g. sensitive user data or APIs on the main origin, this would be very important for security. That's why Playground warns in the console when it detects same-origin execution. Our site is 100% static, so there's pretty limited risks -- an attacker could e.g. modify some page content, navigate the main window, etc. If we did something like integrate with GitHub gists for shorter Playground URLs, then an attacker might then be able to make authenticated GitHub requests through shared Playground code. So it seems like a good idea to close this hole before launch. How We have a new Cloud Run service called lit-dev-playground. Its URL is https://lit-dev-playground-5ftespv5na-uc.a.run.app/, and PR revisions have the same pr<PR>-<SHA> prefix that the main service has. When we go live, the URL will be https://playground.lit.dev When we do an Eleventy build, the PLAYGROUND_SANDBOX environment variable is rendered into the HTML everywhere we instantiate a <playground-ide> or <playground-project> using the sandbox-base-url attribute. This attribute tells Playground to interact with a Service Worker at that URL, instead of the default one on the same origin. The server has a new MODE environment variable switch. When it's set to playground, it only serves the js/ directory, instead of the full site. It
1 parent ce3fdf0 commit ad7b5ec

File tree

15 files changed

+187
-46
lines changed

15 files changed

+187
-46
lines changed

Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ RUN npx lerna run build --scope lit-dev-api --stream && \
4343

4444
# Site content
4545
COPY packages/lit-dev-content/ ./packages/lit-dev-content/
46+
ARG PLAYGROUND_SANDBOX
47+
# Kaniko doesn't include ARG values in the layer cache key (see
48+
# https://github.com/GoogleContainerTools/kaniko/pull/1085). This is different
49+
# to normal Docker behavior, which would invalidate anything after the ARG
50+
# declaration if the value changes. So, we need to write it to the file system
51+
# to force a cache invalidation. Otherwise, we might re-use the most recent
52+
# Eleventy build output, even when the playground sandbox URL has changed.
53+
RUN echo "$PLAYGROUND_SANDBOX" > playground-sandbox
4654
RUN npx lerna run build --scope lit-dev-content --stream
4755

4856
# Run the web service on container startup.

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ Dev mode is different to production in these ways:
5050
are reflected immediately after `tsc` compile.
5151
- HTML is not minified.
5252

53-
If needed, you can check for dev mode from an Eleventy template using the `dev`
54-
global:
53+
If needed, you can check for dev mode from an Eleventy template using the
54+
`env.DEV` global:
5555

5656
```
57-
{% if dev %}
57+
{% if env.DEV %}
5858
<p>Dev mode</p>
5959
{% else %}
6060
<p>Prod mode</p>
@@ -110,6 +110,7 @@ Serves at [`http://localhost:8080`](http://localhost:8080)
110110
### Start production Docker environment locally
111111

112112
```sh
113-
docker build -t litdev .
114-
docker run --rm --name litdev -p 8080:8080 litdev
113+
docker build -t litdev . --build-arg PLAYGROUND_SANDBOX=http://localhost:8081/
114+
docker run --rm --name litdev -p 8080:8080 -e PORT=8080 -e MODE=main litdev
115+
docker run --rm --name litdev-playground -p 8081:8081 -e PORT=8081 -e MODE=playground litdev
115116
```

cloudbuild-main.yaml

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,31 @@ steps:
88
# https://docs.docker.com/engine/reference/commandline/build/
99
# https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/docker
1010
# https://cloud.google.com/build/docs/kaniko-cache
11-
- id: Build
11+
- id: build
1212
name: gcr.io/kaniko-project/executor
1313
args:
1414
- --dockerfile=./Dockerfile
15-
- --destination=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
15+
- --destination=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/lit-dev:$COMMIT_SHA
1616
- --cache=true
1717
- --cache-ttl=168h # 1 week
18+
# Bake in the playground sandbox url
19+
- --build-arg=PLAYGROUND_SANDBOX=https://lit-dev-playground-5ftespv5na-uc.a.run.app/
1820

19-
# Create a new Cloud Run revision.
21+
# Create a new Cloud Run revision for the main site.
2022
#
2123
# https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy
2224
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker
23-
- id: Deploy
25+
- id: deploy-main
2426
name: gcr.io/google.com/cloudsdktool/cloud-sdk
2527
entrypoint: gcloud
2628
args:
2729
- beta
2830
- run
2931
- deploy
30-
- $_SERVICE_NAME
32+
- lit-dev # Service name
3133
- '--region=$_DEPLOY_REGION'
3234
- '--platform=managed'
33-
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
35+
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/lit-dev:$COMMIT_SHA'
3436
- '--quiet'
3537
- '--no-traffic'
3638
- '--tag=master-$SHORT_SHA'
@@ -42,20 +44,80 @@ steps:
4244
- '--concurrency=40'
4345
- '--min-instances=1'
4446
- '--max-instances=1000'
47+
# Serve the main site
48+
- '--update-env-vars=MODE=main'
4549

46-
# Route traffic to new revision.
50+
# Create a new Cloud Run revision for the Playground sandbox.
51+
#
52+
# https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy
53+
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker
54+
- id: deploy-playground
55+
name: gcr.io/google.com/cloudsdktool/cloud-sdk
56+
entrypoint: gcloud
57+
waitFor:
58+
# Don't wait for main site deploy
59+
- build
60+
args:
61+
- beta
62+
- run
63+
- deploy
64+
- lit-dev-playground # Service name
65+
- '--region=$_DEPLOY_REGION'
66+
- '--platform=managed'
67+
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/lit-dev:$COMMIT_SHA'
68+
- '--quiet'
69+
- '--no-traffic'
70+
- '--tag=master-$SHORT_SHA'
71+
# IMPORTANT: If you change --memory, be sure to also change
72+
# --max-old-space-size in ./Dockerfile, and this same flag in
73+
# ./cloudbuild-pr.yaml
74+
- '--memory=1Gi'
75+
- '--cpu=1'
76+
- '--concurrency=40'
77+
- '--min-instances=1'
78+
- '--max-instances=1000'
79+
# Serve the playground files
80+
- '--update-env-vars=MODE=playground'
81+
82+
# Route traffic to new revision for the playground.
4783
#
4884
# https://cloud.google.com/sdk/gcloud/reference/beta/run/services
4985
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker
50-
- id: Route Traffic
86+
- id: route-traffic-main
5187
name: gcr.io/google.com/cloudsdktool/cloud-sdk
5288
entrypoint: gcloud
89+
waitFor:
90+
# Route traffic simultaneously once both deploys are done
91+
- deploy-main
92+
- deploy-playground
5393
args:
5494
- beta
5595
- run
5696
- services
5797
- update-traffic
58-
- $_SERVICE_NAME
98+
- lit-dev # Service name
99+
- '--region=$_DEPLOY_REGION'
100+
- '--platform=managed'
101+
- '--quiet'
102+
- '--to-tags=master-$SHORT_SHA=100'
103+
104+
# Route traffic to new revision for the main site.
105+
#
106+
# https://cloud.google.com/sdk/gcloud/reference/beta/run/services
107+
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker
108+
- id: route-traffic-playground
109+
name: gcr.io/google.com/cloudsdktool/cloud-sdk
110+
entrypoint: gcloud
111+
waitFor:
112+
# Route traffic simultaneously once both deploys are done
113+
- deploy-main
114+
- deploy-playground
115+
args:
116+
- beta
117+
- run
118+
- services
119+
- update-traffic # Service name
120+
- lit-dev-playground
59121
- '--region=$_DEPLOY_REGION'
60122
- '--platform=managed'
61123
- '--quiet'

cloudbuild-pr.yaml

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,31 @@ steps:
1212
# https://docs.docker.com/engine/reference/commandline/build/
1313
# https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/docker
1414
# https://cloud.google.com/build/docs/kaniko-cache
15-
- id: Build
15+
- id: build
1616
name: gcr.io/kaniko-project/executor
1717
args:
1818
- --dockerfile=./Dockerfile
19-
- --destination=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
19+
- --destination=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/lit-dev:$COMMIT_SHA
2020
- --cache=true
2121
- --cache-ttl=168h # 1 week
22+
# Bake in this revision's corresponding playground sandbox url
23+
- --build-arg=PLAYGROUND_SANDBOX=https://pr$_PR_NUMBER-$SHORT_SHA---lit-dev-playground-5ftespv5na-uc.a.run.app/
2224

23-
# Create a new Cloud Run revision.
25+
# Create a new Cloud Run revision for the main site.
2426
#
2527
# https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy
2628
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker
27-
- id: Deploy
29+
- id: deploy-main
2830
name: gcr.io/google.com/cloudsdktool/cloud-sdk
2931
entrypoint: gcloud
3032
args:
3133
- beta
3234
- run
3335
- deploy
34-
- $_SERVICE_NAME
36+
- lit-dev # Service name
3537
- '--region=$_DEPLOY_REGION'
3638
- '--platform=managed'
37-
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
39+
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/lit-dev:$COMMIT_SHA'
3840
- '--quiet'
3941
- '--no-traffic'
4042
- '--tag=pr$_PR_NUMBER-$SHORT_SHA'
@@ -46,6 +48,40 @@ steps:
4648
- '--concurrency=default' # unlimited
4749
- '--min-instances=0'
4850
- '--max-instances=1'
51+
# Serve the main site
52+
- '--update-env-vars=MODE=main'
53+
54+
# Create a new Cloud Run revision for the playground sandbox.
55+
#
56+
# https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy
57+
# https://github.com/GoogleCloudPlatform/cloud-sdk-docker
58+
- id: deploy-playground
59+
name: gcr.io/google.com/cloudsdktool/cloud-sdk
60+
entrypoint: gcloud
61+
waitFor:
62+
# Don't wait for main site to deploy
63+
- build
64+
args:
65+
- beta
66+
- run
67+
- deploy
68+
- lit-dev-playground # Service name
69+
- '--region=$_DEPLOY_REGION'
70+
- '--platform=managed'
71+
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/lit-dev:$COMMIT_SHA'
72+
- '--quiet'
73+
- '--no-traffic'
74+
- '--tag=pr$_PR_NUMBER-$SHORT_SHA'
75+
# IMPORTANT: If you change --memory, be sure to also change
76+
# --max-old-space-size in ./Dockerfile, and this same flag in
77+
# ./cloudbuild-main.yaml
78+
- '--memory=1Gi'
79+
- '--cpu=1'
80+
- '--concurrency=default' # unlimited
81+
- '--min-instances=0'
82+
- '--max-instances=1'
83+
# Serve the playground
84+
- '--update-env-vars=MODE=playground'
4985

5086
tags:
5187
- lit-dev

packages/lit-dev-content/.eleventy.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const slugify = (s) => slugifyLib(s, {lower: true});
2828

2929
const DEV = process.env.ELEVENTY_ENV === 'dev';
3030
const OUTPUT_DIR = DEV ? '_dev' : '_site';
31+
const PLAYGROUND_SANDBOX = process.env.PLAYGROUND_SANDBOX;
3132

3233
module.exports = function (eleventyConfig) {
3334
// https://github.com/JordanShurmer/eleventy-plugin-toc#readme
@@ -37,7 +38,9 @@ module.exports = function (eleventyConfig) {
3738
wrapperClass: '',
3839
});
3940
eleventyConfig.addPlugin(eleventyNavigationPlugin);
40-
eleventyConfig.addPlugin(playgroundPlugin);
41+
eleventyConfig.addPlugin(playgroundPlugin, {
42+
sandboxUrl: PLAYGROUND_SANDBOX,
43+
});
4144
if (!DEV) {
4245
// In dev mode, we symlink these directly to source.
4346
eleventyConfig.addPassthroughCopy({'rollupout/': './js/'});

packages/lit-dev-content/site/_data/dev.js

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
// Allow templates to access environment settings, e.g. if we are building in
8+
// dev mode or not with `{% if env.DEV %}`.
9+
//
10+
// https://www.11ty.dev/docs/data-js/#example-exposing-environment-variables
11+
module.exports = {
12+
DEV: process.env.ELEVENTY_ENV === 'dev',
13+
PLAYGROUND_SANDBOX: process.env.PLAYGROUND_SANDBOX,
14+
}

packages/lit-dev-content/site/_includes/default.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919

2020
<!-- Preload common chunks we always need. Note <link rel="modulepreload">
2121
isn't yet supported in Firefox or Safari. -->
22-
<script type="module" src="{{ site.baseurl }}/js/lit.js"></script>
23-
<script type="module" src="{{ site.baseurl }}/js/tslib.js"></script>
24-
<script type="module" src="{{ site.baseurl }}/js/mwc-base.js"></script>
25-
<script type="module" src="{{ site.baseurl }}/js/mwc-icon-button.js"></script>
22+
{% if not env.DEV %}
23+
<script type="module" src="{{ site.baseurl }}/js/lit.js"></script>
24+
<script type="module" src="{{ site.baseurl }}/js/tslib.js"></script>
25+
<script type="module" src="{{ site.baseurl }}/js/mwc-base.js"></script>
26+
<script type="module" src="{{ site.baseurl }}/js/mwc-icon-button.js"></script>
27+
{% endif %}
2628

2729
<link rel="preconnect" href="https://fonts.gstatic.com">
2830

packages/lit-dev-content/site/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
{% inlinecss "home.css" %}
55
{% inlinejs "pages/home.js" %}
66

7-
{% if dev %}
7+
{% if env.DEV %}
88
<!-- HACK: In dev mode, the logo renders before the stylesheet loads, so it
99
is initially visible, and then immediately fades away. This doesn't affect
1010
prod because the whole stylesheet is inlined. -->

packages/lit-dev-content/site/playground.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ <h3>{{ section.name }}</h3>
6969
</div>
7070

7171
<playground-ide
72+
{% if env.PLAYGROUND_SANDBOX %}
73+
sandbox-base-url={{ env.PLAYGROUND_SANDBOX }}
74+
{% endif %}
7275
slot="appContent"
7376
pragmas="off"
7477
resizable

0 commit comments

Comments
 (0)