From 9b1f6e5710617c17a2441c29dcaa23257a1927ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 28 Jun 2023 12:20:22 +0200 Subject: [PATCH 1/4] feat: secure Lassie server using authorization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configure Lassie HTTP server to require authorization with the configured access token. This change does not affect Zinnia modules with one exception: `fetch('ipfs://`) requests are not allowed to send an `Authorization` header now. Signed-off-by: Miroslav Bajtoš --- Cargo.lock | 4 +- cli/main.rs | 4 +- daemon/main.rs | 6 ++- runtime/Cargo.toml | 2 +- runtime/js/99_main.js | 4 +- runtime/js/fetch.js | 16 +++++++- runtime/runtime.rs | 15 +++++++ runtime/tests/helpers/mod.rs | 11 ++++- runtime/tests/js/ipfs_retrieval_tests.js | 51 ++++++++++++++++++++++-- 9 files changed, 98 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47d8fb31..2c155505 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2232,9 +2232,9 @@ dependencies = [ [[package]] name = "lassie" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "996778d3f1be80d0d1152d20bf05476ef16c0ba6e163580230bd04b5744b4891" +checksum = "205d4b3140054548c1ddbf689bb961a60947a5b2290e8a8920524a02519c28f6" dependencies = [ "cc", "log", diff --git a/cli/main.rs b/cli/main.rs index 3fb2723e..bfe0d305 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -11,7 +11,8 @@ use zinnia_runtime::anyhow::{Context, Error, Result}; use zinnia_runtime::deno_core::error::JsError; use zinnia_runtime::fmt_errors::format_js_error; use zinnia_runtime::{ - colors, lassie, resolve_path, run_js_module, BootstrapOptions, ConsoleReporter, + colors, generate_lassie_access_token, lassie, resolve_path, run_js_module, BootstrapOptions, + ConsoleReporter, }; #[tokio::main(flavor = "current_thread")] @@ -57,6 +58,7 @@ async fn main_impl() -> Result<()> { temp_dir: None, // Listen on an ephemeral port selected by the operating system port: 0, + access_token: Some(generate_lassie_access_token()), // Use the default Lassie configuration for everything else ..lassie::DaemonConfig::default() }) diff --git a/daemon/main.rs b/daemon/main.rs index 16e2d073..b64afad2 100644 --- a/daemon/main.rs +++ b/daemon/main.rs @@ -12,7 +12,10 @@ use args::CliArgs; use clap::Parser; use zinnia_runtime::anyhow::{anyhow, Context, Error, Result}; -use zinnia_runtime::{get_module_root, lassie, resolve_path, run_js_module, BootstrapOptions}; +use zinnia_runtime::{ + generate_lassie_access_token, get_module_root, lassie, resolve_path, run_js_module, + BootstrapOptions, +}; use crate::station_reporter::{log_info_activity, StationReporter}; @@ -49,6 +52,7 @@ async fn run(config: CliArgs) -> Result<()> { temp_dir: Some(lassie_temp_dir), // Listen on an ephemeral port selected by the operating system port: 0, + access_token: Some(generate_lassie_access_token()), // Use the default Lassie configuration for everything else ..lassie::DaemonConfig::default() }; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index f6f3449c..8a6d6e9c 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -21,7 +21,7 @@ deno_fetch = "0.132.0" deno_url = "0.108.0" deno_web = "0.139.0" deno_webidl = "0.108.0" -lassie = "0.4.0" +lassie = "0.5.1" # lassie = { git = "https://github.com/filecoin-station/rusty-lassie.git" } log.workspace = true once_cell = "1.18.0" diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 67ab1e92..6fef69ce 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -36,7 +36,7 @@ import { mainRuntimeGlobalProperties, windowOrWorkerGlobalScope, } from "ext:zinnia_runtime/98_global_scope.js"; -import { setLassieUrl } from "ext:zinnia_runtime/fetch.js"; +import { setLassieConfig } from "ext:zinnia_runtime/fetch.js"; import { setVersions } from "ext:zinnia_runtime/90_zinnia_apis.js"; function formatException(error) { @@ -69,7 +69,7 @@ function runtimeStart(runtimeOptions) { // deno-lint-ignore prefer-primordials Error.prepareStackTrace = core.prepareStackTrace; - setLassieUrl(runtimeOptions.lassieUrl); + setLassieConfig(runtimeOptions.lassieUrl, runtimeOptions.lassieAuth); setVersions(runtimeOptions.zinniaVersion, runtimeOptions.v8Version); } diff --git a/runtime/js/fetch.js b/runtime/js/fetch.js index 2ead4ae0..b028865c 100644 --- a/runtime/js/fetch.js +++ b/runtime/js/fetch.js @@ -2,12 +2,17 @@ import { fetch as fetchImpl } from "ext:deno_fetch/26_fetch.js"; import { fromInnerResponse, toInnerResponse } from "ext:deno_fetch/23_response.js"; import { toInnerRequest, fromInnerRequest, Request } from "ext:deno_fetch/23_request.js"; import { guardFromHeaders } from "ext:deno_fetch/20_headers.js"; +import { byteLowerCase } from "ext:deno_web/00_infra.js"; const ipfsScheme = "ipfs://"; let ipfsBaseUrl = undefined; -export function setLassieUrl(/** @type {string} */ value) { - ipfsBaseUrl = value + "ipfs/"; +/** @type {string|null} */ +let lassieAuth = null; + +export function setLassieConfig(/** @type {string} */ url, /** @type {string|null} */ auth) { + ipfsBaseUrl = url + "ipfs/"; + lassieAuth = auth; } export function fetch(resource, options) { @@ -52,6 +57,13 @@ function buildIpfsRequest(request) { url.startsWith(ipfsScheme) ? ipfsBaseUrl + url.slice(ipfsScheme.length) : url, ); + if (inner.headerList.some(([name, _value]) => byteLowerCase(name) == "authorization")) { + throw new Error("IPFS retrieval requests don't support Authorization header yet"); + } + if (lassieAuth) { + inner.headerList.push(["authorization", lassieAuth]); + } + return fromInnerRequest(inner, request.signal, guardFromHeaders(request.headers)); } diff --git a/runtime/runtime.rs b/runtime/runtime.rs index c261b64c..83b3b154 100644 --- a/runtime/runtime.rs +++ b/runtime/runtime.rs @@ -73,6 +73,10 @@ impl BootstrapOptions { "isTty": self.is_tty, "walletAddress": self.wallet_address, "lassieUrl": format!("http://127.0.0.1:{}/", self.lassie_daemon.port()), + "lassieAuth": match self.lassie_daemon.access_token() { + Some(token) => serde_json::Value::String(format!("Bearer {token}")), + None => serde_json::Value::Null, + }, "zinniaVersion": self.zinnia_version, "v8Version": deno_core::v8_version(), }); @@ -132,3 +136,14 @@ pub async fn run_js_module( Ok(()) } + +use deno_crypto::rand::{self, distributions::Alphanumeric, Rng}; + +/// A helper function to generate an access token for protecting Lassie's HTTP API +pub fn generate_lassie_access_token() -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(24) + .map(char::from) + .collect() +} diff --git a/runtime/tests/helpers/mod.rs b/runtime/tests/helpers/mod.rs index ec9edc52..7b203b95 100644 --- a/runtime/tests/helpers/mod.rs +++ b/runtime/tests/helpers/mod.rs @@ -1,11 +1,18 @@ use std::sync::{Arc, OnceLock}; +use zinnia_runtime::generate_lassie_access_token; + pub fn lassie_daemon() -> Arc { static LASSIE_DAEMON: OnceLock, lassie::StartError>> = OnceLock::new(); - let result = LASSIE_DAEMON - .get_or_init(|| lassie::Daemon::start(lassie::DaemonConfig::default()).map(Arc::new)); + let result = LASSIE_DAEMON.get_or_init(|| { + lassie::Daemon::start(lassie::DaemonConfig { + access_token: Some(generate_lassie_access_token()), + ..lassie::DaemonConfig::default() + }) + .map(Arc::new) + }); match result { Ok(ptr) => Arc::clone(ptr), diff --git a/runtime/tests/js/ipfs_retrieval_tests.js b/runtime/tests/js/ipfs_retrieval_tests.js index 08f6012b..d09e94e4 100644 --- a/runtime/tests/js/ipfs_retrieval_tests.js +++ b/runtime/tests/js/ipfs_retrieval_tests.js @@ -1,5 +1,5 @@ import { test } from "zinnia:test"; -import { assertEquals, AssertionError } from "zinnia:assert"; +import { assertEquals, assertMatch, assertRejects, AssertionError } from "zinnia:assert"; const EXPECTED_CAR_BASE64 = "OqJlcm9vdHOB2CpYJQABcBIgO/KicpaH2Kj0sXyJNWLdY4kGpEe2mjY5zovBGRJ+6mpndmVyc2lvbgFrAXASIDvyonKWh9io9LF8iTVi3WOJBqRHtpo2Oc6LwRkSfupqCkUIAhI/TXkgbW9zdCBmYW1vdXMgZHJhd2luZywgYW5kIG9uZSBvZiB0aGUgZmlyc3QgSSBkaWQgZm9yIHRoZSBzaXRlGD8="; @@ -7,7 +7,7 @@ const EXPECTED_CAR_BASE64 = test("can retrieve CID content as a CAR file", async () => { const requestUrl = "ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni"; const response = await fetch(requestUrl); - assertResponseIsOk(response); + await assertResponseIsOk(response); const payload = await response.arrayBuffer(); assertEquals(payload.byteLength, 167, "CAR size in bytes"); @@ -21,7 +21,7 @@ test("can retrieve CID content as a CAR file", async () => { test("can retrieve IPFS content using URL", async () => { const requestUrl = new URL("ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni"); const response = await fetch(requestUrl); - assertResponseIsOk(response); + await assertResponseIsOk(response); const payload = await response.arrayBuffer(); assertEquals(payload.byteLength, 167, "CAR size in bytes"); @@ -32,7 +32,7 @@ test("can retrieve IPFS content using URL", async () => { test("can retrieve IPFS content using Fetch Request object", async () => { const request = new Request("ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni"); const response = await fetch(request); - assertResponseIsOk(response); + await assertResponseIsOk(response); const payload = await response.arrayBuffer(); assertEquals(payload.byteLength, 167, "CAR size in bytes"); @@ -40,6 +40,49 @@ test("can retrieve IPFS content using Fetch Request object", async () => { assertEquals(response.url, request.url); }); +test("does not modify original request headers - headers initialized as array", async () => { + const request = new Request( + "ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni", + { headers: [["X-Test", "true"]] }, + ); + const response = await fetch(request); + await assertResponseIsOk(response); + + assertEquals(Array.from(request.headers.keys()), ["x-test"]); +}); + +test("does not modify original request headers - headers initialized as object", async () => { + const request = new Request( + "ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni", + { headers: { "X-Test": "true" } }, + ); + const response = await fetch(request); + await assertResponseIsOk(response); + + assertEquals(Array.from(request.headers.keys()), ["x-test"]); +}); + +test("does not modify original request headers - headers initialized as Headers", async () => { + const request = new Request( + "ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni", + { headers: new Headers({ "X-Test": "true" }) }, + ); + const response = await fetch(request); + await assertResponseIsOk(response); + + assertEquals(Array.from(request.headers.keys()), ["x-test"]); +}); + +test("rejects user-provided Authorization header", async () => { + const request = new Request( + "ipfs://bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni", + { headers: { Authorization: "invalid" } }, + ); + + let error = await assertRejects(() => fetch(request)); + assertMatch(error.message, /authorization/i); +}); + /** * @param {Response} response Fetch API response */ From 515893a1f091ed0c72d5f905234c746b1375d82a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 28 Jun 2023 14:50:05 +0200 Subject: [PATCH 2/4] add a test calling Lassie HTTP directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miroslav Bajtoš --- Cargo.lock | 1 + cli/Cargo.toml | 1 + cli/main.rs | 159 +++++++++++++++++++++++++++++++++------------- daemon/Cargo.toml | 1 + daemon/main.rs | 77 +++++++++++++++++++++- 5 files changed, 193 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2c155505..bdb78c7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5786,6 +5786,7 @@ name = "zinniad" version = "0.12.0" dependencies = [ "assert_cmd", + "assert_fs", "atomicwrites", "clap", "env_logger", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 5007f358..ae5d0488 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,6 +27,7 @@ assert_fs = { workspace = true } lazy_static = "1.4.0" pretty_assertions = { workspace = true } regex = "1.8.4" +tokio = { workspace = true, features = ["io-util"] } [package.metadata.winres] # This section defines the metadata that appears in the deno.exe PE header. diff --git a/cli/main.rs b/cli/main.rs index bfe0d305..8cc70f6c 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -32,55 +32,73 @@ async fn main_impl() -> Result<()> { let cli_args = CliArgs::parse_from(std::env::args()); match cli_args.command { Commands::Run { file } => { - let main_module = resolve_path( - &file, - &std::env::current_dir().context("unable to get current working directory")?, - )?; - - let lassie_daemon = Arc::new( - lassie::Daemon::start(lassie::DaemonConfig { - // This configuration applies to `zinnia` CLI only. The `zinniad` daemon running - // inside Station uses a different temp_dir config based on the env var - // `CACHE_ROOT` provided by the Station. - // - // By default, Lassie stores its temporary files in the system temp directory. - // That's good enough for now. We can improve this later based on user feedback, - // for example: - // - we can honour CACHE_ROOT - // - we can default to something like - // `~/.cache/zinnia/lassie` on Unix, - // `%APPLOCALDATA%\zinnia\lassie' on Windows. - // - // Important: if we tell Lassie to use a specific temp dir that's not - // automatically cleaned by the operating system, we will need to clean any - // leftover files ourselves. See the GH issue for deleting leftover files - // when `zinniad` starts: https://github.com/filecoin-station/zinnia/issues/245 - temp_dir: None, - // Listen on an ephemeral port selected by the operating system - port: 0, - access_token: Some(generate_lassie_access_token()), - // Use the default Lassie configuration for everything else - ..lassie::DaemonConfig::default() - }) - .context("cannot initialize the IPFS retrieval client Lassie")?, - ); - - let runtime_config = BootstrapOptions { - zinnia_version: env!("CARGO_PKG_VERSION"), - ..BootstrapOptions::new( - format!("zinnia/{}", env!("CARGO_PKG_VERSION")), - Rc::new(ConsoleReporter::new(Duration::from_millis(500))), - lassie_daemon, - None, - ) - }; + run_module(file).await?; - run_js_module(&main_module, &runtime_config).await?; Ok(()) } } } +#[allow(dead_code)] +struct RunOutput { + // TBD + module_result: (), + // for testing + lassie_daemon: Arc, +} + +async fn run_module(file: String) -> Result { + let main_module = resolve_path( + &file, + &std::env::current_dir().context("unable to get current working directory")?, + )?; + + let lassie_daemon = Arc::new( + lassie::Daemon::start(lassie::DaemonConfig { + // This configuration applies to `zinnia` CLI only. The `zinniad` daemon running + // inside Station uses a different temp_dir config based on the env var + // `CACHE_ROOT` provided by the Station. + // + // By default, Lassie stores its temporary files in the system temp directory. + // That's good enough for now. We can improve this later based on user feedback, + // for example: + // - we can honour CACHE_ROOT + // - we can default to something like + // `~/.cache/zinnia/lassie` on Unix, + // `%APPLOCALDATA%\zinnia\lassie' on Windows. + // + // Important: if we tell Lassie to use a specific temp dir that's not + // automatically cleaned by the operating system, we will need to clean any + // leftover files ourselves. See the GH issue for deleting leftover files + // when `zinniad` starts: https://github.com/filecoin-station/zinnia/issues/245 + temp_dir: None, + // Listen on an ephemeral port selected by the operating system + port: 0, + access_token: Some(generate_lassie_access_token()), + // Use the default Lassie configuration for everything else + ..lassie::DaemonConfig::default() + }) + .context("cannot initialize the IPFS retrieval client Lassie")?, + ); + + let runtime_config = BootstrapOptions { + zinnia_version: env!("CARGO_PKG_VERSION"), + ..BootstrapOptions::new( + format!("zinnia/{}", env!("CARGO_PKG_VERSION")), + Rc::new(ConsoleReporter::new(Duration::from_millis(500))), + Arc::clone(&lassie_daemon), + None, + ) + }; + + run_js_module(&main_module, &runtime_config).await?; + + Ok(RunOutput { + module_result: (), + lassie_daemon, + }) +} + fn exit_with_error(error: Error) { // Inspired by unwrap_or_exit from Deno's `cli/main.rs` // https://github.com/denoland/deno/blob/34bfa2cb2c1f0f74a94ced8fc164e81cc91cb9f4/cli/main.rs @@ -98,3 +116,58 @@ fn exit_with_error(error: Error) { ); std::process::exit(error_code); } + +#[cfg(test)] +mod tests { + use super::*; + use assert_fs::prelude::*; + use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; + + #[tokio::test] + async fn lassie_auth_is_configured() { + // Step 1: execute `zinnia run` with a dummy module that does nothing + let mod_js = + assert_fs::NamedTempFile::new("dummy.js").expect("cannot create temp dummy.js"); + + mod_js + .write_str(&format!("/* no-op */",)) + .expect("cannot write to dummy.js"); + + let RunOutput { lassie_daemon, .. } = + run_module(mod_js.path().to_string_lossy().to_string()) + .await + .expect("cannot run dummy.js"); + + assert!( + lassie_daemon.access_token().is_some(), + "lassie_daemon access_token was not set" + ); + + // Make a retrieval request to Lassie but do not provide any access token + let mut stream = + tokio::net::TcpStream::connect(format!("127.0.0.1:{}", lassie_daemon.port())) + .await + .expect("cannot connect to Lassie HTTP daemon"); + + stream + .write_all( + concat!( + "GET /ipfs/bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni HTTP/1.1\n", + "Host: 127.0.0.1\n", + "\n", + ) + .as_bytes(), + ) + .await + .expect("cannot write HTTP request"); + + let status = BufReader::new(stream) + .lines() + .next_line() + .await + .expect("cannot read the first line of the HTTP response") + .expect("server returned at least one line"); + + assert_eq!(status, "HTTP/1.1 401 Unauthorized") + } +} diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index a003f012..616f3473 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -25,5 +25,6 @@ zinnia_runtime = { workspace = true } [dev-dependencies] assert_cmd = { workspace = true } +assert_fs = { workspace = true } pretty_assertions = { workspace = true } tempfile = "3.6.0" diff --git a/daemon/main.rs b/daemon/main.rs index b64afad2..c174699b 100644 --- a/daemon/main.rs +++ b/daemon/main.rs @@ -30,7 +30,7 @@ async fn main() { } } -async fn run(config: CliArgs) -> Result<()> { +async fn run(config: CliArgs) -> Result { log::info!("Starting zinniad with config {config:?}"); if config.files.is_empty() { @@ -84,7 +84,7 @@ async fn run(config: CliArgs) -> Result<()> { Duration::from_millis(200), module_name.into(), )), - lassie_daemon, + lassie_daemon: Arc::clone(&lassie_daemon), module_root: Some(module_root), no_color: true, is_tty: false, @@ -96,7 +96,18 @@ async fn run(config: CliArgs) -> Result<()> { log::info!("Starting module {main_module}"); run_js_module(&main_module, &runtime_config).await?; - Ok(()) + Ok(RunOutput { + module_result: (), + lassie_daemon, + }) +} + +#[allow(dead_code)] +struct RunOutput { + // TBD + module_result: (), + // for testing + lassie_daemon: Arc, } fn setup_logger() { @@ -149,3 +160,63 @@ fn setup_lassie_tempdir(lassie_temp_dir: &Path) -> Result<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use assert_fs::prelude::*; + use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; + + #[tokio::test] + async fn lassie_auth_is_configured() { + // Step 1: execute `zinnia run` with a dummy module that does nothing + let mod_js = + assert_fs::NamedTempFile::new("dummy.js").expect("cannot create temp dummy.js"); + + mod_js + .write_str(&format!("/* no-op */",)) + .expect("cannot write to dummy.js"); + + let temp = assert_fs::TempDir::new().expect("cannot create a new temp directory"); + + let args = CliArgs { + cache_root: temp.join("cache").to_string_lossy().into(), + state_root: temp.join("state").to_string_lossy().into(), + wallet_address: "f1test".to_string(), + files: vec![mod_js.path().to_string_lossy().to_string()], + }; + let RunOutput { lassie_daemon, .. } = run(args).await.expect("cannot run dummy.js"); + + assert!( + lassie_daemon.access_token().is_some(), + "lassie_daemon access_token was not set" + ); + + // Make a retrieval request to Lassie but do not provide any access token + let mut stream = + tokio::net::TcpStream::connect(format!("127.0.0.1:{}", lassie_daemon.port())) + .await + .expect("cannot connect to Lassie HTTP daemon"); + + stream + .write_all( + concat!( + "GET /ipfs/bafybeib36krhffuh3cupjml4re2wfxldredkir5wti3dttulyemre7xkni HTTP/1.1\n", + "Host: 127.0.0.1\n", + "\n", + ) + .as_bytes(), + ) + .await + .expect("cannot write HTTP request"); + + let status = BufReader::new(stream) + .lines() + .next_line() + .await + .expect("cannot read the first line of the HTTP response") + .expect("server returned at least one line"); + + assert_eq!(status, "HTTP/1.1 401 Unauthorized") + } +} From 17dfa1fc6679ae574d8d2814ce5c37bef455129e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 28 Jun 2023 14:51:42 +0200 Subject: [PATCH 3/4] fixup! cargo clippy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miroslav Bajtoš --- cli/main.rs | 2 +- daemon/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/main.rs b/cli/main.rs index 8cc70f6c..8f3194eb 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -130,7 +130,7 @@ mod tests { assert_fs::NamedTempFile::new("dummy.js").expect("cannot create temp dummy.js"); mod_js - .write_str(&format!("/* no-op */",)) + .write_str("/* no-op */") .expect("cannot write to dummy.js"); let RunOutput { lassie_daemon, .. } = diff --git a/daemon/main.rs b/daemon/main.rs index c174699b..a9ca7efc 100644 --- a/daemon/main.rs +++ b/daemon/main.rs @@ -174,7 +174,7 @@ mod tests { assert_fs::NamedTempFile::new("dummy.js").expect("cannot create temp dummy.js"); mod_js - .write_str(&format!("/* no-op */",)) + .write_str("/* no-op */") .expect("cannot write to dummy.js"); let temp = assert_fs::TempDir::new().expect("cannot create a new temp directory"); From e3e0738026abb95f2effa8b1a621911509a53fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Wed, 28 Jun 2023 15:17:00 +0200 Subject: [PATCH 4/4] fixup! remove TBD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miroslav Bajtoš --- cli/main.rs | 8 ++++---- daemon/main.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cli/main.rs b/cli/main.rs index 8f3194eb..0f2ba6ef 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -41,8 +41,7 @@ async fn main_impl() -> Result<()> { #[allow(dead_code)] struct RunOutput { - // TBD - module_result: (), + module_output: (), // for testing lassie_daemon: Arc, } @@ -91,10 +90,11 @@ async fn run_module(file: String) -> Result { ) }; - run_js_module(&main_module, &runtime_config).await?; + #[allow(clippy::let_unit_value)] + let module_output = run_js_module(&main_module, &runtime_config).await?; Ok(RunOutput { - module_result: (), + module_output, lassie_daemon, }) } diff --git a/daemon/main.rs b/daemon/main.rs index a9ca7efc..5d58511d 100644 --- a/daemon/main.rs +++ b/daemon/main.rs @@ -94,18 +94,18 @@ async fn run(config: CliArgs) -> Result { // TODO: handle module exit and restart it // https://github.com/filecoin-station/zinnia/issues/146 log::info!("Starting module {main_module}"); - run_js_module(&main_module, &runtime_config).await?; + #[allow(clippy::let_unit_value)] + let module_output = run_js_module(&main_module, &runtime_config).await?; Ok(RunOutput { - module_result: (), + module_output, lassie_daemon, }) } #[allow(dead_code)] struct RunOutput { - // TBD - module_result: (), + module_output: (), // for testing lassie_daemon: Arc, }