chore: consolidate platform split checks
Some checks failed
Dependency Audit / dependency-audit (push) Has been cancelled
Module Matrix / module-matrix (push) Has been cancelled

This commit is contained in:
2026-07-10 12:51:19 +02:00
parent 150b720f12
commit 635d25c74c
216 changed files with 23336 additions and 4077 deletions

View File

@@ -27,6 +27,7 @@ from govoplan_core.core.module_installer import (
update_module_installer_request,
update_module_installer_daemon_status,
)
from govoplan_core.core.module_license import issue_module_license, module_license_diagnostics
from govoplan_core.core.module_package_catalog import sign_module_package_catalog, validate_module_package_catalog
from govoplan_core.core.module_management import (
configured_enabled_modules,
@@ -80,10 +81,69 @@ def main() -> int:
parser.add_argument("--catalog-signing-key-id", help="Key id to record when signing a package catalog.")
parser.add_argument("--catalog-signing-private-key", type=Path, help="PEM Ed25519 private key used by --sign-package-catalog.")
parser.add_argument("--catalog-output", type=Path, help="Output path for --sign-package-catalog. Defaults to overwriting the input file.")
parser.add_argument("--validate-license", nargs="?", const="", metavar="PATH", help="Validate a license JSON file, or the configured license when PATH is omitted.")
parser.add_argument("--require-trusted-license", action="store_true", help="Require license validation to trust an Ed25519 signature.")
parser.add_argument("--license-trusted-key", action="append", default=[], metavar="KEY_ID=BASE64_PUBLIC_KEY", help="Trusted Ed25519 license public key; may be repeated.")
parser.add_argument("--license-required-feature", action="append", default=[], help="License feature to check; may be repeated.")
parser.add_argument("--issue-license", type=Path, metavar="PATH", help="Write a signed offline license JSON file.")
parser.add_argument("--license-id", help="License id for --issue-license.")
parser.add_argument("--license-subject", help="License subject/customer for --issue-license.")
parser.add_argument("--license-feature", action="append", default=[], help="Feature entitlement to include in --issue-license; may be repeated.")
parser.add_argument("--license-valid-from", help="License valid_from timestamp. Defaults to now.")
parser.add_argument("--license-valid-until", help="License valid_until timestamp.")
parser.add_argument("--license-signing-key-id", help="Signing key id for --issue-license.")
parser.add_argument("--license-signing-private-key", type=Path, help="PEM Ed25519 private key for --issue-license.")
parser.add_argument("--license-issuer", help="Optional issuer string for --issue-license.")
parser.add_argument("--license-notes", help="Optional operator note for --issue-license.")
args = parser.parse_args()
runtime_dir = args.runtime_dir or default_installer_runtime_dir(args.database_url)
try:
if args.issue_license:
if not args.license_id or not args.license_subject or not args.license_valid_until:
raise ModuleInstallerError("--issue-license requires --license-id, --license-subject, and --license-valid-until.")
if not args.license_signing_key_id or not args.license_signing_private_key:
raise ModuleInstallerError("--issue-license requires --license-signing-key-id and --license-signing-private-key.")
if not [item for item in args.license_feature if item.strip()]:
raise ModuleInstallerError("--issue-license requires at least one --license-feature.")
try:
path = issue_module_license(
path=args.issue_license,
license_id=args.license_id,
subject=args.license_subject,
features=args.license_feature,
valid_from=args.license_valid_from,
valid_until=args.license_valid_until,
signing_key_id=args.license_signing_key_id,
signing_private_key_path=args.license_signing_private_key,
issuer=args.license_issuer,
notes=args.license_notes,
)
except (OSError, ValueError) as exc:
raise ModuleInstallerError(str(exc)) from exc
_print_result(
{
"issued": True,
"path": str(path),
"license_id": args.license_id,
"subject": args.license_subject,
"features": list(dict.fromkeys(item.strip() for item in args.license_feature if item.strip())),
"valid_until": args.license_valid_until,
"key_id": args.license_signing_key_id,
},
output_format=args.format,
)
return 0
if args.validate_license is not None:
path = Path(args.validate_license).expanduser() if args.validate_license else None
result = module_license_diagnostics(
path,
require_trusted=args.require_trusted_license,
trusted_keys=_trusted_keys_from_args(args.license_trusted_key, flag_name="--license-trusted-key"),
required_features=args.license_required_feature,
)
_print_result(result, output_format=args.format)
return 0 if result.get("valid") and not result.get("missing_features") else 1
if args.sign_package_catalog:
if not args.catalog_signing_key_id or not args.catalog_signing_private_key:
raise ModuleInstallerError("--sign-package-catalog requires --catalog-signing-key-id and --catalog-signing-private-key.")
@@ -101,7 +161,7 @@ def main() -> int:
path,
require_trusted=args.require_signed_catalog,
approved_channels=tuple(args.approved_catalog_channel),
trusted_keys=_trusted_catalog_keys_from_args(args.catalog_trusted_key),
trusted_keys=_trusted_keys_from_args(args.catalog_trusted_key, flag_name="--catalog-trusted-key"),
)
_print_result(result, output_format=args.format)
return 0 if result.get("valid") else 1
@@ -322,6 +382,7 @@ def _process_request(*, request: dict[str, object], args: argparse.Namespace, ru
health_urls=_list_option(options, "health_urls") or _list_option(options, "health_url") or ([args.health_url] if args.health_url else []),
health_timeout_seconds=_float_option(options, "health_timeout_seconds", args.health_timeout_seconds),
health_interval_seconds=_float_option(options, "health_interval_seconds", args.health_interval_seconds),
request_context=_request_context(request),
)
update_module_installer_request(
runtime_dir=runtime_dir,
@@ -362,6 +423,18 @@ def _request_options_from_args(args: argparse.Namespace) -> dict[str, object]:
}
def _request_context(request: dict[str, object]) -> dict[str, object]:
context: dict[str, object] = {
"request_id": request.get("request_id"),
"requested_by": request.get("requested_by"),
}
if request.get("retry_of"):
context["retry_of"] = request["retry_of"]
if isinstance(request.get("trace"), dict):
context["trace"] = request["trace"]
return {key: value for key, value in context.items() if value is not None}
def _str_option(options: object, key: str) -> str | None:
if not isinstance(options, dict):
return None
@@ -403,14 +476,14 @@ def _list_option(options: object, key: str) -> list[str]:
return []
def _trusted_catalog_keys_from_args(values: list[str]) -> dict[str, str] | None:
def _trusted_keys_from_args(values: list[str], *, flag_name: str) -> dict[str, str] | None:
if not values:
return None
keys: dict[str, str] = {}
for value in values:
key_id, separator, public_key = value.partition("=")
if not separator or not key_id.strip() or not public_key.strip():
raise ModuleInstallerError("--catalog-trusted-key must use KEY_ID=BASE64_PUBLIC_KEY.")
raise ModuleInstallerError(f"{flag_name} must use KEY_ID=BASE64_PUBLIC_KEY.")
keys[key_id.strip()] = public_key.strip()
return keys