diff --git a/cmd/pulse-agent/main.go b/cmd/pulse-agent/main.go index cfc0d4867..c9b9269e1 100644 --- a/cmd/pulse-agent/main.go +++ b/cmd/pulse-agent/main.go @@ -1376,24 +1376,6 @@ func applyRemoteSettings(cfg *Config, settings map[string]interface{}, logger *z } } -func remoteBoolSetting(settings map[string]interface{}, key string) (bool, bool) { - value, ok := settings[key] - if !ok { - return false, false - } - parsed, ok := value.(bool) - return parsed, ok -} - -func remoteStringSetting(settings map[string]interface{}, key string) (string, bool) { - value, ok := settings[key] - if !ok { - return "", false - } - parsed, ok := value.(string) - return parsed, ok -} - func remoteDurationSetting(settings map[string]interface{}, key string) (time.Duration, bool) { value, ok := settings[key] if !ok { diff --git a/frontend-modern/src/api/ai.ts b/frontend-modern/src/api/ai.ts index ad895727c..667beee8a 100644 --- a/frontend-modern/src/api/ai.ts +++ b/frontend-modern/src/api/ai.ts @@ -556,20 +556,6 @@ export interface StepResult { run_at: string; } -export interface RemediationExecution { - id: string; - plan_id: string; - status: 'pending' | 'approved' | 'running' | 'completed' | 'failed' | 'rolled_back'; - approved_by?: string; - approved_at?: string; - started_at?: string; - completed_at?: string; - current_step: number; - step_results?: StepResult[]; - error?: string; - rollback_error?: string; -} - // Compatibility response shape for older execution endpoints. export interface RemediationExecutionResult { execution_id: string; diff --git a/frontend-modern/src/api/monitoring.ts b/frontend-modern/src/api/monitoring.ts index 181b445b2..3c28219b8 100644 --- a/frontend-modern/src/api/monitoring.ts +++ b/frontend-modern/src/api/monitoring.ts @@ -16,29 +16,6 @@ import { parseOptionalAPIResponseOrNull, } from './responseUtils'; -export interface RemovedDockerHost { - id: string; - hostname?: string; - displayName?: string; - removedAt: number; -} - -export interface RemovedHostAgent { - id: string; - hostname?: string; - displayName?: string; - linkedVmId?: string; - linkedContainerId?: string; - removedAt: number; -} - -export interface RemovedKubernetesCluster { - id: string; - name?: string; - displayName?: string; - removedAt: number; -} - async function deleteResource( url: string, parseErrorMessage: string, diff --git a/frontend-modern/src/api/responseUtils.ts b/frontend-modern/src/api/responseUtils.ts index 211e4800a..80156930e 100644 --- a/frontend-modern/src/api/responseUtils.ts +++ b/frontend-modern/src/api/responseUtils.ts @@ -201,14 +201,6 @@ export function apiErrorCode(error: unknown): string | null { return trimmedOptionalString((error as APIErrorLike).code); } -export function apiErrorDetail(error: unknown): string | null { - if (!error || typeof error !== 'object') { - return null; - } - - return trimmedOptionalString((error as APIErrorLike).detail); -} - export function apiErrorDetails(error: unknown): Record | null { if (!error || typeof error !== 'object') { return null; diff --git a/frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts b/frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts index 0c66963c6..e75cbc817 100644 --- a/frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts +++ b/frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts @@ -359,5 +359,3 @@ export const formatInteger = (value?: number): string => { if (value === undefined || value === null || Number.isNaN(value)) return '—'; return new Intl.NumberFormat().format(Math.round(value)); }; - -export const ALIAS_COLLAPSE_THRESHOLD = 4; diff --git a/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts b/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts index aa277cdf3..8122a5400 100644 --- a/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts +++ b/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts @@ -490,7 +490,3 @@ export const useResourceDetailDrawerDerivedState = ( tabs, }; }; - -export type ResourceDetailDrawerDerivedState = ReturnType< - typeof useResourceDetailDrawerDerivedState ->; diff --git a/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts b/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts index bfd7b388a..3f1e2f17d 100644 --- a/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts +++ b/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts @@ -95,7 +95,3 @@ export const useResourceDetailDrawerDockerActionsState = ( queueDockerUpdateAll, }; }; - -export type UseResourceDetailDrawerDockerActionsStateResult = ReturnType< - typeof useResourceDetailDrawerDockerActionsState ->; diff --git a/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts b/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts index 9f7bddb36..7ae6dd26a 100644 --- a/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts +++ b/frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts @@ -234,7 +234,3 @@ export const useResourceDetailDrawerHistoryState = ( refetchHistoryFacets, }; }; - -export type ResourceDetailDrawerHistoryState = ReturnType< - typeof useResourceDetailDrawerHistoryState ->; diff --git a/frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts b/frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts index 8c9cc2459..77e311f14 100644 --- a/frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts +++ b/frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts @@ -45,7 +45,3 @@ export function useUnifiedResourceTableViewportSync( setHostBodyRef, }; } - -export type UnifiedResourceTableViewportSync = ReturnType< - typeof useUnifiedResourceTableViewportSync ->; diff --git a/frontend-modern/src/components/Settings/aiSettingsModel.ts b/frontend-modern/src/components/Settings/aiSettingsModel.ts index f7833e756..7c94d7ca4 100644 --- a/frontend-modern/src/components/Settings/aiSettingsModel.ts +++ b/frontend-modern/src/components/Settings/aiSettingsModel.ts @@ -216,16 +216,3 @@ export function isModelProviderConfigured( const provider = getProviderFromModelId(modelId); return isAIProviderConfigured(provider, settings); } - -export function groupModelsByProvider(models: AIAvailableModel[]): Map { - const grouped = new Map(); - - for (const model of models) { - const provider = getProviderFromModelId(model.id); - const existing = grouped.get(provider) || []; - existing.push(model); - grouped.set(provider, existing); - } - - return grouped; -} diff --git a/frontend-modern/src/components/Settings/infrastructureSettingsModel.ts b/frontend-modern/src/components/Settings/infrastructureSettingsModel.ts index d9deb2021..a01a8952a 100644 --- a/frontend-modern/src/components/Settings/infrastructureSettingsModel.ts +++ b/frontend-modern/src/components/Settings/infrastructureSettingsModel.ts @@ -48,34 +48,6 @@ export const matchConfiguredNodeToResource = ( }); }; -export const collectConfiguredInfrastructureHosts = (nodes: NodeConfigWithStatus[]) => { - const configuredHosts = new Set(); - const clusterMemberIPs = new Set(); - - nodes.forEach((node) => { - const cleanedHost = node.host.replace(/^https?:\/\//, '').replace(/:\d+$/, ''); - configuredHosts.add(cleanedHost.toLowerCase()); - - if (!('isCluster' in node) || !node.isCluster || !('clusterEndpoints' in node)) { - return; - } - - node.clusterEndpoints?.forEach((endpoint: ClusterEndpoint) => { - if (endpoint.ip) { - clusterMemberIPs.add(endpoint.ip.toLowerCase()); - } - if (endpoint.host) { - clusterMemberIPs.add(endpoint.host.toLowerCase()); - } - }); - }); - - return { - clusterMemberIPs, - configuredHosts, - }; -}; - const createRepresentedDiscoveryHosts = (): RepresentedDiscoveryHosts => ({ pve: new Set(), pbs: new Set(), diff --git a/frontend-modern/src/components/Settings/proxmoxSettingsModel.ts b/frontend-modern/src/components/Settings/proxmoxSettingsModel.ts index 851039651..08b4281c7 100644 --- a/frontend-modern/src/components/Settings/proxmoxSettingsModel.ts +++ b/frontend-modern/src/components/Settings/proxmoxSettingsModel.ts @@ -12,8 +12,6 @@ import type { DiscoverySettingsFormProps } from './discoverySettingsModel'; import type { TrueNASSettingsPanelState } from './useTrueNASSettingsPanelState'; import type { VMwareSettingsPanelState } from './useVMwareSettingsPanelState'; -export type DiscoveryMode = 'auto' | 'custom'; - export interface InfrastructurePlatformSettingsProps { selectedAgent: Accessor; onSelectAgent: (agent: NodeType) => void; diff --git a/frontend-modern/src/components/Settings/reportingResourceTypes.ts b/frontend-modern/src/components/Settings/reportingResourceTypes.ts index 02783a1ab..8b1378917 100644 --- a/frontend-modern/src/components/Settings/reportingResourceTypes.ts +++ b/frontend-modern/src/components/Settings/reportingResourceTypes.ts @@ -1,2 +1 @@ -export type { ReportingResourceType } from '@/utils/reportingResourceTypes'; -export { toReportingResourceType } from '@/utils/reportingResourceTypes'; + diff --git a/frontend-modern/src/components/Settings/settingsRouting.ts b/frontend-modern/src/components/Settings/settingsRouting.ts index eff2edac5..8e19926cb 100644 --- a/frontend-modern/src/components/Settings/settingsRouting.ts +++ b/frontend-modern/src/components/Settings/settingsRouting.ts @@ -1,16 +1,3 @@ export { - DEFAULT_SETTINGS_TAB, - agentKeyFromPlatformType, - deriveTabFromPath, - deriveTabFromQuery, - isRetiredSettingsCompatibilityPath, - isRouteableSettingsPath, - resolveCanonicalSettingsPath, - settingsAgentLabel, settingsAgentNodeLabel, - settingsAgentPlatformType, - settingsTabPath, - type AgentKey, - type ProxmoxPlatformType, - type SettingsTab, } from './settingsNavigationModel'; diff --git a/frontend-modern/src/components/Settings/settingsTypes.ts b/frontend-modern/src/components/Settings/settingsTypes.ts index c192b3041..42eb1f6c5 100644 --- a/frontend-modern/src/components/Settings/settingsTypes.ts +++ b/frontend-modern/src/components/Settings/settingsTypes.ts @@ -1,8 +1,3 @@ export type { - SettingsHeaderMeta, - SettingsHeaderMetaMap, - SettingsNavGroup, - SettingsNavGroupId, - SettingsNavItem, SettingsTab, } from './settingsNavigationModel'; diff --git a/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx b/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx index 7f9ddf2d7..d74b55fad 100644 --- a/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx +++ b/frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx @@ -559,5 +559,3 @@ Pulse prepares the first-host install token from setup so you can move straight tokenName, }; }; - -export type InfrastructureInstallState = ReturnType; diff --git a/frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts b/frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts index 0e8768029..e638eb10c 100644 --- a/frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts +++ b/frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts @@ -6,12 +6,6 @@ import { useInfrastructureDiscoveryRuntimeState } from './useInfrastructureDisco import { useTrueNASSettingsPanelState } from './useTrueNASSettingsPanelState'; import { useVMwareSettingsPanelState } from './useVMwareSettingsPanelState'; -export type { - DiscoveryScanStatus, - DiscoveredServer, - NodeType, -} from './infrastructureSettingsModel'; - type InfrastructureEventBus = { on(event: T, handler: (data?: EventDataMap[T]) => void): () => void; }; diff --git a/frontend-modern/src/components/SetupWizard/index.ts b/frontend-modern/src/components/SetupWizard/index.ts index 88370ca9b..74a516fc4 100644 --- a/frontend-modern/src/components/SetupWizard/index.ts +++ b/frontend-modern/src/components/SetupWizard/index.ts @@ -1,3 +1,2 @@ export { SetupWizard } from './SetupWizard'; -export { StepIndicator } from './StepIndicator'; -export type { WizardState, WizardStep } from './SetupWizard'; +export type { WizardState, } from './SetupWizard'; diff --git a/frontend-modern/src/components/Workloads/workloadMetricHistoryModel.ts b/frontend-modern/src/components/Workloads/workloadMetricHistoryModel.ts index fbb60efc4..ccc8a05e5 100644 --- a/frontend-modern/src/components/Workloads/workloadMetricHistoryModel.ts +++ b/frontend-modern/src/components/Workloads/workloadMetricHistoryModel.ts @@ -68,7 +68,6 @@ export const WORKLOAD_TABLE_HISTORY_RANGE_LABELS: Record = (props) => { const search = useSearchInputState(props); diff --git a/frontend-modern/src/components/shared/SearchTipsPopover.tsx b/frontend-modern/src/components/shared/SearchTipsPopover.tsx index e1f3906c8..f71256b96 100644 --- a/frontend-modern/src/components/shared/SearchTipsPopover.tsx +++ b/frontend-modern/src/components/shared/SearchTipsPopover.tsx @@ -11,7 +11,7 @@ import { } from './searchTipsPopoverModel'; import { useSearchTipsPopoverState } from './useSearchTipsPopoverState'; -export type { SearchTip, SearchTipsPopoverProps } from './searchTipsPopoverModel'; +export type { SearchTipsPopoverProps } from './searchTipsPopoverModel'; export const SearchTipsPopover: Component = (props) => { const triggerVariant = () => getSearchTipsPopoverTriggerVariant(props.triggerVariant); diff --git a/frontend-modern/src/components/shared/SelectionCardGroup.tsx b/frontend-modern/src/components/shared/SelectionCardGroup.tsx index 2ac7d79ce..0ad3dbdb7 100644 --- a/frontend-modern/src/components/shared/SelectionCardGroup.tsx +++ b/frontend-modern/src/components/shared/SelectionCardGroup.tsx @@ -11,9 +11,7 @@ import { useSelectionCardGroupState } from './useSelectionCardGroupState'; export type { SelectionCardGroupProps, - SelectionCardGroupVariant, SelectionCardOption, - SelectionCardTone, } from './selectionCardGroupModel'; export function SelectionCardGroup(props: SelectionCardGroupProps) { diff --git a/frontend-modern/src/components/shared/responsive/ResponsiveMetricCell.tsx b/frontend-modern/src/components/shared/responsive/ResponsiveMetricCell.tsx index b2217c942..49a9900e1 100644 --- a/frontend-modern/src/components/shared/responsive/ResponsiveMetricCell.tsx +++ b/frontend-modern/src/components/shared/responsive/ResponsiveMetricCell.tsx @@ -153,85 +153,3 @@ export const ResponsiveMetricCell: Component = (props ); }; - -/** - * Simpler metric text component for when you just want colored percentage - * without the MetricBar complexity - */ -export const MetricText: Component<{ - value: number; - type: 'cpu' | 'memory' | 'disk'; - label?: string; - class?: string; - thresholds?: MetricDisplayThresholds | null; -}> = (props) => { - const displayLabel = createMemo(() => props.label ?? formatPercent(props.value)); - const colorClass = createMemo(() => metricTextClass(props.value, props.type, props.thresholds)); - - return ( - - - - - - ); -}; - -/** - * Metric cell with explicit mobile/desktop rendering - * Use this when you need full control over what renders in each mode - */ -export const DualMetricCell: Component<{ - value: number; - type: 'cpu' | 'memory' | 'disk'; - label?: string; - sublabel?: string; - resourceId?: string; - isRunning?: boolean; - showMobile: boolean; - mobileContent?: JSX.Element; - desktopContent?: JSX.Element; - fallback?: JSX.Element; - class?: string; - thresholds?: MetricDisplayThresholds | null; -}> = (props) => { - const displayLabel = createMemo(() => props.label ?? formatPercent(props.value)); - const colorClass = createMemo(() => metricTextClass(props.value, props.type, props.thresholds)); - const isRunning = () => props.isRunning !== false; - - const defaultFallback = ( -
- -
- ); - - const defaultMobileContent = ( -
- - - -
- ); - - const defaultDesktopContent = ( - - ); - - return ( - -
- - {props.mobileContent ?? defaultMobileContent} - -
-
- ); -}; diff --git a/frontend-modern/src/components/shared/summaryChartLayout.ts b/frontend-modern/src/components/shared/summaryChartLayout.ts index 16c38fdbb..45fd9be16 100644 --- a/frontend-modern/src/components/shared/summaryChartLayout.ts +++ b/frontend-modern/src/components/shared/summaryChartLayout.ts @@ -1,3 +1,3 @@ -export const SUMMARY_CHART_SLOT_CLASS = 'h-[136px] sm:h-[150px]'; + export const SUMMARY_CHART_SLOT_COMPACT_CLASS = 'h-[108px] sm:h-[120px]'; export const SUMMARY_CHART_PLOT_AREA_CLASS = 'h-[120px] sm:h-[134px]'; diff --git a/frontend-modern/src/components/shared/summaryTimeRange.ts b/frontend-modern/src/components/shared/summaryTimeRange.ts index a9c20d8f6..70a47891c 100644 --- a/frontend-modern/src/components/shared/summaryTimeRange.ts +++ b/frontend-modern/src/components/shared/summaryTimeRange.ts @@ -8,6 +8,3 @@ export const SUMMARY_TIME_RANGE_LABEL: Record = { '24h': '24h', '7d': '7d', }; - -export const isSummaryTimeRange = (value: string): value is SummaryTimeRange => - (SUMMARY_TIME_RANGES as readonly string[]).includes(value); diff --git a/frontend-modern/src/components/shared/useCommandPaletteState.ts b/frontend-modern/src/components/shared/useCommandPaletteState.ts index ba4536693..2727cccb5 100644 --- a/frontend-modern/src/components/shared/useCommandPaletteState.ts +++ b/frontend-modern/src/components/shared/useCommandPaletteState.ts @@ -73,5 +73,3 @@ export function useCommandPaletteState(props: CommandPaletteModalProps) { setQuery, }; } - -export type CommandPaletteState = ReturnType; diff --git a/frontend-modern/src/components/shared/useContainerUpdateButtonState.ts b/frontend-modern/src/components/shared/useContainerUpdateButtonState.ts index 80d1f6050..017398e8c 100644 --- a/frontend-modern/src/components/shared/useContainerUpdateButtonState.ts +++ b/frontend-modern/src/components/shared/useContainerUpdateButtonState.ts @@ -126,5 +126,3 @@ export function useContainerUpdateButtonState(props: UpdateButtonProps) { shouldHideButton, }; } - -export type ContainerUpdateButtonState = ReturnType; diff --git a/frontend-modern/src/components/shared/useHelpIconState.ts b/frontend-modern/src/components/shared/useHelpIconState.ts index b2b430b0a..e635445fb 100644 --- a/frontend-modern/src/components/shared/useHelpIconState.ts +++ b/frontend-modern/src/components/shared/useHelpIconState.ts @@ -98,5 +98,3 @@ export function useHelpIconState(props: HelpIconProps) { toggleOpen, }; } - -export type HelpIconState = ReturnType; diff --git a/frontend-modern/src/components/shared/useMobileNavBarState.ts b/frontend-modern/src/components/shared/useMobileNavBarState.ts index 0e23cf7ab..c962d58cd 100644 --- a/frontend-modern/src/components/shared/useMobileNavBarState.ts +++ b/frontend-modern/src/components/shared/useMobileNavBarState.ts @@ -80,5 +80,3 @@ export function useMobileNavBarState(props: MobileNavBarProps) { showLeftFade, }; } - -export type MobileNavBarState = ReturnType; diff --git a/frontend-modern/src/components/shared/useWebInterfaceUrlFieldState.ts b/frontend-modern/src/components/shared/useWebInterfaceUrlFieldState.ts index 3d23ed7e4..963f6fa74 100644 --- a/frontend-modern/src/components/shared/useWebInterfaceUrlFieldState.ts +++ b/frontend-modern/src/components/shared/useWebInterfaceUrlFieldState.ts @@ -211,5 +211,3 @@ export function useWebInterfaceUrlFieldState(props: WebInterfaceUrlFieldProps) { urlValue, }; } - -export type WebInterfaceUrlFieldState = ReturnType; diff --git a/frontend-modern/src/features/alerts/guestOverrideIdentity.ts b/frontend-modern/src/features/alerts/guestOverrideIdentity.ts index 5daa9d8df..043f95363 100644 --- a/frontend-modern/src/features/alerts/guestOverrideIdentity.ts +++ b/frontend-modern/src/features/alerts/guestOverrideIdentity.ts @@ -124,16 +124,6 @@ export const getGuestOverrideIdentity = ( }; }; -export const canonicalGuestOverrideResourceId = ( - resource: GuestOverrideResourceLike, -): string | undefined => { - const identity = getGuestOverrideIdentity(resource); - if (!identity) { - return undefined; - } - return `${identity.instance}:${identity.node}:${identity.vmid}`; -}; - export const guestOverrideStorageId = (resource: GuestOverrideResourceLike): string => { const identity = getGuestOverrideIdentity(resource); if (!identity) { diff --git a/frontend-modern/src/features/alerts/thresholds/thresholdsOverrideMutationModel.ts b/frontend-modern/src/features/alerts/thresholds/thresholdsOverrideMutationModel.ts index aa865a156..3bfd9fd8e 100644 --- a/frontend-modern/src/features/alerts/thresholds/thresholdsOverrideMutationModel.ts +++ b/frontend-modern/src/features/alerts/thresholds/thresholdsOverrideMutationModel.ts @@ -40,17 +40,3 @@ export const stripStateKeys = ( delete (next as Record).poweredOffSeverity; return next; }; - -export const removeOverrideState = ( - overrides: Override[], - rawOverridesConfig: Record, - resourceId: string, -) => { - const nextRawConfig = { ...rawOverridesConfig }; - delete nextRawConfig[resourceId]; - - return { - nextOverrides: overrides.filter((override) => override.id !== resourceId), - nextRawConfig, - }; -}; diff --git a/frontend-modern/src/features/storageBackups/storagePagePresentation.ts b/frontend-modern/src/features/storageBackups/storagePagePresentation.ts index ce2664834..730a65750 100644 --- a/frontend-modern/src/features/storageBackups/storagePagePresentation.ts +++ b/frontend-modern/src/features/storageBackups/storagePagePresentation.ts @@ -81,14 +81,6 @@ export const getStoragePoolTableColumns = ( colClassName: 'hidden xl:table-column xl:w-[11%]', }, ]; - -export const STORAGE_CONTROLS_NODE_SELECT_CLASS = - 'px-2 py-1 text-xs border border-border rounded-md bg-surface text-base-content focus:ring-2 focus:ring-blue-500 focus:border-blue-500'; - -export const STORAGE_CONTROLS_NODE_DIVIDER_CLASS = 'h-5 w-px bg-surface-hover hidden sm:block'; - -export const STORAGE_CONTENT_CARD_HEADER_CLASS = - 'border-b border-border bg-surface-hover px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-muted'; export const STORAGE_CONTENT_CARD_BODY_CLASS = 'p-2'; export const STORAGE_POOLS_EMPTY_STATE_CLASS = 'p-6 text-sm text-muted'; diff --git a/frontend-modern/src/features/truenas/truenasPageModel.ts b/frontend-modern/src/features/truenas/truenasPageModel.ts index 8bf803405..ab2c15b76 100644 --- a/frontend-modern/src/features/truenas/truenasPageModel.ts +++ b/frontend-modern/src/features/truenas/truenasPageModel.ts @@ -854,18 +854,6 @@ const matchesTrueNASStorageSearch = (resource: Resource, search: string): boolea return haystack.includes(needle); }; -export function filterTrueNASStorageResources( - resources: Resource[], - search: string, - status: TrueNASStorageStatusFilter, -): Resource[] { - return resources.filter((resource) => { - if (!matchesTrueNASStorageSearch(resource, search)) return false; - if (status === 'all') return true; - return mapTrueNASStorageStatus(resource) === status; - }); -} - const resourceIncidentLabel = (resource: Resource, incident: ResourceIncident): string => { const label = asTrimmedString(resource.incidentLabel); if (label) return label; diff --git a/frontend-modern/src/routing/resourceLinks.ts b/frontend-modern/src/routing/resourceLinks.ts index 5bcede4fd..f708f8025 100644 --- a/frontend-modern/src/routing/resourceLinks.ts +++ b/frontend-modern/src/routing/resourceLinks.ts @@ -29,7 +29,6 @@ export const TRUENAS_DEFAULT_TAB = 'overview'; export const VMWARE_PATH = '/vmware'; export const VMWARE_DEFAULT_TAB = 'overview'; export const PMG_THRESHOLDS_PATH = '/alerts/thresholds/mail-gateway'; -export const ALERTS_OVERVIEW_PATH = '/alerts/overview'; export const PATROL_PATH = '/patrol'; export const STORAGE_QUERY_PARAMS = { diff --git a/frontend-modern/src/types/ai.ts b/frontend-modern/src/types/ai.ts index 1600a5dd2..71a7e8aff 100644 --- a/frontend-modern/src/types/ai.ts +++ b/frontend-modern/src/types/ai.ts @@ -191,18 +191,6 @@ export interface AIConversationMessage { content: string; } -// AI Execute request/response types -export interface AIExecuteRequest { - prompt: string; - target_type?: string; // "agent", "system-container", "vm", etc. - target_id?: string; - context?: Record; - history?: AIConversationMessage[]; // Previous conversation messages - finding_id?: string; // If fixing a patrol finding, the ID to resolve on success - model?: string; // Override model for this request (user selection in chat) - use_case?: 'chat' | 'patrol'; // Optional server-side routing/model selection -} - // Tool execution info export interface AIToolExecution { name: string; // "run_command", "read_file" @@ -387,15 +375,6 @@ export interface AIChatMessage { toolCalls?: AIChatToolCall[]; } -export interface AIChatSession { - id: string; - username: string; - title: string; - createdAt: Date; - updatedAt: Date; - messages: AIChatMessage[]; -} - // Summary returned by list endpoint (no messages) export interface AIChatSessionHandoffResource { id?: string; diff --git a/frontend-modern/src/types/api.ts b/frontend-modern/src/types/api.ts index c47da7032..a79bf70a0 100644 --- a/frontend-modern/src/types/api.ts +++ b/frontend-modern/src/types/api.ts @@ -63,30 +63,6 @@ export interface ConnectedInfrastructureItem { surfaces: ConnectedInfrastructureSurface[]; } -export interface KubernetesCluster { - id: string; - agentId: string; - name?: string; - displayName?: string; - customDisplayName?: string; - server?: string; - context?: string; - version?: string; - status: string; - lastSeen: number; - intervalSeconds: number; - agentVersion?: string; - tokenId?: string; - tokenName?: string; - tokenHint?: string; - tokenLastUsedAt?: number; - hidden?: boolean; - pendingUninstall?: boolean; - nodes?: KubernetesNode[]; - pods?: KubernetesPod[]; - deployments?: KubernetesDeployment[]; -} - export interface KubernetesNode { uid: string; name: string; @@ -1068,11 +1044,6 @@ export interface PhysicalDisk { smartAttributes?: SMARTAttributes; } -/** Returns the best resource ID for disk metrics queries (serial preferred, WWN fallback). */ -export function diskResourceId(disk: PhysicalDisk): string | null { - return disk.serial || disk.wwn || null; -} - export interface CPUInfo { model: string; cores: number; @@ -1259,7 +1230,3 @@ export type WSMessage = scanning?: boolean; }; }; - -// Utility types -export type Status = 'running' | 'stopped' | 'paused' | 'unknown'; -export type GuestType = 'vm' | 'system-container'; diff --git a/frontend-modern/src/types/config.ts b/frontend-modern/src/types/config.ts index 8c0e6830d..f413c0917 100644 --- a/frontend-modern/src/types/config.ts +++ b/frontend-modern/src/types/config.ts @@ -87,15 +87,6 @@ export interface NodesConfig { pbsInstances: PBSNodeConfig[]; } -/** - * Complete configuration structure - */ -export interface PulseConfig { - auth: Partial; // From .env - system: SystemConfig; // From system.json - nodes: NodesConfig; // From nodes.enc -} - /** * API response for security status */ @@ -180,47 +171,3 @@ export interface SSOProviderInfo { iconUrl?: string; loginUrl: string; } - -/** - * First-run setup request - */ -export interface SetupRequest { - username: string; - password: string; - apiToken?: string; - enableNotifications?: boolean; - darkMode?: boolean; -} - -/** - * Type guards for configuration validation - */ -export const isValidUpdateChannel = (value: string): value is UpdateChannel => { - return value === 'stable' || value === 'rc'; -}; - -export const isValidTimeFormat = (value: string): boolean => { - return /^([01]\d|2[0-3]):([0-5]\d)$/.test(value); -}; - -/** - * Default values for configuration - */ -export const DEFAULT_CONFIG: { - system: SystemConfig; -} = { - system: { - connectionTimeout: 60, - autoUpdateEnabled: false, - updateChannel: 'stable', - autoUpdateCheckInterval: 24, - autoUpdateTime: '03:00', - backupPollingEnabled: true, - backupPollingInterval: 0, - temperatureMonitoringEnabled: true, - telemetryEnabled: true, - sshPort: 22, - allowedOrigins: '', - frontendPort: 7655, - }, -}; diff --git a/frontend-modern/src/types/discovery.ts b/frontend-modern/src/types/discovery.ts index 9baef26e2..c08cca38e 100644 --- a/frontend-modern/src/types/discovery.ts +++ b/frontend-modern/src/types/discovery.ts @@ -162,10 +162,6 @@ export interface UpdateNotesRequest { user_secrets?: Record; } -export interface UpdateSettingsRequest { - max_discovery_age_days?: number; // Days before rediscovery (default 30) -} - // AI provider information for discovery transparency export interface AIProviderInfo { provider: string; // e.g., "anthropic", "openai", "ollama" diff --git a/frontend-modern/src/types/nodes.ts b/frontend-modern/src/types/nodes.ts index ad98f7788..44ed00684 100644 --- a/frontend-modern/src/types/nodes.ts +++ b/frontend-modern/src/types/nodes.ts @@ -104,18 +104,3 @@ export type NodeConfigWithStatus = NodeConfig & { hasToken?: boolean; status: 'connected' | 'disconnected' | 'offline' | 'error' | 'pending'; }; - -export interface NodesResponse { - pve_instances: PVENodeConfig[]; - pbs_instances: PBSNodeConfig[]; - pmg_instances?: PMGNodeConfig[]; -} - -export interface NodeUpdateRequest { - node: NodeConfig; -} - -export interface NodeDeleteResponse { - success: boolean; - message: string; -} diff --git a/frontend-modern/src/types/recovery.ts b/frontend-modern/src/types/recovery.ts index c505657e7..e2e562b43 100644 --- a/frontend-modern/src/types/recovery.ts +++ b/frontend-modern/src/types/recovery.ts @@ -137,10 +137,6 @@ export interface RecoveryPointsSeriesBucket { remote: number; } -export interface RecoveryPointsSeriesResponse { - data: RecoveryPointsSeriesBucket[]; -} - export interface RecoveryPointsFacets { clusters?: string[]; nodesAgents?: string[]; @@ -150,7 +146,3 @@ export interface RecoveryPointsFacets { hasVerification?: boolean; hasEntityId?: boolean; } - -export interface RecoveryPointsFacetsResponse { - data: RecoveryPointsFacets; -} diff --git a/frontend-modern/src/types/resource.ts b/frontend-modern/src/types/resource.ts index 842aeda22..df912a079 100644 --- a/frontend-modern/src/types/resource.ts +++ b/frontend-modern/src/types/resource.ts @@ -196,8 +196,6 @@ export const requiresGovernedResourceDisplay = (policy?: ResourcePolicy | null): if (!policy) return false; return policy.routing.scope === 'local-only' || (policy.routing.redact?.length ?? 0) > 0; }; - -export type ResourceApprovalLevel = 'none' | 'dry_run_only' | 'admin' | 'mfa'; export type ResourceChangeConfidence = 'high' | 'medium' | 'low'; export type ResourceChangeKind = | 'state_transition' diff --git a/frontend-modern/src/utils/aiFindingPresentation.ts b/frontend-modern/src/utils/aiFindingPresentation.ts index 5de3b56b1..12ed02495 100644 --- a/frontend-modern/src/utils/aiFindingPresentation.ts +++ b/frontend-modern/src/utils/aiFindingPresentation.ts @@ -342,23 +342,6 @@ export const getFindingSeverityCompactLabel = ( severity: UnifiedFinding['severity'] | string, ): string => FINDING_SEVERITY_COMPACT_LABELS[severity] || String(severity).toUpperCase(); -export const getFindingCompactBadgePresentation = ( - finding: Pick, -): FindingCompactBadgePresentation => { - if (isPatrolRuntimeFinding(finding)) { - const severityPresentation = getFindingSeverityPresentation(finding); - return { - label: severityPresentation.label, - badgeClasses: severityPresentation.badgeClasses, - }; - } - - return { - label: getFindingSeverityCompactLabel(finding.severity), - badgeClasses: getFindingSeverityBadgeClasses(finding.severity), - }; -}; - export const isPatrolRuntimeFinding = ( finding: Pick, ): boolean => { @@ -617,25 +600,6 @@ export const doesFindingNeedAttention = ( ); }; -// True when the finding has an investigation outcome indicating that some -// remediation step has run against it — anything past "fix queued." For these -// states, Verify fix is a meaningful action; for fix_queued (still awaiting -// approval) and earlier states there is nothing applied yet to verify, and -// for fix_failed the fix didn't complete so verification doesn't apply. -export const findingHasAppliedFix = ( - finding: Pick, -): boolean => { - switch (finding.investigationOutcome) { - case 'fix_executed': - case 'fix_verified': - case 'fix_verification_failed': - case 'fix_verification_unknown': - return true; - default: - return false; - } -}; - export const getFindingLoopStateBadgeClasses = (loopState: string): string => FINDING_LOOP_STATE_CLASSES[loopState] || DEFAULT_LOOP_STATE_CLASSES; diff --git a/frontend-modern/src/utils/alertConfigPresentation.ts b/frontend-modern/src/utils/alertConfigPresentation.ts index 3f9db9a4a..88d55d45a 100644 --- a/frontend-modern/src/utils/alertConfigPresentation.ts +++ b/frontend-modern/src/utils/alertConfigPresentation.ts @@ -190,10 +190,6 @@ export function getAlertConfigDiscardLabel(isReloading: boolean) { return isReloading ? ALERT_CONFIG_DISCARDING_LABEL : ALERT_CONFIG_DISCARD_LABEL; } -export function getAlertConfigSwarmGapValidationError() { - return ALERT_CONFIG_SWARM_GAP_VALIDATION; -} - export function getAlertConfigQuietHourSuppressOptions() { return ALERT_CONFIG_QUIET_HOUR_SUPPRESS_OPTIONS; } diff --git a/frontend-modern/src/utils/alertWebhookPresentation.ts b/frontend-modern/src/utils/alertWebhookPresentation.ts index 2a63983d8..168bf932c 100644 --- a/frontend-modern/src/utils/alertWebhookPresentation.ts +++ b/frontend-modern/src/utils/alertWebhookPresentation.ts @@ -275,17 +275,6 @@ export function getAlertWebhookUrlPlaceholder(urlPattern?: string) { return urlPattern || ALERT_WEBHOOK_URL_PLACEHOLDER; } -export function getAlertWebhookMentionPlaceholder(service: string) { - return ( - ALERT_WEBHOOK_SERVICE_PRESENTATION[service as AlertWebhookService]?.mentionPlaceholder || - ALERT_WEBHOOK_MENTION_FALLBACK_PLACEHOLDER - ); -} - -export function getAlertWebhookMentionHelp(service: string) { - return ALERT_WEBHOOK_SERVICE_PRESENTATION[service as AlertWebhookService]?.mentionHelp || ''; -} - export function getAlertWebhookSummaryLabel(enabledCount: number, totalCount: number) { return `${enabledCount} of ${totalCount} webhooks enabled`; } diff --git a/frontend-modern/src/utils/cloudPlans.ts b/frontend-modern/src/utils/cloudPlans.ts index 77b3b496d..0a0f80fb6 100644 --- a/frontend-modern/src/utils/cloudPlans.ts +++ b/frontend-modern/src/utils/cloudPlans.ts @@ -146,10 +146,6 @@ export function parseCloudTier(value?: string | null): CloudTierKey { } } -export function getCloudPlanForTier(value?: string | null): CloudPlanDefinition { - return CLOUD_PLAN_BY_TIER[parseCloudTier(value)]; -} - export function getCloudPlanPricePresentation( plan: CloudPlanDefinition, ): CloudPlanPricePresentation { diff --git a/frontend-modern/src/utils/commercialBillingModel.ts b/frontend-modern/src/utils/commercialBillingModel.ts index 2cfdf3c37..6fe4b42b8 100644 --- a/frontend-modern/src/utils/commercialBillingModel.ts +++ b/frontend-modern/src/utils/commercialBillingModel.ts @@ -48,8 +48,6 @@ export interface HostedCommercialModelInput { guestUsage: number; renewsOrExpires: string; } - -export const SELF_HOSTED_NOT_METERED_LABEL = 'Not metered'; export const LIFETIME_DAYS_REMAINING_LABEL = 'Permanent'; const asUnlimitedLimit = (value?: number) => diff --git a/frontend-modern/src/utils/infrastructureSummaryCache.ts b/frontend-modern/src/utils/infrastructureSummaryCache.ts index c5ef33d7a..dd33a5232 100644 --- a/frontend-modern/src/utils/infrastructureSummaryCache.ts +++ b/frontend-modern/src/utils/infrastructureSummaryCache.ts @@ -307,14 +307,6 @@ export function readInfrastructureSummaryCache( } } -export function hasFreshInfrastructureSummaryCache( - range: TimeRange, - maxAgeMs: number = INFRA_SUMMARY_CACHE_MAX_AGE_MS, - metrics?: readonly InfrastructureSummaryMetric[] | null, -): boolean { - return readInfrastructureSummaryCache(range, maxAgeMs, undefined, metrics) !== null; -} - const inFlightFetches = new Map>(); let infraSummaryFetchSeq = 0; diff --git a/frontend-modern/src/utils/licensePresentation.ts b/frontend-modern/src/utils/licensePresentation.ts index ce31f0052..53c67c56e 100644 --- a/frontend-modern/src/utils/licensePresentation.ts +++ b/frontend-modern/src/utils/licensePresentation.ts @@ -60,10 +60,6 @@ export interface LicenseInlineNotice { body: string; } -export interface LicenseActionNotice extends LicenseInlineNotice { - actionLabel: string; -} - export interface BillingAdminOrganizationBadge { label: string; badgeClass: string; diff --git a/frontend-modern/src/utils/resourceBadgePresentation.ts b/frontend-modern/src/utils/resourceBadgePresentation.ts index 77368cc37..4bd25e8cb 100644 --- a/frontend-modern/src/utils/resourceBadgePresentation.ts +++ b/frontend-modern/src/utils/resourceBadgePresentation.ts @@ -758,13 +758,3 @@ export function getContainerRuntimeBadgeForRuntime(runtime?: string | null): Res title: `Runtime: ${label}`, }; } - -export function getContainerRuntimeBadge( - platformType?: PlatformType, - platformData?: Record | null, -): ResourceBadge | null { - if (platformType !== 'docker' || !platformData) return null; - - const docker = (platformData as { docker?: { runtime?: string } } | undefined)?.docker; - return getContainerRuntimeBadgeForRuntime(docker?.runtime); -} diff --git a/frontend-modern/src/utils/storageSources.ts b/frontend-modern/src/utils/storageSources.ts index 1b6128f34..d4aa8f79b 100644 --- a/frontend-modern/src/utils/storageSources.ts +++ b/frontend-modern/src/utils/storageSources.ts @@ -163,9 +163,3 @@ export const buildStorageSourceOptionsFromKeys = ( const orderedKeys = orderStorageSourceKeys(keys).filter((key) => key !== 'all'); return [ALL_STORAGE_SOURCE_OPTION, ...orderedKeys.map((key) => getStorageSourceOption(key))]; }; - -export const DEFAULT_STORAGE_SOURCE_OPTIONS: StorageSourceOption[] = - buildStorageSourceOptionsFromKeys(['proxmox-pve', 'proxmox-pbs', 'ceph', 'truenas']); - -export const buildStorageSourceOptions = (storageList: Storage[]): StorageSourceOption[] => - buildStorageSourceOptionsFromKeys(storageList.map((storage) => resolveStorageSourceKey(storage))); diff --git a/frontend-modern/src/utils/storageSummaryCache.ts b/frontend-modern/src/utils/storageSummaryCache.ts index 305ddeca5..e8dd1ace8 100644 --- a/frontend-modern/src/utils/storageSummaryCache.ts +++ b/frontend-modern/src/utils/storageSummaryCache.ts @@ -48,11 +48,6 @@ export function fetchStorageSummaryAndCache( return request; } -export function __resetStorageSummaryCacheForTests(): void { - inMemoryCache.clear(); - inFlightFetches.clear(); -} - const unsubscribeStorageOrgSwitch = eventBus.on('org_switched', () => { inMemoryCache.clear(); inFlightFetches.clear(); diff --git a/frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts b/frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts index 984de0336..ceaa5e847 100644 --- a/frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts +++ b/frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts @@ -39,12 +39,6 @@ export function getUnifiedAgentLastSeenLabel( return row.lastSeen ? formatRelativeTime(row.lastSeen) : '—'; } -export function getMonitoringStoppedEmptyState(hasFilters: boolean): string { - return hasFilters - ? 'No monitoring-stopped items match the current filters.' - : 'No infrastructure currently has monitoring stopped.'; -} - export function getUnifiedAgentStopMonitoringUnavailableMessage(): string { return 'No host identifiers are available to stop monitoring.'; } diff --git a/frontend-modern/src/utils/unifiedAgentStatusPresentation.ts b/frontend-modern/src/utils/unifiedAgentStatusPresentation.ts index d2a81b656..998ff35e6 100644 --- a/frontend-modern/src/utils/unifiedAgentStatusPresentation.ts +++ b/frontend-modern/src/utils/unifiedAgentStatusPresentation.ts @@ -13,7 +13,6 @@ export interface UnifiedAgentLookupStatusPresentation { } export const MONITORING_STOPPED_STATUS_LABEL = 'Monitoring stopped'; -export const ALLOW_RECONNECT_LABEL = 'Allow reconnect'; export function getUnifiedAgentStatusPresentation( state: UnifiedAgentMonitoringState, diff --git a/frontend-modern/src/utils/workloadsSummaryCache.ts b/frontend-modern/src/utils/workloadsSummaryCache.ts index 6f8a725b3..b5d3475d5 100644 --- a/frontend-modern/src/utils/workloadsSummaryCache.ts +++ b/frontend-modern/src/utils/workloadsSummaryCache.ts @@ -9,7 +9,6 @@ import { normalizeOrgScope } from '@/utils/orgScope'; import { eventBus } from '@/stores/events'; export const WORKLOADS_SUMMARY_CACHE_VERSION = 6; -export const WORKLOAD_CHART_DEFAULT_POINT_LIMIT = 180; const WORKLOADS_SUMMARY_CACHE_PREFIX = 'pulse.workloadsSummaryCharts.'; const WORKLOADS_SUMMARY_CACHE_MAX_AGE_MS = 5 * 60_000; diff --git a/internal/agentexec/verifier_postconditions.go b/internal/agentexec/verifier_postconditions.go index f1bbc09ac..7cd15df4c 100644 --- a/internal/agentexec/verifier_postconditions.go +++ b/internal/agentexec/verifier_postconditions.go @@ -21,16 +21,16 @@ const ( FieldContainerStatus PostconditionField = "status" // Systemd unit fields read via DBus or systemctl show. - FieldUnitActiveState PostconditionField = "ActiveState" - FieldUnitSubState PostconditionField = "SubState" - FieldUnitActiveEnterTimestamp PostconditionField = "ActiveEnterTimestamp" + FieldUnitActiveState PostconditionField = "ActiveState" + FieldUnitSubState PostconditionField = "SubState" + FieldUnitActiveEnterTimestamp PostconditionField = "ActiveEnterTimestamp" // Docker container fields. FieldDockerStatus PostconditionField = "status" FieldDockerLastStarted PostconditionField = "last_started" // Kubernetes deployment fields. - FieldDeploymentReadyReplicas PostconditionField = "readyReplicas" + FieldDeploymentReadyReplicas PostconditionField = "readyReplicas" FieldDeploymentDesiredReplicas PostconditionField = "desiredReplicas" ) @@ -69,11 +69,11 @@ type PostconditionCheck struct { // postcondition to be observed; capabilities with no natural settle // (a single-shot status read) use the default. type CapabilityPostcondition struct { - Capability string `json:"capability"` - VerifyRead string `json:"verifyRead"` - Window time.Duration `json:"window"` - Description string `json:"description"` - Checks []PostconditionCheck `json:"checks"` + Capability string `json:"capability"` + VerifyRead string `json:"verifyRead"` + Window time.Duration `json:"window"` + Description string `json:"description"` + Checks []PostconditionCheck `json:"checks"` } // defaultVerifyWindow is the per-capability fallback window. The agentexec @@ -82,23 +82,6 @@ type CapabilityPostcondition struct { // this surface" hint. const defaultVerifyWindow = 2 * time.Minute -// CapabilityPostconditions returns the canonical capability -> postcondition -// map for the verifier substrate. The returned map is a copy so callers -// cannot mutate the shared substrate. -// -// Capabilities not present in this map have no automated postcondition and -// will surface as VerificationUnknown on the audit record. -func CapabilityPostconditions() map[string]CapabilityPostcondition { - out := make(map[string]CapabilityPostcondition, len(capabilityPostconditions)) - for k, v := range capabilityPostconditions { - copyChecks := make([]PostconditionCheck, len(v.Checks)) - copy(copyChecks, v.Checks) - v.Checks = copyChecks - out[k] = v - } - return out -} - // LookupCapabilityPostcondition returns the postcondition for the given // capability name, or false if no postcondition is registered. func LookupCapabilityPostcondition(capability string) (CapabilityPostcondition, bool) { diff --git a/internal/agentupdate/update.go b/internal/agentupdate/update.go index 169f9c8e1..d0a040d5c 100644 --- a/internal/agentupdate/update.go +++ b/internal/agentupdate/update.go @@ -333,14 +333,6 @@ func (u *Updater) CheckAndUpdate(ctx context.Context) { u.logger.Info().Msg("agent updated successfully, restarting") } -// setAuthHeaders adds authentication headers to the request if an API token is configured. -func (u *Updater) setAuthHeaders(req *http.Request) { - if u.cfg.APIToken != "" { - req.Header.Set(apiTokenHeader, u.cfg.APIToken) - req.Header.Set(authorizationHeader, bearerTokenPrefix+u.cfg.APIToken) - } -} - func (u *Updater) startCheck() bool { u.checkMu.Lock() defer u.checkMu.Unlock() diff --git a/internal/ai/chat/agentic.go b/internal/ai/chat/agentic.go index 16858bc7d..4571bfcce 100644 --- a/internal/ai/chat/agentic.go +++ b/internal/ai/chat/agentic.go @@ -85,12 +85,6 @@ func sessionFSMState(fsm *SessionFSM) string { return string(fsm.State) } -func (a *AgenticLoop) currentFSMState() string { - a.mu.Lock() - defer a.mu.Unlock() - return sessionFSMState(a.sessionFSM) -} - func fallbackProviderStreamErrorMessage(err error) string { const defaultMessage = "AI response stream interrupted before completion. Please retry." if err == nil { diff --git a/internal/ai/coverage_increase_test.go b/internal/ai/coverage_increase_test.go index f53e72378..38a963255 100644 --- a/internal/ai/coverage_increase_test.go +++ b/internal/ai/coverage_increase_test.go @@ -50,26 +50,6 @@ type mockBaselineStore struct { anomalies map[string]baselineResult } -func (m *mockBaselineStore) CheckAnomaly(resourceID, metric string, value float64) (baseline.AnomalySeverity, float64, *baseline.MetricBaseline) { - res, ok := m.anomalies[resourceID+":"+metric] - if !ok { - return baseline.AnomalyNone, 0, &baseline.MetricBaseline{} - } - return res.severity, res.zScore, res.bl -} - -func (m *mockBaselineStore) GetBaseline(resourceID, metric string) (*baseline.MetricBaseline, bool) { - res, ok := m.anomalies[resourceID+":"+metric] - if !ok { - return nil, false - } - return res.bl, true -} - -func (m *mockBaselineStore) Update(resourceID, metric string, value float64) {} -func (m *mockBaselineStore) Save() error { return nil } -func (m *mockBaselineStore) Load() error { return nil } - func TestGenerateRemediationSummary(t *testing.T) { tests := []struct { command string @@ -643,19 +623,3 @@ func TestService_BuildRecentResourceChangesContext_FallsBackToMemoryFormatter(t type mockIncidentStore struct { } - -func (m *mockIncidentStore) FormatForAlert(alertID string, limit int) string { - return "alert:" + alertID -} - -func (m *mockIncidentStore) FormatForResource(resourceID string, limit int) string { - return "res:" + resourceID -} - -func (m *mockIncidentStore) FormatForPatrol(limit int) string { - return "patrol" -} - -func (m *mockIncidentStore) Record(resourceID, resourceType, alertID, analysis, remediation string) error { - return nil -} diff --git a/internal/ai/discovery_adapter.go b/internal/ai/discovery_adapter.go index 99203ae9d..6ced12230 100644 --- a/internal/ai/discovery_adapter.go +++ b/internal/ai/discovery_adapter.go @@ -157,14 +157,3 @@ func cloneStringSlice(values []string) []string { copy(cloned, values) return cloned } - -func cloneStringMap(values map[string]string) map[string]string { - if len(values) == 0 { - return nil - } - cloned := make(map[string]string, len(values)) - for k, v := range values { - cloned[k] = v - } - return cloned -} diff --git a/internal/ai/infradiscovery/service.go b/internal/ai/infradiscovery/service.go index 1b9120993..999e7a582 100644 --- a/internal/ai/infradiscovery/service.go +++ b/internal/ai/infradiscovery/service.go @@ -194,13 +194,6 @@ func normalizeConfig(cfg Config) Config { return cfg } -func normalizeContext(ctx context.Context) context.Context { - if ctx == nil { - return context.Background() - } - return ctx -} - // NewService creates a new infrastructure discovery service. func NewService(knowledgeStore *knowledge.Store, cfg Config) *Service { cfg = normalizeConfig(cfg) @@ -245,21 +238,6 @@ func (s *Service) SetReadState(rs unifiedresources.ReadState) { } } -// goRecover launches fn in a goroutine with panic recovery logging. -func goRecover(label string, fn func()) { - go func() { - defer func() { - if r := recover(); r != nil { - log.Error(). - Interface("panic", r). - Stack(). - Msgf("Recovered from panic in %s", label) - } - }() - fn() - }() -} - // Start begins the background discovery service. func (s *Service) Start(ctx context.Context) { if ctx == nil { @@ -914,22 +892,6 @@ func (s *Service) saveDiscoveries(apps []DiscoveredApp) { } } -func (s *Service) tryStartDiscovery() bool { - s.discoveryMu.Lock() - defer s.discoveryMu.Unlock() - if s.discoveryRun { - return false - } - s.discoveryRun = true - return true -} - -func (s *Service) finishDiscovery() { - s.discoveryMu.Lock() - s.discoveryRun = false - s.discoveryMu.Unlock() -} - // GetDiscoveries returns the cached list of discovered applications. func (s *Service) GetDiscoveries() []DiscoveredApp { s.mu.RLock() diff --git a/internal/ai/intelligence.go b/internal/ai/intelligence.go index f91353308..988814e59 100644 --- a/internal/ai/intelligence.go +++ b/internal/ai/intelligence.go @@ -1315,15 +1315,6 @@ func (i *Intelligence) getResourcesAtRisk(limit int) []ResourceRiskSummary { return summaries } -func (i *Intelligence) detectCurrentAnomalies(resourceID string) []AnomalyReport { - if i.anomalyDetector != nil { - return i.anomalyDetector(resourceID) - } - // This would be called with current metrics from state - // For now, return empty - will be integrated with patrol - return nil -} - func (i *Intelligence) getRecentChangesForResource(resourceID string, limit int) []unifiedresources.ResourceChange { resourceID = strings.TrimSpace(resourceID) if resourceID == "" || limit <= 0 { diff --git a/internal/ai/memory/changes.go b/internal/ai/memory/changes.go index 638f43d81..097a1d79e 100644 --- a/internal/ai/memory/changes.go +++ b/internal/ai/memory/changes.go @@ -174,41 +174,6 @@ func (d *ChangeDetector) DetectChanges(currentSnapshots []ResourceSnapshot) []Ch return newChanges } -func (d *ChangeDetector) requestAsyncSave() { - if d.dataDir == "" { - return - } - - d.saveStateMu.Lock() - d.saveRequested = true - if d.saveRunning { - d.saveStateMu.Unlock() - return - } - d.saveRunning = true - d.saveStateMu.Unlock() - - go d.runSaveLoop() -} - -func (d *ChangeDetector) runSaveLoop() { - for { - d.saveStateMu.Lock() - shouldSave := d.saveRequested - d.saveRequested = false - if !shouldSave { - d.saveRunning = false - d.saveStateMu.Unlock() - return - } - d.saveStateMu.Unlock() - - if err := d.saveToDisk(); err != nil { - log.Warn().Err(err).Msg("Failed to save change history") - } - } -} - // detectResourceChanges checks for changes between two snapshots of the same resource func (d *ChangeDetector) detectResourceChanges(prev, current ResourceSnapshot, now time.Time) []Change { var changes []Change diff --git a/internal/ai/memory/context.go b/internal/ai/memory/context.go index 064b7a4ef..1b5547d88 100644 --- a/internal/ai/memory/context.go +++ b/internal/ai/memory/context.go @@ -85,16 +85,6 @@ type ContextStoreConfig struct { RelevanceDecayDays int // Days after which relevance starts decaying } -// DefaultContextStoreConfig returns sensible defaults -func DefaultContextStoreConfig() ContextStoreConfig { - return ContextStoreConfig{ - MaxMemoriesPerType: 1000, - MaxResourceNotes: 20, - RetentionDays: 90, - RelevanceDecayDays: 7, - } -} - // ContextStore stores and manages persistent AI context type ContextStore struct { mu sync.RWMutex @@ -370,31 +360,6 @@ func (s *ContextStore) Recall(resourceID string) []Memory { return result } -// RecallByType retrieves memories of a specific type -func (s *ContextStore) RecallByType(memType MemoryType, limit int) []Memory { - s.mu.Lock() - defer s.mu.Unlock() - - var result []Memory - if memories, ok := s.memories[memType]; ok { - for _, mem := range memories { - s.markUsedLocked(mem) - result = append(result, *mem) - } - } - - // Sort by relevance - sort.Slice(result, func(i, j int) bool { - return result[i].Relevance > result[j].Relevance - }) - - if limit > 0 && len(result) > limit { - result = result[:limit] - } - - return result -} - // GetResourceMemory returns the memory for a specific resource func (s *ContextStore) GetResourceMemory(resourceID string) *ResourceMemory { s.mu.RLock() diff --git a/internal/ai/patrol_ai.go b/internal/ai/patrol_ai.go index 9b84c71e8..52ec99937 100644 --- a/internal/ai/patrol_ai.go +++ b/internal/ai/patrol_ai.go @@ -1253,13 +1253,6 @@ func maxInt(a, b int) int { return b } -func minInt(a, b int) int { - if a < b { - return a - } - return b -} - func (p *PatrolService) assembleSeedWithinBudget(sections []seedSection, budgetTokens int) string { if len(sections) == 0 { return "" diff --git a/internal/ai/patrol_findings.go b/internal/ai/patrol_findings.go index f867392c5..2ce1a9351 100644 --- a/internal/ai/patrol_findings.go +++ b/internal/ai/patrol_findings.go @@ -1872,10 +1872,6 @@ func patrolRegisterResourceMetrics(dest map[string]map[string]float64, metrics m } } -func patrolGuestMatches(guestID, id, name string, vmid int) bool { - return id == guestID || name == guestID || fmt.Sprintf("%d", vmid) == guestID -} - func patrolFirstIP(ips []string) string { if len(ips) == 0 { return "" diff --git a/internal/ai/patrol_state.go b/internal/ai/patrol_state.go index be94a426a..4b232f9a1 100644 --- a/internal/ai/patrol_state.go +++ b/internal/ai/patrol_state.go @@ -419,17 +419,6 @@ func patrolRuntimeSortedResourceIDs(s patrolRuntimeState) []string { return ids } -func patrolRuntimeStorageResourceCount(s patrolRuntimeState) int { - count := 0 - patrolVisitRuntimeResources(s, func(record patrolRuntimeResourceRecord) bool { - if record.kind == patrolRuntimeResourceStorage || record.kind == patrolRuntimeResourcePhysicalDisk { - count++ - } - return true - }) - return count -} - type patrolRuntimeResourceCounts struct { nodes int guests int diff --git a/internal/ai/providers/openai.go b/internal/ai/providers/openai.go index 468c173da..3d91a489d 100644 --- a/internal/ai/providers/openai.go +++ b/internal/ai/providers/openai.go @@ -180,14 +180,6 @@ func (c *OpenAIClient) shouldSendReasoningContent() bool { return c.isDeepSeek() } -func normalizeOpenAICompatibleModelName(model string) string { - model = strings.ToLower(strings.TrimSpace(model)) - for _, prefix := range []string{"openai:", "openrouter:", "deepseek:"} { - model = strings.TrimPrefix(model, prefix) - } - return model -} - func (c *OpenAIClient) applyProviderHeaders(req *http.Request) { if !c.isOpenRouter() { return diff --git a/internal/ai/providers/provider.go b/internal/ai/providers/provider.go index 3b21b3a5e..8c67ea216 100644 --- a/internal/ai/providers/provider.go +++ b/internal/ai/providers/provider.go @@ -127,10 +127,6 @@ type ChatResponse struct { OutputTokens int `json:"output_tokens,omitempty"` } -func EmptyChatResponse() ChatResponse { - return ChatResponse{}.NormalizeCollections() -} - func (r ChatResponse) NormalizeCollections() ChatResponse { if r.ToolCalls == nil { r.ToolCalls = []ToolCall{} diff --git a/internal/ai/tools/names.go b/internal/ai/tools/names.go index 075cf3aaa..cddb6e182 100644 --- a/internal/ai/tools/names.go +++ b/internal/ai/tools/names.go @@ -2,18 +2,6 @@ package tools import "sync" -// KnownToolNames returns the canonical list of registered Pulse tool names, -// keyed off the registry built by registerTools(). The list is built lazily -// on first call via a throwaway executor so adding a new tool to -// registerTools() automatically extends the allowlist — no separate -// hand-maintained list to drift out of sync. -func KnownToolNames() []string { - initKnownToolNames() - out := make([]string, len(knownToolNamesList)) - copy(out, knownToolNamesList) - return out -} - // IsKnownToolName reports whether name is one of the canonical Pulse tool // names. Used by chat-content sanitisers to gate stripping on a closed // allowlist (e.g. JSON tool-call shapes leaked by weak local models that diff --git a/internal/ai/tools/protocol.go b/internal/ai/tools/protocol.go index 127f5db65..f6a17f6e1 100644 --- a/internal/ai/tools/protocol.go +++ b/internal/ai/tools/protocol.go @@ -238,23 +238,6 @@ const ( ErrCodeNoAgent = "NO_AGENT" ) -// NewToolSuccess creates a successful tool response -func NewToolSuccess(data interface{}) ToolResponse { - return ToolResponse{ - OK: true, - Data: data, - } -} - -// NewToolSuccessWithMeta creates a successful tool response with metadata -func NewToolSuccessWithMeta(data interface{}, meta map[string]interface{}) ToolResponse { - return ToolResponse{ - OK: true, - Data: data, - Meta: meta, - } -} - // NewToolBlockedError creates a policy/validation blocked error func NewToolBlockedError(code, message string, details map[string]interface{}) ToolResponse { return ToolResponse{ @@ -268,20 +251,6 @@ func NewToolBlockedError(code, message string, details map[string]interface{}) T } } -// NewToolFailedError creates a runtime failure error -func NewToolFailedError(code, message string, retryable bool, details map[string]interface{}) ToolResponse { - return ToolResponse{ - OK: false, - Error: &ToolError{ - Code: code, - Message: message, - Failed: true, - Retryable: retryable, - Details: details, - }, - } -} - // Helper functions // NewTextContent creates a text content object diff --git a/internal/ai/tools/tools_control.go b/internal/ai/tools/tools_control.go index 54f2a4eb3..093a1cb8f 100644 --- a/internal/ai/tools/tools_control.go +++ b/internal/ai/tools/tools_control.go @@ -1581,24 +1581,6 @@ func extractServiceUnitName(command string) string { return "" } -// extractContainerName parses the container name out of a docker/podman -// command of the form "docker restart " or "podman stop ". -func extractContainerName(command string) string { - fields := strings.Fields(strings.TrimSpace(command)) - if len(fields) < 3 { - return "" - } - first := strings.ToLower(fields[0]) - if first != "docker" && first != "podman" { - return "" - } - verb := strings.ToLower(fields[1]) - if verb != "restart" && verb != "stop" && verb != "start" { - return "" - } - return fields[2] -} - // shellQuoteSingle wraps the value in single quotes and escapes any // embedded single quotes for shell-safe inclusion in the verification // command. The verification path runs through the same agent dispatch as diff --git a/internal/ai/tools/tools_storage_test.go b/internal/ai/tools/tools_storage_test.go index 8cbadb3ac..67e22ed43 100644 --- a/internal/ai/tools/tools_storage_test.go +++ b/internal/ai/tools/tools_storage_test.go @@ -28,10 +28,6 @@ type stubDiskHealthProvider struct { hosts []*unifiedresources.HostView } -func (s *stubDiskHealthProvider) GetHosts() []*unifiedresources.HostView { - return s.hosts -} - type stubUpdatesProvider struct { pending []ContainerUpdateInfo enabled bool diff --git a/internal/ai/tools/tools_summarize_test.go b/internal/ai/tools/tools_summarize_test.go index e5b568cc3..fc60cabc4 100644 --- a/internal/ai/tools/tools_summarize_test.go +++ b/internal/ai/tools/tools_summarize_test.go @@ -39,18 +39,6 @@ func newSummarizeTestEnvironment(t *testing.T) (*PulseToolExecutor, func()) { return exec, cleanup } -func writeMetricSamples(t *testing.T, dir string, store *metrics.Store, resourceID string, value float64, count int) { - t.Helper() - now := time.Now() - for i := 0; i < count; i++ { - ts := now.Add(time.Duration(-30+i*2) * time.Minute) - store.Write("node", resourceID, "cpu", value, ts) - store.Write("node", resourceID, "memory", value-10, ts) - } - store.Flush() - _ = dir -} - func TestSummarizeTool_RegisteredAndDiscoverable(t *testing.T) { exec, cleanup := newSummarizeTestEnvironment(t) defer cleanup() diff --git a/internal/ai/unified/integration.go b/internal/ai/unified/integration.go index 85049a42f..ef2df17d6 100644 --- a/internal/ai/unified/integration.go +++ b/internal/ai/unified/integration.go @@ -91,21 +91,6 @@ func (i *Integration) SetPatrolTrigger(fn PatrolTriggerFunc) { i.bridge.SetPatrolTrigger(fn) } -// Start starts the unified system -func (i *Integration) Start() { - i.bridge.Start() - log.Info().Msg("unified alert/finding system started") -} - -// Stop stops the unified system -func (i *Integration) Stop() { - i.bridge.Stop() - if err := i.store.ForceSave(); err != nil { - log.Error().Err(err).Msg("failed to save unified findings on shutdown") - } - log.Info().Msg("unified alert/finding system stopped") -} - // GetStore returns the unified store func (i *Integration) GetStore() *UnifiedStore { return i.store diff --git a/internal/alerts/callbacks.go b/internal/alerts/callbacks.go index 1161a7f5a..479d826b2 100644 --- a/internal/alerts/callbacks.go +++ b/internal/alerts/callbacks.go @@ -198,13 +198,6 @@ func (b *callbackBus) alertForAICallbacks() []func(alert *Alert) { return callbacks } -func (b *callbackBus) resolvedCallback() func(alertID string) { - b.mu.RLock() - cb := b.onResolved - b.mu.RUnlock() - return cb -} - func (b *callbackBus) resolvedCallbacks() []func(alertID string) { b.mu.RLock() defer b.mu.RUnlock() @@ -330,10 +323,6 @@ func (m *Manager) getAlertForAICallbacks() []func(alert *Alert) { return m.callbacks.alertForAICallbacks() } -func (m *Manager) getResolvedCallback() func(alertID string) { - return m.callbacks.resolvedCallback() -} - func (m *Manager) getResolvedCallbacks() []func(alertID string) { return m.callbacks.resolvedCallbacks() } diff --git a/internal/alerts/config_facade.go b/internal/alerts/config_facade.go index 46230a9e4..44b5cf82a 100644 --- a/internal/alerts/config_facade.go +++ b/internal/alerts/config_facade.go @@ -66,28 +66,7 @@ func ensureValidHysteresis(threshold *HysteresisThreshold, metricName string) { alertconfig.EnsureValidHysteresis(threshold, metricName) } -func normalizeStorageDefaults(config *AlertConfig) { alertconfig.NormalizeStorageDefaults(config) } - -func normalizeDockerThreshold(th HysteresisThreshold, defaultTrigger float64, metricName string) HysteresisThreshold { - return alertconfig.NormalizeDockerThreshold(th, defaultTrigger, metricName) -} - -func normalizeDockerDefaults(config *AlertConfig) { alertconfig.NormalizeDockerDefaults(config) } -func normalizePMGDefaults(config *AlertConfig) { alertconfig.NormalizePMGDefaults(config) } func normalizeSnapshotDefaults(config *AlertConfig) { alertconfig.NormalizeSnapshotDefaults(config) } func normalizeBackupDefaults(config *AlertConfig) { alertconfig.NormalizeBackupDefaults(config) } -func normalizeNodeDefaults(config *AlertConfig) { alertconfig.NormalizeNodeDefaults(config) } -func normalizeAgentDefaults(config *AlertConfig) { alertconfig.NormalizeAgentDefaults(config) } -func normalizeKubernetesDefaults(config *AlertConfig) { - alertconfig.NormalizeKubernetesDefaults(config) -} -func normalizeTrueNASDefaults(config *AlertConfig) { alertconfig.NormalizeTrueNASDefaults(config) } -func normalizeVMwareDefaults(config *AlertConfig) { alertconfig.NormalizeVMwareDefaults(config) } -func normalizeGeneralSettings(config *AlertConfig) { alertconfig.NormalizeGeneralSettings(config) } -func normalizeTimeThresholds(config *AlertConfig) { alertconfig.NormalizeTimeThresholds(config) } - -func validateHysteresisThresholds(config *AlertConfig) { - alertconfig.ValidateHysteresisThresholds(config) -} func validateQuietHoursTimezone(config *AlertConfig) { alertconfig.ValidateQuietHoursTimezone(config) } diff --git a/internal/alerts/specs/types.go b/internal/alerts/specs/types.go index 89c6ba2d9..c6bb76713 100644 --- a/internal/alerts/specs/types.go +++ b/internal/alerts/specs/types.go @@ -1066,16 +1066,6 @@ type OverridePolicy struct { ExpiresAt *time.Time `json:"expiresAt,omitempty"` } -func (p OverridePolicy) Validate() error { - if err := p.Target.Validate(); err != nil { - return err - } - if p.ExpiresAt != nil && p.ExpiresAt.IsZero() { - return fmt.Errorf("expires at must be set when provided") - } - return nil -} - func isKnownResourceType(rt unifiedresources.ResourceType) bool { if rt == "" { return false diff --git a/internal/alerts/unified_eval.go b/internal/alerts/unified_eval.go index 10782921d..9ab104ed7 100644 --- a/internal/alerts/unified_eval.go +++ b/internal/alerts/unified_eval.go @@ -109,16 +109,6 @@ func unifiedAlertType(typeKey string) string { } } -// isUnifiedGuestType returns true for resource types that support I/O metrics. -func isUnifiedGuestType(typeKey string) bool { - switch typeKey { - case "vm", "system-container", "app-container": - return true - default: - return false - } -} - func supportsUnifiedIOMetrics(typeKey string) bool { switch typeKey { case "vm", "system-container", "app-container", "k8s-cluster", "k8s-deployment", "pod", "truenas-system", "vmware-host", "vmware-vm": @@ -597,32 +587,6 @@ func unifiedResourceAlertInstance(resource unifiedresources.Resource, typeKey st return "" } -func mergeMetricOptions(base *metricOptions, extra map[string]interface{}) *metricOptions { - if len(extra) == 0 { - return base - } - - merged := &metricOptions{} - if base != nil { - *merged = *base - } - if len(extra) > 0 { - if merged.Metadata == nil { - merged.Metadata = make(map[string]interface{}, len(extra)) - } else { - copied := make(map[string]interface{}, len(merged.Metadata)+len(extra)) - for k, v := range merged.Metadata { - copied[k] = v - } - merged.Metadata = copied - } - for k, v := range extra { - merged.Metadata[k] = v - } - } - return merged -} - func (i *UnifiedResourceInput) CPUValue() float64 { if i == nil || i.CPU == nil { return 0 diff --git a/internal/alerts/unified_incidents.go b/internal/alerts/unified_incidents.go index 5fa9c6bfb..a6da8d236 100644 --- a/internal/alerts/unified_incidents.go +++ b/internal/alerts/unified_incidents.go @@ -6,7 +6,6 @@ import ( "time" alertspecs "github.com/rcourtman/pulse-go-rewrite/internal/alerts/specs" - "github.com/rcourtman/pulse-go-rewrite/internal/storagehealth" "github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources" ) @@ -261,17 +260,6 @@ func resourceSupportsUnifiedIncidentAlerts(resource unifiedresources.Resource) b } } -func alertLevelFromIncidentSeverity(level storagehealth.RiskLevel) (AlertLevel, bool) { - switch level { - case storagehealth.RiskCritical: - return AlertLevelCritical, true - case storagehealth.RiskWarning: - return AlertLevelWarning, true - default: - return "", false - } -} - func alertLevelFromCanonicalSeverity(level alertspecs.AlertSeverity) (AlertLevel, bool) { switch level { case alertspecs.AlertSeverityCritical: @@ -526,39 +514,6 @@ func unifiedIncidentConsumerSummary(storage *unifiedresources.StorageMeta) strin return unifiedresources.StorageConsumerImpactSummary(storage) } -func unifiedIncidentDependentConsumerSummary(storage *unifiedresources.StorageMeta) string { - if storage == nil || storage.ConsumerCount <= 0 { - return "" - } - - names := make([]string, 0, len(storage.TopConsumers)) - for _, consumer := range storage.TopConsumers { - name := strings.TrimSpace(consumer.Name) - if name == "" { - continue - } - names = append(names, name) - if len(names) == 3 { - break - } - } - - resourceLabel := "dependent resource" - if storage.ConsumerCount != 1 { - resourceLabel = "dependent resources" - } - - if len(names) == 0 { - return "Affects " + intLabel(storage.ConsumerCount) + " " + resourceLabel - } - - if remaining := storage.ConsumerCount - len(names); remaining > 0 { - return "Affects " + intLabel(storage.ConsumerCount) + " " + resourceLabel + ": " + strings.Join(names, ", ") + ", and " + intLabel(remaining) + " more" - } - - return "Affects " + intLabel(storage.ConsumerCount) + " " + resourceLabel + ": " + strings.Join(names, ", ") -} - func unifiedIncidentBackupConsumerSummary(storage *unifiedresources.StorageMeta) string { if storage == nil || storage.ConsumerCount <= 0 { return "" diff --git a/internal/api/agent_events.go b/internal/api/agent_events.go index 1066004ab..a7705a7fe 100644 --- a/internal/api/agent_events.go +++ b/internal/api/agent_events.go @@ -1,7 +1,6 @@ package api import ( - "context" "encoding/json" "fmt" "net/http" @@ -384,10 +383,3 @@ func (b *AgentEventBroadcaster) PublishActionCompletedRecord(record unifiedresou // call sites don't need this — they hold a direct reference — but // keeping it here makes the dependency explicit. type agentEventBroadcasterContextKey struct{} - -// ContextWithAgentEventBroadcaster attaches a broadcaster to a -// context. Used by integration tests that need to inject a fake -// broadcaster. -func ContextWithAgentEventBroadcaster(ctx context.Context, b *AgentEventBroadcaster) context.Context { - return context.WithValue(ctx, agentEventBroadcasterContextKey{}, b) -} diff --git a/internal/api/ai_hosted_runtime.go b/internal/api/ai_hosted_runtime.go index 70e8b1c65..506fc883c 100644 --- a/internal/api/ai_hosted_runtime.go +++ b/internal/api/ai_hosted_runtime.go @@ -19,14 +19,6 @@ func loadHostedAwareAIConfig(hostedMode bool, billingBaseDir, orgID string, pers return cfg, nil } -func shouldAutoBootstrapHostedAIConfig(hostedMode bool, persistence *config.ConfigPersistence) bool { - return false -} - -func hostedAIAutoBootstrapEligible(state *billingState) bool { - return false -} - func hostedModeEnabledFromEnv() bool { return os.Getenv("PULSE_HOSTED_MODE") == "true" } diff --git a/internal/api/alerts.go b/internal/api/alerts.go index 1d1cf1c0c..8bad45a1d 100644 --- a/internal/api/alerts.go +++ b/internal/api/alerts.go @@ -584,10 +584,6 @@ type incidentEventView struct { Details map[string]interface{} `json:"details"` } -func emptyIncidentEventView() incidentEventView { - return incidentEventView{}.NormalizeCollections() -} - func (v incidentEventView) NormalizeCollections() incidentEventView { if v.Details == nil { v.Details = map[string]interface{}{} diff --git a/internal/api/chat_service_adapter_test.go b/internal/api/chat_service_adapter_test.go index 7737884ce..1b5057151 100644 --- a/internal/api/chat_service_adapter_test.go +++ b/internal/api/chat_service_adapter_test.go @@ -6,7 +6,6 @@ import ( "github.com/rcourtman/pulse-go-rewrite/internal/ai/chat" "github.com/rcourtman/pulse-go-rewrite/internal/config" - "github.com/rcourtman/pulse-go-rewrite/internal/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -14,8 +13,6 @@ import ( // Mock implementation of chat.StateProvider type mockChatStateProvider struct{} -func (m *mockChatStateProvider) ReadSnapshot() models.StateSnapshot { return models.StateSnapshot{} } - func TestChatServiceAdapter_CreateSession(t *testing.T) { // Setup real chat service with minimal config cfg := chat.Config{ diff --git a/internal/api/connections_aggregator_test.go b/internal/api/connections_aggregator_test.go index d236b8048..818c2acd3 100644 --- a/internal/api/connections_aggregator_test.go +++ b/internal/api/connections_aggregator_test.go @@ -30,15 +30,6 @@ func healthEntry(lastSuccess *time.Time, errMessage, errCategory string, breaker } } -func desiredAgentConfigFingerprint(t *testing.T, commandsEnabled *bool, settings map[string]interface{}) ConnectionFleetConfigFingerprint { - t.Helper() - desired := desiredAgentConfig(t, commandsEnabled, settings) - if desired.Fingerprint == nil { - t.Fatal("expected desired config fingerprint") - } - return *desired.Fingerprint -} - func desiredAgentConfig(t *testing.T, commandsEnabled *bool, settings map[string]interface{}) connectionAgentDesiredConfig { t.Helper() metadata, err := remoteconfig.BuildDesiredConfigMetadata(commandsEnabled, settings) diff --git a/internal/api/connections_alerts.go b/internal/api/connections_alerts.go index 7cb83fd80..521e862bd 100644 --- a/internal/api/connections_alerts.go +++ b/internal/api/connections_alerts.go @@ -17,15 +17,6 @@ type aggregatorRuntimeSources struct { truenasPoller *monitoring.TrueNASPoller } -// buildAggregatorInputs gathers the same inputs the HTTP connections handler -// uses so the alerts pipeline can derive identical Connection rows without -// going through the HTTP layer. Returning an empty aggregatorInputs when a -// dependency is unavailable keeps the alerts loop a no-op rather than a hard -// failure. -func buildAggregatorInputs(ctx context.Context, cfg *config.Config, persistence *config.ConfigPersistence, monitor *monitoring.Monitor) aggregatorInputs { - return buildAggregatorInputsWithRuntimeSources(ctx, cfg, persistence, monitor, aggregatorRuntimeSources{}) -} - func buildAggregatorInputsWithRuntimeSources( ctx context.Context, cfg *config.Config, @@ -137,14 +128,6 @@ func snapshotConnectionsForAlerts(connections []Connection) []alerts.ConnectionS return out } -// BuildAlertConnectionSnapshots returns the platform-connection snapshots the -// alerts package consumes for the connection-degraded check. This is the -// monitor-loop counterpart to the HTTP connections handler — it runs the -// same derivation but skips the JSON envelope. -func BuildAlertConnectionSnapshots(ctx context.Context, cfg *config.Config, persistence *config.ConfigPersistence, monitor *monitoring.Monitor) []alerts.ConnectionSnapshot { - return buildAlertConnectionSnapshotsWithRuntimeSources(ctx, cfg, persistence, monitor, aggregatorRuntimeSources{}) -} - func buildAlertConnectionSnapshotsWithRuntimeSources( ctx context.Context, cfg *config.Config, diff --git a/internal/api/connections_probe_test.go b/internal/api/connections_probe_test.go index 179bc23a6..8dd3a1c59 100644 --- a/internal/api/connections_probe_test.go +++ b/internal/api/connections_probe_test.go @@ -113,14 +113,6 @@ func pbsHandler(body string) http.HandlerFunc { } } -func pmgHandler(body string) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Server", "pmg-api-daemon/8.1") - w.Header().Set("Content-Type", "text/html; charset=utf-8") - fmt.Fprint(w, body) - } -} - func vmwareHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/xml") diff --git a/internal/api/demo_mode_commercial.go b/internal/api/demo_mode_commercial.go index 3df06bc90..139162a44 100644 --- a/internal/api/demo_mode_commercial.go +++ b/internal/api/demo_mode_commercial.go @@ -111,14 +111,6 @@ func publicDemoCommercialPolicyForRequest( return "", false } -func publicDemoCommercialRouteInventory() []string { - routes := make([]string, 0, len(publicDemoCommercialPolicies)) - for _, policy := range publicDemoCommercialPolicies { - routes = append(routes, policy.route) - } - return routes -} - func sanitizeRuntimeCapabilitiesPayloadForPublicDemo( payload RuntimeCapabilitiesPayload, ) RuntimeCapabilitiesPayload { diff --git a/internal/api/entitlement_handlers_test.go b/internal/api/entitlement_handlers_test.go index 90649b078..96e9b2247 100644 --- a/internal/api/entitlement_handlers_test.go +++ b/internal/api/entitlement_handlers_test.go @@ -986,18 +986,3 @@ func TestEntitlementHandler_CommercialMigrationDoesNotExposeTrialStartReason(t * t.Fatalf("trial_eligibility_reason=%q, want empty", payload.TrialEligibilityReason) } } - -// countProMinusFreeFeatures returns the number of Pro features not included in Free. -func countProMinusFreeFeatures() int { - freeSet := make(map[string]struct{}, len(license.TierFeatures[license.TierFree])) - for _, f := range license.TierFeatures[license.TierFree] { - freeSet[f] = struct{}{} - } - count := 0 - for _, f := range license.TierFeatures[license.TierPro] { - if _, ok := freeSet[f]; !ok { - count++ - } - } - return count -} diff --git a/internal/api/licensing_bridge.go b/internal/api/licensing_bridge.go index fb301030f..ff41b342b 100644 --- a/internal/api/licensing_bridge.go +++ b/internal/api/licensing_bridge.go @@ -279,11 +279,6 @@ func writeLicenseRequiredFromLicensing(w http.ResponseWriter, feature, message s // licenseTierFreeValue is the canonical free-tier constant for use outside the bridge. const licenseTierFreeValue = pkglicensing.TierFree -// overflowBonusFromLicensing returns the number of bonus host slots granted by the onboarding overflow. -func overflowBonusFromLicensing(tier licenseTier, overflowGrantedAt *int64, now time.Time) int { - return pkglicensing.OverflowBonus(tier, overflowGrantedAt, now) -} - // overflowDaysRemainingFromLicensing returns the number of days remaining in the overflow window. func overflowDaysRemainingFromLicensing(tier licenseTier, overflowGrantedAt *int64, now time.Time) int { return pkglicensing.OverflowDaysRemaining(tier, overflowGrantedAt, now) diff --git a/internal/api/licensing_handlers.go b/internal/api/licensing_handlers.go index db2c94658..fc897a068 100644 --- a/internal/api/licensing_handlers.go +++ b/internal/api/licensing_handlers.go @@ -670,17 +670,6 @@ func (h *LicenseHandlers) syncReleaseDemoFixtureRuntime(orgID string, service *l } } -func (h *LicenseHandlers) canonicalMonitoredSystemGrandfatherFloor(ctx context.Context) (int, bool) { - usage := h.entitlementUsageSnapshot(ctx) - if !usage.MonitoredSystemsAvailable { - return 0, false - } - if usage.MonitoredSystems < 0 { - return 0, false - } - return int(usage.MonitoredSystems), true -} - func (h *LicenseHandlers) ensureEvaluatorForOrg(orgID string, service *licenseService) error { if h == nil || service == nil || h.mtPersistence == nil { return nil diff --git a/internal/api/middleware_license.go b/internal/api/middleware_license.go index 2bbee59bf..8ae68d66f 100644 --- a/internal/api/middleware_license.go +++ b/internal/api/middleware_license.go @@ -172,33 +172,6 @@ func RequireMultiTenant(next http.HandlerFunc) http.HandlerFunc { } } -// RequireMultiTenantHandler returns middleware for http.Handler. -func RequireMultiTenantHandler(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - orgID := GetOrgID(r.Context()) - - // Default org is always allowed (backward compatibility) - if orgID == "" || orgID == "default" { - next.ServeHTTP(w, r) - return - } - - // Feature flag check - multi-tenant must be explicitly enabled - if !multiTenantEnabled { - writeMultiTenantDisabledError(w) - return - } - - // Non-default orgs require multi-tenant license - if !hasMultiTenantFeatureForContext(r.Context()) { - writeMultiTenantRequiredError(w) - return - } - - next.ServeHTTP(w, r) - }) -} - // writeMultiTenantRequiredError writes a 402 Payment Required response // indicating that multi-tenant requires an Enterprise license. func writeMultiTenantRequiredError(w http.ResponseWriter) { diff --git a/internal/api/middleware_tenant.go b/internal/api/middleware_tenant.go index 529eb6da8..9c6118a84 100644 --- a/internal/api/middleware_tenant.go +++ b/internal/api/middleware_tenant.go @@ -87,11 +87,6 @@ func NewTenantMiddlewareWithConfig(cfg TenantMiddlewareConfig) *TenantMiddleware } } -// SetAuthChecker sets the authorization checker for the middleware. -func (m *TenantMiddleware) SetAuthChecker(checker AuthorizationChecker) { - m.authChecker = checker -} - func (m *TenantMiddleware) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 1. Extract Org ID diff --git a/internal/api/middleware_tenant_test.go b/internal/api/middleware_tenant_test.go index 9ee3ce6ce..93a67c46f 100644 --- a/internal/api/middleware_tenant_test.go +++ b/internal/api/middleware_tenant_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "encoding/json" "net/http" "net/http/httptest" @@ -10,7 +9,6 @@ import ( "github.com/rcourtman/pulse-go-rewrite/internal/config" "github.com/rcourtman/pulse-go-rewrite/internal/models" - pkglicensing "github.com/rcourtman/pulse-go-rewrite/pkg/licensing" "github.com/stretchr/testify/assert" ) @@ -22,14 +20,6 @@ type mockLicenseProvider struct { hasFeatures bool } -func (p *mockLicenseProvider) Service(ctx context.Context) *pkglicensing.Service { - // In a real scenario, we'd return a mocked service control structure. - // Since license.Service is concrete, we rely on its default state (no features) - // or we'd need a way to inject state. - // For now, testing the negative case (no license) is most important for security. - return pkglicensing.NewService() -} - func TestTenantMiddleware_Enforcement_Permanent(t *testing.T) { // Cleanup env after test defer func() { diff --git a/internal/api/monitored_system_ledger.go b/internal/api/monitored_system_ledger.go index 86fb78fa8..4a8215d8c 100644 --- a/internal/api/monitored_system_ledger.go +++ b/internal/api/monitored_system_ledger.go @@ -322,14 +322,6 @@ func monitoredSystemLedgerEntry(system unifiedresources.MonitoredSystemRecord) M } } -func monitoredSystemLedgerEntryPointer(system *unifiedresources.MonitoredSystemRecord) *MonitoredSystemLedgerEntry { - if system == nil { - return nil - } - entry := monitoredSystemLedgerEntry(*system) - return &entry -} - func monitoredSystemLedgerEntries( systems []unifiedresources.MonitoredSystemRecord, ) []MonitoredSystemLedgerEntry { diff --git a/internal/api/monitored_system_usage.go b/internal/api/monitored_system_usage.go index 5763b5d87..403b5635e 100644 --- a/internal/api/monitored_system_usage.go +++ b/internal/api/monitored_system_usage.go @@ -48,10 +48,6 @@ func writeMonitoredSystemUsageUnavailable(w http.ResponseWriter, reason string) ) } -func legacyConnectionCounts(monitor *monitoring.Monitor) legacyConnectionCountsModel { - return legacyConnectionCountsModel{} -} - func legacyConnectionCountsFromReadState(rs unifiedresources.ReadState) legacyConnectionCountsModel { return legacyConnectionCountsModel{} } diff --git a/internal/api/monitored_system_usage_test_helpers_test.go b/internal/api/monitored_system_usage_test_helpers_test.go index 9f05f24d2..8b0507785 100644 --- a/internal/api/monitored_system_usage_test_helpers_test.go +++ b/internal/api/monitored_system_usage_test_helpers_test.go @@ -42,11 +42,6 @@ func (p *testSupplementalUsageProvider) SupplementalInventoryReadyAt(*monitoring return p.readyAt, p.settled } -func (p *testSupplementalUsageProvider) settleWithRecords(records []unifiedresources.IngestRecord) time.Time { - now := time.Now().UTC() - return p.settleAtWithRecords(now, records) -} - func (p *testSupplementalUsageProvider) settleAtWithRecords(at time.Time, records []unifiedresources.IngestRecord) time.Time { p.readyAt = at p.settled = true diff --git a/internal/api/oidc_mapping_test.go b/internal/api/oidc_mapping_test.go index 6661a3108..1f7ec930d 100644 --- a/internal/api/oidc_mapping_test.go +++ b/internal/api/oidc_mapping_test.go @@ -13,24 +13,6 @@ type mockAuthManager struct { updatedRoles []string } -func (m *mockAuthManager) GetRoles() []auth.Role { return nil } -func (m *mockAuthManager) GetRole(id string) (auth.Role, bool) { return auth.Role{}, false } -func (m *mockAuthManager) SaveRole(role auth.Role) error { return nil } -func (m *mockAuthManager) DeleteRole(id string) error { return nil } -func (m *mockAuthManager) GetUserAssignments() []auth.UserRoleAssignment { return nil } -func (m *mockAuthManager) GetUserAssignment(username string) (auth.UserRoleAssignment, bool) { - return auth.UserRoleAssignment{}, false -} -func (m *mockAuthManager) AssignRole(username string, roleID string) error { return nil } -func (m *mockAuthManager) RemoveRole(username string, roleID string) error { return nil } -func (m *mockAuthManager) GetUserPermissions(username string) []auth.Permission { return nil } - -func (m *mockAuthManager) UpdateUserRoles(username string, roleIDs []string) error { - m.updatedUser = username - m.updatedRoles = roleIDs - return nil -} - func TestOIDCRoleMappingLogic(t *testing.T) { tests := []struct { name string diff --git a/internal/api/router.go b/internal/api/router.go index aaa25e3ce..f62199869 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -9,7 +9,6 @@ import ( "encoding/json" "errors" "fmt" - "hash/fnv" "io" "math" "net" @@ -6530,28 +6529,6 @@ const ( mockWorkloadMaxSeriesPoints = 180 ) -func clampChartValue(value, min, max float64) float64 { - if math.IsNaN(value) || math.IsInf(value, 0) { - return min - } - if value < min { - return min - } - if value > max { - return max - } - return value -} - -func hashChartSeed(parts ...string) uint64 { - h := fnv.New64a() - for _, p := range parts { - _, _ = h.Write([]byte(p)) - _, _ = h.Write([]byte{0}) - } - return h.Sum64() -} - func targetMockSeriesPoints(duration time.Duration, maxPoints int) int { target := int(duration / (2 * time.Minute)) if target < mockWorkloadMinSeriesPoints { @@ -6625,19 +6602,6 @@ func generateStyledMockSeries( return points } -func updateOldestTimestampFromSeries(metrics VMChartData, oldestTimestamp *int64) { - if oldestTimestamp == nil { - return - } - for _, points := range metrics { - for _, point := range points { - if point.Timestamp < *oldestTimestamp { - *oldestTimestamp = point.Timestamp - } - } - } -} - func buildSyntheticMetricHistorySeries( now time.Time, duration time.Duration, @@ -7543,40 +7507,6 @@ func clampNonNegativeWorkloadValue(value float64) float64 { return value } -func kubernetesClusterKey(cluster models.KubernetesCluster) string { - if value := strings.TrimSpace(cluster.ID); value != "" { - return value - } - if value := strings.TrimSpace(cluster.Name); value != "" { - return value - } - if value := strings.TrimSpace(cluster.DisplayName); value != "" { - return value - } - return "k8s-cluster" -} - -func kubernetesPodIdentifier(pod models.KubernetesPod) string { - if value := strings.TrimSpace(pod.UID); value != "" { - return value - } - namespace := strings.TrimSpace(pod.Namespace) - name := strings.TrimSpace(pod.Name) - if namespace != "" || name != "" { - return fmt.Sprintf("%s/%s", namespace, name) - } - return "pod" -} - -func kubernetesPodMetricID(cluster models.KubernetesCluster, pod models.KubernetesPod) string { - clusterKey := kubernetesClusterKey(cluster) - podKey := kubernetesPodIdentifier(pod) - if clusterKey == "" || podKey == "" { - return "" - } - return fmt.Sprintf("k8s:%s:pod:%s", clusterKey, podKey) -} - func kubernetesPodMetricIDFromView(pod *unifiedresources.PodView) string { if pod == nil { return "" @@ -7599,71 +7529,6 @@ func kubernetesPodMetricIDFromView(pod *unifiedresources.PodView) string { return fmt.Sprintf("k8s:%s:pod:%s", clusterKey, podKey) } -func kubernetesPodDisplayName(pod models.KubernetesPod) string { - name := strings.TrimSpace(pod.Name) - namespace := strings.TrimSpace(pod.Namespace) - if namespace == "" { - if name == "" { - return kubernetesPodIdentifier(pod) - } - return name - } - if name == "" { - return namespace - } - return fmt.Sprintf("%s/%s", namespace, name) -} - -func kubernetesPodIsRunning(pod models.KubernetesPod) bool { - return strings.EqualFold(strings.TrimSpace(pod.Phase), "running") -} - -func kubernetesPodCurrentMetrics(cluster models.KubernetesCluster, pod models.KubernetesPod) map[string]float64 { - cpuPercent := clampWorkloadPercent(pod.UsageCPUPercent) - memoryPercent := clampWorkloadPercent(pod.UsageMemoryPercent) - - if memoryPercent <= 0 && pod.UsageMemoryBytes > 0 { - totalBytes := kubernetesPodMemoryTotalBytes(cluster, pod) - if totalBytes > 0 { - memoryPercent = clampWorkloadPercent((float64(pod.UsageMemoryBytes) / float64(totalBytes)) * 100) - } - } - - diskPercent := clampWorkloadPercent(pod.DiskUsagePercent) - netIn := clampNonNegativeWorkloadValue(pod.NetInRate) - netOut := clampNonNegativeWorkloadValue(pod.NetOutRate) - - return map[string]float64{ - "cpu": cpuPercent, - "memory": memoryPercent, - "disk": diskPercent, - "diskread": 0, - "diskwrite": 0, - "netin": netIn, - "netout": netOut, - } -} - -func kubernetesPodMemoryTotalBytes(cluster models.KubernetesCluster, pod models.KubernetesPod) int64 { - nodeName := strings.TrimSpace(pod.NodeName) - if nodeName == "" { - return 0 - } - for _, node := range cluster.Nodes { - if !strings.EqualFold(strings.TrimSpace(node.Name), nodeName) { - continue - } - if node.AllocMemoryBytes > 0 { - return node.AllocMemoryBytes - } - if node.CapacityMemoryBytes > 0 { - return node.CapacityMemoryBytes - } - return 0 - } - return 0 -} - func getOrCreateWorkloadBucket(buckets map[int64]*workloadSummaryBuckets, bucketTs int64) *workloadSummaryBuckets { if bucket, ok := buckets[bucketTs]; ok { return bucket diff --git a/internal/api/security_regression_test.go b/internal/api/security_regression_test.go index e269ddf49..454713b1a 100644 --- a/internal/api/security_regression_test.go +++ b/internal/api/security_regression_test.go @@ -16,7 +16,6 @@ import ( "github.com/gorilla/websocket" "github.com/rcourtman/pulse-go-rewrite/internal/agentexec" - "github.com/rcourtman/pulse-go-rewrite/internal/ai" "github.com/rcourtman/pulse-go-rewrite/internal/config" "github.com/rcourtman/pulse-go-rewrite/internal/monitoring" "github.com/rcourtman/pulse-go-rewrite/internal/servicediscovery" @@ -106,13 +105,6 @@ func readRegisteredPayload(t *testing.T, conn *websocket.Conn) agentexec.Registe return payload } -// newLegacyAIServiceForTest creates an *ai.Service with loaded config for route-level tests. -func newLegacyAIServiceForTest(persistence *config.ConfigPersistence) *ai.Service { - svc := ai.NewService(persistence, nil) - _ = svc.LoadConfig() - return svc -} - func TestSimpleStatsRequiresAuthInAPIMode(t *testing.T) { rawToken := "stats-token-123.12345678" record := newTokenRecord(t, rawToken, []string{config.ScopeMonitoringRead}, nil) diff --git a/internal/api/security_status_capabilities.go b/internal/api/security_status_capabilities.go index f00ef994b..dc48cee8a 100644 --- a/internal/api/security_status_capabilities.go +++ b/internal/api/security_status_capabilities.go @@ -236,10 +236,6 @@ func (r *Router) securityStatusSettingsCapabilitiesFromSnapshot(snapshot securit } } -func (r *Router) securityStatusSettingsCapabilities(req *http.Request) securityStatusSettingsCapabilities { - return r.securityStatusSettingsCapabilitiesFromSnapshot(r.buildSecurityStatusAuthSnapshot(req)) -} - func (r *Router) securityStatusSessionCapabilities(ctx context.Context) securityStatusSessionCapabilities { demoMode := r != nil && r.config != nil && r.config.DemoMode assistantEnabled := false diff --git a/internal/api/subscription_entitlements.go b/internal/api/subscription_entitlements.go index d7f754690..d83512596 100644 --- a/internal/api/subscription_entitlements.go +++ b/internal/api/subscription_entitlements.go @@ -225,20 +225,6 @@ func buildEntitlementPayload(status *licenseStatus, subscriptionState string) En return buildEntitlementPayloadFromLicensing(status, subscriptionState) } -func buildRuntimeCapabilitiesPayload( - status *licenseStatus, - subscriptionState string, -) RuntimeCapabilitiesPayload { - return buildRuntimeCapabilitiesPayloadFromLicensing(status, subscriptionState) -} - -func buildCommercialPosturePayload( - status *licenseStatus, - subscriptionState string, -) CommercialPosturePayload { - return buildCommercialPosturePayloadFromLicensing(status, subscriptionState) -} - // buildEntitlementPayloadWithUsage constructs the normalized payload from LicenseStatus and observed usage. func buildEntitlementPayloadWithUsage( status *licenseStatus, @@ -360,35 +346,6 @@ func (h *LicenseHandlers) ensureOnboardingOverflow(ctx context.Context, tier lic return &now } -// overflowGrantedAtForContext returns the OverflowGrantedAt timestamp for the -// current org, reading from the evaluator first (hosted path), then falling -// back to billing state on disk (self-hosted path). Does NOT lazy-initialize. -func (h *LicenseHandlers) overflowGrantedAtForContext(ctx context.Context) *int64 { - if h == nil || h.mtPersistence == nil { - return nil - } - - // Hosted path: evaluator already has OverflowGrantedAt cached. - svc, _, err := h.getTenantComponents(ctx) - if err == nil && svc != nil { - if eval := svc.Evaluator(); eval != nil { - return eval.OverflowGrantedAt() - } - } - - // Self-hosted path: read from billing state directly. - orgID := GetOrgID(ctx) - if orgID == "" { - orgID = "default" - } - billingStore := config.NewFileBillingStore(h.mtPersistence.BaseDataDir()) - existing, readErr := billingStore.GetBillingState(orgID) - if readErr != nil || existing == nil { - return nil - } - return existing.OverflowGrantedAt -} - func (h *LicenseHandlers) billingStateForContext(ctx context.Context) *billingState { if h == nil || h.mtPersistence == nil { return nil diff --git a/internal/api/subscription_state_reconciler.go b/internal/api/subscription_state_reconciler.go index d348cbd8d..1b888b081 100644 --- a/internal/api/subscription_state_reconciler.go +++ b/internal/api/subscription_state_reconciler.go @@ -1,13 +1,7 @@ package api import ( - "context" - "os" - "path/filepath" "time" - - "github.com/rcourtman/pulse-go-rewrite/internal/config" - "github.com/rs/zerolog/log" ) const ( @@ -20,79 +14,3 @@ const ( type SubscriptionStateReconciler struct { dataDir string } - -// NewSubscriptionStateReconciler creates a reconciler. -func NewSubscriptionStateReconciler(dataDir string) *SubscriptionStateReconciler { - return &SubscriptionStateReconciler{dataDir: dataDir} -} - -// Run starts the reconciliation loop. It blocks until ctx is cancelled. -func (sr *SubscriptionStateReconciler) Run(ctx context.Context) { - log.Info().Msg("Subscription reconciler started (log-only mode)") - - ticker := time.NewTicker(reconcileInterval) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - log.Info().Msg("Subscription reconciler stopped") - return - case <-ticker.C: - sr.reconcile(ctx) - } - } -} - -func (sr *SubscriptionStateReconciler) reconcile(ctx context.Context) { - _ = ctx - - store := config.NewFileBillingStore(sr.dataDir) - state, err := store.GetBillingState("default") - if err != nil { - log.Debug().Err(err).Msg("Subscription reconciler: no state found (self-hosted instance)") - return - } - if state == nil { - return - } - - // Staleness signal: billing.json mtime (best-effort). - if sr.dataDir != "" && state.StripeSubscriptionID != "" { - billingPath := filepath.Join(sr.dataDir, "billing.json") - if fi, statErr := os.Stat(billingPath); statErr == nil { - if time.Since(fi.ModTime()) > staleSubscriptionState { - log.Warn(). - Str("stripe_subscription_id", state.StripeSubscriptionID). - Str("stripe_customer_id", state.StripeCustomerID). - Dur("stale_window", staleSubscriptionState). - Time("billing_file_mtime", fi.ModTime()). - Msg("Subscription reconciler: state appears stale; ensure webhook processing is healthy") - } - } - } - - // Check for drift between stored subscription state and expected capabilities. - if state.StripeSubscriptionID != "" && state.SubscriptionState == subscriptionStateActiveValue { - // Active subscription: expected to have capabilities; nothing to warn about. - return - } - - if state.StripeSubscriptionID != "" && state.SubscriptionState == subscriptionStateGraceValue { - log.Warn(). - Str("stripe_subscription_id", state.StripeSubscriptionID). - Str("stripe_customer_id", state.StripeCustomerID). - Str("subscription_state", string(state.SubscriptionState)). - Msg("Subscription reconciler: tenant in grace period; verify payment-provider dashboard") - } - - if state.StripeSubscriptionID != "" && state.SubscriptionState == subscriptionStateCanceledValue { - if len(state.Capabilities) > 0 { - log.Warn(). - Str("stripe_subscription_id", state.StripeSubscriptionID). - Str("subscription_state", string(state.SubscriptionState)). - Int("capability_count", len(state.Capabilities)). - Msg("Subscription reconciler: DRIFT: canceled subscription still has capabilities") - } - } -} diff --git a/internal/api/unified_agent.go b/internal/api/unified_agent.go index 97971e120..eb08ad937 100644 --- a/internal/api/unified_agent.go +++ b/internal/api/unified_agent.go @@ -442,10 +442,6 @@ func readBinaryWithChecksum(body io.Reader) ([]byte, string, error) { return content, hex.EncodeToString(hasher.Sum(nil)), nil } -func serveProxiedAgentBinary(w http.ResponseWriter, content []byte, checksum, servedFrom string) { - serveProxiedAgentBinaryWithSignatures(w, content, checksum, "", "", servedFrom) -} - func serveProxiedAgentBinaryWithSignatures(w http.ResponseWriter, content []byte, checksum, signature, sshSignature, servedFrom string) { w.Header().Set(checksumHeaderName, checksum) if strings.TrimSpace(signature) != "" { diff --git a/internal/api/websocket_isolation_test.go b/internal/api/websocket_isolation_test.go index d7fdfe989..992970635 100644 --- a/internal/api/websocket_isolation_test.go +++ b/internal/api/websocket_isolation_test.go @@ -4,7 +4,6 @@ import ( "context" "testing" - pkglicensing "github.com/rcourtman/pulse-go-rewrite/pkg/licensing" "github.com/stretchr/testify/assert" ) @@ -13,24 +12,11 @@ type WSMockLicenseService struct { Features map[string]bool } -func (m *WSMockLicenseService) HasFeature(feature string) bool { - return m.Features[feature] -} - -func (m *WSMockLicenseService) Service(ctx context.Context) *pkglicensing.Service { - // Return empty service (no license) by default - return pkglicensing.NewService() -} - // WebSocketMockLicenseProvider to return our mock service type WebSocketMockLicenseProvider struct { service *WSMockLicenseService } -func (p *WebSocketMockLicenseProvider) Service(ctx context.Context) *pkglicensing.Service { - return pkglicensing.NewService() -} - func TestWebSocketIsolation_Permanent(t *testing.T) { // Reset global state defer SetMultiTenantEnabled(false) diff --git a/internal/cloudcp/account/tenant_handlers.go b/internal/cloudcp/account/tenant_handlers.go index 8da2656df..e8d1070a7 100644 --- a/internal/cloudcp/account/tenant_handlers.go +++ b/internal/cloudcp/account/tenant_handlers.go @@ -331,20 +331,6 @@ func parseTenantState(s string) (registry.TenantState, bool) { } } -func loadTenantForAccount(reg *registry.TenantRegistry, accountID, tenantID string) (*registry.Tenant, error) { - t, err := reg.Get(tenantID) - if err != nil { - return nil, fmt.Errorf("load tenant %q: %w", tenantID, err) - } - if t == nil { - return nil, nil - } - if strings.TrimSpace(t.AccountID) == "" || t.AccountID != accountID { - return nil, nil - } - return t, nil -} - // HandleUpdateTenant updates display name and/or state. // Route: PATCH /api/accounts/{account_id}/tenants/{tenant_id} func HandleUpdateTenant(reg *registry.TenantRegistry) http.HandlerFunc { diff --git a/internal/cloudcp/docker/manager.go b/internal/cloudcp/docker/manager.go index f8a082a07..3e58e2470 100644 --- a/internal/cloudcp/docker/manager.go +++ b/internal/cloudcp/docker/manager.go @@ -551,10 +551,6 @@ func tenantRuntimeContainerConfig(tenantID string, cfg ManagerConfig, labels map } } -func tenantRuntimeUser() string { - return fmt.Sprintf("%d:%d", tenantRuntimeUID, tenantRuntimeGID) -} - func tenantRuntimeUserFor(cfg ManagerConfig) string { return fmt.Sprintf("%d:%d", tenantRuntimeUIDFor(cfg), tenantRuntimeGIDFor(cfg)) } diff --git a/internal/cloudcp/portal/page.go b/internal/cloudcp/portal/page.go index f26c525d2..73826aab5 100644 --- a/internal/cloudcp/portal/page.go +++ b/internal/cloudcp/portal/page.go @@ -75,18 +75,6 @@ const ( var errPortalAuthRequired = errors.New("portal auth required") -// HandlePortalPage serves the MSP/Cloud portal dashboard (browser-facing HTML). -// Route: GET /portal -// - No session or invalid session -> shows a magic-link login form -// - Valid session -> shows workspace list with management actions -func HandlePortalPage(sessionSvc *cpauth.Service, reg *registry.TenantRegistry, commercialLookup CommercialIdentityLookup, faviconHref string) http.HandlerFunc { - return HandlePortalPageWithSignupPath(sessionSvc, reg, commercialLookup, faviconHref, PortalSignupPath) -} - -func HandlePortalPageWithSignupPath(sessionSvc *cpauth.Service, reg *registry.TenantRegistry, commercialLookup CommercialIdentityLookup, faviconHref string, signupPath string) http.HandlerFunc { - return HandlePortalPageWithSignupPathAndSetupFacts(sessionSvc, reg, commercialLookup, faviconHref, signupPath, nil) -} - func HandlePortalPageWithSignupPathAndSetupFacts(sessionSvc *cpauth.Service, reg *registry.TenantRegistry, commercialLookup CommercialIdentityLookup, faviconHref string, signupPath string, setupFacts WorkspaceSetupFactReader) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { diff --git a/internal/cloudcp/public_msp_signup_handlers.go b/internal/cloudcp/public_msp_signup_handlers.go index 53a190c68..a0193bda7 100644 --- a/internal/cloudcp/public_msp_signup_handlers.go +++ b/internal/cloudcp/public_msp_signup_handlers.go @@ -92,11 +92,6 @@ func (h *PublicCloudSignupHandlers) selfServeMSPPriceIDForTier(tier mspTier) (st return h.priceIDForMSPTier(tier) } -func (h *PublicCloudSignupHandlers) hasMSPTier(tier mspTier) bool { - _, ok := h.priceIDForMSPTier(tier) - return ok -} - func validatePublicMSPSignupPriceID(tier mspTier, priceID string) error { wantPlanVersion := expectedPlanVersionForMSPTier(tier) if wantPlanVersion == "" { diff --git a/internal/config/metadata_helpers.go b/internal/config/metadata_helpers.go index d86f3bbf1..8dd37d9cb 100644 --- a/internal/config/metadata_helpers.go +++ b/internal/config/metadata_helpers.go @@ -1,84 +1,6 @@ package config -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "github.com/rs/zerolog/log" -) - // metadataFileLoader provides a generic way to load metadata from disk type metadataFileLoader interface { LoadFromDisk() error } - -// loadMetadataFromFile reads metadata from a JSON file and unmarshals it into the provided map. -// The map pointer must be passed as a generic interface{} to allow runtime assignment. -func loadMetadataFromFile[T any]( - fs FileSystem, - dataPath string, - fileName string, - maxFileSize int64, - metadataMap *map[string]*T, - logMsg string, -) error { - filePath := filepath.Join(dataPath, fileName) - - log.Debug().Str("path", filePath).Msg("Loading " + logMsg + " from disk") - - data, err := readLimitedRegularFileFS(fs, filePath, maxFileSize) - if err != nil { - if os.IsNotExist(err) { - log.Debug().Str("path", filePath).Msg(logMsg + " file does not exist yet") - return nil - } - return fmt.Errorf("failed to read metadata file: %w", err) - } - - if err := json.Unmarshal(data, metadataMap); err != nil { - return fmt.Errorf("failed to unmarshal metadata: %w", err) - } - - log.Info().Int("count", len(*metadataMap)).Msg("Loaded " + logMsg) - return nil -} - -// saveMetadataToFile writes metadata to a JSON file using atomic write (write to temp, then rename). -func saveMetadataToFile[T any]( - fs FileSystem, - dataPath string, - fileName string, - metadataMap map[string]*T, - logMsg string, -) error { - filePath := filepath.Join(dataPath, fileName) - - log.Debug().Str("path", filePath).Msg("Saving " + logMsg + " to disk") - - data, err := json.Marshal(metadataMap) - if err != nil { - return fmt.Errorf("failed to marshal metadata: %w", err) - } - - // Restrict metadata persistence to owner-only access. - if err := fs.MkdirAll(dataPath, 0o700); err != nil { - return fmt.Errorf("failed to create data directory: %w", err) - } - - // Write to temp file first for atomic operation - tempFile := filePath + ".tmp" - if err := fs.WriteFile(tempFile, data, 0o600); err != nil { - return fmt.Errorf("failed to write metadata file: %w", err) - } - - // Rename temp file to actual file (atomic on most systems) - if err := fs.Rename(tempFile, filePath); err != nil { - return fmt.Errorf("failed to rename metadata file: %w", err) - } - - log.Debug().Str("path", filePath).Int("entries", len(metadataMap)).Msg(logMsg + " saved successfully") - - return nil -} diff --git a/internal/dockeragent/container_update.go b/internal/dockeragent/container_update.go index d4e89dd83..6c786d204 100644 --- a/internal/dockeragent/container_update.go +++ b/internal/dockeragent/container_update.go @@ -403,30 +403,6 @@ func (a *Agent) updateContainerWithProgress(ctx context.Context, containerID str return result } -func drainAndClosePullResponse(pullResp io.ReadCloser) error { - if pullResp == nil { - return errors.New("pull response body is nil") - } - - _, drainErr := io.Copy(io.Discard, pullResp) - closeErr := pullResp.Close() - - if drainErr != nil && closeErr != nil { - return errors.Join( - fmt.Errorf("drain pull response body: %w", drainErr), - fmt.Errorf("close pull response body: %w", closeErr), - ) - } - if drainErr != nil { - return fmt.Errorf("drain pull response body: %w", drainErr) - } - if closeErr != nil { - return fmt.Errorf("close pull response body: %w", closeErr) - } - - return nil -} - func (a *Agent) rollbackRenameAndRestart(ctx context.Context, backupName, originalName, originalID string, restart bool) { if err := a.docker.ContainerRename(ctx, backupName, originalName); err != nil { a.logger.Warn(). diff --git a/internal/hosted/provisioner_test.go b/internal/hosted/provisioner_test.go index 9e9053b52..b6754d5c9 100644 --- a/internal/hosted/provisioner_test.go +++ b/internal/hosted/provisioner_test.go @@ -56,25 +56,6 @@ type mockOrgPersistence struct { saveErr error } -func (m *mockOrgPersistence) GetPersistence(orgID string) (*config.ConfigPersistence, error) { - return m.base.GetPersistence(orgID) -} - -func (m *mockOrgPersistence) SaveOrganization(org *models.Organization) error { - if m.saveErr != nil { - return m.saveErr - } - return m.base.SaveOrganization(org) -} - -func (m *mockOrgPersistence) LoadOrganization(orgID string) (*models.Organization, error) { - return m.base.LoadOrganization(orgID) -} - -func (m *mockOrgPersistence) ListOrganizations() ([]*models.Organization, error) { - return m.base.ListOrganizations() -} - func TestProvisionTenantSuccess(t *testing.T) { baseDir := t.TempDir() persistence := config.NewMultiTenantPersistence(baseDir) diff --git a/internal/kubernetesagent/agent.go b/internal/kubernetesagent/agent.go index b37ea40fe..a28b4f9fa 100644 --- a/internal/kubernetesagent/agent.go +++ b/internal/kubernetesagent/agent.go @@ -1270,14 +1270,6 @@ func hasPodUsage(usage agentsk8s.PodUsage) bool { usage.EphemeralStorageCapacityBytes > 0 } -func copyStringMap(m map[string]string) map[string]string { - c := make(map[string]string, len(m)) - for k, v := range m { - c[k] = v - } - return c -} - func parseQuantity(value string, convert func(k8sresource.Quantity) int64) int64 { value = strings.TrimSpace(value) if value == "" { diff --git a/internal/license/features.go b/internal/license/features.go index 0ea92f9ac..818760c5b 100644 --- a/internal/license/features.go +++ b/internal/license/features.go @@ -49,11 +49,6 @@ var TierFeatures = licensing.TierFeatures // TierHistoryDays defines the maximum metrics history retention per tier. var TierHistoryDays = licensing.TierHistoryDays -// DeriveCapabilitiesFromTier derives effective capabilities from tier and explicit features. -func DeriveCapabilitiesFromTier(tier Tier, explicitFeatures []string) []string { - return licensing.DeriveCapabilitiesFromTier(tier, explicitFeatures) -} - // DeriveEntitlements derives capabilities and limits from tier and canonical monitored-system fields. func DeriveEntitlements(tier Tier, features []string, maxMonitoredSystems int, maxGuests int) (capabilities []string, limits map[string]int64) { return licensing.DeriveEntitlements(tier, features, maxMonitoredSystems, maxGuests) @@ -73,10 +68,3 @@ func GetTierDisplayName(tier Tier) string { func GetFeatureDisplayName(feature string) string { return licensing.GetFeatureDisplayName(feature) } - -// IsCompatibilityOnlyFeature reports capability keys that remain valid runtime -// contracts for backwards compatibility but should not be marketed as current -// v6 commercial pillars or generic upgrade prompts. -func IsCompatibilityOnlyFeature(feature string) bool { - return licensing.IsCompatibilityOnlyFeature(feature) -} diff --git a/internal/license/license.go b/internal/license/license.go index 7814e83ad..1eea86ff2 100644 --- a/internal/license/license.go +++ b/internal/license/license.go @@ -30,17 +30,6 @@ func SetPublicKey(key ed25519.PublicKey) { pkglicensing.SetPublicKey(key) } -func currentPublicKey() ed25519.PublicKey { - publicKeyMu.RLock() - defer publicKeyMu.RUnlock() - if len(publicKey) == 0 { - return nil - } - keyCopy := make(ed25519.PublicKey, len(publicKey)) - copy(keyCopy, publicKey) - return keyCopy -} - var ( ErrInvalidLicense = pkglicensing.ErrInvalidLicense ErrExpiredLicense = pkglicensing.ErrExpiredLicense diff --git a/internal/metrics/incident_recorder.go b/internal/metrics/incident_recorder.go index 288142638..cb4f607c9 100644 --- a/internal/metrics/incident_recorder.go +++ b/internal/metrics/incident_recorder.go @@ -694,41 +694,6 @@ func (r *IncidentRecorder) snapshotCompletedWindows() []*IncidentWindow { return snapshot } -func (r *IncidentRecorder) requestAsyncSave() { - if r.filePath == "" { - return - } - - r.saveMu.Lock() - r.saveRequested = true - if r.saveInProgress { - r.saveMu.Unlock() - return - } - r.saveInProgress = true - r.saveMu.Unlock() - - go r.saveLoop() -} - -func (r *IncidentRecorder) saveLoop() { - for { - r.saveMu.Lock() - if !r.saveRequested { - r.saveInProgress = false - r.saveCond.Broadcast() - r.saveMu.Unlock() - return - } - r.saveRequested = false - r.saveMu.Unlock() - - if err := r.saveToDisk(); err != nil { - log.Warn().Err(err).Msg("Failed to save incident windows") - } - } -} - func (r *IncidentRecorder) waitForPendingSaves() { if r.filePath == "" { return diff --git a/internal/mock/availability_fixtures.go b/internal/mock/availability_fixtures.go index 9497168c4..1ad1a42a3 100644 --- a/internal/mock/availability_fixtures.go +++ b/internal/mock/availability_fixtures.go @@ -61,19 +61,6 @@ func AvailabilityFixtures() []AvailabilityFixture { return CurrentFixtureGraph().AvailabilityFixtures } -func AvailabilityTargets() []AvailabilityTargetFixture { - fixtures := AvailabilityFixtures() - out := make([]AvailabilityTargetFixture, 0, len(fixtures)) - for _, fixture := range fixtures { - target := normalizeAvailabilityTargetFixture(fixture.Target) - if strings.TrimSpace(target.ID) == "" { - continue - } - out = append(out, target) - } - return out -} - func normalizeAvailabilityTargetFixture(target AvailabilityTargetFixture) AvailabilityTargetFixture { target.ID = strings.TrimSpace(target.ID) target.Name = strings.TrimSpace(target.Name) diff --git a/internal/mock/demo_scenarios.go b/internal/mock/demo_scenarios.go index cdb4c53b5..7b5c43545 100644 --- a/internal/mock/demo_scenarios.go +++ b/internal/mock/demo_scenarios.go @@ -1204,10 +1204,6 @@ func scenarioClusterAlias(name string) string { } } -func scenarioStorageAlias(name string) string { - return scenarioStorageAliasForNode(name, "") -} - func storageScenarioAlias(storage models.Storage) string { return scenarioStorageAliasForNode(storage.Name, storage.Node) } diff --git a/internal/mock/env_dev.go b/internal/mock/env_dev.go index 1bb3d265b..1db70783f 100644 --- a/internal/mock/env_dev.go +++ b/internal/mock/env_dev.go @@ -2,12 +2,4 @@ package mock -import "os" - -// mockModeFromEnv reads PULSE_MOCK_MODE from the environment. -// Only available in non-release builds. -func mockModeFromEnv() bool { - return os.Getenv("PULSE_MOCK_MODE") == "true" -} - func shouldSyncEnvFlag() bool { return true } diff --git a/internal/mock/generator.go b/internal/mock/generator.go index 4c5b6d85c..f264f102d 100644 --- a/internal/mock/generator.go +++ b/internal/mock/generator.go @@ -3668,14 +3668,6 @@ func generateMockHostRate(ioType string) float64 { } } -func generateMockTemperature(cpuUsagePercent float64) *float64 { - if cpuUsagePercent <= 0 { - return nil - } - temp := clampFloat(34+(cpuUsagePercent*0.45)+rand.Float64()*4, 32, 88) - return &temp -} - func fluctuateMockHostRate(current float64, ioType string, min, max float64) float64 { if current <= 0 { current = generateMockHostRate(ioType) @@ -3688,42 +3680,6 @@ func fluctuateMockHostRate(current float64, ioType string, min, max float64) flo return clampFloat(next, min, max) } -func updateMockHostRates(host *models.Host) { - if host == nil { - return - } - if strings.EqualFold(host.Status, "offline") { - host.NetInRate = 0 - host.NetOutRate = 0 - host.DiskReadRate = 0 - host.DiskWriteRate = 0 - return - } - - host.NetInRate = fluctuateMockHostRate(host.NetInRate, "network-in", 32*1024, 250*1024*1024) - host.NetOutRate = fluctuateMockHostRate(host.NetOutRate, "network-out", 24*1024, 200*1024*1024) - host.DiskReadRate = fluctuateMockHostRate(host.DiskReadRate, "disk-read", 16*1024, 120*1024*1024) - host.DiskWriteRate = fluctuateMockHostRate(host.DiskWriteRate, "disk-write", 8*1024, 90*1024*1024) -} - -func updateMockDockerHostRates(host *models.DockerHost) { - if host == nil { - return - } - if strings.EqualFold(host.Status, "offline") { - host.NetInRate = 0 - host.NetOutRate = 0 - host.DiskReadRate = 0 - host.DiskWriteRate = 0 - return - } - - host.NetInRate = fluctuateMockHostRate(host.NetInRate, "network-in", 32*1024, 250*1024*1024) - host.NetOutRate = fluctuateMockHostRate(host.NetOutRate, "network-out", 24*1024, 200*1024*1024) - host.DiskReadRate = fluctuateMockHostRate(host.DiskReadRate, "disk-read", 16*1024, 120*1024*1024) - host.DiskWriteRate = fluctuateMockHostRate(host.DiskWriteRate, "disk-write", 8*1024, 90*1024*1024) -} - func generateDockerContainers(hostName string, hostIdx int, config MockConfig, podman bool) []models.DockerContainer { base := config.DockerContainersPerHost if base < 1 { @@ -4125,29 +4081,6 @@ func applyDiskUsage(disk *models.Disk, usage float64) { } } -func naturalMetricUpdate(current, min, max float64, resourceClass, resourceID, metric string, speed float64) float64 { - now := time.Now() - if speed <= 0 { - speed = 1.0 - } - - ideal := sampleNaturalMetric(resourceClass, resourceID, metric, min, max, speed, now) - alpha := 0.06 * speed - if speed >= 0.8 && math.Abs(ideal-current) > math.Max(1, (max-min)*0.03) { - alpha = 0.15 // track spike (gentler than before to avoid jarring snaps) - } - if alpha < 0.005 { - alpha = 0.005 - } - if alpha > 0.5 { - alpha = 0.5 - } - alpha = normalizeMockBlendWeight(alpha, currentMockUpdateInterval(), time.Minute) - newValue := current + alpha*(ideal-current) - - return clampFloat(newValue, min, max) -} - func randomHexString(n int) string { const hexChars = "0123456789abcdef" if n <= 0 { diff --git a/internal/mock/integration.go b/internal/mock/integration.go index fa1790bc8..456b0f4e6 100644 --- a/internal/mock/integration.go +++ b/internal/mock/integration.go @@ -86,12 +86,6 @@ func SetReleaseFixturesAuthorized(authorized bool) { mockruntime.SetReleaseFixturesAuthorized(authorized) } -// ValidateEnablement checks whether the current build/runtime may enter the -// requested mock mode state. -func ValidateEnablement(enable bool) error { - return mockruntime.ValidateEnablement(enable) -} - // SetEnabled enables or disables mock mode. func SetEnabled(enable bool) error { return setEnabled(enable, false) @@ -431,20 +425,6 @@ func LoadMockConfig() MockConfig { return normalizeMockConfig(config) } -func parseIntEnv(key, value string, fallback int, min int) (int, bool) { - n, err := strconv.Atoi(value) - if err == nil && n >= min { - return n, true - } - log.Warn(). - Str("env_var", key). - Str("env_value", value). - Int("default", fallback). - Int("minimum", min). - Msg("Ignoring invalid mock configuration integer override") - return 0, false -} - // SetMockConfig updates the mock configuration dynamically and regenerates data when enabled. func SetMockConfig(cfg MockConfig) { normalized := normalizeMockConfig(cfg) diff --git a/internal/mock/metric_personas.go b/internal/mock/metric_personas.go index 49281e36f..88d42381f 100644 --- a/internal/mock/metric_personas.go +++ b/internal/mock/metric_personas.go @@ -52,10 +52,6 @@ func setMetricRoleRegistry(registry map[string]string) { metricRoleRegistry.Store(cloned) } -func clearMetricRoleRegistry() { - metricRoleRegistry.Store(map[string]string{}) -} - func currentMetricRoleRegistry() map[string]string { raw := metricRoleRegistry.Load() if raw == nil { diff --git a/internal/mock/platform_fixtures.go b/internal/mock/platform_fixtures.go index 664b93218..6563bd4f9 100644 --- a/internal/mock/platform_fixtures.go +++ b/internal/mock/platform_fixtures.go @@ -151,13 +151,6 @@ func SupplementalChanges(source unifiedresources.DataSource) []unifiedresources. } } -func PlatformOwnedSources() []unifiedresources.DataSource { - return []unifiedresources.DataSource{ - unifiedresources.SourceTrueNAS, - unifiedresources.SourceVMware, - } -} - func SupplementalOwnedSources() []unifiedresources.DataSource { return []unifiedresources.DataSource{ unifiedresources.SourceTrueNAS, diff --git a/internal/mock/recovery_points.go b/internal/mock/recovery_points.go index 06b49cbad..61f0ea397 100644 --- a/internal/mock/recovery_points.go +++ b/internal/mock/recovery_points.go @@ -626,47 +626,6 @@ func firstNonEmptyTrimmed(values ...string) string { return "" } -func cloneRecoveryPoints(src []recovery.RecoveryPoint) []recovery.RecoveryPoint { - if len(src) == 0 { - return nil - } - dst := make([]recovery.RecoveryPoint, 0, len(src)) - for _, p := range src { - dst = append(dst, cloneRecoveryPoint(p)) - } - return dst -} - -func cloneRecoveryPoint(p recovery.RecoveryPoint) recovery.RecoveryPoint { - out := p - - out.StartedAt = cloneTimePtr(p.StartedAt) - out.CompletedAt = cloneTimePtr(p.CompletedAt) - out.SizeBytes = cloneInt64Ptr(p.SizeBytes) - out.Verified = cloneBoolPtr(p.Verified) - out.Encrypted = cloneBoolPtr(p.Encrypted) - out.Immutable = cloneBoolPtr(p.Immutable) - - if p.SubjectRef != nil { - ref := *p.SubjectRef - if p.SubjectRef.Extra != nil { - ref.Extra = cloneStringMap(p.SubjectRef.Extra) - } - out.SubjectRef = &ref - } - if p.RepositoryRef != nil { - ref := *p.RepositoryRef - if p.RepositoryRef.Extra != nil { - ref.Extra = cloneStringMap(p.RepositoryRef.Extra) - } - out.RepositoryRef = &ref - } - if p.Details != nil { - out.Details = cloneAnyMap(p.Details) - } - return out -} - func cloneStringMap(src map[string]string) map[string]string { if len(src) == 0 { return nil @@ -678,22 +637,6 @@ func cloneStringMap(src map[string]string) map[string]string { return dst } -func cloneAnyMap(src map[string]any) map[string]any { - if len(src) == 0 { - return nil - } - dst := make(map[string]any, len(src)) - for k, v := range src { - // Values are primitives/slices in our mock payloads; shallow copy is sufficient. - if s, ok := v.([]string); ok { - dst[k] = append([]string(nil), s...) - continue - } - dst[k] = v - } - return dst -} - func cloneTimePtr(t *time.Time) *time.Time { if t == nil || t.IsZero() { return nil diff --git a/internal/mock/truenas_metrics_identity.go b/internal/mock/truenas_metrics_identity.go index ba6ae9480..9f8c9b776 100644 --- a/internal/mock/truenas_metrics_identity.go +++ b/internal/mock/truenas_metrics_identity.go @@ -36,14 +36,3 @@ func TrueNASScopedMetricID(hostname string, sourceID string) string { } return "system:" + hostname + "/" + sourceID } - -func trueNASDiskMetricsResourceID(disk truenas.Disk) string { - resourceID := strings.TrimSpace(disk.Serial) - if resourceID == "" { - resourceID = strings.TrimSpace(disk.ID) - } - if resourceID == "" { - resourceID = strings.TrimSpace(disk.Name) - } - return resourceID -} diff --git a/internal/mockmodel/metrics.go b/internal/mockmodel/metrics.go index 7de79c40e..27f4d675f 100644 --- a/internal/mockmodel/metrics.go +++ b/internal/mockmodel/metrics.go @@ -102,21 +102,6 @@ func NormalizeBlendWeight(weight float64, step, reference time.Duration) float64 return clampFloat(normalized, 0.0005, 0.999) } -func StyleSpeed(style SeriesStyle) float64 { - switch style { - case StylePlateau: - return 0.5 - case StyleFlat: - return 0.12 - default: - return 1.0 - } -} - -func ValueAt(seed uint64, min, max float64, speed float64, at time.Time) float64 { - return valueAtProfile(seed, min, max, profileFromSpeed(speed), at) -} - func ValueAtMetric(seed uint64, min, max float64, metric string, speed float64, at time.Time) float64 { return ValueAtMetricWithRole(seed, min, max, metric, speed, "", at) } @@ -264,10 +249,6 @@ func seriesForProfileWithRole( return values } -func valueAtProfile(seed uint64, min, max float64, profile metricProfile, at time.Time) float64 { - return valueAtProfileWithRole(seed, min, max, profile, "", at) -} - func valueAtProfileWithRole(seed uint64, min, max float64, profile metricProfile, role string, at time.Time) float64 { span := math.Max(1, max-min) modifiers := metricRoleProfile(role) diff --git a/internal/models/deepcopy.go b/internal/models/deepcopy.go index d564f4c99..ee8605d88 100644 --- a/internal/models/deepcopy.go +++ b/internal/models/deepcopy.go @@ -1140,10 +1140,6 @@ func clonePBSBackups(src []PBSBackup) []PBSBackup { return dest } -func clonePMGBackup(src PMGBackup) PMGBackup { - return src -} - func clonePMGBackups(src []PMGBackup) []PMGBackup { return append([]PMGBackup(nil), src...) } diff --git a/internal/monitoring/mock_chart_history.go b/internal/monitoring/mock_chart_history.go index 5201baecf..bd9a932ba 100644 --- a/internal/monitoring/mock_chart_history.go +++ b/internal/monitoring/mock_chart_history.go @@ -243,53 +243,3 @@ func (m *Monitor) mockStorageSummaryCapacityTrend(duration time.Duration) []Metr return lttb(points, chartDownsampleTarget) } - -func (m *Monitor) mockPhysicalDiskTemperatureCharts(duration time.Duration) map[string]DiskChartEntry { - if m == nil { - return nil - } - - readState := m.GetUnifiedReadStateOrSnapshot() - if readState == nil { - return nil - } - metricsTargetStore := m.currentMetricsTargetStore() - timestamps := mockChartTimestamps(duration) - if len(timestamps) == 0 { - return nil - } - - result := make(map[string]DiskChartEntry) - for _, disk := range readState.PhysicalDisks() { - if disk == nil || disk.Temperature() <= 0 { - continue - } - - resourceID := "" - if metricsTargetStore != nil { - if target := metricsTargetStore.MetricsTargetForResource(disk.ID()); target != nil { - resourceID = strings.TrimSpace(target.ResourceID) - } - } - if resourceID == "" { - resourceID = strings.TrimSpace(disk.MetricResourceID()) - } - if resourceID == "" { - continue - } - - name := strings.TrimSpace(disk.Model()) - if name == "" { - name = strings.TrimSpace(disk.DevPath()) - } - - result[resourceID] = DiskChartEntry{ - Name: name, - Node: strings.TrimSpace(disk.Node()), - Instance: strings.TrimSpace(disk.Instance()), - Temperature: mockCanonicalMetricSeries("disk", resourceID, "smart_temp", timestamps), - } - } - - return result -} diff --git a/internal/monitoring/mock_metrics_history.go b/internal/monitoring/mock_metrics_history.go index a001d8c3e..836d86c0b 100644 --- a/internal/monitoring/mock_metrics_history.go +++ b/internal/monitoring/mock_metrics_history.go @@ -1139,60 +1139,6 @@ func recordVMwareFixturesMetrics(mh *MetricsHistory, ms *metrics.Store, fixtures } } -func vmwareFloat64Metric(metrics *vmware.InventoryMetrics, pick func(*vmware.InventoryMetrics) *float64) float64 { - if metrics == nil || pick == nil { - return 0 - } - value := pick(metrics) - if value == nil { - return 0 - } - return *value -} - -func vmwareDatastoreUsageByID(datastores []vmware.InventoryDatastore) map[string]float64 { - out := make(map[string]float64, len(datastores)) - for _, datastore := range datastores { - id := strings.TrimSpace(datastore.Datastore) - if id == "" { - continue - } - out[id] = vmwareDatastoreUsagePercent(datastore) - } - return out -} - -func vmwareAverageDatastoreUsage(byID map[string]float64, ids []string) float64 { - if len(ids) == 0 || len(byID) == 0 { - return 0 - } - var total float64 - var count int - for _, id := range ids { - usage, ok := byID[strings.TrimSpace(id)] - if !ok { - continue - } - total += usage - count++ - } - if count == 0 { - return 0 - } - return total / float64(count) -} - -func vmwareDatastoreUsagePercent(datastore vmware.InventoryDatastore) float64 { - if datastore.Capacity <= 0 { - return 0 - } - used := datastore.Capacity - datastore.FreeSpace - if used < 0 { - used = 0 - } - return clampFloat((float64(used)/float64(datastore.Capacity))*100, 0, 100) -} - type guestMetricSource interface { GetID() string GetStatus() string diff --git a/internal/monitoring/truenas_poller.go b/internal/monitoring/truenas_poller.go index d3a6e2391..e0bd2b560 100644 --- a/internal/monitoring/truenas_poller.go +++ b/internal/monitoring/truenas_poller.go @@ -402,23 +402,6 @@ func (p *TrueNASPoller) syncConnections() { } } -func (p *TrueNASPoller) closeAllProviders() { - if p == nil { - return - } - - p.mu.Lock() - defer p.mu.Unlock() - - for _, providers := range p.providersByOrg { - for _, provider := range providers { - if provider != nil { - provider.Close() - } - } - } -} - // ConnectionSummaries returns per-connection runtime health and discovered // contribution summaries for the supplied TrueNAS settings records. func (p *TrueNASPoller) ConnectionSummaries(orgID string, instances []config.TrueNASInstance) map[string]TrueNASConnectionSummary { diff --git a/internal/notifications/notifications.go b/internal/notifications/notifications.go index 952ddbff0..d545282bf 100644 --- a/internal/notifications/notifications.go +++ b/internal/notifications/notifications.go @@ -400,25 +400,6 @@ func quietHoursReplayAtForAlert(alert *alerts.Alert, now time.Time) *time.Time { return &parsed } -func quietHoursReplayAtForAlerts(alertList []*alerts.Alert, now time.Time) *time.Time { - var replayAt time.Time - for _, alert := range alertList { - alertReplayAt := quietHoursReplayAtForAlert(alert, now) - if alertReplayAt == nil { - continue - } - if replayAt.IsZero() || alertReplayAt.After(replayAt) { - replayAt = *alertReplayAt - } - } - - if replayAt.IsZero() { - return nil - } - replayAt = replayAt.UTC() - return &replayAt -} - func notificationQueueBucketsForJob(job notificationDeliveryJob, now time.Time) []notificationQueueBucket { if len(job.Alerts) == 0 { return []notificationQueueBucket{{job: job}} @@ -1990,16 +1971,6 @@ func (n *NotificationManager) sendHTMLEmailWithError(subject, htmlBody, textBody return nil } -// sendHTMLEmail sends an HTML email with multipart content -func (n *NotificationManager) sendHTMLEmail(subject, htmlBody, textBody string, config EmailConfig) { - if err := n.sendHTMLEmailWithError(subject, htmlBody, textBody, config); err != nil { - log.Error(). - Err(err). - Str("smtp", fmt.Sprintf("%s:%d", config.SMTPHost, config.SMTPPort)). - Msg("failed to send HTML email notification") - } -} - type webhookRenderMode string const ( @@ -2565,55 +2536,6 @@ func (n *NotificationManager) sendWebhookRequest(webhook WebhookConfig, jsonData } } -func (n *NotificationManager) sendSingleWebhookWithError(webhook WebhookConfig, alert *alerts.Alert) error { - customFields := convertWebhookCustomFields(webhook.CustomFields) - data := n.prepareWebhookData(alert, customFields) - - var err error - webhook, data, err = n.prepareWebhookDeliveryContext(webhook, data) - if err != nil { - log.Error(). - Err(err). - Str("webhook", webhook.Name). - Msg("failed to prepare webhook delivery context") - return err - } - - jsonData, err := n.renderWebhookPayloadJSON(webhook, data, webhookRenderModeSingle, func() ([]byte, error) { - payload := map[string]interface{}{ - "alert": alert, - "timestamp": time.Now().Unix(), - "source": "pulse-monitoring", - } - return json.Marshal(payload) - }) - if err != nil { - log.Error(). - Err(err). - Str("webhook", webhook.Name). - Str("alertID", alert.ID). - Msg("failed to render webhook payload") - return err - } - - // Send using common request logic - if err := n.sendWebhookRequest(webhook, jsonData, fmt.Sprintf("alert-%s", alert.ID)); err != nil { - return err - } - return nil -} - -// sendWebhook sends a webhook notification -func (n *NotificationManager) sendWebhook(webhook WebhookConfig, alert *alerts.Alert) { - if err := n.sendSingleWebhookWithError(webhook, alert); err != nil { - log.Error(). - Err(err). - Str("webhook", webhook.Name). - Str("alertID", alert.ID). - Msg("failed to send webhook notification") - } -} - func convertWebhookCustomFields(fields map[string]string) map[string]interface{} { if len(fields) == 0 { return nil diff --git a/internal/securityutil/websocket_origin.go b/internal/securityutil/websocket_origin.go index 9a294d297..376d2931c 100644 --- a/internal/securityutil/websocket_origin.go +++ b/internal/securityutil/websocket_origin.go @@ -2,10 +2,6 @@ package securityutil import pubsec "github.com/rcourtman/pulse-go-rewrite/pkg/securityutil" -func NormalizeWebSocketOriginHost(host string) string { - return pubsec.NormalizeWebSocketOriginHost(host) -} - func SameHostWebSocketOrigin(origin string, requestHost string) bool { return pubsec.SameHostWebSocketOrigin(origin, requestHost) } diff --git a/internal/sensors/collector.go b/internal/sensors/collector.go index adf148af2..3471b85fb 100644 --- a/internal/sensors/collector.go +++ b/internal/sensors/collector.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "os" "os/exec" "strconv" "strings" @@ -151,42 +150,3 @@ func runCommandOutputLimited(cmd *exec.Cmd, maxBytes int) ([]byte, error) { return output, nil } - -func readRPiThermalMilliDegrees(path string) (int64, error) { - raw, err := readLimitedTrimmedString(path, maxThermalFileReadBytes) - if err != nil { - return 0, err - } - - if raw == "" { - return 0, fmt.Errorf("empty thermal value") - } - - temp, err := strconv.ParseInt(raw, 10, 64) - if err != nil { - return 0, fmt.Errorf("invalid thermal value: %w", err) - } - if temp < -100000 || temp > 300000 { - return 0, fmt.Errorf("thermal value out of range") - } - - return temp, nil -} - -func readLimitedTrimmedString(path string, maxBytes int64) (string, error) { - file, err := os.Open(path) - if err != nil { - return "", err - } - defer file.Close() - - data, err := io.ReadAll(io.LimitReader(file, maxBytes+1)) - if err != nil { - return "", err - } - if int64(len(data)) > maxBytes { - return "", fmt.Errorf("file exceeds maximum size of %d bytes", maxBytes) - } - - return strings.TrimSpace(string(data)), nil -} diff --git a/internal/sensors/power.go b/internal/sensors/power.go index b6a45c44e..0947c029f 100644 --- a/internal/sensors/power.go +++ b/internal/sensors/power.go @@ -40,25 +40,6 @@ var raplBasePath = "/sys/class/powercap/intel-rapl" // Shorter intervals are less accurate; longer intervals add latency. const sampleInterval = 100 * time.Millisecond -func waitForSample(ctx context.Context) error { - timer := time.NewTimer(sampleInterval) - defer func() { - if !timer.Stop() { - select { - case <-timer.C: - default: - } - } - }() - - select { - case <-ctx.Done(): - return ctx.Err() - case <-timer.C: - return nil - } -} - // CollectPower reads power consumption data from the system. // Supports Intel RAPL and AMD energy driver. // Returns nil if no power data is available. diff --git a/internal/servicediscovery/service.go b/internal/servicediscovery/service.go index d6081922a..5625074d6 100644 --- a/internal/servicediscovery/service.go +++ b/internal/servicediscovery/service.go @@ -328,30 +328,6 @@ func DefaultConfig() Config { } } -func normalizeServiceConfig(cfg Config) Config { - if cfg.Interval <= 0 { - log.Warn().Dur("interval", cfg.Interval).Dur("default", defaultDiscoveryInterval).Msg("Invalid discovery interval; using default") - cfg.Interval = defaultDiscoveryInterval - } - if cfg.CacheExpiry <= 0 { - log.Warn().Dur("cache_expiry", cfg.CacheExpiry).Dur("default", defaultDiscoveryCacheExpiry).Msg("Invalid discovery cache expiry; using default") - cfg.CacheExpiry = defaultDiscoveryCacheExpiry - } - if cfg.DeepScanTimeout <= 0 { - log.Warn().Dur("deep_scan_timeout", cfg.DeepScanTimeout).Dur("default", defaultDiscoveryScanTimeout).Msg("Invalid deep scan timeout; using default") - cfg.DeepScanTimeout = defaultDiscoveryScanTimeout - } - switch { - case cfg.MaxDiscoveryAge <= 0: - log.Warn().Dur("max_discovery_age", cfg.MaxDiscoveryAge).Dur("default", defaultDiscoveryMaxAge).Msg("Invalid max discovery age; using default") - cfg.MaxDiscoveryAge = defaultDiscoveryMaxAge - case cfg.MaxDiscoveryAge < minDiscoveryMaxAge: - log.Warn().Dur("max_discovery_age", cfg.MaxDiscoveryAge).Dur("minimum", minDiscoveryMaxAge).Msg("Max discovery age below minimum; clamping") - cfg.MaxDiscoveryAge = minDiscoveryMaxAge - } - return cfg -} - func normalizeDiscoveryInterval(interval time.Duration) time.Duration { if interval > 0 { return interval @@ -642,19 +618,6 @@ func (s *Service) runDiscoveryLoop(ctx context.Context, stopCh <-chan struct{}, } } -func (s *Service) finishDiscoveryLoop(stopCh <-chan struct{}) { - s.mu.Lock() - defer s.mu.Unlock() - // Only clear lifecycle state if this is still the active run. - if s.stopCh != nil && s.stopCh != stopCh { - return - } - s.running = false - s.stopping = false - s.stopCh = nil - s.loopDone = nil -} - func (s *Service) runAutomaticDiscoveryRefresh(ctx context.Context) { if _, err := s.runDiscoveryRefresh(ctx, "automatic"); err != nil { log.Debug().Err(err).Msg("skipping automatic discovery refresh") @@ -2222,13 +2185,6 @@ func parseLegacyURLSuggestionSource(note string) (sourceCode, sourceDetail strin return trimmed, "" } -// suggestHostManagementURL provides host-level fallback URL suggestions when -// AI discovery does not identify a known web service. -func (s *Service) suggestHostManagementURL(req DiscoveryRequest, host string) string { - url, _, _ := s.suggestHostManagementURLWithReason(req, host) - return url -} - func (s *Service) suggestHostManagementURLWithReason(req DiscoveryRequest, host string) (string, string, string) { if req.ResourceType != ResourceTypeAgent { return "", "host_fallback_not_applicable", "not a host resource" diff --git a/internal/servicediscovery/store.go b/internal/servicediscovery/store.go index acb3fbb4b..9b7eaacb4 100644 --- a/internal/servicediscovery/store.go +++ b/internal/servicediscovery/store.go @@ -1021,32 +1021,6 @@ func (s *Store) CleanupOrphanedDiscoveries(currentResourceIDs map[string]bool) i return removed } -// filenameToResourceID converts a discovery filename back to a resource ID. -// Reverses the transformation done in getFilePath. -func filenameToResourceID(filename string) string { - // The filename uses underscores for colons and slashes - // We need to be smart about this - the format is type_host_resourceid - // First underscore separates type, rest could have underscores in host/resource names - - parts := strings.SplitN(filename, "_", 3) - if len(parts) < 3 { - return filename // Can't parse, return as-is - } - - resourceType := parts[0] - host := parts[1] - resourceID := parts[2] - - // For k8s, the resource ID might have been namespace/name which became namespace_name - // We convert back: k8s:cluster:namespace/name - if resourceType == "k8s" && strings.Contains(resourceID, "_") { - // Could be namespace_name, convert back to namespace/name - resourceID = strings.Replace(resourceID, "_", "/", 1) - } - - return resourceType + ":" + host + ":" + resourceID -} - func (s *Store) readDiscoveryIDFromPath(filePath string) (string, error) { data, migratedPlaintext, err := s.loadDiscoveryFileData(filePath, maxDiscoveryFileReadBytes) if err != nil { diff --git a/internal/servicediscovery/store_test.go b/internal/servicediscovery/store_test.go index da647f41f..a1efdccbd 100644 --- a/internal/servicediscovery/store_test.go +++ b/internal/servicediscovery/store_test.go @@ -15,18 +15,6 @@ import ( type fakeCrypto struct{} -func (fakeCrypto) Encrypt(plaintext []byte) ([]byte, error) { - out := make([]byte, len(plaintext)) - for i := range plaintext { - out[i] = plaintext[len(plaintext)-1-i] - } - return out, nil -} - -func (fakeCrypto) Decrypt(ciphertext []byte) ([]byte, error) { - return fakeCrypto{}.Encrypt(ciphertext) -} - type taggedCrypto struct{} func (taggedCrypto) Encrypt(plaintext []byte) ([]byte, error) { @@ -1202,12 +1190,3 @@ func TestStore_GetStaleResources(t *testing.T) { t.Fatalf("expected GetStaleResources to return list error") } } - -func containsString(items []string, target string) bool { - for _, item := range items { - if item == target { - return true - } - } - return false -} diff --git a/internal/system/container.go b/internal/system/container.go index 55cbaa009..e98ad2c7c 100644 --- a/internal/system/container.go +++ b/internal/system/container.go @@ -153,15 +153,6 @@ func hasAnyMarker(content string, markers []string) bool { return false } -func isHexString(s string) bool { - for _, c := range s { - if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { - return false - } - } - return true -} - // DetectLXCCTID attempts to detect the Proxmox LXC container ID. // Returns empty string if not in an LXC container or CTID cannot be determined. func DetectLXCCTID() string { diff --git a/internal/unifiedresources/monitored_system_projection.go b/internal/unifiedresources/monitored_system_projection.go index 9fa5359cf..e3238f6a6 100644 --- a/internal/unifiedresources/monitored_system_projection.go +++ b/internal/unifiedresources/monitored_system_projection.go @@ -139,17 +139,6 @@ func ProjectMonitoredSystemRecords( return projectMonitoredSystemResources(rs, nil, recordsBySource, nil) } -// ProjectMonitoredSystemRecordsReplacement projects source-native records while -// replacing one existing source-owned surface in the canonical top-level -// resolver. -func ProjectMonitoredSystemRecordsReplacement( - rs ReadState, - replacement MonitoredSystemReplacement, - recordsBySource map[DataSource][]IngestRecord, -) MonitoredSystemProjection { - return projectMonitoredSystemResources(rs, nil, recordsBySource, &replacement) -} - func projectMonitoredSystemResources( rs ReadState, additionalResources []Resource, @@ -324,21 +313,6 @@ func previewProjectedMonitoredSystems( return monitoredSystemRecordsForGroupIDs(projectedResolver, groupIDs) } -func monitoredSystemRecordForGroupID(resolver TopLevelSystemResolver, groupID string) *MonitoredSystemRecord { - groupID = strings.TrimSpace(groupID) - if groupID == "" { - return nil - } - for _, group := range resolver.groups { - if group.id != groupID { - continue - } - record := monitoredSystemRecordForResolvedGroup(group) - return &record - } - return nil -} - func monitoredSystemRecordsForGroupIDs( resolver TopLevelSystemResolver, groupIDs map[string]struct{}, @@ -387,14 +361,6 @@ func (r TopLevelSystemResolver) groupForResourceID(resourceID string) *topLevelS return nil } -func monitoredSystemGroupResourceIDs(resources []*Resource, excludeID string) map[string]struct{} { - excluded := make(map[string]struct{}) - if excludeID = strings.TrimSpace(excludeID); excludeID != "" { - excluded[excludeID] = struct{}{} - } - return monitoredSystemGroupResourceIDsExcluding(resources, excluded) -} - func monitoredSystemGroupResourceIDsExcluding( resources []*Resource, excluded map[string]struct{}, diff --git a/internal/unifiedresources/monitored_systems.go b/internal/unifiedresources/monitored_systems.go index d06f3cbda..e785407dc 100644 --- a/internal/unifiedresources/monitored_systems.go +++ b/internal/unifiedresources/monitored_systems.go @@ -152,19 +152,6 @@ type monitoredSystemGroup struct { explanation MonitoredSystemGroupingExplanation } -func monitoredSystemGroups(rs ReadState) []monitoredSystemGroup { - resolver := resolveMonitoredSystemTopLevelSystems(rs) - groups := make([]monitoredSystemGroup, 0, len(resolver.groups)) - for _, group := range resolver.groups { - groups = append(groups, monitoredSystemGroup{ - keys: cloneStringSet(group.strongIDs), - resources: group.resources, - explanation: group.explanation, - }) - } - return groups -} - func monitoredSystemRoots(rs ReadState) []*Resource { if rs == nil { return nil @@ -932,10 +919,6 @@ func monitoredSystemSurfaceStatusReasonSummary( return summary + "." } -func monitoredSystemLastSeen(resources []*Resource) time.Time { - return monitoredSystemLatestObservation(resources).LastSeen -} - func monitoredSystemSource(resources []*Resource) string { sources := make(map[string]struct{}) for _, resource := range resources { diff --git a/internal/unifiedresources/top_level_systems.go b/internal/unifiedresources/top_level_systems.go index 2422b6885..0a9c17cf6 100644 --- a/internal/unifiedresources/top_level_systems.go +++ b/internal/unifiedresources/top_level_systems.go @@ -214,34 +214,6 @@ func (r TopLevelSystemResolver) records() []MonitoredSystemRecord { return records } -func (r TopLevelSystemResolver) HasMatchingCandidate(candidate MonitoredSystemCandidate) bool { - resource := monitoredSystemCandidateResource(candidate) - if resource == nil { - return false - } - if !monitoredSystemCandidateAllowsHostAttachment(candidate) && - len(monitoredSystemCandidateStrongIDs(candidate)) == 0 { - return false - } - - resources := r.resources() - resources = append(resources, *resource) - return ResolveTopLevelSystems(resources).Count() == r.Count() -} - -func (r TopLevelSystemResolver) resources() []Resource { - resources := make([]Resource, 0, len(r.resourceToGroup)) - for _, group := range r.groups { - for _, resource := range group.resources { - if resource == nil { - continue - } - resources = append(resources, cloneResource(resource)) - } - } - return resources -} - func buildTopLevelSystemResolvedGroups( nodes []topLevelSystemNode, parent []int, @@ -538,105 +510,6 @@ func uniqueBetterTopLevelSystemTarget( return topLevelSystemFallbackTarget{}, false } -func candidateExactTargetGroups( - candidate MonitoredSystemCandidate, - hostOwners map[string]map[string]struct{}, - ipOwners map[string]map[string]struct{}, - groups map[string]topLevelSystemResolvedGroup, - priority int, -) map[string]struct{} { - targets := make(map[string]struct{}) - groupIDs := make(map[string]struct{}, len(groups)) - for groupID := range groups { - groupIDs[groupID] = struct{}{} - } - for host := range monitoredSystemCandidateExactHosts(candidate) { - for groupID := range hostOwners[host] { - if groups[groupID].priority >= priority { - continue - } - targets[groupID] = struct{}{} - } - } - candidateHosts := monitoredSystemCandidateExactHosts(candidate) - for _, groupID := range topLevelSystemSortedSet(groupIDs) { - if groups[groupID].priority >= priority { - continue - } - if _, ok := targets[groupID]; ok { - continue - } - if _, ok := topLevelSystemShortFormHostMatchValue(candidateHosts, groups[groupID].exactHosts); ok { - targets[groupID] = struct{}{} - } - } - for ip := range monitoredSystemCandidateExactIPs(candidate) { - for groupID := range ipOwners[ip] { - if groups[groupID].priority >= priority { - continue - } - targets[groupID] = struct{}{} - } - } - return targets -} - -func monitoredSystemCandidateStrongIDs(candidate MonitoredSystemCandidate) map[string]struct{} { - ids := make(map[string]struct{}) - if resourceID := strings.TrimSpace(candidate.ResourceID); resourceID != "" { - ids["resource:"+resourceID] = struct{}{} - } - if machineID := strings.TrimSpace(candidate.MachineID); machineID != "" { - ids["machine:"+machineID] = struct{}{} - } - if candidate.Type != ResourceTypeK8sCluster { - if agentID := strings.TrimSpace(candidate.AgentID); agentID != "" { - ids["agent:"+agentID] = struct{}{} - } - } - return ids -} - -func monitoredSystemCandidateExactHosts(candidate MonitoredSystemCandidate) map[string]struct{} { - hosts := make(map[string]struct{}) - for _, value := range []string{candidate.Hostname, extractHostname(candidate.HostURL)} { - if normalized := topLevelSystemNormalizeHost(value); normalized != "" { - hosts[normalized] = struct{}{} - } - } - return hosts -} - -func monitoredSystemCandidateExactIPs(candidate MonitoredSystemCandidate) map[string]struct{} { - ips := make(map[string]struct{}) - for _, value := range []string{candidate.Hostname, extractHostname(candidate.HostURL)} { - if normalized := NormalizeIP(value); normalized != "" && !isNonUniqueIP(normalized) { - ips[normalized] = struct{}{} - } - } - return ips -} - -func monitoredSystemCandidatePriority(candidate MonitoredSystemCandidate) int { - switch candidate.Type { - case ResourceTypePBS: - return 10 - case ResourceTypePMG: - return 11 - case ResourceTypeK8sCluster: - return 12 - default: - return 3 - } -} - -func monitoredSystemCandidateAllowsHostAttachment(candidate MonitoredSystemCandidate) bool { - if candidate.Type == ResourceTypeK8sCluster { - return false - } - return len(monitoredSystemCandidateExactHosts(candidate)) > 0 || len(monitoredSystemCandidateExactIPs(candidate)) > 0 -} - func monitoredSystemResourceAllowsHostAttachment(resource *Resource) bool { if resource == nil || CanonicalResourceType(resource.Type) == ResourceTypeK8sCluster { return false @@ -1020,30 +893,6 @@ func topLevelSystemSortedSet(values map[string]struct{}) []string { return out } -func topLevelSystemSetsOverlap(left, right map[string]struct{}) bool { - if len(left) == 0 || len(right) == 0 { - return false - } - if len(left) > len(right) { - left, right = right, left - } - for value := range left { - if _, ok := right[value]; ok { - return true - } - } - return false -} - -func addTopLevelSystemOwner(index map[string]map[string]struct{}, key, owner string) { - bucket := index[key] - if bucket == nil { - bucket = make(map[string]struct{}) - index[key] = bucket - } - bucket[owner] = struct{}{} -} - func topLevelSystemNormalizeHost(value string) string { return normalizeComparableHostname(value) } diff --git a/internal/unifiedresources/views_test.go b/internal/unifiedresources/views_test.go index 04483bd22..ff2255868 100644 --- a/internal/unifiedresources/views_test.go +++ b/internal/unifiedresources/views_test.go @@ -11,8 +11,6 @@ import ( func ptrInt64(v int64) *int64 { return &v } -func ptrFloat64(v float64) *float64 { return &v } - func assertStringSlice(t *testing.T, got, want []string) { t.Helper() if len(got) != len(want) { diff --git a/internal/updates/sse.go b/internal/updates/sse.go index 1104e24ec..bd7a20bbe 100644 --- a/internal/updates/sse.go +++ b/internal/updates/sse.go @@ -356,10 +356,6 @@ func (b *SSEBroadcaster) sendHeartbeatToClient(c *SSEClient) { c.LastActive = time.Now() } -func (b *SSEBroadcaster) isClosed() bool { - return b.closed.Load() -} - func closeDone(ch chan bool) { select { case <-ch: diff --git a/internal/utils/buffer.go b/internal/utils/buffer.go index 2a39a4c3f..0772f60bc 100644 --- a/internal/utils/buffer.go +++ b/internal/utils/buffer.go @@ -46,13 +46,6 @@ func (q *Queue[T]) Push(item T) { q.data = append(q.data, item) } -func normalizeCapacity(capacity int) int { - if capacity < minCapacity { - return minCapacity - } - return capacity -} - // Pop removes and returns the oldest item from the queue. // Returns zero value and false if empty. func (q *Queue[T]) Pop() (T, bool) { @@ -108,10 +101,3 @@ func (q *Queue[T]) Items() []T { copy(cp, q.data) return cp } - -func sanitizeCapacity(capacity int) int { - if capacity < minQueueCapacity { - return minQueueCapacity - } - return capacity -} diff --git a/internal/vmware/client.go b/internal/vmware/client.go index 39a237df6..fe13ee3f1 100644 --- a/internal/vmware/client.go +++ b/internal/vmware/client.go @@ -215,11 +215,6 @@ func (c *Client) CollectInventory(ctx context.Context) (*InventorySnapshot, erro return inventory, nil } -func (c *Client) collectInventoryBase(ctx context.Context) (*InventorySnapshot, error) { - snapshot, _, err := c.collectInventoryBaseWithSession(ctx) - return snapshot, err -} - func (c *Client) collectInventoryBaseWithSession(ctx context.Context) (*InventorySnapshot, string, error) { automationSessionID, err := c.createAutomationSession(ctx) if err != nil { diff --git a/internal/vmware/provider.go b/internal/vmware/provider.go index a7a4d28ec..c13d1b6b4 100644 --- a/internal/vmware/provider.go +++ b/internal/vmware/provider.go @@ -430,11 +430,6 @@ func NewProvider(snapshot InventorySnapshot) *Provider { return provider } -// NewDefaultProvider returns a provider loaded with the default VMware fixtures. -func NewDefaultProvider() *Provider { - return NewProvider(DefaultFixtures()) -} - // Refresh fetches and caches the latest snapshot. func (p *Provider) Refresh(ctx context.Context) error { if p == nil { diff --git a/internal/websocket/hub_tenant_test.go b/internal/websocket/hub_tenant_test.go index c7201ed90..8493a8298 100644 --- a/internal/websocket/hub_tenant_test.go +++ b/internal/websocket/hub_tenant_test.go @@ -12,10 +12,6 @@ type MockStateGetter struct { state interface{} } -func (m *MockStateGetter) GetState() interface{} { - return m.state -} - // MockTenantStateGetter implements TenantStateGetter interface type MockTenantStateGetter struct { state map[string]interface{} diff --git a/pkg/licensing/activation_test_helpers_test.go b/pkg/licensing/activation_test_helpers_test.go index a790f98a1..1c8ee7430 100644 --- a/pkg/licensing/activation_test_helpers_test.go +++ b/pkg/licensing/activation_test_helpers_test.go @@ -52,13 +52,6 @@ func makeTestGrantJWT(t *testing.T, gc *GrantClaims) string { return signTestJWT(t, payload, testPrivateKey) } -// makeTestJWT creates a properly signed test JWT with the given raw payload. -func makeTestJWT(t *testing.T, payload string) string { - t.Helper() - testKeyPairInit() - return signTestJWT(t, []byte(payload), testPrivateKey) -} - // makeUnsignedTestGrantJWT creates an unsigned test JWT (placeholder signature). // Use only for tests that specifically exercise parseGrantJWTUnsafe. func makeUnsignedTestGrantJWT(t *testing.T, gc *GrantClaims) string { diff --git a/pkg/licensing/activation_types.go b/pkg/licensing/activation_types.go index 2026e08e6..45d17ae24 100644 --- a/pkg/licensing/activation_types.go +++ b/pkg/licensing/activation_types.go @@ -43,10 +43,6 @@ func normalizeActivationContinuity(continuity ActivationContinuity) ActivationCo return continuity } -func (c ActivationContinuity) needsLegacyMonitoredSystemCapture() bool { - return false -} - func grantClaimsUseUncappedCoreMonitoring(gc *GrantClaims) bool { if gc == nil { return false diff --git a/pkg/licensing/dev_mode_features.go b/pkg/licensing/dev_mode_features.go index b5799c3d1..b23ed2ac4 100644 --- a/pkg/licensing/dev_mode_features.go +++ b/pkg/licensing/dev_mode_features.go @@ -2,22 +2,9 @@ package licensing import ( "os" - "sort" "strings" ) -func devModeFeatures() []string { - known := allKnownFeatures() - filtered := make([]string, 0, len(known)) - for _, feature := range known { - if devModeFeatureEnabled(feature) { - filtered = append(filtered, feature) - } - } - sort.Strings(filtered) - return filtered -} - func devModeFeatureEnabled(feature string) bool { switch feature { case FeatureMultiUser, FeatureWhiteLabel, FeatureUnlimited: diff --git a/pkg/licensing/monitored_system_limit.go b/pkg/licensing/monitored_system_limit.go index 6f61eed7e..7be709122 100644 --- a/pkg/licensing/monitored_system_limit.go +++ b/pkg/licensing/monitored_system_limit.go @@ -22,18 +22,6 @@ func InstalledUnifiedAgentCount(state models.StateSnapshot) int { return len(state.Hosts) } -func CanonicalizeMonitoredSystemLimitKey(key string) string { - normalized := strings.TrimSpace(key) - switch normalized { - case "", MaxMonitoredSystemsLicenseGateKey: - return MaxMonitoredSystemsLicenseGateKey - } - if canonical, ok := canonicalizeLegacyV5MonitoredSystemLimitKey(normalized); ok { - return canonical - } - return normalized -} - func NormalizeMonitoredSystemLimits(limits map[string]int64) map[string]int64 { if limits == nil { return nil diff --git a/pkg/licensing/persistence.go b/pkg/licensing/persistence.go index e52b7cf55..3ef3d3dca 100644 --- a/pkg/licensing/persistence.go +++ b/pkg/licensing/persistence.go @@ -421,11 +421,6 @@ func (p *Persistence) encrypt(plaintext []byte) ([]byte, error) { return ciphertext, nil } -// decrypt uses AES-GCM to decrypt data with the current encryption key. -func (p *Persistence) decrypt(ciphertext []byte) ([]byte, error) { - return p.decryptWithKey(ciphertext, p.deriveKey()) -} - // decryptWithKey uses AES-GCM to decrypt data with a specific key. func (p *Persistence) decryptWithKey(ciphertext []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) diff --git a/pkg/licensing/self_hosted_feature_catalog.go b/pkg/licensing/self_hosted_feature_catalog.go index 4993ab7bf..56f178dcc 100644 --- a/pkg/licensing/self_hosted_feature_catalog.go +++ b/pkg/licensing/self_hosted_feature_catalog.go @@ -354,26 +354,6 @@ func IsCompatibilityOnlyFeature(feature string) bool { entry.SelfHostedRoles.Pro == SelfHostedFeatureRoleCompatibilityOnly } -func SelfHostedComparisonFeatures() []FeatureMetadata { - out := make([]FeatureMetadata, 0) - for _, entry := range AllFeatureMetadata() { - if entry.ShowInComparisonTable { - out = append(out, entry) - } - } - return out -} - -func SelfHostedPlanFeaturesForRole(tier Tier, role SelfHostedFeatureRole) []FeatureMetadata { - out := make([]FeatureMetadata, 0) - for _, entry := range AllFeatureMetadata() { - if GetSelfHostedFeatureRole(entry.Key, tier) == role { - out = append(out, entry) - } - } - return out -} - func GenericUpgradeFeatureMetadata() []FeatureMetadata { out := make([]FeatureMetadata, 0) for _, entry := range AllFeatureMetadata() { diff --git a/pkg/licensing/upgrade.go b/pkg/licensing/upgrade.go index 48dd461bf..6faf609b2 100644 --- a/pkg/licensing/upgrade.go +++ b/pkg/licensing/upgrade.go @@ -40,11 +40,6 @@ func ResolvePulseAccountPortalURL(override string) string { return DefaultPulseAccountPortalURL } -// ProTrialSignupURL returns the default legacy hosted commercial base URL. -func ProTrialSignupURL() string { - return DefaultProTrialSignupURL -} - func validateExternalUpgradeURLOverride(raw string) (string, bool) { raw = strings.TrimSpace(raw) if raw == "" { diff --git a/pkg/pulsecli/deps.go b/pkg/pulsecli/deps.go index 7d7f0f1cc..513c999a7 100644 --- a/pkg/pulsecli/deps.go +++ b/pkg/pulsecli/deps.go @@ -124,10 +124,6 @@ func (env *Env) CommandDeps(process ProcessIO, mockFS MockFS) CommandDeps { } } -func (env *Env) ResetFlags() { - ResetFlags(env.ConfigDeps(ProcessIO{})) -} - func NewConfigDeps(exportFile, importFile, passphrase *string, forceImport *bool, readPassword func(int) ([]byte, error)) *ConfigDeps { return &ConfigDeps{ ExportFile: exportFile,