Merge lp:~cjwatson/launchpad/snap-release-fix-macaroon-auth into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18329
Proposed branch: lp:~cjwatson/launchpad/snap-release-fix-macaroon-auth
Merge into: lp:launchpad
Diff against target: 153 lines (+67/-20)
2 files modified
lib/lp/snappy/model/snapstoreclient.py (+1/-1)
lib/lp/snappy/tests/test_snapstoreclient.py (+66/-19)
To merge this branch: bzr merge lp:~cjwatson/launchpad/snap-release-fix-macaroon-auth
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+318352@code.launchpad.net

Commit message

Allow releasing a snap build to channels without a discharge macaroon.

Description of the change

I handled pushing but apparently forgot about releasing. Beefed up tests a bit for both.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/snappy/model/snapstoreclient.py'
--- lib/lp/snappy/model/snapstoreclient.py 2017-01-27 12:44:41 +0000
+++ lib/lp/snappy/model/snapstoreclient.py 2017-02-27 12:24:14 +0000
@@ -340,7 +340,7 @@
340 release_url, method="POST", json=data,340 release_url, method="POST", json=data,
341 auth=MacaroonAuth(341 auth=MacaroonAuth(
342 snap.store_secrets["root"],342 snap.store_secrets["root"],
343 snap.store_secrets["discharge"]))343 snap.store_secrets.get("discharge")))
344 except requests.HTTPError as e:344 except requests.HTTPError as e:
345 if e.response is not None:345 if e.response is not None:
346 error = None346 error = None
347347
=== modified file 'lib/lp/snappy/tests/test_snapstoreclient.py'
--- lib/lp/snappy/tests/test_snapstoreclient.py 2017-01-27 12:44:41 +0000
+++ lib/lp/snappy/tests/test_snapstoreclient.py 2017-02-27 12:24:14 +0000
@@ -323,11 +323,13 @@
323 self.client.requestPackageUploadPermission,323 self.client.requestPackageUploadPermission,
324 snappy_series, "test-snap")324 snappy_series, "test-snap")
325325
326 def test_upload(self):326 def makeUploadableSnapBuild(self, store_secrets=None):
327 if store_secrets is None:
328 store_secrets = self._make_store_secrets()
327 snap = self.factory.makeSnap(329 snap = self.factory.makeSnap(
328 store_upload=True,330 store_upload=True,
329 store_series=self.factory.makeSnappySeries(name="rolling"),331 store_series=self.factory.makeSnappySeries(name="rolling"),
330 store_name="test-snap", store_secrets=self._make_store_secrets())332 store_name="test-snap", store_secrets=store_secrets)
331 snapbuild = self.factory.makeSnapBuild(snap=snap)333 snapbuild = self.factory.makeSnapBuild(snap=snap)
332 snap_lfa = self.factory.makeLibraryFileAlias(334 snap_lfa = self.factory.makeLibraryFileAlias(
333 filename="test-snap.snap", content="dummy snap content")335 filename="test-snap.snap", content="dummy snap content")
@@ -336,6 +338,10 @@
336 filename="test-snap.manifest", content="dummy manifest content")338 filename="test-snap.manifest", content="dummy manifest content")
337 self.factory.makeSnapFile(339 self.factory.makeSnapFile(
338 snapbuild=snapbuild, libraryfile=manifest_lfa)340 snapbuild=snapbuild, libraryfile=manifest_lfa)
341 return snapbuild
342
343 def test_upload(self):
344 snapbuild = self.makeUploadableSnapBuild()
339 transaction.commit()345 transaction.commit()
340 with dbuser(config.ISnapStoreUploadJobSource.dbuser):346 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
341 with HTTMock(self._unscanned_upload_handler,347 with HTTMock(self._unscanned_upload_handler,
@@ -362,6 +368,37 @@
362 "name": "test-snap", "updown_id": 1, "series": "rolling",368 "name": "test-snap", "updown_id": 1, "series": "rolling",
363 }))369 }))
364370
371 def test_upload_no_discharge(self):
372 root_key = hashlib.sha256(self.factory.getUniqueString()).hexdigest()
373 root_macaroon = Macaroon(key=root_key)
374 snapbuild = self.makeUploadableSnapBuild(
375 store_secrets={"root": root_macaroon.serialize()})
376 transaction.commit()
377 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
378 with HTTMock(self._unscanned_upload_handler,
379 self._snap_push_handler):
380 self.assertEqual(
381 "http://sca.example/dev/api/snaps/1/builds/1/status",
382 self.client.upload(snapbuild))
383 self.assertThat(self.unscanned_upload_requests, MatchesListwise([
384 RequestMatches(
385 url=Equals("http://updown.example/unscanned-upload/"),
386 method=Equals("POST"),
387 form_data={
388 "binary": MatchesStructure.byEquality(
389 name="binary", filename="test-snap.snap",
390 value="dummy snap content",
391 type="application/octet-stream",
392 )})]))
393 self.assertThat(self.snap_push_request, RequestMatches(
394 url=Equals("http://sca.example/dev/api/snap-push/"),
395 method=Equals("POST"),
396 headers=ContainsDict({"Content-Type": Equals("application/json")}),
397 auth=("Macaroon", MacaroonsVerify(root_key)),
398 json_data={
399 "name": "test-snap", "updown_id": 1, "series": "rolling",
400 }))
401
365 def test_upload_unauthorized(self):402 def test_upload_unauthorized(self):
366 @urlmatch(path=r".*/snap-push/$")403 @urlmatch(path=r".*/snap-push/$")
367 def snap_push_handler(url, request):404 def snap_push_handler(url, request):
@@ -372,14 +409,7 @@
372 }409 }
373410
374 store_secrets = self._make_store_secrets()411 store_secrets = self._make_store_secrets()
375 snap = self.factory.makeSnap(412 snapbuild = self.makeUploadableSnapBuild(store_secrets=store_secrets)
376 store_upload=True,
377 store_series=self.factory.makeSnappySeries(name="rolling"),
378 store_name="test-snap", store_secrets=store_secrets)
379 snapbuild = self.factory.makeSnapBuild(snap=snap)
380 lfa = self.factory.makeLibraryFileAlias(
381 filename="test-snap.snap", content="dummy snap content")
382 self.factory.makeSnapFile(snapbuild=snapbuild, libraryfile=lfa)
383 transaction.commit()413 transaction.commit()
384 with dbuser(config.ISnapStoreUploadJobSource.dbuser):414 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
385 with HTTMock(self._unscanned_upload_handler, snap_push_handler,415 with HTTMock(self._unscanned_upload_handler, snap_push_handler,
@@ -402,14 +432,7 @@
402 snap_push_handler.call_count = 0432 snap_push_handler.call_count = 0
403433
404 store_secrets = self._make_store_secrets()434 store_secrets = self._make_store_secrets()
405 snap = self.factory.makeSnap(435 snapbuild = self.makeUploadableSnapBuild(store_secrets=store_secrets)
406 store_upload=True,
407 store_series=self.factory.makeSnappySeries(name="rolling"),
408 store_name="test-snap", store_secrets=store_secrets)
409 snapbuild = self.factory.makeSnapBuild(snap=snap)
410 lfa = self.factory.makeLibraryFileAlias(
411 filename="test-snap.snap", content="dummy snap content")
412 self.factory.makeSnapFile(snapbuild=snapbuild, libraryfile=lfa)
413 transaction.commit()436 transaction.commit()
414 with dbuser(config.ISnapStoreUploadJobSource.dbuser):437 with dbuser(config.ISnapStoreUploadJobSource.dbuser):
415 with HTTMock(self._unscanned_upload_handler, snap_push_handler,438 with HTTMock(self._unscanned_upload_handler, snap_push_handler,
@@ -419,7 +442,8 @@
419 self.client.upload(snapbuild))442 self.client.upload(snapbuild))
420 self.assertEqual(2, snap_push_handler.call_count)443 self.assertEqual(2, snap_push_handler.call_count)
421 self.assertNotEqual(444 self.assertNotEqual(
422 store_secrets["discharge"], snap.store_secrets["discharge"])445 store_secrets["discharge"],
446 snapbuild.snap.store_secrets["discharge"])
423447
424 def test_refresh_discharge_macaroon(self):448 def test_refresh_discharge_macaroon(self):
425 store_secrets = self._make_store_secrets()449 store_secrets = self._make_store_secrets()
@@ -595,6 +619,29 @@
595 "channels": ["stable", "edge"], "series": "rolling",619 "channels": ["stable", "edge"], "series": "rolling",
596 }))620 }))
597621
622 def test_release_no_discharge(self):
623 root_key = hashlib.sha256(self.factory.getUniqueString()).hexdigest()
624 root_macaroon = Macaroon(key=root_key)
625 with HTTMock(self._channels_handler):
626 snap = self.factory.makeSnap(
627 store_upload=True,
628 store_series=self.factory.makeSnappySeries(name="rolling"),
629 store_name="test-snap",
630 store_secrets={"root": root_macaroon.serialize()},
631 store_channels=["stable", "edge"])
632 snapbuild = self.factory.makeSnapBuild(snap=snap)
633 with HTTMock(self._snap_release_handler):
634 self.client.release(snapbuild, 1)
635 self.assertThat(self.snap_release_request, RequestMatches(
636 url=Equals("http://sca.example/dev/api/snap-release/"),
637 method=Equals("POST"),
638 headers=ContainsDict({"Content-Type": Equals("application/json")}),
639 auth=("Macaroon", MacaroonsVerify(root_key)),
640 json_data={
641 "name": "test-snap", "revision": 1,
642 "channels": ["stable", "edge"], "series": "rolling",
643 }))
644
598 def test_release_error(self):645 def test_release_error(self):
599 @urlmatch(path=r".*/snap-release/$")646 @urlmatch(path=r".*/snap-release/$")
600 def handler(url, request):647 def handler(url, request):