Skip to content

Commit 4bee9e1

Browse files
committed
Merge branch 'main' into callum-cors
Signed-off-by: Callum Styan <callumstyan@gmail.com>
2 parents 53c607e + ab254ad commit 4bee9e1

File tree

7,157 files changed

+229557
-74804
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

7,157 files changed

+229557
-74804
lines changed

.cursorrules

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Cursor Rules
2+
3+
This project is called "Coder" - an application for managing remote development environments.
4+
5+
Coder provides a platform for creating, managing, and using remote development environments (also known as Cloud Development Environments or CDEs). It leverages Terraform to define and provision these environments, which are referred to as "workspaces" within the project. The system is designed to be extensible, secure, and provide developers with a seamless remote development experience.
6+
7+
## Core Architecture
8+
9+
The heart of Coder is a control plane that orchestrates the creation and management of workspaces. This control plane interacts with separate Provisioner processes over gRPC to handle workspace builds. The Provisioners consume workspace definitions and use Terraform to create the actual infrastructure.
10+
11+
The CLI package serves dual purposes - it can be used to launch the control plane itself and also provides client functionality for users to interact with an existing control plane instance. All user-facing frontend code is developed in TypeScript using React and lives in the `site/` directory.
12+
13+
The database layer uses PostgreSQL with SQLC for generating type-safe database code. Database migrations are carefully managed to ensure both forward and backward compatibility through paired `.up.sql` and `.down.sql` files.
14+
15+
## API Design
16+
17+
Coder's API architecture combines REST and gRPC approaches. The REST API is defined in `coderd/coderd.go` and uses Chi for HTTP routing. This provides the primary interface for the frontend and external integrations.
18+
19+
Internal communication with Provisioners occurs over gRPC, with service definitions maintained in `.proto` files. This separation allows for efficient binary communication with the components responsible for infrastructure management while providing a standard REST interface for human-facing applications.
20+
21+
## Network Architecture
22+
23+
Coder implements a secure networking layer based on Tailscale's Wireguard implementation. The `tailnet` package provides connectivity between workspace agents and clients through DERP (Designated Encrypted Relay for Packets) servers when direct connections aren't possible. This creates a secure overlay network allowing access to workspaces regardless of network topology, firewalls, or NAT configurations.
24+
25+
### Tailnet and DERP System
26+
27+
The networking system has three key components:
28+
29+
1. **Tailnet**: An overlay network implemented in the `tailnet` package that provides secure, end-to-end encrypted connections between clients, the Coder server, and workspace agents.
30+
31+
2. **DERP Servers**: These relay traffic when direct connections aren't possible. Coder provides several options:
32+
- A built-in DERP server that runs on the Coder control plane
33+
- Integration with Tailscale's global DERP infrastructure
34+
- Support for custom DERP servers for lower latency or offline deployments
35+
36+
3. **Direct Connections**: When possible, the system establishes peer-to-peer connections between clients and workspaces using STUN for NAT traversal. This requires both endpoints to send UDP traffic on ephemeral ports.
37+
38+
### Workspace Proxies
39+
40+
Workspace proxies (in the Enterprise edition) provide regional relay points for browser-based connections, reducing latency for geo-distributed teams. Key characteristics:
41+
42+
- Deployed as independent servers that authenticate with the Coder control plane
43+
- Relay connections for SSH, workspace apps, port forwarding, and web terminals
44+
- Do not make direct database connections
45+
- Managed through the `coder wsproxy` commands
46+
- Implemented primarily in the `enterprise/wsproxy/` package
47+
48+
## Agent System
49+
50+
The workspace agent runs within each provisioned workspace and provides core functionality including:
51+
52+
- SSH access to workspaces via the `agentssh` package
53+
- Port forwarding
54+
- Terminal connectivity via the `pty` package for pseudo-terminal support
55+
- Application serving
56+
- Healthcheck monitoring
57+
- Resource usage reporting
58+
59+
Agents communicate with the control plane using the tailnet system and authenticate using secure tokens.
60+
61+
## Workspace Applications
62+
63+
Workspace applications (or "apps") provide browser-based access to services running within workspaces. The system supports:
64+
65+
- HTTP(S) and WebSocket connections
66+
- Path-based or subdomain-based access URLs
67+
- Health checks to monitor application availability
68+
- Different sharing levels (owner-only, authenticated users, or public)
69+
- Custom icons and display settings
70+
71+
The implementation is primarily in the `coderd/workspaceapps/` directory with components for URL generation, proxying connections, and managing application state.
72+
73+
## Implementation Details
74+
75+
The project structure separates frontend and backend concerns. React components and pages are organized in the `site/src/` directory, with Jest used for testing. The backend is primarily written in Go, with a strong emphasis on error handling patterns and test coverage.
76+
77+
Database interactions are carefully managed through migrations in `coderd/database/migrations/` and queries in `coderd/database/queries/`. All new queries require proper database authorization (dbauthz) implementation to ensure that only users with appropriate permissions can access specific resources.
78+
79+
## Authorization System
80+
81+
The database authorization (dbauthz) system enforces fine-grained access control across all database operations. It uses role-based access control (RBAC) to validate user permissions before executing database operations. The `dbauthz` package wraps the database store and performs authorization checks before returning data. All database operations must pass through this layer to ensure security.
82+
83+
## Testing Framework
84+
85+
The codebase has a comprehensive testing approach with several key components:
86+
87+
1. **Parallel Testing**: All tests must use `t.Parallel()` to run concurrently, which improves test suite performance and helps identify race conditions.
88+
89+
2. **coderdtest Package**: This package in `coderd/coderdtest/` provides utilities for creating test instances of the Coder server, setting up test users and workspaces, and mocking external components.
90+
91+
3. **Integration Tests**: Tests often span multiple components to verify system behavior, such as template creation, workspace provisioning, and agent connectivity.
92+
93+
4. **Enterprise Testing**: Enterprise features have dedicated test utilities in the `coderdenttest` package.
94+
95+
## Open Source and Enterprise Components
96+
97+
The repository contains both open source and enterprise components:
98+
99+
- Enterprise code lives primarily in the `enterprise/` directory
100+
- Enterprise features focus on governance, scalability (high availability), and advanced deployment options like workspace proxies
101+
- The boundary between open source and enterprise is managed through a licensing system
102+
- The same core codebase supports both editions, with enterprise features conditionally enabled
103+
104+
## Development Philosophy
105+
106+
Coder emphasizes clear error handling, with specific patterns required:
107+
108+
- Concise error messages that avoid phrases like "failed to"
109+
- Wrapping errors with `%w` to maintain error chains
110+
- Using sentinel errors with the "err" prefix (e.g., `errNotFound`)
111+
112+
All tests should run in parallel using `t.Parallel()` to ensure efficient testing and expose potential race conditions. The codebase is rigorously linted with golangci-lint to maintain consistent code quality.
113+
114+
Git contributions follow a standard format with commit messages structured as `type: <message>`, where type is one of `feat`, `fix`, or `chore`.
115+
116+
## Development Workflow
117+
118+
Development can be initiated using `scripts/develop.sh` to start the application after making changes. Database schema updates should be performed through the migration system using `create_migration.sh <name>` to generate migration files, with each `.up.sql` migration paired with a corresponding `.down.sql` that properly reverts all changes.
119+
120+
If the development database gets into a bad state, it can be completely reset by removing the PostgreSQL data directory with `rm -rf .coderv2/postgres`. This will destroy all data in the development database, requiring you to recreate any test users, templates, or workspaces after restarting the application.
121+
122+
Code generation for the database layer uses `coderd/database/generate.sh`, and developers should refer to `sqlc.yaml` for the appropriate style and patterns to follow when creating new queries or tables.
123+
124+
The focus should always be on maintaining security through proper database authorization, clean error handling, and comprehensive test coverage to ensure the platform remains robust and reliable.

.devcontainer/devcontainer.json

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,82 @@
11
{
22
"name": "Development environments on your infrastructure",
33
"image": "codercom/oss-dogfood:latest",
4-
54
"features": {
6-
// See all possible options here https://github.com/devcontainers/features/tree/main/src/docker-in-docker
75
"ghcr.io/devcontainers/features/docker-in-docker:2": {
86
"moby": "false"
7+
},
8+
"ghcr.io/coder/devcontainer-features/code-server:1": {
9+
"auth": "none",
10+
"port": 13337
11+
},
12+
"./filebrowser": {
13+
"folder": "${containerWorkspaceFolder}"
914
}
1015
},
1116
// SYS_PTRACE to enable go debugging
12-
"runArgs": ["--cap-add=SYS_PTRACE"]
17+
"runArgs": ["--cap-add=SYS_PTRACE"],
18+
"customizations": {
19+
"vscode": {
20+
"extensions": ["biomejs.biome"]
21+
},
22+
"coder": {
23+
"apps": [
24+
{
25+
"slug": "cursor",
26+
"displayName": "Cursor Desktop",
27+
"url": "cursor://coder.coder-remote/openDevContainer?owner=${localEnv:CODER_WORKSPACE_OWNER_NAME}&workspace=${localEnv:CODER_WORKSPACE_NAME}&agent=${localEnv:CODER_WORKSPACE_PARENT_AGENT_NAME}&url=${localEnv:CODER_URL}&token=$SESSION_TOKEN&devContainerName=${localEnv:CONTAINER_ID}&devContainerFolder=${containerWorkspaceFolder}",
28+
"external": true,
29+
"icon": "/icon/cursor.svg",
30+
"order": 1
31+
},
32+
{
33+
"slug": "windsurf",
34+
"displayName": "Windsurf Editor",
35+
"url": "windsurf://coder.coder-remote/openDevContainer?owner=${localEnv:CODER_WORKSPACE_OWNER_NAME}&workspace=${localEnv:CODER_WORKSPACE_NAME}&agent=${localEnv:CODER_WORKSPACE_PARENT_AGENT_NAME}&url=${localEnv:CODER_URL}&token=$SESSION_TOKEN&devContainerName=${localEnv:CONTAINER_ID}&devContainerFolder=${containerWorkspaceFolder}",
36+
"external": true,
37+
"icon": "/icon/windsurf.svg",
38+
"order": 4
39+
},
40+
{
41+
"slug": "zed",
42+
"displayName": "Zed Editor",
43+
"url": "zed://ssh/${localEnv:CODER_WORKSPACE_AGENT_NAME}.${localEnv:CODER_WORKSPACE_NAME}.${localEnv:CODER_WORKSPACE_OWNER_NAME}.coder${containerWorkspaceFolder}",
44+
"external": true,
45+
"icon": "/icon/zed.svg",
46+
"order": 5
47+
},
48+
// Reproduce `code-server` app here from the code-server
49+
// feature so that we can set the correct folder and order.
50+
// Currently, the order cannot be specified via option because
51+
// we parse it as a number whereas variable interpolation
52+
// results in a string. Additionally we set health check which
53+
// is not yet set in the feature.
54+
{
55+
"slug": "code-server",
56+
"displayName": "code-server",
57+
"url": "http://${localEnv:FEATURE_CODE_SERVER_OPTION_HOST:127.0.0.1}:${localEnv:FEATURE_CODE_SERVER_OPTION_PORT:8080}/?folder=${containerWorkspaceFolder}",
58+
"openIn": "${localEnv:FEATURE_CODE_SERVER_OPTION_APPOPENIN:slim-window}",
59+
"share": "${localEnv:FEATURE_CODE_SERVER_OPTION_APPSHARE:owner}",
60+
"icon": "/icon/code.svg",
61+
"group": "${localEnv:FEATURE_CODE_SERVER_OPTION_APPGROUP:Web Editors}",
62+
"order": 3,
63+
"healthCheck": {
64+
"url": "http://${localEnv:FEATURE_CODE_SERVER_OPTION_HOST:127.0.0.1}:${localEnv:FEATURE_CODE_SERVER_OPTION_PORT:8080}/healthz",
65+
"interval": 5,
66+
"threshold": 2
67+
}
68+
}
69+
]
70+
}
71+
},
72+
"mounts": [
73+
// Add a volume for the Coder home directory to persist shell history,
74+
// and speed up dotfiles init and/or personalization.
75+
"source=coder-coder-devcontainer-home,target=/home/coder,type=volume",
76+
// Mount the entire home because conditional mounts are not supported.
77+
// See: https://github.com/devcontainers/spec/issues/132
78+
"source=${localEnv:HOME},target=/mnt/home/coder,type=bind,readonly"
79+
],
80+
"postCreateCommand": ["./.devcontainer/scripts/post_create.sh"],
81+
"postStartCommand": ["./.devcontainer/scripts/post_start.sh"]
1382
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"id": "filebrowser",
3+
"version": "0.0.1",
4+
"name": "File Browser",
5+
"description": "A web-based file browser for your development container",
6+
"options": {
7+
"port": {
8+
"type": "string",
9+
"default": "13339",
10+
"description": "The port to run filebrowser on"
11+
},
12+
"folder": {
13+
"type": "string",
14+
"default": "",
15+
"description": "The root directory for filebrowser to serve"
16+
},
17+
"baseUrl": {
18+
"type": "string",
19+
"default": "",
20+
"description": "The base URL for filebrowser (e.g., /filebrowser)"
21+
}
22+
},
23+
"entrypoint": "/usr/local/bin/filebrowser-entrypoint",
24+
"dependsOn": {
25+
"ghcr.io/devcontainers/features/common-utils:2": {}
26+
},
27+
"customizations": {
28+
"coder": {
29+
"apps": [
30+
{
31+
"slug": "filebrowser",
32+
"displayName": "File Browser",
33+
"url": "http://localhost:${localEnv:FEATURE_FILEBROWSER_OPTION_PORT:13339}",
34+
"icon": "/icon/filebrowser.svg",
35+
"order": 3,
36+
"subdomain": true,
37+
"healthcheck": {
38+
"url": "http://localhost:${localEnv:FEATURE_FILEBROWSER_OPTION_PORT:13339}/health",
39+
"interval": 5,
40+
"threshold": 2
41+
}
42+
}
43+
]
44+
}
45+
}
46+
}

.devcontainer/filebrowser/install.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
BOLD='\033[0;1m'
6+
7+
printf "%sInstalling filebrowser\n\n" "${BOLD}"
8+
9+
# Check if filebrowser is installed.
10+
if ! command -v filebrowser &>/dev/null; then
11+
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
12+
fi
13+
14+
# Create entrypoint.
15+
cat >/usr/local/bin/filebrowser-entrypoint <<EOF
16+
#!/usr/bin/env bash
17+
18+
PORT="${PORT}"
19+
FOLDER="${FOLDER:-}"
20+
FOLDER="\${FOLDER:-\$(pwd)}"
21+
BASEURL="${BASEURL:-}"
22+
LOG_PATH=/tmp/filebrowser.log
23+
export FB_DATABASE="\${HOME}/.filebrowser.db"
24+
25+
printf "🛠️ Configuring filebrowser\n\n"
26+
27+
# Check if filebrowser db exists.
28+
if [[ ! -f "\${FB_DATABASE}" ]]; then
29+
filebrowser config init >>\${LOG_PATH} 2>&1
30+
filebrowser users add admin "" --perm.admin=true --viewMode=mosaic >>\${LOG_PATH} 2>&1
31+
fi
32+
33+
filebrowser config set --baseurl=\${BASEURL} --port=\${PORT} --auth.method=noauth --root=\${FOLDER} >>\${LOG_PATH} 2>&1
34+
35+
printf "👷 Starting filebrowser...\n\n"
36+
37+
printf "📂 Serving \${FOLDER} at http://localhost:\${PORT}\n\n"
38+
39+
filebrowser >>\${LOG_PATH} 2>&1 &
40+
41+
printf "📝 Logs at \${LOG_PATH}\n\n"
42+
EOF
43+
44+
chmod +x /usr/local/bin/filebrowser-entrypoint
45+
46+
printf "🥳 Installation complete!\n\n"

.devcontainer/scripts/post_create.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/sh
2+
3+
install_devcontainer_cli() {
4+
npm install -g @devcontainers/cli
5+
}
6+
7+
install_ssh_config() {
8+
echo "🔑 Installing SSH configuration..."
9+
rsync -a /mnt/home/coder/.ssh/ ~/.ssh/
10+
chmod 0700 ~/.ssh
11+
}
12+
13+
install_git_config() {
14+
echo "📂 Installing Git configuration..."
15+
if [ -f /mnt/home/coder/git/config ]; then
16+
rsync -a /mnt/home/coder/git/ ~/.config/git/
17+
elif [ -d /mnt/home/coder/.gitconfig ]; then
18+
rsync -a /mnt/home/coder/.gitconfig ~/.gitconfig
19+
else
20+
echo "⚠️ Git configuration directory not found."
21+
fi
22+
}
23+
24+
install_dotfiles() {
25+
if [ ! -d /mnt/home/coder/.config/coderv2/dotfiles ]; then
26+
echo "⚠️ Dotfiles directory not found."
27+
return
28+
fi
29+
30+
cd /mnt/home/coder/.config/coderv2/dotfiles || return
31+
for script in install.sh install bootstrap.sh bootstrap script/bootstrap setup.sh setup script/setup; do
32+
if [ -x $script ]; then
33+
echo "📦 Installing dotfiles..."
34+
./$script || {
35+
echo "❌ Error running $script. Please check the script for issues."
36+
return
37+
}
38+
echo "✅ Dotfiles installed successfully."
39+
return
40+
fi
41+
done
42+
echo "⚠️ No install script found in dotfiles directory."
43+
}
44+
45+
personalize() {
46+
# Allow script to continue as Coder dogfood utilizes a hack to
47+
# synchronize startup script execution.
48+
touch /tmp/.coder-startup-script.done
49+
50+
if [ -x /mnt/home/coder/personalize ]; then
51+
echo "🎨 Personalizing environment..."
52+
/mnt/home/coder/personalize
53+
fi
54+
}
55+
56+
install_devcontainer_cli
57+
install_ssh_config
58+
install_dotfiles
59+
personalize

.devcontainer/scripts/post_start.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
3+
# Start Docker service if not already running.
4+
sudo service docker start

.dockerignore

Lines changed: 0 additions & 6 deletions
This file was deleted.

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ indent_style = tab
1111
indent_style = space
1212
indent_size = 2
1313

14+
[*.proto]
15+
indent_style = space
16+
indent_size = 2
17+
1418
[coderd/database/dump.sql]
1519
indent_style = space
1620
indent_size = 4

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Generated files
2+
agent/agentcontainers/acmock/acmock.go linguist-generated=true
3+
agent/agentcontainers/dcspec/dcspec_gen.go linguist-generated=true
4+
agent/agentcontainers/testdata/devcontainercli/*/*.log linguist-generated=true
25
coderd/apidoc/docs.go linguist-generated=true
36
docs/reference/api/*.md linguist-generated=true
47
docs/reference/cli/*.md linguist-generated=true

0 commit comments

Comments
 (0)