diff --git a/.github/workflows/start-tunnel.yaml b/.github/workflows/start-tunnel.yaml new file mode 100644 index 000000000..24136993c --- /dev/null +++ b/.github/workflows/start-tunnel.yaml @@ -0,0 +1,94 @@ +name: Debian-based ISO and SquashFS + +on: + workflow_call: + workflow_dispatch: + inputs: + environment: + type: choice + description: Environment + options: + - NONE + - dev + - unstable + - dev-unstable + runner: + type: choice + description: Runner + options: + - standard + - fast + arch: + type: choice + description: Architecture + options: + - ALL + - x86_64 + - aarch64 + - riscv64 + push: + branches: + - master + - next/* + pull_request: + branches: + - master + - next/* + +env: + NODEJS_VERSION: "24.11.0" + ENVIRONMENT: '${{ fromJson(format(''["{0}", ""]'', github.event.inputs.environment || ''dev''))[github.event.inputs.environment == ''NONE''] }}' + +jobs: + compile: + name: Compile Base Binaries + strategy: + fail-fast: true + matrix: + arch: >- + ${{ + fromJson('{ + "x86_64": ["x86_64"], + "aarch64": ["aarch64"], + "riscv64": ["riscv64"], + "ALL": ["x86_64", "aarch64", "riscv64"] + }')[github.event.inputs.platform || 'ALL'] + }} + runs-on: ${{ fromJson('["ubuntu-22.04", "buildjet-32vcpu-ubuntu-2204"]')[github.event.inputs.runner == 'fast'] }} + steps: + - run: | + sudo mount -t tmpfs tmpfs . + if: ${{ github.event.inputs.runner == 'fast' }} + + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODEJS_VERSION }} + + - name: Set up docker QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Configure sccache + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Make + run: make ARCH=${{ matrix.arch }} compiled-${{ matrix.arch }}.tar + env: + PLATFORM: ${{ matrix.arch }} + SCCACHE_GHA_ENABLED: on + SCCACHE_GHA_VERSION: 0 + + - uses: actions/upload-artifact@v4 + with: + name: start-tunnel_${{ matrix.arch }}.deb + path: start-tunnel-*_${{ matrix.arch }}.deb diff --git a/.github/workflows/startos-iso.yaml b/.github/workflows/startos-iso.yaml index d862fc109..934456e08 100644 --- a/.github/workflows/startos-iso.yaml +++ b/.github/workflows/startos-iso.yaml @@ -67,8 +67,13 @@ jobs: "ALL": ["x86_64", "aarch64"] }')[github.event.inputs.platform || 'ALL'] }} - runs-on: ${{ fromJson('["ubuntu-22.04", "buildjet-32vcpu-ubuntu-2204"]')[github.event.inputs.runner == 'fast'] }} + runs-on: ${{ fromJson('["ubuntu-latest", "buildjet-32vcpu-ubuntu-2204"]')[github.event.inputs.runner == 'fast'] }} steps: + - name: Cleaning up unnecessary files + run: | + sudo apt-get remove --purge -y google-chrome-stable firefox mono-devel + sudo apt-get autoremove -y + sudo apt-get clean - run: | sudo mount -t tmpfs tmpfs . if: ${{ github.event.inputs.runner == 'fast' }} @@ -134,7 +139,7 @@ jobs: ${{ fromJson( format( - '["ubuntu-22.04", "{0}"]', + '["ubuntu-latest", "{0}"]', fromJson('{ "x86_64": "buildjet-8vcpu-ubuntu-2204", "x86_64-nonfree": "buildjet-8vcpu-ubuntu-2204", @@ -267,7 +272,7 @@ jobs: index: if: ${{ github.event.inputs.deploy != '' && github.event.inputs.deploy != 'NONE' }} needs: [image] - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - run: >- curl "https://${{ diff --git a/Makefile b/Makefile index def2fa8dd..1f5383090 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,6 @@ STARTOS_TARGETS := $(STARTD_SRC) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE) $(VERSION_ fi') REGISTRY_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/registrybox core/startos/start-registryd.service TUNNEL_TARGETS := core/target/$(RUST_ARCH)-unknown-linux-musl/$(PROFILE)/tunnelbox core/startos/start-tunneld.service -REBUILD_TYPES = 1 ifeq ($(REMOTE),) mkdir = mkdir -p $1 @@ -63,7 +62,7 @@ endif .DELETE_ON_ERROR: -.PHONY: all metadata install clean format cli uis ui reflash deb $(IMAGE_TYPE) squashfs wormhole wormhole-deb test test-core test-sdk test-container-runtime registry install-registry tunnel install-tunnel +.PHONY: all metadata install clean format cli uis ui reflash deb $(IMAGE_TYPE) squashfs wormhole wormhole-deb test test-core test-sdk test-container-runtime registry install-registry tunnel install-tunnel ts-bindings all: $(STARTOS_TARGETS) @@ -277,10 +276,9 @@ container-runtime/node_modules/.package-lock.json: container-runtime/package-loc npm --prefix container-runtime ci touch container-runtime/node_modules/.package-lock.json -sdk/base/lib/osBindings/index.ts: $(shell if [ "$(REBUILD_TYPES)" -ne 0 ]; then echo core/startos/bindings/index.ts; fi) +ts-bindings: core/startos/bindings/index.ts mkdir -p sdk/base/lib/osBindings rsync -ac --delete core/startos/bindings/ sdk/base/lib/osBindings/ - touch sdk/base/lib/osBindings/index.ts core/startos/bindings/index.ts: $(call ls-files, core) $(ENVIRONMENT_FILE) rm -rf core/startos/bindings diff --git a/build/lib/scripts/forward-port b/build/lib/scripts/forward-port index 5d1e0ba45..cb16447d2 100755 --- a/build/lib/scripts/forward-port +++ b/build/lib/scripts/forward-port @@ -25,5 +25,5 @@ apply_rule PREROUTING -p tcp -d $sip --dport $sport -j DNAT --to-destination $di apply_rule OUTPUT -p tcp -d $sip --dport $sport -j DNAT --to-destination $dip:$dport if [ "$UNDO" = 1 ]; then - conntrack -D -p tcp -d $sip --dport $sport + conntrack -D -p tcp -d $sip --dport $sport || true # conntrack returns exit 1 if no connections are active fi \ No newline at end of file diff --git a/container-runtime/package-lock.json b/container-runtime/package-lock.json index 756f31d5d..7b62984fa 100644 --- a/container-runtime/package-lock.json +++ b/container-runtime/package-lock.json @@ -38,7 +38,7 @@ }, "../sdk/dist": { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.43", + "version": "0.4.0-beta.44", "license": "MIT", "dependencies": { "@iarna/toml": "^3.0.0", diff --git a/container-runtime/src/Adapters/RpcListener.ts b/container-runtime/src/Adapters/RpcListener.ts index e8876aea1..c924f9a79 100644 --- a/container-runtime/src/Adapters/RpcListener.ts +++ b/container-runtime/src/Adapters/RpcListener.ts @@ -158,6 +158,8 @@ export class RpcListener { this.unixSocketServer.listen(SOCKET_PATH) + console.log("Listening on %s", SOCKET_PATH) + this.unixSocketServer.on("connection", (s) => { let id: IdType = null const captureId = (x: X) => { diff --git a/core/Cargo.lock b/core/Cargo.lock index ab19c8c97..3cf72c8c4 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -7908,7 +7908,7 @@ dependencies = [ [[package]] name = "start-os" -version = "0.4.0-alpha.13" +version = "0.4.0-alpha.14" dependencies = [ "aes 0.7.5", "arti-client", diff --git a/core/build-cli.sh b/core/build-cli.sh index 4cff77981..1dfcc8bc2 100755 --- a/core/build-cli.sh +++ b/core/build-cli.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/build-containerbox.sh b/core/build-containerbox.sh index 46c023d4c..d9a7844a9 100755 --- a/core/build-containerbox.sh +++ b/core/build-containerbox.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/build-registrybox.sh b/core/build-registrybox.sh index ad1c6dce4..9cffc49a3 100755 --- a/core/build-registrybox.sh +++ b/core/build-registrybox.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/build-startbox.sh b/core/build-startbox.sh index c637c1d97..b617675c6 100755 --- a/core/build-startbox.sh +++ b/core/build-startbox.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/build-ts.sh b/core/build-ts.sh index 757ed6991..143c36bd3 100755 --- a/core/build-ts.sh +++ b/core/build-ts.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/build-tunnelbox.sh b/core/build-tunnelbox.sh index 1a6516388..f37c5eae6 100755 --- a/core/build-tunnelbox.sh +++ b/core/build-tunnelbox.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/builder-alias.sh b/core/builder-alias.sh index e940efd76..965f1d6ff 100644 --- a/core/builder-alias.sh +++ b/core/builder-alias.sh @@ -5,4 +5,4 @@ if tty -s; then USE_TTY="-it" fi -alias 'rust-zig-builder'='docker run '"$USE_TTY"' --rm -e "RUSTFLAGS=$RUSTFLAGS" -e "CFLAGS=-D_FORTIFY_SOURCE=2" -e "CXXFLAGS=-D_FORTIFY_SOURCE=2" -e SCCACHE_GHA_ENABLED -e SCCACHE_GHA_VERSION -e ACTIONS_RESULTS_URL -e ACTIONS_RUNTIME_TOKEN -v "$HOME/.cargo/registry":/usr/local/cargo/registry -v "$HOME/.cargo/git":/root/.cargo/git -v "$HOME/.cache/sccache":/root/.cache/sccache -v "$(pwd)":/workdir -w /workdir -P start9/cargo-zigbuild' +alias 'rust-zig-builder'='docker run '"$USE_TTY"' --rm -e "RUSTFLAGS=$RUSTFLAGS" -e "AWS_LC_SYS_CMAKE_TOOLCHAIN_FILE_riscv64gc_unknown_linux_musl=/root/cmake-overrides/toolchain-riscv64-musl-clang.cmake" -e SCCACHE_GHA_ENABLED -e SCCACHE_GHA_VERSION -e ACTIONS_RESULTS_URL -e ACTIONS_RUNTIME_TOKEN -v "$HOME/.cargo/registry":/usr/local/cargo/registry -v "$HOME/.cargo/git":/root/.cargo/git -v "$HOME/.cache/sccache":/root/.cache/sccache -v "$(pwd)":/workdir -w /workdir -P start9/cargo-zigbuild' diff --git a/core/run-tests.sh b/core/run-tests.sh index 9273bc066..46cc5a158 100755 --- a/core/run-tests.sh +++ b/core/run-tests.sh @@ -12,7 +12,7 @@ if [ "${PROFILE}" = "release" ]; then BUILD_FLAGS="--release" else if [ "$PROFILE" != "debug"]; then - >&2 echo "Unknonw profile $PROFILE: falling back to debug..." + >&2 echo "Unknown profile $PROFILE: falling back to debug..." PROFILE=debug fi fi diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index 4fd67cebf..e10fe6c34 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -15,7 +15,7 @@ license = "MIT" name = "start-os" readme = "README.md" repository = "https://github.com/Start9Labs/start-os" -version = "0.4.0-alpha.13" # VERSION_BUMP +version = "0.4.0-alpha.14" # VERSION_BUMP [lib] name = "startos" diff --git a/core/startos/src/db/model/public.rs b/core/startos/src/db/model/public.rs index f16125ae9..8aca6ceef 100644 --- a/core/startos/src/db/model/public.rs +++ b/core/startos/src/db/model/public.rs @@ -260,11 +260,7 @@ impl NetworkInterfaceInfo { } pub fn secure(&self) -> bool { - self.secure.unwrap_or_else(|| { - self.ip_info.as_ref().map_or(false, |ip_info| { - ip_info.device_type == Some(NetworkInterfaceType::Wireguard) - }) && !self.public() - }) + self.secure.unwrap_or(false) } } diff --git a/core/startos/src/lxc/mod.rs b/core/startos/src/lxc/mod.rs index 869e58c09..0a9a12f90 100644 --- a/core/startos/src/lxc/mod.rs +++ b/core/startos/src/lxc/mod.rs @@ -366,6 +366,7 @@ impl LxcContainer { } tokio::time::sleep(Duration::from_millis(100)).await; } + tracing::info!("Connected to socket in {:?}", started.elapsed()); Ok(UnixRpcClient::new(sock_path)) } } diff --git a/core/startos/src/net/tor/ctor.rs b/core/startos/src/net/tor/ctor.rs index e956e551e..a03945942 100644 --- a/core/startos/src/net/tor/ctor.rs +++ b/core/startos/src/net/tor/ctor.rs @@ -649,16 +649,6 @@ async fn torctl( .invoke(ErrorKind::Tor) .await?; - let logs = journalctl( - LogSource::Unit(SYSTEMD_UNIT), - Some(0), - None, - Some("0"), - false, - true, - ) - .await?; - let mut tcp_stream = None; for _ in 0..60 { if let Ok(conn) = TcpStream::connect(tor_control).await { @@ -720,7 +710,7 @@ async fn torctl( ErrorKind::Tor, )); } - Ok((connection, logs)) + Ok(connection) }; let pre_handler = async { while let Some(command) = recv.recv().await { @@ -745,7 +735,7 @@ async fn torctl( Ok(()) }; - let (mut connection, mut logs) = tokio::select! { + let mut connection = tokio::select! { res = bootstrap => res?, res = pre_handler => return res, }; @@ -851,46 +841,59 @@ async fn torctl( Ok(()) }; let log_parser = async { - while let Some(log) = logs.try_next().await? { - for (regex, severity) in &*LOG_REGEXES { - if regex.is_match(&log.message) { - let (check, wipe_state) = match severity { - ErrorLogSeverity::Fatal { wipe_state } => (false, *wipe_state), - ErrorLogSeverity::Unknown { wipe_state } => (true, *wipe_state), - }; - let addr = hck_key.public().get_onion_address().to_string(); - if !check - || TcpStream::connect(tor_socks) - .map_err(|e| Error::new(e, ErrorKind::Tor)) - .and_then(|mut tor_socks| async move { - tokio::time::timeout( - Duration::from_secs(30), - socks5_impl::client::connect(&mut tor_socks, (addr, 80), None) - .map_err(|e| Error::new(e, ErrorKind::Tor)), - ) + loop { + let mut logs = journalctl( + LogSource::Unit(SYSTEMD_UNIT), + Some(0), + None, + Some("0"), + false, + true, + ) + .await?; + while let Some(log) = logs.try_next().await? { + for (regex, severity) in &*LOG_REGEXES { + if regex.is_match(&log.message) { + let (check, wipe_state) = match severity { + ErrorLogSeverity::Fatal { wipe_state } => (false, *wipe_state), + ErrorLogSeverity::Unknown { wipe_state } => (true, *wipe_state), + }; + let addr = hck_key.public().get_onion_address().to_string(); + if !check + || TcpStream::connect(tor_socks) .map_err(|e| Error::new(e, ErrorKind::Tor)) - .await? - }) - .await - .with_ctx(|_| (ErrorKind::Tor, "Tor is confirmed to be down")) - .log_err() - .is_some() - { - if wipe_state { - Command::new("systemctl") - .arg("stop") - .arg("tor") - .invoke(ErrorKind::Tor) - .await?; - tokio::fs::remove_dir_all("/var/lib/tor").await?; + .and_then(|mut tor_socks| async move { + tokio::time::timeout( + Duration::from_secs(30), + socks5_impl::client::connect( + &mut tor_socks, + (addr, 80), + None, + ) + .map_err(|e| Error::new(e, ErrorKind::Tor)), + ) + .map_err(|e| Error::new(e, ErrorKind::Tor)) + .await? + }) + .await + .with_ctx(|_| (ErrorKind::Tor, "Tor is confirmed to be down")) + .log_err() + .is_some() + { + if wipe_state { + Command::new("systemctl") + .arg("stop") + .arg("tor") + .invoke(ErrorKind::Tor) + .await?; + tokio::fs::remove_dir_all("/var/lib/tor").await?; + } + return Err(Error::new(eyre!("{}", log.message), ErrorKind::Tor)); } - return Err(Error::new(eyre!("{}", log.message), ErrorKind::Tor)); } } } } - // Err(Error::new(eyre!("Log stream terminated"), ErrorKind::Tor)) - Ok(()) }; let health_checker = async { let mut last_success = Instant::now(); @@ -960,20 +963,23 @@ impl TorControl { _thread: tokio::spawn(async move { let wipe_state = AtomicBool::new(false); let mut health_timeout = Duration::from_secs(STARTING_HEALTH_TIMEOUT); - while let Err(e) = torctl( - tor_control, - tor_socks, - &mut recv, - &mut thread_services, - &wipe_state, - &mut health_timeout, - ) - .await - { - tracing::error!("{e}: Restarting tor"); - tracing::debug!("{e:?}"); + loop { + if let Err(e) = torctl( + tor_control, + tor_socks, + &mut recv, + &mut thread_services, + &wipe_state, + &mut health_timeout, + ) + .await + { + tracing::error!("TorControl : {e}"); + tracing::debug!("{e:?}"); + } + tracing::info!("Restarting Tor"); + tokio::time::sleep(Duration::from_secs(1)).await; } - tracing::info!("TorControl is shut down.") }) .into(), send, diff --git a/core/startos/src/service/effects/subcontainer/sync.rs b/core/startos/src/service/effects/subcontainer/sync.rs index 6e4930c40..73d7ff6e1 100644 --- a/core/startos/src/service/effects/subcontainer/sync.rs +++ b/core/startos/src/service/effects/subcontainer/sync.rs @@ -106,7 +106,9 @@ pub struct ExecParams { #[arg(long)] pty_size: Option, #[arg(short, long)] - env: Option, + env: Vec, + #[arg(long)] + env_file: Option, #[arg(short, long)] workdir: Option, #[arg(short, long)] @@ -119,6 +121,7 @@ impl ExecParams { fn exec(&self) -> Result<(), Error> { let ExecParams { env, + env_file, workdir, user, chroot, @@ -131,14 +134,15 @@ impl ExecParams { ErrorKind::InvalidRequest, )); }; - let env_string = if let Some(env) = &env { - std::fs::read_to_string(env) + let env_string = if let Some(env_file) = &env_file { + std::fs::read_to_string(env_file) .with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("read {env:?}")))? } else { Default::default() }; let env = env_string .lines() + .chain(env.iter().map(|l| l.as_str())) .map(|l| l.trim()) .filter_map(|l| l.split_once("=")) .collect::>(); @@ -199,6 +203,7 @@ pub fn launch( force_stderr_tty, pty_size, env, + env_file, workdir, user, chroot, @@ -294,8 +299,11 @@ pub fn launch( let (pty, pts) = pty_process::open().with_kind(ErrorKind::Filesystem)?; let mut cmd = pty_process::Command::new("/usr/bin/start-container"); cmd = cmd.arg("subcontainer").arg("launch-init"); - if let Some(env) = env { - cmd = cmd.arg("--env").arg(env); + for env in env { + cmd = cmd.arg("-e").arg(env) + } + if let Some(env_file) = env_file { + cmd = cmd.arg("--env-file").arg(env_file); } if let Some(workdir) = workdir { cmd = cmd.arg("--workdir").arg(workdir); @@ -349,8 +357,11 @@ pub fn launch( } else { let mut cmd = StdCommand::new("/usr/bin/start-container"); cmd.arg("subcontainer").arg("launch-init"); - if let Some(env) = env { - cmd.arg("--env").arg(env); + for env in env { + cmd.arg("-e").arg(env); + } + if let Some(env_file) = env_file { + cmd.arg("--env-file").arg(env_file); } if let Some(workdir) = workdir { cmd.arg("--workdir").arg(workdir); @@ -441,6 +452,7 @@ pub fn exec( force_stderr_tty, pty_size, env, + env_file, workdir, user, chroot, @@ -544,8 +556,11 @@ pub fn exec( let (pty, pts) = pty_process::open().with_kind(ErrorKind::Filesystem)?; let mut cmd = pty_process::Command::new("/usr/bin/start-container"); cmd = cmd.arg("subcontainer").arg("exec-command"); - if let Some(env) = env { - cmd = cmd.arg("--env").arg(env); + for env in env { + cmd = cmd.arg("-e").arg(env); + } + if let Some(env_file) = env_file { + cmd = cmd.arg("--env-file").arg(env_file); } if let Some(workdir) = workdir { cmd = cmd.arg("--workdir").arg(workdir); @@ -599,8 +614,11 @@ pub fn exec( } else { let mut cmd = StdCommand::new("/usr/bin/start-container"); cmd.arg("subcontainer").arg("exec-command"); - if let Some(env) = env { - cmd.arg("--env").arg(env); + for env in env { + cmd.arg("-e").arg(env); + } + if let Some(env_file) = env_file { + cmd.arg("--env-file").arg(env_file); } if let Some(workdir) = workdir { cmd.arg("--workdir").arg(workdir); diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index 9f8621d2a..e2a93d7e4 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -885,7 +885,7 @@ pub async fn attach( .arg("start-container") .arg("subcontainer") .arg("exec") - .arg("--env") + .arg("--env-file") .arg( Path::new("/media/startos/images") .join(image_id) diff --git a/core/startos/src/service/persistent_container.rs b/core/startos/src/service/persistent_container.rs index 28fcb0687..80f764a00 100644 --- a/core/startos/src/service/persistent_container.rs +++ b/core/startos/src/service/persistent_container.rs @@ -43,7 +43,7 @@ use crate::util::rpc_client::UnixRpcClient; use crate::volume::data_dir; use crate::{ARCH, DATA_DIR, PACKAGE_DATA}; -const RPC_CONNECT_TIMEOUT: Duration = Duration::from_secs(10); +const RPC_CONNECT_TIMEOUT: Duration = Duration::from_secs(30); #[derive(Debug)] pub struct ServiceState { diff --git a/core/startos/src/service/service_map.rs b/core/startos/src/service/service_map.rs index 355ef8316..18ed115bc 100644 --- a/core/startos/src/service/service_map.rs +++ b/core/startos/src/service/service_map.rs @@ -117,6 +117,8 @@ impl ServiceMap { match Service::load(ctx, id, disposition).await { Ok(s) => *service = s.into(), Err(e) => { + tracing::error!("Error loading service: {e}"); + tracing::debug!("{e:?}"); let e = ErrorData::from(e); ctx.db .mutate(|db| { diff --git a/core/startos/src/tunnel/auth.rs b/core/startos/src/tunnel/auth.rs index 62b960f96..327049bb3 100644 --- a/core/startos/src/tunnel/auth.rs +++ b/core/startos/src/tunnel/auth.rs @@ -3,7 +3,7 @@ use imbl::HashMap; use imbl_value::InternedString; use itertools::Itertools; use patch_db::HasModel; -use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; +use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async}; use serde::{Deserialize, Serialize}; use ts_rs::TS; @@ -113,27 +113,12 @@ impl AuthContext for TunnelContext { #[derive(Clone, Debug, Deserialize, Serialize, HasModel, TS, Parser)] #[serde(rename_all = "camelCase")] #[model = "Model"] -#[ts(export)] pub struct SignerInfo { pub name: InternedString, } pub fn auth_api() -> ParentHandler { - ParentHandler::new() - .subcommand( - "login", - from_fn_async(crate::auth::login_impl::) - .with_metadata("login", Value::Bool(true)) - .no_cli(), - ) - .subcommand( - "logout", - from_fn_async(crate::auth::logout::) - .with_metadata("get_session", Value::Bool(true)) - .no_display() - .with_about("Log out of current auth session") - .with_call_remote::(), - ) + crate::auth::auth::() .subcommand("set-password", from_fn_async(set_password_rpc).no_cli()) .subcommand( "set-password", @@ -173,19 +158,15 @@ pub fn auth_api() -> ParentHandler { .with_display_serializable() .with_custom_display_fn(|HandlerArgs { params, .. }, res| { use prettytable::*; - if let Some(format) = params.format { return display_serializable(format, res); } - let mut table = Table::new(); table.add_row(row![bc => "NAME", "KEY"]); for (key, info) in res { table.add_row(row![info.name, key]); } - table.print_tty(false)?; - Ok(()) }) .with_about("List authorized keys") @@ -194,7 +175,7 @@ pub fn auth_api() -> ParentHandler { ) } -#[derive(Debug, Deserialize, Serialize, Parser)] +#[derive(Debug, Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] pub struct AddKeyParams { pub name: InternedString, @@ -216,7 +197,7 @@ pub async fn add_key( .result } -#[derive(Debug, Deserialize, Serialize, Parser)] +#[derive(Debug, Deserialize, Serialize, Parser, TS)] #[serde(rename_all = "camelCase")] pub struct RemoveKeyParams { pub key: AnyVerifyingKey, @@ -240,7 +221,7 @@ pub async fn list_keys(ctx: TunnelContext) -> Result), V0_4_0_alpha_11(Wrapper), V0_4_0_alpha_12(Wrapper), - V0_4_0_alpha_13(Wrapper), // VERSION_BUMP + V0_4_0_alpha_13(Wrapper), + V0_4_0_alpha_14(Wrapper), // VERSION_BUMP Other(exver::Version), } @@ -225,7 +227,8 @@ impl Version { Self::V0_4_0_alpha_10(v) => DynVersion(Box::new(v.0)), Self::V0_4_0_alpha_11(v) => DynVersion(Box::new(v.0)), Self::V0_4_0_alpha_12(v) => DynVersion(Box::new(v.0)), - Self::V0_4_0_alpha_13(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP + Self::V0_4_0_alpha_13(v) => DynVersion(Box::new(v.0)), + Self::V0_4_0_alpha_14(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP Self::Other(v) => { return Err(Error::new( eyre!("unknown version {v}"), @@ -273,7 +276,8 @@ impl Version { Version::V0_4_0_alpha_10(Wrapper(x)) => x.semver(), Version::V0_4_0_alpha_11(Wrapper(x)) => x.semver(), Version::V0_4_0_alpha_12(Wrapper(x)) => x.semver(), - Version::V0_4_0_alpha_13(Wrapper(x)) => x.semver(), // VERSION_BUMP + Version::V0_4_0_alpha_13(Wrapper(x)) => x.semver(), + Version::V0_4_0_alpha_14(Wrapper(x)) => x.semver(), // VERSION_BUMP Version::Other(x) => x.clone(), } } diff --git a/core/startos/src/version/v0_4_0_alpha_12.rs b/core/startos/src/version/v0_4_0_alpha_12.rs index 95b210ce9..5ff6cd4d2 100644 --- a/core/startos/src/version/v0_4_0_alpha_12.rs +++ b/core/startos/src/version/v0_4_0_alpha_12.rs @@ -4,7 +4,7 @@ use exver::{PreReleaseSegment, VersionRange}; use imbl_value::InternedString; use super::v0_3_5::V0_3_0_COMPAT; -use super::{VersionT, v0_4_0_alpha_11}; +use super::{v0_4_0_alpha_11, VersionT}; use crate::net::tor::TorSecretKey; use crate::prelude::*; @@ -75,7 +75,10 @@ impl VersionT for Version { } fix_host(&mut db["public"]["serverInfo"]["network"]["host"])?; - db["private"]["keyStore"]["localCerts"] = db["private"]["keyStore"]["local_certs"].clone(); + if db["private"]["keyStore"]["localCerts"].is_null() { + db["private"]["keyStore"]["localCerts"] = + db["private"]["keyStore"]["local_certs"].clone(); + } Ok(Value::Null) } diff --git a/core/startos/src/version/v0_4_0_alpha_14.rs b/core/startos/src/version/v0_4_0_alpha_14.rs new file mode 100644 index 000000000..7c75dd66a --- /dev/null +++ b/core/startos/src/version/v0_4_0_alpha_14.rs @@ -0,0 +1,37 @@ +use exver::{PreReleaseSegment, VersionRange}; + +use super::v0_3_5::V0_3_0_COMPAT; +use super::{VersionT, v0_4_0_alpha_13}; +use crate::prelude::*; + +lazy_static::lazy_static! { + static ref V0_4_0_alpha_14: exver::Version = exver::Version::new( + [0, 4, 0], + [PreReleaseSegment::String("alpha".into()), 14.into()] + ); +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct Version; + +impl VersionT for Version { + type Previous = v0_4_0_alpha_13::Version; + type PreUpRes = (); + + async fn pre_up(self) -> Result { + Ok(()) + } + fn semver(self) -> exver::Version { + V0_4_0_alpha_14.clone() + } + fn compat(self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + #[instrument(skip_all)] + fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result { + Ok(Value::Null) + } + fn down(self, _db: &mut Value) -> Result<(), Error> { + Ok(()) + } +} diff --git a/sdk/base/lib/osBindings/SignerInfo.ts b/sdk/base/lib/osBindings/SignerInfo.ts index 76cbdafce..7e7aa2588 100644 --- a/sdk/base/lib/osBindings/SignerInfo.ts +++ b/sdk/base/lib/osBindings/SignerInfo.ts @@ -1,3 +1,9 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AnyVerifyingKey } from "./AnyVerifyingKey" +import type { ContactInfo } from "./ContactInfo" -export type SignerInfo = { name: string } +export type SignerInfo = { + name: string + contact: Array + keys: Array +} diff --git a/sdk/base/lib/util/getServiceInterface.ts b/sdk/base/lib/util/getServiceInterface.ts index 8106843fa..6fbe18f95 100644 --- a/sdk/base/lib/util/getServiceInterface.ts +++ b/sdk/base/lib/util/getServiceInterface.ts @@ -3,7 +3,7 @@ import { knownProtocols } from "../interfaces/Host" import { AddressInfo, Host, Hostname, HostnameInfo } from "../types" import { Effects } from "../Effects" import { DropGenerator, DropPromise } from "./Drop" -import { IPV6_LINK_LOCAL } from "./ip" +import { IpAddress, IPV6_LINK_LOCAL } from "./ip" export type UrlString = string export type HostId = string @@ -17,7 +17,15 @@ export const getHostname = (url: string): Hostname | null => { return last } -type FilterKinds = "onion" | "local" | "domain" | "ip" | "ipv4" | "ipv6" +type FilterKinds = + | "onion" + | "local" + | "domain" + | "ip" + | "ipv4" + | "ipv6" + | "localhost" + | "link-local" export type Filter = { visibility?: "public" | "private" kind?: FilterKinds | FilterKinds[] @@ -72,6 +80,12 @@ type FilterReturnTy = F extends { : Exclude> : HostnameInfo +const defaultFilter = { + exclude: { + kind: ["localhost", "link-local"] as ("localhost" | "link-local")[], + }, +} + type Formats = "hostname-info" | "urlstring" | "url" type FormatReturnTy< F extends Filter, @@ -92,8 +106,11 @@ export type Filled = { sslUrl: UrlString | null } - filter: ( - filter: F, + filter: < + F extends Filter = typeof defaultFilter, + Format extends Formats = "urlstring", + >( + filter?: F, format?: Format, ) => FormatReturnTy[] @@ -215,7 +232,13 @@ function filterRec( h.kind === "ip" && h.hostname.kind === "domain") || (kind.has("ipv4") && h.kind === "ip" && h.hostname.kind === "ipv4") || - (kind.has("ipv6") && h.kind === "ip" && h.hostname.kind === "ipv6")), + (kind.has("ipv6") && h.kind === "ip" && h.hostname.kind === "ipv6") || + (kind.has("localhost") && + ["localhost", "127.0.0.1", "[::1]"].includes(h.hostname.value)) || + (kind.has("link-local") && + h.kind === "ip" && + h.hostname.kind === "ipv6" && + IPV6_LINK_LOCAL.contains(IpAddress.parse(h.hostname.value)))), ) } @@ -239,11 +262,14 @@ export const filledAddress = ( ...addressInfo, hostnames, toUrls, - filter: ( - filter: F, + filter: < + F extends Filter = typeof defaultFilter, + Format extends Formats = "urlstring", + >( + filter?: F, format?: Format, ) => { - const filtered = filterRec(hostnames, filter, false) + const filtered = filterRec(hostnames, filter ?? defaultFilter, false) let res: FormatReturnTy[] = filtered as any if (format === "hostname-info") return res const urls = filtered.flatMap(toUrlArray) diff --git a/sdk/package/lib/StartSdk.ts b/sdk/package/lib/StartSdk.ts index 8ad2b3b3b..6045dc961 100644 --- a/sdk/package/lib/StartSdk.ts +++ b/sdk/package/lib/StartSdk.ts @@ -61,7 +61,7 @@ import { } from "../../base/lib/inits" import { DropGenerator } from "../../base/lib/util/Drop" -export const OSVersion = testTypeVersion("0.4.0-alpha.13") +export const OSVersion = testTypeVersion("0.4.0-alpha.14") // prettier-ignore type AnyNeverCond = diff --git a/sdk/package/lib/util/SubContainer.ts b/sdk/package/lib/util/SubContainer.ts index afa7cc14a..879c6bafb 100644 --- a/sdk/package/lib/util/SubContainer.ts +++ b/sdk/package/lib/util/SubContainer.ts @@ -410,12 +410,17 @@ export class SubContainerOwned< workdir = options.cwd delete options.cwd } + if (options?.env) { + for (let [k, v] of Object.entries(options.env)) { + extra.push(`--env=${k}=${v}`) + } + } const child = cp.spawn( "start-container", [ "subcontainer", "exec", - `--env=/media/startos/images/${this.imageId}.env`, + `--env-file=/media/startos/images/${this.imageId}.env`, `--user=${user}`, `--workdir=${workdir}`, ...extra, @@ -530,6 +535,11 @@ export class SubContainerOwned< workdir = options.cwd delete options.cwd } + if (options?.env) { + for (let [k, v] of Object.entries(options.env)) { + extra.push(`--env=${k}=${v}`) + } + } await this.killLeader() this.leaderExited = false this.leader = cp.spawn( @@ -537,7 +547,7 @@ export class SubContainerOwned< [ "subcontainer", "launch", - `--env=/media/startos/images/${this.imageId}.env`, + `--env-file=/media/startos/images/${this.imageId}.env`, `--user=${user}`, `--workdir=${workdir}`, ...extra, @@ -574,12 +584,17 @@ export class SubContainerOwned< workdir = options.cwd delete options.cwd } + if (options?.env) { + for (let [k, v] of Object.entries(options.env)) { + extra.push(`--env=${k}=${v}`) + } + } return cp.spawn( "start-container", [ "subcontainer", "exec", - `--env=/media/startos/images/${this.imageId}.env`, + `--env-file=/media/startos/images/${this.imageId}.env`, `--user=${user}`, `--workdir=${workdir}`, ...extra, diff --git a/sdk/package/package-lock.json b/sdk/package/package-lock.json index e2a15252b..3c8e890be 100644 --- a/sdk/package/package-lock.json +++ b/sdk/package/package-lock.json @@ -1,12 +1,12 @@ { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.43", + "version": "0.4.0-beta.44", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.43", + "version": "0.4.0-beta.44", "license": "MIT", "dependencies": { "@iarna/toml": "^3.0.0", @@ -98,6 +98,7 @@ "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.0", @@ -1643,6 +1644,7 @@ "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.20.0" } @@ -1944,6 +1946,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001669", "electron-to-chromium": "^1.5.41", @@ -3053,6 +3056,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -4157,6 +4161,7 @@ "integrity": "sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "commander": "^10.0.0", "source-map-generator": "0.8.0" @@ -4833,6 +4838,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -4953,6 +4959,7 @@ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/sdk/package/package.json b/sdk/package/package.json index fcbed7bfc..21fdfa803 100644 --- a/sdk/package/package.json +++ b/sdk/package/package.json @@ -1,6 +1,6 @@ { "name": "@start9labs/start-sdk", - "version": "0.4.0-beta.43", + "version": "0.4.0-beta.44", "description": "Software development kit to facilitate packaging services for StartOS", "main": "./package/lib/index.js", "types": "./package/lib/index.d.ts", diff --git a/web/package-lock.json b/web/package-lock.json index 24f189f93..c84f70c1d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "startos-ui", - "version": "0.4.0-alpha.13", + "version": "0.4.0-alpha.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "startos-ui", - "version": "0.4.0-alpha.13", + "version": "0.4.0-alpha.14", "license": "MIT", "dependencies": { "@angular/animations": "^20.3.0", diff --git a/web/package.json b/web/package.json index e634aae1e..16b3c3ff4 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "startos-ui", - "version": "0.4.0-alpha.13", + "version": "0.4.0-alpha.14", "author": "Start9 Labs, Inc", "homepage": "https://start9.com/", "license": "MIT", diff --git a/web/projects/ui/src/app/services/api/api.fixures.ts b/web/projects/ui/src/app/services/api/api.fixures.ts index 9924a6d43..965950794 100644 --- a/web/projects/ui/src/app/services/api/api.fixures.ts +++ b/web/projects/ui/src/app/services/api/api.fixures.ts @@ -110,7 +110,7 @@ export namespace Mock { squashfs: { aarch64: { publishedAt: '2025-04-21T20:58:48.140749883Z', - url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.13/startos-0.4.0-alpha.13-33ae46f~dev_aarch64.squashfs', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_aarch64.squashfs', commitment: { hash: '4elBFVkd/r8hNadKmKtLIs42CoPltMvKe2z3LRqkphk=', size: 1343500288, @@ -122,7 +122,7 @@ export namespace Mock { }, 'aarch64-nonfree': { publishedAt: '2025-04-21T21:07:00.249285116Z', - url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.13/startos-0.4.0-alpha.13-33ae46f~dev_aarch64-nonfree.squashfs', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_aarch64-nonfree.squashfs', commitment: { hash: 'MrCEi4jxbmPS7zAiGk/JSKlMsiuKqQy6RbYOxlGHOIQ=', size: 1653075968, @@ -134,7 +134,7 @@ export namespace Mock { }, raspberrypi: { publishedAt: '2025-04-21T21:16:12.933319237Z', - url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.13/startos-0.4.0-alpha.13-33ae46f~dev_raspberrypi.squashfs', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_raspberrypi.squashfs', commitment: { hash: '/XTVQRCqY3RK544PgitlKu7UplXjkmzWoXUh2E4HCw0=', size: 1490731008, @@ -146,7 +146,7 @@ export namespace Mock { }, x86_64: { publishedAt: '2025-04-21T21:14:20.246908903Z', - url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.13/startos-0.4.0-alpha.13-33ae46f~dev_x86_64.squashfs', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_x86_64.squashfs', commitment: { hash: '/6romKTVQGSaOU7FqSZdw0kFyd7P+NBSYNwM3q7Fe44=', size: 1411657728, @@ -158,7 +158,7 @@ export namespace Mock { }, 'x86_64-nonfree': { publishedAt: '2025-04-21T21:15:17.955265284Z', - url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.13/startos-0.4.0-alpha.13-33ae46f~dev_x86_64-nonfree.squashfs', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.14/startos-0.4.0-alpha.14-33ae46f~dev_x86_64-nonfree.squashfs', commitment: { hash: 'HCRq9sr/0t85pMdrEgNBeM4x11zVKHszGnD1GDyZbSE=', size: 1731035136, @@ -385,7 +385,7 @@ export namespace Mock { docsUrl: 'https://bitcoin.org', releaseNotes: 'Even better support for Bitcoin and wallets!', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: BTC_ICON, sourceVersion: null, @@ -420,7 +420,7 @@ export namespace Mock { docsUrl: 'https://bitcoinknots.org', releaseNotes: 'Even better support for Bitcoin and wallets!', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: BTC_ICON, sourceVersion: null, @@ -465,7 +465,7 @@ export namespace Mock { docsUrl: 'https://bitcoin.org', releaseNotes: 'Even better support for Bitcoin and wallets!', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: BTC_ICON, sourceVersion: null, @@ -500,7 +500,7 @@ export namespace Mock { docsUrl: 'https://bitcoinknots.org', releaseNotes: 'Even better support for Bitcoin and wallets!', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: BTC_ICON, sourceVersion: null, @@ -547,7 +547,7 @@ export namespace Mock { docsUrl: 'https://lightning.engineering/', releaseNotes: 'Upstream release to 0.17.5', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: LND_ICON, sourceVersion: null, @@ -595,7 +595,7 @@ export namespace Mock { docsUrl: 'https://lightning.engineering/', releaseNotes: 'Upstream release to 0.17.4', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: LND_ICON, sourceVersion: null, @@ -647,7 +647,7 @@ export namespace Mock { docsUrl: 'https://bitcoin.org', releaseNotes: 'Even better support for Bitcoin and wallets!', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: BTC_ICON, sourceVersion: null, @@ -682,7 +682,7 @@ export namespace Mock { docsUrl: 'https://bitcoinknots.org', releaseNotes: 'Even better support for Bitcoin and wallets!', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: BTC_ICON, sourceVersion: null, @@ -727,7 +727,7 @@ export namespace Mock { docsUrl: 'https://lightning.engineering/', releaseNotes: 'Upstream release and minor fixes.', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: LND_ICON, sourceVersion: null, @@ -775,7 +775,7 @@ export namespace Mock { marketingSite: '', releaseNotes: 'Upstream release and minor fixes.', osVersion: '0.3.6', - sdkVersion: '0.4.0-beta.43', + sdkVersion: '0.4.0-beta.44', gitHash: 'fakehash', icon: PROXY_ICON, sourceVersion: null,