fix(runner): load sealed CommonJS entrypoints by descriptor
This commit is contained in:
parent
7c85257f66
commit
325e1e813d
|
|
@ -213,7 +213,8 @@ impl AcpxProviderDescriptor {
|
|||
let verified_args = launch_profile
|
||||
.args
|
||||
.iter()
|
||||
.map(|argument| {
|
||||
.enumerate()
|
||||
.map(|(index, argument)| {
|
||||
let path = Path::new(argument);
|
||||
if !path.is_absolute() {
|
||||
return Ok(VerifiedProcessArgument::Literal(argument.clone()));
|
||||
|
|
@ -221,7 +222,13 @@ impl AcpxProviderDescriptor {
|
|||
verified
|
||||
.get(path)
|
||||
.cloned()
|
||||
.map(VerifiedProcessArgument::Artifact)
|
||||
.map(|artifact| {
|
||||
if index == 0 {
|
||||
VerifiedProcessArgument::CommonJsArtifact(artifact)
|
||||
} else {
|
||||
VerifiedProcessArgument::Artifact(artifact)
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
DurableRunnerError::invalid(
|
||||
"ACPX runner launch profile does not authenticate an absolute argument",
|
||||
|
|
@ -1419,7 +1426,7 @@ mod tests {
|
|||
let verified_launch = transport.verified_launch.as_ref().unwrap();
|
||||
assert!(matches!(
|
||||
verified_launch.arguments().first(),
|
||||
Some(VerifiedProcessArgument::Artifact(_))
|
||||
Some(VerifiedProcessArgument::CommonJsArtifact(_))
|
||||
));
|
||||
|
||||
let mut drifted_path = descriptor.clone();
|
||||
|
|
|
|||
|
|
@ -1995,7 +1995,7 @@ fn verified_opencode_launch(
|
|||
let executable = verify_launch_artifact(&profile.executable, "OpenCode provider executable")
|
||||
.map_err(|error| LocalRunnerError::invalid(error.to_string()))?;
|
||||
let args = vec![
|
||||
VerifiedProcessArgument::Artifact(proxy),
|
||||
VerifiedProcessArgument::CommonJsArtifact(proxy),
|
||||
VerifiedProcessArgument::Literal(TRUSTED_OPENCODE_EXECUTABLE_ARG.to_owned()),
|
||||
VerifiedProcessArgument::ExecutableArtifact(executable),
|
||||
];
|
||||
|
|
@ -2746,7 +2746,7 @@ mod tests {
|
|||
let launch = verified_opencode_launch(&profile).unwrap();
|
||||
assert!(matches!(
|
||||
launch.arguments().first(),
|
||||
Some(VerifiedProcessArgument::Artifact(_))
|
||||
Some(VerifiedProcessArgument::CommonJsArtifact(_))
|
||||
));
|
||||
assert!(matches!(
|
||||
launch.arguments().get(1),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ use sha2::{Digest, Sha256};
|
|||
use crate::local_runner::LocalRunnerError;
|
||||
|
||||
const PROCESS_OUTPUT_QUEUE_CAPACITY: usize = 256;
|
||||
const VERIFIED_COMMONJS_ARTIFACT_LOADER: &str = r#"const fs=require("node:fs");const Module=require("node:module");const filename=process.argv[1];const source=fs.readFileSync(filename,"utf8").replace(/^#![^\r\n]*(?:\r?\n|$)/,"");const artifact=new Module(filename);artifact.filename=filename;artifact.paths=[];artifact._compile(source,filename);"#;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VerifiedProcessArtifact {
|
||||
|
|
@ -185,6 +186,7 @@ fn snapshot_error(display_path: &Path, error: impl std::fmt::Display) -> LocalRu
|
|||
pub enum VerifiedProcessArgument {
|
||||
Literal(String),
|
||||
Artifact(VerifiedProcessArtifact),
|
||||
CommonJsArtifact(VerifiedProcessArtifact),
|
||||
ExecutableArtifact(VerifiedProcessArtifact),
|
||||
}
|
||||
|
||||
|
|
@ -226,6 +228,13 @@ impl VerifiedProcessLaunch {
|
|||
inherited.push(fd);
|
||||
args.push(path.to_string_lossy().into_owned());
|
||||
}
|
||||
VerifiedProcessArgument::CommonJsArtifact(artifact) => {
|
||||
let (fd, path) = inherited_artifact(artifact)?;
|
||||
inherited.push(fd);
|
||||
args.push("--eval".to_owned());
|
||||
args.push(VERIFIED_COMMONJS_ARTIFACT_LOADER.to_owned());
|
||||
args.push(path.to_string_lossy().into_owned());
|
||||
}
|
||||
VerifiedProcessArgument::ExecutableArtifact(artifact) => {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
|
|
@ -858,3 +867,49 @@ fn exit_fact(status: ExitStatus) -> ProcessExitFact {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(target_os = "linux", target_os = "macos")))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
fn verified_artifact(path: &Path, bytes: &[u8]) -> VerifiedProcessArtifact {
|
||||
fs::write(path, bytes).unwrap();
|
||||
let digest = format!("sha256:{:x}", Sha256::digest(bytes));
|
||||
VerifiedProcessArtifact::snapshot_verified(
|
||||
path.to_owned(),
|
||||
File::open(path).unwrap(),
|
||||
&digest,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commonjs_artifacts_use_the_bounded_descriptor_loader() {
|
||||
let nonce = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos();
|
||||
let directory = std::env::temp_dir().join(format!(
|
||||
"paperclip-commonjs-launch-{}-{nonce}",
|
||||
std::process::id()
|
||||
));
|
||||
fs::create_dir_all(&directory).unwrap();
|
||||
let program = verified_artifact(&directory.join("node"), b"node");
|
||||
let script = verified_artifact(&directory.join("sidecar.cjs"), b"module.exports = {};\n");
|
||||
let launch = VerifiedProcessLaunch::new(
|
||||
program,
|
||||
vec![VerifiedProcessArgument::CommonJsArtifact(script)],
|
||||
);
|
||||
|
||||
let inherited = launch.inherited_command().unwrap();
|
||||
|
||||
assert_eq!(inherited.args[0], "--eval");
|
||||
assert_eq!(inherited.args[1], VERIFIED_COMMONJS_ARTIFACT_LOADER);
|
||||
#[cfg(target_os = "linux")]
|
||||
assert!(inherited.args[2].starts_with("/proc/self/fd/"));
|
||||
#[cfg(target_os = "macos")]
|
||||
assert!(inherited.args[2].starts_with("/dev/fd/"));
|
||||
fs::remove_dir_all(directory).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue