


# Compliance Forms

## Why Would You Use Compliance Forms?

**DataHub Compliance Forms** streamline the process of documenting, annotating, and classifying your most critical Data Assets through a collaborative, crowdsourced approach.

With Compliance Forms, you can execute large-scale compliance initiatives by assigning tasks (e.g., documentation, tagging, or classification requirements) to the appropriate stakeholders — data owners, stewards, and subject matter experts.

Learn more about forms in the [Compliance Forms Feature Guide](../../../docs/features/feature-guides/compliance-forms/overview.md).

### Goal Of This Guide

This guide will show you how to

- Create, Update, Read, and Delete a form
- Assign and Remove a form from entities

## Prerequisites

For this tutorial, you need to deploy DataHub Quickstart and ingest sample data.
For detailed information, please refer to [DataHub Quickstart Guide](/docs/quickstart.md).

### Required Privileges

- Creating, updating, deleting, assigning, or unassigning forms through the GraphQL API (including the `batchAssignForm`, `batchRemoveForm`, and `createDynamicFormAssignment` mutations used below) requires the **Manage Compliance Forms** Platform privilege. Admins and Editors hold it by default.
- Writing the `forms` or `dynamicFormAssignment` aspects directly through OpenAPI, Rest.li, or a CLI metadata emitter requires **Manage Compliance Forms** _and_ **Edit Entity** on the target entity, because those APIs authorize every aspect write as a generic entity update (unless REST API authorization is disabled).
- Completing or verifying a form that is already assigned to you does not require **Manage Compliance Forms**.



#### CLI


Install the relevant CLI version. Forms are available as of CLI version `0.13.1`. The corresponding DataHub Cloud release version is `v0.2.16.5`
Connect to your instance via [init](/docs/cli/#init):

1. Run `datahub init` to update the instance you want to load into
2. Set the server to your sandbox instance, `https://{your-instance-address}/gms`
3. Set the token to your access token




## Create a Form



#### GraphQL


```graphql
mutation createForm {
  createForm(
    input: {
      id: "metadataInitiative2024"
      name: "Metadata Initiative 2024"
      description: "How we want to ensure the most important data assets in our organization have all of the most important and expected pieces of metadata filled out"
      type: VERIFICATION
      prompts: [
        {
          id: "123"
          title: "retentionTime"
          description: "Apply Retention Time structured property to form"
          type: STRUCTURED_PROPERTY
          structuredPropertyParams: {
            urn: "urn:li:structuredProperty:retentionTime"
          }
        }
      ]
      actors: {
        users: [
          "urn:li:corpuser:jane@email.com"
          "urn:li:corpuser:john@email.com"
        ]
        groups: ["urn:li:corpGroup:team@email.com"]
        owners: true # assign to asset owners
        ownershipTypes: [
          # optional: filter by specific ownership types
          "urn:li:ownershipType:__system__technical_owner"
          "urn:li:ownershipType:__system__data_steward"
        ]
      }
    }
  ) {
    urn
  }
}
```



#### CLI


Create a yaml file representing the forms you’d like to load.
For example, below file represents a form `123456` You can see the full example [here](https://github.com/datahub-project/datahub/blob/example-yaml-sp/metadata-ingestion/examples/forms/forms.yaml).

```yaml
- id: 123456
  # urn: "urn:li:form:123456"  # optional if id is provided
  type: VERIFICATION # Supported Types: COMPLETION(DOCUMENTATION), VERIFICATION
  name: "Metadata Initiative 2023"
  description: "How we want to ensure the most important data assets in our organization have all of the most important and expected pieces of metadata filled out"
  prompts:
    - id: "123"
      title: "Retention Time"
      description: "Apply Retention Time structured property to form"
      type: STRUCTURED_PROPERTY
      structured_property_id: io.acryl.privacy.retentionTime
      required: True # optional, will default to True
  entities: # Either pass a list of urns or a group of filters. This example shows a list of urns
    urns:
      - urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)
  # optionally assign the form to a specific set of users and/or groups
  # when omitted, form will be assigned to Asset owners
  actors:
    users:
      - urn:li:corpuser:jane@email.com # note: these should be urns
      - urn:li:corpuser:john@email.com
    groups:
      - urn:li:corpGroup:team@email.com # note: these should be urns
    owners: true # assign to asset owners (default: true when actors is omitted)
    ownership_types: # optional: filter by specific ownership types
      - urn:li:ownershipType:__system__technical_owner
      - urn:li:ownershipType:__system__data_steward
      # you can also use custom ownership types
```

:::note
Note that the structured properties and related entities should be created before you create the form.
Please refer to the [Structured Properties Tutorial](/docs/api/tutorials/structured-properties.md) for more information.
:::

You can apply forms to either a list of entity urns, or a list of filters. For a list of entity urns, use this structure:

```
entities:
urns:
  - urn:li:dataset:...
```

For a list of filters, use this structure:

```
entities:
filters:
  types:
    - dataset  # you can use entity type name or urn
  platforms:
    - snowflake  # you can use platform name or urn
  domains:
    - urn:li:domain:finance  # you must use domain urn
  containers:
    - urn:li:container:my_container  # you must use container urn
```

Note that you can filter to entity types, platforms, domains, and/or containers.

#### Form Assignment Options

The `actors` field controls who is asked to complete the form. The three options can be combined:

- `owners: true` (default) — assign to all owners of each in-scope asset.
- `ownership_types` — restrict the `owners: true` assignment to owners with one or more specific ownership types (e.g. `__system__technical_owner`, `__system__data_steward`, or any custom type). Omit it to match all ownership types.
- `users` / `groups` — explicitly target individuals or groups by URN, independent of ownership.

Example assigning to data stewards plus one explicit user:

```yaml
actors:
  owners: true
  ownership_types:
    - urn:li:ownershipType:__system__data_steward
  users:
    - urn:li:corpuser:admin@email.com
```

Use the CLI to create your properties:

```commandline
datahub forms upsert -f {forms_yaml}
```

If successful, you should see `Created form urn:li:form:...`




## Update Form



#### GraphQL


```graphql
mutation updateForm {
  updateForm(
    input: {
      urn: "urn:li:form:metadataInitiative2024"
      name: "Metadata Initiative 2024"
      description: "How we want to ensure the most important data assets in our organization have all of the most important and expected pieces of metadata filled out"
      type: VERIFICATION
      promptsToAdd: [
        {
          id: "456"
          title: "deprecationDate"
          description: "Deprecation date for dataset"
          type: STRUCTURED_PROPERTY
          structuredPropertyParams: {
            urn: "urn:li:structuredProperty:deprecationDate"
          }
        }
      ]
      promptsToRemove: ["123"]
    }
  ) {
    urn
  }
}
```




## Read Property Definition



#### CLI


You can see the properties you created by running the following command:

```commandline
datahub forms get --urn {urn}
```

For example, you can run `datahub forms get --urn urn:li:form:123456`.

If successful, you should see metadata about your form returned like below.

```json
{
  "urn": "urn:li:form:123456",
  "name": "Metadata Initiative 2023",
  "description": "How we want to ensure the most important data assets in our organization have all of the most important and expected pieces of metadata filled out",
  "prompts": [
    {
      "id": "123",
      "title": "Retention Time",
      "description": "Apply Retention Time structured property to form",
      "type": "STRUCTURED_PROPERTY",
      "structured_property_urn": "urn:li:structuredProperty:io.acryl.privacy.retentionTime"
    }
  ],
  "type": "VERIFICATION"
}
```




## Delete Form



#### GraphQL


```graphql
mutation deleteForm {
  deleteForm(input: { urn: "urn:li:form:metadataInitiative2024" })
}
```




## Assign Form to Entities

For assigning a form to a given list of entities:



#### GraphQL


```graphql
mutation batchAssignForm {
  batchAssignForm(
    input: {
      formUrn: "urn:li:form:myform"
      entityUrns: ["urn:li:dataset:mydataset1", "urn:li:dataset:mydataset2"]
    }
  )
}
```




## Remove Form from Entities

For removing a form from a given list of entities:



#### GraphQL


```graphql
mutation batchRemoveForm {
  batchRemoveForm(
    input: {
      formUrn: "urn:li:form:myform"
      entityUrns: ["urn:li:dataset:mydataset1", "urn:li:dataset:mydataset2"]
    }
  )
}
```



