{"action":"created","comment":{"url":"https://api.github.com/repos/square/p2/pulls/comments/24600137","id":24600137,"diff_hunk":"@@ -74,6 +97,14 @@ func (manifest *PodManifest) Write(out io.Writer) error {\n }\n \n func (manifest *PodManifest) Bytes() ([]byte, error) {\n+\tif manifest.signature != nil {\n+\t\t// if it's signed, we must recycle the original content to preserve the\n+\t\t// signature's validity. remarshaling it might change the exact text of","path":"pkg/pods/manifest_parser.go","position":50,"original_position":50,"commit_id":"9d566ae6b256c3ea56027130f3dc149d6e0cfe10","original_commit_id":"9d566ae6b256c3ea56027130f3dc149d6e0cfe10","user":{"login":"xaviershay","id":1714,"avatar_url":"https://avatars.githubusercontent.com/u/1714?v=3","gravatar_id":"","url":"https://api.github.com/users/xaviershay","html_url":"https://github.com/xaviershay","followers_url":"https://api.github.com/users/xaviershay/followers","following_url":"https://api.github.com/users/xaviershay/following{/other_user}","gists_url":"https://api.github.com/users/xaviershay/gists{/gist_id}","starred_url":"https://api.github.com/users/xaviershay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xaviershay/subscriptions","organizations_url":"https://api.github.com/users/xaviershay/orgs","repos_url":"https://api.github.com/users/xaviershay/repos","events_url":"https://api.github.com/users/xaviershay/events{/privacy}","received_events_url":"https://api.github.com/users/xaviershay/received_events","type":"User","site_admin":false},"body":"oh, maybe hash ordering is deterministic in go?","created_at":"2015-02-12T17:35:45Z","updated_at":"2015-02-12T17:35:45Z","html_url":"https://github.com/square/p2/pull/101#discussion_r24600137","pull_request_url":"https://api.github.com/repos/square/p2/pulls/101","_links":{"self":{"href":"https://api.github.com/repos/square/p2/pulls/comments/24600137"},"html":{"href":"https://github.com/square/p2/pull/101#discussion_r24600137"},"pull_request":{"href":"https://api.github.com/repos/square/p2/pulls/101"}}},"pull_request":{"url":"https://api.github.com/repos/square/p2/pulls/101","id":29155273,"html_url":"https://github.com/square/p2/pull/101","diff_url":"https://github.com/square/p2/pull/101.diff","patch_url":"https://github.com/square/p2/pull/101.patch","issue_url":"https://api.github.com/repos/square/p2/issues/101","number":101,"state":"open","locked":false,"title":"PGP signed manifests","user":{"login":"tummychow","id":4285049,"avatar_url":"https://avatars.githubusercontent.com/u/4285049?v=3","gravatar_id":"","url":"https://api.github.com/users/tummychow","html_url":"https://github.com/tummychow","followers_url":"https://api.github.com/users/tummychow/followers","following_url":"https://api.github.com/users/tummychow/following{/other_user}","gists_url":"https://api.github.com/users/tummychow/gists{/gist_id}","starred_url":"https://api.github.com/users/tummychow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tummychow/subscriptions","organizations_url":"https://api.github.com/users/tummychow/orgs","repos_url":"https://api.github.com/users/tummychow/repos","events_url":"https://api.github.com/users/tummychow/events{/privacy}","received_events_url":"https://api.github.com/users/tummychow/received_events","type":"User","site_admin":false},"body":"Apologies for the titanic diff; that's what happens when you import two new packages and one of them is really big. My changes are way down at the bottom.\r\n\r\nAnyway this code \"should\" implement our security model:\r\n\r\n- manifests can be part of a PGP clearsigned message (ie manifest in plain text with a signature attached to the end, generated with gpg `--clearsign` flag)\r\n- the preparer boots up with an optional keyring somewhere on the filesystem\r\n- if the keyring was provided, the preparer will reject manifests that were not signed by a member of that keyring\r\n- the public key of a signed manifest is logged (debug level), while unsigned or unknown-signer manifests will raise warnings\r\n- if no keyring was provided, the preparer ignores signatures altogether and installs any manifest, as it did before (they wouldn't be meaningful anyway, because the signature can't be identified without a keyring)\r\n\r\nI'll test it in universe after messing with gpg a bit more. For now please review code.\r\n\r\nImplementation notes:\r\n\r\n- I know we originally planned to have another struct that wrapped around PodManifest, but in the end it was **much** simpler to add the `Signer` method to PodManifest directly. A ton of type signatures would have changed if I had added a new structure.\r\n\r\n- Signature validation is delayed for as long as possible - only when you invoke `Signer` with the keyring in question. This allows the vast majority of our code to ignore the existence of a signature altogether (otherwise you would have to copy the keyring all the way down to the `kp.Store` that generated the manifests).\r\n\r\n  In exchange, you have to preserve the original message forever, to avoid remarshaling (which might result in a slightly different text that invalidates the signature). In addition, if you mutate the public fields of the PodManifest, this API still behaves as if the pod manifest is signed.\r\n\r\n  There's no way to fix either of these problems unless we remove the four exported fields from PodManifest and, continuing from there, make the entire structure immutable. I actually really wanted to make this refactor happen (while I'm at it, I'd convert every `*PodManifest` to a `PodManifest`), but it would have taken a few days, where as this took a few hours. We should come back to it next month or something.","created_at":"2015-02-12T06:12:38Z","updated_at":"2015-02-12T17:35:45Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5f027c5e1d87177110313392e76905eaa4052855","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/square/p2/pulls/101/commits","review_comments_url":"https://api.github.com/repos/square/p2/pulls/101/comments","review_comment_url":"https://api.github.com/repos/square/p2/pulls/comments/{number}","comments_url":"https://api.github.com/repos/square/p2/issues/101/comments","statuses_url":"https://api.github.com/repos/square/p2/statuses/9d566ae6b256c3ea56027130f3dc149d6e0cfe10","head":{"label":"tummychow:signed-manifests","ref":"signed-manifests","sha":"9d566ae6b256c3ea56027130f3dc149d6e0cfe10","user":{"login":"tummychow","id":4285049,"avatar_url":"https://avatars.githubusercontent.com/u/4285049?v=3","gravatar_id":"","url":"https://api.github.com/users/tummychow","html_url":"https://github.com/tummychow","followers_url":"https://api.github.com/users/tummychow/followers","following_url":"https://api.github.com/users/tummychow/following{/other_user}","gists_url":"https://api.github.com/users/tummychow/gists{/gist_id}","starred_url":"https://api.github.com/users/tummychow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tummychow/subscriptions","organizations_url":"https://api.github.com/users/tummychow/orgs","repos_url":"https://api.github.com/users/tummychow/repos","events_url":"https://api.github.com/users/tummychow/events{/privacy}","received_events_url":"https://api.github.com/users/tummychow/received_events","type":"User","site_admin":false},"repo":{"id":29206040,"name":"p2","full_name":"tummychow/p2","owner":{"login":"tummychow","id":4285049,"avatar_url":"https://avatars.githubusercontent.com/u/4285049?v=3","gravatar_id":"","url":"https://api.github.com/users/tummychow","html_url":"https://github.com/tummychow","followers_url":"https://api.github.com/users/tummychow/followers","following_url":"https://api.github.com/users/tummychow/following{/other_user}","gists_url":"https://api.github.com/users/tummychow/gists{/gist_id}","starred_url":"https://api.github.com/users/tummychow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tummychow/subscriptions","organizations_url":"https://api.github.com/users/tummychow/orgs","repos_url":"https://api.github.com/users/tummychow/repos","events_url":"https://api.github.com/users/tummychow/events{/privacy}","received_events_url":"https://api.github.com/users/tummychow/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tummychow/p2","description":"Platypus Platform: Tools for Scalable Deployment","fork":true,"url":"https://api.github.com/repos/tummychow/p2","forks_url":"https://api.github.com/repos/tummychow/p2/forks","keys_url":"https://api.github.com/repos/tummychow/p2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tummychow/p2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tummychow/p2/teams","hooks_url":"https://api.github.com/repos/tummychow/p2/hooks","issue_events_url":"https://api.github.com/repos/tummychow/p2/issues/events{/number}","events_url":"https://api.github.com/repos/tummychow/p2/events","assignees_url":"https://api.github.com/repos/tummychow/p2/assignees{/user}","branches_url":"https://api.github.com/repos/tummychow/p2/branches{/branch}","tags_url":"https://api.github.com/repos/tummychow/p2/tags","blobs_url":"https://api.github.com/repos/tummychow/p2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tummychow/p2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tummychow/p2/git/refs{/sha}","trees_url":"https://api.github.com/repos/tummychow/p2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tummychow/p2/statuses/{sha}","languages_url":"https://api.github.com/repos/tummychow/p2/languages","stargazers_url":"https://api.github.com/repos/tummychow/p2/stargazers","contributors_url":"https://api.github.com/repos/tummychow/p2/contributors","subscribers_url":"https://api.github.com/repos/tummychow/p2/subscribers","subscription_url":"https://api.github.com/repos/tummychow/p2/subscription","commits_url":"https://api.github.com/repos/tummychow/p2/commits{/sha}","git_commits_url":"https://api.github.com/repos/tummychow/p2/git/commits{/sha}","comments_url":"https://api.github.com/repos/tummychow/p2/comments{/number}","issue_comment_url":"https://api.github.com/repos/tummychow/p2/issues/comments/{number}","contents_url":"https://api.github.com/repos/tummychow/p2/contents/{+path}","compare_url":"https://api.github.com/repos/tummychow/p2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tummychow/p2/merges","archive_url":"https://api.github.com/repos/tummychow/p2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tummychow/p2/downloads","issues_url":"https://api.github.com/repos/tummychow/p2/issues{/number}","pulls_url":"https://api.github.com/repos/tummychow/p2/pulls{/number}","milestones_url":"https://api.github.com/repos/tummychow/p2/milestones{/number}","notifications_url":"https://api.github.com/repos/tummychow/p2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tummychow/p2/labels{/name}","releases_url":"https://api.github.com/repos/tummychow/p2/releases{/id}","created_at":"2015-01-13T19:07:54Z","updated_at":"2015-02-06T00:18:12Z","pushed_at":"2015-02-12T06:24:06Z","git_url":"git://github.com/tummychow/p2.git","ssh_url":"git@github.com:tummychow/p2.git","clone_url":"https://github.com/tummychow/p2.git","svn_url":"https://github.com/tummychow/p2","homepage":"","size":15656,"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":"square:master","ref":"master","sha":"c35400336e399a3444f7a206f98418034f871db2","user":{"login":"square","id":82592,"avatar_url":"https://avatars.githubusercontent.com/u/82592?v=3","gravatar_id":"","url":"https://api.github.com/users/square","html_url":"https://github.com/square","followers_url":"https://api.github.com/users/square/followers","following_url":"https://api.github.com/users/square/following{/other_user}","gists_url":"https://api.github.com/users/square/gists{/gist_id}","starred_url":"https://api.github.com/users/square/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/square/subscriptions","organizations_url":"https://api.github.com/users/square/orgs","repos_url":"https://api.github.com/users/square/repos","events_url":"https://api.github.com/users/square/events{/privacy}","received_events_url":"https://api.github.com/users/square/received_events","type":"Organization","site_admin":false},"repo":{"id":25320424,"name":"p2","full_name":"square/p2","owner":{"login":"square","id":82592,"avatar_url":"https://avatars.githubusercontent.com/u/82592?v=3","gravatar_id":"","url":"https://api.github.com/users/square","html_url":"https://github.com/square","followers_url":"https://api.github.com/users/square/followers","following_url":"https://api.github.com/users/square/following{/other_user}","gists_url":"https://api.github.com/users/square/gists{/gist_id}","starred_url":"https://api.github.com/users/square/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/square/subscriptions","organizations_url":"https://api.github.com/users/square/orgs","repos_url":"https://api.github.com/users/square/repos","events_url":"https://api.github.com/users/square/events{/privacy}","received_events_url":"https://api.github.com/users/square/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/square/p2","description":"Platypus Platform: Tools for Scalable Deployment","fork":false,"url":"https://api.github.com/repos/square/p2","forks_url":"https://api.github.com/repos/square/p2/forks","keys_url":"https://api.github.com/repos/square/p2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/square/p2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/square/p2/teams","hooks_url":"https://api.github.com/repos/square/p2/hooks","issue_events_url":"https://api.github.com/repos/square/p2/issues/events{/number}","events_url":"https://api.github.com/repos/square/p2/events","assignees_url":"https://api.github.com/repos/square/p2/assignees{/user}","branches_url":"https://api.github.com/repos/square/p2/branches{/branch}","tags_url":"https://api.github.com/repos/square/p2/tags","blobs_url":"https://api.github.com/repos/square/p2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/square/p2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/square/p2/git/refs{/sha}","trees_url":"https://api.github.com/repos/square/p2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/square/p2/statuses/{sha}","languages_url":"https://api.github.com/repos/square/p2/languages","stargazers_url":"https://api.github.com/repos/square/p2/stargazers","contributors_url":"https://api.github.com/repos/square/p2/contributors","subscribers_url":"https://api.github.com/repos/square/p2/subscribers","subscription_url":"https://api.github.com/repos/square/p2/subscription","commits_url":"https://api.github.com/repos/square/p2/commits{/sha}","git_commits_url":"https://api.github.com/repos/square/p2/git/commits{/sha}","comments_url":"https://api.github.com/repos/square/p2/comments{/number}","issue_comment_url":"https://api.github.com/repos/square/p2/issues/comments/{number}","contents_url":"https://api.github.com/repos/square/p2/contents/{+path}","compare_url":"https://api.github.com/repos/square/p2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/square/p2/merges","archive_url":"https://api.github.com/repos/square/p2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/square/p2/downloads","issues_url":"https://api.github.com/repos/square/p2/issues{/number}","pulls_url":"https://api.github.com/repos/square/p2/pulls{/number}","milestones_url":"https://api.github.com/repos/square/p2/milestones{/number}","notifications_url":"https://api.github.com/repos/square/p2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/square/p2/labels{/name}","releases_url":"https://api.github.com/repos/square/p2/releases{/id}","created_at":"2014-10-16T20:31:12Z","updated_at":"2015-02-12T01:44:50Z","pushed_at":"2015-02-12T01:44:50Z","git_url":"git://github.com/square/p2.git","ssh_url":"git@github.com:square/p2.git","clone_url":"https://github.com/square/p2.git","svn_url":"https://github.com/square/p2","homepage":"","size":16696,"stargazers_count":13,"watchers_count":13,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":1,"forks":5,"open_issues":1,"watchers":13,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/square/p2/pulls/101"},"html":{"href":"https://github.com/square/p2/pull/101"},"issue":{"href":"https://api.github.com/repos/square/p2/issues/101"},"comments":{"href":"https://api.github.com/repos/square/p2/issues/101/comments"},"review_comments":{"href":"https://api.github.com/repos/square/p2/pulls/101/comments"},"review_comment":{"href":"https://api.github.com/repos/square/p2/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/square/p2/pulls/101/commits"},"statuses":{"href":"https://api.github.com/repos/square/p2/statuses/9d566ae6b256c3ea56027130f3dc149d6e0cfe10"}}}}