aboutsummaryrefslogtreecommitdiff
path: root/pw_software_update/py/remote_sign_test.py
blob: 78d6df4faee5dd8cd3f707065c18bab8dc577f5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Copyright 2021 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Unit tests for pw_software_update.remote_sign module."""

import os
from pathlib import Path
import tempfile
import textwrap
import unittest
from unittest import mock

from google.cloud.storage import Blob  # type: ignore
from google.cloud.storage.bucket import Bucket  # type: ignore

from pw_software_update import remote_sign

# inclusive-language: disable
FAKE_BUILDER_KEY = textwrap.dedent(
    """\
    -----BEGIN RSA PRIVATE KEY-----
    MIIEpAIBAAKCAQEA4qEQSHM0QpWEhTvhWMBahS7wbTIihaiRpUQC8+hEkmHhoJQy
    zaNR3CKdYWnJ1bAjdBT1HTHznbYSBasFAUKPiB16K/akuKSPnwHG9OM6+8Psw7lt
    GLP2jP65HE4a8n9lGas399xIK4hxZJkV2BXocociXVEVB3nzzNk1AQZdJxik/ToL
    MYC2EKTu1kdt+OLl56/O1Mq9p8V7u2G1l8fqHtJi4Z34LzUzIoyFf7+bSmZBcHG1
    F/QdjbHb4temShDzptOM1VfXZchYTDVnbNsmR7TP2B857agog4rhqtVlPvHqFial
    WEU1WmAQz+oYqtRikUVWHq10SACxo6MFoM7LqQIDAQABAoIBAQCjrdoZyYLUGDLn
    G1FtDTgTesxQwWXnjNDsQMu1J2rnImSX2pE6rhtAV4u9QG9ys01X2I8Tr/EYVdh8
    WYE64LzTfR6ww+lCJjBIkjsEwVznWyEUV0bxEYEfYhWF2O9jdxkoyd2ZWXKSZnAn
    TN1W/LOui+UI6re6d5zatYGvpM4AnlMTmwcO5aPQqTZMBOqJQZgEgyyHH2DZpIRI
    L7dG/k9Y/ML4T+hSVvi84+NS7GyTajPtaNRoVnlwr9+QVKplIgT8ZSqAF7unBsmF
    +s/U+TCFKq0pOhamOVz8eVd/uusy0d7a2oomtKoIzcPd74J5KZMub8izmEOwp5TZ
    17rsBDuVAoGBAPJMv737tYf5T5ihwEJ84OWxq3qLwWSoNwezOF3iWi4r42+QoqsC
    F0dLlgTmsafNTwVP1ztoeGvvezXSUfKfMTjjaZDRB226gwW7+eZ0MbrVcEnI9wm5
    K9MOWut40KsoAHHGs5sLyAtIENwnPAkPQPwPxmEcUxJJZwI/Rq78zR1bAoGBAO9x
    fAi9M8VdbV3r/l1SnExRlTu2gp9Rv02Zy78HVOWEWdEn6mhG3to5mXsHNIQwLulQ
    jm/hBSme5g4xbSCL/qCqRkc1rRautq/W50G8h7S3+KFGdnzXdEYnEh4oh5t5PJtA
    LHWc2WhTe5bsBNwOR1xQ8bEm+V/lf4Fbq+jOcjZLAoGBALzKgDwPfApOf2512c/0
    bWeLYAlEC5PaXcZqJmlAjPOczsGG+Lg2EN1ET8fR2Gre1ctVwmZPqESxfFcbYS6i
    S0AAMajcteURhjVZmgWuU3E4DR3wsEurNDJm5QDEShKSQIZmRFtyepQPutNO3sBQ
    WloMEI5p+3AsMU7W7sQ5xbgxAoGABWwAbwI5xeJTs6jAXcSdHW1Lf8qmMo1bU5qD
    7pNv7LKOhhntSOcx7KcZPpvvKH8e0NGuKAJkZ4jdlLyxx+bjoSe556rjfHwATwMC
    wY5PVFxGGQDLdhA65cvEsUIhr/eS08EkQJWIpsAdMFGv2nvISeLbVjOXugAsXvWA
    cwkZtPkCgYBQJPRCGBz73lBFB16oYJR6AnC32nf0WbrnMLFwMejUrsTLN6M72axw
    bWFpW7rWV7ldSgxKJ6ucKWl78uUMUnkM+CGPt5WJiisZXM2X1Q8+V7fmdAtK/AFj
    /tbEFpftkCyIM1nGZwZ/ziPF4n5hzGGF6w/ZMWZkwFZlqxlejK9IfQ==
    -----END RSA PRIVATE KEY-----
"""
)

FAKE_BUILDER_PUBLIC_KEY = textwrap.dedent(
    """\
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4qEQSHM0QpWEhTvhWMBa
    hS7wbTIihaiRpUQC8+hEkmHhoJQyzaNR3CKdYWnJ1bAjdBT1HTHznbYSBasFAUKP
    iB16K/akuKSPnwHG9OM6+8Psw7ltGLP2jP65HE4a8n9lGas399xIK4hxZJkV2BXo
    cociXVEVB3nzzNk1AQZdJxik/ToLMYC2EKTu1kdt+OLl56/O1Mq9p8V7u2G1l8fq
    HtJi4Z34LzUzIoyFf7+bSmZBcHG1F/QdjbHb4temShDzptOM1VfXZchYTDVnbNsm
    R7TP2B857agog4rhqtVlPvHqFialWEU1WmAQz+oYqtRikUVWHq10SACxo6MFoM7L
    qQIDAQAB
    -----END PUBLIC KEY-----
"""
)

# inclusive-language: enable


# TODO(b/235240430): Improve unit test coverage.
class PathSigningTest(unittest.TestCase):
    """Tests the signing of bundles by path."""

    @classmethod
    def setUpClass(cls):
        cls.tempdir = tempfile.mkdtemp()

        cls.builder_key = Path(cls.tempdir) / 'fake_builder_key'
        cls.builder_key.write_text(FAKE_BUILDER_KEY)

        cls.builder_pub_key = Path(cls.tempdir) / 'fake_builder_pub_key.pem'
        cls.builder_pub_key.write_text(FAKE_BUILDER_PUBLIC_KEY)

        cls.bundle = Path(cls.tempdir) / 'fake_bundle'
        cls.bundle.write_bytes(b'FAKE BUNDLE CONTENTS\n')

    def test_bundle_blob_uploads(self):
        """Signing should upload the bundle, pub key, and signing request."""
        mock_blob = mock.create_autospec(Blob, instance=True)
        mock_blob.exists = mock.MagicMock(return_value=False)
        mock_in_bucket = mock.create_autospec(Bucket, instance=True)
        mock_in_bucket.blob = mock.MagicMock(return_value=mock_blob)
        mock_out_bucket = mock.create_autospec(Bucket, instance=True)
        mock_out_bucket.name = 'fake_out_bucket'
        client = remote_sign.RemoteSignClient(
            input_bucket=mock_in_bucket, output_bucket=mock_out_bucket
        )

        client.sign(
            self.bundle,
            signing_key_name='fake_key',
            builder_key=self.builder_key,
            builder_public_key=self.builder_pub_key,
            request_blob_name='signing_request.json',
            timeout_s=0.1,
        )

        mock_blob.upload_from_filename.assert_has_calls(
            [
                mock.call(os.path.join(self.tempdir, 'fake_bundle')),
                mock.call(
                    os.path.join(self.tempdir, 'fake_builder_pub_key.pem')
                ),
            ],
            any_order=True,
        )
        mock_blob.upload_from_string.assert_called_once()


if __name__ == '__main__':
    unittest.main()