Compare commits

..

11 Commits

Author SHA1 Message Date
henrygd
3e73399b87 fix battery detection on newer macs (#1170) 2025-09-15 12:02:50 -04:00
Ryan W
e149366451 Fixing service name in helm chart and making default values unopinionated (#1166) 2025-09-13 12:09:36 -04:00
henrygd
8da1ded73e strip whitespace from TOKEN_FILE (#984) 2025-09-12 12:59:53 -04:00
henrygd
efa37b2312 web: extra check for valid system before adding (#1063) 2025-09-11 15:37:11 -04:00
henrygd
bcdb4c92b5 add freebsd to list of copyable commands 2025-09-11 15:07:37 -04:00
henrygd
a7d07310b6 Add AUTO_LOGIN environment variable for automatic login. (#399) 2025-09-11 14:01:09 -04:00
hank
8db87e5497 Update Crowdin configuration file 2025-09-11 12:45:43 -04:00
henrygd
e601a0d564 add TRUSTED_AUTH_HEADER for auth forwarding (#399) 2025-09-10 21:26:59 -04:00
Fankesyooni
07491108cd new zh-CN translations (#1160) 2025-09-10 13:34:17 -04:00
henrygd
42ab17de1f move i18n.yml to project root 2025-09-10 13:30:42 -04:00
henrygd
2d14174f61 update i18n.yml 2025-09-10 13:28:06 -04:00
15 changed files with 292 additions and 68 deletions

View File

@@ -20,9 +20,8 @@ func HasReadableBattery() bool {
}
haveCheckedBattery = true
bat, err := battery.Get(0)
if err == nil && bat != nil {
systemHasBattery = true
} else {
systemHasBattery = err == nil && bat != nil && bat.Design != 0 && bat.Full != 0
if !systemHasBattery {
slog.Debug("No battery found", "err", err)
}
return systemHasBattery

View File

@@ -85,7 +85,7 @@ func getToken() (string, error) {
if err != nil {
return "", err
}
return string(tokenBytes), nil
return strings.TrimSpace(string(tokenBytes)), nil
}
// getOptions returns the WebSocket client options, creating them if necessary.

View File

@@ -537,4 +537,25 @@ func TestGetToken(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "", token, "Empty file should return empty string")
})
t.Run("strips whitespace from TOKEN_FILE", func(t *testing.T) {
unsetEnvVars()
tokenWithWhitespace := " test-token-with-whitespace \n\t"
expectedToken := "test-token-with-whitespace"
tokenFile, err := os.CreateTemp("", "token-test-*.txt")
require.NoError(t, err)
defer os.Remove(tokenFile.Name())
_, err = tokenFile.WriteString(tokenWithWhitespace)
require.NoError(t, err)
tokenFile.Close()
os.Setenv("TOKEN_FILE", tokenFile.Name())
defer os.Unsetenv("TOKEN_FILE")
token, err := getToken()
assert.NoError(t, err)
assert.Equal(t, expectedToken, token, "Whitespace should be stripped from token file content")
})
}

View File

@@ -1,3 +1,3 @@
files:
- source: /beszel/site/src/locales/en/en.po
translation: /beszel/site/src/locales/%two_letters_code%/%two_letters_code%.po
- source: /internal/site/src/locales/en/
translation: /internal/site/src/locales/%two_letters_code%/%two_letters_code%.po

View File

@@ -69,6 +69,8 @@ func (h *Hub) StartHub() error {
if err := config.SyncSystems(e); err != nil {
return err
}
// register middlewares
h.registerMiddlewares(e)
// register api routes
if err := h.registerApiRoutes(e); err != nil {
return err
@@ -171,6 +173,37 @@ func (h *Hub) registerCronJobs(_ *core.ServeEvent) error {
return nil
}
// custom middlewares
func (h *Hub) registerMiddlewares(se *core.ServeEvent) {
// authorizes request with user matching the provided email
authorizeRequestWithEmail := func(e *core.RequestEvent, email string) (err error) {
if e.Auth != nil || email == "" {
return e.Next()
}
isAuthRefresh := e.Request.URL.Path == "/api/collections/users/auth-refresh" && e.Request.Method == http.MethodPost
e.Auth, err = e.App.FindFirstRecordByData("users", "email", email)
if err != nil || !isAuthRefresh {
return e.Next()
}
// auth refresh endpoint, make sure token is set in header
token, _ := e.Auth.NewAuthToken()
e.Request.Header.Set("Authorization", token)
return e.Next()
}
// authenticate with trusted header
if autoLogin, _ := GetEnv("AUTO_LOGIN"); autoLogin != "" {
se.Router.BindFunc(func(e *core.RequestEvent) error {
return authorizeRequestWithEmail(e, autoLogin)
})
}
// authenticate with trusted header
if trustedHeader, _ := GetEnv("TRUSTED_AUTH_HEADER"); trustedHeader != "" {
se.Router.BindFunc(func(e *core.RequestEvent) error {
return authorizeRequestWithEmail(e, e.Request.Header.Get(trustedHeader))
})
}
}
// custom api routes
func (h *Hub) registerApiRoutes(se *core.ServeEvent) error {
// auth protected routes

View File

@@ -711,3 +711,117 @@ func TestCreateUserEndpointAvailability(t *testing.T) {
scenario.Test(t)
})
}
func TestAutoLoginMiddleware(t *testing.T) {
var hubs []*beszelTests.TestHub
defer func() {
defer os.Unsetenv("AUTO_LOGIN")
for _, hub := range hubs {
hub.Cleanup()
}
}()
os.Setenv("AUTO_LOGIN", "user@test.com")
testAppFactory := func(t testing.TB) *pbTests.TestApp {
hub, _ := beszelTests.NewTestHub(t.TempDir())
hubs = append(hubs, hub)
hub.StartHub()
return hub.TestApp
}
scenarios := []beszelTests.ApiScenario{
{
Name: "GET /getkey - without auto login should fail",
Method: http.MethodGet,
URL: "/api/beszel/getkey",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
},
{
Name: "GET /getkey - with auto login should fail if no matching user",
Method: http.MethodGet,
URL: "/api/beszel/getkey",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
},
{
Name: "GET /getkey - with auto login should succeed",
Method: http.MethodGet,
URL: "/api/beszel/getkey",
ExpectedStatus: 200,
ExpectedContent: []string{"\"key\":", "\"v\":"},
TestAppFactory: testAppFactory,
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.CreateUser(app, "user@test.com", "password123")
},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func TestTrustedHeaderMiddleware(t *testing.T) {
var hubs []*beszelTests.TestHub
defer func() {
defer os.Unsetenv("TRUSTED_AUTH_HEADER")
for _, hub := range hubs {
hub.Cleanup()
}
}()
os.Setenv("TRUSTED_AUTH_HEADER", "X-Beszel-Trusted")
testAppFactory := func(t testing.TB) *pbTests.TestApp {
hub, _ := beszelTests.NewTestHub(t.TempDir())
hubs = append(hubs, hub)
hub.StartHub()
return hub.TestApp
}
scenarios := []beszelTests.ApiScenario{
{
Name: "GET /getkey - without trusted header should fail",
Method: http.MethodGet,
URL: "/api/beszel/getkey",
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
},
{
Name: "GET /getkey - with trusted header should fail if no matching user",
Method: http.MethodGet,
URL: "/api/beszel/getkey",
Headers: map[string]string{
"X-Beszel-Trusted": "user@test.com",
},
ExpectedStatus: 401,
ExpectedContent: []string{"requires valid"},
TestAppFactory: testAppFactory,
},
{
Name: "GET /getkey - with trusted header should succeed",
Method: http.MethodGet,
URL: "/api/beszel/getkey",
Headers: map[string]string{
"X-Beszel-Trusted": "user@test.com",
},
ExpectedStatus: 200,
ExpectedContent: []string{"\"key\":", "\"v\":"},
TestAppFactory: testAppFactory,
BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) {
beszelTests.CreateUser(app, "user@test.com", "password123")
},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}

View File

@@ -17,7 +17,10 @@
"linter": {
"enabled": true,
"rules": {
"recommended": true
"recommended": true,
"correctness": {
"useUniqueElementIds": "off"
}
}
},
"javascript": {
@@ -35,4 +38,4 @@
}
}
}
}
}

View File

@@ -22,7 +22,7 @@ import { memo, useEffect, useRef, useState } from "react"
import { $router, basePath, Link, navigate } from "./router"
import { SystemRecord } from "@/types"
import { SystemStatus } from "@/lib/enums"
import { AppleIcon, DockerIcon, TuxIcon, WindowsIcon } from "./ui/icons"
import { AppleIcon, DockerIcon, FreeBsdIcon, TuxIcon, WindowsIcon } from "./ui/icons"
import { InputCopy } from "./ui/input-copy"
import { getPagePath } from "@nanostores/router"
import {
@@ -253,6 +253,12 @@ export const SystemDialog = ({ setOpen, system }: { setOpen: (open: boolean) =>
copyWindowsCommand(isUnixSocket ? hostValue : port.current?.value, publicKey, token),
icons: [WindowsIcon],
},
{
text: t({ message: "FreeBSD command", context: "Button to copy install command" }),
onClick: async () =>
copyLinuxCommand(isUnixSocket ? hostValue : port.current?.value, publicKey, token),
icons: [FreeBsdIcon],
},
{
text: t`Manual setup instructions`,
url: "https://beszel.dev/guide/agent-installation#binary",

View File

@@ -9,6 +9,7 @@ import {
RotateCwIcon,
ServerIcon,
Trash2Icon,
ExternalLinkIcon,
} from "lucide-react"
import { memo, useEffect, useMemo, useState } from "react"
import {
@@ -28,7 +29,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { AppleIcon, DockerIcon, TuxIcon, WindowsIcon } from "@/components/ui/icons"
import { AppleIcon, DockerIcon, FreeBsdIcon, TuxIcon, WindowsIcon } from "@/components/ui/icons"
import { Separator } from "@/components/ui/separator"
import { Switch } from "@/components/ui/switch"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
@@ -150,6 +151,7 @@ const SectionUniversalToken = memo(() => {
setIsLoading(false)
}
// biome-ignore lint/correctness/useExhaustiveDependencies: only on mount
useEffect(() => {
updateToken()
}, [])
@@ -221,6 +223,16 @@ const ActionsButtonUniversalToken = memo(({ token, checked }: { token: string; c
onClick: () => copyWindowsCommand(port, publicKey, token),
icons: [WindowsIcon],
},
{
text: t({ message: "FreeBSD command", context: "Button to copy install command" }),
onClick: () => copyLinuxCommand(port, publicKey, token),
icons: [FreeBsdIcon],
},
{
text: t`Manual setup instructions`,
url: "https://beszel.dev/guide/agent-installation#binary",
icons: [ExternalLinkIcon],
},
]
return (
<div className="flex items-center gap-2">
@@ -291,8 +303,8 @@ const SectionTable = memo(({ fingerprints = [] }: { fingerprints: FingerprintRec
</tr>
</TableHeader>
<TableBody className="whitespace-pre">
{fingerprints.map((fingerprint, i) => (
<TableRow key={i}>
{fingerprints.map((fingerprint) => (
<TableRow key={fingerprint.id}>
<TableCell className="font-medium ps-5 py-2 max-w-60 truncate">
{fingerprint.expand.system.name}
</TableCell>
@@ -317,10 +329,10 @@ async function updateFingerprint(fingerprint: FingerprintRecord, rotateToken = f
fingerprint: "",
token: rotateToken ? generateToken() : fingerprint.token,
})
} catch (error: any) {
} catch (error: unknown) {
toast({
title: t`Error`,
description: error.message,
description: (error as Error).message,
})
}
}

View File

@@ -1,3 +1,4 @@
/** biome-ignore-all lint/suspicious/noAssignInExpressions: it's fine :) */
import type { PreinitializedMapStore } from "nanostores"
import { pb, verifyAuth } from "@/lib/api"
import {
@@ -16,9 +17,10 @@ const COLLECTION = pb.collection<SystemRecord>("systems")
const FIELDS_DEFAULT = "id,name,host,port,info,status"
/** Maximum system name length for display purposes */
const MAX_SYSTEM_NAME_LENGTH = 20
const MAX_SYSTEM_NAME_LENGTH = 22
let initialized = false
// biome-ignore lint/suspicious/noConfusingVoidType: typescript rocks
let unsub: (() => void) | undefined | void
/** Initialize the systems manager and set up listeners */
@@ -104,20 +106,37 @@ async function fetchSystems(): Promise<SystemRecord[]> {
}
}
/** Makes sure the system has valid info object and throws if not */
function validateSystemInfo(system: SystemRecord) {
if (!("cpu" in system.info)) {
throw new Error(`${system.name} has no CPU info`)
}
}
/** Add system to both name and ID stores */
export function add(system: SystemRecord) {
$allSystemsByName.setKey(system.name, system)
$allSystemsById.setKey(system.id, system)
try {
validateSystemInfo(system)
$allSystemsByName.setKey(system.name, system)
$allSystemsById.setKey(system.id, system)
} catch (error) {
console.error(error)
}
}
/** Update system in stores */
export function update(system: SystemRecord) {
// if name changed, make sure old name is removed from the name store
const oldName = $allSystemsById.get()[system.id]?.name
if (oldName !== system.name) {
$allSystemsByName.setKey(oldName, undefined as any)
try {
validateSystemInfo(system)
// if name changed, make sure old name is removed from the name store
const oldName = $allSystemsById.get()[system.id]?.name
if (oldName !== system.name) {
$allSystemsByName.setKey(oldName, undefined as unknown as SystemRecord)
}
add(system)
} catch (error) {
console.error(error)
}
add(system)
}
/** Remove system from stores */
@@ -132,7 +151,7 @@ export function remove(system: SystemRecord) {
/** Remove system from specific store */
function removeFromStore(system: SystemRecord, store: PreinitializedMapStore<Record<string, SystemRecord>>) {
const key = store === $allSystemsByName ? system.name : system.id
store.setKey(key, undefined as any)
store.setKey(key, undefined as unknown as SystemRecord)
}
/** Action functions for subscription */

View File

@@ -41,38 +41,38 @@ msgstr "已选择 {0} / {1} 行"
#: src/lib/utils.ts
msgid "1 hour"
msgstr "1小时"
msgstr "1 小时"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "1 min"
msgstr "1分钟"
msgstr "1 分钟"
#: src/lib/utils.ts
msgid "1 week"
msgstr "1周"
msgstr "1 周"
#: src/lib/utils.ts
msgid "12 hours"
msgstr "12小时"
msgstr "12 小时"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "15 min"
msgstr "15分钟"
msgstr "15 分钟"
#: src/lib/utils.ts
msgid "24 hours"
msgstr "24小时"
msgstr "24 小时"
#: src/lib/utils.ts
msgid "30 days"
msgstr "30天"
msgstr "30 天"
#. Load average
#: src/components/charts/load-average-chart.tsx
msgid "5 min"
msgstr "5分钟"
msgstr "5 分钟"
#. Table column
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -103,7 +103,7 @@ msgstr "添加客户端"
#: src/components/routes/settings/notifications.tsx
msgid "Add URL"
msgstr "添加URL"
msgstr "添加 URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
@@ -137,7 +137,7 @@ msgstr "所有客户端"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Are you sure you want to delete {name}?"
msgstr "您确定要删除{name}吗?"
msgstr "您确定要删除 {name} 吗?"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Are you sure?"
@@ -189,11 +189,11 @@ msgstr "电池"
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel支持OpenID Connect和其他OAuth2认证方式。"
msgstr "Beszel 支持 OpenID Connect 和其他 OAuth2 认证方式。"
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
msgstr "Beszel使用<0>Shoutrrr</0>以实现与常见的通知服务集成。"
msgstr "Beszel 使用 <0>Shoutrrr</0> 以实现与常见的通知服务集成。"
#: src/components/add-system.tsx
msgid "Binary"
@@ -338,7 +338,7 @@ msgstr "复制下面的客户端<0>docker-compose.yml</0>内容,或使用<1>
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Copy YAML"
msgstr "复制YAML"
msgstr "复制 YAML"
#: src/components/systems-table/systems-table-columns.tsx
msgid "CPU"
@@ -348,7 +348,7 @@ msgstr "CPU"
#: src/components/routes/system.tsx
#: src/lib/alerts.ts
msgid "CPU Usage"
msgstr "CPU使用率"
msgstr "CPU 使用率"
#: src/components/login/auth-form.tsx
msgid "Create account"
@@ -397,7 +397,7 @@ msgstr "磁盘"
#: src/components/routes/system.tsx
msgid "Disk I/O"
msgstr "磁盘I/O"
msgstr "磁盘 I/O"
#: src/components/routes/settings/general.tsx
msgid "Disk unit"
@@ -415,15 +415,15 @@ msgstr "{extraFsName}的磁盘使用"
#: src/components/routes/system.tsx
msgid "Docker CPU Usage"
msgstr "Docker CPU使用"
msgstr "Docker CPU 使用"
#: src/components/routes/system.tsx
msgid "Docker Memory Usage"
msgstr "Docker内存使用"
msgstr "Docker 内存使用"
#: src/components/routes/system.tsx
msgid "Docker Network I/O"
msgstr "Docker网络I/O"
msgstr "Docker 网络 I/O"
#: src/components/command-palette.tsx
msgid "Documentation"
@@ -603,15 +603,15 @@ msgstr "系统负载"
#: src/lib/alerts.ts
msgid "Load Average 15m"
msgstr "15分钟内的平均负载"
msgstr "15 分钟内的平均负载"
#: src/lib/alerts.ts
msgid "Load Average 1m"
msgstr "1分钟负载平均值"
msgstr "1 分钟负载平均值"
#: src/lib/alerts.ts
msgid "Load Average 5m"
msgstr "5分钟内的平均负载"
msgstr "5 分钟内的平均负载"
#. Short label for load average
#: src/components/systems-table/systems-table-columns.tsx
@@ -660,11 +660,11 @@ msgstr "内存"
#: src/components/routes/system.tsx
#: src/lib/alerts.ts
msgid "Memory Usage"
msgstr "内存使用"
msgstr "内存使用"
#: src/components/routes/system.tsx
msgid "Memory usage of docker containers"
msgstr "Docker 容器的内存使用"
msgstr "Docker 容器的内存使用"
#: src/components/add-system.tsx
#: src/components/alerts-history-columns.tsx
@@ -709,7 +709,7 @@ msgstr "通知"
#: src/components/login/auth-form.tsx
msgid "OAuth 2 / OIDC support"
msgstr "支持 OAuth 2 / OIDC"
msgstr "支持 OAuth 2/OIDC"
#: src/components/routes/settings/config-yaml.tsx
msgid "On each restart, systems in the database will be updated to match the systems defined in the file."
@@ -741,7 +741,7 @@ msgstr "第 {0} 页,共 {1} 页"
#: src/components/command-palette.tsx
msgid "Pages / Settings"
msgstr "页面/设置"
msgstr "页面 / 设置"
#: src/components/login/auth-form.tsx
#: src/components/login/auth-form.tsx
@@ -774,7 +774,7 @@ msgstr "已暂停 ({pausedSystemsLength})"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
msgstr "请<0>配置SMTP服务器</0>以确保警报被传递。"
msgstr "请<0>配置 SMTP 服务器</0>以确保警报被传递。"
#: src/components/alerts/alerts-sheet.tsx
msgid "Please check logs for more details."
@@ -909,7 +909,7 @@ msgstr "登录"
#: src/components/command-palette.tsx
msgid "SMTP settings"
msgstr "SMTP设置"
msgstr "SMTP 设置"
#: src/components/systems-table/systems-table.tsx
msgid "Sort By"
@@ -931,7 +931,7 @@ msgstr "系统使用的 SWAP 空间"
#: src/components/routes/system.tsx
msgid "Swap Usage"
msgstr "SWAP 使用"
msgstr "SWAP 使用"
#: src/components/alerts-history-columns.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1024,7 +1024,7 @@ msgstr "令牌"
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens & Fingerprints"
msgstr "令牌指纹"
msgstr "令牌指纹"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
@@ -1032,19 +1032,19 @@ msgstr "令牌允许客户端连接和注册。指纹是每个系统唯一的稳
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "令牌指纹用于验证到中心的WebSocket连接。"
msgstr "令牌指纹用于验证到中心的 WebSocket 连接。"
#: src/lib/alerts.ts
msgid "Triggers when 1 minute load average exceeds a threshold"
msgstr "当1分钟负载平均值超过阈值时触发"
msgstr "当 1 分钟负载平均值超过阈值时触发"
#: src/lib/alerts.ts
msgid "Triggers when 15 minute load average exceeds a threshold"
msgstr "当15分钟负载平均值超过阈值时触发"
msgstr "当 15 分钟负载平均值超过阈值时触发"
#: src/lib/alerts.ts
msgid "Triggers when 5 minute load average exceeds a threshold"
msgstr "当5分钟内的平均负载超过阈值时触发"
msgstr "当 5 分钟内的平均负载超过阈值时触发"
#: src/lib/alerts.ts
msgid "Triggers when any sensor exceeds a threshold"
@@ -1056,7 +1056,7 @@ msgstr "当网络的上/下行速度超过阈值时触发"
#: src/lib/alerts.ts
msgid "Triggers when CPU usage exceeds a threshold"
msgstr "当CPU使用率超过阈值时触发"
msgstr "当 CPU 使用率超过阈值时触发"
#: src/lib/alerts.ts
msgid "Triggers when memory usage exceeds a threshold"
@@ -1174,11 +1174,11 @@ msgstr "写入"
#: src/components/routes/settings/layout.tsx
msgid "YAML Config"
msgstr "YAML配置"
msgstr "YAML 配置"
#: src/components/routes/settings/config-yaml.tsx
msgid "YAML Configuration"
msgstr "YAML配置"
msgstr "YAML 配置"
#: src/components/routes/settings/layout.tsx
msgid "Your user settings have been updated."

View File

@@ -74,6 +74,19 @@ const Layout = () => {
document.documentElement.dir = direction
}, [direction])
// biome-ignore lint/correctness/useExhaustiveDependencies: only run on mount
useEffect(() => {
// refresh auth if not authenticated (required for trusted auth header)
if (!authenticated) {
pb.collection("users")
.authRefresh()
.then((res) => {
pb.authStore.save(res.token, res.record)
$authenticated.set(!!pb.authStore.isValid)
})
}
}, [])
return (
<DirectionProvider dir={direction}>
{!authenticated ? (

View File

@@ -1,5 +1,13 @@
## 0.12.8
- Add setting for time format (12h / 24h). (#424)
- Add experimental one-time password (OTP) support.
- Add `TRUSTED_AUTH_HEADER` environment variable for authentication forwarding. (#399)
- Add `AUTO_LOGIN` environment variable for automatic login. (#399)
- Add FreeBSD support for agent install script and update command.
## 0.12.7

View File

@@ -1,7 +1,7 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "beszel.fullname" . }}-web
name: {{ include "beszel.fullname" . }}
labels:
{{- include "beszel.labels" . | nindent 4 }}
{{- if .Values.service.annotations }}

View File

@@ -30,14 +30,10 @@ securityContext: {}
service:
enabled: true
type: LoadBalancer
loadBalancerIP: "10.0.10.251"
annotations: {}
type: ClusterIP
loadBalancerIP: ""
port: 8090
# -- Annotations for the DHCP service
annotations:
metallb.universe.tf/address-pool: pool
metallb.universe.tf/allow-shared-ip: beszel-hub-web
# -- Labels for the DHCP service
ingress:
enabled: false
@@ -96,7 +92,7 @@ persistentVolumeClaim:
accessModes:
- ReadWriteOnce
storageClass: "retain-local-path"
storageClass: ""
# -- volume claim size
size: "500Mi"