diff --git a/.github/ct-install.yaml b/.github/ct-install.yaml index da2571ea597..9146fb1c9f0 100644 --- a/.github/ct-install.yaml +++ b/.github/ct-install.yaml @@ -8,3 +8,4 @@ chart-repos: - postgres-operator-ui=https://raw.githubusercontent.com/zalando/postgres-operator/master/charts/postgres-operator-ui/ - postgres-operator=https://raw.githubusercontent.com/zalando/postgres-operator/master/charts/postgres-operator/ - traefik=https://helm.traefik.io/traefik +- bitnami=https://charts.bitnami.com/bitnami diff --git a/.github/ct-lint.yaml b/.github/ct-lint.yaml index 2561517c268..8814fbc2247 100644 --- a/.github/ct-lint.yaml +++ b/.github/ct-lint.yaml @@ -7,3 +7,4 @@ chart-repos: - postgres-operator-ui=https://raw.githubusercontent.com/zalando/postgres-operator/master/charts/postgres-operator-ui/ - postgres-operator=https://raw.githubusercontent.com/zalando/postgres-operator/master/charts/postgres-operator/ - traefik=https://helm.traefik.io/traefik +- bitnami=https://charts.bitnami.com/bitnami diff --git a/stable/bitwarden/1.0.0/.helmignore b/stable/bitwarden/1.0.0/.helmignore new file mode 100644 index 00000000000..e559de0a012 --- /dev/null +++ b/stable/bitwarden/1.0.0/.helmignore @@ -0,0 +1,24 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# OWNERS file for Kubernetes +OWNERS diff --git a/stable/bitwarden/1.0.0/CONFIG.md b/stable/bitwarden/1.0.0/CONFIG.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/stable/bitwarden/1.0.0/Chart.lock b/stable/bitwarden/1.0.0/Chart.lock new file mode 100644 index 00000000000..5f28baa0efc --- /dev/null +++ b/stable/bitwarden/1.0.0/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: common + repository: https://truecharts.org/ + version: 2.2.2 +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 10.3.15 +digest: sha256:693741fa9c74107c6ce226bd406fc886dafd4b115c82e4db68a90e46cb5f2f68 +generated: "2021-04-12T17:54:54.6605766+02:00" diff --git a/stable/bitwarden/1.0.0/Chart.yaml b/stable/bitwarden/1.0.0/Chart.yaml new file mode 100644 index 00000000000..7e4d4334382 --- /dev/null +++ b/stable/bitwarden/1.0.0/Chart.yaml @@ -0,0 +1,38 @@ +apiVersion: v2 +kubeVersion: ">=1.16.0-0" +name: bitwarden +version: 1.0.0 +upstream_version: 2.1.5 +appVersion: "auto" +description: Unofficial Bitwarden compatible server written in Rust +type: application +deprecated: false +home: https://github.com/truecharts/apps/tree/master/incubator/bitwarden +icon: https://raw.githubusercontent.com/bitwarden/brand/master/icons/256x256.png +keywords: + - bitwarden + - bitwardenrs + - bitwarden_rs + - password + - rust +sources: + - https://github.com/truecharts/apps/tree/master/incubator/bitwarden + - https://github.com/k8s-at-home/charts/tree/master/charts/stable/bitwardenrs + - https://github.com/dani-garcia/bitwarden_rs +dependencies: + - name: common + repository: https://truecharts.org/ + version: 2.2.2 + # condition: + - name: postgresql + version: 10.3.15 + repository: https://charts.bitnami.com/bitnami + condition: postgresql.enabled +maintainers: + - name: TrueCharts + email: info@truecharts.org + url: truecharts.org + - name: Ornias1993 + email: kjeld@schouten-lebbing.nl + url: truecharts.org +# annotations: diff --git a/stable/bitwarden/1.0.0/README.md b/stable/bitwarden/1.0.0/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/stable/bitwarden/1.0.0/app-readme.md b/stable/bitwarden/1.0.0/app-readme.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/stable/bitwarden/1.0.0/charts/common-2.2.2.tgz b/stable/bitwarden/1.0.0/charts/common-2.2.2.tgz new file mode 100644 index 00000000000..3ee02a531a1 Binary files /dev/null and b/stable/bitwarden/1.0.0/charts/common-2.2.2.tgz differ diff --git a/stable/bitwarden/1.0.0/charts/postgresql-10.3.15.tgz b/stable/bitwarden/1.0.0/charts/postgresql-10.3.15.tgz new file mode 100644 index 00000000000..2700fb95688 Binary files /dev/null and b/stable/bitwarden/1.0.0/charts/postgresql-10.3.15.tgz differ diff --git a/stable/bitwarden/1.0.0/ix_values.yaml b/stable/bitwarden/1.0.0/ix_values.yaml new file mode 100644 index 00000000000..bc81215cb88 --- /dev/null +++ b/stable/bitwarden/1.0.0/ix_values.yaml @@ -0,0 +1,54 @@ +## +# This file contains Values.yaml content that gets added to the output of questions.yaml +# It's ONLY meant for content that the user is NOT expected to change. +# Example: Everything under "image" is not included in questions.yaml but is included here. +## + +image: + repository: bitwardenrs/server + pullPolicy: IfNotPresent + tag: 1.20.0 + +envTpl: + DOMAIN: "{{ if .Values.ingress }}{{ if .Values.ingress.main.enabled }}https://{{ ( index .Values.ingress.main.hosts 0 ).host }}{{ end }}{{ end }}" + +envFrom: + - configMapRef: + name: bitwardenconfig + - secretRef: + name: bitwardensecret + + +envValueFrom: + DATABASE_URL: + secretKeyRef: + name: dbcreds + key: url + +database: + # Database type, must be one of: 'sqlite', 'mysql' or 'postgresql'. + type: postgresql + # Enable DB Write-Ahead-Log for SQLite, disabled for other databases. https://github.com/dani-garcia/bitwarden_rs/wiki/Running-without-WAL-enabled + wal: false + ## URL for external databases (mysql://user:pass@host:port or postgresql://user:pass@host:port). + # url: "" + ## Set the size of the database connection pool. + # maxConnections: 10 + ## Connection retries during startup, 0 for infinite. 1 second between retries. + retries: 30 + +# Enabled postgres +# ... for more options see https://github.com/bitnami/charts/tree/master/bitnami/postgresql +postgresql: + enabled: true + postgresqlUsername: homeassistant + postgresqlDatabase: homeassistant + existingSecret: dbcreds + persistence: + enabled: true + existingClaim: db + +## +# Most other defaults are set in questions.yaml +# For other options please refer to the wiki, default_values.yaml or the common library chart +## diff --git a/stable/bitwarden/1.0.0/questions.yaml b/stable/bitwarden/1.0.0/questions.yaml new file mode 100644 index 00000000000..ddca9cfbb2e --- /dev/null +++ b/stable/bitwarden/1.0.0/questions.yaml @@ -0,0 +1,889 @@ +groups: + - name: "Container Image" + description: "Image to be used for container" + - name: "Workload Configuration" + description: "Configure workload deployment" + - name: "Configuration" + description: "additional container configuration" + - name: "Networking" + description: "Configure / service for container" + - name: "Storage" + description: "Persist and share data that is separate from the lifecycle of the container" + - name: "Resource Reservation" + description: "Specify resources to be allocated to workload" + - name: "Reverse Proxy Configuration" + description: "Reverse Proxy configuration" + - name: "Advanced" + description: "Advanced Configuration" + - name: "WARNING" + description: "WARNING" + +portals: + web_portal: + protocols: + - "$kubernetes-resource_configmap_portal_protocol" + host: + - "$kubernetes-resource_configmap_portal_host" + ports: + - "$kubernetes-resource_configmap_portal_port" + +questions: + + - variable: portal + group: "Container Image" + label: "Configure Portal Button" + schema: + type: dict + hidden: true + attrs: + - variable: enabled + label: "Enable" + description: "enable the portal button" + schema: + hidden: true + editable: false + type: boolean + default: true + + # Update Policy + - variable: strategyType + group: "Container Image" + label: "Update Strategy" + schema: + type: string + default: "Recreate" + enum: + - value: "RollingUpdate" + description: "Create new pods and then kill old ones" + - value: "Recreate" + description: "Kill existing pods before creating new ones" + + # Configure Time Zone + - variable: timezone + group: "Container Image" + label: "Timezone" + schema: + type: string + default: "Etc/UTC" + $ref: + - "definitions/timezone" + + - variable: PUID + group: "Container Image" + label: "PUID" + description: "The UserID of the user running the application and owning the files" + schema: + type: int + default: 568 + + - variable: PGID + group: "Container Image" + label: "PGID" + description: "The groupID of the user/group running the application and owning the files" + schema: + type: int + default: 568 + + - variable: UMASK + group: "Container Image" + label: "UMASK (advanced)" + description: "The UMASK used if supported by the application" + schema: + type: string + default: "002" + +# Configure Bitwarden: + + - variable: bitwardenrs + label: "" + group: "Configuration" + schema: + type: dict + attrs: + - variable: yubico + label: "Yubico OPT authentication" + schema: + type: dict + attrs: + - variable: enabled + label: "Enable Yubico OPT authentication" + description: "Please refer to the manual at: https://github.com/dani-garcia/bitwarden_rs/wiki/Enabling-Yubikey-OTP-authentication" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: server + label: "Yubico server" + description: "Defaults to YubiCloud" + schema: + type: string + default: "" + - variable: clientId + label: "Yubico ID" + schema: + type: string + default: "" + - variable: secretKey + label: "Yubico Secret Key" + schema: + type: string + default: "" + + - variable: admin + label: "Admin Portal" + schema: + type: dict + attrs: + - variable: enabled + label: "Enable Admin Portal" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: disableAdminToken + label: "Make Accessible Without Password/Token" + schema: + type: boolean + default: false + - variable: token + label: "Admin Portal Password/Token" + description: "Will be automatically generated if not defined" + schema: + type: string + default: "" + + - variable: icons + label: "Icon Download Settings" + schema: + type: dict + attrs: + - variable: disableDownload + label: "Disable Icon Download" + description: "Disables download of external icons. Setting to true will still serve icons from cache (/data/icon_cache)" + schema: + type: boolean + default: false + - variable: cache + label: "Cache time-to-live" + description: "Cache time-to-live for icons fetched. 0 means no purging" + schema: + type: int + default: 2592000 + - variable: token + label: "Failed Downloads Cache time-to-live" + description: "Cache time-to-live for icons that were not available. 0 means no purging." + schema: + type: int + default: 2592000 + + - variable: log + label: "Logging" + schema: + type: dict + attrs: + - variable: level + label: "Log level" + schema: + type: string + default: "info" + required: true + enum: + - value: "trace" + description: "trace" + - value: "debug" + description: "debug" + - value: "info" + description: "info" + - value: "warn" + description: "warn" + - value: "error" + description: "error" + - value: "off" + description: "off" + - variable: file + label: "Log-File Location" + schema: + type: string + default: "" + + + - variable: smtp + label: "SMTP Settings (Email)" + schema: + type: dict + attrs: + - variable: enabled + label: "Enable SMTP Support" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: host + label: "SMTP hostname" + schema: + type: string + required: true + default: "" + - variable: from + label: "SMTP sender e-mail address" + schema: + type: string + required: true + default: "" + - variable: fromName + label: "SMTP sender name" + schema: + type: string + required: true + default: "" + - variable: user + label: "SMTP username" + schema: + type: string + required: true + default: "" + - variable: password + label: "SMTP password" + description: "Required is user is specified, ignored if no user provided" + schema: + type: string + default: "" + - variable: ssl + label: "Enable SSL connection" + schema: + type: boolean + default: true + - variable: port + label: "SMTP port" + description: "Usually: 25 without SSL, 587 with SSL" + schema: + type: int + default: 587 + - variable: authMechanism + label: "SMTP Authentication Mechanisms" + description: "Comma-separated options: Plain, Login and Xoauth2" + schema: + type: string + default: "Plain" + - variable: heloName + label: "SMTP HELO - Hostname" + description: "Hostname to be sent for SMTP HELO. Defaults to pod name" + schema: + type: string + default: "" + - variable: port + label: "SMTP timeout" + schema: + type: int + default: 15 + - variable: invalidHostname + label: "Accept Invalid Hostname" + description: "Accept SSL session if certificate is valid but hostname doesn't match. DANGEROUS, vulnerable to men-in-the-middle attacks!" + schema: + type: boolean + default: false + - variable: invalidCertificate + label: "Accept Invalid Certificate" + description: "Accept invalid certificates. DANGEROUS, vulnerable to men-in-the-middle attacks!" + schema: + type: boolean + default: false + + + - variable: allowSignups + label: "Allow Signup" + description: "Allow any user to sign-up: https://github.com/dani-garcia/bitwarden_rs/wiki/Disable-registration-of-new-users" + schema: + type: boolean + default: true + - variable: allowInvitation + label: "Always allow Invitation" + description: "Allow invited users to sign-up even feature is disabled: https://github.com/dani-garcia/bitwarden_rs/wiki/Disable-invitations" + schema: + type: boolean + default: true + - variable: defaultInviteName + label: "Default Invite Organisation Name" + description: "Default organization name in invitation e-mails that are not coming from a specific organization." + schema: + type: string + default: "" + + + - variable: showPasswordHint + label: "Show password hints" + description: "https://github.com/dani-garcia/bitwarden_rs/wiki/Password-hint-display" + schema: + type: boolean + default: true + + + + - variable: signupwhitelistenable + label: "Enable Signup Whitelist" + description: "allowSignups is ignored if set" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: signupDomains + label: "Signup Whitelist Domains" + schema: + type: list + default: [] + items: + - variable: domain + label: "Domain" + schema: + type: string + default: "" + - variable: verifySignup + label: "Verifiy Signup" + description: "Verify e-mail before login is enabled. SMTP must be enabled" + schema: + type: boolean + default: false + - variable: requireEmail + label: "Block Login if email fails" + description: "When a user logs in an email is required to be sent. If sending the email fails the login attempt will fail. SMTP must be enabled" + schema: + type: boolean + default: false + - variable: emailAttempts + label: "Email token reset attempts" + description: "Maximum attempts before an email token is reset and a new email will need to be sent" + schema: + type: int + default: 3 + - variable: emailTokenExpiration + label: "Email token validity in seconds" + schema: + type: int + default: 600 + - variable: enableWebsockets + label: "Enable Websocket Connections" + description: "Enable Websockets for notification. https://github.com/dani-garcia/bitwarden_rs/wiki/Enabling-WebSocket-notifications" + schema: + type: boolean + default: true + hidden: true + - variable: enableWebVault + label: "Enable Webvault" + description: "Enable Web Vault (static content). https://github.com/dani-garcia/bitwarden_rs/wiki/Disabling-or-overriding-the-Vault-interface-hosting" + schema: + type: boolean + default: true + - variable: orgCreationUsers + label: "Limit Organisation Creation to (users)" + description: "Restrict creation of orgs. Options are: 'all', 'none' or a comma-separated list of users." + schema: + type: string + default: "all" + - variable: attachmentLimitOrg + label: "Limit Attachment Disk Usage per Organisation" + schema: + type: string + default: "" + - variable: attachmentLimitUser + label: "Limit Attachment Disk Usage per User" + schema: + type: string + default: "" + - variable: hibpApiKey + label: "HaveIBeenPwned API Key" + description: "Can be purchased at https://haveibeenpwned.com/API/Key" + schema: + type: string + default: "" + + # Configure Enviroment Variables + - variable: environmentVariables + label: "Image environment" + group: "Configuration" + schema: + type: list + default: [] + items: + - variable: environmentVariable + label: "Environment Variable" + schema: + type: dict + attrs: + - variable: name + label: "Name" + schema: + type: string + - variable: value + label: "Value" + schema: + type: string + + # Enable Host Networking + - variable: hostNetwork + group: "Networking" + label: "Enable Host Networking" + schema: + type: boolean + default: false + + - variable: services + group: "Networking" + label: "Configure Service" + schema: + type: dict + attrs: + - variable: main + label: "Main service" + description: "The Primary service on which the healthcheck runs, often the webUI" + schema: + type: dict + attrs: + - variable: enabled + label: "Enable the service" + schema: + type: boolean + default: true + hidden: true + - variable: type + label: "Service type" + description: "ClusterIP's are only internally available, nodePorts expose the container to the host node System" + schema: + type: string + default: "ClusterIP" + enum: + - value: "NodePort" + description: "NodePort" + - value: "ClusterIP" + description: "ClusterIP" + - variable: port + label: "Port configuration" + schema: + type: dict + attrs: + - variable: protocol + label: "Port Type" + schema: + type: string + default: "HTTP" + hidden: false + enum: + - value: HTTP + description: "HTTP" + - value: "HTTPS" + description: "HTTPS" + - variable: port + label: "container port" + schema: + type: int + default: 8080 + editable: false + hidden: true + - variable: targetport + label: "Internal Service port" + description: "When connecting internally to this App, you'll need this port" + schema: + type: int + default: 8080 + editable: false + hidden: true + - variable: nodePort + label: "(optional) host nodePort to expose to" + description: "only get used when nodePort is selected" + schema: + type: int + min: 9000 + max: 65535 + default: 36052 + required: true + - variable: ws + label: "Websocket service" + description: "Websocket Service" + schema: + type: dict + attrs: + - variable: enabled + label: "Enable the service" + schema: + type: boolean + default: true + hidden: true + - variable: type + label: "Service type" + description: "ClusterIP's are only internally available, nodePorts expose the container to the host node System" + schema: + type: string + default: "ClusterIP" + enum: + - value: "NodePort" + description: "NodePort" + - value: "ClusterIP" + description: "ClusterIP" + - variable: port + label: "Port configuration" + schema: + type: dict + attrs: + - variable: protocol + label: "Port Type" + schema: + type: string + default: "HTTP" + hidden: false + enum: + - value: HTTP + description: "HTTP" + - value: "HTTPS" + description: "HTTPS" + - variable: port + label: "container port" + schema: + type: int + default: 3012 + editable: false + hidden: true + - variable: targetport + label: "Internal Service port" + description: "When connecting internally to this App, you'll need this port" + schema: + type: int + default: 3012 + editable: false + hidden: true + - variable: nodePort + label: "(optional) host nodePort to expose to" + description: "only get used when nodePort is selected" + schema: + type: int + min: 9000 + max: 65535 + default: 36053 + required: true + + +## TrueCharts Specific + + - variable: persistence + label: "Integrated Persistent Storage" + description: "Websocket Service" + group: "Storage" + schema: + type: dict + attrs: + - variable: data + label: "App Config Storage" + description: "Stores the Application Configuration." + schema: + type: dict + attrs: + - variable: enabled + label: "Enable the storage" + schema: + type: boolean + default: true + hidden: true + - variable: storageClass + label: "Type of Storage" + description: " Warning: Anything other than Internal will break rollback!" + schema: + type: string + default: "" + enum: + - value: "" + description: "Internal" + - variable: mountPath + label: "mountPath" + description: "Path inside the container the storage is mounted" + schema: + type: string + default: "/data" + hidden: true + - variable: emptyDir + label: "Mount a ramdisk instead of actual storage" + schema: + type: boolean + default: false + hidden: true + - variable: accessMode + label: "Access Mode (Advanced)" + description: "Allow or disallow multiple PVC's writhing to the same PVC" + schema: + type: string + default: "ReadWriteOnce" + enum: + - value: "ReadWriteOnce" + description: "ReadWriteOnce" + - value: "ReadOnlyMany" + description: "ReadOnlyMany" + - value: "ReadWriteMany" + description: "ReadWriteMany" + - variable: size + label: "Size quotum of storage" + schema: + type: string + default: "100Gi" + - variable: db + label: "Database Storage" + description: "Stores the Application database." + schema: + type: dict + attrs: + - variable: enabled + label: "Enable the storage" + schema: + type: boolean + default: true + hidden: true + - variable: nameOverride + label: "Override PVC Name (advanced)" + description: "Forces a certain name for the PVC" + schema: + type: string + default: "db" + hidden: true + - variable: storageClass + label: "Type of Storage" + description: " Warning: Anything other than Internal will break rollback!" + schema: + type: string + default: "" + enum: + - value: "" + description: "Internal" + - variable: mountPath + label: "mountPath" + description: "Path inside the container the storage is mounted" + schema: + type: string + default: "" + hidden: true + - variable: emptyDir + label: "Mount a ramdisk instead of actual storage" + schema: + type: boolean + default: false + hidden: true + - variable: accessMode + label: "Access Mode (Advanced)" + description: "Allow or disallow multiple PVC's writhing to the same PVC" + schema: + type: string + default: "ReadWriteOnce" + enum: + - value: "ReadWriteOnce" + description: "ReadWriteOnce" + - value: "ReadOnlyMany" + description: "ReadOnlyMany" + - value: "ReadWriteMany" + description: "ReadWriteMany" + - variable: size + label: "Size quotum of storage" + schema: + type: string + default: "100Gi" + - variable: dbbackup + label: "Database Backup Storage" + description: "Stores the Application database backups." + schema: + type: dict + attrs: + - variable: enabled + label: "Enable the storage" + schema: + type: boolean + default: true + hidden: true + - variable: storageClass + label: "Type of Storage" + description: " Warning: Anything other than Internal will break rollback!" + schema: + type: string + default: "" + enum: + - value: "" + description: "Internal" + - variable: mountPath + label: "mountPath" + description: "Path inside the container the storage is mounted" + schema: + type: string + default: "" + hidden: true + - variable: emptyDir + label: "Mount a ramdisk instead of actual storage" + schema: + type: boolean + default: false + hidden: true + - variable: accessMode + label: "Access Mode (Advanced)" + description: "Allow or disallow multiple PVC's writhing to the same PVC" + schema: + type: string + default: "ReadWriteOnce" + enum: + - value: "ReadWriteOnce" + description: "ReadWriteOnce" + - value: "ReadOnlyMany" + description: "ReadOnlyMany" + - value: "ReadWriteMany" + description: "ReadWriteMany" + - variable: size + label: "Size quotum of storage" + schema: + type: string + default: "100Gi" + + - variable: additionalAppVolumeMounts + label: "Custom app storage" + group: "Storage" + schema: + type: list + default: [] + items: + - variable: volumeMount + label: "Custom Storage" + schema: + type: dict + attrs: + - variable: enabled + label: "Enabled" + schema: + type: boolean + default: true + required: true + hidden: true + editable: false + - variable: setPermissions + label: "Automatic Permissions" + description: "Automatically set permissions on install" + schema: + type: boolean + default: true + hidden: false + - variable: name + label: "Mountpoint Name" + schema: + type: string + default: "" + required: true + editable: true + - variable: emptyDir + label: "emptyDir" + schema: + type: boolean + default: false + hidden: true + editable: false + - variable: mountPath + label: "Mount Path" + description: "Path to mount inside the pod" + schema: + type: path + required: true + default: "" + editable: true + - variable: hostPathEnabled + label: "host Path Enabled" + schema: + type: boolean + default: true + hidden: true + - variable: hostPath + label: "Host Path" + schema: + type: hostpath + required: true + + - variable: ingress + label: "" + group: "Reverse Proxy Configuration" + schema: + type: dict + attrs: + - variable: main + label: "Web Reverse Proxy Configuration" + schema: + type: dict + attrs: + - variable: enabled + label: "Enable Web Reverse Proxy" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: type + label: "Reverse Proxy Type" + schema: + type: string + default: "HTTP" + hidden: true + editable: false + required: true + - variable: serviceName + label: "Service name to proxy to" + schema: + hidden: true + editable: false + type: string + default: "" + - variable: entrypoint + label: "Select Entrypoint" + schema: + type: string + default: "websecure" + required: true + enum: + - value: "websecure" + description: "Websecure: HTTPS/TLS port 443" + - variable: hosts + label: "Hosts" + schema: + type: list + default: [] + items: + - variable: host + label: "Host" + schema: + type: dict + attrs: + - variable: host + label: "Domain Name" + required: true + schema: + type: string + - variable: path + label: "path" + schema: + type: string + required: true + hidden: true + default: "/" + - variable: certType + label: "Select Certificate Type" + schema: + type: string + default: "selfsigned" + enum: + - value: "" + description: "No Encryption/TLS/Certificates" + - value: "selfsigned" + description: "Self-Signed Certificate" + - value: "ixcert" + description: "TrueNAS SCALE Certificate" + - variable: certificate + label: "Select TrueNAS SCALE Certificate" + schema: + type: int + show_if: [["certType", "=", "ixcert"]] + $ref: + - "definitions/certificate" + - variable: authForwardURL + label: "Forward Authentication URL" + schema: + type: string + default: "" diff --git a/stable/bitwarden/1.0.0/templates/_specialingress.tpl b/stable/bitwarden/1.0.0/templates/_specialingress.tpl new file mode 100644 index 00000000000..f44598078d3 --- /dev/null +++ b/stable/bitwarden/1.0.0/templates/_specialingress.tpl @@ -0,0 +1,105 @@ +{{/* +Renders the Ingress objects required by the chart by returning a concatinated list +of the main Ingress and any additionalIngresses. +*/}} +{{- define "bitwarden.ingress" -}} + {{- $fullName := include "common.names.fullname" . -}} + + {{- range $name, $ingress := .Values.ingress }} + {{- if $ingress.enabled -}} + {{- print ("---") | nindent 0 -}} + {{- $ingressValues := $ingress -}} + + + {{/* Create Second Ingress */}} + {{- $_ := set $ingressValues "nameSuffix" "extra" -}} + {{- $_ := set ( index $ingressValues.hosts 0 ) "path" "/notifications/hub/negotiate" -}} + {{- $_ := set $ingressValues "serviceName" $fullName -}} + {{- $_ := set $ingressValues "servicePort" "8080" -}} + + + + {{/* set defaults */}} + {{- if and (not $ingressValues.nameSuffix) ( ne $name "main" ) -}} + {{- $_ := set $ingressValues "nameSuffix" $name -}} + {{ end -}} + + {{- $_ := set $ "ObjectValues" (dict "ingress" $ingressValues) -}} + {{- if not $ingressValues.type -}} + {{- $_ := set $ingressValues "type" "HTTP" -}} + {{ end -}} + {{- if not $ingressValues.certType -}} + {{- $_ := set $ingressValues "certType" "" -}} + {{ end -}} + + {{- if or ( eq $ingressValues.type "TCP" ) ( eq $ingressValues.type "UDP" ) ( eq $ingressValues.type "HTTP-IR" ) -}} + {{- include "common.classes.ingressRoute" $ -}} + {{- else -}} + {{- include "common.classes.ingress" $ -}} + {{ end -}} + + {{- if $ingressValues.authForwardURL -}} + {{- print ("---") | nindent 0 -}} + {{- include "common.classes.ingress.authForward" $ }} + {{ end -}} + + {{- if eq $ingressValues.certType "ixcert" -}} + {{- $_ := set $ "ObjectValues" (dict "certHolder" $ingressValues) -}} + {{- print ("---") | nindent 0 -}} + {{- include "common.resources.cert.secret" $ }} + {{ end -}} + {{- end }} + {{- end }} + + + {{- /* Generate named ingresses as required */ -}} + {{- range $name, $ingress := .Values.ingress }} + {{- if $ingress.enabled -}} + {{- print ("---") | nindent 0 -}} + {{- $ingressValues := $ingress -}} + + + {{/* Create Second Ingress */}} + {{- $_ := set $ingressValues "nameSuffix" "ws" -}} + {{- $_ := set ( index $ingressValues.hosts 0 ) "path" "/notifications/hub" -}} + {{- $svcName := printf "%v-%v" $fullName "ws" -}} + {{- $_ := set $ingressValues "serviceName" $svcName -}} + {{- $_ := set $ingressValues "servicePort" "3012" -}} + + + {{/* set defaults */}} + {{- if and (not $ingressValues.nameSuffix) ( ne $name "main" ) -}} + {{- $_ := set $ingressValues "nameSuffix" $name -}} + {{ end -}} + + {{- $_ := set $ "ObjectValues" (dict "ingress" $ingressValues) -}} + {{- if not $ingressValues.type -}} + {{- $_ := set $ingressValues "type" "HTTP" -}} + {{ end -}} + {{- if not $ingressValues.certType -}} + {{- $_ := set $ingressValues "certType" "" -}} + {{ end -}} + + {{- if or ( eq $ingressValues.type "TCP" ) ( eq $ingressValues.type "UDP" ) ( eq $ingressValues.type "HTTP-IR" ) -}} + {{- include "common.classes.ingressRoute" $ -}} + {{- else -}} + {{- include "common.classes.ingress" $ -}} + {{ end -}} + + {{- if $ingressValues.authForwardURL -}} + {{- print ("---") | nindent 0 -}} + {{- include "common.classes.ingress.authForward" $ }} + {{ end -}} + + {{- if eq $ingressValues.certType "ixcert" -}} + {{- $_ := set $ "ObjectValues" (dict "certHolder" $ingressValues) -}} + {{- print ("---") | nindent 0 -}} + {{- include "common.resources.cert.secret" $ }} + {{ end -}} + {{- end }} + {{- end }} + + + + +{{- end }} diff --git a/stable/bitwarden/1.0.0/templates/_validate.tpl b/stable/bitwarden/1.0.0/templates/_validate.tpl new file mode 100644 index 00000000000..5bd127517b1 --- /dev/null +++ b/stable/bitwarden/1.0.0/templates/_validate.tpl @@ -0,0 +1,17 @@ +{{/* +Ensure valid DB type is select, defaults to SQLite +*/}} +{{- define "bitwardenrs.dbTypeValid" -}} +{{- if not (or (eq .Values.database.type "postgresql") (eq .Values.database.type "mysql") (eq .Values.database.type "sqlite")) }} +{{- required "Invalid database type" nil }} +{{- end -}} +{{- end -}} + +{{/* +Ensure log type is valid +*/}} +{{- define "bitwardenrs.logLevelValid" -}} +{{- if not (or (eq .Values.bitwardenrs.log.level "trace") (eq .Values.bitwardenrs.log.level "debug") (eq .Values.bitwardenrs.log.level "info") (eq .Values.bitwardenrs.log.level "warn") (eq .Values.bitwardenrs.log.level "error") (eq .Values.bitwardenrs.log.level "off")) }} +{{- required "Invalid log level" nil }} +{{- end }} +{{- end }} diff --git a/stable/bitwarden/1.0.0/templates/common.yaml b/stable/bitwarden/1.0.0/templates/common.yaml new file mode 100644 index 00000000000..c83beb6c7ae --- /dev/null +++ b/stable/bitwarden/1.0.0/templates/common.yaml @@ -0,0 +1,8 @@ +{{/* Make sure all variables are set properly */}} +{{- include "common.values.setup" . }} + +{{/* Render the templates */}} +{{ include "common.all" . }} + +{{/* Render special ingress for bitwarden */}} +{{- include "bitwarden.ingress" . }} diff --git a/stable/bitwarden/1.0.0/templates/configmap.yaml b/stable/bitwarden/1.0.0/templates/configmap.yaml new file mode 100644 index 00000000000..074f8237e6a --- /dev/null +++ b/stable/bitwarden/1.0.0/templates/configmap.yaml @@ -0,0 +1,114 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: bitwardenconfig + labels: + {{- include "common.labels" . | nindent 4 }} +data: + ROCKET_PORT: "8080" + SIGNUPS_ALLOWED: {{ .Values.bitwardenrs.allowSignups | quote }} + {{- if .Values.bitwardenrs.signupDomains }} + SIGNUPS_DOMAINS_WHITELIST: {{ join "," .Values.bitwardenrs.signupDomains | quote }} + {{- end }} + {{- if and (eq .Values.bitwardenrs.verifySignup true) (eq .Values.bitwardenrs.smtp.enabled false) }}{{ required "Signup verification requires SMTP to be enabled" nil}}{{end}} + SIGNUPS_VERIFY: {{ .Values.bitwardenrs.verifySignup | quote }} + {{- if and (eq .Values.bitwardenrs.requireEmail true) (eq .Values.bitwardenrs.smtp.enabled false) }}{{ required "Requiring emails for login depends on SMTP" nil}}{{end}} + REQUIRE_DEVICE_EMAIL: {{ .Values.bitwardenrs.requireEmail | quote }} + {{- if .Values.bitwardenrs.emailAttempts }} + EMAIL_ATTEMPTS_LIMIT: {{ .Values.bitwardenrs.emailAttempts | quote }} + {{- end }} + {{- if .Values.bitwardenrs.emailTokenExpiration }} + EMAIL_EXPIRATION_TIME: {{ .Values.bitwardenrs.emailTokenExpiration | quote }} + {{- end }} + INVITATIONS_ALLOWED: {{ .Values.bitwardenrs.allowInvitation | quote }} + {{- if .Values.bitwardenrs.defaultInviteName }} + INVITATION_ORG_NAME: {{ .Values.bitwardenrs.defaultInviteName | quote }} + {{- end }} + SHOW_PASSWORD_HINT: {{ .Values.bitwardenrs.showPasswordHint | quote }} + WEBSOCKET_ENABLED: {{ .Values.bitwardenrs.enableWebsockets | quote }} + WEB_VAULT_ENABLED: {{ .Values.bitwardenrs.enableWebVault | quote }} + ORG_CREATION_USERS: {{ .Values.bitwardenrs.orgCreationUsers | quote }} + {{- if .Values.bitwardenrs.attachmentLimitOrg }} + ORG_ATTACHMENT_LIMIT: {{ .Values.bitwardenrs.attachmentLimitOrg | quote }} + {{- end }} + {{- if .Values.bitwardenrs.attachmentLimitUser }} + USER_ATTACHMENT_LIMIT: {{ .Values.bitwardenrs.attachmentLimitUser | quote }} + {{- end }} + {{- if .Values.bitwardenrs.hibpApiKey }} + HIBP_API_KEY: {{ .Values.bitwardenrs.hibpApiKey | quote }} + {{- end }} + {{- include "bitwardenrs.dbTypeValid" . }} + {{- if .Values.database.retries }} + DB_CONNECTION_RETRIES: {{ .Values.database.retries | quote }} + {{- end }} + {{- if .Values.database.maxConnections }} + DATABASE_MAX_CONNS: {{ .Values.database.maxConnections | quote }} + {{- end }} + {{- if eq .Values.bitwardenrs.smtp.enabled true }} + SMTP_HOST: {{ required "SMTP host is required to enable SMTP" .Values.bitwardenrs.smtp.host | quote }} + SMTP_FROM: {{ required "SMTP sender address ('from') is required to enable SMTP" .Values.bitwardenrs.smtp.from | quote }} + {{- if .Values.bitwardenrs.smtp.fromName }} + SMTP_FROM_NAME: {{ .Values.bitwardenrs.smtp.fromName | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.ssl }} + SMTP_SSL: {{ .Values.bitwardenrs.smtp.ssl | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.port }} + SMTP_PORT: {{ .Values.bitwardenrs.smtp.port | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.authMechanism }} + SMTP_AUTH_MECHANISM: {{ .Values.bitwardenrs.smtp.authMechanism | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.heloName }} + HELO_NAME: {{ .Values.bitwardenrs.smtp.heloName | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.timeout }} + SMTP_TIMEOUT: {{ .Values.bitwardenrs.smtp.timeout | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.invalidHostname }} + SMTP_ACCEPT_INVALID_HOSTNAMES: {{ .Values.bitwardenrs.smtp.invalidHostname | quote }} + {{- end }} + {{- if .Values.bitwardenrs.smtp.invalidCertificate }} + SMTP_ACCEPT_INVALID_CERTS: {{ .Values.bitwardenrs.smtp.invalidCertificate | quote }} + {{- end }} + {{- end }} + {{- if .Values.bitwardenrs.log.file }} + LOG_FILE: {{ .Values.bitwardenrs.log.file | quote }} + {{- end }} + {{- if or .Values.bitwardenrs.log.level .Values.bitwardenrs.log.timeFormat }} + EXTENDED_LOGGING: "true" + {{- end }} + {{- if .Values.bitwardenrs.log.level }} + {{- include "bitwardenrs.logLevelValid" . }} + LOG_LEVEL: {{ .Values.bitwardenrs.log.level | quote }} + {{- end }} + {{- if .Values.bitwardenrs.log.timeFormat }} + LOG_TIMESTAMP_FORMAT: {{ .Values.bitwardenrs.log.timeFormat | quote }} + {{- end }} + {{- if .Values.bitwardenrs.icons.disableDownload }} + DISABLE_ICON_DOWNLOAD: {{ .Values.bitwardenrs.icons.disableDownload | quote }} + {{- if and (not .Values.bitwardenrs.icons.cache) (eq .Values.bitwardenrs.icons.disableDownload "true") }} + ICON_CACHE_TTL: "0" + {{- end }} + {{- end }} + {{- if .Values.bitwardenrs.icons.cache }} + ICON_CACHE_TTL: {{ .Values.bitwardenrs.icons.cache | quote }} + {{- end }} + {{- if .Values.bitwardenrs.icons.cacheFailed }} + ICON_CACHE_NEGTTL: {{ .Values.bitwardenrs.icons.cacheFailed | quote }} + {{- end }} + {{- if eq .Values.bitwardenrs.admin.enabled true }} + {{- if eq .Values.bitwardenrs.admin.disableAdminToken true }} + DISABLE_ADMIN_TOKEN: "true" + {{- end }} + {{- end }} + {{- if eq .Values.bitwardenrs.yubico.enabled true }} + {{- if .Values.bitwardenrs.yubico.server }} + YUBICO_SERVER: {{ .Values.bitwardenrs.yubico.server | quote }} + {{- end }} + {{- end }} + {{- if eq .Values.database.type "sqlite" }} + ENABLE_DB_WAL: {{ .Values.database.wal | quote }} + {{- else }} + ENABLE_DB_WAL: "false" + {{- end }} diff --git a/stable/bitwarden/1.0.0/templates/secrets.yaml b/stable/bitwarden/1.0.0/templates/secrets.yaml new file mode 100644 index 00000000000..e8e0dcc3e0b --- /dev/null +++ b/stable/bitwarden/1.0.0/templates/secrets.yaml @@ -0,0 +1,56 @@ +{{- $adminToken := "" }} +{{- if eq .Values.bitwardenrs.admin.enabled true }} +{{- $adminToken = .Values.bitwardenrs.admin.token | default (randAlphaNum 48) | b64enc | quote }} +{{- end -}} + +{{- $smtpUser := "" }} +{{- if and (eq .Values.bitwardenrs.smtp.enabled true ) (.Values.bitwardenrs.smtp.user) }} +{{- $smtpUser = .Values.bitwardenrs.smtp.user | b64enc | quote }} +{{- end -}} + +{{- $yubicoClientId := "" }} +{{- if eq .Values.bitwardenrs.yubico.enabled true }} +{{- $yubicoClientId = required "Yubico Client ID required" .Values.bitwardenrs.yubico.clientId | toString | b64enc | quote }} +{{- end -}} + +apiVersion: v1 +kind: Secret +metadata: + name: bitwardensecret + labels: + {{- include "common.labels" . | nindent 4 }} +data: + {{- if ne $adminToken "" }} + ADMIN_TOKEN: {{ $adminToken }} + {{- end }} + {{- if ne $smtpUser "" }} + SMTP_USERNAME: {{ $smtpUser }} + SMTP_PASSWORD: {{ required "Must specify SMTP password" .Values.bitwardenrs.smtp.password | b64enc | quote }} + {{- end }} + {{- if ne $yubicoClientId "" }} + YUBICO_CLIENT_ID: {{ $yubicoClientId }} + YUBICO_SECRET_KEY: {{ required "Yubico Secret Key required" .Values.bitwardenrs.yubico.secretKey | b64enc | quote }} + {{- end }} + +--- + +apiVersion: v1 +kind: Secret +metadata: + labels: + {{- include "common.labels" . | nindent 4 }} + name: dbcreds +{{- $previous := lookup "v1" "Secret" .Release.Namespace "dbcreds" }} +{{- $dbPass := "" }} +data: +{{- if $previous }} + {{- $dbPass = ( index $previous.data "postgresql-password" ) | b64dec }} + postgresql-password: {{ ( index $previous.data "postgresql-password" ) }} + postgresql-postgres-password: {{ ( index $previous.data "postgresql-postgres-password" ) }} +{{- else }} + {{- $dbPass = randAlphaNum 50 }} + postgresql-password: {{ $dbPass | b64enc | quote }} + postgresql-postgres-password: {{ randAlphaNum 50 | b64enc | quote }} +{{- end }} + url: {{ ( printf "%v%v:%v@%v-%v:%v/%v" "postgresql://" .Values.postgresql.postgresqlUsername $dbPass .Release.Name "postgresql" "5432" .Values.postgresql.postgresqlDatabase ) | b64enc | quote }} +type: Opaque diff --git a/stable/bitwarden/1.0.0/test_values.yaml b/stable/bitwarden/1.0.0/test_values.yaml new file mode 100644 index 00000000000..d9b25460268 --- /dev/null +++ b/stable/bitwarden/1.0.0/test_values.yaml @@ -0,0 +1,177 @@ +# Default values for Bitwarden. + +image: + repository: bitwardenrs/server + pullPolicy: IfNotPresent + tag: 1.20.0 + +strategy: + type: Recreate + +services: + main: + port: + port: 8080 + ws: + port: + port: 3012 + +env: {} + +envTpl: + DOMAIN: "https://{{ if .Values.ingress }}{{ if .Values.ingress.main.enabled }}{{ ( index .Values.ingress.main.hosts 0 ).host }}{{ else }}placeholder.com{{ end }}{{ else }}placeholder.com{{ end }}" + +envFrom: + - configMapRef: + name: bitwardenconfig + - secretRef: + name: bitwardensecret + +envValueFrom: + DATABASE_URL: + secretKeyRef: + name: dbcreds + key: url + +database: + # Database type, must be one of: 'sqlite', 'mysql' or 'postgresql'. + type: postgresql + # Enable DB Write-Ahead-Log for SQLite, disabled for other databases. https://github.com/dani-garcia/bitwarden_rs/wiki/Running-without-WAL-enabled + wal: true + ## URL for external databases (mysql://user:pass@host:port or postgresql://user:pass@host:port). + # url: "" + ## Set the size of the database connection pool. + # maxConnections: 10 + ## Connection retries during startup, 0 for infinite. 1 second between retries. + # retries: 15 + +# Set Bitwarden_rs application variables +bitwardenrs: + # Allow any user to sign-up: https://github.com/dani-garcia/bitwarden_rs/wiki/Disable-registration-of-new-users + allowSignups: true + ## Whitelist domains allowed to sign-up. 'allowSignups' is ignored if set. + # signupDomains: + # - domain.tld + # Verify e-mail before login is enabled. SMTP must be enabled. + verifySignup: false + # When a user logs in an email is required to be sent. If sending the email fails the login attempt will fail. SMTP must be enabled. + requireEmail: false + ## Maximum attempts before an email token is reset and a new email will need to be sent. + # emailAttempts: 3 + ## Email token validity in seconds. + # emailTokenExpiration: 600 + # Allow invited users to sign-up even feature is disabled: https://github.com/dani-garcia/bitwarden_rs/wiki/Disable-invitations + allowInvitation: true + # Show password hints: https://github.com/dani-garcia/bitwarden_rs/wiki/Password-hint-display + ## Default organization name in invitation e-mails that are not coming from a specific organization. + # defaultInviteName: "" + showPasswordHint: true + # Enable Websockets for notification. https://github.com/dani-garcia/bitwarden_rs/wiki/Enabling-WebSocket-notifications + # Redirect HTTP path "/notifications/hub" to port 3012. Ingress/IngressRoute controllers are automatically configured. + enableWebsockets: true + # Enable Web Vault (static content). https://github.com/dani-garcia/bitwarden_rs/wiki/Disabling-or-overriding-the-Vault-interface-hosting + enableWebVault: true + # Restrict creation of orgs. Options are: 'all', 'none' or a comma-separated list of users. + orgCreationUsers: all + ## Limit attachment disk usage per organization. + # attachmentLimitOrg: + ## Limit attachment disk usage per user. + # attachmentLimitUser: + ## HaveIBeenPwned API Key. Can be purchased at https://haveibeenpwned.com/API/Key. + # hibpApiKey: + + admin: + # Enable admin portal. + enabled: false + # Disabling the admin token will make the admin portal accessible to anyone, use carefully: https://github.com/dani-garcia/bitwarden_rs/wiki/Disable-admin-token + disableAdminToken: false + ## Token for admin login, will be generated if not defined. https://github.com/dani-garcia/bitwarden_rs/wiki/Enabling-admin-page + # token: + + # Enable SMTP. https://github.com/dani-garcia/bitwarden_rs/wiki/SMTP-configuration + smtp: + enabled: false + # SMTP hostname, required if SMTP is enabled. + host: "" + # SMTP sender e-mail address, required if SMTP is enabled. + from: "" + ## SMTP sender name, defaults to 'Bitwarden_RS'. + # fromName: "" + ## Enable SSL connection. + # ssl: true + ## SMTP port. Defaults to 25 without SSL, 587 with SSL. + # port: 587 + ## SMTP Authentication Mechanisms. Comma-separated options: 'Plain', 'Login' and 'Xoauth2'. Defaults to 'Plain'. + # authMechanism: Plain + ## Hostname to be sent for SMTP HELO. Defaults to pod name. + # heloName: "" + ## SMTP timeout. + # timeout: 15 + ## Accept SSL session if certificate is valid but hostname doesn't match. DANGEROUS, vulnerable to men-in-the-middle attacks! + # invalidHostname: false + ## Accept invalid certificates. DANGEROUS, vulnerable to men-in-the-middle attacks! + # invalidCertificate: false + ## SMTP username. + # user: "" + ## SMTP password. Required is user is specified, ignored if no user provided. + # password: "" + + ## Enable Yubico OPT authentication. https://github.com/dani-garcia/bitwarden_rs/wiki/Enabling-Yubikey-OTP-authentication + yubico: + enabled: false + ## Yubico server. Defaults to YubiCloud. + # server: + ## Yubico ID and Secret Key. + # clientId: + # secretKey: + + ## Logging options. https://github.com/dani-garcia/bitwarden_rs/wiki/Logging + log: + # Log to file. + file: "" + # Log level. Options are "trace", "debug", "info", "warn", "error" or "off". + level: "trace" + ## Log timestamp format. See https://docs.rs/chrono/0.4.15/chrono/format/strftime/index.html. Defaults to time in milliseconds. + # timeFormat: "" + + icons: + # Disables download of external icons. Setting to true will still serve icons from cache (/data/icon_cache). TTL will default to zero. + disableDownload: false + ## Cache time-to-live for icons fetched. 0 means no purging. + # cache: 2592000 + ## Cache time-to-live for icons that were not available. 0 means no purging. + # cacheFailed: 259200 + +persistence: + data: + enabled: true + mountPath: "/data" + emptyDir: true + accessMode: ReadWriteOnce + size: 1Gi + storageClass: "" + db: + nameOverride: "db" + enabled: true + emptyDir: true + accessMode: ReadWriteOnce + size: 1Gi + storageClass: "" + dbbackup: + enabled: true + emptyDir: true + accessMode: ReadWriteOnce + size: 1Gi + storageClass: "" + + +# Enabled postgres +# ... for more options see https://github.com/bitnami/charts/tree/master/bitnami/postgresql +postgresql: + enabled: true + postgresqlUsername: homeassistant + postgresqlDatabase: homeassistant + existingSecret: dbcreds + persistence: + enabled: false + existingClaim: db diff --git a/stable/bitwarden/1.0.0/values.yaml b/stable/bitwarden/1.0.0/values.yaml new file mode 100644 index 00000000000..58eb9c684b0 --- /dev/null +++ b/stable/bitwarden/1.0.0/values.yaml @@ -0,0 +1 @@ +# This file is empty on purpose, as it should not be used with TrueNAS SCALE diff --git a/stable/bitwarden/item.yaml b/stable/bitwarden/item.yaml new file mode 100644 index 00000000000..12bd3f41af9 --- /dev/null +++ b/stable/bitwarden/item.yaml @@ -0,0 +1,3 @@ +categories: + - security +icon_url: https://raw.githubusercontent.com/bitwarden/brand/master/icons/256x256.png