+ Authentication is required before cellular data can be read for this instance.
+
+ );
+ }
+
+ if (!dataSource) {
+ return (
+
+ No safe cellular read data source is available. This console will not invent or call an
+ uncontracted production endpoint.
+
+ );
+ }
+
+ const ownedSnapshot =
+ state.kind !== 'idle' && state.snapshot?.ownerId === instance.id ? state.snapshot : undefined;
+
+ if ((state.kind === 'idle' || state.kind === 'loading') && !ownedSnapshot) {
+ return (
+
+ {state.kind === 'loading' ?
Refreshing cellular data…
: null}
+ {state.kind === 'error' ? (
+
+
Refresh failed; showing the last known cellular data.
+
setRetry((value) => value + 1)}>
+ Retry loading cellular data
+
+
+ ) : null}
+ {instance.freshness !== 'fresh' ? (
+
+ Cellular data is {instance.freshness}; verify freshness before relying on these values.
+
+ ) : null}
+ {snapshot.observedAt ?
Observed {snapshot.observedAt}
: null}
+
+ {SECTIONS.map(([key, label, fields]) => (
+
+ ))}
+
+
+ Network registration operations
+
+ Automatic network registration is available only through the audited R2 prepare, confirm,
+ and execute flow. Manual registration and monitoring controls remain unavailable. This
+ read-only panel does not bypass those gates.
+
+
+
+ );
+}
diff --git a/apps/web/src/instances/device-network-module.test.tsx b/apps/web/src/instances/device-network-module.test.tsx
new file mode 100644
index 0000000..fa06740
--- /dev/null
+++ b/apps/web/src/instances/device-network-module.test.tsx
@@ -0,0 +1,258 @@
+// @vitest-environment jsdom
+import { cleanup, render, screen, within } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { afterEach, describe, expect, it, vi } from 'vitest';
+
+import type { InstanceContext } from '../app-shell.js';
+import {
+ DeviceNetworkModule,
+ type DeviceNetworkDataSource,
+ type DeviceNetworkSnapshot,
+} from './device-network-module.js';
+
+afterEach(cleanup);
+
+const owner: InstanceContext = {
+ id: 'alpha',
+ name: 'Alpha',
+ origin: 'https://alpha.example',
+ status: 'online',
+ authentication: 'authenticated',
+ freshness: 'fresh',
+};
+
+const snapshot: DeviceNetworkSnapshot = {
+ observedAt: '2026-07-17T11:00:00Z',
+ wlan: {
+ status: {
+ enabled: true,
+ radioState: 'on',
+ connectionState: 'connected',
+ activeProfile: 'office',
+ ssid: 'Operations Wi-Fi',
+ },
+ profiles: [
+ {
+ name: 'office',
+ ssid: 'Operations Wi-Fi',
+ security: 'WPA3',
+ enabled: true,
+ priority: 1,
+ // Deliberate excess field: the module must only render its bounded allowlist.
+ password: 'never-render-this',
+ },
+ ],
+ },
+ interfaces: [
+ {
+ name: 'wlan0',
+ kind: 'wireless',
+ state: 'up',
+ macAddress: '00:11:22:33:44:55',
+ mtu: 1500,
+ addresses: [{ family: 'IPv4', address: '192.0.2.10', prefixLength: 24, scope: 'global' }],
+ },
+ ],
+ ddns: {
+ status: {
+ enabled: true,
+ state: 'updated',
+ lastUpdateAt: '2026-07-17T10:58:00Z',
+ },
+ config: {
+ provider: 'Example DNS',
+ hostname: 'gateway.example.test',
+ updateIntervalSeconds: 300,
+ // Deliberate excess fields must not escape into the DOM.
+ username: 'private-user',
+ password: 'private-password',
+ },
+ logSummary: {
+ totalEntries: 12,
+ successfulUpdates: 11,
+ failedUpdates: 1,
+ lastEventAt: '2026-07-17T10:58:00Z',
+ },
+ },
+};
+
+function deferredSource() {
+ let resolve!: (value: DeviceNetworkSnapshot) => void;
+ let reject!: (reason: unknown) => void;
+ const load = vi.fn