Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/utils/digests.py: 95.65%
23 statements
« prev ^ index » next coverage.py v7.4.1, created at 2025-02-11 15:07 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2025-02-11 15:07 +0000
1# Copyright (C) 2024 Bloomberg LP
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# <http://www.apache.org/licenses/LICENSE-2.0>
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
16from dataclasses import dataclass
18from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import Digest, DigestFunction
19from buildgrid.server.settings import HASH, HASH_LENGTH
22@dataclass(frozen=True)
23class HashableDigest:
24 hash: str
25 size_bytes: int
27 def to_digest(self) -> Digest:
28 return Digest(hash=self.hash, size_bytes=self.size_bytes)
31def get_hash_type() -> "DigestFunction.Value.ValueType":
32 """Returns the hash type."""
33 hash_name = HASH().name
34 if hash_name == "sha256":
35 return DigestFunction.SHA256
36 return DigestFunction.UNKNOWN
39def create_digest(bytes_to_digest: bytes) -> Digest:
40 """Computes the :obj:`Digest` of a piece of data.
42 The :obj:`Digest` of a data is a function of its hash **and** size.
44 Args:
45 bytes_to_digest (bytes): byte data to digest.
47 Returns:
48 :obj:`Digest`: The :obj:`Digest` for the given byte data.
49 """
50 return Digest(hash=HASH(bytes_to_digest).hexdigest(), size_bytes=len(bytes_to_digest))
53def parse_digest(digest_string: str) -> Digest | None:
54 """Creates a :obj:`Digest` from a digest string.
56 A digest string should alway be: ``{hash}/{size_bytes}``.
58 Args:
59 digest_string (str): the digest string.
61 Returns:
62 :obj:`Digest`: The :obj:`Digest` read from the string or None if
63 `digest_string` is not a valid digest string.
64 """
65 digest_hash, digest_size = digest_string.split("/")
67 if len(digest_hash) == HASH_LENGTH and digest_size.isdigit():
68 return Digest(hash=digest_hash, size_bytes=int(digest_size))
70 return None
73def validate_digest_data(digest: Digest, data: bytes) -> bool:
74 """Validate that the given digest corresponds to the given data."""
75 return len(data) == digest.size_bytes and HASH(data).hexdigest() == digest.hash