Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/utils/digests.py: 95.83%
24 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-10-04 17:48 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-10-04 17:48 +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
17from typing import Optional
19from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import Digest, DigestFunction
20from buildgrid.server.settings import HASH, HASH_LENGTH
23@dataclass(frozen=True)
24class HashableDigest:
25 hash: str
26 size_bytes: int
28 def to_digest(self) -> Digest:
29 return Digest(hash=self.hash, size_bytes=self.size_bytes)
32def get_hash_type() -> "DigestFunction.Value.ValueType":
33 """Returns the hash type."""
34 hash_name = HASH().name
35 if hash_name == "sha256":
36 return DigestFunction.SHA256
37 return DigestFunction.UNKNOWN
40def create_digest(bytes_to_digest: bytes) -> Digest:
41 """Computes the :obj:`Digest` of a piece of data.
43 The :obj:`Digest` of a data is a function of its hash **and** size.
45 Args:
46 bytes_to_digest (bytes): byte data to digest.
48 Returns:
49 :obj:`Digest`: The :obj:`Digest` for the given byte data.
50 """
51 return Digest(hash=HASH(bytes_to_digest).hexdigest(), size_bytes=len(bytes_to_digest))
54def parse_digest(digest_string: str) -> Optional[Digest]:
55 """Creates a :obj:`Digest` from a digest string.
57 A digest string should alway be: ``{hash}/{size_bytes}``.
59 Args:
60 digest_string (str): the digest string.
62 Returns:
63 :obj:`Digest`: The :obj:`Digest` read from the string or None if
64 `digest_string` is not a valid digest string.
65 """
66 digest_hash, digest_size = digest_string.split("/")
68 if len(digest_hash) == HASH_LENGTH and digest_size.isdigit():
69 return Digest(hash=digest_hash, size_bytes=int(digest_size))
71 return None
74def validate_digest_data(digest: Digest, data: bytes) -> bool:
75 """Validate that the given digest corresponds to the given data."""
76 return len(data) == digest.size_bytes and HASH(data).hexdigest() == digest.hash