Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,21 @@ jobs:
- name: Install dependencies
run: poetry install --no-interaction --no-root

- name: Build binary
- name: Build default binary
run: poetry run pyinstaller -F --distpath ./app/bundled_app/linux --specpath ./app/build/linux --workpath ./app/build/linux --paths=./.venv/lib/python3.9/site-packages ./app/pilotcli.py -n ${{ github.sha }}

- name: Rename output file
- name: Rename default output file
run: mv "./app/bundled_app/linux/${{ github.sha }}" "./app/bundled_app/linux/pilotcli_linux"

- name: Enable cloud mode
run: touch ./app/ENABLE_CLOUD_MODE

- name: Build cloud binary
run: poetry run pyinstaller -F --distpath ./app/bundled_app/linux --specpath ./app/build/linux --workpath ./app/build/linux --paths=./.venv/lib/python3.9/site-packages --add-binary=$(pwd)/app/ENABLE_CLOUD_MODE:. ./app/pilotcli.py -n ${{ github.sha }}

- name: Rename cloud output file
run: mv "./app/bundled_app/linux/${{ github.sha }}" "./app/bundled_app/linux/pilotcli_cloud"

- name: Set version in env
run: poetry run echo "TAG_VERSION=`poetry version --short`" >> $GITHUB_ENV

Expand All @@ -82,7 +91,9 @@ jobs:
draft: false
prerelease: false
target_commitish: ${{ needs.extract-branch-name.outputs.branch }}
files: ./app/bundled_app/linux/pilotcli_linux
files: |
./app/bundled_app/linux/pilotcli_linux
./app/bundled_app/linux/pilotcli_cloud

push-binary-macos:
needs: [ push-binary-linux ]
Expand Down
24 changes: 21 additions & 3 deletions app/configs/user_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import configparser
import os
import stat
import sys
import time
from pathlib import Path
from typing import Iterable
Expand All @@ -26,11 +27,27 @@ class UserConfig(metaclass=Singleton):
This user config is global.
"""

def __init__(self, config_path: Union[str, Path, None] = None, config_filename: Union[str, None] = None) -> None:
def __init__(
self,
config_path: Union[str, Path, None] = None,
config_filename: Union[str, None] = None,
is_cloud_mode: Union[bool, None] = None,
) -> None:
"""When `is_cloud_mode` is enabled, it omits the checks for file or folder ownership and correct access mode for
the user.

This adjustment is made to prevent complications with mounted NFS volumes where all files have root ownership.
"""

if config_path is None:
config_path = ConfigClass.config_path
if config_filename is None:
config_filename = ConfigClass.config_file
if is_cloud_mode is None:
# Check when code is bundled using pyinstaller
# https://pyinstaller.org/en/stable/runtime-information.html#run-time-information
is_bundled = getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS')
is_cloud_mode = is_bundled and (Path(sys._MEIPASS) / 'ENABLE_CLOUD_MODE').is_file()

config_path = Path(config_path)
if not config_path.exists():
Expand All @@ -39,7 +56,7 @@ def __init__(self, config_path: Union[str, Path, None] = None, config_filename:
current_user_id = os.geteuid()

error = self._check_user_permissions(config_path, current_user_id, (0o0500, 0o0700))
if error:
if error and not is_cloud_mode:
SrvErrorHandler.customized_handle(ECustomizedError.CONFIG_INVALID_PERMISSIONS, True, error)
return

Expand All @@ -48,10 +65,11 @@ def __init__(self, config_path: Union[str, Path, None] = None, config_filename:
config_file.touch(mode=0o0600, exist_ok=False)

error = self._check_user_permissions(config_file, current_user_id, (0o0400, 0o0600))
if error:
if error and not is_cloud_mode:
SrvErrorHandler.customized_handle(ECustomizedError.CONFIG_INVALID_PERMISSIONS, True, error)
return

self.is_cloud_mode = is_cloud_mode
self.config_file = config_file
self.config = configparser.ConfigParser()
self.config.read(self.config_file)
Expand Down
40 changes: 40 additions & 0 deletions tests/app/configs/test_user_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
import stat
import sys

import pytest

Expand Down Expand Up @@ -73,3 +74,42 @@ def test__init__exits_with_error_when_config_file_does_not_have_expected_access_
)

error_log.assert_called_with(expected_message)

def test__init__does_not_exit_with_error_when_config_folder_has_invalid_access_mode_and_is_cloud_mode_set_to_true(
self, tmp_path, fake
):
config_folder = tmp_path / fake.pystr()
config_folder.mkdir(mode=0o0755)

UserConfig(config_folder, is_cloud_mode=True)

def test__init__does_not_exit_with_error_when_config_file_has_invalid_access_mode_and_is_cloud_mode_set_to_true(
self, tmp_path, fake
):
config_folder = tmp_path / fake.pystr()
file_name = fake.pystr()
config_file = config_folder / file_name
config_folder.mkdir(mode=0o0700)
config_file.touch(mode=0o0644)

UserConfig(config_folder, file_name, is_cloud_mode=True)

def test__init__sets_is_cloud_mode_to_false_by_default(self, tmp_path, fake):
config_folder = tmp_path / fake.pystr()

user_config = UserConfig(config_folder)

assert user_config.is_cloud_mode is False

def test__init__sets_is_cloud_mode_to_true_when_pyinstaller_bundle_params_are_set_and_cloud_mode_file_is_present(
self, tmp_path, monkeypatch
):
monkeypatch.setattr(sys, 'frozen', True, raising=False)
monkeypatch.setattr(sys, '_MEIPASS', str(tmp_path), raising=False)

cloud_mode_file = tmp_path / 'ENABLE_CLOUD_MODE'
cloud_mode_file.touch()

user_config = UserConfig()

assert user_config.is_cloud_mode is True