fix: restart Dever releases at 0.0.1 with complete signed assets
This commit is contained in:
1 parent
5589b657db
commit
faf8b168a7
22 files changed
+582
-94
No files matched your search
@@ -120,6 +120,7 @@ impl Environment {
|
||||
for (path, (bytes, executable)) in &self.files {
|
||||
stage.write(&format!("input/{path}"), bytes, *executable)?;
|
||||
}
|
||||
stage.link_tool_libraries(&self.files)?;
|
||||
for (path, bytes) in &self.assets {
|
||||
stage.write(
|
||||
&format!("process-runtime/{path}"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! One lifecycle for every managed compiler and package build hook.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
@@ -13,6 +14,10 @@ const MAX_OUTPUT: u64 = 16 * 1024 * 1024;
|
||||
static NEXT_STAGE: AtomicU64 = AtomicU64::new(0);
|
||||
mod budget;
|
||||
|
||||
#[cfg(all(test, unix))]
|
||||
#[path = "../../../../../test/dever-cli-tests/build_tool_libraries.rs"]
|
||||
mod tests;
|
||||
|
||||
pub(crate) struct Stage(pub(crate) PathBuf);
|
||||
|
||||
impl Stage {
|
||||
@@ -68,6 +73,55 @@ impl Stage {
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub(crate) fn link_tool_libraries(
|
||||
&self,
|
||||
files: &BTreeMap<String, (Vec<u8>, bool)>,
|
||||
) -> Result<(), String> {
|
||||
for (path, (bytes, _)) in files {
|
||||
if !path.starts_with("rootfs/usr/lib/") || !bytes.starts_with(b"\x7fELF") {
|
||||
continue;
|
||||
}
|
||||
let library = goblin::elf::Elf::parse(bytes)
|
||||
.map_err(|error| format!("invalid build library: {error}"))?;
|
||||
let Some(name) = library.soname else {
|
||||
continue;
|
||||
};
|
||||
crate::workers::valid_path(name)?;
|
||||
if name.contains('/') {
|
||||
return Err("build library SONAME must be a filename".into());
|
||||
}
|
||||
if matches!(
|
||||
name,
|
||||
"libc.so.6"
|
||||
| "libm.so.6"
|
||||
| "libmvec.so.1"
|
||||
| "libanl.so.1"
|
||||
| "libdl.so.2"
|
||||
| "libpthread.so.0"
|
||||
| "librt.so.1"
|
||||
| "libutil.so.1"
|
||||
| "libresolv.so.2"
|
||||
| "ld-linux-x86-64.so.2"
|
||||
| "ld-linux-aarch64.so.1"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
let directory = self.0.join("input/lib");
|
||||
fs::create_dir_all(&directory).map_err(|error| error.to_string())?;
|
||||
let destination = directory.join(name);
|
||||
match fs::hard_link(self.0.join("input").join(path), &destination) {
|
||||
Ok(()) => {}
|
||||
Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {
|
||||
if fs::read(&destination).map_err(|error| error.to_string())? != *bytes {
|
||||
return Err("build libraries contain conflicting SONAMEs".into());
|
||||
}
|
||||
}
|
||||
Err(error) => return Err(format!("cannot link signed build library: {error}")),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn run(
|
||||
&self,
|
||||
command: Command,
|
||||
|
||||
@@ -400,6 +400,7 @@ impl Environment {
|
||||
for (path, (bytes, executable)) in &self.files {
|
||||
stage.write(&format!("input/{path}"), bytes, *executable)?;
|
||||
}
|
||||
stage.link_tool_libraries(&self.files)?;
|
||||
for (path, bytes) in &self.assets {
|
||||
stage.write(
|
||||
&format!("process-runtime/{path}"),
|
||||
|
||||
@@ -90,7 +90,7 @@ pub fn install(installer_root: &Path) -> Result<Version, String> {
|
||||
// The private copy is checked again by the version owner before any health
|
||||
// command executes. A writable download cannot race signed bytes into it.
|
||||
let manifest = MachineManager::verify_package(&package, None, &key)?;
|
||||
validate_payload(&package, &manifest.artifacts, true, false)?;
|
||||
validate_payload(&package, &manifest.artifacts, true)?;
|
||||
pin_key(&layout, &key)?;
|
||||
let manager = MachineManager::new(layout.clone());
|
||||
if manager
|
||||
@@ -134,7 +134,6 @@ pub(crate) fn validate_payload(
|
||||
root: &Path,
|
||||
artifacts: &[Artifact],
|
||||
current_template: bool,
|
||||
previous_layout: bool,
|
||||
) -> Result<(), String> {
|
||||
let scoped = artifacts
|
||||
.iter()
|
||||
@@ -149,20 +148,10 @@ pub(crate) fn validate_payload(
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
validate_files(
|
||||
&root.join("bootstrap"),
|
||||
&scoped,
|
||||
current_template,
|
||||
previous_layout,
|
||||
)
|
||||
validate_files(&root.join("bootstrap"), &scoped, current_template)
|
||||
}
|
||||
|
||||
fn validate_files(
|
||||
root: &Path,
|
||||
artifacts: &[Artifact],
|
||||
new_payload: bool,
|
||||
previous_layout: bool,
|
||||
) -> Result<(), String> {
|
||||
fn validate_files(root: &Path, artifacts: &[Artifact], new_payload: bool) -> Result<(), String> {
|
||||
let bytes = artifacts
|
||||
.iter()
|
||||
.try_fold(0u64, |total, artifact| total.checked_add(artifact.bytes))
|
||||
@@ -174,8 +163,7 @@ fn validate_files(
|
||||
let supported = matches!(
|
||||
artifact.path.as_str(),
|
||||
"dever" | "deverd" | "deverd.service"
|
||||
) || artifact.path.starts_with("lib/")
|
||||
|| previous_layout && !new_payload && artifact.path == "dever-sandbox";
|
||||
) || artifact.path.starts_with("lib/");
|
||||
if !supported {
|
||||
return Err("bootstrap has an unsupported artifact".into());
|
||||
}
|
||||
@@ -240,7 +228,7 @@ fn validate_bin(root: &Path, key: &[u8]) -> Result<Vec<u8>, String> {
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
validate_files(root, &artifacts, false, manifest.uses_sandbox_layout())?;
|
||||
validate_files(root, &artifacts, false)?;
|
||||
let expected = artifacts
|
||||
.iter()
|
||||
.map(|artifact| artifact.path.as_str())
|
||||
|
||||
@@ -55,7 +55,7 @@ impl ExtensionId {
|
||||
format!("ext-{}.tar.zst", self.name())
|
||||
}
|
||||
|
||||
fn permits(&self, path: &str, process_root: &str) -> bool {
|
||||
fn permits(&self, path: &str) -> bool {
|
||||
let target = self.target.platform();
|
||||
match &self.kind {
|
||||
ExtensionKind::Runtime(ecosystem) => {
|
||||
@@ -66,7 +66,7 @@ impl ExtensionId {
|
||||
}
|
||||
ExtensionKind::Target => {
|
||||
path.starts_with(&format!("runtime/{target}/"))
|
||||
|| path.starts_with(&format!("{process_root}/{target}/"))
|
||||
|| path.starts_with(&format!("process-runtime/{target}/"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,11 +113,6 @@ pub fn validate_catalog(manifest: &ReleaseManifest) -> Result<(), String> {
|
||||
}
|
||||
let mut paths = BTreeSet::new();
|
||||
validate_artifacts(&manifest.artifacts, &mut paths)?;
|
||||
let process_root = if manifest.uses_sandbox_layout() {
|
||||
"sandbox"
|
||||
} else {
|
||||
"process-runtime"
|
||||
};
|
||||
let mut ids = BTreeSet::new();
|
||||
for extension in &manifest.extensions {
|
||||
let id = extension.id();
|
||||
@@ -131,7 +126,7 @@ pub fn validate_catalog(manifest: &ReleaseManifest) -> Result<(), String> {
|
||||
if extension
|
||||
.artifacts
|
||||
.iter()
|
||||
.any(|artifact| !id.permits(&artifact.path, process_root))
|
||||
.any(|artifact| !id.permits(&artifact.path))
|
||||
{
|
||||
return Err(format!(
|
||||
"extension '{}' contains a file outside its resource namespace",
|
||||
|
||||
@@ -49,7 +49,7 @@ pub(super) fn assemble(
|
||||
bytes: bytes.len() as u64,
|
||||
sha256: format!("{:x}", Sha256::digest(bytes)),
|
||||
});
|
||||
crate::toolchain::bootstrap::validate_payload(writer.staging, &artifacts, true, false)?;
|
||||
crate::toolchain::bootstrap::validate_payload(writer.staging, &artifacts, true)?;
|
||||
}
|
||||
Ok(artifacts)
|
||||
}
|
||||
@@ -78,10 +78,6 @@ pub struct ReleaseManifest {
|
||||
}
|
||||
|
||||
impl ReleaseManifest {
|
||||
pub(super) fn uses_sandbox_layout(&self) -> bool {
|
||||
version_components(self.version.as_str()) < [0, 1, 5]
|
||||
}
|
||||
|
||||
pub fn new(version: Version, artifacts: Vec<Artifact>) -> Self {
|
||||
Self {
|
||||
format: "dever-release-v2".into(),
|
||||
@@ -707,12 +703,7 @@ impl MachineManager {
|
||||
{
|
||||
// Older installed versions retain their own signed service template.
|
||||
// Only the explicit bootstrap installer applies the current template.
|
||||
super::bootstrap::validate_payload(
|
||||
root,
|
||||
&manifest.artifacts,
|
||||
false,
|
||||
manifest.uses_sandbox_layout(),
|
||||
)?;
|
||||
super::bootstrap::validate_payload(root, &manifest.artifacts, false)?;
|
||||
}
|
||||
Ok(manifest)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user