{"action":"created","comment":{"url":"https://api.github.com/repos/snapcore/snapd/pulls/comments/70240870","id":70240870,"diff_hunk":"@@ -0,0 +1,249 @@\n+// -*- Mode: Go; indent-tabs-mode: t -*-\n+\n+/*\n+ * Copyright (C) 2016 Canonical Ltd\n+ *\n+ * This program is free software: you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 3 as\n+ * published by the Free Software Foundation.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n+ *\n+ */\n+\n+// Package tool offers tooling to sign assertions.\n+package tool\n+\n+import (\n+\t\"bytes\"\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"strconv\"\n+\n+\t\"gopkg.in/yaml.v2\"\n+\n+\t\"github.com/snapcore/snapd/asserts\"\n+)\n+\n+// The supported media types for the input of assertion signing.\n+const (\n+\tJSONInput = \"application/json\"\n+\tYAMLInput = \"application/x-yaml\"\n+)\n+\n+// SignRequest specifies the complete input for signing an assertion.\n+type SignRequest struct {\n+\t// The key to use can be speficied either passing the text of\n+\t// an account-key assertion in AccountKey\n+\tAccountKey []byte\n+\t// or passing the key id in KeyID\n+\tKeyID string\n+\t// and an optional account-id of the signer (if left out headers value are consulted) in AuthorityID\n+\tAuthorityID string\n+\n+\t// The assertion type (as a string)\n+\tAssertionType string\n+\t// StatementMediaType specifies the media type of the input\n+\tStatementMediaType string\n+\t// Statement is used as input to construct the assertion\n+\t// it's a mapping encoded as either JSON or YAML\n+\t// (specified in StatementMediaType)\n+\t// either of just the header fields of the assertion\n+\t// or containting exactly two entries\n+\t// \"headers\": mapping with the header fields\n+\t// \"body\": used as the body of the assertion\n+\tStatement []byte\n+\n+\t// The revision of the new assertion\n+\tRevision int\n+}\n+\n+func parseStatement(req *SignRequest, dest interface{}) error {\n+\tswitch req.StatementMediaType {\n+\tcase YAMLInput:\n+\t\terr := yaml.Unmarshal(req.Statement, dest)\n+\t\tif err != nil {\n+\t\t\treturn fmt.Errorf(\"cannot parse the assertion input as YAML: %v\", err)\n+\t\t}\n+\tcase JSONInput:\n+\t\tdec := json.NewDecoder(bytes.NewBuffer(req.Statement))\n+\t\t// we want control over supporting only integers\n+\t\tdec.UseNumber()\n+\t\terr := dec.Decode(dest)\n+\t\tif err != nil {\n+\t\t\treturn fmt.Errorf(\"cannot parse the assertion input as JSON: %v\", err)\n+\t\t}\n+\tdefault:\n+\t\treturn fmt.Errorf(\"unsupported media type for assertion input: %q\", req.StatementMediaType)\n+\t}\n+\treturn nil\n+}\n+\n+type nestedStatement struct {\n+\tHeaders map[string]interface{} `yaml:\"headers\" json:\"headers\"`\n+\tBody    string                 `yaml:\"body\" json:\"body\"`\n+}\n+\n+// Sign produces the text of a signed assertion as specified by req.\n+func Sign(req *SignRequest, keypairMgr asserts.KeypairManager) ([]byte, error) {\n+\ttyp := asserts.Type(req.AssertionType)\n+\tif typ == nil {\n+\t\treturn nil, fmt.Errorf(\"invalid assertion type: %q\", req.AssertionType)\n+\t}\n+\tif req.Revision < 0 {\n+\t\treturn nil, fmt.Errorf(\"assertion revision cannot be negative\")\n+\t}\n+\tif req.AccountKey == nil && req.KeyID == \"\" {\n+\t\treturn nil, fmt.Errorf(\"both account-key and key id were not specified\")\n+\t}","path":"asserts/tool/sign.go","position":104,"original_position":104,"commit_id":"e655ba1e86cfcec346775505b3edd852b1f0893c","original_commit_id":"e655ba1e86cfcec346775505b3edd852b1f0893c","user":{"login":"pedronis","id":975757,"avatar_url":"https://avatars.githubusercontent.com/u/975757?v=3","gravatar_id":"","url":"https://api.github.com/users/pedronis","html_url":"https://github.com/pedronis","followers_url":"https://api.github.com/users/pedronis/followers","following_url":"https://api.github.com/users/pedronis/following{/other_user}","gists_url":"https://api.github.com/users/pedronis/gists{/gist_id}","starred_url":"https://api.github.com/users/pedronis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pedronis/subscriptions","organizations_url":"https://api.github.com/users/pedronis/orgs","repos_url":"https://api.github.com/users/pedronis/repos","events_url":"https://api.github.com/users/pedronis/events{/privacy}","received_events_url":"https://api.github.com/users/pedronis/received_events","type":"User","site_admin":false},"body":"they all are, it's mostly about failing errors/having more contextual messages ","created_at":"2016-07-11T11:26:30Z","updated_at":"2016-07-11T11:26:30Z","html_url":"https://github.com/snapcore/snapd/pull/1340#discussion_r70240870","pull_request_url":"https://api.github.com/repos/snapcore/snapd/pulls/1340","_links":{"self":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/comments/70240870"},"html":{"href":"https://github.com/snapcore/snapd/pull/1340#discussion_r70240870"},"pull_request":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1340"}}},"pull_request":{"url":"https://api.github.com/repos/snapcore/snapd/pulls/1340","id":73940845,"html_url":"https://github.com/snapcore/snapd/pull/1340","diff_url":"https://github.com/snapcore/snapd/pull/1340.diff","patch_url":"https://github.com/snapcore/snapd/pull/1340.patch","issue_url":"https://api.github.com/repos/snapcore/snapd/issues/1340","number":1340,"state":"open","locked":false,"title":"many: introduce a tool to sign assertions","user":{"login":"pedronis","id":975757,"avatar_url":"https://avatars.githubusercontent.com/u/975757?v=3","gravatar_id":"","url":"https://api.github.com/users/pedronis","html_url":"https://github.com/pedronis","followers_url":"https://api.github.com/users/pedronis/followers","following_url":"https://api.github.com/users/pedronis/following{/other_user}","gists_url":"https://api.github.com/users/pedronis/gists{/gist_id}","starred_url":"https://api.github.com/users/pedronis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pedronis/subscriptions","organizations_url":"https://api.github.com/users/pedronis/orgs","repos_url":"https://api.github.com/users/pedronis/repos","events_url":"https://api.github.com/users/pedronis/events{/privacy}","received_events_url":"https://api.github.com/users/pedronis/received_events","type":"User","site_admin":false},"body":"The branch introduces a tool to sign assertions in the form of stand-alone snap-assert executable,\r\nI think once we understand the needs better it may be moved to a snap subcommand if that is what makes sense. It is mainly intended to be used by other tools (snapcraft, model-creator etc.)\r\n\r\nThe tool piggy backs to a local GPG setup for signing (through a GPGKeypairManager), and allows to give the input for the assertion as either YAML or JSON, and as flat header values (if the assertion doesn't have a body) or specifying headers and body if not.\r\n\r\nPrivate keys can be identified by long key id or using an account-key assertion as a opaque handle.\r\n\r\nHere is a walk through for it: \r\n\r\nhttp://pastebin.ubuntu.com/17367550/\r\n\r\nStill to-do:\r\n* testing of snap-asserts (either unit tests or with spread?)","created_at":"2016-06-15T16:13:16Z","updated_at":"2016-07-11T11:26:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":"27cabc35114d28242507ccae5416a0a6b4cb1c44","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/snapcore/snapd/pulls/1340/commits","review_comments_url":"https://api.github.com/repos/snapcore/snapd/pulls/1340/comments","review_comment_url":"https://api.github.com/repos/snapcore/snapd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/snapcore/snapd/issues/1340/comments","statuses_url":"https://api.github.com/repos/snapcore/snapd/statuses/e655ba1e86cfcec346775505b3edd852b1f0893c","head":{"label":"pedronis:tool-sign","ref":"tool-sign","sha":"e655ba1e86cfcec346775505b3edd852b1f0893c","user":{"login":"pedronis","id":975757,"avatar_url":"https://avatars.githubusercontent.com/u/975757?v=3","gravatar_id":"","url":"https://api.github.com/users/pedronis","html_url":"https://github.com/pedronis","followers_url":"https://api.github.com/users/pedronis/followers","following_url":"https://api.github.com/users/pedronis/following{/other_user}","gists_url":"https://api.github.com/users/pedronis/gists{/gist_id}","starred_url":"https://api.github.com/users/pedronis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pedronis/subscriptions","organizations_url":"https://api.github.com/users/pedronis/orgs","repos_url":"https://api.github.com/users/pedronis/repos","events_url":"https://api.github.com/users/pedronis/events{/privacy}","received_events_url":"https://api.github.com/users/pedronis/received_events","type":"User","site_admin":false},"repo":{"id":45828707,"name":"snappy","full_name":"pedronis/snappy","owner":{"login":"pedronis","id":975757,"avatar_url":"https://avatars.githubusercontent.com/u/975757?v=3","gravatar_id":"","url":"https://api.github.com/users/pedronis","html_url":"https://github.com/pedronis","followers_url":"https://api.github.com/users/pedronis/followers","following_url":"https://api.github.com/users/pedronis/following{/other_user}","gists_url":"https://api.github.com/users/pedronis/gists{/gist_id}","starred_url":"https://api.github.com/users/pedronis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pedronis/subscriptions","organizations_url":"https://api.github.com/users/pedronis/orgs","repos_url":"https://api.github.com/users/pedronis/repos","events_url":"https://api.github.com/users/pedronis/events{/privacy}","received_events_url":"https://api.github.com/users/pedronis/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/pedronis/snappy","description":"Snappy is the software at the heart of Ubuntu Core.","fork":true,"url":"https://api.github.com/repos/pedronis/snappy","forks_url":"https://api.github.com/repos/pedronis/snappy/forks","keys_url":"https://api.github.com/repos/pedronis/snappy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pedronis/snappy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pedronis/snappy/teams","hooks_url":"https://api.github.com/repos/pedronis/snappy/hooks","issue_events_url":"https://api.github.com/repos/pedronis/snappy/issues/events{/number}","events_url":"https://api.github.com/repos/pedronis/snappy/events","assignees_url":"https://api.github.com/repos/pedronis/snappy/assignees{/user}","branches_url":"https://api.github.com/repos/pedronis/snappy/branches{/branch}","tags_url":"https://api.github.com/repos/pedronis/snappy/tags","blobs_url":"https://api.github.com/repos/pedronis/snappy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pedronis/snappy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pedronis/snappy/git/refs{/sha}","trees_url":"https://api.github.com/repos/pedronis/snappy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pedronis/snappy/statuses/{sha}","languages_url":"https://api.github.com/repos/pedronis/snappy/languages","stargazers_url":"https://api.github.com/repos/pedronis/snappy/stargazers","contributors_url":"https://api.github.com/repos/pedronis/snappy/contributors","subscribers_url":"https://api.github.com/repos/pedronis/snappy/subscribers","subscription_url":"https://api.github.com/repos/pedronis/snappy/subscription","commits_url":"https://api.github.com/repos/pedronis/snappy/commits{/sha}","git_commits_url":"https://api.github.com/repos/pedronis/snappy/git/commits{/sha}","comments_url":"https://api.github.com/repos/pedronis/snappy/comments{/number}","issue_comment_url":"https://api.github.com/repos/pedronis/snappy/issues/comments{/number}","contents_url":"https://api.github.com/repos/pedronis/snappy/contents/{+path}","compare_url":"https://api.github.com/repos/pedronis/snappy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pedronis/snappy/merges","archive_url":"https://api.github.com/repos/pedronis/snappy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pedronis/snappy/downloads","issues_url":"https://api.github.com/repos/pedronis/snappy/issues{/number}","pulls_url":"https://api.github.com/repos/pedronis/snappy/pulls{/number}","milestones_url":"https://api.github.com/repos/pedronis/snappy/milestones{/number}","notifications_url":"https://api.github.com/repos/pedronis/snappy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pedronis/snappy/labels{/name}","releases_url":"https://api.github.com/repos/pedronis/snappy/releases{/id}","deployments_url":"https://api.github.com/repos/pedronis/snappy/deployments","created_at":"2015-11-09T09:40:46Z","updated_at":"2016-01-13T09:10:26Z","pushed_at":"2016-07-11T08:38:31Z","git_url":"git://github.com/pedronis/snappy.git","ssh_url":"git@github.com:pedronis/snappy.git","clone_url":"https://github.com/pedronis/snappy.git","svn_url":"https://github.com/pedronis/snappy","homepage":null,"size":32319,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"snapcore:master","ref":"master","sha":"cdf1cfa5a733923c53ff0d75edd66c3fe3c22e0b","user":{"login":"snapcore","id":19532717,"avatar_url":"https://avatars.githubusercontent.com/u/19532717?v=3","gravatar_id":"","url":"https://api.github.com/users/snapcore","html_url":"https://github.com/snapcore","followers_url":"https://api.github.com/users/snapcore/followers","following_url":"https://api.github.com/users/snapcore/following{/other_user}","gists_url":"https://api.github.com/users/snapcore/gists{/gist_id}","starred_url":"https://api.github.com/users/snapcore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snapcore/subscriptions","organizations_url":"https://api.github.com/users/snapcore/orgs","repos_url":"https://api.github.com/users/snapcore/repos","events_url":"https://api.github.com/users/snapcore/events{/privacy}","received_events_url":"https://api.github.com/users/snapcore/received_events","type":"Organization","site_admin":false},"repo":{"id":44672744,"name":"snapd","full_name":"snapcore/snapd","owner":{"login":"snapcore","id":19532717,"avatar_url":"https://avatars.githubusercontent.com/u/19532717?v=3","gravatar_id":"","url":"https://api.github.com/users/snapcore","html_url":"https://github.com/snapcore","followers_url":"https://api.github.com/users/snapcore/followers","following_url":"https://api.github.com/users/snapcore/following{/other_user}","gists_url":"https://api.github.com/users/snapcore/gists{/gist_id}","starred_url":"https://api.github.com/users/snapcore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snapcore/subscriptions","organizations_url":"https://api.github.com/users/snapcore/orgs","repos_url":"https://api.github.com/users/snapcore/repos","events_url":"https://api.github.com/users/snapcore/events{/privacy}","received_events_url":"https://api.github.com/users/snapcore/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/snapcore/snapd","description":"The snapd and snap tools enable systems to work with .snap files.","fork":false,"url":"https://api.github.com/repos/snapcore/snapd","forks_url":"https://api.github.com/repos/snapcore/snapd/forks","keys_url":"https://api.github.com/repos/snapcore/snapd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/snapcore/snapd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/snapcore/snapd/teams","hooks_url":"https://api.github.com/repos/snapcore/snapd/hooks","issue_events_url":"https://api.github.com/repos/snapcore/snapd/issues/events{/number}","events_url":"https://api.github.com/repos/snapcore/snapd/events","assignees_url":"https://api.github.com/repos/snapcore/snapd/assignees{/user}","branches_url":"https://api.github.com/repos/snapcore/snapd/branches{/branch}","tags_url":"https://api.github.com/repos/snapcore/snapd/tags","blobs_url":"https://api.github.com/repos/snapcore/snapd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/snapcore/snapd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/snapcore/snapd/git/refs{/sha}","trees_url":"https://api.github.com/repos/snapcore/snapd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/snapcore/snapd/statuses/{sha}","languages_url":"https://api.github.com/repos/snapcore/snapd/languages","stargazers_url":"https://api.github.com/repos/snapcore/snapd/stargazers","contributors_url":"https://api.github.com/repos/snapcore/snapd/contributors","subscribers_url":"https://api.github.com/repos/snapcore/snapd/subscribers","subscription_url":"https://api.github.com/repos/snapcore/snapd/subscription","commits_url":"https://api.github.com/repos/snapcore/snapd/commits{/sha}","git_commits_url":"https://api.github.com/repos/snapcore/snapd/git/commits{/sha}","comments_url":"https://api.github.com/repos/snapcore/snapd/comments{/number}","issue_comment_url":"https://api.github.com/repos/snapcore/snapd/issues/comments{/number}","contents_url":"https://api.github.com/repos/snapcore/snapd/contents/{+path}","compare_url":"https://api.github.com/repos/snapcore/snapd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/snapcore/snapd/merges","archive_url":"https://api.github.com/repos/snapcore/snapd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/snapcore/snapd/downloads","issues_url":"https://api.github.com/repos/snapcore/snapd/issues{/number}","pulls_url":"https://api.github.com/repos/snapcore/snapd/pulls{/number}","milestones_url":"https://api.github.com/repos/snapcore/snapd/milestones{/number}","notifications_url":"https://api.github.com/repos/snapcore/snapd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/snapcore/snapd/labels{/name}","releases_url":"https://api.github.com/repos/snapcore/snapd/releases{/id}","deployments_url":"https://api.github.com/repos/snapcore/snapd/deployments","created_at":"2015-10-21T11:51:46Z","updated_at":"2016-07-11T10:53:12Z","pushed_at":"2016-07-11T10:39:54Z","git_url":"git://github.com/snapcore/snapd.git","ssh_url":"git@github.com:snapcore/snapd.git","clone_url":"https://github.com/snapcore/snapd.git","svn_url":"https://github.com/snapcore/snapd","homepage":"","size":34126,"stargazers_count":350,"watchers_count":350,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":67,"mirror_url":null,"open_issues_count":32,"forks":67,"open_issues":32,"watchers":350,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1340"},"html":{"href":"https://github.com/snapcore/snapd/pull/1340"},"issue":{"href":"https://api.github.com/repos/snapcore/snapd/issues/1340"},"comments":{"href":"https://api.github.com/repos/snapcore/snapd/issues/1340/comments"},"review_comments":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1340/comments"},"review_comment":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1340/commits"},"statuses":{"href":"https://api.github.com/repos/snapcore/snapd/statuses/e655ba1e86cfcec346775505b3edd852b1f0893c"}}}}
{"actor":{"display_login":"pedronis"}}