blob: fbc9eecb7fae01544469222e31b05be67a874558 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use assembly_file_relative_path::{FileRelativePathBuf, SupportsFileRelativePaths};
use assembly_package_utils::{PackageInternalPathBuf, PackageManifestPathBuf};
use camino::{Utf8Path, Utf8PathBuf};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::common::DriverDetails;
/// The Product-provided configuration details.
#[derive(Debug, Deserialize, Serialize, JsonSchema, SupportsFileRelativePaths)]
#[serde(deny_unknown_fields)]
pub struct ProductConfig {
#[serde(default)]
#[file_relative_paths]
pub packages: ProductPackagesConfig,
/// List of base drivers to include in the product.
#[serde(default)]
pub base_drivers: Vec<DriverDetails>,
/// Start URL to pass to `session_manager`.
///
/// Default to the empty string which creates a "paused" config that launches nothing to start.
#[serde(default)]
pub session_url: String,
/// Generic product information.
#[serde(default)]
pub info: Option<ProductInfoConfig>,
/// The file paths to various build information.
#[file_relative_paths]
pub build_info: Option<BuildInfoConfig>,
/// The policy given to component_manager that restricts where sensitive capabilities can be
/// routed.
#[serde(default)]
#[file_relative_paths]
pub component_policy: ComponentPolicyConfig,
/// Components which depend on trusted applications running in the TEE.
#[serde(default)]
pub trusted_apps: Vec<TrustedApp>,
}
/// Packages provided by the product, to add to the assembled images.
///
/// This also includes configuration for those packages:
///
/// ```json5
/// packages: {
/// base: [
/// {
/// manifest: "path/to/package_a/package_manifest.json",
/// },
/// {
/// manifest: "path/to/package_b/package_manifest.json",
/// config_data: {
/// "foo.cfg": "path/to/some/source/file/foo.cfg",
/// "bar/more/data.json": "path/to/some.json",
/// },
/// },
/// ],
/// cache: []
/// }
/// ```
///
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema, SupportsFileRelativePaths)]
#[serde(deny_unknown_fields)]
pub struct ProductPackagesConfig {
/// Paths to package manifests, or more detailed json entries for packages
/// to add to the 'base' package set.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
#[file_relative_paths]
pub base: Vec<ProductPackageDetails>,
/// Paths to package manifests, or more detailed json entries for packages
/// to add to the 'cache' package set.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
#[file_relative_paths]
pub cache: Vec<ProductPackageDetails>,
}
/// Describes in more detail a package to add to the assembly.
#[derive(Debug, PartialEq, Deserialize, Serialize, JsonSchema, SupportsFileRelativePaths)]
#[serde(deny_unknown_fields)]
pub struct ProductPackageDetails {
/// Path to the package manifest for this package.
pub manifest: FileRelativePathBuf,
/// Map of config_data entries for this package, from the destination path
/// within the package, to the path where the source file is to be found.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub config_data: Vec<ProductConfigData>,
}
impl From<PackageManifestPathBuf> for ProductPackageDetails {
fn from(manifest: PackageManifestPathBuf) -> Self {
let manifestpath: &Utf8Path = manifest.as_ref();
let path: Utf8PathBuf = manifestpath.into();
Self { manifest: FileRelativePathBuf::Resolved(path), config_data: Vec::default() }
}
}
impl From<&str> for ProductPackageDetails {
fn from(s: &str) -> Self {
ProductPackageDetails { manifest: s.into(), config_data: Vec::default() }
}
}
#[derive(Debug, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ProductConfigData {
/// Path to the config file on the host.
pub source: FileRelativePathBuf,
/// Path to find the file in the package on the target.
pub destination: PackageInternalPathBuf,
}
/// Configuration options for product info.
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ProductInfoConfig {
/// Name of the product.
pub name: String,
/// Model of the product.
pub model: String,
/// Manufacturer of the product.
pub manufacturer: String,
}
/// Configuration options for build info.
#[derive(
Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema, SupportsFileRelativePaths,
)]
#[serde(deny_unknown_fields)]
pub struct BuildInfoConfig {
/// Name of the product build target.
pub name: String,
/// Path to the version file.
pub version: FileRelativePathBuf,
/// Path to the jiri snapshot.
pub jiri_snapshot: FileRelativePathBuf,
/// Path to the latest commit date.
pub latest_commit_date: FileRelativePathBuf,
/// Path to the minimum UTC stamp.
pub minimum_utc_stamp: FileRelativePathBuf,
}
/// Configuration options for the component policy.
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, SupportsFileRelativePaths)]
#[serde(deny_unknown_fields)]
pub struct ComponentPolicyConfig {
/// The file paths to a product-provided component policies.
#[serde(default)]
#[file_relative_paths]
pub product_policies: Vec<FileRelativePathBuf>,
}
/// A configuration for a component which depends on TEE-based protocols.
/// Examples include components which implement DRM, or authentication services.
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct TrustedApp {
/// The URL of the component.
pub component_url: String,
/// GUIDs which of the form fuchsia.tee.Application.{GUID} will match a
/// protocol provided by the TEE.
pub guids: Vec<String>,
/// Capabilities provided by this component which should be routed to the
/// rest of the system.
pub capabilities: Vec<String>,
/// Additional protocols which are required for this component to work, and
/// which will be routed from 'parent'
#[serde(default)]
pub additional_required_protocols: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use assembly_util as util;
#[test]
fn test_product_provided_config_data() {
let json5 = r#"
{
base: [
{
manifest: "path/to/base/package_manifest.json"
},
{
manifest: "some/other/manifest.json",
config_data: [
{
destination: "dest/path/cfg.txt",
source: "source/path/cfg.txt",
},
{
destination: "other_data.json",
source: "source_other_data.json",
},
]
}
],
cache: [
{
manifest: "path/to/cache/package_manifest.json"
}
]
}
"#;
let mut cursor = std::io::Cursor::new(json5);
let packages: ProductPackagesConfig = util::from_reader(&mut cursor).unwrap();
assert_eq!(
packages.base,
vec![
ProductPackageDetails {
manifest: FileRelativePathBuf::FileRelative(
"path/to/base/package_manifest.json".into()
),
config_data: Vec::default()
},
ProductPackageDetails {
manifest: FileRelativePathBuf::FileRelative("some/other/manifest.json".into()),
config_data: vec![
ProductConfigData {
destination: "dest/path/cfg.txt".into(),
source: FileRelativePathBuf::FileRelative("source/path/cfg.txt".into()),
},
ProductConfigData {
destination: "other_data.json".into(),
source: FileRelativePathBuf::FileRelative(
"source_other_data.json".into()
),
},
]
}
]
);
assert_eq!(
packages.cache,
vec![ProductPackageDetails {
manifest: FileRelativePathBuf::FileRelative(
"path/to/cache/package_manifest.json".into()
),
config_data: Vec::default()
}]
);
}
#[test]
fn product_package_details_deserialization() {
let json5 = r#"
{
manifest: "some/other/manifest.json",
config_data: [
{
destination: "dest/path/cfg.txt",
source: "source/path/cfg.txt",
},
{
destination: "other_data.json",
source: "source_other_data.json",
},
]
}
"#;
let expected = ProductPackageDetails {
manifest: FileRelativePathBuf::FileRelative("some/other/manifest.json".into()),
config_data: vec![
ProductConfigData {
destination: "dest/path/cfg.txt".into(),
source: FileRelativePathBuf::FileRelative("source/path/cfg.txt".into()),
},
ProductConfigData {
destination: "other_data.json".into(),
source: FileRelativePathBuf::FileRelative("source_other_data.json".into()),
},
],
};
let mut cursor = std::io::Cursor::new(json5);
let details: ProductPackageDetails = util::from_reader(&mut cursor).unwrap();
assert_eq!(details, expected);
}
#[test]
fn product_package_details_serialization() {
let entries = vec![
ProductPackageDetails {
manifest: "path/to/manifest.json".into(),
config_data: Vec::default(),
},
ProductPackageDetails {
manifest: "another/path/to/a/manifest.json".into(),
config_data: vec![
ProductConfigData {
destination: "dest/path/A".into(),
source: "source/path/A".into(),
},
ProductConfigData {
destination: "dest/path/B".into(),
source: "source/path/B".into(),
},
],
},
];
let serialized = serde_json::to_value(entries).unwrap();
let expected = serde_json::json!(
[
{
"manifest": "path/to/manifest.json"
},
{
"manifest": "another/path/to/a/manifest.json",
"config_data": [
{
"destination": "dest/path/A",
"source": "source/path/A",
},
{
"destination": "dest/path/B",
"source": "source/path/B",
},
]
}
]
);
assert_eq!(serialized, expected);
}
}