{"action":"created","issue":{"url":"https://api.github.com/repos/twitter/secureheaders/issues/281","repository_url":"https://api.github.com/repos/twitter/secureheaders","labels_url":"https://api.github.com/repos/twitter/secureheaders/issues/281/labels{/name}","comments_url":"https://api.github.com/repos/twitter/secureheaders/issues/281/comments","events_url":"https://api.github.com/repos/twitter/secureheaders/issues/281/events","html_url":"https://github.com/twitter/secureheaders/pull/281","id":170263343,"number":281,"title":"Setting two CSP headers, abstract out dynamic pieces","user":{"login":"oreoshake","id":448516,"avatar_url":"https://avatars.githubusercontent.com/u/448516?v=3","gravatar_id":"","url":"https://api.github.com/users/oreoshake","html_url":"https://github.com/oreoshake","followers_url":"https://api.github.com/users/oreoshake/followers","following_url":"https://api.github.com/users/oreoshake/following{/other_user}","gists_url":"https://api.github.com/users/oreoshake/gists{/gist_id}","starred_url":"https://api.github.com/users/oreoshake/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/oreoshake/subscriptions","organizations_url":"https://api.github.com/users/oreoshake/orgs","repos_url":"https://api.github.com/users/oreoshake/repos","events_url":"https://api.github.com/users/oreoshake/events{/privacy}","received_events_url":"https://api.github.com/users/oreoshake/received_events","type":"User","site_admin":true},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":34,"created_at":"2016-08-09T20:32:05Z","updated_at":"2016-08-18T22:10:47Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/twitter/secureheaders/pulls/281","html_url":"https://github.com/twitter/secureheaders/pull/281","diff_url":"https://github.com/twitter/secureheaders/pull/281.diff","patch_url":"https://github.com/twitter/secureheaders/pull/281.patch"},"body":"Fixes #256\r\n\r\n* [x] `@modified` bit strategy isn't working perfectly, I'm seeing objects being created when policies are not modified.\r\n* [x] Has tests\r\n* [x] Documentation updated\r\n\r\nSetting two headers has been an often requested feature that has always had a workaround but was never a first class feature. This PR allows setting both headers.\r\n\r\nIn the process of supporting both, I decided to move away from hash-backed configs and towards class-based configs - mostly because it made debugging things very hard and mistyping a hash key is far to easy. This has the added benefit of not having to perform \"deep clones\" all the time and relying on hash voodoo. This is much clearer even if some of the operations are just glorified hash operations. \r\n\r\nThis also adds a `@modified` attribute which signals whether the cached headers can be used or not. This removes the need to track a `dynamic_csp`, choose between two configs, and use the `idempotent_operations` call which was all just a bit too funky and created the need for a lot of boilerplate code.\r\n\r\nWhen writing support for `override_content_security_policy_directives/append_content_security_policy_directives`, I realized that the default policy is not very user-friendly and insecure at the same time. Updating the default policy should make it easier for people to use the default setting and make their policy dynamic as needed. The new policy is less restrictive for the most part, with the exception of `object-src 'none'` which is just an unsafe default.\r\n\r\nThe reason the `DynamicConfig` stuff is extracted into a module with some hackery is so that it can be reused when implementing [FeaturePolicy](https://github.com/twitter/secureheaders/issues/275) which will benefit from the dynamic helper functions and non-hash-backed data. I like the idea, but the implementation looks a bit janky. I'll look into how ActiveRecord handles it's `changed?` function. I'm also questioning the use of `update_directive`/`directive_value`.\r\n"},"comment":{"url":"https://api.github.com/repos/twitter/secureheaders/issues/comments/240872903","html_url":"https://github.com/twitter/secureheaders/pull/281#issuecomment-240872903","issue_url":"https://api.github.com/repos/twitter/secureheaders/issues/281","id":240872903,"user":{"login":"jacobbednarz","id":283234,"avatar_url":"https://avatars.githubusercontent.com/u/283234?v=3","gravatar_id":"","url":"https://api.github.com/users/jacobbednarz","html_url":"https://github.com/jacobbednarz","followers_url":"https://api.github.com/users/jacobbednarz/followers","following_url":"https://api.github.com/users/jacobbednarz/following{/other_user}","gists_url":"https://api.github.com/users/jacobbednarz/gists{/gist_id}","starred_url":"https://api.github.com/users/jacobbednarz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacobbednarz/subscriptions","organizations_url":"https://api.github.com/users/jacobbednarz/orgs","repos_url":"https://api.github.com/users/jacobbednarz/repos","events_url":"https://api.github.com/users/jacobbednarz/events{/privacy}","received_events_url":"https://api.github.com/users/jacobbednarz/received_events","type":"User","site_admin":false},"created_at":"2016-08-18T22:10:47Z","updated_at":"2016-08-18T22:10:47Z","body":"Gemfile (running at 7600b90)\r\n```\r\ngem 'secure_headers', git: 'https://github.com/twitter/secureheaders.git',      \r\n                      ref: 'dynamic-csp-config-abstraction'\r\n```\r\n\r\nConfig (some of these directive values have been changed but it still results in the same error).\r\n```rb\r\nSecureHeaders::Configuration.default do |config|\r\n  config.csp = SecureHeaders::OPT_OUT\r\n  config.csp_report_only = {\r\n    report_uri: %w(https://my-report-only-uri),\r\n    preserve_schemes: true,\r\n\r\n    default_src: %w(* data:),\r\n    img_src: %w(* data:),\r\n    style_src: %w(* 'self' 'unsafe-inline'),\r\n    font_src: %w('self' data:),\r\n    script_src: %w(\r\n      *\r\n      data:\r\n      'self'\r\n      'unsafe-eval'\r\n      'unsafe-inline'\r\n    ),\r\n    connect_src: %w(*),\r\n    base_uri: %w(*),\r\n  }\r\nend\r\n```\r\n\r\nStacktrace\r\n```\r\n/opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/bundler/gems/secureheaders-7600b900c666/lib/secure_headers.rb:25:in `boom': wrong number of arguments (2 for 0..1) (ArgumentError)\r\n\tfrom /Users/Jacob/src/marketplace/config/initializers/http_security_headers.rb:40:in `block in <top (required)>'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/bundler/gems/secureheaders-7600b900c666/lib/secure_headers/configuration.rb:34:in `instance_eval'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/bundler/gems/secureheaders-7600b900c666/lib/secure_headers/configuration.rb:34:in `override'\r\n\tfrom /Users/Jacob/src/marketplace/config/initializers/http_security_headers.rb:39:in `<top (required)>'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22.4/lib/active_support/dependencies.rb:245:in `load'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22.4/lib/active_support/dependencies.rb:245:in `block in load'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22.4/lib/active_support/dependencies.rb:236:in `load_dependency'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/activesupport-3.2.22.4/lib/active_support/dependencies.rb:245:in `load'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/railties-3.2.22.4/lib/rails/engine.rb:593:in `block (2 levels) in <class:Engine>'\r\n\tfrom /opt/boxen/rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/railties-3.2.22.4/lib/rails/engine.rb:592:in `each'"}}
{"actor":{"display_login":"jacobbednarz"}}