def test_get_bucket_async(self): config.Bucket( id='master.tryserver.chromium.linux', project_id='chromium', revision='deadbeef', config_content=MASTER_TRYSERVER_CHROMIUM_LINUX_CONFIG_TEXT, config_content_binary=text_to_binary( MASTER_TRYSERVER_CHROMIUM_LINUX_CONFIG_TEXT), ).put() project, cfg = config.get_bucket_async( 'master.tryserver.chromium.linux').get_result() self.assertEqual(project, 'chromium') self.assertEqual( cfg, project_config_pb2.Bucket( name='master.tryserver.chromium.linux', acls=[ project_config_pb2.Acl(role=project_config_pb2.Acl.READER, group='all'), project_config_pb2.Acl( role=project_config_pb2.Acl.SCHEDULER, group='tryjob-access'), ]), ) self.assertIsNone( config.get_bucket_async('non.existing').get_result()[0])
def impl(): ctx = ndb.get_context() cache_key = 'role/%s/%s' % (identity_str, bucket_id) cache = yield ctx.memcache_get(cache_key) if cache is not None: raise ndb.Return(cache[0]) _, bucket_cfg = yield config.get_bucket_async(bucket_id) if not bucket_cfg: raise ndb.Return(None) if auth.is_admin(identity): raise ndb.Return(project_config_pb2.Acl.WRITER) # A LUCI service calling us in the context of some project is allowed to # do anything it wants in that project. We trust all LUCI services to do # authorization on their own for this case. A cross-project request must be # explicitly authorized in Buildbucket ACLs though (so we proceed to the # bucket_cfg check below). if identity.is_project: project_id, _ = config.parse_bucket_id(bucket_id) if project_id == identity.name: raise ndb.Return(project_config_pb2.Acl.WRITER) # Roles are just numbers. The higher the number, the more permissions # the identity has. We exploit this here to get the single maximally # permissive role for the current identity. role = None for rule in bucket_cfg.acls: if rule.role <= role: continue if (rule.identity == identity_str or (rule.group and auth.is_group_member(rule.group, identity))): role = rule.role yield ctx.memcache_set(cache_key, (role, ), time=60) raise ndb.Return(role)
def test_get_bucket_async(self): config.Bucket( id='master.tryserver.chromium.linux', project_id='chromium', revision='deadbeef', config_content=MASTER_TRYSERVER_CHROMIUM_LINUX_CONFIG_TEXT).put() cfg = config.get_bucket_async( 'master.tryserver.chromium.linux').get_result() self.assertEqual( cfg, project_config_pb2.Bucket( name='master.tryserver.chromium.linux', acls=[ project_config_pb2.Acl( role=project_config_pb2.Acl.READER, group='all'), project_config_pb2.Acl( role=project_config_pb2.Acl.SCHEDULER, group='tryjob-access'), ]), ) self.assertIsNone(config.get_bucket_async('non.existing').get_result())
def get_task_def(self, request): """Returns a swarming task definition for a build request.""" try: # Checks access too. request.build_request.bucket = api.convert_bucket( request.build_request.bucket) build_request = api.put_request_message_to_build_request( request.build_request) # Find builder config. builder_id = build_request.schedule_build_request.builder builder_cfg = None bucket_id = config.format_bucket_id(builder_id.project, builder_id.bucket) _, bucket_cfg = config.get_bucket_async(bucket_id).get_result() assert bucket_cfg, 'if there is no bucket, access check would fail' for cfg in bucket_cfg.swarming.builders: # pragma: no branch if cfg.name == builder_id.builder: builder_cfg = cfg break if not builder_cfg: raise endpoints.NotFoundException( 'Builder %s/%s/%s not found' % (builder_id.project, builder_id.bucket, builder_id.builder)) settings = config.get_settings_async().get_result() # Create a fake build and prepare a task definition. identity = auth.get_current_identity() build = build_request.create_build_async( 1, settings, builder_cfg, identity, utils.utcnow()).get_result() assert build.proto.HasField('infra') build.proto.number = 1 settings = config.get_settings_async().get_result() task_def = swarming.compute_task_def(build, settings, fake_build=True) task_def_json = json.dumps(task_def) return GetTaskDefinitionResponseMessage( task_definition=task_def_json, swarming_host=build.proto.infra.swarming.hostname, ) except errors.InvalidInputError as ex: raise endpoints.BadRequestException('invalid build request: %s' % ex.message)
def prepare_task_def_async(build, fake_build=False): """Prepares a swarming task definition. Validates the new build. If configured, generates a build number and updates the build. Creates a swarming task definition. Returns a tuple (bucket_cfg, builder_cfg, task_def). """ if build.lease_key: raise errors.InvalidInputError( 'Swarming buckets do not support creation of leased builds') if not build.parameters: raise errors.InvalidInputError( 'A build for bucket %r must have parameters' % build.bucket) builder_name = build.parameters.get(BUILDER_PARAMETER) if not isinstance(builder_name, basestring): raise errors.InvalidInputError('Invalid builder name %r' % builder_name) project_id, bucket_cfg = yield config.get_bucket_async(build.bucket) if not bucket_cfg.HasField('swarming'): raise errors.InvalidInputError( 'Bucket %s is not configured for swarming' % build.bucket) builder_cfg = None for b in bucket_cfg.swarming.builders: # pragma: no branch if b.name == builder_name: # pragma: no branch builder_cfg = b break if not builder_cfg: raise errors.InvalidInputError( 'Builder %r is not defined in bucket %r' % (builder_name, build.bucket)) build_number = None if builder_cfg.build_numbers: # pragma: no branch seq_name = '%s/%s' % (build.bucket, builder_name) if fake_build: # pragma: no cover | covered by swarmbucket_api_test build_number = 0 else: build_number = yield sequence.generate_async(seq_name, 1) build.tags.append('build_address:%s/%d' % (seq_name, build_number)) task_def = yield _create_task_def_async(project_id, bucket_cfg.swarming, builder_cfg, build, build_number, fake_build) raise ndb.Return(bucket_cfg, builder_cfg, task_def)
def has_any_of_roles_async(bucket, roles): """True if current identity has any of |roles| in |bucket|.""" assert bucket assert roles errors.validate_bucket_name(bucket) roles = set(roles) assert roles.issubset(project_config_pb2.Acl.Role.values()) if auth.is_admin(): raise ndb.Return(True) _, bucket_cfg = yield config.get_bucket_async(bucket) identity_str = auth.get_current_identity().to_bytes() if bucket_cfg: for rule in bucket_cfg.acls: if rule.role not in roles: continue if rule.identity == identity_str: raise ndb.Return(True) if rule.group and auth.is_group_member(rule.group): raise ndb.Return(True) raise ndb.Return(False)
def has_any_of_roles_async(bucket, roles): """True if current identity has any of |roles| in |bucket|.""" assert bucket assert roles errors.validate_bucket_name(bucket) roles = set(roles) assert roles.issubset(project_config_pb2.Acl.Role.values()) if auth.is_admin(): raise ndb.Return(True) bucket_cfg = yield config.get_bucket_async(bucket) identity_str = auth.get_current_identity().to_bytes() if bucket_cfg: for rule in bucket_cfg.acls: if rule.role not in roles: continue if rule.identity == identity_str: raise ndb.Return(True) if rule.group and auth.is_group_member(rule.group): raise ndb.Return(True) raise ndb.Return(False)