fleet/frontend/interfaces/config.ts
Gabriel Hernandez 1785bcb5cb add UI for adding and removing multiple microsoft entra tenant ids (#39910)
**Related issue:** Resolves #39266

> NOTE: activities is in another PR
[here](https://github.com/fleetdm/fleet/pull/39919)

# Checklist for submitter


This adds/updates the UI to enable users to add multiple Microsoft Entra
tenant ids. This also updates the mdm page microsoft entra section.

**New Microsoft Entra card states on mdm page:**

<img width="757" height="107" alt="image"
src="https://github.com/user-attachments/assets/b1c58268-ed75-4055-8192-d74cc7be67f6"
/>

<img width="770" height="131" alt="image"
src="https://github.com/user-attachments/assets/149e08a2-acfc-4f3f-948f-bffce5a27f8a"
/>

<img width="768" height="110" alt="image"
src="https://github.com/user-attachments/assets/74d7bc58-dd64-496e-a36a-44de44aa6b0b"
/>


**New Microsoft Entra page to add/remove multiple tenant ids:**

<img width="792" height="713" alt="image"
src="https://github.com/user-attachments/assets/c34baab8-19ad-4d28-87ea-51955e28f428"
/>

**new add and delete tenant id modals**

<img width="664" height="319" alt="image"
src="https://github.com/user-attachments/assets/d3ccc177-a780-4ec4-a2c0-747edad40ae1"
/>

<img width="664" height="267" alt="image"
src="https://github.com/user-attachments/assets/c08b7992-c440-4c57-9d4e-4b20ae0f5cf2"
/>

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
2026-02-27 12:34:31 -06:00

318 lines
8.5 KiB
TypeScript

/* Config interface is a flattened version of the fleet/config API response */
import {
IWebhookHostStatus,
IWebhookFailingPolicies,
IWebhookSoftwareVulnerabilities,
IWebhookActivities,
} from "interfaces/webhook";
import { IGlobalIntegrations } from "./integration";
export interface ILicense {
tier: string;
device_count: number;
expiration: string;
note: string;
organization: string;
// Whether the Fleet instance is managed by FleetDM
managed_cloud: boolean;
allow_disable_telemetry: boolean;
}
export interface IEndUserAuthentication {
entity_id: string;
idp_name: string;
issuer_uri: string;
metadata: string;
metadata_url: string;
}
export interface IMacOsMigrationSettings {
enable: boolean;
mode: "voluntary" | "forced" | "";
webhook_url: string;
}
interface ICustomSetting {
path: string;
labels_include_all?: string[];
labels_exclude_any?: string[];
}
export interface IAppleDeviceUpdates {
minimum_version: string;
deadline: string;
update_new_hosts?: boolean;
}
export interface IMdmConfig {
/** Update this URL if you're self-hosting Fleet and you want your hosts to talk to a different URL for MDM features. (If not configured, hosts will use the base URL of the Fleet instance.) */
apple_server_url: string;
enable_disk_encryption: boolean;
windows_require_bitlocker_pin: boolean;
/** `enabled_and_configured` only tells us if Apples MDM has been enabled and
configured correctly. The naming is slightly confusing but at one point we
only supported apple mdm, so thats why it's name the way it is. */
enabled_and_configured: boolean;
apple_bm_default_team?: string;
/**
* @deprecated
* Refer to needsAbmTermsRenewal from AppContext instead of config.apple_bm_terms_expired.
* https://github.com/fleetdm/fleet/pull/21043/files#r1705977965
*/
apple_bm_terms_expired: boolean;
apple_bm_enabled_and_configured: boolean;
windows_enabled_and_configured: boolean;
enable_turn_on_windows_mdm_manually: boolean;
windows_migration_enabled: boolean;
android_enabled_and_configured: boolean;
end_user_authentication: IEndUserAuthentication;
macos_updates: IAppleDeviceUpdates;
ios_updates: IAppleDeviceUpdates;
ipados_updates: IAppleDeviceUpdates;
macos_settings: {
custom_settings: null | ICustomSetting[];
enable_disk_encryption: boolean;
};
macos_setup: {
bootstrap_package: string | null;
enable_end_user_authentication: boolean;
macos_setup_assistant: string | null;
enable_release_device_manually: boolean | null;
manual_agent_install: boolean | null;
require_all_software_macos: boolean | null;
};
macos_migration: IMacOsMigrationSettings;
windows_updates: {
deadline_days: number | null;
grace_period_days: number | null;
};
windows_entra_tenant_ids: string[] | null;
}
// Note: IDeviceGlobalConfig is misnamed on the backend because in some cases it returns team config
// values if the device is assigned to a team, e.g., features.enable_software_inventory reflects the
// team config, if applicable, rather than the global config.
export interface IDeviceGlobalConfig {
mdm: {
enabled_and_configured: boolean;
require_all_software_macos: boolean | null;
};
features: Pick<
IConfigFeatures,
| "enable_software_inventory"
| "enable_conditional_access"
| "enable_conditional_access_bypass"
>;
}
export interface IFleetDesktopSettings {
transparency_url: string;
alternative_browser_host: string;
}
export interface IConfigFeatures {
enable_host_users: boolean;
enable_software_inventory: boolean;
enable_conditional_access: boolean;
enable_conditional_access_bypass: boolean;
}
export interface IConfigServerSettings {
server_url: string;
live_query_disabled: boolean;
enable_analytics: boolean;
deferred_save_host: boolean;
query_reports_disabled: boolean;
scripts_disabled: boolean;
ai_features_disabled: boolean;
}
export interface IConfig {
org_info: {
org_name: string;
org_logo_url: string;
org_logo_url_light_background: string;
contact_url: string;
};
sandbox_enabled: boolean;
server_settings: IConfigServerSettings;
smtp_settings?: {
enable_smtp: boolean;
configured?: boolean;
sender_address: string;
server: string;
port?: number;
authentication_type: string;
user_name: string;
password: string;
enable_ssl_tls: boolean;
authentication_method: string;
domain: string;
verify_ssl_certs: boolean;
enable_start_tls: boolean;
};
sso_settings?: {
entity_id: string;
issuer_uri: string;
idp_image_url: string;
metadata: string;
metadata_url: string;
idp_name: string;
enable_sso: boolean;
enable_sso_idp_login: boolean;
enable_jit_provisioning: boolean;
enable_jit_role_sync: boolean;
sso_server_url?: string;
};
// configuration details for conditional access. For enabled/disabled status per team, see
// subfields under `integrations`
conditional_access?: {
// Microsoft Entra
microsoft_entra_tenant_id: string;
microsoft_entra_connection_configured: boolean;
// Okta
okta_idp_id: string;
okta_assertion_consumer_service_url: string;
okta_audience_uri: string;
okta_certificate: string;
// Bypass setting
bypass_disabled?: boolean;
};
host_expiry_settings: {
host_expiry_enabled: boolean;
host_expiry_window?: number;
};
activity_expiry_settings: {
activity_expiry_enabled: boolean;
activity_expiry_window?: number;
};
features: IConfigFeatures;
agent_options: unknown; // Can pass empty object
update_interval: {
osquery_detail: number;
osquery_policy: number;
};
license: ILicense;
fleet_desktop: IFleetDesktopSettings;
vulnerabilities: {
databases_path: string;
periodicity: number;
cpe_database_url: string;
cve_feed_prefix_url: string;
current_instance_checks: string;
disable_data_sync: boolean;
recent_vulnerability_max_age: number;
};
webhook_settings: IWebhookSettings;
integrations: IGlobalIntegrations;
logging: ILoggingConfig;
email?: {
backend: string;
config: {
region: string;
source_arn: string;
};
};
mdm: IMdmConfig;
gitops: IGitOpsModeConfig;
partnerships?: IFleetPartnerships;
}
interface IFleetPartnerships {
enable_primo: boolean;
}
export interface IWebhookSettings {
failing_policies_webhook: IWebhookFailingPolicies;
host_status_webhook: IWebhookHostStatus | null;
vulnerabilities_webhook: IWebhookSoftwareVulnerabilities;
activities_webhook: IWebhookActivities;
}
export type IAutomationsConfig = Pick<
IConfig,
"webhook_settings" | "integrations"
>;
export type LogDestination =
| "filesystem"
| "firehose"
| "kinesis"
| "lambda"
| "pubsub"
| "kafka"
| "nats"
| "stdout"
| "webhook"
| "";
export interface ILoggingConfig {
debug: boolean;
json: boolean;
result: {
plugin: LogDestination;
config?: {
status_log_file: string;
result_log_file: string;
enable_log_rotation: boolean;
enable_log_compression: boolean;
status_url?: string;
result_url?: string;
};
};
status?: {
plugin: string;
config: {
status_log_file: string;
result_log_file: string;
enable_log_rotation: boolean;
enable_log_compression: boolean;
};
};
audit?: {
plugin: string;
config: any;
};
}
export const CONFIG_DEFAULT_RECENT_VULNERABILITY_MAX_AGE_IN_DAYS = 30;
export interface IUserSettings {
hidden_host_columns: string[];
}
export interface IGitOpsModeConfig {
gitops_mode_enabled: boolean;
repository_url: string;
}
/** Check if Okta conditional access is configured (all 4 fields must be present) */
export const isOktaConditionalAccessConfigured = (
config: IConfig | null | undefined
): boolean => {
const ca = config?.conditional_access;
return !!(
ca?.okta_idp_id &&
ca?.okta_assertion_consumer_service_url &&
ca?.okta_audience_uri &&
ca?.okta_certificate
);
};
/** Check if Microsoft Entra conditional access is configured */
export const isEntraConditionalAccessConfigured = (
config: IConfig | null | undefined
): boolean => {
return (
config?.conditional_access?.microsoft_entra_connection_configured ?? false
);
};
/** Check if any conditional access provider is configured (Okta or Entra) */
export const isConditionalAccessConfigured = (
config: IConfig | null | undefined
): boolean => {
return (
isOktaConditionalAccessConfigured(config) ||
isEntraConditionalAccessConfigured(config)
);
};