You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by no...@apache.org on 2020/12/29 12:28:01 UTC

[buildstream] 02/02: Adapt tests to use secured CAS server

This is an automated email from the ASF dual-hosted git repository.

not-in-ldap pushed a commit to branch dp0/casserver-tests
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit e9ffd7eab8608d6a400182e2f1af8a8f97e3a7f9
Author: Daniel Playle <dp...@bloomberg.net>
AuthorDate: Fri Aug 31 16:55:24 2018 +0100

    Adapt tests to use secured CAS server
    
    Previously, we had been only testing an unsecured CAS server. As such,
    no authentication mechanisms were tested. This commit adapts existing
    tests to ensure that a secured CAS server is also tested alongside
    unsecured configurations.
    
    This commit introduces two data files which are used in part of the
    testing process: a server private key, and a server certificate. The
    server private key is of size 4096 bytes. The server certificate is for
    the name "localhost" and has an expiration set to 1000 years in the
    future, so there should be little concern of the expiration of this
    testing artifact.
---
 tests/frontend/creds/server_cert.pem | 29 +++++++++++++
 tests/frontend/creds/server_key.pem  | 52 ++++++++++++++++++++++
 tests/frontend/push.py               | 84 ++++++++++++++++++++++++++++--------
 tests/testutils/artifactshare.py     | 19 +++++---
 4 files changed, 160 insertions(+), 24 deletions(-)

diff --git a/tests/frontend/creds/server_cert.pem b/tests/frontend/creds/server_cert.pem
new file mode 100644
index 0000000..b1c6dc2
--- /dev/null
+++ b/tests/frontend/creds/server_cert.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFADCCAuigAwIBAgIJAMrnbCKz2am/MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
+BAMMCWxvY2FsaG9zdDAgFw0xODA4MzExNTEzMThaGA8zMDE4MDEwMTE1MTMxOFow
+FDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAtOF+EmfIIQVz4eox6lZLcQcsf089r65XB5su8SzDXvC2kYIn8Crqs67Q
+x4s10YfYAOWS0Bj0Jx5GS7NQB+vUQtHWNTAO+19edAsrH204OD3QTrU0rt1rpJGb
+P36tIgZk+zgWj9MquHibacg2u/sz+4OlfxsDg2FDt1zhgamY9AQ2BRlxDza9/lcU
+/yBD2hSw3LyLQLJAL0TbTARqUkCHWZRcy1KPQ47SV4aWC2WhUwimDK44UZs1Ub50
+GcaB7s/ZRm6mREGV5mBzW63GLthOGlTps5YzE45GsLrmRiQ9aJgr8I6BZoNggLl9
+WomvGvd4PBzsXxyu3d+ZVdoudxeQbMKlyr7i5yVDO5S26xohUbpQg8wAl4YZ7tG7
+K2ihEphSgeCh3owWPkptXSxX+dXnA7W2/uJ4HwHjRLf7/MRL3GccJsviL7qtg9fO
+PF5av/psRkfR5tq/qtFrWAor4E1/nLKJbtEzHP8XoSJglSIXL2g1Q6ofNmbHvghg
+hR0pT6oEf6hc5R+qXVT7TTSxdVQkyLnrR+nUWMzaMUrD990kdhY+eJu15sJXsHyJ
+OThkuqiGbiTlTUEyhbTsFCK1UVi9P8cLGndyeB9LtQynWVqBFXPkT/qVyjOINUHZ
+2wu2U0OhjMpZ3dtQC58ME/Q0xDbJoyr+HwsMFV97TXT/WoLiN48CAwEAAaNTMFEw
+HQYDVR0OBBYEFFWfm5e2tS2Ask/QRNP8Y10yM3S4MB8GA1UdIwQYMBaAFFWfm5e2
+tS2Ask/QRNP8Y10yM3S4MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD
+ggIBACGpGGhliKiwAu1TjxMoQfI9rpO7uVyEYeBIYJ/eK3beJqCs3FmirgYdmGtK
+2KHcPnMG27c1m9EEsJf9sVOjkd43OB7fdWw38i0TaPxSgmPh0v6b+jhR4tqxwIRi
+jSQUxNklurKroyMWL9QFFLufwd43g3XTm449EOzrLB2jxUd10u+OXwzraQRRgTeM
+9U9PMoTfp6dICKKcV7XJdDR2hUH7SRrk96ucgYhztLx4x9R+mTZzgeCw5euY7a/t
+02uijT4tIrtCryOTukHrtfWdy5+ng4mcsdlWvZgJiRy+vwdWFx8k5t/MJ6f1xqxs
+RHl/99LAh/d9scdkVXPEB57vQRuHeybPH2i4cM/0VyFDfCrCG9AeXeVeB/pbanzB
+ex6MHttnhopTWtFHuMDquCeLP5P5cnKNLB676bZvKhgNoYZAXIrFGJtJNLMFBXD6
+v9kXrCIpDdUFHd3GLi8U9GTiwSmfz6HQVCvQZ+feVBpZLxaFrLpbRszKIE1lYFVS
+eJd3StxS/BGm3jzbWGgG9kq7kuF3cuJmtfKoAzOYYNz3/eipfQl6giOitJx5MWW5
+mevCq9mCNBIKvRNdxR0kJ4rJ5eTlDJ6xfFs2aKGXHFKS1+21RM/S58El+XosWXov
+4jZCTLS7wmk2/MrABGmbCgK4YfrQnt6eY2nElJXEBPX0jeHu
+-----END CERTIFICATE-----
diff --git a/tests/frontend/creds/server_key.pem b/tests/frontend/creds/server_key.pem
new file mode 100644
index 0000000..ba546dc
--- /dev/null
+++ b/tests/frontend/creds/server_key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+e+XVdfiURwWj6Q7/y/Rujtp7K6z2dA==
+-----END PRIVATE KEY-----
diff --git a/tests/frontend/push.py b/tests/frontend/push.py
index f351e33..74f0623 100644
--- a/tests/frontend/push.py
+++ b/tests/frontend/push.py
@@ -35,6 +35,22 @@ DATA_DIR = os.path.join(
     "project",
 )
 
+# Credential directory
+CRED_DIR = os.path.join(
+    os.path.dirname(os.path.realpath(__file__)),
+    "creds",
+)
+
+# Parameters for credentials
+CREDENTIAL_FILENAMES = {
+    'unsecured': {},
+
+    'server_secured': {
+        'server_key': 'server_key.pem',
+        'server_cert': 'server_cert.pem',
+    },
+}
+
 
 # Assert that a given artifact is in the share
 #
@@ -60,14 +76,41 @@ def assert_not_shared(cli, share, project, element_name):
                              .format(share.repo, element_name))
 
 
+# Taking a dictionary of filenames, this returns a dictionary of qualified
+# fielnames
+def join_credentials_path(credential_filenames, credential_files):
+    return {
+        key: os.path.join(credential_files, filename)
+        for key, filename in credential_filenames.items()
+    }
+
+
+# Adds the server certificate to the configuration if it exists and returns
+# this for ease of use
+def add_client_config_creds(configuration, credentials):
+    if 'server_cert' in credentials:
+        artifacts = configuration['artifacts']
+        if isinstance(artifacts, (list,)):
+            for subconfig in artifacts:
+                subconfig['server-cert'] = credentials['server_cert']
+        else:
+            artifacts['server-cert'] = credentials['server_cert']
+    return configuration
+
+
 # Tests that:
 #
 #  * `bst push` fails if there are no remotes configured for pushing
 #  * `bst push` successfully pushes to any remote that is configured for pushing
 #
-@pytest.mark.datafiles(DATA_DIR)
-def test_push(cli, tmpdir, datafiles):
-    project = str(datafiles)
+@pytest.mark.parametrize(
+    'credential_filenames', CREDENTIAL_FILENAMES.values(), ids=list(CREDENTIAL_FILENAMES))
+@pytest.mark.datafiles(DATA_DIR, CRED_DIR, keep_top_dir=True)
+def test_push(cli, tmpdir, datafiles, credential_filenames):
+    project = os.path.join(datafiles, 'project')
+    credfiles = os.path.join(datafiles, 'creds')
+
+    credentials = join_credentials_path(credential_filenames, credfiles)
 
     # First build the project without the artifact cache configured
     result = cli.run(project=project, args=['build', 'target.bst'])
@@ -77,9 +120,11 @@ def test_push(cli, tmpdir, datafiles):
     assert cli.get_element_state(project, 'target.bst') == 'cached'
 
     # Set up two artifact shares.
-    with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1')) as share1:
+    with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1'),
+                               credentials=credentials) as share1:
 
-        with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as share2:
+        with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2'),
+                                   credentials=credentials) as share2:
 
             # Try pushing with no remotes configured. This should fail.
             result = cli.run(project=project, args=['push', 'target.bst'])
@@ -87,19 +132,19 @@ def test_push(cli, tmpdir, datafiles):
 
             # Configure bst to pull but not push from a cache and run `bst push`.
             # This should also fail.
-            cli.configure({
+            cli.configure(add_client_config_creds({
                 'artifacts': {'url': share1.repo, 'push': False},
-            })
+            }, credentials))
             result = cli.run(project=project, args=['push', 'target.bst'])
             result.assert_main_error(ErrorDomain.STREAM, None)
 
             # Configure bst to push to one of the caches and run `bst push`. This works.
-            cli.configure({
+            cli.configure(add_client_config_creds({
                 'artifacts': [
                     {'url': share1.repo, 'push': False},
                     {'url': share2.repo, 'push': True},
                 ]
-            })
+            }, credentials))
             result = cli.run(project=project, args=['push', 'target.bst'])
 
             assert_not_shared(cli, share1, project, 'target.bst')
@@ -108,12 +153,12 @@ def test_push(cli, tmpdir, datafiles):
         # Now try pushing to both
 
         with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as share2:
-            cli.configure({
+            cli.configure(add_client_config_creds({
                 'artifacts': [
                     {'url': share1.repo, 'push': True},
                     {'url': share2.repo, 'push': True},
                 ]
-            })
+            }, credentials))
             result = cli.run(project=project, args=['push', 'target.bst'])
 
             assert_shared(cli, share1, project, 'target.bst')
@@ -122,11 +167,16 @@ def test_push(cli, tmpdir, datafiles):
 
 # Tests that `bst push --deps all` pushes all dependencies of the given element.
 #
-@pytest.mark.datafiles(DATA_DIR)
-def test_push_all(cli, tmpdir, datafiles):
-    project = os.path.join(datafiles.dirname, datafiles.basename)
+@pytest.mark.parametrize(
+    'credential_filenames', CREDENTIAL_FILENAMES.values(), ids=list(CREDENTIAL_FILENAMES))
+@pytest.mark.datafiles(DATA_DIR, CRED_DIR, keep_top_dir=True)
+def test_push_all(cli, tmpdir, datafiles, credential_filenames):
+    project = os.path.join(datafiles, 'project')
+    credfiles = os.path.join(datafiles, 'creds')
 
-    with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare')) as share:
+    credentials = join_credentials_path(credential_filenames, credfiles)
+
+    with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare'), credentials=credentials) as share:
 
         # First build it without the artifact cache configured
         result = cli.run(project=project, args=['build', 'target.bst'])
@@ -136,7 +186,7 @@ def test_push_all(cli, tmpdir, datafiles):
         assert cli.get_element_state(project, 'target.bst') == 'cached'
 
         # Configure artifact share
-        cli.configure({
+        cli.configure(add_client_config_creds({
             #
             # FIXME: This test hangs "sometimes" if we allow
             #        concurrent push.
@@ -152,7 +202,7 @@ def test_push_all(cli, tmpdir, datafiles):
                 'url': share.repo,
                 'push': True,
             }
-        })
+        }, credentials))
 
         # Now try bst push all the deps
         result = cli.run(project=project, args=[
diff --git a/tests/testutils/artifactshare.py b/tests/testutils/artifactshare.py
index d7575e5..a486ca1 100644
--- a/tests/testutils/artifactshare.py
+++ b/tests/testutils/artifactshare.py
@@ -29,7 +29,7 @@ from buildstream._exceptions import ArtifactError
 #
 class ArtifactShare():
 
-    def __init__(self, directory, *, total_space=None, free_space=None):
+    def __init__(self, directory, *, total_space=None, free_space=None, credentials={}):
 
         # The working directory for the artifact share (in case it
         # needs to do something outside of it's backend's storage folder).
@@ -55,19 +55,24 @@ class ArtifactShare():
 
         q = Queue()
 
-        self.process = Process(target=self.run, args=(q,))
+        self.process = Process(target=self.run, args=(q, credentials))
         self.process.start()
 
         # Retrieve port from server subprocess
         port = q.get()
 
-        self.repo = 'http://localhost:{}'.format(port)
+        if credentials:
+            protocol = 'https'
+        else:
+            protocol = 'http'
+
+        self.repo = '{}://localhost:{}'.format(protocol, port)
 
     # run():
     #
     # Run the artifact server.
     #
-    def run(self, q):
+    def run(self, q, credentials):
         pytest_cov.embed.cleanup_on_sigterm()
 
         # Optionally mock statvfs
@@ -77,7 +82,7 @@ class ArtifactShare():
             os.statvfs = self._mock_statvfs
 
         server = create_server(self.repodir, enable_push=True)
-        port = setup_server(server, 'localhost', 0)
+        port = setup_server(server, 'localhost', 0, **credentials)
 
         server.start()
 
@@ -149,8 +154,8 @@ class ArtifactShare():
 # Create an ArtifactShare for use in a test case
 #
 @contextmanager
-def create_artifact_share(directory, *, total_space=None, free_space=None):
-    share = ArtifactShare(directory, total_space=total_space, free_space=free_space)
+def create_artifact_share(directory, *, total_space=None, free_space=None, credentials={}):
+    share = ArtifactShare(directory, total_space=total_space, free_space=free_space, credentials=credentials)
     try:
         yield share
     finally: