{"action":"created","comment":{"url":"https://api.github.com/repos/CanonicalLtd/candid/pulls/comments/229676676","pull_request_review_id":170229805,"id":229676676,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyOTY3NjY3Ng==","diff_hunk":"@@ -0,0 +1,103 @@\n+// Copyright 2017 Canonical Ltd.\n+// Licensed under the AGPLv3, see LICENCE file for details.\n+\n+// Package candidtest provides suites and functions useful for testing the\n+// identity manager.\n+package candidtest\n+\n+import (\n+\t\"net/url\"\n+\t\"time\"\n+\n+\tqt \"github.com/frankban/quicktest\"\n+\t\"golang.org/x/net/context\"\n+\t\"gopkg.in/macaroon-bakery.v2/bakery\"\n+\t\"gopkg.in/macaroon-bakery.v2/bakery/checkers\"\n+\t\"gopkg.in/macaroon-bakery.v2/bakery/identchecker\"\n+\t\"gopkg.in/macaroon-bakery.v2/httpbakery\"\n+\tmacaroon \"gopkg.in/macaroon.v2\"\n+)\n+\n+// DischargeCreator represents a third party service\n+// that creates discharges addressed to Candid.\n+type DischargeCreator struct {\n+\tServerURL string\n+\n+\tBakery *identchecker.Bakery\n+\n+\tbakeryKey *bakery.KeyPair\n+}\n+\n+// NewDischargeCreator returns a DischargeCreator that\n+// creates third party caveats addressed to the given server,\n+// which must be serving the \"discharger\" API.\n+func NewDischargeCreator(server *Server) *DischargeCreator {\n+\tbakeryKey, err := bakery.GenerateKey()\n+\tif err != nil {\n+\t\tpanic(err)\n+\t}\n+\treturn &DischargeCreator{\n+\t\tServerURL: server.URL,\n+\t\tBakery: identchecker.NewBakery(identchecker.BakeryParams{\n+\t\t\tLocator:        server,\n+\t\t\tKey:            bakeryKey,\n+\t\t\tIdentityClient: server.AdminIdentityClient(),\n+\t\t\tLocation:       \"discharge-test\",\n+\t\t}),\n+\t\tbakeryKey: bakeryKey,\n+\t}\n+}\n+\n+// AssertDischarge checks that a macaroon can be discharged with\n+// interaction using the specified visitor.\n+func (s *DischargeCreator) AssertDischarge(c *qt.C, i httpbakery.Interactor) {\n+\tms, err := s.Discharge(c, \"is-authenticated-user\", BakeryClient(i))\n+\tc.Assert(err, qt.Equals, nil)\n+\t_, err = s.Bakery.Checker.Auth(ms).Allow(context.Background(), identchecker.LoginOp)\n+\tc.Assert(err, qt.Equals, nil)\n+}\n+\n+// Discharge attempts to perform a discharge of a new macaroon against\n+// this suites identity server using the given client and returns a\n+// macaroon slice containing a discharged macaroon or any error. The\n+// newly minted macaroon will have a third-party caveat addressed to the\n+// identity server with the given condition.\n+func (s *DischargeCreator) Discharge(c *qt.C, condition string, client *httpbakery.Client) (macaroon.Slice, error) {\n+\treturn client.DischargeAll(context.Background(), s.NewMacaroon(c, condition, identchecker.LoginOp))\n+}\n+\n+// NewMacaroon creates a new macaroon with a third-party caveat addressed\n+// to the identity server which has the given condition.\n+func (s *DischargeCreator) NewMacaroon(c *qt.C, condition string, op bakery.Op) *bakery.Macaroon {\n+\tm, err := s.Bakery.Oven.NewMacaroon(\n+\t\tcontext.Background(),\n+\t\tbakery.LatestVersion,\n+\t\t[]checkers.Caveat{{\n+\t\t\tLocation:  s.ServerURL,\n+\t\t\tCondition: condition,\n+\t\t}, checkers.TimeBeforeCaveat(time.Now().Add(time.Minute))},\n+\t\top,\n+\t)\n+\tc.Assert(err, qt.Equals, nil)\n+\treturn m\n+}\n+\n+// AssertMacaroon asserts that the given macaroon slice is valid for the\n+// given operation. If id is specified then the declared identity in the\n+// macaroon is checked to be the same as id.\n+func (s *DischargeCreator) AssertMacaroon(c *qt.C, ms macaroon.Slice, op bakery.Op, id string) {\n+\tui, err := s.Bakery.Checker.Auth(ms).Allow(context.Background(), op)\n+\tc.Assert(err, qt.Equals, nil)\n+\tif id == \"\" {\n+\t\treturn\n+\t}\n+\tc.Assert(ui.Identity.Id(), qt.Equals, id)\n+}\n+\n+// A VisitorFunc converts a function to a httpbakery.LegacyInteractor.\n+type VisitorFunc func(*url.URL) error\n+\n+// VisitWebPage implements httpbakery.Visitor.VisitWebPage.","path":"internal/qtcandidtest/discharge.go","position":100,"original_position":100,"commit_id":"4b6e7224843202754e44bf455704c8f37e00c6cc","original_commit_id":"4b6e7224843202754e44bf455704c8f37e00c6cc","user":{"login":"rogpeppe","id":66491,"node_id":"MDQ6VXNlcjY2NDkx","avatar_url":"https://avatars0.githubusercontent.com/u/66491?v=4","gravatar_id":"","url":"https://api.github.com/users/rogpeppe","html_url":"https://github.com/rogpeppe","followers_url":"https://api.github.com/users/rogpeppe/followers","following_url":"https://api.github.com/users/rogpeppe/following{/other_user}","gists_url":"https://api.github.com/users/rogpeppe/gists{/gist_id}","starred_url":"https://api.github.com/users/rogpeppe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rogpeppe/subscriptions","organizations_url":"https://api.github.com/users/rogpeppe/orgs","repos_url":"https://api.github.com/users/rogpeppe/repos","events_url":"https://api.github.com/users/rogpeppe/events{/privacy}","received_events_url":"https://api.github.com/users/rogpeppe/received_events","type":"User","site_admin":false},"body":"done","created_at":"2018-10-31T12:42:42Z","updated_at":"2018-10-31T12:42:43Z","html_url":"https://github.com/CanonicalLtd/candid/pull/76#discussion_r229676676","pull_request_url":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/CanonicalLtd/candid/pulls/comments/229676676"},"html":{"href":"https://github.com/CanonicalLtd/candid/pull/76#discussion_r229676676"},"pull_request":{"href":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76"}},"in_reply_to_id":229636810},"pull_request":{"url":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76","id":227228139,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI3MjI4MTM5","html_url":"https://github.com/CanonicalLtd/candid/pull/76","diff_url":"https://github.com/CanonicalLtd/candid/pull/76.diff","patch_url":"https://github.com/CanonicalLtd/candid/pull/76.patch","issue_url":"https://api.github.com/repos/CanonicalLtd/candid/issues/76","number":76,"state":"open","locked":false,"title":"qtcandidtest: new test fixtures","user":{"login":"rogpeppe","id":66491,"node_id":"MDQ6VXNlcjY2NDkx","avatar_url":"https://avatars0.githubusercontent.com/u/66491?v=4","gravatar_id":"","url":"https://api.github.com/users/rogpeppe","html_url":"https://github.com/rogpeppe","followers_url":"https://api.github.com/users/rogpeppe/followers","following_url":"https://api.github.com/users/rogpeppe/following{/other_user}","gists_url":"https://api.github.com/users/rogpeppe/gists{/gist_id}","starred_url":"https://api.github.com/users/rogpeppe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rogpeppe/subscriptions","organizations_url":"https://api.github.com/users/rogpeppe/orgs","repos_url":"https://api.github.com/users/rogpeppe/repos","events_url":"https://api.github.com/users/rogpeppe/events{/privacy}","received_events_url":"https://api.github.com/users/rogpeppe/received_events","type":"User","site_admin":false},"body":"This PR copies candidtest to qtcandidtest (first commit), then adapts it to use quicktest, and does a partial conversion of one package by way of proof-of-concept (second commit).\r\n\r\nOnce we've converted all the other tests, we can rename qtcandidtest back to candidtest.\r\n","created_at":"2018-10-31T10:17:09Z","updated_at":"2018-10-31T12:42:43Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6c1a8044e4c082d72d787dfed2d7bcc605d480a1","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76/commits","review_comments_url":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76/comments","review_comment_url":"https://api.github.com/repos/CanonicalLtd/candid/pulls/comments{/number}","comments_url":"https://api.github.com/repos/CanonicalLtd/candid/issues/76/comments","statuses_url":"https://api.github.com/repos/CanonicalLtd/candid/statuses/4b6e7224843202754e44bf455704c8f37e00c6cc","head":{"label":"rogpeppe:150-qtcandidtest","ref":"150-qtcandidtest","sha":"4b6e7224843202754e44bf455704c8f37e00c6cc","user":{"login":"rogpeppe","id":66491,"node_id":"MDQ6VXNlcjY2NDkx","avatar_url":"https://avatars0.githubusercontent.com/u/66491?v=4","gravatar_id":"","url":"https://api.github.com/users/rogpeppe","html_url":"https://github.com/rogpeppe","followers_url":"https://api.github.com/users/rogpeppe/followers","following_url":"https://api.github.com/users/rogpeppe/following{/other_user}","gists_url":"https://api.github.com/users/rogpeppe/gists{/gist_id}","starred_url":"https://api.github.com/users/rogpeppe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rogpeppe/subscriptions","organizations_url":"https://api.github.com/users/rogpeppe/orgs","repos_url":"https://api.github.com/users/rogpeppe/repos","events_url":"https://api.github.com/users/rogpeppe/events{/privacy}","received_events_url":"https://api.github.com/users/rogpeppe/received_events","type":"User","site_admin":false},"repo":{"id":128244714,"node_id":"MDEwOlJlcG9zaXRvcnkxMjgyNDQ3MTQ=","name":"candid","full_name":"rogpeppe/candid","private":false,"owner":{"login":"rogpeppe","id":66491,"node_id":"MDQ6VXNlcjY2NDkx","avatar_url":"https://avatars0.githubusercontent.com/u/66491?v=4","gravatar_id":"","url":"https://api.github.com/users/rogpeppe","html_url":"https://github.com/rogpeppe","followers_url":"https://api.github.com/users/rogpeppe/followers","following_url":"https://api.github.com/users/rogpeppe/following{/other_user}","gists_url":"https://api.github.com/users/rogpeppe/gists{/gist_id}","starred_url":"https://api.github.com/users/rogpeppe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rogpeppe/subscriptions","organizations_url":"https://api.github.com/users/rogpeppe/orgs","repos_url":"https://api.github.com/users/rogpeppe/repos","events_url":"https://api.github.com/users/rogpeppe/events{/privacy}","received_events_url":"https://api.github.com/users/rogpeppe/received_events","type":"User","site_admin":false},"html_url":"https://github.com/rogpeppe/candid","description":"Identity manager service","fork":true,"url":"https://api.github.com/repos/rogpeppe/candid","forks_url":"https://api.github.com/repos/rogpeppe/candid/forks","keys_url":"https://api.github.com/repos/rogpeppe/candid/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rogpeppe/candid/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rogpeppe/candid/teams","hooks_url":"https://api.github.com/repos/rogpeppe/candid/hooks","issue_events_url":"https://api.github.com/repos/rogpeppe/candid/issues/events{/number}","events_url":"https://api.github.com/repos/rogpeppe/candid/events","assignees_url":"https://api.github.com/repos/rogpeppe/candid/assignees{/user}","branches_url":"https://api.github.com/repos/rogpeppe/candid/branches{/branch}","tags_url":"https://api.github.com/repos/rogpeppe/candid/tags","blobs_url":"https://api.github.com/repos/rogpeppe/candid/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rogpeppe/candid/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rogpeppe/candid/git/refs{/sha}","trees_url":"https://api.github.com/repos/rogpeppe/candid/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rogpeppe/candid/statuses/{sha}","languages_url":"https://api.github.com/repos/rogpeppe/candid/languages","stargazers_url":"https://api.github.com/repos/rogpeppe/candid/stargazers","contributors_url":"https://api.github.com/repos/rogpeppe/candid/contributors","subscribers_url":"https://api.github.com/repos/rogpeppe/candid/subscribers","subscription_url":"https://api.github.com/repos/rogpeppe/candid/subscription","commits_url":"https://api.github.com/repos/rogpeppe/candid/commits{/sha}","git_commits_url":"https://api.github.com/repos/rogpeppe/candid/git/commits{/sha}","comments_url":"https://api.github.com/repos/rogpeppe/candid/comments{/number}","issue_comment_url":"https://api.github.com/repos/rogpeppe/candid/issues/comments{/number}","contents_url":"https://api.github.com/repos/rogpeppe/candid/contents/{+path}","compare_url":"https://api.github.com/repos/rogpeppe/candid/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rogpeppe/candid/merges","archive_url":"https://api.github.com/repos/rogpeppe/candid/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rogpeppe/candid/downloads","issues_url":"https://api.github.com/repos/rogpeppe/candid/issues{/number}","pulls_url":"https://api.github.com/repos/rogpeppe/candid/pulls{/number}","milestones_url":"https://api.github.com/repos/rogpeppe/candid/milestones{/number}","notifications_url":"https://api.github.com/repos/rogpeppe/candid/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rogpeppe/candid/labels{/name}","releases_url":"https://api.github.com/repos/rogpeppe/candid/releases{/id}","deployments_url":"https://api.github.com/repos/rogpeppe/candid/deployments","created_at":"2018-04-05T18:02:44Z","updated_at":"2018-04-05T18:02:47Z","pushed_at":"2018-10-31T10:15:16Z","git_url":"git://github.com/rogpeppe/candid.git","ssh_url":"git@github.com:rogpeppe/candid.git","clone_url":"https://github.com/rogpeppe/candid.git","svn_url":"https://github.com/rogpeppe/candid","homepage":null,"size":1233,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"CanonicalLtd:master","ref":"master","sha":"a988e7d94f01abcbd28717d64064b113c33334c3","user":{"login":"CanonicalLtd","id":7490288,"node_id":"MDEyOk9yZ2FuaXphdGlvbjc0OTAyODg=","avatar_url":"https://avatars0.githubusercontent.com/u/7490288?v=4","gravatar_id":"","url":"https://api.github.com/users/CanonicalLtd","html_url":"https://github.com/CanonicalLtd","followers_url":"https://api.github.com/users/CanonicalLtd/followers","following_url":"https://api.github.com/users/CanonicalLtd/following{/other_user}","gists_url":"https://api.github.com/users/CanonicalLtd/gists{/gist_id}","starred_url":"https://api.github.com/users/CanonicalLtd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CanonicalLtd/subscriptions","organizations_url":"https://api.github.com/users/CanonicalLtd/orgs","repos_url":"https://api.github.com/users/CanonicalLtd/repos","events_url":"https://api.github.com/users/CanonicalLtd/events{/privacy}","received_events_url":"https://api.github.com/users/CanonicalLtd/received_events","type":"Organization","site_admin":false},"repo":{"id":128048586,"node_id":"MDEwOlJlcG9zaXRvcnkxMjgwNDg1ODY=","name":"candid","full_name":"CanonicalLtd/candid","private":false,"owner":{"login":"CanonicalLtd","id":7490288,"node_id":"MDEyOk9yZ2FuaXphdGlvbjc0OTAyODg=","avatar_url":"https://avatars0.githubusercontent.com/u/7490288?v=4","gravatar_id":"","url":"https://api.github.com/users/CanonicalLtd","html_url":"https://github.com/CanonicalLtd","followers_url":"https://api.github.com/users/CanonicalLtd/followers","following_url":"https://api.github.com/users/CanonicalLtd/following{/other_user}","gists_url":"https://api.github.com/users/CanonicalLtd/gists{/gist_id}","starred_url":"https://api.github.com/users/CanonicalLtd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/CanonicalLtd/subscriptions","organizations_url":"https://api.github.com/users/CanonicalLtd/orgs","repos_url":"https://api.github.com/users/CanonicalLtd/repos","events_url":"https://api.github.com/users/CanonicalLtd/events{/privacy}","received_events_url":"https://api.github.com/users/CanonicalLtd/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/CanonicalLtd/candid","description":"Identity manager service","fork":false,"url":"https://api.github.com/repos/CanonicalLtd/candid","forks_url":"https://api.github.com/repos/CanonicalLtd/candid/forks","keys_url":"https://api.github.com/repos/CanonicalLtd/candid/keys{/key_id}","collaborators_url":"https://api.github.com/repos/CanonicalLtd/candid/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/CanonicalLtd/candid/teams","hooks_url":"https://api.github.com/repos/CanonicalLtd/candid/hooks","issue_events_url":"https://api.github.com/repos/CanonicalLtd/candid/issues/events{/number}","events_url":"https://api.github.com/repos/CanonicalLtd/candid/events","assignees_url":"https://api.github.com/repos/CanonicalLtd/candid/assignees{/user}","branches_url":"https://api.github.com/repos/CanonicalLtd/candid/branches{/branch}","tags_url":"https://api.github.com/repos/CanonicalLtd/candid/tags","blobs_url":"https://api.github.com/repos/CanonicalLtd/candid/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/CanonicalLtd/candid/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/CanonicalLtd/candid/git/refs{/sha}","trees_url":"https://api.github.com/repos/CanonicalLtd/candid/git/trees{/sha}","statuses_url":"https://api.github.com/repos/CanonicalLtd/candid/statuses/{sha}","languages_url":"https://api.github.com/repos/CanonicalLtd/candid/languages","stargazers_url":"https://api.github.com/repos/CanonicalLtd/candid/stargazers","contributors_url":"https://api.github.com/repos/CanonicalLtd/candid/contributors","subscribers_url":"https://api.github.com/repos/CanonicalLtd/candid/subscribers","subscription_url":"https://api.github.com/repos/CanonicalLtd/candid/subscription","commits_url":"https://api.github.com/repos/CanonicalLtd/candid/commits{/sha}","git_commits_url":"https://api.github.com/repos/CanonicalLtd/candid/git/commits{/sha}","comments_url":"https://api.github.com/repos/CanonicalLtd/candid/comments{/number}","issue_comment_url":"https://api.github.com/repos/CanonicalLtd/candid/issues/comments{/number}","contents_url":"https://api.github.com/repos/CanonicalLtd/candid/contents/{+path}","compare_url":"https://api.github.com/repos/CanonicalLtd/candid/compare/{base}...{head}","merges_url":"https://api.github.com/repos/CanonicalLtd/candid/merges","archive_url":"https://api.github.com/repos/CanonicalLtd/candid/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/CanonicalLtd/candid/downloads","issues_url":"https://api.github.com/repos/CanonicalLtd/candid/issues{/number}","pulls_url":"https://api.github.com/repos/CanonicalLtd/candid/pulls{/number}","milestones_url":"https://api.github.com/repos/CanonicalLtd/candid/milestones{/number}","notifications_url":"https://api.github.com/repos/CanonicalLtd/candid/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/CanonicalLtd/candid/labels{/name}","releases_url":"https://api.github.com/repos/CanonicalLtd/candid/releases{/id}","deployments_url":"https://api.github.com/repos/CanonicalLtd/candid/deployments","created_at":"2018-04-04T10:47:41Z","updated_at":"2018-10-31T10:14:50Z","pushed_at":"2018-10-31T10:17:10Z","git_url":"git://github.com/CanonicalLtd/candid.git","ssh_url":"git@github.com:CanonicalLtd/candid.git","clone_url":"https://github.com/CanonicalLtd/candid.git","svn_url":"https://github.com/CanonicalLtd/candid","homepage":null,"size":1217,"stargazers_count":5,"watchers_count":5,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":8,"mirror_url":null,"archived":false,"open_issues_count":8,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":8,"open_issues":8,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76"},"html":{"href":"https://github.com/CanonicalLtd/candid/pull/76"},"issue":{"href":"https://api.github.com/repos/CanonicalLtd/candid/issues/76"},"comments":{"href":"https://api.github.com/repos/CanonicalLtd/candid/issues/76/comments"},"review_comments":{"href":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76/comments"},"review_comment":{"href":"https://api.github.com/repos/CanonicalLtd/candid/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/CanonicalLtd/candid/pulls/76/commits"},"statuses":{"href":"https://api.github.com/repos/CanonicalLtd/candid/statuses/4b6e7224843202754e44bf455704c8f37e00c6cc"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"rogpeppe"}}