mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 23:01:02 +00:00
Merge pull request #6449 from dotCooCoo/fix/script-run-keeps-file-scope
Scripts: a framed run keeps the file-access roots it started under
This commit is contained in:
@@ -502,6 +502,8 @@ struct Job {
|
||||
/// The documents open when the run began, by [`DocState::uid`].
|
||||
start_uids: Vec<u64>,
|
||||
name: String,
|
||||
/// The file-access scope `script.run` came in, which every slice runs in.
|
||||
scope: crate::file_access::ScopeHandle,
|
||||
}
|
||||
|
||||
/// The `Data` for a JSON value, within `limits`. When it does not fit, the error is the place in
|
||||
@@ -986,7 +988,8 @@ impl Session {
|
||||
self.script_report = Some(report);
|
||||
return Err(EngineError::Other(message));
|
||||
}
|
||||
let job = Job { realm, host, world: World::working(self), start_uids: open, name: request.name };
|
||||
let scope = crate::file_access::ScopeHandle::capture();
|
||||
let job = Job { realm, host, world: World::working(self), start_uids: open, name: request.name, scope };
|
||||
let id = NEXT_JOB.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
JOBS.with(|jobs| jobs.borrow_mut().insert(id, job));
|
||||
self.script_key = Some(JobKey(id));
|
||||
@@ -1170,20 +1173,24 @@ fn failure_text(report: &Value) -> String {
|
||||
}
|
||||
|
||||
/// A run's slice: the working copy in, the real session lent to the host functions, one measured
|
||||
/// slice run, and everything back. A panic in the interpreter is the outer `Err`.
|
||||
/// slice run in the file-access scope the run began in, and everything back. A panic in the
|
||||
/// interpreter is the outer `Err`.
|
||||
fn run_slice(s: &mut Session, job: &mut Job) -> std::result::Result<std::result::Result<Progress, RunError>, String> {
|
||||
let depth = std::mem::replace(&mut s.depth, 0);
|
||||
job.world.swap(s);
|
||||
s.script_in_run = true;
|
||||
let cell = job.host.session.clone();
|
||||
std::mem::swap(s, &mut *cell.borrow_mut());
|
||||
let scope = job.scope.clone();
|
||||
let realm = &mut job.realm;
|
||||
let r = guard::catch_panic(|| {
|
||||
#[cfg(test)]
|
||||
if PANIC_IN_SLICE.with(Cell::get) {
|
||||
panic!("a slice failed");
|
||||
}
|
||||
realm.advance(SLICE_FUEL)
|
||||
let r = scope.run(|| {
|
||||
guard::catch_panic(|| {
|
||||
#[cfg(test)]
|
||||
if PANIC_IN_SLICE.with(Cell::get) {
|
||||
panic!("a slice failed");
|
||||
}
|
||||
realm.advance(SLICE_FUEL)
|
||||
})
|
||||
});
|
||||
std::mem::swap(s, &mut *cell.borrow_mut());
|
||||
s.script_in_run = false;
|
||||
|
||||
@@ -862,6 +862,44 @@ fn a_file_saved_before_a_failure_stays_written_and_is_named() {
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
/// A run in the app's frames keeps the file-access scope its `script.run` came in, whatever scope
|
||||
/// the frames that advance it run in.
|
||||
#[test]
|
||||
fn a_framed_run_keeps_the_file_access_scope_it_started_in() {
|
||||
let dir = std::env::temp_dir().join(format!("vc-script-scope-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
let (allowed, outside) = (dir.join("allowed"), dir.join("outside"));
|
||||
std::fs::create_dir_all(&allowed).unwrap();
|
||||
std::fs::create_dir_all(&outside).unwrap();
|
||||
let roots = crate::file_access::AutomationRoots::new(&[&allowed], &[&allowed]).unwrap().unwrap();
|
||||
let export = |target: &std::path::Path| {
|
||||
let p = target.to_string_lossy().into_owned();
|
||||
format!("try {{ vc.run('document.export', {{path: {p:?}, format: 'svg'}}); vc.log('ok'); }} catch (e) {{ vc.log(e.name); }}")
|
||||
};
|
||||
let finish = |s: &mut Session| {
|
||||
loop {
|
||||
if let Some(r) = s.script_pump() {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut s = two_docs();
|
||||
s.script_frames = true;
|
||||
let confined_target = outside.join("confined.svg");
|
||||
let started = crate::file_access::confine(Some(&roots), || run(&mut s, &export(&confined_target))).unwrap();
|
||||
assert_eq!(started["running"], true);
|
||||
let r = crate::file_access::unconfined(|| finish(&mut s)).unwrap();
|
||||
assert_eq!(r["log"], json!(["Error"]), "a confined caller's run stays confined: {r}");
|
||||
assert!(!confined_target.exists());
|
||||
let user_target = outside.join("user.svg");
|
||||
let started = crate::file_access::unconfined(|| run(&mut s, &export(&user_target))).unwrap();
|
||||
assert_eq!(started["running"], true);
|
||||
let r = crate::file_access::confine(Some(&roots), || finish(&mut s)).unwrap();
|
||||
assert_eq!(r["log"], json!(["ok"]), "a run the person started is not confined by a later caller: {r}");
|
||||
assert!(user_target.exists());
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_committed_run_exports_what_it_drew() {
|
||||
let path = std::env::temp_dir().join(format!("vc-script-export-{}.svg", std::process::id()));
|
||||
|
||||
Reference in New Issue
Block a user