Default profiles to persistent system paths
This commit is contained in:
parent
09dae24f52
commit
acd0b4cc8c
5 changed files with 36 additions and 3 deletions
|
|
@ -5,6 +5,7 @@ pub const STORAGE_CATALOG_SCHEMA_ID: &str = "lazaret-storage-catalog-v1";
|
||||||
pub const DOMAIN_STORE_SCHEMA_VERSION: u32 = 1;
|
pub const DOMAIN_STORE_SCHEMA_VERSION: u32 = 1;
|
||||||
pub const STORAGE_CATALOG_SCHEMA_VERSION: u32 = 1;
|
pub const STORAGE_CATALOG_SCHEMA_VERSION: u32 = 1;
|
||||||
pub const TRUSTED_HOST_CONFIGURATION_SCHEMA_ID: &str = "lazaret-trusted-host-config-v1";
|
pub const TRUSTED_HOST_CONFIGURATION_SCHEMA_ID: &str = "lazaret-trusted-host-config-v1";
|
||||||
|
pub const DEFAULT_PERSISTENT_DIRS: [&str; 5] = ["/root", "/usr", "/var", "/etc", "/opt"];
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
|
|
@ -74,7 +75,7 @@ pub struct ProfileConfigurationV1 {
|
||||||
pub image: String,
|
pub image: String,
|
||||||
#[serde(default = "default_isolate_gitignored")]
|
#[serde(default = "default_isolate_gitignored")]
|
||||||
pub isolate_gitignored: bool,
|
pub isolate_gitignored: bool,
|
||||||
#[serde(default)]
|
#[serde(default = "default_persistent_dirs")]
|
||||||
pub persistent_dirs: Vec<String>,
|
pub persistent_dirs: Vec<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub allow_egress: Vec<String>,
|
pub allow_egress: Vec<String>,
|
||||||
|
|
@ -92,6 +93,10 @@ const fn default_isolate_gitignored() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_persistent_dirs() -> Vec<String> {
|
||||||
|
DEFAULT_PERSISTENT_DIRS.map(str::to_owned).into()
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct TrustedHostConfigurationV1 {
|
pub struct TrustedHostConfigurationV1 {
|
||||||
#[serde(rename = "schema")]
|
#[serde(rename = "schema")]
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,10 @@ image = "example.invalid/agent:v1"
|
||||||
let parsed = parse_trusted_configuration(minimal.as_bytes()).unwrap();
|
let parsed = parse_trusted_configuration(minimal.as_bytes()).unwrap();
|
||||||
let profile = &parsed.profiles()["default"];
|
let profile = &parsed.profiles()["default"];
|
||||||
assert!(profile.isolate_gitignored);
|
assert!(profile.isolate_gitignored);
|
||||||
assert!(profile.persistent_dirs.is_empty());
|
assert_eq!(
|
||||||
|
profile.persistent_dirs,
|
||||||
|
["/root", "/usr", "/var", "/etc", "/opt"]
|
||||||
|
);
|
||||||
assert!(profile.allow_egress.is_empty());
|
assert!(profile.allow_egress.is_empty());
|
||||||
assert!(profile.deny_egress.is_empty());
|
assert!(profile.deny_egress.is_empty());
|
||||||
assert!(profile.env.is_empty());
|
assert!(profile.env.is_empty());
|
||||||
|
|
@ -148,6 +151,23 @@ image = "example.invalid/agent:v1"
|
||||||
assert!(parsed.network().default_allow.is_empty());
|
assert!(parsed.network().default_allow.is_empty());
|
||||||
assert!(parsed.network().default_deny.is_empty());
|
assert!(parsed.network().default_deny.is_empty());
|
||||||
|
|
||||||
|
for (value, expected) in [
|
||||||
|
("[]", Vec::<String>::new()),
|
||||||
|
("[\"/nix\"]", vec!["/nix".to_owned()]),
|
||||||
|
] {
|
||||||
|
let explicit = minimal.replace(
|
||||||
|
"image = \"example.invalid/agent:v1\"",
|
||||||
|
&format!("image = \"example.invalid/agent:v1\"\npersistent_dirs = {value}"),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
parse_trusted_configuration(explicit.as_bytes())
|
||||||
|
.unwrap()
|
||||||
|
.profiles()["default"]
|
||||||
|
.persistent_dirs,
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for invalid in [
|
for invalid in [
|
||||||
minimal.replace("schema", "unknown"),
|
minimal.replace("schema", "unknown"),
|
||||||
format!("{minimal}unknown = true\n"),
|
format!("{minimal}unknown = true\n"),
|
||||||
|
|
@ -271,6 +291,10 @@ fn repository_example_loads_with_ipv4_normalization_and_private_denies() {
|
||||||
let config = write_configuration(&tree, include_str!("../../../docs/example.toml"));
|
let config = write_configuration(&tree, include_str!("../../../docs/example.toml"));
|
||||||
let resolved = load_trusted_configuration(request(&tree, config, BTreeMap::new())).unwrap();
|
let resolved = load_trusted_configuration(request(&tree, config, BTreeMap::new())).unwrap();
|
||||||
assert_eq!(resolved.selected_profile(), "default");
|
assert_eq!(resolved.selected_profile(), "default");
|
||||||
|
assert_eq!(
|
||||||
|
resolved.fingerprint_record().persistent_dirs,
|
||||||
|
["/root", "/usr", "/var", "/etc", "/opt"]
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
resolved
|
resolved
|
||||||
.effective_allow_prefixes()
|
.effective_allow_prefixes()
|
||||||
|
|
|
||||||
|
|
@ -558,6 +558,7 @@ fn every_schema_shape_round_trips_and_rejects_malformed_or_unknown_versions() {
|
||||||
br#"schema = "lazaret-trusted-host-config-v1"
|
br#"schema = "lazaret-trusted-host-config-v1"
|
||||||
[profiles.trusted]
|
[profiles.trusted]
|
||||||
image = "example.invalid/agent:v1"
|
image = "example.invalid/agent:v1"
|
||||||
|
persistent_dirs = []
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ default_allow = ["192.0.2.53/32", "198.51.100.53/32"]
|
||||||
[profiles.default]
|
[profiles.default]
|
||||||
image = "docker.io/library/debian:trixie"
|
image = "docker.io/library/debian:trixie"
|
||||||
isolate_gitignored = true
|
isolate_gitignored = true
|
||||||
persistent_dirs = ["/root"]
|
|
||||||
allow_egress = ["203.0.113.10/32"]
|
allow_egress = ["203.0.113.10/32"]
|
||||||
volumes = [
|
volumes = [
|
||||||
{ host = "{profile_dir}/agent-state", container = "/root/.local/state/agent", kind = "directory", access = "read-write", create = true },
|
{ host = "{profile_dir}/agent-state", container = "/root/.local/state/agent", kind = "directory", access = "read-write", create = true },
|
||||||
|
|
|
||||||
|
|
@ -295,6 +295,10 @@ later product mounts, and a layout cannot be constructed without `/workspace`.
|
||||||
Bundle construction, rather than trusted-host configuration syntax, owns the
|
Bundle construction, rather than trusted-host configuration syntax, owns the
|
||||||
exact destination choices and transient-child classification.
|
exact destination choices and transient-child classification.
|
||||||
|
|
||||||
|
An omitted profile `persistent_dirs` field selects `/root`, `/usr`, `/var`,
|
||||||
|
`/etc`, and `/opt`. An explicit list replaces that default in full, including an
|
||||||
|
empty list or paths used by an unorthodox distribution.
|
||||||
|
|
||||||
The loader resolves environment references only after structural, path, and
|
The loader resolves environment references only after structural, path, and
|
||||||
network validation. A missing, non-UTF-8, or NUL-containing host value refuses
|
network validation. A missing, non-UTF-8, or NUL-containing host value refuses
|
||||||
the selected profile. Resolved values live only in one move-owned,
|
the selected profile. Resolved values live only in one move-owned,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue