Skip to content

fix: external urls validate a scheme and hostname - #542

Open
untra wants to merge 2 commits into
mainfrom
fix/DEVEX-523-validate-external-url-scheme
Open

fix: external urls validate a scheme and hostname#542
untra wants to merge 2 commits into
mainfrom
fix/DEVEX-523-validate-external-url-scheme

Conversation

@untra

@untra untra commented Sep 1, 2026

Copy link
Copy Markdown

Summary

  • coder_app resources with external = true now validate the url at plan time via a new CustomizeDiff in
    provider/app.go, ensuring the URL has both a scheme and a host before apply.
  • Adds ValidateExternalURL in provider/helpers/validation.go, matching what a browser or OS URL
    handler would actually accept. Rejects bare host:port strings (which Go's url.Parse misreads as a
    scheme), opaque schemes and malformed urls
    • Increases the timeout of the integration tests for startup in a container 2seconds. this can be controversial; some folks like this tighter.

Why

External app URLs are opened directly by the browser or a custom protocol handler (e.g. vscode://), so
a URL missing a scheme or missing a host (https://) silently fails to open for the user. This catches that at terraform plan time with a clear error instead of a confusing runtime failure.

Testing

  • New table-driven tests in provider/helpers/validation_test.go covering valid cases (https, vscode://,
    reverse-DNS custom schemes, jetbrains-gateway://) and invalid cases (host:port without scheme,
    opaque schemes, missing scheme, missing host, malformed URLs).
  • New acceptance-style test cases in provider/app_test.go (NoScheme, HostPortWithoutScheme, NoHost,
    NotExternalIsUnchecked) verifying the diff-time check only fires when external = true and unknown values (computed at apply) are skipped.
  • go test ./provider/... passes.
  • Increases the integration test timeout to 12 seconds from 10; was causing ci flake.

tested locally with:
~/.terraformrc :

terraform {
 required_providers {
   coder = {
     source = "coder/coder"
   }
 }
}

provider "coder" {}

resource "coder_agent" "dev" {
 os   = "linux"
 arch = "amd64"
}

resource "coder_app" "bad_external" {
 agent_id     = coder_agent.dev.id
 slug         = "bad-external"
 display_name = "Bad External App"
 url          = "localhost:8080"
 external     = true
}

main.tf (intentionally broken missing scheme) :

  terraform {
  required_providers {
    coder = {
      source = "coder/coder"
    }
  }
}

provider "coder" {}

resource "coder_agent" "dev" {
  os   = "linux"
  arch = "amd64"
}

resource "coder_app" "bad_external" {
  agent_id     = coder_agent.dev.id
  slug         = "bad-external"
  display_name = "Bad External App"
  url          = "localhost:8080"
  external     = true
}

with all these tests
@linear-code

linear-code Bot commented Sep 1, 2026

Copy link
Copy Markdown

DEVEX-523

@untra
untra force-pushed the fix/DEVEX-523-validate-external-url-scheme branch from e613fb6 to 4ddc9f1 Compare September 1, 2026 21:57
@untra
untra requested review from johnstcn and matifali September 2, 2026 14:13

@matifali matifali left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nits, but it looks good to me.

Comment thread provider/app_test.go
Comment on lines +138 to +147
resource "coder_app" "test" {
agent_id = coder_agent.dev.id
slug = "test"
display_name = "Testing"
url = "localhost:8080"
external = true
}
`,
external: true,
expectError: regexp.MustCompile(`"localhost" URLs must include a host`),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be "localhost" URLs must include a scheme

Comment thread provider/helpers/validation_test.go
Comment thread provider/helpers/validation_test.go
{
name: "empty string",
value: "",
errorContains: "must include a scheme",

@matifali matifali Sep 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must include a scheme and a host


// ValidateExternalURL validates that value is a URL the browser's URL can parse.
// An external app URL must carry a scheme and hostname
func ValidateExternalURL(value string) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function probably needs to live in coder/coder somewhere so that...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants