-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add subprocess for sandboxed lockfile generation (#1306)
Before this patch lockfile generation would always happen in the CLI's process, which inevitably applied the sandbox to the process itself making the execution environment after generation severely limited. To allow for the CLI and extensions to use sandboxed lockfile generation without having to spawn a separate process, the generation itself is now always executed in a separate process if sandboxing is requested. Closes #1296.
- Loading branch information
Showing
8 changed files
with
165 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
//! `phylum generate-lockfile` subcommand. | ||
use std::path::{Path, PathBuf}; | ||
|
||
use anyhow::{Context, Result}; | ||
use birdcage::{Birdcage, Exception, Sandbox}; | ||
use clap::ArgMatches; | ||
use phylum_lockfile::LockfileFormat; | ||
|
||
use crate::commands::extensions::permissions; | ||
use crate::commands::{CommandResult, ExitCode}; | ||
use crate::dirs; | ||
|
||
/// Handle `phylum generate-lockfile` subcommand. | ||
pub fn handle_command(matches: &ArgMatches) -> CommandResult { | ||
let lockfile_type = matches.get_one::<String>("lockfile-type").unwrap(); | ||
let manifest = matches.get_raw("manifest").unwrap().next().unwrap(); | ||
let manifest_path = PathBuf::from(manifest); | ||
|
||
// Get generator for the lockfile type. | ||
let lockfile_format = lockfile_type.parse::<LockfileFormat>().unwrap(); | ||
let generator = lockfile_format.parser().generator().unwrap(); | ||
|
||
// Setup sandbox for lockfile generation. | ||
let birdcage = lockfile_generation_sandbox(&manifest_path)?; | ||
birdcage.lock()?; | ||
|
||
// Generate the lockfile. | ||
let generated_lockfile = generator | ||
.generate_lockfile(&manifest_path) | ||
.context("lockfile generation subcommand failed")?; | ||
|
||
// Write lockfile to stdout. | ||
println!("{}", generated_lockfile); | ||
|
||
Ok(ExitCode::Ok) | ||
} | ||
|
||
/// Create sandbox with exceptions allowing generation of any lockfile. | ||
fn lockfile_generation_sandbox(canonical_manifest_path: &Path) -> Result<Birdcage> { | ||
let mut birdcage = permissions::default_sandbox()?; | ||
|
||
// Allow all networking. | ||
birdcage.add_exception(Exception::Networking)?; | ||
|
||
// Add exception for the manifest's parent directory. | ||
let project_path = canonical_manifest_path.parent().expect("Invalid manifest path"); | ||
permissions::add_exception(&mut birdcage, Exception::WriteAndRead(project_path.into()))?; | ||
|
||
// Add exception for all the executables required for generation. | ||
let ecosystem_bins = [ | ||
"cargo", "bundle", "mvn", "gradle", "npm", "pnpm", "yarn", "python3", "pipenv", "poetry", | ||
"go", "dotnet", | ||
]; | ||
for bin in ecosystem_bins { | ||
let absolute_path = permissions::resolve_bin_path(bin); | ||
permissions::add_exception(&mut birdcage, Exception::ExecuteAndRead(absolute_path))?; | ||
} | ||
|
||
// Allow any executable in common binary directories. | ||
// | ||
// Reading binaries shouldn't be an attack vector, but significantly simplifies | ||
// complex ecosystems (like Python's symlinks). | ||
permissions::add_exception(&mut birdcage, Exception::ExecuteAndRead("/usr/bin".into()))?; | ||
permissions::add_exception(&mut birdcage, Exception::ExecuteAndRead("/bin".into()))?; | ||
|
||
// Add paths required by specific ecosystems. | ||
let home = dirs::home_dir()?; | ||
// Cargo. | ||
permissions::add_exception(&mut birdcage, Exception::ExecuteAndRead(home.join(".rustup")))?; | ||
permissions::add_exception(&mut birdcage, Exception::ExecuteAndRead(home.join(".cargo")))?; | ||
permissions::add_exception(&mut birdcage, Exception::Read("/etc/passwd".into()))?; | ||
// Bundle. | ||
permissions::add_exception(&mut birdcage, Exception::Read("/dev/urandom".into()))?; | ||
// Maven. | ||
permissions::add_exception(&mut birdcage, Exception::WriteAndRead(home.join(".m2")))?; | ||
permissions::add_exception(&mut birdcage, Exception::WriteAndRead("/var/folders".into()))?; | ||
permissions::add_exception(&mut birdcage, Exception::Read("/opt/maven".into()))?; | ||
permissions::add_exception(&mut birdcage, Exception::Read("/etc/java-openjdk".into()))?; | ||
permissions::add_exception(&mut birdcage, Exception::Read("/usr/local/Cellar/maven".into()))?; | ||
permissions::add_exception(&mut birdcage, Exception::Read("/usr/local/Cellar/openjdk".into()))?; | ||
permissions::add_exception( | ||
&mut birdcage, | ||
Exception::Read("/opt/homebrew/Cellar/maven".into()), | ||
)?; | ||
permissions::add_exception( | ||
&mut birdcage, | ||
Exception::Read("/opt/homebrew/Cellar/openjdk".into()), | ||
)?; | ||
// Gradle. | ||
permissions::add_exception(&mut birdcage, Exception::WriteAndRead(home.join(".gradle")))?; | ||
permissions::add_exception( | ||
&mut birdcage, | ||
Exception::Read("/usr/share/java/gradle/lib".into()), | ||
)?; | ||
permissions::add_exception(&mut birdcage, Exception::Read("/usr/local/Cellar/gradle".into()))?; | ||
permissions::add_exception( | ||
&mut birdcage, | ||
Exception::Read("/opt/homebrew/Cellar/gradle".into()), | ||
)?; | ||
// Pnpm. | ||
permissions::add_exception(&mut birdcage, Exception::Read("/tmp".into()))?; | ||
// Yarn. | ||
permissions::add_exception(&mut birdcage, Exception::Read(home.join("./yarn")))?; | ||
|
||
Ok(birdcage) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters