diff --git a/libs/i18n/locales/en/translation.json b/libs/i18n/locales/en/translation.json index c5ecab72d..13780d66a 100644 --- a/libs/i18n/locales/en/translation.json +++ b/libs/i18n/locales/en/translation.json @@ -1089,6 +1089,8 @@ "Dependency sync probe failed": "Dependency sync probe failed", "Dependency change detected": "Dependency change detected", "Application lifecycle changed": "Application lifecycle changed", + "Preparing delta updates": "Preparing delta updates", + "Delta updates generation complete": "Delta updates generation complete", "Resource": "Resource", "Edit fleet": "Edit fleet", "Create fleet": "Create fleet", @@ -1850,8 +1852,8 @@ "Find by name": "Find by name", "Vulnerabilities table": "Vulnerabilities table", "Show more": "Show more", - "Published: {{ date }}": "Published: {{ date }}", "Scanner name": "Scanner name", + "Published: {{ date }}": "Published: {{ date }}", "<0>{deviceCount} devices in this fleet are running images affected by this vulnerability. Update or replace the affected images to remediate._one": "<0>{deviceCount} device in this fleet is running images affected by this vulnerability. Update or replace the affected images to remediate.", "<0>{deviceCount} devices in this fleet are running images affected by this vulnerability. Update or replace the affected images to remediate._other": "<0>{deviceCount} devices in this fleet are running images affected by this vulnerability. Update or replace the affected images to remediate.", "<0>{deviceCount} devices are running images affected by this vulnerability. Update or replace the affected images to remediate._one": "<0>{deviceCount} device is running an image affected by this vulnerability. Update or replace the affected image to remediate.", diff --git a/libs/types/alpha/models/Vulnerability.ts b/libs/types/alpha/models/Vulnerability.ts index 736cd5fa2..480fbbd0e 100644 --- a/libs/types/alpha/models/Vulnerability.ts +++ b/libs/types/alpha/models/Vulnerability.ts @@ -4,7 +4,7 @@ /* eslint-disable */ import type { ApiVersion } from './ApiVersion'; /** - * A single vulnerability (CVE) finding. Vulnerabilities are global CVE records from Trustify; they are not tenant-owned resources. Tenancy is determined by the device or fleet context through which they are queried. + * A single vulnerability (CVE) finding. Vulnerabilities are global CVE records produced by the configured vulnerability scanner; they are not tenant-owned resources. Tenancy is determined by the device or fleet context through which they are queried. */ export type Vulnerability = { apiVersion: ApiVersion; @@ -44,6 +44,10 @@ export type Vulnerability = { * Advisory publish time when known. */ publishedAt?: string; + /** + * The vulnerability backend that produced this finding. + */ + source?: Vulnerability.source; /** * Image reference (name or URL) from the device context. */ @@ -69,5 +73,12 @@ export namespace Vulnerability { NONE = 'None', UNKNOWN = 'Unknown', } + /** + * The vulnerability backend that produced this finding. + */ + export enum source { + Trustify = 'trustify', + Quay = 'quay', + } } diff --git a/libs/types/imagebuilder/models/ImageBuildSpec.ts b/libs/types/imagebuilder/models/ImageBuildSpec.ts index 00faf0c0f..e34d62ec2 100644 --- a/libs/types/imagebuilder/models/ImageBuildSpec.ts +++ b/libs/types/imagebuilder/models/ImageBuildSpec.ts @@ -13,7 +13,10 @@ export type ImageBuildSpec = { source: ImageBuildSource; destination: ImageBuildDestination; binding: ImageBuildBinding; - onboarding?: boolean; userConfiguration?: ImageBuildUserConfiguration; + /** + * When true, installs the flightctl-onboarding RPM and enables flightctl-onboarding-setup.service for first-boot device configuration via a Cockpit-based onboarding wizard. Compatible with both early and late binding. Defaults to false. + */ + onboarding?: boolean; }; diff --git a/libs/types/index.ts b/libs/types/index.ts index 37264a0c9..da0ecaf39 100644 --- a/libs/types/index.ts +++ b/libs/types/index.ts @@ -69,6 +69,7 @@ export type { DeviceConfigStatus } from './models/DeviceConfigStatus'; export type { DeviceConsole } from './models/DeviceConsole'; export type { DeviceDecommission } from './models/DeviceDecommission'; export { DeviceDecommissionTargetType } from './models/DeviceDecommissionTargetType'; +export type { DeviceDeltaApplyStatus } from './models/DeviceDeltaApplyStatus'; export type { DeviceIntegrityCheckStatus } from './models/DeviceIntegrityCheckStatus'; export { DeviceIntegrityCheckStatusType } from './models/DeviceIntegrityCheckStatusType'; export type { DeviceIntegrityStatus } from './models/DeviceIntegrityStatus'; @@ -182,6 +183,7 @@ export type { PatchRequest } from './models/PatchRequest'; export type { Percentage } from './models/Percentage'; export type { Permission } from './models/Permission'; export type { PermissionList } from './models/PermissionList'; +export type { PrepareDeltasDetails } from './models/PrepareDeltasDetails'; export type { QuadletApplication } from './models/QuadletApplication'; export type { ReferencedRepositoryUpdatedDetails } from './models/ReferencedRepositoryUpdatedDetails'; export type { RelativePath } from './models/RelativePath'; diff --git a/libs/types/models/DeviceApplicationStatus.ts b/libs/types/models/DeviceApplicationStatus.ts index c2b5f5ffb..7b78df73e 100644 --- a/libs/types/models/DeviceApplicationStatus.ts +++ b/libs/types/models/DeviceApplicationStatus.ts @@ -5,6 +5,7 @@ import type { ApplicationStatusType } from './ApplicationStatusType'; import type { ApplicationVolumeStatus } from './ApplicationVolumeStatus'; import type { AppType } from './AppType'; +import type { DeviceDeltaApplyStatus } from './DeviceDeltaApplyStatus'; export type DeviceApplicationStatus = { /** * Human readable name of the application. @@ -32,5 +33,6 @@ export type DeviceApplicationStatus = { * Status of volumes used by this application. */ volumes?: Array; + lastDelta?: DeviceDeltaApplyStatus; }; diff --git a/libs/types/models/DeviceDeltaApplyStatus.ts b/libs/types/models/DeviceDeltaApplyStatus.ts new file mode 100644 index 000000000..235423cb3 --- /dev/null +++ b/libs/types/models/DeviceDeltaApplyStatus.ts @@ -0,0 +1,18 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/** + * Result of the most recent delta apply attempt for this update target. + */ +export type DeviceDeltaApplyStatus = { + /** + * Set when the most recent update attempt fell back from a delta to a full image pull. Absent if no delta was attempted or the delta succeeded. Cleared when the next update attempt for this target starts. + */ + fallbackReason?: string; + /** + * Expected delta size in IEC units (KiB, MiB, GiB, or TiB). Absent when the size is not yet known. + */ + size?: string; +}; + diff --git a/libs/types/models/DeviceLifecycleHookType.ts b/libs/types/models/DeviceLifecycleHookType.ts index 0ac142c18..a6578d3a6 100644 --- a/libs/types/models/DeviceLifecycleHookType.ts +++ b/libs/types/models/DeviceLifecycleHookType.ts @@ -7,4 +7,6 @@ export enum DeviceLifecycleHookType { DeviceLifecycleHookAfterUpdating = 'AfterUpdating', DeviceLifecycleHookBeforeRebooting = 'BeforeRebooting', DeviceLifecycleHookAfterRebooting = 'AfterRebooting', + DeviceLifecycleHookBeforeEnrolling = 'BeforeEnrolling', + DeviceLifecycleHookAfterEnrolling = 'AfterEnrolling', } diff --git a/libs/types/models/DeviceOsSpec.ts b/libs/types/models/DeviceOsSpec.ts index 03154a633..4d3da1ace 100644 --- a/libs/types/models/DeviceOsSpec.ts +++ b/libs/types/models/DeviceOsSpec.ts @@ -3,4 +3,13 @@ /* tslint:disable */ /* eslint-disable */ import type { ImageOrCatalogItemRefSpec } from './ImageOrCatalogItemRefSpec'; -export type DeviceOsSpec = ImageOrCatalogItemRefSpec; +/** + * Either a specific OCI image reference, or a reference to a catalog item version that can be resolved to an OCI image ref. + */ +export type DeviceOsSpec = (ImageOrCatalogItemRefSpec & { + /** + * Optional hint: a reference to a delta artifact the control plane's generation records indicate may be applicable to reach `image` from this device's current image. Absent does not imply no delta exists — the device independently discovers candidate delta artifacts (e.g. deltas published by a customer's own CI) regardless of this field, and falls back to a full pull only if none is usable. + */ + deltaImage?: string; +}); + diff --git a/libs/types/models/DeviceOsStatus.ts b/libs/types/models/DeviceOsStatus.ts index 1b1f74442..b65222aab 100644 --- a/libs/types/models/DeviceOsStatus.ts +++ b/libs/types/models/DeviceOsStatus.ts @@ -2,6 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { DeviceDeltaApplyStatus } from './DeviceDeltaApplyStatus'; /** * Current status of the device OS. */ @@ -14,5 +15,6 @@ export type DeviceOsStatus = { * The digest of the OS image (e.g. sha256:a0...). */ imageDigest: string; + lastDelta?: DeviceDeltaApplyStatus; }; diff --git a/libs/types/models/Event.ts b/libs/types/models/Event.ts index 217c6322c..d55842e4b 100644 --- a/libs/types/models/Event.ts +++ b/libs/types/models/Event.ts @@ -108,6 +108,8 @@ export namespace Event { ENCRYPTION_MIGRATION_STARTED = 'EncryptionMigrationStarted', ENCRYPTION_MIGRATION_COMPLETED = 'EncryptionMigrationCompleted', APPLICATION_LIFECYCLE_CHANGED = 'ApplicationLifecycleChanged', + PREPARE_DELTAS = 'PrepareDeltas', + DELTA_GENERATION_COMPLETED = 'DeltaGenerationCompleted', } /** * The type of the event. One of Normal, Warning. diff --git a/libs/types/models/EventDetails.ts b/libs/types/models/EventDetails.ts index a59dd6b02..12f1b8349 100644 --- a/libs/types/models/EventDetails.ts +++ b/libs/types/models/EventDetails.ts @@ -17,11 +17,12 @@ import type { FleetRolloutFailedDetails } from './FleetRolloutFailedDetails'; import type { FleetRolloutStartedDetails } from './FleetRolloutStartedDetails'; import type { InternalTaskFailedDetails } from './InternalTaskFailedDetails'; import type { InternalTaskPermanentlyFailedDetails } from './InternalTaskPermanentlyFailedDetails'; +import type { PrepareDeltasDetails } from './PrepareDeltasDetails'; import type { ReferencedRepositoryUpdatedDetails } from './ReferencedRepositoryUpdatedDetails'; import type { ResourceSyncCompletedDetails } from './ResourceSyncCompletedDetails'; import type { ResourceUpdatedDetails } from './ResourceUpdatedDetails'; /** * Event-specific details, structured based on event type. */ -export type EventDetails = (ResourceUpdatedDetails | DeviceOwnershipChangedDetails | DeviceMultipleOwnersDetectedDetails | DeviceMultipleOwnersResolvedDetails | InternalTaskFailedDetails | InternalTaskPermanentlyFailedDetails | ResourceSyncCompletedDetails | ReferencedRepositoryUpdatedDetails | FleetRolloutStartedDetails | FleetRolloutFailedDetails | FleetRolloutCompletedDetails | FleetRolloutBatchDispatchedDetails | FleetRolloutBatchCompletedDetails | FleetRolloutDeviceSelectedDetails | DeviceVulnerabilityCveDetails | DependencyChangeDetectedDetails | DependencySyncProbeFailedDetails | ApplicationLifecycleChangedDetails); +export type EventDetails = (ResourceUpdatedDetails | DeviceOwnershipChangedDetails | DeviceMultipleOwnersDetectedDetails | DeviceMultipleOwnersResolvedDetails | InternalTaskFailedDetails | InternalTaskPermanentlyFailedDetails | ResourceSyncCompletedDetails | ReferencedRepositoryUpdatedDetails | FleetRolloutStartedDetails | FleetRolloutFailedDetails | FleetRolloutCompletedDetails | FleetRolloutBatchDispatchedDetails | FleetRolloutBatchCompletedDetails | FleetRolloutDeviceSelectedDetails | DeviceVulnerabilityCveDetails | DependencyChangeDetectedDetails | DependencySyncProbeFailedDetails | ApplicationLifecycleChangedDetails | PrepareDeltasDetails); diff --git a/libs/types/models/OciRepoSpec.ts b/libs/types/models/OciRepoSpec.ts index 346c0023f..44e208356 100644 --- a/libs/types/models/OciRepoSpec.ts +++ b/libs/types/models/OciRepoSpec.ts @@ -33,6 +33,18 @@ export type OciRepoSpec = { * Skip remote server verification. */ skipServerVerification?: boolean; + /** + * Optional OCI repository path under spec.registry (e.g. my-org/diffs). When set, this object is that repo (`my-registry.com/my-org/diffs`), not only a registry. Mutually exclusive with namespace. ImageBuild destination imageName must equal this value. + */ + repository?: string; + /** + * Optional org/subpath under spec.registry (e.g. my-org). Concrete names are spec.registry/namespace/. Mutually exclusive with repository. Used by delta push (`{registry}/{namespace}/{imageName}`). Invalid on an ImageBuild or ImageExport destination Repository. + */ + namespace?: string; + /** + * When true, generated deltas are pushed to this object (at most one per org). Auth is the existing ociAuth / accessMode. Placement follows repository / namespace / registry-only as above. + */ + deltaStorageTarget?: boolean; /** * Curated list of trusted base images available in this registry. When present, the Image Builder source picker surfaces these entries as selectable options. */ diff --git a/libs/types/models/PrepareDeltasDetails.ts b/libs/types/models/PrepareDeltasDetails.ts new file mode 100644 index 000000000..2329ef2e9 --- /dev/null +++ b/libs/types/models/PrepareDeltasDetails.ts @@ -0,0 +1,18 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +/** + * Structured details for PrepareDeltas events. + */ +export type PrepareDeltasDetails = { + /** + * The type of detail for discriminator purposes. + */ + detailType: 'PrepareDeltas'; + /** + * Fleet only. The TemplateVersion this prepare is for. Required when involvedObject.kind is Fleet; omitted for Device. + */ + templateVersion?: string; +}; + diff --git a/libs/ui-components/src/components/Events/useEvents.ts b/libs/ui-components/src/components/Events/useEvents.ts index d42457f18..117e3c115 100644 --- a/libs/ui-components/src/components/Events/useEvents.ts +++ b/libs/ui-components/src/components/Events/useEvents.ts @@ -120,6 +120,9 @@ const getEventReasonTitles = (t: TFunction, kindType: string): Record { + const { t } = useTranslation(); + const { settings } = useAppContext(); + + const source = getVulnerabilitySource(vulnerability, settings.isRHEM ?? false); + return ( + + {t('Scanner name')} + {source} + + ); +}; + const VulnerabilityDetailsDrawer = ({ vulnerability, isSingleDevice, @@ -86,7 +105,7 @@ const VulnerabilityDetailsDrawer = ({ )} - + {t('Severity')} @@ -97,10 +116,8 @@ const VulnerabilityDetailsDrawer = ({ )} - - {t('Scanner name')} - Trustify - + {/* API does not return the source for grouped vulnerabilities */} + {!isGrouped && } diff --git a/libs/ui-components/src/components/Status/VulnerabilitySeverityStatus.tsx b/libs/ui-components/src/components/Status/VulnerabilitySeverityStatus.tsx index 5f23ca1ce..581f851c7 100644 --- a/libs/ui-components/src/components/Status/VulnerabilitySeverityStatus.tsx +++ b/libs/ui-components/src/components/Status/VulnerabilitySeverityStatus.tsx @@ -63,7 +63,7 @@ export const VulnerabilitySeverityDetails = ({ severity, cvssScore }: Vulnerabil const { t } = useTranslation(); return ( - + diff --git a/libs/ui-components/src/utils/vulnerabilities.ts b/libs/ui-components/src/utils/vulnerabilities.ts index 6b527273a..15ce628d9 100644 --- a/libs/ui-components/src/utils/vulnerabilities.ts +++ b/libs/ui-components/src/utils/vulnerabilities.ts @@ -51,6 +51,25 @@ export const getPrimaryVulnerabilityGroupFinding = ( return findingsWithLink.find((finding) => isRedHatIssuer(finding.issuer)) || findingsWithLink[0] || findings[0]; }; +const DEFAULT_VULNERABILITY_SOURCE_US = 'Trustify'; +const DEFAULT_VULNERABILITY_SOURCE_DS = 'Red Hat Trusted Profile Analyzer'; +const QUAY_VULNERABILITY_SOURCE = 'Quay'; + +export const getVulnerabilitySource = (vulnerability: Vulnerability, isRHEM: boolean) => { + switch (vulnerability.source) { + case Vulnerability.source.Trustify: + return isRHEM ? DEFAULT_VULNERABILITY_SOURCE_DS : DEFAULT_VULNERABILITY_SOURCE_US; + case Vulnerability.source.Quay: + return QUAY_VULNERABILITY_SOURCE; + case undefined: + // Source is missing, fallback to the default backend. + return DEFAULT_VULNERABILITY_SOURCE_US; + default: + // Source is unknown to the UI, return it as is. + return vulnerability.source; + } +}; + export const getSeverityCountValue = (severity: Severity, counts: CveCountsBySeverity) => { switch (severity) { case Vulnerability.severity.CRITICAL: