Skip to content

Commit

Permalink
Update Birdcage to v0.7.0 (#1307)
Browse files Browse the repository at this point in the history
  • Loading branch information
cd-work authored Dec 1, 2023
1 parent ae113fa commit 60f6c7b
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 17 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ once_cell = "1.12.0"
deno_runtime = { version = "0.134.0" }
deno_core = { version = "0.232.0" }
deno_ast = { version = "0.31.2", features = ["transpiling"] }
birdcage = { version = "0.6.0" }
birdcage = { version = "0.7.0" }
libc = "0.2.135"
ignore = { version = "0.4.20", optional = true }
uuid = "1.4.1"
Expand Down
4 changes: 4 additions & 0 deletions cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,10 @@ pub fn add_subcommands(command: Command) -> Command {
.value_name("MANIFEST")
.required(true)
.help("Canonicalized manifest path"),
Arg::new("skip-sandbox")
.long("skip-sandbox")
.help("Generate lockfile, without creating a new sandbox")
.action(ArgAction::SetTrue),
])
.about("Run lockfile generation inside sandbox and write it to STDOUT")
.hide(true),
Expand Down
47 changes: 43 additions & 4 deletions cli/src/commands/generate_lockfile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! `phylum generate-lockfile` subcommand.
use std::env;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;

use anyhow::{Context, Result};
use birdcage::{Birdcage, Exception, Sandbox};
Expand All @@ -15,16 +18,48 @@ use crate::dirs;
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 skip_sandbox = matches.get_flag("skip-sandbox");

if skip_sandbox {
generate_lockfile(lockfile_type, manifest)
} else {
spawn_sandbox(lockfile_type, manifest)
}
}

/// Reexecute command inside the sandbox.
fn spawn_sandbox(lockfile_type: &str, manifest: &OsStr) -> CommandResult {
let manifest_path = PathBuf::from(manifest);

// Setup sandbox for lockfile generation.
let birdcage = lockfile_generation_sandbox(&manifest_path)?;

// Reexecute command inside sandbox.
let current_exe = env::current_exe()?;
let mut command = Command::new(current_exe);
command.arg("generate-lockfile");
command.arg("--skip-sandbox");
command.arg(lockfile_type);
command.arg(manifest);
let mut child = birdcage.spawn(command)?;

// Check for process failure.
let status = child.wait()?;
match status.code() {
Some(code) => Ok(ExitCode::Custom(code)),
None if !status.success() => Ok(ExitCode::Generic),
None => Ok(ExitCode::Ok),
}
}

/// Generate lockfile and write it to STDOUT.
fn generate_lockfile(lockfile_type: &str, manifest: &OsStr) -> CommandResult {
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)
Expand All @@ -43,6 +78,10 @@ fn lockfile_generation_sandbox(canonical_manifest_path: &Path) -> Result<Birdcag
// Allow all networking.
birdcage.add_exception(Exception::Networking)?;

// Allow reexecuting phylum.
let current_exe = env::current_exe()?;
permissions::add_exception(&mut birdcage, Exception::ExecuteAndRead(current_exe))?;

// 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()))?;
Expand Down
20 changes: 11 additions & 9 deletions cli/src/commands/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ use crate::commands::{CommandResult, ExitCode};
/// Entry point for the `sandbox` subcommand.
pub async fn handle_sandbox(matches: &ArgMatches) -> CommandResult {
// Setup sandbox.
lock_process(matches)?;
let sandbox = sandbox_config(matches)?;

// Start subprocess.
// Start sandboxed subprocess.
let cmd = matches.get_one::<String>("cmd").unwrap();
let args: Vec<&String> = matches.get_many("args").unwrap_or_default().collect();
let status = match Command::new(cmd).args(args).status() {
let mut command = Command::new(cmd);
command.args(args);
let mut child = sandbox.spawn(command)?;

// Wait for subprocess to complete.
let status = match child.wait() {
Ok(status) => status,
Err(err) => {
eprintln!("Process {cmd:?} failed to start: {err}");
Expand All @@ -41,9 +46,9 @@ pub async fn handle_sandbox(matches: &ArgMatches) -> CommandResult {
}
}

/// Lock down the current process.
/// Create the sandbox configuration.
#[cfg(unix)]
fn lock_process(matches: &ArgMatches) -> Result<()> {
fn sandbox_config(matches: &ArgMatches) -> Result<Birdcage> {
let mut birdcage =
if matches.get_flag("strict") { Birdcage::new() } else { permissions::default_sandbox()? };

Expand Down Expand Up @@ -73,8 +78,5 @@ fn lock_process(matches: &ArgMatches) -> Result<()> {
}
}

// Lock down the process.
birdcage.lock()?;

Ok(())
Ok(birdcage)
}
7 changes: 6 additions & 1 deletion cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use phylum_project::{LockfileConfig, ProjectConfig};
use phylum_types::types::auth::RefreshToken;
use serde::{Deserialize, Deserializer, Serialize};

use crate::{dirs, print_user_warning};
use crate::{dirs, print_user_failure, print_user_warning};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ConnectionInfo {
Expand Down Expand Up @@ -156,6 +156,11 @@ pub fn read_configuration(path: &Path) -> Result<Config> {
Ok(c) => c,
Err(orig_err) => match orig_err.downcast_ref::<io::Error>() {
Some(e) if e.kind() == io::ErrorKind::NotFound => Config::default(),
// We don't fail on permission errors to allow running inside our sandbox.
Some(e) if e.kind() == io::ErrorKind::PermissionDenied => {
print_user_failure!("Config access denied: {e}");
Config::default()
},
_ => return Err(orig_err),
},
};
Expand Down

0 comments on commit 60f6c7b

Please sign in to comment.