fix(node): make environment progress readable from the desktop
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": "missioncore.node.environment/v1",
|
||||
"revision": "ubuntu-24.04-amd64/1",
|
||||
"revision": "ubuntu-24.04-amd64/2",
|
||||
"steps": [
|
||||
{"id":"platform","label":"Проверка системы","description":"Операционная система и архитектура БК","requires":[]},
|
||||
{"id":"packages","label":"Установка системных пакетов","description":"OpenSSH Server и зависимости окружения","requires":["platform"]},
|
||||
|
||||
@@ -13,7 +13,7 @@ import tarfile
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
VERSION = "0.4.0"
|
||||
VERSION = "0.4.1"
|
||||
BRAND_SHA256 = "8bfee8ca9f98e0db48d98aae3af4b32493b8593e18b064a0239d513d824182af"
|
||||
|
||||
|
||||
|
||||
@@ -38,10 +38,16 @@ def command(argv, *, timeout=15):
|
||||
|
||||
|
||||
def trusted_directory(path, mode=0o755):
|
||||
created = not path.exists() and not path.is_symlink()
|
||||
path.mkdir(mode=mode, parents=True, exist_ok=True)
|
||||
info = path.lstat()
|
||||
if not stat.S_ISDIR(info.st_mode) or info.st_uid != 0 or info.st_mode & 0o022:
|
||||
raise SetupError("Каталог настройки имеет неподходящие права. Переустановите пакет Node через интерфейс системы.")
|
||||
# umask 0077 must protect working files, but this nonsensitive report and
|
||||
# newly created configuration directories must be traversable by readers.
|
||||
# The only existing directory repaired here is our dedicated report store.
|
||||
if created or path == STATE:
|
||||
path.chmod(mode)
|
||||
|
||||
|
||||
def publish(path, data):
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Workflow acceptance boundaries without touching the host OS or credentials."""
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
from types import SimpleNamespace
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import tempfile
|
||||
@@ -98,6 +100,23 @@ class EnvironmentWorkflowTests(unittest.TestCase):
|
||||
self.assertTrue(target.is_symlink())
|
||||
self.assertEqual(template.read_bytes(), b'owned')
|
||||
|
||||
def test_restrictive_umask_does_not_hide_report_and_existing_report_dir_is_repaired(self):
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
target = Path(directory)/'report'
|
||||
with patch.object(helper, 'STATE', target), patch.object(Path, 'lstat', autospec=True, side_effect=lambda path: SimpleNamespace(st_uid=0, st_mode=os.stat(path).st_mode)):
|
||||
previous = os.umask(0o077)
|
||||
try:
|
||||
helper.trusted_directory(target)
|
||||
self.assertEqual(target.stat().st_mode & 0o777, 0o755)
|
||||
target.chmod(0o700)
|
||||
helper.trusted_directory(target)
|
||||
self.assertEqual(target.stat().st_mode & 0o777, 0o755)
|
||||
foreign = Path(directory)/'foreign'
|
||||
foreign.mkdir(mode=0o700)
|
||||
helper.trusted_directory(foreign)
|
||||
self.assertEqual(foreign.stat().st_mode & 0o777, 0o700)
|
||||
finally: os.umask(previous)
|
||||
|
||||
def test_delayed_service_start_retries_only_readiness(self):
|
||||
with patch.object(helper, 'probe_node', side_effect=[OSError('not listening'), {}]) as read, patch.object(helper.time, 'sleep'), patch.object(helper, 'command') as mutation:
|
||||
helper.wait_for_node()
|
||||
|
||||
@@ -14,11 +14,11 @@ export function EnvironmentView({environment,failure,success}: {environment:Retu
|
||||
return <div className="node-content">
|
||||
<SettingsCard title="Настройка окружения" description="Установка и проверка компонентов для работы с бортовым компьютером.">
|
||||
<p className="node-note">Сконфигурируйте окружение при первом запуске или повторите проверку после изменений. Приложение установит нужные пакеты, настроит службы и получит системные сведения. Вход в частную сеть и доверенный SSH-ключ подтверждаются ниже.</p>
|
||||
<Button onClick={start} disabled={running||!value||!environmentSetupAvailable()}>{running?"Настраиваем…":value?.run?"Проверить и сконфигурировать":"Сконфигурировать"}</Button>
|
||||
<Button onClick={start} disabled={running||!value||!environmentSetupAvailable()}>{running?"Настраиваем…":"Сконфигурировать"}</Button>
|
||||
{!environmentSetupAvailable()&&<p className="node-note">Настройка запускается из установленного приложения на БК.</p>}
|
||||
{pending&&(!value?.run||value.run.state!=="running")&&<ActivityIndicator label="Подтвердите действие в системном окне. Ожидаем начало настройки…" />}
|
||||
{!value?loading?<ActivityIndicator label="Получаем этапы настройки" />:<p className="node-note">Сведения о настройке недоступны. Обновите страницу.</p>:<>
|
||||
{!value.available&&<p className="node-note">Не удалось прочитать результат предыдущей настройки. Запустите настройку, чтобы заново проверить окружение.</p>}
|
||||
{!value.available&&<p className="node-note">Журнал предыдущего запуска недоступен. Нажмите «Сконфигурировать» — приложение восстановит доступ и выполнит этапы заново.</p>}
|
||||
<ResourceList aria-label="Этапы настройки окружения">{value.profile.steps.map(specification=>{
|
||||
const step=value.run?.steps.find(item=>item.id===specification.id);
|
||||
const state=step?.state??"pending";
|
||||
|
||||
Reference in New Issue
Block a user