diff --git a/tests/unit/test_api.py b/tests/unit/test_api.py index 10c2174..5a9bbb5 100644 --- a/tests/unit/test_api.py +++ b/tests/unit/test_api.py @@ -73,6 +73,7 @@ class TestApi(BaseTestCase): client = ZuulRESTClient(url='https://fake.zuul/', auth_token='aiaiaiai') + client.info_ = {} # test status checks self._test_status_check( client, 'post', client.autohold, @@ -92,10 +93,24 @@ class TestApi(BaseTestCase): 'node_hold_expiration': 3600} ) self.assertEqual(True, ah) + client.info_ = {'tenant': 'scoped'} + ah = client.autohold( + 'tenant', 'project', 'job', 1, None, 'reason', 1, 3600) + client.session.post.assert_called_with( + 'https://fake.zuul/api/project/project/autohold', + json={'reason': 'reason', + 'count': 1, + 'job': 'job', + 'change': 1, + 'ref': None, + 'node_hold_expiration': 3600} + ) + self.assertEqual(True, ah) def test_autohold_list(self): """Test autohold-list""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # test status checks self._test_status_check( client, 'get', client.autohold_list, 'tenant1') @@ -117,16 +132,23 @@ class TestApi(BaseTestCase): client.session.get.assert_called_with( 'https://fake.zuul/api/tenant/tenant1/autohold') self.assertEqual(fakejson, ahl) + client.info_ = {'tenant': 'scoped'} + ahl = client.autohold_list('tenant1') + client.session.get.assert_called_with( + 'https://fake.zuul/api/autohold') + self.assertEqual(fakejson, ahl) def test_autohold_delete(self): """Test autohold-delete""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # token required with self.assertRaisesRegex(Exception, 'Auth Token required'): client.autohold_delete(123, 'tenant1') client = ZuulRESTClient(url='https://fake.zuul/', auth_token='aiaiaiai') + client.info_ = {} # test status checks self._test_status_check( client, 'delete', client.autohold_delete, @@ -140,10 +162,17 @@ class TestApi(BaseTestCase): 'https://fake.zuul/api/tenant/tenant1/autohold/123' ) self.assertEqual(True, ahd) + client.info_ = {'tenant': 'scoped'} + ahd = client.autohold_delete(123, 'tenant1') + client.session.delete.assert_called_with( + 'https://fake.zuul/api/autohold/123' + ) + self.assertEqual(True, ahd) def test_autohold_info(self): """Test autohold-info""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # test status checks self._test_status_check( client, 'get', client.autohold_info, 123, 'tenant1') @@ -165,16 +194,23 @@ class TestApi(BaseTestCase): client.session.get.assert_called_with( 'https://fake.zuul/api/tenant/tenant1/autohold/123') self.assertEqual(fakejson, ahl) + client.info_ = {'tenant': 'scoped'} + ahl = client.autohold_info(tenant='tenant1', id=123) + client.session.get.assert_called_with( + 'https://fake.zuul/api/autohold/123') + self.assertEqual(fakejson, ahl) def test_enqueue(self): """Test enqueue""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # token required with self.assertRaisesRegex(Exception, 'Auth Token required'): client.enqueue('tenant1', 'check', 'project1', '1,1') client = ZuulRESTClient(url='https://fake.zuul/', auth_token='aiaiaiai') + client.info_ = {} # test status checks self._test_status_check( client, 'post', client.enqueue, @@ -190,10 +226,19 @@ class TestApi(BaseTestCase): 'pipeline': 'check'} ) self.assertEqual(True, enq) + client.info_ = {'tenant': 'scoped'} + enq = client.enqueue('tenant1', 'check', 'project1', '1,1') + client.session.post.assert_called_with( + 'https://fake.zuul/api/project/project1/enqueue', + json={'change': '1,1', + 'pipeline': 'check'} + ) + self.assertEqual(True, enq) def test_enqueue_ref(self): """Test enqueue ref""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # token required with self.assertRaisesRegex(Exception, 'Auth Token required'): client.enqueue_ref( @@ -201,6 +246,7 @@ class TestApi(BaseTestCase): client = ZuulRESTClient(url='https://fake.zuul/', auth_token='aiaiaiai') + client.info_ = {} # test status checks self._test_status_check( client, 'post', client.enqueue_ref, @@ -219,16 +265,29 @@ class TestApi(BaseTestCase): 'pipeline': 'check'} ) self.assertEqual(True, enq_ref) + client.info_ = {'tenant': 'scoped'} + enq_ref = client.enqueue_ref( + 'tenant1', 'check', 'project1', 'refs/heads/stable', '0', '0') + client.session.post.assert_called_with( + 'https://fake.zuul/api/project/project1/enqueue', + json={'ref': 'refs/heads/stable', + 'oldrev': '0', + 'newrev': '0', + 'pipeline': 'check'} + ) + self.assertEqual(True, enq_ref) def test_dequeue(self): """Test dequeue""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # token required with self.assertRaisesRegex(Exception, 'Auth Token required'): client.dequeue('tenant1', 'check', 'project1', '1,1') client = ZuulRESTClient(url='https://fake.zuul/', auth_token='aiaiaiai') + client.info_ = {} # test status checks self._test_status_check( client, 'post', client.dequeue, @@ -257,16 +316,34 @@ class TestApi(BaseTestCase): 'pipeline': 'check'} ) self.assertEqual(True, deq) + client.info_ = {'tenant': 'scoped'} + deq = client.dequeue('tenant1', 'check', 'project1', change='1,1') + client.session.post.assert_called_with( + 'https://fake.zuul/api/project/project1/dequeue', + json={'change': '1,1', + 'pipeline': 'check'} + ) + self.assertEqual(True, deq) + deq = client.dequeue( + 'tenant1', 'check', 'project1', ref='refs/heads/stable') + client.session.post.assert_called_with( + 'https://fake.zuul/api/project/project1/dequeue', + json={'ref': 'refs/heads/stable', + 'pipeline': 'check'} + ) + self.assertEqual(True, deq) def test_promote(self): """Test promote""" client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} # token required with self.assertRaisesRegex(Exception, 'Auth Token required'): client.promote('tenant1', 'check', ['1,1', '2,1']) client = ZuulRESTClient(url='https://fake.zuul/', auth_token='aiaiaiai') + client.info_ = {} # test status checks self._test_status_check( client, 'post', client.promote, @@ -282,6 +359,14 @@ class TestApi(BaseTestCase): 'pipeline': 'check'} ) self.assertEqual(True, prom) + client.info_ = {'tenant': 'scoped'} + prom = client.promote('tenant1', 'check', ['1,1', '2,1']) + client.session.post.assert_called_with( + 'https://fake.zuul/api/promote', + json={'changes': ['1,1', '2,1'], + 'pipeline': 'check'} + ) + self.assertEqual(True, prom) def test_get_key(self): """Test getting a project's public key""" @@ -302,6 +387,16 @@ GuS6/ewjS+arA1Iyeg/IxmECAwEAAQ== -----END PUBLIC KEY-----""" req = FakeRequestResponse(200, text=pubkey) client = ZuulRESTClient(url='https://fake.zuul/') + client.info_ = {} client.session.get = MagicMock(return_value=req) key = client.get_key('tenant1', 'project1') + client.session.get.assert_called_with( + 'https://fake.zuul/api/tenant/tenant1/key/project1.pub' + ) + self.assertEqual(pubkey, key) + client.info_ = {'tenant': 'scoped'} + key = client.get_key('tenant1', 'project1') + client.session.get.assert_called_with( + 'https://fake.zuul/api/key/project1.pub' + ) self.assertEqual(pubkey, key) diff --git a/tests/unit/test_cmd.py b/tests/unit/test_cmd.py index de3a5c0..6f9a213 100644 --- a/tests/unit/test_cmd.py +++ b/tests/unit/test_cmd.py @@ -36,6 +36,17 @@ chunks = [ '1tlAuq+vIhlY3iYlzVtPTiIOtF/6V+qPHnq1k6Tiv8YzJms1WyOuw106Bzl9XM='] +def mock_get(func=MagicMock(return_value=None), info={}): + + def funk(*args, **kwargs): + if args[0].endswith('/info'): + return FakeRequestResponse(200, info) + else: + return func(*args, **kwargs) + + return funk + + class TestCmd(BaseTestCase): def test_client_args_errors(self): @@ -52,6 +63,54 @@ class TestCmd(BaseTestCase): '--reason', 'some reason', '--node-hold-expiration', '3600']) + def test_tenant_scoping_errors(self): + """Test the right uses of --tenant""" + ZC = ZuulClient() + with patch('requests.Session') as mock_sesh: + session = mock_sesh.return_value + test_args = [ + ['autohold', + '--project', 'project1', + '--job', 'job1', '--change', '3', + '--reason', 'some reason', + '--node-hold-expiration', '3600'], + ['autohold-delete', '1234'], + ['autohold-info', '1234'], + ['enqueue', + '--pipeline', 'check', + '--change', '3,1', + '--project', 'project1'], + ['enqueue-ref', + '--pipeline', 'check', + '--ref', 'refs/heads/stable', + '--project', 'project1', + '--oldrev', 'ababababab'], + ['dequeue', + '--pipeline', 'check', + '--change', '3,3', + '--project', 'project1'], + ['promote', + '--pipeline', 'gate', + '--changes', '3,3', '4,1', '5,3'], + ['encrypt', '--project', 'project1'] + ] + for args in test_args: + session.get = MagicMock( + side_effect=mock_get() + ) + with self.assertRaisesRegex(Exception, + '--tenant argument is required'): + ZC._main(['--zuul-url', 'https://fake.zuul', + '--auth-token', 'aiaiaiai', ] + args) + session.get = MagicMock( + side_effect=mock_get(info={'tenant': 'scoped'}) + ) + with self.assertRaisesRegex(Exception, + 'scoped to tenant "scoped"'): + ZC._main(['--zuul-url', 'https://fake.zuul', + '--auth-token', 'aiaiaiai', ] + args + + ['--tenant', 'tenant-' + args[0]]) + def test_autohold(self): """Test autohold via CLI""" ZC = ZuulClient() @@ -59,6 +118,9 @@ class TestCmd(BaseTestCase): session = mock_sesh.return_value session.post = MagicMock( return_value=FakeRequestResponse(200, True)) + session.get = MagicMock( + side_effect=mock_get() + ) exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', '--auth-token', 'aiaiaiai', 'autohold', @@ -76,6 +138,27 @@ class TestCmd(BaseTestCase): 'node_hold_expiration': 3600} ) self.assertEqual(0, exit_code) + # test scoped + session.get = MagicMock( + side_effect=mock_get(info={'tenant': 'scoped'}) + ) + exit_code = ZC._main( + ['--zuul-url', 'https://scoped.zuul', + '--auth-token', 'aiaiaiai', 'autohold', + '--project', 'project1', + '--job', 'job1', '--change', '3', '--reason', 'some reason', + '--node-hold-expiration', '3600']) + session.post.assert_called_with( + 'https://scoped.zuul/api/' + 'project/project1/autohold', + json={'reason': 'some reason', + 'count': 1, + 'job': 'job1', + 'change': '3', + 'ref': '', + 'node_hold_expiration': 3600} + ) + self.assertEqual(0, exit_code) def test_autohold_args_errors(self): """Test wrong arguments for autohold""" @@ -130,6 +213,9 @@ class TestCmd(BaseTestCase): session = mock_sesh.return_value session.delete = MagicMock( return_value=FakeRequestResponse(204)) + session.get = MagicMock( + side_effect=mock_get() + ) exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', '--auth-token', 'aiaiaiai', 'autohold-delete', @@ -143,8 +229,9 @@ class TestCmd(BaseTestCase): ZC = ZuulClient() with patch('requests.Session') as mock_sesh: session = mock_sesh.return_value - session.get = MagicMock( - return_value=FakeRequestResponse( + + def rv(*args, **kargs): + return FakeRequestResponse( 200, json={'id': 1234, 'tenant': 'tenant1', @@ -156,7 +243,11 @@ class TestCmd(BaseTestCase): 'node_expiration': 0, 'expired': 0, 'reason': 'some_reason', - 'nodes': ['node1', 'node2']})) + 'nodes': ['node1', 'node2']}) + + session.get = MagicMock( + side_effect=mock_get(rv) + ) exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', 'autohold-info', '--tenant', 'tenant1', '1234']) @@ -178,6 +269,9 @@ class TestCmd(BaseTestCase): session = mock_sesh.return_value session.post = MagicMock( return_value=FakeRequestResponse(200, True)) + session.get = MagicMock( + side_effect=mock_get() + ) exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', '--auth-token', 'aiaiaiai', 'enqueue', @@ -199,6 +293,9 @@ class TestCmd(BaseTestCase): session = mock_sesh.return_value session.post = MagicMock( return_value=FakeRequestResponse(200, True)) + session.get = MagicMock( + side_effect=mock_get() + ) # ensure default revs are set exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', @@ -272,6 +369,9 @@ class TestCmd(BaseTestCase): session = mock_sesh.return_value session.post = MagicMock( return_value=FakeRequestResponse(200, True)) + session.get = MagicMock( + side_effect=mock_get() + ) exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', '--auth-token', 'aiaiaiai', 'dequeue', @@ -306,6 +406,9 @@ class TestCmd(BaseTestCase): session = mock_sesh.return_value session.post = MagicMock( return_value=FakeRequestResponse(200, True)) + session.get = MagicMock( + side_effect=mock_get() + ) exit_code = ZC._main( ['--zuul-url', 'https://fake.zuul', '--auth-token', 'aiaiaiai', 'promote', @@ -329,8 +432,13 @@ class TestCmd(BaseTestCase): ZC = ZuulClient() with patch('requests.Session') as mock_sesh: session = mock_sesh.return_value + + def rv(*args, **kwargs): + return FakeRequestResponse(200, text='aaa') + session.get = MagicMock( - return_value=FakeRequestResponse(200, text='aaa')) + side_effect=mock_get(rv) + ) with patch('zuulclient.cmd.encrypt_with_openssl') as m_encrypt: m_encrypt.return_value = chunks exit_code = ZC._main( diff --git a/zuulclient/api/__init__.py b/zuulclient/api/__init__.py index 0543e6a..9125d55 100644 --- a/zuulclient/api/__init__.py +++ b/zuulclient/api/__init__.py @@ -51,6 +51,20 @@ class ZuulRESTClient(object): self.session.verify = self.verify if self.auth_token: self.session.auth = BearerAuth(self.auth_token) + self.info_ = None + + @property + def info(self): + """Return the Zuul info data. + Useful to get capabilities and tenant info.""" + if self.info_ is None: + url = urllib.parse.urljoin( + self.base_url, + 'info') + req = self.session.get(url) + self._check_request_status(req) + self.info_ = req.json() + return self.info_ def _check_request_status(self, req): try: @@ -76,17 +90,25 @@ class ZuulRESTClient(object): "change": change, "ref": ref, "node_hold_expiration": node_hold_expiration} + if self.info.get('tenant'): + suffix = 'project/%s/autohold' % project + else: + suffix = 'tenant/%s/project/%s/autohold' % (tenant, project) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/project/%s/autohold' % (tenant, project)) + suffix) req = self.session.post(url, json=args) self._check_request_status(req) return req.json() def autohold_list(self, tenant): + if self.info.get('tenant'): + suffix = 'autohold' + else: + suffix = 'tenant/%s/autohold' % tenant url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/autohold' % tenant) + suffix) # auth not needed here req = self.session.get(url) self._check_request_status(req) @@ -96,18 +118,26 @@ class ZuulRESTClient(object): def autohold_delete(self, id, tenant): if not self.auth_token: raise Exception('Auth Token required') + if self.info.get('tenant'): + suffix = 'autohold/%s' % id + else: + suffix = 'tenant/%s/autohold/%s' % (tenant, id) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/autohold/%s' % (tenant, id)) + suffix) req = self.session.delete(url) self._check_request_status(req) # DELETE doesn't return a body, just the HTTP code return (req.status_code == 204) def autohold_info(self, id, tenant): + if self.info.get('tenant'): + suffix = 'autohold/%s' % id + else: + suffix = 'tenant/%s/autohold/%s' % (tenant, id) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/autohold/%s' % (tenant, id)) + suffix) # auth not needed here req = self.session.get(url) self._check_request_status(req) @@ -119,9 +149,13 @@ class ZuulRESTClient(object): raise Exception('Auth Token required') args = {"change": change, "pipeline": pipeline} + if self.info.get('tenant'): + suffix = 'project/%s/enqueue' % project + else: + suffix = 'tenant/%s/project/%s/enqueue' % (tenant, project) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/project/%s/enqueue' % (tenant, project)) + suffix) req = self.session.post(url, json=args) self._check_request_status(req) return req.json() @@ -133,9 +167,13 @@ class ZuulRESTClient(object): "oldrev": oldrev, "newrev": newrev, "pipeline": pipeline} + if self.info.get('tenant'): + suffix = 'project/%s/enqueue' % project + else: + suffix = 'tenant/%s/project/%s/enqueue' % (tenant, project) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/project/%s/enqueue' % (tenant, project)) + suffix) req = self.session.post(url, json=args) self._check_request_status(req) return req.json() @@ -150,9 +188,13 @@ class ZuulRESTClient(object): args['ref'] = ref else: raise Exception('need change OR ref') + if self.info.get('tenant'): + suffix = 'project/%s/dequeue' % project + else: + suffix = 'tenant/%s/project/%s/dequeue' % (tenant, project) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/project/%s/dequeue' % (tenant, project)) + suffix) req = self.session.post(url, json=args) self._check_request_status(req) return req.json() @@ -162,17 +204,25 @@ class ZuulRESTClient(object): raise Exception('Auth Token required') args = {'pipeline': pipeline, 'changes': change_ids} + if self.info.get('tenant'): + suffix = 'promote' + else: + suffix = 'tenant/%s/promote' % tenant url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/promote' % tenant) + suffix) req = self.session.post(url, json=args) self._check_request_status(req) return req.json() def get_key(self, tenant, project): + if self.info.get('tenant'): + suffix = 'key/%s.pub' % project + else: + suffix = 'tenant/%s/key/%s.pub' % (tenant, project) url = urllib.parse.urljoin( self.base_url, - 'tenant/%s/key/%s.pub' % (tenant, project)) + suffix) req = self.session.get(url) self._check_request_status(req) return req.text diff --git a/zuulclient/cmd/__init__.py b/zuulclient/cmd/__init__.py index 6a4cc05..6a689ff 100644 --- a/zuulclient/cmd/__init__.py +++ b/zuulclient/cmd/__init__.py @@ -153,11 +153,24 @@ class ZuulClient(): self.log.error(e) sys.exit(1) + def _check_tenant_scope(self, client): + tenant_scope = client.info.get('tenant', None) + if self.args.tenant != '': + if tenant_scope is not None and tenant_scope != self.args.tenant: + raise Exception( + 'Error: Zuul API URL %s is ' + 'scoped to tenant "%s"' % (client.base_url, tenant_scope)) + else: + if tenant_scope is None: + raise Exception( + "Error: the --tenant argument is required" + ) + def add_autohold_subparser(self, subparsers): cmd_autohold = subparsers.add_parser( 'autohold', help='hold nodes for failed job') cmd_autohold.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_autohold.add_argument('--project', help='project name', required=True) cmd_autohold.add_argument('--job', help='job name', @@ -188,6 +201,7 @@ class ZuulClient(): node_hold_expiration = self.args.node_hold_expiration client = self.get_client() + self._check_tenant_scope(client) r = client.autohold( tenant=self.args.tenant, project=self.args.project, @@ -204,12 +218,13 @@ class ZuulClient(): 'autohold-delete', help='delete autohold request') cmd_autohold_delete.set_defaults(func=self.autohold_delete) cmd_autohold_delete.add_argument('--tenant', help='tenant name', - required=True, default=None) + required=False, default='') cmd_autohold_delete.add_argument('id', metavar='REQUEST_ID', help='the hold request ID') def autohold_delete(self): client = self.get_client() + self._check_tenant_scope(client) return client.autohold_delete(self.args.id, self.args.tenant) def add_autohold_info_subparser(self, subparsers): @@ -217,12 +232,13 @@ class ZuulClient(): 'autohold-info', help='retrieve autohold request detailed info') cmd_autohold_info.set_defaults(func=self.autohold_info) cmd_autohold_info.add_argument('--tenant', help='tenant name', - required=True, default=None) + required=False, default='') cmd_autohold_info.add_argument('id', metavar='REQUEST_ID', help='the hold request ID') def autohold_info(self): client = self.get_client() + self._check_tenant_scope(client) request = client.autohold_info(self.args.id, self.args.tenant) if not request: @@ -247,11 +263,12 @@ class ZuulClient(): cmd_autohold_list = subparsers.add_parser( 'autohold-list', help='list autohold requests') cmd_autohold_list.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_autohold_list.set_defaults(func=self.autohold_list) def autohold_list(self): client = self.get_client() + self._check_tenant_scope(client) autohold_requests = client.autohold_list(tenant=self.args.tenant) if not autohold_requests: @@ -281,7 +298,7 @@ class ZuulClient(): def add_enqueue_subparser(self, subparsers): cmd_enqueue = subparsers.add_parser('enqueue', help='enqueue a change') cmd_enqueue.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_enqueue.add_argument('--pipeline', help='pipeline name', required=True) cmd_enqueue.add_argument('--project', help='project name', @@ -292,6 +309,7 @@ class ZuulClient(): def enqueue(self): client = self.get_client() + self._check_tenant_scope(client) r = client.enqueue( tenant=self.args.tenant, pipeline=self.args.pipeline, @@ -310,7 +328,7 @@ class ZuulClient(): to manually "replay" a trigger received from an external source such as gerrit.''')) cmd_enqueue.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_enqueue.add_argument('--pipeline', help='pipeline name', required=True) cmd_enqueue.add_argument('--project', help='project name', @@ -325,6 +343,7 @@ class ZuulClient(): def enqueue_ref(self): client = self.get_client() + self._check_tenant_scope(client) r = client.enqueue_ref( tenant=self.args.tenant, pipeline=self.args.pipeline, @@ -339,7 +358,7 @@ class ZuulClient(): help='dequeue a buildset by its ' 'change or ref') cmd_dequeue.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_dequeue.add_argument('--pipeline', help='pipeline name', required=True) cmd_dequeue.add_argument('--project', help='project name', @@ -352,6 +371,7 @@ class ZuulClient(): def dequeue(self): client = self.get_client() + self._check_tenant_scope(client) r = client.dequeue( tenant=self.args.tenant, pipeline=self.args.pipeline, @@ -364,7 +384,7 @@ class ZuulClient(): cmd_promote = subparsers.add_parser('promote', help='promote one or more changes') cmd_promote.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_promote.add_argument('--pipeline', help='pipeline name', required=True) cmd_promote.add_argument('--changes', help='change ids', @@ -373,6 +393,7 @@ class ZuulClient(): def promote(self): client = self.get_client() + self._check_tenant_scope(client) r = client.promote( tenant=self.args.tenant, pipeline=self.args.pipeline, @@ -420,7 +441,7 @@ class ZuulClient(): cmd_encrypt = subparsers.add_parser( 'encrypt', help='Encrypt a secret to be used in a project\'s jobs') cmd_encrypt.add_argument('--tenant', help='tenant name', - required=True) + required=False, default='') cmd_encrypt.add_argument('--project', help='project name', required=True) cmd_encrypt.add_argument('--no-strip', action='store_true', @@ -469,6 +490,7 @@ class ZuulClient(): pubkey_file = tempfile.NamedTemporaryFile(delete=False) self.log.debug('Creating temporary key file %s' % pubkey_file.name) client = self.get_client() + self._check_tenant_scope(client) try: key = client.get_key(self.args.tenant, self.args.project) pubkey_file.write(str.encode(key))