Skip to content

[New Feature / Proposal] Add new required attribute in podspec to provide privacy details #10325

@mfaani

Description

@mfaani

This PR description has been edited to take into account the feedback that was later given by comments below. You can find the original posting here

Motivation

Starting from December 8, 2020, Apple has required new apps and app updates to include App privacy details on the App Store. App owners have to go through every pod and all its dependency's readmes or if nothing is revealed then reach out to pod creators to just figure out what information the pod collects. The current process is not transparent nor easy.

Proposal

Each Pod should mention their privacy details, so upon pod install / pod update a report file is generated where the different categories along with the purposes of every pod used are mentioned for each target. To acheive this the following changes need to be made:

PodSpec changes

Add a new array attribute to the the podspec named privacy_details

Expected structure for this attribute (Inspiration: [1])
s.privacy_details = [
  {
    "category": "NAME",
    "purposes": [
      "PRODUCT_PERSONALIZATION",
      "APP_FUNCTIONALITY"
    ],
    "data_protections": [
      "DATA_LINKED_TO_YOU"
    ]
  },
  {
    "category": "PURCHASE_HISTORY",
    "purposes": [
      "APP_FUNCTIONALITY"
    ],
    "data_protections": [
      "DATA_LINKED_TO_YOU",
      "DATA_USED_TO_TRACK_YOU"
    ]
  }
]

💡 Tip: Given that PodSpecs are ruby DSLs, pod owners can easily choose to provide the content of that attribute by reading it from a file (especially given that it might be more verbose than other typical PodSpec attributes).

We might want to mention that tip in the attribute documentation (and blog post that will accompany this new feature) especially since not everybody realizes that PodSpecs are interpreted ruby and can contain ruby code like this to make the spec more readable in some cases.

s.privacy_details = JSON.parse(File.read("privacy.json"))

Handling Subspecs

Note that the new privacy_details attribute will be allowed both at the root level of the podspec as well as for the definition of each subspec, if any. In such cases, the resolved privacy details for each subspec will be the result of merging the value of attribute defined at the root level (if one is defined there) with the value defined at the subspecies level.

Pod::Spec.new do |s|
  s.name = 'CoolKit'
  s.privacy_details = JSON.parse(File.read("common-privacy-details.json")) # includes NAME, EMAIL
  
  s.subspec 'SoundKit' do |cs|
    cs.dependency 'Alamofire'
    cs.privacy_details = JSON.parse(File.read("soundkit-privacy-details.json")) # includes AUDIO
  end

  s.subspec 'Model' do |ms|
    ms.privacy_details = JSON.parse(File.read("model-privacy-details.json")) # includes SENSITIVE_INFO 
  end
end

Then the privacy detail you get upon installation of a pod depends on which subspecies gets included:

  • The whole pod, e.g. pod 'CoolKit' (by default it would install all pods): NAME, EMAIL, AUDIO, SENSITIVE_INFO.
  • Only pod 'CoolKit/SoundKit': NAME, EMAIL, AUDIO.
  • Only pod 'CoolKit/Model': NAME, EMAIL, SENSITIVE_INFO.

If your intention is that if only SoundKit is installed then only AUDIO to be reported as your privacy detail, then you have to restructure your PodSpec accordingly, and remove s.privacy_details from the spec's root and instead only add NAME and EMAIL onto the Model's sub specs.

Example of a Podspec when not all specs share common privacy details
Pod::Spec.new do |s|
  s.name = 'CoolKit'
  
  s.subspec 'SoundKit' do |cs|
    cs.dependency 'Alamofire'
    cs.privacy_details = JSON.parse(File.read("soundkit-privacy-details.json")) # includes AUDIO
  end

  s.subspec 'Model' do |ms|
    ms.privacy_details = JSON.parse(File.read("model-privacy-details.json")) # includes NAME, EMAIL, SENSITIVE_INFO 
  end
end

Gradual rollout for requiring the attribute

  • New pods or any update should include the new privacy_details attribute in each of their subspecs. Mention which of the 32 data types (along with its purpose and data protection) they are collecting. If privacy_details isn't stated, then a message will be written to stdout .
  • It’s gonna be a warning for now but we plan to make it an error in a future version of CocoaPods.
    • The warning would be like this:
  WARN | privacy_details: Pods (X,Y,Z) did not specify privacy_details. This will be a requirment in the upcomming releasees.

Versioning Pods

  • We should make a recommendation to the community that if there is a change in the privacy_details then patches are not welcomed. At least a minor version update should happen.

Generated Report file

  • Upon pod install or pod update, a json is generated for each target of the Podfile.
  • The file will be located where other Support files are at: $PROJECT_DIRECTORY/Pods/Target Support Files/Pods-$target-name/privacy_details.json
  • Generation of the report file (a.k.a privacay.json / privacyDetails.json) is defaulted to on.
  • In order to increase awarness of the generation of this report file a messege is written to stdout upon pod install
Generated privacy details into
INFO | /pods/Target Support Files/pods-targetA/privacyDetails.json
INFO | /pods/Target Support Files/pods-targetB/privacyDetails.json
  • If you don’t want it then you have to opt out with a new flag e.g. pod install --no-privacy-details.
Example of a multi-target report file

/// $PROJECT_DIRECTORY/Pods/Target Support Files/Pods-targetFoo/privacy_details.json

   {
    "privacy_details": [
      {
        "category": "NAME",
        "purposes": [
          "PRODUCT_PERSONALIZATION",
          "APP_FUNCTIONALITY"
        ],
        "data_protections": [
          "DATA_LINKED_TO_YOU"
        ],
        "collectors": ["pod1", "pod2"]
      },
      {
        "category": "PURCHASE_HISTORY",
        "purposes": [
          "APP_FUNCTIONALITY"
        ],
        "data_protections": [
          "DATA_LINKED_TO_YOU",
          "DATA_USED_TO_TRACK_YOU"
        ],
        "collectors": ["pod1", "pod5"]
      },
      {
        "data_protections": [
          "DATA_NOT_COLLECTED"
        ],
        "collectors": ["pod3", "pod6"] 
      }
    ],
    "unknown_privacy_details": ["pod4", "pod7"],
  }

/// $PROJECT_DIRECTORY/Pods/Target Support Files/Pods-targetBar/privacy_details.json

  "target2": {
    "privacy_details": [
      {
        "category": "NAME",
        "purposes": [
          "PRODUCT_PERSONALIZATION",
          "APP_FUNCTIONALITY"
        ],
        "data_protections": [
          "DATA_LINKED_TO_YOU"
        ],
        "collectors": ["pod1", "pod2", "pod8"]
      }
    ]
  }

Note: Every included permutation (of data types, purpose and data protection) should contain a key named "collectors". This provides app owners granularity to see what data each pod is collecting.

Podfile changes

  • In regards to the app's own privacy details we can:
    • Do nothing. Dev can figure out the rest in regards to how to add privacy details about what data their own app is collecting
    • Add new attribute into Podfile. Name it target_privacy_details. App owners can then add their privacy details. Then upon pod install/update do a union with what’s generated from the pods.
      • The target_privacy_details can be set either a root option or a target configuration. The value provided for the target configuration will merge with the root option value if set.
  • Make a recommendation for app owners that if there is a change in the privacy_details then at least a minor version update should happen (not just a patch bump).

Backwards Compatibility

  • Older versions published to CocoaPods would continue to work without their privacy details
  • New pods or updates to existing pods would require a value for their privacy details
  • The ultimate PrivacyDetails.json would mention all the values for updated pods and include a key named unknown_privacy_details (included in the sample report file) for the (old) pods that don't have it set.

Ways to bypass this

  • Given that CocoaPods is open source, pod owners can alter the validations that pod trunk push performs
  • Yet it's a step forward, towards transparency and privacy. It cautions app owners to think again when a pod doesn't include privacy details.
  • At then end a pod owner may have malicious intent or simply forget to mention something they log or keep track of. This should lead app owners to create issues with a privacyDetails label on repos. It will take some time from the community to get use to this process.

Other notes

  • We're looking for feedbacks on this and see if maybe the CocoaPods team have been working on this. If not we're keen to implement the PR for this feature and would like to know what files to look into to start development on this

  • Based on my mediocre Ruby knowledge, is the following a good starting point:
    add a new attribute to Pod::Specification::DSL like this:

attribute :privacy_details,
  :container   => Array,
  :singularize => true,
  :inherited => true

and then fix any error that I get through pod ipc spec <podspec>


[1]: On Dec 3rd, 2020, fastlane added a new action upload_app_data_usage_to_app_store (PR link). It requires a json with a similar shape, which can include a single category or multiple or none. The format/structure of the JSON we're using in this issue/proposal is directly inspired by the one expected by fastlane, both for consistency and so that it provides us the additional benefit of interoperability, as users could then use the JSON generated by CocoaPods via this new feature to feed it as an input for their fastlane actions directly 👌

Metadata

Metadata

Assignees

No one assigned

    Labels

    s3:detailedIssues with in-depth explanations and examples that make it easier to troubleshoott1:enhancementEnhancements that have not been picked up yet. Please comment if you plan to work on itt3:discussionThese are issues that can be non-issues, and encompass best practices, or plans for the future.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions