Coder: Helm chart and configuration

Change-Id: I43515c289001bf1407aee1f9734151a261a7808a
diff --git a/charts/coder/.helmignore b/charts/coder/.helmignore
new file mode 100644
index 0000000..957f15e
--- /dev/null
+++ b/charts/coder/.helmignore
@@ -0,0 +1,27 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
+Makefile
+artifacthub-repo.yml
+
+tests
diff --git a/charts/coder/Chart.lock b/charts/coder/Chart.lock
new file mode 100644
index 0000000..9692722
--- /dev/null
+++ b/charts/coder/Chart.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: libcoder
+  repository: file://../libcoder
+  version: 0.1.0
+digest: sha256:5c9a99109258073b590a9f98268490ef387fde24c0c7c7ade9c1a8c7ef5e6e10
+generated: "2023-08-08T07:27:19.677972411Z"
diff --git a/charts/coder/Chart.yaml b/charts/coder/Chart.yaml
new file mode 100644
index 0000000..530fac7
--- /dev/null
+++ b/charts/coder/Chart.yaml
@@ -0,0 +1,22 @@
+apiVersion: v2
+appVersion: 2.13.2
+dependencies:
+- name: libcoder
+  repository: file://../libcoder
+  version: 0.1.0
+description: Remote development environments on your infrastructure
+home: https://github.com/coder/coder
+icon: https://helm.coder.com/coder_logo_black.png
+keywords:
+- coder
+- terraform
+kubeVersion: '>= 1.19.0-0'
+maintainers:
+- email: support@coder.com
+  name: Coder Technologies, Inc.
+  url: https://coder.com/contact
+name: coder
+sources:
+- https://github.com/coder/coder/tree/main/helm/coder
+type: application
+version: 2.13.2
diff --git a/charts/coder/README.md b/charts/coder/README.md
new file mode 100644
index 0000000..1a1933d
--- /dev/null
+++ b/charts/coder/README.md
@@ -0,0 +1,53 @@
+# Coder Helm Chart
+
+This directory contains the Helm chart used to deploy Coder onto a Kubernetes
+cluster. It contains the minimum required components to run Coder on Kubernetes,
+and notably (compared to Coder Classic) does not include a database server.
+
+## Getting Started
+
+> **Warning**: The main branch in this repository does not represent the
+> latest release of Coder. Please reference our installation docs for
+> instructions on a tagged release.
+
+View
+[our docs](https://coder.com/docs/coder-oss/latest/install/kubernetes)
+for detailed installation instructions.
+
+## Values
+
+Please refer to [values.yaml](values.yaml) for available Helm values and their
+defaults.
+
+A good starting point for your values file is:
+
+```yaml
+coder:
+  # You can specify any environment variables you'd like to pass to Coder
+  # here. Coder consumes environment variables listed in
+  # `coder server --help`, and these environment variables are also passed
+  # to the workspace provisioner (so you can consume them in your Terraform
+  # templates for auth keys etc.).
+  #
+  # Please keep in mind that you should not set `CODER_HTTP_ADDRESS`,
+  # `CODER_TLS_ENABLE`, `CODER_TLS_CERT_FILE` or `CODER_TLS_KEY_FILE` as
+  # they are already set by the Helm chart and will cause conflicts.
+  env:
+    - name: CODER_ACCESS_URL
+      value: "https://coder.example.com"
+    - name: CODER_PG_CONNECTION_URL
+      valueFrom:
+        secretKeyRef:
+          # You'll need to create a secret called coder-db-url with your
+          # Postgres connection URL like:
+          # postgres://coder:password@postgres:5432/coder?sslmode=disable
+          name: coder-db-url
+          key: url
+
+    # This env enables the Prometheus metrics endpoint.
+    - name: CODER_PROMETHEUS_ADDRESS
+      value: "0.0.0.0:2112"
+  tls:
+    secretNames:
+      - my-tls-secret-name
+```
diff --git a/charts/coder/charts/libcoder/Chart.yaml b/charts/coder/charts/libcoder/Chart.yaml
new file mode 100644
index 0000000..7cf6ff9
--- /dev/null
+++ b/charts/coder/charts/libcoder/Chart.yaml
@@ -0,0 +1,11 @@
+apiVersion: v2
+appVersion: 0.1.0
+description: Coder library chart
+home: https://github.com/coder/coder
+maintainers:
+- email: support@coder.com
+  name: Coder Technologies, Inc.
+  url: https://coder.com/contact
+name: libcoder
+type: library
+version: 0.1.0
diff --git a/charts/coder/charts/libcoder/templates/_coder.yaml b/charts/coder/charts/libcoder/templates/_coder.yaml
new file mode 100644
index 0000000..77cdbb2
--- /dev/null
+++ b/charts/coder/charts/libcoder/templates/_coder.yaml
@@ -0,0 +1,85 @@
+{{- define "libcoder.deployment.tpl" -}}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "coder.name" .}}
+  labels:
+    {{- include "coder.labels" . | nindent 4 }}
+    {{- with .Values.coder.labels }}
+      {{- toYaml . | nindent 4 }}
+    {{- end }}
+  annotations: {{ toYaml .Values.coder.annotations | nindent 4}}
+spec:
+  replicas: {{ .Values.coder.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "coder.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      labels:
+        {{- include "coder.labels" . | nindent 8 }}
+          {{- with .Values.coder.podLabels }}
+          {{- toYaml . | nindent 8 }}
+          {{- end }}
+      annotations:
+        {{- toYaml .Values.coder.podAnnotations | nindent 8  }}
+    spec:
+      serviceAccountName: {{ .Values.coder.serviceAccount.name | quote }}
+      restartPolicy: Always
+      {{- with .Values.coder.image.pullSecrets }}
+      imagePullSecrets:
+      {{- toYaml . | nindent 8 }}
+      {{- end }}
+      terminationGracePeriodSeconds: 60
+      {{- with .Values.coder.affinity }}
+      affinity:
+      {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.coder.tolerations }}
+      tolerations:
+      {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.coder.nodeSelector }}
+      nodeSelector:
+      {{ toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.coder.initContainers }}
+      initContainers:
+      {{ toYaml . | nindent 8 }}
+      {{- end }}
+      containers: []
+      {{- include "coder.volumes" . | nindent 6 }}
+{{- end -}}
+{{- define "libcoder.deployment" -}}
+{{- include "libcoder.util.merge" (append . "libcoder.deployment.tpl") -}}
+{{- end -}}
+
+{{- define "libcoder.containerspec.tpl" -}}
+name: coder
+image: {{ include "coder.image" . | quote }}
+imagePullPolicy: {{ .Values.coder.image.pullPolicy }}
+command:
+  {{- toYaml .Values.coder.command | nindent 2 }}
+resources:
+  {{- toYaml .Values.coder.resources | nindent 2 }}
+lifecycle:
+  {{- toYaml .Values.coder.lifecycle | nindent 2 }}
+securityContext: {{ toYaml .Values.coder.securityContext | nindent 2 }}
+{{ include "coder.volumeMounts" . }}
+{{- end -}}
+{{- define "libcoder.containerspec" -}}
+{{- include "libcoder.util.merge" (append . "libcoder.containerspec.tpl") -}}
+{{- end -}}
+
+{{- define "libcoder.serviceaccount.tpl" -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Values.coder.serviceAccount.name | quote }}
+  annotations: {{ toYaml .Values.coder.serviceAccount.annotations | nindent 4 }}
+  labels:
+    {{- include "coder.labels" . | nindent 4 }}
+{{- end -}}
+{{- define "libcoder.serviceaccount" -}}
+{{- include "libcoder.util.merge" (append . "libcoder.serviceaccount.tpl") -}}
+{{- end -}}
diff --git a/charts/coder/charts/libcoder/templates/_helpers.tpl b/charts/coder/charts/libcoder/templates/_helpers.tpl
new file mode 100644
index 0000000..9a6c5df
--- /dev/null
+++ b/charts/coder/charts/libcoder/templates/_helpers.tpl
@@ -0,0 +1,200 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "coder.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "coder.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Selector labels
+
+!!!!! DO NOT ADD ANY MORE SELECTORS. IT IS A BREAKING CHANGE !!!!!
+*/}}
+{{- define "coder.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "coder.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "coder.labels" -}}
+helm.sh/chart: {{ include "coder.chart" . }}
+{{ include "coder.selectorLabels" . }}
+app.kubernetes.io/part-of: {{ include "coder.name" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Coder Docker image URI
+*/}}
+{{- define "coder.image" -}}
+{{- if and (eq .Values.coder.image.tag "") (eq .Chart.AppVersion "0.1.0") -}}
+{{ fail "You must specify the coder.image.tag value if you're installing the Helm chart directly from Git." }}
+{{- end -}}
+{{ .Values.coder.image.repo }}:{{ .Values.coder.image.tag | default (printf "v%v" .Chart.AppVersion) }}
+{{- end }}
+
+{{/*
+Coder TLS enabled.
+*/}}
+{{- define "coder.tlsEnabled" -}}
+    {{- if hasKey .Values.coder "tls" -}}
+      {{- if .Values.coder.tls.secretNames -}}
+        true
+      {{- else -}}
+        false
+      {{- end -}}
+    {{- else -}}
+      false
+    {{- end -}}
+{{- end }}
+
+{{/*
+Coder TLS environment variables.
+*/}}
+{{- define "coder.tlsEnv" }}
+{{- if eq (include "coder.tlsEnabled" .) "true" }}
+- name: CODER_TLS_ENABLE
+  value: "true"
+- name: CODER_TLS_ADDRESS
+  value: "0.0.0.0:8443"
+- name: CODER_TLS_CERT_FILE
+  value: "{{ range $idx, $secretName := .Values.coder.tls.secretNames -}}{{ if $idx }},{{ end }}/etc/ssl/certs/coder/{{ $secretName }}/tls.crt{{- end }}"
+- name: CODER_TLS_KEY_FILE
+  value: "{{ range $idx, $secretName := .Values.coder.tls.secretNames -}}{{ if $idx }},{{ end }}/etc/ssl/certs/coder/{{ $secretName }}/tls.key{{- end }}"
+{{- end }}
+{{- end }}
+
+{{/*
+Coder default access URL
+*/}}
+{{- define "coder.defaultAccessURL" }}
+{{- if eq (include "coder.tlsEnabled" .) "true" -}}
+https
+{{- else -}}
+http
+{{- end -}}
+://coder.{{ .Release.Namespace }}.svc.cluster.local
+{{- end }}
+
+{{/*
+Coder volume definitions.
+*/}}
+{{- define "coder.volumeList" }}
+{{- if hasKey .Values.coder "tls" -}}
+{{- range $secretName := .Values.coder.tls.secretNames }}
+- name: "tls-{{ $secretName }}"
+  secret:
+    secretName: {{ $secretName | quote }}
+{{ end -}}
+{{- end }}
+{{ range $secret := .Values.coder.certs.secrets -}}
+- name: "ca-cert-{{ $secret.name }}"
+  secret:
+    secretName: {{ $secret.name | quote }}
+{{ end -}}
+{{ if gt (len .Values.coder.volumes) 0 -}}
+{{ toYaml .Values.coder.volumes }}
+{{ end -}}
+{{- end }}
+
+{{/*
+Coder volumes yaml.
+*/}}
+{{- define "coder.volumes" }}
+{{- if trim (include "coder.volumeList" .) -}}
+volumes:
+{{- include "coder.volumeList" . -}}
+{{- else -}}
+volumes: []
+{{- end -}}
+{{- end }}
+
+{{/*
+Coder volume mounts.
+*/}}
+{{- define "coder.volumeMountList" }}
+{{- if hasKey .Values.coder "tls" }}
+{{ range $secretName := .Values.coder.tls.secretNames -}}
+- name: "tls-{{ $secretName }}"
+  mountPath: "/etc/ssl/certs/coder/{{ $secretName }}"
+  readOnly: true
+{{ end -}}
+{{- end }}
+{{ range $secret := .Values.coder.certs.secrets -}}
+- name: "ca-cert-{{ $secret.name }}"
+  mountPath: "/etc/ssl/certs/{{ $secret.name }}.crt"
+  subPath: {{ $secret.key | quote }}
+  readOnly: true
+{{ end -}}
+{{ if gt (len .Values.coder.volumeMounts) 0 -}}
+{{ toYaml .Values.coder.volumeMounts }}
+{{ end -}}
+{{- end }}
+
+{{/*
+Coder volume mounts yaml.
+*/}}
+{{- define "coder.volumeMounts" }}
+{{- if trim (include "coder.volumeMountList" .) -}}
+volumeMounts:
+{{- include "coder.volumeMountList" . -}}
+{{- else -}}
+volumeMounts: []
+{{- end -}}
+{{- end }}
+
+{{/*
+Coder ingress wildcard hostname with the wildcard suffix stripped.
+*/}}
+{{- define "coder.ingressWildcardHost" -}}
+{{/* This regex replace is required as the original input including the suffix
+   * is not a legal ingress host. We need to remove the suffix and keep the
+   * wildcard '*'.
+   *
+   *   - '\\*'     Starts with '*'
+   *   - '[^.]*'   Suffix is 0 or more characters, '-suffix'
+   *   - '('       Start domain capture group
+   *   -   '\\.'     The domain should be separated with a '.' from the subdomain
+   *   -   '.*'      Rest of the domain.
+   *   - ')'       $1 is the ''.example.com'
+   */}}
+{{- regexReplaceAll "\\*[^.]*(\\..*)" .Values.coder.ingress.wildcardHost "*${1}" -}}
+{{- end }}
+
+{{/*
+Fail on fully deprecated values or deprecated value combinations. This is
+included at the top of coder.yaml.
+*/}}
+{{- define "coder.verifyDeprecated" }}
+{{/*
+Deprecated value coder.tls.secretName must not be used.
+*/}}
+{{- if .Values.coder.tls.secretName }}
+{{ fail "coder.tls.secretName is deprecated, use coder.tls.secretNames instead." }}
+{{- end }}
+{{- end }}
+
+{{/*
+Renders a value that contains a template.
+Usage:
+{{ include "coder.renderTemplate" ( dict "value" .Values.path.to.the.Value "context" $) }}
+*/}}
+{{- define "coder.renderTemplate" -}}
+    {{- if typeIs "string" .value }}
+        {{- tpl .value .context }}
+    {{- else }}
+        {{- tpl (.value | toYaml) .context }}
+    {{- end }}
+{{- end -}}
diff --git a/charts/coder/charts/libcoder/templates/_rbac.yaml b/charts/coder/charts/libcoder/templates/_rbac.yaml
new file mode 100644
index 0000000..1320c65
--- /dev/null
+++ b/charts/coder/charts/libcoder/templates/_rbac.yaml
@@ -0,0 +1,62 @@
+{{- define "libcoder.rbac.tpl" -}}
+{{- if .Values.coder.serviceAccount.workspacePerms }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ .Values.coder.serviceAccount.name }}-workspace-perms
+rules:
+  - apiGroups: [""]
+    resources: ["pods"]
+    verbs:
+    - create
+    - delete
+    - deletecollection
+    - get
+    - list
+    - patch
+    - update
+    - watch
+  - apiGroups: [""]
+    resources: ["persistentvolumeclaims"]
+    verbs:
+    - create
+    - delete
+    - deletecollection
+    - get
+    - list
+    - patch
+    - update
+    - watch
+{{- if .Values.coder.serviceAccount.enableDeployments }}
+  - apiGroups:
+    - apps
+    resources:
+    - deployments
+    verbs:
+    - create
+    - delete
+    - deletecollection
+    - get
+    - list
+    - patch
+    - update
+    - watch
+{{- end }}
+{{- with .Values.coder.serviceAccount.extraRules }}
+{{ toYaml . | nindent 2 }}
+{{- end }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ .Values.coder.serviceAccount.name | quote }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ .Values.coder.serviceAccount.name | quote }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ .Values.coder.serviceAccount.name }}-workspace-perms
+{{- end }}
+{{- end -}}
diff --git a/charts/coder/charts/libcoder/templates/_util.yaml b/charts/coder/charts/libcoder/templates/_util.yaml
new file mode 100644
index 0000000..ebdc13e
--- /dev/null
+++ b/charts/coder/charts/libcoder/templates/_util.yaml
@@ -0,0 +1,13 @@
+{{- /*
+  libcoder.util.merge will merge two YAML templates and output the result.
+  This takes an array of three values:
+    - the top context
+    - the template name of the overrides (destination)
+    - the template name of the base (source)
+*/}}
+{{- define "libcoder.util.merge" -}}
+{{- $top := first . -}}
+{{- $overrides := fromYaml (include (index . 1) $top) | default (dict ) -}}
+{{- $tpl := fromYaml (include (index . 2) $top) | default (dict ) -}}
+{{- toYaml (merge $overrides $tpl) -}}
+{{- end -}}
diff --git a/charts/coder/templates/NOTES.txt b/charts/coder/templates/NOTES.txt
new file mode 100644
index 0000000..18fc33c
--- /dev/null
+++ b/charts/coder/templates/NOTES.txt
@@ -0,0 +1,6 @@
+{{/*
+Deprecation notices:
+*/}}
+
+Enjoy Coder! Please create an issue at https://github.com/coder/coder if you run
+into any problems! :)
diff --git a/charts/coder/templates/_coder.tpl b/charts/coder/templates/_coder.tpl
new file mode 100644
index 0000000..d0846ec
--- /dev/null
+++ b/charts/coder/templates/_coder.tpl
@@ -0,0 +1,108 @@
+{{/*
+Service account to merge into the libcoder template
+*/}}
+{{- define "coder.serviceaccount" -}}
+{{- end -}}
+
+{{/*
+Deployment to merge into the libcoder template
+*/}}
+{{- define "coder.deployment" -}}
+spec:
+  template:
+    spec:
+      containers:
+      -
+{{ include "libcoder.containerspec" (list . "coder.containerspec") | indent 8}}
+
+{{- end -}}
+
+{{/*
+ContainerSpec for the Coder container of the Coder deployment
+*/}}
+{{- define "coder.containerspec" -}}
+args:
+{{- if .Values.coder.commandArgs }}
+  {{- toYaml .Values.coder.commandArgs | nindent 12 }}
+{{- else }}
+  {{- if .Values.coder.workspaceProxy }}
+- wsproxy
+  {{- end }}
+- server
+{{- end }}
+{{- if .Values.coder.envFrom }}
+envFrom:
+{{- with .Values.coder.envFrom }}
+{{ toYaml . }}
+{{- end }}
+{{- end }}
+env:
+- name: CODER_HTTP_ADDRESS
+  value: "0.0.0.0:8080"
+- name: CODER_PROMETHEUS_ADDRESS
+  value: "0.0.0.0:2112"
+{{- if .Values.provisionerDaemon.pskSecretName }}
+- name: CODER_PROVISIONER_DAEMON_PSK
+  valueFrom:
+    secretKeyRef:
+      name: {{ .Values.provisionerDaemon.pskSecretName | quote }}
+      key: psk
+{{- end }}
+  # Set the default access URL so a `helm apply` works by default.
+  # See: https://github.com/coder/coder/issues/5024
+{{- $hasAccessURL := false }}
+{{- range .Values.coder.env }}
+{{- if eq .name "CODER_ACCESS_URL" }}
+{{- $hasAccessURL = true }}
+{{- end }}
+{{- end }}
+{{- if and (not $hasAccessURL) .Values.coder.envUseClusterAccessURL }}
+- name: CODER_ACCESS_URL
+  value: {{ include "coder.defaultAccessURL" . | quote }}
+{{- end }}
+# Used for inter-pod communication with high-availability.
+- name: KUBE_POD_IP
+  valueFrom:
+    fieldRef:
+      fieldPath: status.podIP
+- name: CODER_DERP_SERVER_RELAY_URL
+  value: "http://$(KUBE_POD_IP):8080"
+{{- include "coder.tlsEnv" . }}
+{{- with .Values.coder.env }}
+{{ toYaml . }}
+{{- end }}
+ports:
+- name: "http"
+  containerPort: 8080
+  protocol: TCP
+  {{- if eq (include "coder.tlsEnabled" .) "true" }}
+- name: "https"
+  containerPort: 8443
+  protocol: TCP
+  {{- end }}
+  {{- range .Values.coder.env }}
+  {{- if eq .name "CODER_PROMETHEUS_ENABLE" }}
+  {{/*
+    This sadly has to be nested to avoid evaluating the second part
+    of the condition too early and potentially getting type errors if
+    the value is not a string (like a `valueFrom`). We do not support
+    `valueFrom` for this env var specifically.
+    */}}
+  {{- if eq .value "true" }}
+- name: "prometheus-http"
+  containerPort: 2112
+  protocol: TCP
+  {{- end }}
+  {{- end }}
+  {{- end }}
+readinessProbe:
+  httpGet:
+    path: /healthz
+    port: "http"
+    scheme: "HTTP"
+livenessProbe:
+  httpGet:
+    path: /healthz
+    port: "http"
+    scheme: "HTTP"
+{{- end }}
diff --git a/charts/coder/templates/coder.yaml b/charts/coder/templates/coder.yaml
new file mode 100644
index 0000000..65eaac0
--- /dev/null
+++ b/charts/coder/templates/coder.yaml
@@ -0,0 +1,5 @@
+---
+{{ include "libcoder.serviceaccount" (list . "coder.serviceaccount") }}
+
+---
+{{ include "libcoder.deployment" (list . "coder.deployment") }}
diff --git a/charts/coder/templates/extra-templates.yaml b/charts/coder/templates/extra-templates.yaml
new file mode 100644
index 0000000..e047658
--- /dev/null
+++ b/charts/coder/templates/extra-templates.yaml
@@ -0,0 +1,4 @@
+{{- range .Values.extraTemplates }}
+---
+{{ include "coder.renderTemplate" (dict "value" . "context" $) }}
+{{- end }}
diff --git a/charts/coder/templates/ingress.yaml b/charts/coder/templates/ingress.yaml
new file mode 100644
index 0000000..7dd2a13
--- /dev/null
+++ b/charts/coder/templates/ingress.yaml
@@ -0,0 +1,54 @@
+
+{{- if .Values.coder.ingress.enable }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: coder
+  labels:
+    {{- include "coder.labels" . | nindent 4 }}
+  annotations:
+    {{- toYaml .Values.coder.ingress.annotations | nindent 4 }}
+spec:
+  {{- if .Values.coder.ingress.className }}
+  {{/* If this is set to an empty string it fails validation on K8s */}}
+  ingressClassName: {{ .Values.coder.ingress.className | quote }}
+  {{- end }}
+
+  rules:
+    - host: {{ .Values.coder.ingress.host | quote }}
+      http:
+        paths:
+          - path: /
+            pathType: Prefix
+            backend:
+              service:
+                name: coder
+                port:
+                  name: "http"
+
+    {{- if .Values.coder.ingress.wildcardHost }}
+    - host: {{ include "coder.ingressWildcardHost" . | quote }}
+      http:
+        paths:
+          - path: /
+            pathType: Prefix
+            backend:
+              service:
+                name: coder
+                port:
+                  name: "http"
+    {{- end }}
+
+  {{- if .Values.coder.ingress.tls.enable }}
+  tls:
+    - hosts:
+        - {{ .Values.coder.ingress.host | quote }}
+      secretName: {{ .Values.coder.ingress.tls.secretName | quote}}
+    {{- if .Values.coder.ingress.tls.wildcardSecretName }}
+    - hosts:
+        - {{ include "coder.ingressWildcardHost" . | quote }}
+      secretName: {{ .Values.coder.ingress.tls.wildcardSecretName | quote}}
+    {{- end }}
+  {{- end }}
+{{- end }}
diff --git a/charts/coder/templates/rbac.yaml b/charts/coder/templates/rbac.yaml
new file mode 100644
index 0000000..07fb36d
--- /dev/null
+++ b/charts/coder/templates/rbac.yaml
@@ -0,0 +1 @@
+{{ include "libcoder.rbac.tpl" . }}
diff --git a/charts/coder/templates/service.yaml b/charts/coder/templates/service.yaml
new file mode 100644
index 0000000..1881f99
--- /dev/null
+++ b/charts/coder/templates/service.yaml
@@ -0,0 +1,41 @@
+{{- if .Values.coder.service.enable }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: coder
+  labels:
+    {{- include "coder.labels" . | nindent 4 }}
+  annotations:
+    {{- toYaml .Values.coder.service.annotations | nindent 4 }}
+spec:
+  type: {{ .Values.coder.service.type }}
+  sessionAffinity: {{ .Values.coder.service.sessionAffinity }}
+  ports:
+    - name: "http"
+      port: 80
+      targetPort: "http"
+      protocol: TCP
+      {{ if eq .Values.coder.service.type "NodePort" }}
+      nodePort: {{ .Values.coder.service.httpNodePort }}
+      {{ end }}
+    {{- if eq (include "coder.tlsEnabled" .) "true" }}
+    - name: "https"
+      port: 443
+      targetPort: "https"
+      protocol: TCP
+      {{ if eq .Values.coder.service.type "NodePort" }}
+      nodePort: {{ .Values.coder.service.httpsNodePort }}
+      {{ end }}
+    {{- end }}
+  {{- if eq "LoadBalancer" .Values.coder.service.type }}
+  {{- with .Values.coder.service.loadBalancerIP }}
+  loadBalancerIP: {{ . | quote }}
+  {{- end }}
+  {{- with .Values.coder.service.externalTrafficPolicy }}
+  externalTrafficPolicy: {{ . | quote }}
+  {{- end }}
+  {{- end }}
+  selector:
+    {{- include "coder.selectorLabels" . | nindent 4 }}
+{{- end }}
diff --git a/charts/coder/values.yaml b/charts/coder/values.yaml
new file mode 100644
index 0000000..dcf32c6
--- /dev/null
+++ b/charts/coder/values.yaml
@@ -0,0 +1,344 @@
+# coder -- Primary configuration for `coder server`.
+coder:
+  # coder.env -- The environment variables to set for Coder. These can be used
+  # to configure all aspects of `coder server`. Please see `coder server --help`
+  # for information about what environment variables can be set.
+  # Note: The following environment variables are set by default and cannot be
+  # overridden:
+  # - CODER_HTTP_ADDRESS: set to 0.0.0.0:8080 and cannot be changed.
+  # - CODER_TLS_ADDRESS: set to 0.0.0.0:8443 if tls.secretName is not empty.
+  # - CODER_TLS_ENABLE: set if tls.secretName is not empty.
+  # - CODER_TLS_CERT_FILE: set if tls.secretName is not empty.
+  # - CODER_TLS_KEY_FILE: set if tls.secretName is not empty.
+  # - CODER_PROMETHEUS_ADDRESS: set to 0.0.0.0:2112 and cannot be changed.
+  #   Prometheus must still be enabled by setting CODER_PROMETHEUS_ENABLE.
+  # - KUBE_POD_IP
+  # - CODER_DERP_SERVER_RELAY_URL
+  #
+  # We will additionally set CODER_ACCESS_URL if unset to the cluster service
+  # URL, unless coder.envUseClusterAccessURL is set to false.
+  env: []
+  # - name: "CODER_ACCESS_URL"
+  #   value: "https://coder.example.com"
+
+  # coder.envFrom -- Secrets or ConfigMaps to use for Coder's environment
+  # variables. If you want one environment variable read from a secret, then use
+  # coder.env valueFrom. See the K8s docs for valueFrom here:
+  # https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data
+  #
+  # If setting CODER_ACCESS_URL in coder.envFrom, then you must set
+  # coder.envUseClusterAccessURL to false.
+  envFrom: []
+  # - configMapRef:
+  #     name: coder-config
+  # - secretRef:
+  #     name: coder-config
+
+  # coder.envUseClusterAccessURL -- Determines whether the CODER_ACCESS_URL env
+  # is added to coder.env if it's not already set there. Set this to false if
+  # defining CODER_ACCESS_URL in coder.envFrom to avoid conflicts.
+  envUseClusterAccessURL: true
+
+  # coder.image -- The image to use for Coder.
+  image:
+    # coder.image.repo -- The repository of the image.
+    repo: "ghcr.io/coder/coder"
+    # coder.image.tag -- The tag of the image, defaults to {{.Chart.AppVersion}}
+    # if not set. If you're using the chart directly from git, the default
+    # app version will not work and you'll need to set this value. The helm
+    # chart helpfully fails quickly in this case.
+    tag: ""
+    # coder.image.pullPolicy -- The pull policy to use for the image. See:
+    # https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy
+    pullPolicy: IfNotPresent
+    # coder.image.pullSecrets -- The secrets used for pulling the Coder image from
+    # a private registry.
+    pullSecrets: []
+    #  - name: "pull-secret"
+
+  # coder.initContainers -- Init containers for the deployment. See:
+  # https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
+  initContainers:
+    []
+    # - name: init-container
+    #   image: busybox:1.28
+    #   command: ['sh', '-c', "sleep 2"]
+
+  # coder.annotations -- The Deployment annotations. See:
+  # https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+  annotations: {}
+
+  # coder.labels -- The Deployment labels. See:
+  # https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+  labels: {}
+
+  # coder.podAnnotations -- The Coder pod annotations. See:
+  # https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+  podAnnotations: {}
+
+  # coder.podLabels -- The Coder pod labels. See:
+  # https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+  podLabels: {}
+
+  # coder.serviceAccount -- Configuration for the automatically created service
+  # account. Creation of the service account cannot be disabled.
+  serviceAccount:
+    # coder.serviceAccount.workspacePerms -- Whether or not to grant the coder
+    # service account permissions to manage workspaces. This includes
+    # permission to manage pods and persistent volume claims in the deployment
+    # namespace.
+    #
+    # It is recommended to keep this on if you are using Kubernetes templates
+    # within Coder.
+    workspacePerms: true
+    # coder.serviceAccount.enableDeployments -- Provides the service account
+    # permission to manage Kubernetes deployments. Depends on workspacePerms.
+    enableDeployments: true
+    # coder.serviceAccount.extraRules -- Additional permissions added to the SA
+    # role. Depends on workspacePerms.
+    extraRules: []
+    # - apiGroups: [""]
+    #   resources: ["services"]
+    #   verbs:
+    #     - create
+    #     - delete
+    #     - deletecollection
+    #     - get
+    #     - list
+    #     - patch
+    #     - update
+    #     - watch
+
+    # coder.serviceAccount.annotations -- The Coder service account annotations.
+    annotations: {}
+    # coder.serviceAccount.name -- The service account name
+    name: coder
+
+  # coder.securityContext -- Fields related to the container's security
+  # context (as opposed to the pod). Some fields are also present in the pod
+  # security context, in which case these values will take precedence.
+  securityContext:
+    # coder.securityContext.runAsNonRoot -- Requires that the coder container
+    # runs as an unprivileged user. If setting runAsUser to 0 (root), this
+    # will need to be set to false.
+    runAsNonRoot: true
+    # coder.securityContext.runAsUser -- Sets the user id of the container.
+    # For security reasons, we recommend using a non-root user.
+    runAsUser: 1000
+    # coder.securityContext.runAsGroup -- Sets the group id of the container.
+    # For security reasons, we recommend using a non-root group.
+    runAsGroup: 1000
+    # coder.securityContext.readOnlyRootFilesystem -- Mounts the container's
+    # root filesystem as read-only.
+    readOnlyRootFilesystem: null
+    # coder.securityContext.seccompProfile -- Sets the seccomp profile for
+    # the coder container.
+    seccompProfile:
+      type: RuntimeDefault
+    # coder.securityContext.allowPrivilegeEscalation -- Controls whether
+    # the container can gain additional privileges, such as escalating to
+    # root. It is recommended to leave this setting disabled in production.
+    allowPrivilegeEscalation: false
+
+  # coder.volumes -- A list of extra volumes to add to the Coder pod.
+  volumes: []
+  # - name: "my-volume"
+  #   emptyDir: {}
+
+  # coder.volumeMounts -- A list of extra volume mounts to add to the Coder pod.
+  volumeMounts: []
+  # - name: "my-volume"
+  #   mountPath: "/mnt/my-volume"
+
+  # coder.tls -- The TLS configuration for Coder.
+  tls:
+    # coder.tls.secretNames -- A list of TLS server certificate secrets to mount
+    # into the Coder pod. The secrets should exist in the same namespace as the
+    # Helm deployment and should be of type "kubernetes.io/tls". The secrets
+    # will be automatically mounted into the pod if specified, and the correct
+    # "CODER_TLS_*" environment variables will be set for you.
+    secretNames: []
+
+  # coder.replicaCount -- The number of Kubernetes deployment replicas. This
+  # should only be increased if High Availability is enabled.
+  #
+  # This is an Enterprise feature. Contact sales@coder.com.
+  replicaCount: 1
+
+  # coder.workspaceProxy -- Whether or not this deployment of Coder is a Coder
+  # Workspace Proxy. Workspace Proxies reduce the latency between the user and
+  # their workspace for web connections (workspace apps and web terminal) and
+  # proxied connections from the CLI. Workspace Proxies are optional and only
+  # recommended for geographically sparse teams.
+  #
+  # Make sure you set CODER_PRIMARY_ACCESS_URL and CODER_PROXY_SESSION_TOKEN in
+  # the environment below. You can get a proxy token using the CLI:
+  #   coder wsproxy create \
+  #     --name "proxy-name" \
+  #     --display-name "Proxy Name" \
+  #     --icon "/emojis/xyz.png"
+  #
+  # This is an Enterprise feature. Contact sales@coder.com
+  # Docs: https://coder.com/docs/v2/latest/admin/workspace-proxies
+  workspaceProxy: false
+
+  # coder.lifecycle -- container lifecycle handlers for the Coder container, allowing
+  # for lifecycle events such as postStart and preStop events
+  # See: https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/
+  lifecycle:
+    {}
+    # postStart:
+    #   exec:
+    #     command: ["/bin/sh", "-c", "echo postStart"]
+    # preStop:
+    #   exec:
+    #     command: ["/bin/sh","-c","echo preStart"]
+
+  # coder.resources -- The resources to request for Coder. These are optional
+  # and are not set by default.
+  resources:
+    {}
+    # limits:
+    #   cpu: 2000m
+    #   memory: 4096Mi
+    # requests:
+    #   cpu: 2000m
+    #   memory: 4096Mi
+
+  # coder.certs -- CA bundles to mount inside the Coder pod.
+  certs:
+    # coder.certs.secrets -- A list of CA bundle secrets to mount into the Coder
+    # pod. The secrets should exist in the same namespace as the Helm
+    # deployment.
+    #
+    # The given key in each secret is mounted at
+    # `/etc/ssl/certs/{secret_name}.crt`.
+    secrets:
+      []
+      # - name: "my-ca-bundle"
+      #   key: "ca-bundle.crt"
+
+  # coder.affinity -- Allows specifying an affinity rule for the `coder` deployment.
+  # The default rule prefers to schedule coder pods on different
+  # nodes, which is only applicable if coder.replicaCount is greater than 1.
+  affinity:
+    podAntiAffinity:
+      preferredDuringSchedulingIgnoredDuringExecution:
+        - podAffinityTerm:
+            labelSelector:
+              matchExpressions:
+                - key: app.kubernetes.io/instance
+                  operator: In
+                  values:
+                    - "coder"
+            topologyKey: kubernetes.io/hostname
+          weight: 1
+
+  # coder.tolerations -- Tolerations for tainted nodes.
+  # See: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+  tolerations:
+    {}
+    # - key: "key"
+    #   operator: "Equal"
+    #   value: "value"
+    #   effect: "NoSchedule"
+
+  # coder.nodeSelector -- Node labels for constraining coder pods to nodes.
+  # See: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+  nodeSelector: {}
+  #  kubernetes.io/os: linux
+
+  # coder.service -- The Service object to expose for Coder.
+  service:
+    # coder.service.enable -- Whether to create the Service object.
+    enable: true
+    # coder.service.type -- The type of service to expose. See:
+    # https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
+    type: LoadBalancer
+    # coder.service.sessionAffinity -- Must be set to ClientIP or None
+    # AWS ELB does not support session stickiness based on ClientIP, so you must set this to None.
+    # The error message you might see: "Unsupported load balancer affinity: ClientIP"
+    # https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity
+    sessionAffinity: None
+    # coder.service.externalTrafficPolicy -- The external traffic policy to use.
+    # You may need to change this to "Local" to preserve the source IP address
+    # in some situations.
+    # https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
+    externalTrafficPolicy: Cluster
+    # coder.service.loadBalancerIP -- The IP address of the LoadBalancer. If not
+    # specified, a new IP will be generated each time the load balancer is
+    # recreated. It is recommended to manually create a static IP address in
+    # your cloud and specify it here in production to avoid accidental IP
+    # address changes.
+    loadBalancerIP: ""
+    # coder.service.annotations -- The service annotations. See:
+    # https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer
+    annotations: {}
+    # coder.service.httpNodePort -- Enabled if coder.service.type is set to
+    # NodePort. If not set, Kubernetes will allocate a port from the default
+    # range, 30000-32767.
+    httpNodePort: ""
+    # coder.service.httpsNodePort -- Enabled if coder.service.type is set to
+    # NodePort. If not set, Kubernetes will allocate a port from the default
+    # range, 30000-32767.
+    httpsNodePort: ""
+
+  # coder.ingress -- The Ingress object to expose for Coder.
+  ingress:
+    # coder.ingress.enable -- Whether to create the Ingress object. If using an
+    # Ingress, we recommend not specifying coder.tls.secretNames as the Ingress
+    # will handle TLS termination.
+    enable: false
+    # coder.ingress.className -- The name of the Ingress class to use.
+    className: ""
+    # coder.ingress.host -- The hostname to match on.
+    # Be sure to also set CODER_ACCESS_URL within coder.env[]
+    host: ""
+    # coder.ingress.wildcardHost -- The wildcard hostname to match on. Should be
+    # in the form "*.example.com" or "*-suffix.example.com". If you are using a
+    # suffix after the wildcard, the suffix will be stripped from the created
+    # ingress to ensure that it is a legal ingress host. Optional if not using
+    # applications over subdomains.
+    # Be sure to also set CODER_WILDCARD_ACCESS_URL within coder.env[]
+    wildcardHost: ""
+    # coder.ingress.annotations -- The ingress annotations.
+    annotations: {}
+    # coder.ingress.tls -- The TLS configuration to use for the Ingress.
+    tls:
+      # coder.ingress.tls.enable -- Whether to enable TLS on the Ingress.
+      enable: false
+      # coder.ingress.tls.secretName -- The name of the TLS secret to use.
+      secretName: ""
+      # coder.ingress.tls.wildcardSecretName -- The name of the TLS secret to
+      # use for the wildcard host.
+      wildcardSecretName: ""
+
+  # coder.command -- The command to use when running the Coder container. Used
+  # for customizing the location of the `coder` binary in your image.
+  command:
+    - /opt/coder
+
+  # coder.commandArgs -- Set arguments for the entrypoint command of the Coder pod.
+  commandArgs: []
+
+# provisionerDaemon -- Configuration for external provisioner daemons.
+#
+# This is an Enterprise feature. Contact sales@coder.com.
+provisionerDaemon:
+  # provisionerDaemon.pskSecretName -- The name of the Kubernetes secret that contains the
+  # Pre-Shared Key (PSK) to use to authenticate external provisioner daemons with Coder.  The
+  # secret must be in the same namespace as the Helm deployment, and contain an item called "psk"
+  # which contains the pre-shared key.
+  pskSecretName: ""
+
+# extraTemplates -- Array of extra objects to deploy with the release. Strings
+# are evaluated as a template and can use template expansions and functions. All
+# other objects are used as yaml.
+extraTemplates:
+  #- |
+  #    apiVersion: v1
+  #    kind: ConfigMap
+  #    metadata:
+  #      name: my-configmap
+  #    data:
+  #      key: {{ .Values.myCustomValue | quote }}
diff --git a/core/installer/app_repository.go b/core/installer/app_repository.go
index 62ca38a..1befd7c 100644
--- a/core/installer/app_repository.go
+++ b/core/installer/app_repository.go
@@ -19,6 +19,7 @@
 
 var storeEnvAppConfigs = []string{
 	"values-tmpl/dodo-app.cue",
+	"values-tmpl/coder.cue",
 	"values-tmpl/url-shortener.cue",
 	"values-tmpl/matrix.cue",
 	"values-tmpl/vaultwarden.cue",
diff --git a/core/installer/values-tmpl/coder.cue b/core/installer/values-tmpl/coder.cue
new file mode 100644
index 0000000..dec7457
--- /dev/null
+++ b/core/installer/values-tmpl/coder.cue
@@ -0,0 +1,136 @@
+input: {
+	network: #Network @name(Network)
+	subdomain: string @name(Subdomain)
+}
+
+_domain: "\(input.subdomain).\(input.network.domain)"
+url: "https://\(_domain)"
+
+name: "Coder"
+namespace: "app-coder"
+readme: "VSCode in the browser"
+description: readme
+icon: "<svg xmlns='http://www.w3.org/2000/svg' width='50px' height='50px' viewBox='0 0 16 16'><path fill='currentColor' fill-rule='evenodd' d='M11.573.275a1.203 1.203 0 0 0-.191.073c-.039.021-1.383 1.172-2.986 2.558C6.792 4.291 5.462 5.424 5.44 5.424c-.022 0-.664-.468-1.427-1.04c-.762-.571-1.428-1.057-1.48-1.078c-.15-.063-.468-.05-.613.024C1.754 3.416.189 4.975.094 5.15a.741.741 0 0 0 .04.766c.041.057.575.557 1.185 1.11c.611.553 1.107 1.015 1.102 1.026c-.004.012-.495.442-1.091.957c-.596.514-1.122.981-1.168 1.036a.746.746 0 0 0-.069.804c.096.175 1.659 1.734 1.827 1.821c.166.087.497.089.653.005c.059-.031.7-.502 1.424-1.046l1.318-.988l.109.1l2.73 2.473c1.846 1.671 2.666 2.396 2.772 2.453l.15.08h1.348l1.631-.814c1.5-.748 1.64-.823 1.748-.942c.213-.237.197.241.197-5.738c0-5.821.009-5.468-.151-5.699c-.058-.084-.41-.331-1.634-1.148c-.857-.572-1.613-1.065-1.68-1.095c-.1-.045-.187-.056-.482-.063c-.237-.005-.401.004-.48.027m1.699 2.305l1.233.82l.001 4.82l.001 4.82l-1.205.6l-1.204.6h-.569L8.66 11.644c-1.578-1.428-2.912-2.616-2.963-2.641c-.199-.094-.5-.101-.661-.014c-.034.018-.651.475-1.372 1.015c-.721.541-1.322.983-1.335.983c-.03 0-.477-.448-.461-.462c.673-.577 2.078-1.794 2.182-1.891c.086-.081.169-.192.21-.28c.057-.127.065-.174.054-.343c-.01-.158-.028-.223-.091-.324c-.053-.086-.454-.466-1.229-1.167l-1.15-1.04l.231-.233a1.83 1.83 0 0 1 .256-.234c.013 0 .644.465 1.4 1.033c1.496 1.123 1.537 1.148 1.81 1.116a.968.968 0 0 0 .253-.069c.062-.029.503-.39.979-.802L7.96 5.265a5929.2 5929.2 0 0 0 2.187-1.89a191.687 191.687 0 0 1 1.879-1.614c.008-.001.568.368 1.246.819M11.64 4.257a1.5 1.5 0 0 0-.16.051c-.059.021-1.079.738-2.267 1.593C6.867 7.59 6.92 7.547 6.851 7.854a.556.556 0 0 0 0 .292c.068.307.017.264 2.362 1.953c1.188.855 2.214 1.576 2.28 1.601c.347.133.743-.029.929-.38l.071-.133V4.813l-.071-.133a.76.76 0 0 0-.369-.356c-.127-.056-.324-.088-.413-.067m-.66 4.5l-.007.757l-1.046-.75A41.313 41.313 0 0 1 8.881 8c0-.007.471-.351 1.046-.764l1.046-.75l.007.757a95.51 95.51 0 0 1 0 1.514'/></svg>"
+
+ingress: {
+	coder: {
+		auth: enabled: false
+		network: input.network
+		subdomain: input.subdomain
+		service: {
+			name: "coder"
+			port: name: "http"
+		}
+	}
+}
+
+images: {
+	postgres: {
+		repository: "library"
+		name: "postgres"
+		tag: "15.3"
+		pullPolicy: "IfNotPresent"
+	}
+	coder: {
+		registry: "ghcr.io"
+		repository: "coder"
+		name: "coder"
+		tag: "latest"
+		pullPolicy: "IfNotPresent"
+	}
+}
+
+charts: {
+	postgres: {
+		kind: "GitRepository"
+		address: "https://github.com/giolekva/pcloud.git"
+		branch: "main"
+		path: "charts/postgresql"
+	}
+	coder: {
+		kind: "GitRepository"
+		address: "https://github.com/giolekva/pcloud.git"
+		branch: "main"
+		path: "charts/coder"
+	}
+	oauth2Client: {
+		kind: "GitRepository"
+		address: "https://github.com/giolekva/pcloud.git"
+		branch: "main"
+		path: "charts/oauth2-client"
+	}
+}
+
+_oauth2ClientSecretName: "oauth2-credentials"
+
+helm: {
+	"oauth2-client": {
+		chart: charts.oauth2Client
+		values: {
+			name: "\(release.namespace)-coder"
+			secretName: _oauth2ClientSecretName
+			grantTypes: ["authorization_code"]
+			responseTypes: ["code"]
+			scope: "openid profile email"
+			redirectUris: ["\(url)/api/v2/users/oidc/callbackzot"]
+			hydraAdmin: "http://hydra-admin.\(global.namespacePrefix)core-auth.svc.cluster.local"
+		}
+	}
+	postgres: {
+		chart: charts.postgres
+		values: {
+			fullnameOverride: "postgres"
+			image: {
+				registry: images.postgres.registry
+				repository: images.postgres.imageName
+				tag: images.postgres.tag
+				pullPolicy: images.postgres.pullPolicy
+			}
+			auth: {
+				username: "coder"
+				password: "coder"
+				database: "coder"
+			}
+		}
+	}
+	coder: {
+		chart: charts.coder
+		values: coder: {
+			image: {
+				repo: images.coder.fullName
+				tag: images.coder.tag
+				pullPolicy: images.coder.pullPolicy
+			}
+			envUseClusterAccessURL: false
+			env: [{
+				name: "CODER_ACCESS_URL"
+				value: url
+			}, {
+				name: "CODER_PG_CONNECTION_URL"
+				value: "postgres://coder:coder@postgres.\(release.namespace).svc.cluster.local:5432/coder?sslmode=disable"
+			}, {
+				name: "CODER_OIDC_ISSUER_URL"
+				value: "https://hydra.\(networks.public.domain)"
+			}, {
+				name: "CODER_OIDC_EMAIL_DOMAIN"
+				value: networks.public.domain
+			}, {
+				name: "CODER_OIDC_CLIENT_ID"
+				valueFrom: {
+					secretKeyRef: {
+						name: _oauth2ClientSecretName
+						key: "client_id"
+					}
+				}
+			}, {
+				name: "CODER_OIDC_CLIENT_SECRET"
+				valueFrom: {
+					secretKeyRef: {
+						name: _oauth2ClientSecretName
+						key: "client_secret"
+					}
+				}
+			}]
+		}
+	}
+}