httk.workflow.manifests ======================= .. py:module:: httk.workflow.manifests .. autoapi-nested-parse:: Deterministic signed project manifests. Attributes ---------- .. autoapisummary:: httk.workflow.manifests.MAINTENANCE_LOCK_FILE httk.workflow.manifests.MAINTENANCE_LOCK_MAX_AGE_SECONDS httk.workflow.manifests.VALID_TRUSTED httk.workflow.manifests.VALID_UNKNOWN_KEY httk.workflow.manifests.INVALID httk.workflow.manifests.VERDICT_EXIT_CODES Classes ------- .. autoapisummary:: httk.workflow.manifests.MaintenanceLock httk.workflow.manifests.ManifestVerification Functions --------- .. autoapisummary:: httk.workflow.manifests.read_maintenance_lock httk.workflow.manifests.release_maintenance_lock httk.workflow.manifests.workspace_maintenance_guard httk.workflow.manifests.create_manifest httk.workflow.manifests.resolve_trusted_keys httk.workflow.manifests.verify_v2_manifest httk.workflow.manifests.verify_legacy_manifest httk.workflow.manifests.verify_manifest Module Contents --------------- .. py:data:: MAINTENANCE_LOCK_FILE :value: 'maintenance.lock' .. py:data:: MAINTENANCE_LOCK_MAX_AGE_SECONDS :value: 86400 .. py:data:: VALID_TRUSTED :value: 'valid_trusted' .. py:data:: VALID_UNKNOWN_KEY :value: 'valid_unknown_key' .. py:data:: INVALID :value: 'invalid' .. py:data:: VERDICT_EXIT_CODES .. py:class:: MaintenanceLock Recorded holder of one workspace maintenance lock. .. py:attribute:: path :type: pathlib.Path .. py:attribute:: pid :type: int | None .. py:attribute:: hostname :type: str | None .. py:attribute:: created :type: str | None .. py:property:: age_seconds :type: float | None Age of the lock, or ``None`` when its timestamp is unusable. .. py:property:: local :type: bool Whether the recorded host is the host inspecting the lock. .. py:property:: dead :type: bool Whether a same-host holder process is known to be gone. .. py:method:: is_stale(*, max_age_seconds: float = MAINTENANCE_LOCK_MAX_AGE_SECONDS) -> bool Whether the lock can be reclaimed without operator confirmation. .. py:method:: describe() -> str Describe the holder for an operator diagnostic. .. py:function:: read_maintenance_lock(workspace: httk.workflow.workspace.Workspace) -> MaintenanceLock | None Describe the workspace maintenance lock, or ``None`` when it is absent. .. py:function:: release_maintenance_lock(workspace: httk.workflow.workspace.Workspace, *, force: bool = False) -> str Remove a stale, or with *force* any, maintenance lock and report it. .. py:function:: workspace_maintenance_guard(workspace: httk.workflow.workspace.Workspace) -> collections.abc.Iterator[None] Fence manager launches while a project snapshot is inspected. .. py:function:: create_manifest(project: str | os.PathLike[str] | None = None, *, output: str | os.PathLike[str] | None = None) -> pathlib.Path Create and atomically publish the signed v2 project manifest. .. py:class:: ManifestVerification What verifying one manifest against one tree established. A signature check answers two separate questions, and reporting them as one boolean loses the interesting one. *Does this manifest describe this tree, unaltered?* is answered by the digests and the signature. *Was it made by somebody this project trusts?* is answered only by comparing the signing key with a trust anchor that did not come from the manifest itself. .. py:attribute:: verdict :type: str .. py:attribute:: reason :type: str .. py:attribute:: manifest :type: pathlib.Path .. py:attribute:: manifest_format :type: str .. py:attribute:: public_key :type: str | None :value: None .. py:attribute:: trusted_keys :type: tuple[str, Ellipsis] :value: () .. py:property:: valid :type: bool Whether the manifest describes this tree and its signature verified. .. py:property:: trusted :type: bool Whether the verified signature was made by a pinned key. .. py:property:: exit_code :type: int The command-line status this verdict reports. .. py:method:: as_mapping() -> dict[str, object] Return the JSON representation of this verdict. .. py:function:: resolve_trusted_keys(project: str | os.PathLike[str] | None = None, *, trusted_keys: collections.abc.Sequence[str | os.PathLike[str]] | None = None) -> tuple[str, Ellipsis] Return the trust anchors of *project* plus every explicitly named key. An entry of *trusted_keys* is either a recorded key — ``ed25519:BASE64`` or the bare base64 — or the path of a ``*.pub`` file holding one. .. py:function:: verify_v2_manifest(root: pathlib.Path, path: pathlib.Path) -> bool Report whether a v2 manifest describes *root* and its signature verifies. This deliberately says nothing about *whose* key signed it: the key comes out of the manifest header. Use :func:`verify_manifest` for the trust decision. .. py:function:: verify_legacy_manifest(root: pathlib.Path, path: pathlib.Path) -> bool Verify a legacy manifest without modifying its project tree. .. py:function:: verify_manifest(project: str | os.PathLike[str] | None = None, *, manifest: str | os.PathLike[str] | None = None, trusted_keys: collections.abc.Sequence[str | os.PathLike[str]] | None = None) -> ManifestVerification Auto-detect a v2 or legacy manifest and verify it against its trust anchors. The trust anchor is the key pinned in ``project.json`` — never the key the manifest being verified names in its own header — plus any key passed in *trusted_keys*, as a recorded value or as the path of a ``*.pub`` file.