Skip to content

Commit

Permalink
Encryption processes can request packages to install
Browse files Browse the repository at this point in the history
  • Loading branch information
ancorgs committed Oct 26, 2023
1 parent f438742 commit 3edb1c9
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 95 deletions.
6 changes: 4 additions & 2 deletions src/lib/y2partitioner/widgets/overview.rb
@@ -1,4 +1,4 @@
# Copyright (c) [2017-2022] SUSE LLC
# Copyright (c) [2017-2023] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -215,7 +215,9 @@ def valid_setup?
def packages_installed?
return true if Yast::Mode.installation

pkgs = device_graph.actiongraph.used_features.pkg_list
features = device_graph.actiongraph.used_features
features.concat(device_graph.yast_commit_features)
pkgs = features.pkg_list
Y2Storage::PackageHandler.new(pkgs).install
end

Expand Down
32 changes: 27 additions & 5 deletions src/lib/y2storage/devicegraph.rb
@@ -1,4 +1,4 @@
# Copyright (c) [2017-2021] SUSE LLC
# Copyright (c) [2017-2023] SUSE LLC
#
# All Rights Reserved.
#
Expand Down Expand Up @@ -594,12 +594,19 @@ def finish_installation

# List of storage features used by the devicegraph
#
# Note this is used during system installation. In the installed system, the
# combination of Actiongraph#used_features and Devicegraph#yast_commit_features
# is used instead.
#
# By default, it returns the features associated to all devices and filesystems
# in the devicegraph. The required_only argument can be used to limit the result
# by excluding features associated to those filesystems that have no mount point.
# by excluding features that are not mandatory to produce a functional system. For
# example, it excludes features associated to those filesystems that have no mount
# point.
#
# @param required_only [Boolean] whether the result should only include those
# features that are mandatory (ie. associated to devices with a mount point)
# features that are mandatory (ie. associated to devices with a mount point or
# to devices that will be configured during the first boot of the new system)
# @return [StorageFeaturesList]
def used_features(required_only: false)
type =
Expand All @@ -609,7 +616,9 @@ def used_features(required_only: false)
Storage::UsedFeaturesDependencyType_SUGGESTED
end

StorageFeaturesList.from_bitfield(storage_used_features(type))
list = StorageFeaturesList.from_bitfield(storage_used_features(type))
list.concat(yast_commit_features)
list
end

# List of required (mandatory) storage features used by the devicegraph
Expand All @@ -626,7 +635,20 @@ def optional_used_features
all = storage_used_features(Storage::UsedFeaturesDependencyType_SUGGESTED)
required = storage_used_features(Storage::UsedFeaturesDependencyType_REQUIRED)
# Using binary XOR in those bit fields to calculate the difference
StorageFeaturesList.from_bitfield(all ^ required)
list = StorageFeaturesList.from_bitfield(all ^ required)
list.concat(yast_commit_features)
list
end

# List of features that correspond to aspects handled by Y2Storage (not coming
# from libstorage-ng) and that need to be present in the target system either during
# the storage commit phase or at a later stage. Ie. features needed in the target
# system to access the device or to finish its configuration.
#
# @return [StorageFeaturesList]
def yast_commit_features
features = encryptions.flat_map(&:commit_features).uniq
StorageFeaturesList.new(features)
end

private
Expand Down
8 changes: 8 additions & 0 deletions src/lib/y2storage/encryption.rb
Expand Up @@ -362,6 +362,14 @@ def finish_installation
encryption_process&.finish_installation
end

# Features that must be supported in the target system to finish the encryption
# process
#
# @return [Array<YastFeature>]
def commit_features
encryption_process&.commit_features || []
end

# If the current mount_by is suitable, it does nothing.
#
# Otherwise, it assigns the best option from all the suitable ones
Expand Down
6 changes: 2 additions & 4 deletions src/lib/y2storage/encryption_method/tpm_fde.rb
Expand Up @@ -20,6 +20,7 @@

require "yast"
require "y2storage/encryption_method/base"
require "y2storage/yast_feature"
require "y2storage/encryption_processes/tpm_fde_tools"

Yast.import "Mode"
Expand Down Expand Up @@ -97,16 +98,13 @@ def tpm_present?
@tpm_present = EncryptionProcesses::FdeTools.new.tpm_present?
end

NEEDED_PACKAGES = ["fde-tools"].freeze
private_constant :NEEDED_PACKAGES

def tpm_product?
# FIXME: Can we detect when to invalidate this memoization (new packages available due
# to some change in selected product or to new repositories)?
return @tpm_product unless @tpm_product.nil?

# Beware: apart from true and false, AvailableAll can return nil if things go wrong
@tpm_product = Yast::Package.AvailableAll(NEEDED_PACKAGES.pkg_list)
@tpm_product = Yast::Package.AvailableAll(YastFeature::ENCRYPTION_TPM_FDE.pkg_list)
end
end
end
Expand Down
12 changes: 11 additions & 1 deletion src/lib/y2storage/encryption_processes/base.rb
@@ -1,4 +1,4 @@
# Copyright (c) [2019] SUSE LLC
# Copyright (c) [2019-2023] SUSE LLC
#
# All Rights Reserved.
#
Expand All @@ -18,6 +18,7 @@
# find current contact information at www.suse.com.

require "yast"
require "y2storage/yast_feature"

require "abstract_method"

Expand Down Expand Up @@ -93,6 +94,15 @@ def crypt_options(_blk_device)
[]
end

# Features objects to describe the requirements to perform the commit phase
# and any subsequent operation (eg., initialization during the first boot) of
# the encryption procedure
#
# @return [Array<YastFeature>]
def commit_features
[]
end

private

# Open options with the format expected by the underlying tools (cryptsetup)
Expand Down
4 changes: 3 additions & 1 deletion src/lib/y2storage/encryption_processes/pervasive.rb
@@ -1,4 +1,4 @@
# Copyright (c) [2019-2020] SUSE LLC
# Copyright (c) [2019-2023] SUSE LLC
#
# All Rights Reserved.
#
Expand All @@ -23,6 +23,8 @@
require "yast2/execute"
require "yast"

Yast.import "Mode"

module Y2Storage
module EncryptionProcesses
# Encryption process that allows to create and identify a volume encrypted
Expand Down
7 changes: 7 additions & 0 deletions src/lib/y2storage/encryption_processes/tpm_fde_tools.rb
Expand Up @@ -95,6 +95,13 @@ def finish_installation
self.class.devices = []
end

# @see Base#commit_features
def commit_features
# In installation mode is needed to ensure the enroll service is present in the new system.
# In an installed system is needed in order to be able to execute the fdectl commands.
[YastFeature::ENCRYPTION_TPM_FDE]
end

private

def configure_fde_tools(devices)
Expand Down
123 changes: 123 additions & 0 deletions src/lib/y2storage/feature.rb
@@ -0,0 +1,123 @@
# Copyright (c) [2023] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"
require "storage"

module Y2Storage
# Generalization of the concept of {StorageFeature}.
#
# In libstorage-ng the concept of "feature" is used to communicate the usage of some
# functionality that may require the presence in the system of some packages and tools.
#
# The sibling concept of {YastFeature} makes it possible for Y2Storage to add its own
# requirements.
#
# This is the abstract base class for both.
class Feature
include Yast::Logger

# Constructor
#
# @param id [Symbol] see {#id}
# @param packages [Array<Package>] see {#all_packages}
def initialize(id, packages)
@id = id
@all_packages = packages
end

# Symbol representation of the feature
#
# For StorageFeature objects, this has the same form than the corresponding constant
# name in libstorage-ng, eg. :UF_NTFS
#
# @return [Symbol]
attr_reader :id

alias_method :to_sym, :id

# Names of the packages that should be installed if the feature is going to be used
#
# @return [Array<String>]
def pkg_list
packages.map(&:name)
end

# Drop the cache about which packages related to the feature are available
def drop_cache
@packages = nil
end

private

# All packages that would be relevant for the feature, no matter if they are really available
# @return [Array<Feature::Package>]
attr_reader :all_packages

# List of available packages associated to the feature
#
# @return [Array<Feature::Package>]
def packages
return @packages unless @packages.nil?

unavailable, @packages = all_packages.partition(&:unavailable_optional?)
if unavailable.any?
log.warn("WARNING: Skipping unavailable support packages #{unavailable.map(&:name)}")
end

@packages
end

# Internal class to represent a package associated to a feature
class Package
Yast.import "Package"

# Constructor
#
# @param name [String] see {#name}
# @param optional [Boolean] see {#optional?}
def initialize(name, optional: false)
@name = name
@optional = optional
end

# @return [String] name of the package
attr_reader :name

# Whether installation of the package can be skipped if the package is not
# available
#
# See the comment in {StorageFeature::OPTIONAL_PACKAGES} for more details
#
# @return [Boolean]
def optional?
!!@optional
end

# Check if a package is an optional package that is unavailable.
# See also bsc#1039830
#
# @return [Boolean] true if package is optional and unavailable,
# false if not optional or if available.
def unavailable_optional?
optional? && !Yast::Package.Available(name)
end
end
end
end

0 comments on commit 3edb1c9

Please sign in to comment.