Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b122eb2
feat(device-security): add TypeScript interfaces and DeviceSecurityPr…
Apr 10, 2026
b69c6ef
feat: add device security settings page
Apr 10, 2026
eeed710
feat: add device security enrollments page
Apr 10, 2026
5e51fb1
feat: add device security trusted CAs page
Apr 10, 2026
dd937de
fix: add type guards, inventory_type passthrough, error handling in d…
Apr 10, 2026
4d5c329
fix: add error handling for renewDevice in DevicesTable
Apr 10, 2026
860c7ce
feat: add device security navigation and layout
Apr 10, 2026
d177e04
fix: gate device security navigation by isRestricted permission
Apr 10, 2026
81fda0d
fix: add error state, extend cert-and-sso lockout warning, clamp vali…
Apr 10, 2026
5932bff
fix: add PEM END certificate marker validation in AddTrustedCAModal
Apr 10, 2026
32e7cb9
fix: fix empty state text, add reason column, add error feedback in e…
Apr 10, 2026
af9c7f3
fix: move DeviceSecurityProvider to layout, add /device-security redi…
Apr 10, 2026
f89fe65
fix: remove unsupported title prop from Callout in settings error state
Apr 10, 2026
9f57b51
fix: align CAType values with backend (builtin/vault/smallstep/scep, …
Apr 10, 2026
44f0037
feat(device-security): add CA config and inventory types and provider…
Apr 11, 2026
f046ee4
feat(device-security): add Inventory nav item and update Trusted CAs …
Apr 11, 2026
285a409
feat(device-security): redesign settings page with CA config, enrollm…
Apr 11, 2026
69dc5e0
fix: spec compliance corrections for settings page
Apr 11, 2026
976eaad
fix: improve accessibility in CA test panel and settings
Apr 11, 2026
5af0b2a
feat: add inventory configuration page
Apr 11, 2026
329940e
fix: add validation and accessibility improvements to inventory page
Apr 11, 2026
81f4f38
fix: remove OCSP fields, fix handleSave error handling, fix handleTes…
Apr 11, 2026
50c7516
feat: inventory page - two-tab static list, status callout, coming-so…
Apr 11, 2026
e43239f
fix: prevent race in inventory save, guard disabled provider types
Apr 11, 2026
7d0bb31
fix: update Dockerfile to nginx:alpine, fix stand for reviewers
Apr 11, 2026
a6dab03
fix: remove duplicate daemon directive in nginx.conf
Apr 11, 2026
6471257
feat: multi-source inventory, fix defaults and styling
Apr 11, 2026
79577bd
fix: prevent Bearer undefined requests when OIDC token not yet loaded
Apr 12, 2026
b003023
feat: add require_inventory_check toggle and cert_approver role
Apr 12, 2026
daed654
chore: update package-lock.json
Apr 12, 2026
99b82b2
feat: add Beta badge to Device Security nav item
Apr 13, 2026
4b61a08
fix: sync caType into localCAConfig so Test Connection sends correct …
Apr 13, 2026
578c243
feat: show peer name as link in enrollments table
Apr 13, 2026
193ce1a
feat: show peer name as link in device certificates table
Apr 13, 2026
c95455d
feat: add serial numbers CRUD in inventory static allow-list
Apr 13, 2026
b00c705
feat: expandable certificate PEM viewer in trusted CAs table
Apr 13, 2026
0cc8df8
security: confirmation dialogs for enrollment actions, strip inactive…
Apr 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
// }
// }
// }
// }
28 changes: 10 additions & 18 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
FROM alpine:3.14
FROM nginx:alpine

RUN apk add --no-cache bash curl less ca-certificates git tzdata zip gettext \
nginx curl supervisor certbot-nginx && \
rm -rf /var/cache/apk/* && mkdir -p /run/nginx

STOPSIGNAL SIGINT
EXPOSE 80
EXPOSE 443
ENTRYPOINT ["/usr/bin/supervisord","-c","/etc/supervisord.conf"]

WORKDIR /usr/share/nginx/html
# copy configuration files
COPY docker/default.conf /etc/nginx/http.d/default.conf

# Copy nginx configs
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/init_cert.sh /usr/local/init_cert.sh
COPY docker/init_react_envs.sh /usr/local/init_react_envs.sh
RUN chmod +x /usr/local/init_cert.sh && rm /etc/crontabs/root
RUN chmod +x /usr/local/init_react_envs.sh
COPY docker/default.conf /etc/nginx/conf.d/default.conf

# Copy init script as an entrypoint hook (runs before nginx starts)
COPY docker/init_react_envs.sh /docker-entrypoint.d/40-init-react-envs.sh
RUN chmod +x /docker-entrypoint.d/40-init-react-envs.sh

# configure supervisor
COPY docker/supervisord.conf /etc/supervisord.conf
# copy build files
COPY out/ /usr/share/nginx/html/
# Copy static build output
COPY out/ /usr/share/nginx/html/
60 changes: 30 additions & 30 deletions docker/init_react_envs.sh
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
#!/bin/bash
#!/bin/sh
set -e

if [[ -z "${AUTH_AUTHORITY}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
if [ -z "${AUTH_AUTHORITY}" ]; then
if [ -z "${AUTH0_DOMAIN}" ]; then
echo "AUTH_AUTHORITY or AUTH0_DOMAIN environment variable must be set"
exit 1
fi
fi

if [[ -z "${AUTH_CLIENT_ID}" ]]; then
if [[ -z "${AUTH0_CLIENT_ID}" ]]; then
if [ -z "${AUTH_CLIENT_ID}" ]; then
if [ -z "${AUTH0_CLIENT_ID}" ]; then
echo "AUTH_CLIENT_ID or AUTH0_CLIENT_ID environment variable must be set"
exit 1
fi
fi

if [[ -z "${AUTH_AUDIENCE}" ]]; then
if [[ -z "${AUTH0_AUDIENCE}" ]]; then
if [ -z "${AUTH_AUDIENCE}" ]; then
if [ -z "${AUTH0_AUDIENCE}" ]; then
echo "AUTH_AUDIENCE or AUTH0_AUDIENCE environment variable must be set"
exit 1
fi
fi

if [[ "${AUTH_AUDIENCE}" == "none" ]]; then
if [ "${AUTH_AUDIENCE}" = "none" ]; then
unset AUTH_AUDIENCE
fi

if [[ -z "${AUTH_SUPPORTED_SCOPES}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
if [ -z "${AUTH_SUPPORTED_SCOPES}" ]; then
if [ -z "${AUTH0_DOMAIN}" ]; then
echo "AUTH_SUPPORTED_SCOPES environment variable must be set"
exit 1
fi
fi

if [[ -z "${USE_AUTH0}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
if [ -z "${USE_AUTH0}" ]; then
if [ -z "${AUTH0_DOMAIN}" ]; then
echo "USE_AUTH0 environment variable must be set"
exit 1
fi
fi

if [[ -z "${NETBIRD_MGMT_API_ENDPOINT}" ]]; then
if [ -z "${NETBIRD_MGMT_API_ENDPOINT}" ]; then
echo "NETBIRD_MGMT_API_ENDPOINT environment variable must be set"
exit 1
fi

export AUTH_AUTHORITY=${AUTH_AUTHORITY:-https://$AUTH0_DOMAIN}
export AUTH_CLIENT_ID=${AUTH_CLIENT_ID:-$AUTH0_CLIENT_ID}
export AUTH_CLIENT_SECRET=${AUTH_CLIENT_SECRET}
export AUTH_AUDIENCE=${AUTH_AUDIENCE:-$AUTH0_AUDIENCE}
export AUTH_REDIRECT_URI=${AUTH_REDIRECT_URI}
export AUTH_SILENT_REDIRECT_URI=${AUTH_SILENT_REDIRECT_URI}
export USE_AUTH0=${USE_AUTH0:-true}
export AUTH_SUPPORTED_SCOPES=${AUTH_SUPPORTED_SCOPES:-openid profile email api offline_access email_verified}
export AUTH_AUTHORITY="${AUTH_AUTHORITY:-https://${AUTH0_DOMAIN}}"
export AUTH_CLIENT_ID="${AUTH_CLIENT_ID:-${AUTH0_CLIENT_ID}}"
export AUTH_CLIENT_SECRET="${AUTH_CLIENT_SECRET}"
export AUTH_AUDIENCE="${AUTH_AUDIENCE:-${AUTH0_AUDIENCE}}"
export AUTH_REDIRECT_URI="${AUTH_REDIRECT_URI}"
export AUTH_SILENT_REDIRECT_URI="${AUTH_SILENT_REDIRECT_URI}"
export USE_AUTH0="${USE_AUTH0:-true}"
export AUTH_SUPPORTED_SCOPES="${AUTH_SUPPORTED_SCOPES:-openid profile email api offline_access email_verified}"

export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//')
export NETBIRD_MGMT_GRPC_API_ENDPOINT=${NETBIRD_MGMT_GRPC_API_ENDPOINT}
export NETBIRD_HOTJAR_TRACK_ID=${NETBIRD_HOTJAR_TRACK_ID}
export NETBIRD_GOOGLE_ANALYTICS_ID=${NETBIRD_GOOGLE_ANALYTICS_ID}
export NETBIRD_GOOGLE_TAG_MANAGER_ID=${NETBIRD_GOOGLE_TAG_MANAGER_ID}
export NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
export NETBIRD_DRAG_QUERY_PARAMS=${NETBIRD_DRAG_QUERY_PARAMS:-false}
export NETBIRD_WASM_PATH=${NETBIRD_WASM_PATH}
export NETBIRD_MGMT_API_ENDPOINT="$(echo "$NETBIRD_MGMT_API_ENDPOINT" | sed -E 's/(:80|:443)$//')"
export NETBIRD_MGMT_GRPC_API_ENDPOINT="${NETBIRD_MGMT_GRPC_API_ENDPOINT}"
export NETBIRD_HOTJAR_TRACK_ID="${NETBIRD_HOTJAR_TRACK_ID}"
export NETBIRD_GOOGLE_ANALYTICS_ID="${NETBIRD_GOOGLE_ANALYTICS_ID}"
export NETBIRD_GOOGLE_TAG_MANAGER_ID="${NETBIRD_GOOGLE_TAG_MANAGER_ID}"
export NETBIRD_TOKEN_SOURCE="${NETBIRD_TOKEN_SOURCE:-accessToken}"
export NETBIRD_DRAG_QUERY_PARAMS="${NETBIRD_DRAG_QUERY_PARAMS:-false}"
export NETBIRD_WASM_PATH="${NETBIRD_WASM_PATH}"

echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"

Expand All @@ -74,4 +74,4 @@ for f in $(grep -R -l AUTH_SUPPORTED_SCOPES /usr/share/nginx/html); do
cp "$f" "$f".copy
envsubst "$ENV_STR" < "$f".copy > "$f"
rm "$f".copy
done
done
4 changes: 1 addition & 3 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# /etc/nginx/nginx.conf
daemon off;

user nginx;

# Set number of worker processes automatically based on number of CPU cores.
Expand Down Expand Up @@ -136,7 +134,7 @@ http {


# Includes virtual hosts configs.
include /etc/nginx/http.d/*.conf;
include /etc/nginx/conf.d/*.conf;
}

# TIP: Uncomment if you use stream module.
Expand Down
20 changes: 1 addition & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions src/app/(dashboard)/device-security/devices/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use client";

import Breadcrumbs from "@components/Breadcrumbs";
import Paragraph from "@components/Paragraph";
import SkeletonTable from "@components/skeletons/SkeletonTable";
import { ShieldCheckIcon } from "lucide-react";
import React, { lazy, Suspense } from "react";
import PageContainer from "@/layouts/PageContainer";

const DevicesTable = lazy(
() => import("@/modules/device-security/DevicesTable"),
);

export default function DevicesPage() {
return (
<PageContainer>
<div className={"p-default py-6"}>
<Breadcrumbs>
<Breadcrumbs.Item
href={"/device-security/devices"}
label={"Device Security"}
icon={<ShieldCheckIcon size={13} />}
/>
<Breadcrumbs.Item
href={"/device-security/devices"}
label={"Devices"}
Comment on lines +20 to +26
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Breadcrumb hierarchy is duplicated; parent and current item point to the same URL.

Line 20 and Line 25 both target /device-security/devices, so users can’t navigate “up” from the first crumb.

🧭 Suggested fix
           <Breadcrumbs.Item
-            href={"/device-security/devices"}
+            href={"/device-security/settings"}
             label={"Device Security"}
             icon={<ShieldCheckIcon size={13} />}
           />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
href={"/device-security/devices"}
label={"Device Security"}
icon={<ShieldCheckIcon size={13} />}
/>
<Breadcrumbs.Item
href={"/device-security/devices"}
label={"Devices"}
href={"/device-security/settings"}
label={"Device Security"}
icon={<ShieldCheckIcon size={13} />}
/>
<Breadcrumbs.Item
href={"/device-security/devices"}
label={"Devices"}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/`(dashboard)/device-security/devices/page.tsx around lines 20 - 26,
The breadcrumb items are duplicating the same href; update the parent breadcrumb
so it points to the parent section rather than the current page. In the
Breadcrumbs.Item with label "Device Security" (using ShieldCheckIcon) change
href from "/device-security/devices" to the parent route "/device-security",
leaving the "Devices" Breadcrumbs.Item href as "/device-security/devices" so
users can navigate up.

active
/>
</Breadcrumbs>
<h1>Device Certificates</h1>
<Paragraph>
Certificates issued to devices in your network. Renew or revoke
certificates to control device access.
</Paragraph>
</div>
<Suspense fallback={<SkeletonTable />}>
<DevicesTable />
</Suspense>
</PageContainer>
);
}
42 changes: 42 additions & 0 deletions src/app/(dashboard)/device-security/enrollments/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"use client";

import Breadcrumbs from "@components/Breadcrumbs";
import Paragraph from "@components/Paragraph";
import SkeletonTable from "@components/skeletons/SkeletonTable";
import { ShieldCheckIcon } from "lucide-react";
import React, { lazy, Suspense } from "react";
import PageContainer from "@/layouts/PageContainer";

const EnrollmentsTable = lazy(
() => import("@/modules/device-security/EnrollmentsTable"),
);

export default function EnrollmentsPage() {
return (
<PageContainer>
<div className="p-default py-6">
<Breadcrumbs>
<Breadcrumbs.Item
href="/device-security/enrollments"
label="Device Security"
icon={<ShieldCheckIcon size={13} />}
/>
<Breadcrumbs.Item
href="/device-security/enrollments"
label="Enrollments"
active
/>
</Breadcrumbs>
<h1>Device Enrollments</h1>
<Paragraph>
Review and manage device enrollment requests. Approve or reject
pending requests to control which devices can connect to your
network.
</Paragraph>
</div>
<Suspense fallback={<SkeletonTable />}>
<EnrollmentsTable />
</Suspense>
</PageContainer>
);
}
2 changes: 2 additions & 0 deletions src/app/(dashboard)/device-security/inventory/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import InventoryPage from "@/modules/device-security/InventoryPage";
export default InventoryPage;
Loading