def test_setAccountStatus(self): person = self.factory.makePerson() registrar = self.factory.makePerson( name='registrar', member_of=[getUtility(IPersonSet).getByName('registry')]) person_url = api_url(person) # A normal user cannot set even their own account status. webservice = webservice_for_person( person, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.named_post( person_url, 'setAccountStatus', status='Suspended', comment='Go away', api_version='devel') self.assertEqual(401, response.status) # A member of ~registry can do what they wish. webservice = webservice_for_person( registrar, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.named_post( person_url, 'setAccountStatus', status='Suspended', comment='Go away', api_version='devel') self.assertEqual(200, response.status) with admin_logged_in(): self.assertEqual(AccountStatus.SUSPENDED, person.account_status) self.assertEndsWith( person.account_status_history, 'registrar: Active -> Suspended: Go away\n')
def test_creation_honor_product_sharing_policy(self): # `ISpecificationSet.createSpecification` respect product # specification_sharing_policy. user = self.factory.makePerson() product = self.factory.makeProduct( owner=user, specification_sharing_policy=( SpecificationSharingPolicy.PROPRIETARY)) product_url = api_url(product) webservice = webservice_for_person( user, permission=OAuthPermission.WRITE_PRIVATE) spec_name = 'test-prop' response = webservice.named_post('/specs', 'createSpecification', name=spec_name, title='Proprietary', specurl='http://test.com', definition_status='Approved', summary='A summary', target=product_url, api_version='devel') self.assertEqual(201, response.status) # The new specification was created as PROPROETARY. response = webservice.get('%s/+spec/%s' % (product_url, spec_name)) self.assertEqual(200, response.status) self.assertEqual('Proprietary', response.jsonBody()['information_type'])
def test_set_target(self): old_target = self.factory.makeProduct() spec = self.factory.makeSpecification(product=old_target, name='foo') new_target = self.factory.makeProduct(displayname='Fooix') spec_url = api_url(spec) new_target_url = api_url(new_target) webservice = webservice_for_person( old_target.owner, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.patch(spec_url, "application/json", json.dumps( dict(target_link=new_target_url)), api_version='devel') self.assertEqual(301, response.status) with admin_logged_in(): self.assertEqual(new_target, spec.target) # Moving another spec with the same name fails. other_spec = self.factory.makeSpecification(product=old_target, name='foo') other_spec_url = api_url(other_spec) response = webservice.patch(other_spec_url, "application/json", json.dumps( dict(target_link=new_target_url)), api_version='devel') self.assertEqual(400, response.status) self.assertEqual("There is already a blueprint named foo for Fooix.", response.body)
def test_new_duplicate_name(self): # An attempt to create a SnapBase with a duplicate name is rejected. person = self.factory.makeRegistryExpert() distroseries = self.factory.makeDistroSeries() distroseries_url = api_url(distroseries) webservice = webservice_for_person( person, permission=OAuthPermission.WRITE_PUBLIC) webservice.default_api_version = "devel" logout() response = webservice.named_post( "/+snap-bases", "new", name="dummy", display_name="Dummy", distro_series=distroseries_url, build_channels={"snapcraft": "stable"}) self.assertEqual(201, response.status) response = webservice.named_post( "/+snap-bases", "new", name="dummy", display_name="Dummy", distro_series=distroseries_url, build_channels={"snapcraft": "stable"}) self.assertEqual(400, response.status) self.assertEqual("name: dummy is already in use by another base.", response.body)
def test_new(self): # A registry expert can create a SnapBase. person = self.factory.makeRegistryExpert() distroseries = self.factory.makeDistroSeries() distroseries_url = api_url(distroseries) webservice = webservice_for_person( person, permission=OAuthPermission.WRITE_PUBLIC) webservice.default_api_version = "devel" logout() response = webservice.named_post( "/+snap-bases", "new", name="dummy", display_name="Dummy", distro_series=distroseries_url, build_channels={"snapcraft": "stable"}) self.assertEqual(201, response.status) snap_base = webservice.get(response.getHeader("Location")).jsonBody() with person_logged_in(person): self.assertThat( snap_base, ContainsDict({ "registrant_link": Equals(webservice.getAbsoluteUrl(api_url(person))), "name": Equals("dummy"), "display_name": Equals("Dummy"), "distro_series_link": Equals(webservice.getAbsoluteUrl(distroseries_url)), "build_channels": Equals({"snapcraft": "stable"}), "is_default": Is(False), }))
def test_representation(self): with admin_logged_in(): faq = self.factory.makeFAQ(title="Nothing works") with notify_modified(faq, ['keywords', 'content'], user=faq.owner): faq.keywords = "foo bar" faq.content = "It is all broken." faq_url = api_url(faq) webservice = webservice_for_person(self.factory.makePerson()) repr = webservice.get(faq_url, api_version='devel').jsonBody() with admin_logged_in(): self.assertThat( repr, ContainsDict({ "id": Equals(faq.id), "title": Equals("Nothing works"), "keywords": Equals("foo bar"), "content": Equals("It is all broken."), "date_created": MatchesRegex("\d\d\d\d-\d\d-\d\dT.*"), "date_last_updated": MatchesRegex("\d\d\d\d-\d\d-\d\dT.*"), "last_updated_by_link": Contains("/devel/~%s" % faq.owner.name), "target_link": Contains("/devel/%s" % faq.target.name), }))
def test_security(self): # Attributes can only be set by buildd admins. builder = self.factory.makeBuilder() user = self.factory.makePerson() user_webservice = webservice_for_person( user, permission=OAuthPermission.WRITE_PUBLIC) patch = dumps({'clean_status': 'Cleaning'}) logout() # A normal user is unauthorized. response = user_webservice.patch(api_url(builder), 'application/json', patch, api_version='devel') self.assertEqual(401, response.status) # But a buildd admin can set the attribute. with admin_logged_in(): buildd_admins = getUtility(IPersonSet).getByName( 'launchpad-buildd-admins') buildd_admins.addMember(user, buildd_admins.teamowner) response = user_webservice.patch(api_url(builder), 'application/json', patch, api_version='devel') self.assertEqual(209, response.status) self.assertEqual('Cleaning', response.jsonBody()['clean_status'])
def test_checkPermissions(self): [ref] = self.factory.makeGitRefs() owner = ref.owner grantees = [self.factory.makePerson() for _ in range(2)] self.factory.makeGitRuleGrant(repository=ref.repository, ref_pattern=ref.path, grantee=grantees[0], can_create=True) self.factory.makeGitRuleGrant(repository=ref.repository, ref_pattern="*", grantee=grantees[1], can_force_push=True) with person_logged_in(owner): ref_url = api_url(ref) owner_url = api_url(owner) grantee_urls = [api_url(grantee) for grantee in grantees] webservice = webservice_for_person( owner, permission=OAuthPermission.WRITE_PUBLIC) webservice.default_api_version = "devel" response = webservice.named_get(ref_url, "checkPermissions", person=owner_url) self.assertEqual(["create", "push"], json.loads(response.body)) response = webservice.named_get(ref_url, "checkPermissions", person=grantee_urls[0]) self.assertEqual(["create"], json.loads(response.body)) response = webservice.named_get(ref_url, "checkPermissions", person=grantee_urls[1]) self.assertEqual(["push", "force-push"], json.loads(response.body))
def setUp(self): super(TestWebhookTargetBase, self).setUp() self.target = self.makeTarget() self.owner = self.target.owner self.target_url = api_url(self.target) self.webservice = webservice_for_person( self.owner, permission=OAuthPermission.WRITE_PRIVATE)
def setUp(self): super(TestBinaryPackageBuildWebservice, self).setUp() self.ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA) self.build = self.factory.makeBinaryPackageBuild(archive=self.ppa) self.webservice = webservice_for_person( self.ppa.owner, permission=OAuthPermission.WRITE_PUBLIC) login(ANONYMOUS)
def test_requestBuild_not_owner(self): # If the requester is not the owner or a member of the owner team, # build requests are rejected. other_team = self.factory.makeTeam(displayname="Other Team") distroseries = self.factory.makeDistroSeries(registrant=self.person) distroarchseries = self.factory.makeDistroArchSeries( distroseries=distroseries, owner=self.person) distroarchseries_url = api_url(distroarchseries) archive_url = api_url(distroseries.main_archive) other_webservice = webservice_for_person( other_team.teamowner, permission=OAuthPermission.WRITE_PUBLIC) other_webservice.default_api_version = "devel" login(ANONYMOUS) livefs, _ = self.makeLiveFS(owner=other_team, distroseries=distroseries, webservice=other_webservice) response = self.webservice.named_post( livefs["self_link"], "requestBuild", archive=archive_url, distro_arch_series=distroarchseries_url, pocket="Release") self.assertEqual(401, response.status) self.assertEqual( "Test Person cannot create live filesystem builds owned by Other " "Team.", response.body)
def test_landing_targets_constant_queries(self): project = self.factory.makeProduct() with person_logged_in(project.owner): source = self.factory.makeBranch(target=project) source_url = api_url(source) webservice = webservice_for_person( project.owner, permission=OAuthPermission.WRITE_PRIVATE) def create_mp(): with admin_logged_in(): branch = self.factory.makeBranch( target=project, stacked_on=self.factory.makeBranch( target=project, information_type=InformationType.PRIVATESECURITY), information_type=InformationType.PRIVATESECURITY) self.factory.makeBranchMergeProposal(source_branch=source, target_branch=branch) def list_mps(): webservice.get(source_url + '/landing_targets') list_mps() recorder1, recorder2 = record_two_runs(list_mps, create_mp, 2) self.assertThat(recorder1, HasQueryCount(LessThan(30))) self.assertThat(recorder2, HasQueryCount.byEquality(recorder1))
def setProcessors(self, user, archive_url, names): ws = webservice_for_person( user, permission=OAuthPermission.WRITE_PUBLIC) return ws.named_post( archive_url, 'setProcessors', processors=['/+processors/%s' % name for name in names], api_version='devel')
def setUp(self): super(TestLiveFSWebservice, self).setUp() self.useFixture(FeatureFixture({LIVEFS_FEATURE_FLAG: "on"})) self.person = self.factory.makePerson(displayname="Test Person") self.webservice = webservice_for_person( self.person, permission=OAuthPermission.WRITE_PUBLIC) self.webservice.default_api_version = "devel" login(ANONYMOUS)
def setUp(self): super(TestSnapBuildWebservice, self).setUp() self.useFixture(FeatureFixture(SNAP_TESTING_FLAGS)) self.person = self.factory.makePerson() self.webservice = webservice_for_person( self.person, permission=OAuthPermission.WRITE_PRIVATE) self.webservice.default_api_version = "devel" login(ANONYMOUS)
def make_old_bug(self): bug = self.factory.makeBug() one_year_ago = datetime.now(pytz.UTC) - timedelta(days=365) removeSecurityProxy(bug).date_last_updated = one_year_ago owner = bug.owner with person_logged_in(owner): webservice = webservice_for_person( owner, permission=OAuthPermission.WRITE_PUBLIC) return (bug, owner, webservice)
def test_getByReference_private(self): with admin_logged_in(): archive = self.factory.makeArchive(private=True) owner = archive.owner reference = archive.reference random = self.factory.makePerson() body = LaunchpadWebServiceCaller('consumer', '').named_get( '/archives', 'getByReference', reference=reference, api_version='devel').jsonBody() self.assertIs(None, body) body = webservice_for_person(random).named_get( '/archives', 'getByReference', reference=reference, api_version='devel').jsonBody() self.assertIs(None, body) body = webservice_for_person(owner).named_get( '/archives', 'getByReference', reference=reference, api_version='devel').jsonBody() self.assertEqual(body['reference'], reference)
def test_security_contact_exported(self): # security_contact is exported for 1.0, but not for other versions. product = self.factory.makeProduct() webservice = webservice_for_person(product.owner) api_prod = self.fetch_product(webservice, product, '1.0') self.assertIs(None, api_prod['security_contact']) for api_version in ('beta', 'devel'): api_prod = self.fetch_product(webservice, product, api_version) self.assertNotIn('security_contact', api_prod)
def assertScoreReadableByAnyone(self, obj): """An object's build score is readable by anyone.""" with person_logged_in(obj.owner): obj_url = api_url(obj) removeSecurityProxy(obj).relative_build_score = 100 webservice = webservice_for_person( self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC) entry = webservice.get(obj_url, api_version="devel").jsonBody() self.assertEqual(100, entry["relative_build_score"])
def test_xhtml_email_address_not_obfuscated(self): # Email addresses are not obfuscated for authenticated users. bug = self._makeBug() user = self.factory.makePerson() webservice = webservice_for_person(user) result = webservice(ws_url(bug), headers={'Accept': 'application/xhtml+xml'}) self.assertIn(self.email_address, result.body) self.assertNotIn(self.email_address_obfuscated_escaped, result.body)
def test_email_address_not_obfuscated(self): # Email addresses are not obfuscated for authenticated users. bug = self._makeBug() user = self.factory.makePerson() webservice = webservice_for_person(user) result = webservice(ws_url(bug)).jsonBody() self.assertEqual(self.bug_title % self.email_address, result['title']) self.assertEqual( self.bug_description % self.email_address, result['description'])
def addSSHKeyForPerson(self, openid_identifier, key_text, dry_run=False): with admin_logged_in(): sso = getUtility(IPersonSet).getByName('ubuntu-sso') webservice = webservice_for_person( sso, permission=OAuthPermission.WRITE_PRIVATE) return webservice.named_post( '/people', 'addSSHKeyFromSSO', openid_identifier=openid_identifier, key_text=key_text, dry_run=dry_run, api_version='devel')
def test_email_address_not_obfuscated(self): # Email addresses are not obfuscated for authenticated users. bug = self._makeBug() user = self.factory.makePerson() webservice = webservice_for_person(user) result = webservice(ws_url(bug)).jsonBody() self.assertEqual(self.bug_title % self.email_address, result['title']) self.assertEqual(self.bug_description % self.email_address, result['description'])
def setUsernameFromSSO(self, user, openid_identifier, name, dry_run=False): webservice = webservice_for_person( user, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.named_post( '/people', 'setUsernameFromSSO', openid_identifier=openid_identifier, name=name, dry_run=dry_run, api_version='devel') return response
def getOrCreateSoftwareCenterCustomer(self, user): webservice = webservice_for_person( user, permission=OAuthPermission.WRITE_PRIVATE) response = webservice.named_post( '/people', 'getOrCreateSoftwareCenterCustomer', openid_identifier='somebody', email_address='*****@*****.**', display_name='Somebody', api_version='devel') return response
def test_getByReference(self): random = self.factory.makePerson() body = LaunchpadWebServiceCaller('consumer', '').named_get( '/archives', 'getByReference', reference='ubuntu', api_version='devel').jsonBody() self.assertEqual(body['reference'], 'ubuntu') body = webservice_for_person(random).named_get( '/archives', 'getByReference', reference='ubuntu', api_version='devel').jsonBody() self.assertEqual(body['reference'], 'ubuntu')
def test_xhtml_email_address_not_obfuscated(self): # Email addresses are not obfuscated for authenticated users. bug = self._makeBug() user = self.factory.makePerson() webservice = webservice_for_person(user) result = webservice( ws_url(bug), headers={'Accept': 'application/xhtml+xml'}) self.assertIn(self.email_address, result.body) self.assertNotIn( self.email_address_obfuscated_escaped, result.body)
def test_getSSHKeysForSSO_nonexistent(self): with admin_logged_in(): sso = getUtility(IPersonSet).getByName('ubuntu-sso') webservice = webservice_for_person( sso, permission=OAuthPermission.READ_PUBLIC) response = webservice.named_get( '/people', 'getSSHKeysForSSO', openid_identifier='doesnotexist', api_version='devel') self.assertEqual(200, response.status) self.assertEqual(None, response.jsonBody())
def test_public(self): # A SnapBuild with a public Snap and archive is itself public. db_build = self.factory.makeSnapBuild() build_url = api_url(db_build) unpriv_webservice = webservice_for_person( self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC) unpriv_webservice.default_api_version = "devel" logout() self.assertEqual(200, self.webservice.get(build_url).status) self.assertEqual(200, unpriv_webservice.get(build_url).status)
def setUp(self): super(TestWebhook, self).setUp() target = self.factory.makeGitRepository() self.owner = target.owner with person_logged_in(self.owner): self.webhook = self.factory.makeWebhook( target=target, delivery_url=u'http://example.com/ep') self.webhook_url = api_url(self.webhook) self.webservice = webservice_for_person( self.owner, permission=OAuthPermission.WRITE_PRIVATE)
def test_delete_is_restricted(self): with admin_logged_in(): ppa = self.factory.makeArchive(purpose=ArchivePurpose.PPA) ppa_url = api_url(ppa) ws = webservice_for_person( self.factory.makePerson(), permission=OAuthPermission.WRITE_PRIVATE) # A random user can't delete someone else's PPA. self.assertEqual(401, ws.delete(ppa_url, api_version='devel').status)
def test_cancel_security(self): # Check that unauthorised users cannot call cancel() build_url = api_url(self.build) webservice = webservice_for_person( self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC) logout() entry = webservice.get(build_url, api_version='devel').jsonBody() response = webservice.named_post( entry['self_link'], 'cancel', api_version='devel') self.assertEqual(401, response.status)
def assertScoreWriteableByTeam(self, obj, team): """Members of TEAM can change an object's build score.""" with person_logged_in(obj.owner): obj_url = api_url(obj) person = self.factory.makePerson(member_of=[team]) webservice = webservice_for_person( person, permission=OAuthPermission.WRITE_PUBLIC) entry = webservice.get(obj_url, api_version="devel").jsonBody() response = webservice.patch( entry["self_link"], "application/json", dumps(dict(relative_build_score=100))) self.assertEqual(209, response.status) self.assertEqual(100, response.jsonBody()["relative_build_score"])
def test_binaryFileUrls(self): person = self.factory.makePerson() webservice = webservice_for_person( person, permission=OAuthPermission.READ_PUBLIC) response = webservice.named_get( self.make_bpph_for(person)[1], 'binaryFileUrls', api_version='devel') self.assertEqual(200, response.status) urls = response.jsonBody() self.assertEqual(1, len(urls)) self.assertTrue(urls[0], IsInstance(unicode))
def test_bug_sharing_policy_can_be_set(self): # bug_sharing_policy can be set via the API. product = self.factory.makeProduct() owner = product.owner self.factory.makeCommercialSubscription(product=product) webservice = webservice_for_person( product.owner, permission=OAuthPermission.WRITE_PRIVATE) response = self.patch( webservice, product, bug_sharing_policy='Proprietary') self.assertEqual(209, response.status) with person_logged_in(owner): self.assertEqual( BugSharingPolicy.PROPRIETARY, product.bug_sharing_policy)
def test_representation_is_empty_on_1_dot_0(self): # ISpecification is exposed on the 1.0 version so that they can be # linked against branches, but none of its fields is exposed on that # version as we expect it to undergo significant refactorings before # it's ready for prime time. spec = self.factory.makeSpecification() user = self.factory.makePerson() url = '/%s/+spec/%s' % (spec.product.name, spec.name) webservice = webservice_for_person(user) response = webservice.get(url) expected_keys = [u'self_link', u'http_etag', u'resource_type_link', u'web_link', u'information_type'] self.assertEqual(response.status, 200) self.assertContentEqual(expected_keys, response.jsonBody().keys())
def test_branch_sharing_policy_non_commercial(self): # An API attempt to set a commercial-only branch_sharing_policy # on a non-commercial project returns Forbidden. product = self.factory.makeProduct() owner = product.owner webservice = webservice_for_person( product.owner, permission=OAuthPermission.WRITE_PRIVATE) response = self.patch( webservice, product, branch_sharing_policy='Proprietary') self.assertThat(response, MatchesStructure.byEquality( status=403, body=('A current commercial subscription is required to use ' 'proprietary branches.'))) with person_logged_in(owner): self.assertEqual( BranchSharingPolicy.PUBLIC, product.branch_sharing_policy)
def test_etags_differ_for_anon_and_non_anon_represetations(self): # When a webservice client retrieves data anonymously, this # data should not be used in later write requests, if the # text fields contain obfuscated email addresses. The etag # for a GET request is calculated after the email address # obfuscation and thus differs from the etag returned for # not obfuscated data, so clients usings etags to check if the # cached data is up to date will not use the obfuscated data # in PATCH or PUT requests. bug = self._makeBug() user = self.factory.makePerson() webservice = webservice_for_person(user) etag_logged_in = webservice(ws_url(bug)).getheader('etag') logout() webservice = LaunchpadWebServiceCaller() etag_logged_out = webservice(ws_url(bug)).getheader('etag') self.assertNotEqual(etag_logged_in, etag_logged_out)
def assertScoreNotWriteableByOwner(self, obj): """Being an object's owner does not allow changing its build score. This affects a site-wide resource, and is thus restricted to launchpad-buildd-admins. """ with person_logged_in(obj.owner): obj_url = api_url(obj) webservice = webservice_for_person( obj.owner, permission=OAuthPermission.WRITE_PUBLIC) entry = webservice.get(obj_url, api_version="devel").jsonBody() response = webservice.patch( entry["self_link"], "application/json", dumps(dict(relative_build_score=100))) self.assertEqual(401, response.status) new_entry = webservice.get(obj_url, api_version="devel").jsonBody() self.assertEqual(0, new_entry["relative_build_score"])
def test_binaryFileUrls_include_meta(self): person = self.factory.makePerson() webservice = webservice_for_person( person, permission=OAuthPermission.READ_PUBLIC) bpph, url = self.make_bpph_for(person) query_counts = [] for i in range(3): flush_database_caches() with QueryCollector() as collector: response = webservice.named_get( url, 'binaryFileUrls', include_meta=True, api_version='devel') query_counts.append(collector.count) with person_logged_in(person): self.factory.makeBinaryPackageFile( binarypackagerelease=bpph.binarypackagerelease) self.assertEqual(query_counts[0] - 1, query_counts[-1]) self.assertEqual(200, response.status) urls = response.jsonBody() self.assertEqual(3, len(urls)) self.assertThat(urls[0], IsInstance(dict))