fix(firmware-info): используй UTC+3 в именах папок

Переведи только время имени архива в UTC+3, сохрани UTC в метаданных и заголовке. Проверь переход на следующий день и копирование текущей папки.
This commit is contained in:
2026-10-08 17:05:04 +03:00
parent 4fc0ad4e14
commit 131f306131
3 changed files with 18 additions and 14 deletions
@@ -26,7 +26,7 @@ class ArchiveTests(unittest.TestCase):
metadata.write_text(json.dumps(self.metadata()), encoding="utf-8") metadata.write_text(json.dumps(self.metadata()), encoding="utf-8")
result = archive_build(image, metadata, root / "out") result = archive_build(image, metadata, root / "out")
folder = Path(result["directory"]) folder = Path(result["directory"])
self.assertEqual(folder.name, "a1b2c3d4_2026-10-08_12-30-00_UTC") self.assertEqual(folder.name, "a1b2c3d4_2026-10-08_15-30-00_UTC+3")
self.assertEqual((folder / image.name).read_bytes(), payload) self.assertEqual((folder / image.name).read_bytes(), payload)
self.assertEqual(image.read_bytes(), payload) self.assertEqual(image.read_bytes(), payload)
self.assertEqual(json.loads((folder / "firmware_identity.json").read_text()), self.metadata()) self.assertEqual(json.loads((folder / "firmware_identity.json").read_text()), self.metadata())
@@ -60,7 +60,7 @@ class ArchiveTests(unittest.TestCase):
result = archive_build(image, metadata, root / "local", export=root / "exported") result = archive_build(image, metadata, root / "local", export=root / "exported")
copied = Path(result["exported_directory"]) copied = Path(result["exported_directory"])
self.assertEqual([p.name for p in (root / "exported").iterdir()], self.assertEqual([p.name for p in (root / "exported").iterdir()],
["a1b2c3d4_2026-10-08_12-30-00_UTC"]) ["a1b2c3d4_2026-10-08_15-30-00_UTC+3"])
self.assertEqual((copied / image.name).read_bytes(), image.read_bytes()) self.assertEqual((copied / image.name).read_bytes(), image.read_bytes())
self.assertTrue((copied / "firmware_identity.json").is_file()) self.assertTrue((copied / "firmware_identity.json").is_file())
self.assertTrue((copied / (image.name + ".sha256")).is_file()) self.assertTrue((copied / (image.name + ".sha256")).is_file())
@@ -83,15 +83,19 @@ class ArchiveTests(unittest.TestCase):
self.assertEqual((old / "keep.txt").read_text(), "keep") self.assertEqual((old / "keep.txt").read_text(), "keep")
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
export_build(folder, folder / "recursive", image.name) export_build(folder, folder / "recursive", image.name)
def test_offset_normalizes_to_utc_and_dirty_is_visible(self): def test_offset_normalizes_to_utc_plus_three_and_dirty_is_visible(self):
metadata = self.metadata("2026-10-08T15:30:00+03:00") metadata = self.metadata("2026-10-08T15:30:00+03:00")
metadata["source"]["dirty"] = True metadata["source"]["dirty"] = True
self.assertEqual(build_folder_name(metadata), "a1b2c3d4+_2026-10-08_12-30-00_UTC") self.assertEqual(build_folder_name(metadata), "a1b2c3d4+_2026-10-08_15-30-00_UTC+3")
def test_folder_date_rolls_over_at_utc_plus_three_midnight(self):
metadata = self.metadata("2026-10-08T22:30:00+00:00")
self.assertEqual(build_folder_name(metadata), "a1b2c3d4_2026-10-09_01-30-00_UTC+3")
self.assertEqual(metadata["built_at_utc"], "2026-10-08T22:30:00+00:00")
def test_archive_without_git_has_explicit_placeholder(self): def test_archive_without_git_has_explicit_placeholder(self):
metadata = self.metadata() metadata = self.metadata()
metadata["source"]["commit"] = None metadata["source"]["commit"] = None
self.assertEqual(build_folder_name(metadata), "NOGIT000_2026-10-08_12-30-00_UTC") self.assertEqual(build_folder_name(metadata), "NOGIT000_2026-10-08_15-30-00_UTC+3")
def test_invalid_provenance_cannot_be_a_folder_name(self): def test_invalid_provenance_cannot_be_a_folder_name(self):
metadata = self.metadata() metadata = self.metadata()
+4 -4
View File
@@ -7,7 +7,7 @@ protocol encoding lives here: the generated header contains scalar constants.
from __future__ import annotations from __future__ import annotations
import argparse import argparse
from datetime import datetime, timezone from datetime import datetime, timedelta, timezone
import hashlib import hashlib
import json import json
import os import os
@@ -108,7 +108,7 @@ def verify(image: Path, manifest: Path) -> dict:
def build_folder_name(metadata: dict) -> str: def build_folder_name(metadata: dict) -> str:
"""Use the firmware commit and pre-build UTC time, never post-build time.""" """Use the firmware commit and pre-build time rendered in UTC+3."""
source = metadata.get("source") or {} source = metadata.get("source") or {}
dependency = metadata.get("templates") or {} dependency = metadata.get("templates") or {}
commit = source.get("commit") commit = source.get("commit")
@@ -128,8 +128,8 @@ def build_folder_name(metadata: dict) -> str:
stamp = datetime.fromisoformat(stamp_text.replace("Z", "+00:00")) stamp = datetime.fromisoformat(stamp_text.replace("Z", "+00:00"))
if stamp.tzinfo is None: if stamp.tzinfo is None:
raise ValueError("pre-build timestamp must include a timezone") raise ValueError("pre-build timestamp must include a timezone")
stamp = stamp.astimezone(timezone.utc) stamp = stamp.astimezone(timezone(timedelta(hours=3)))
return identity + "_" + stamp.strftime("%Y-%m-%d_%H-%M-%S_UTC") return identity + "_" + stamp.strftime("%Y-%m-%d_%H-%M-%S_UTC+3")
def export_build(folder: Path, export: Path, image_name: str) -> Path: def export_build(folder: Path, export: Path, image_name: str) -> Path:
File diff suppressed because one or more lines are too long