Use GitLab instance as Web IDE Extension Host Domain
Issue [WebIDE] Use GitLab instance as the Web IDE's e... (#576648)
What does this MR do and why?
It implements a new mechanism to resolve CORS rules headers for HTTP requests that come from the Web IDE extension host domain origin. Before this Merge Request, the allowed origin was a static/hardcoded value set in both Workhorse and the Rack::CORS
middleware : ^https://.*.web-ide.gitlab-static.net"
. This Merge Request replaces the Workhorse's static CORS middleware with delegating to Rails for CORS headers resolution by sending an OPTIONS
request that is handled by a new middleware called WebIdeExtensionHostDomain
.
In turn, the WebIdeExtensionHostDomain
middleware uses an application setting introduced in Web IDE extension host domain application setting (!208978 - merged) rather than a static value.
Bigger picture
This Merge Request is part of the project to improve support for air-gapped/offline environments in the Web IDE: [WebIDE] Support Web IDE on GitLab Self-Managed... (&15146). The end goal is allowing customers to set up a custom wildcard domain that is used by the Web IDE to sandbox 3rd-party extensions. Rather than having a separate static assets server just like https://.*.web-ide.gitlab-static.net
, the GitLab instance itself can serve the Web IDE static assets. Workhorse doesn't support configuring dynamic CORS headers rules for static assets therefore it delegates to the GitLab Rails Application.
sequenceDiagram
participant Browser as Web Browser
participant Frontend as Frontend Server<br/>(NGINX)
participant Workhorse as GitLab Workhorse
participant Rails as GitLab Rails<br/>Application
Note over Browser,Rails: Code - OSS Static Asset Request Flow with CORS
Browser->>Frontend: GET /assets/webpack/[web-ide-vscode-workbench-file-path]<br/>Origin: https://workbench-[encrypted].gitlab-static.net
Note right of Browser: Request includes Origin header<br/>for CORS validation
Frontend->>Workhorse: Proxy request to Workhorse<br/>(reverse proxy)
Note right of Frontend: NGINX forwards request<br/>to internal Workhorse service
Workhorse->>Rails: Request CORS headers<br/>for origin validation
Note right of Workhorse: Validates if origin is allowed<br/>for this static asset
Rails->>Rails: Validate origin against<br/>allowed domains
Rails-->>Workhorse: Return CORS headers<br/>(Access-Control-Allow-Origin, etc.)
Workhorse->>Workhorse: Serve static asset<br/>from filesystem
Workhorse-->>Frontend: Static asset response<br/>+ CORS headers
Note right of Workhorse: Includes validated CORS headers<br/>with the static content
Frontend-->>Browser: Forward response with<br/>static asset + CORS headers
Note right of Browser: Browser validates CORS<br/>and loads the asset
Performance considerations
This Merge Request could impact the application's performance because the Rails service is hit to fetch static assets. I think that this implementation mitigates the performance impact for the following reasons:
-
Workhorse will only send OPTIONS HTTP requests to the Rails application for cross origin requests (a.k.a. http requests that contain the
Origin
header). In practice, the Web IDE only loads 10-12 static assets using cross-origin requests. These HTTP requests only happen once when the user opens the Web IDE and they only happen in the Web IDE page. -
The
web_ide_extension_host_domain
fully handles the OPTIONS HTTP requests sent by Workhorse and bypasses the rest of the middleware chain. Resolving CORS headers for an asset path is also a cheap operation that only requires evaluating obtaining an application setting and evaluating a regular expression. Given the database processing costs reported by the performance monitor, I assume that the query to obtain the application setting is cached too.
References
Screenshots or screen recordings
This Merge Request doesn't introduce user-facing changes.
How to set up and validate locally
-
You should have NGINX set up in your GDK. Follow these instructions to set it up.
-
Use
dnsmasq
to set up a local DNS resolver for*.test
domain using these instructions. -
Use
mkcert
to generate a TLS certificate for the domain*.web-ide.test
. -
In your GDK, add the following configuration to the NGINX conf file located
[gdk-dir]/conf/nginx.conf
)server { listen *.web-ide.test:3443 ssl; ssl_certificate /Users/enrique/gitlab/gdk/web-ide-cert.pem; ssl_certificate_key /Users/enrique/gitlab/gdk/web-ide-cert-key.pem; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_http_version 1.1; proxy_read_timeout 300; location /assets/ { proxy_pass https://gitlab-workhorse; } }
-
Compile workhorse
cd workhorse && make
. -
Go to
Admin -> Settings -> General -> Web IDE
and set the domain + portweb-ide.test:3443
. -
Restart services
gdk rails-web gitlab-workhorse nginx
. -
Open the Web IDE. Features such as Duo Chat and Markdown preview should work as expected and all assets HTTP requests go to the domain
.web-ide.test
.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.