Skip to content

Custom Package Metadata#

Enhanced Advanced

Overview#

Posit Package Manager allows administrators to define custom key-value pairs as metadata for packages with flexible matching criteria.

Package metadata can be added globally, affecting multiple packages across a source or repository; or they can be as specific as a single package version in one source or repository.

Custom package metadata support is available at the Enhanced tier for local use and Advanced tier for remote use.

Custom Metadata System#

Package metadata utilizes a criteria matching system to apply key-value pairs to packages with increasing specificity the more criteria are matched. As examples of how custom metadata can be applied, you can:

  • Add a risk score to all packages in a repository
  • Add a risk score to a single version of a specific package
  • Add a documentation link to a specific package

The matching criteria for package metadata is displayed when creating metadata. Use the rspm create metadata or rspm create bulk-metadata commands to create new metadata, and rspm list metadata command to list them.

Terminal
# Add a high risk score to all CRAN packages
$ rspm create metadata --source=cran --key=risk --value=10

# Add a high risk score to django 1.0.0
$ rspm create metadata --package-name=django --version='1.0.0' --key=risk --value=10

# Add a low risk score to django 1.0.0 in an exempt source
$ rspm create metadata --package-name=django --version='1.0.0' --source="exempt-source" --key=risk --value=0

# List all metadata
$ rspm list metadata

ID: 1 (global)
-- Data:
    - Key: risk
    - Value: 10
-- Constraints:
    - Source: cran

ID: 2 (Package: django)
-- Data:
    - Key: risk
    - Value: 10
-- Constraints:
    - Version: 1.0.0

ID: 3 (Package: django)
-- Data:
    - Key: risk
    - Value: 0
-- Constraints:
    - Source: exempt-source
    - Version: 1.0.0

Bulk Creation#

Bulk creation of metadata can be done both via JSON and CSV input files. See rspm create bulk-metadata for more information.

Terminal
# View the shape of the JSON
$ cat /tmp/metadata.json
[
    {
        "package_name": "ggplot2",
        "key": "risk",
        "value": "10",
        "repo": "cran",
        "source": "cran"
    },
    {
        "package_name": "ggplot2",
        "key": "risk",
        "value": "5",
        "repo": "cran",
        "source": "cran",
        "version": "1.0.0"
    }
]

# Bulk create the metadata
$ bin/rspm create bulk-metadata --path=/tmp/metadata.json
{
  "affected": [
    {
      "id": 1,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "10",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        }
      ]
    },
    {
      "id": 2,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "5",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        },
        {
          "version": "1.0.0"
        }
      ]
    }
  ],
  "rejected": null
}
Terminal
# View the shape of the CSV
$ cat /tmp/metadata.csv
"value","key","source","repo","version","package_name"
"10","risk","cran","cran","","ggplot2"
"5","risk","cran","cran","1.0.0","ggplot2"

# Bulk create the metadata
$ rspm create bulk-metadata --csv-in=/tmp/metadata.csv
{
  "affected": [
    {
      "id": 1,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "10",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        }
      ]
    },
    {
      "id": 2,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "5",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        },
        {
          "version": "1.0.0"
        }
      ]
    }
  ],
  "rejected": null
}

Matching Criteria#

Custom metadata supports several matching criteria. These include:

  • Package name: Name of the package. R packages are case-sensitive, while Python packages are case-insensitive.
  • Version: A package version.
  • Source: Name of the source, such as cran or pypi. All source types are supported.
  • Repository: Name of the repository.

For more information on the matching criteria, reference the CLI appendix.

Specificity and Conflicting Key-Value Pairs#

When multiple matching keys are matched to a package, the key-value pair with the highest specificity takes precedence.

Examples#

Terminal
ID: 1 (global)
-- Data:
    - Key: risk
    - Value: 60
-- Constraints:
    - Source: cran
ID: 2 (Package: plumber)
-- Data:
    - Key: risk
    - Value: 70
ID: 3 (Package: plumber)
-- Data:
    - Key: risk
    - Value: 80
-- Constraints:
    - Version: 1.0.1
ID: 4 (Package: plumber)
-- Data:
    - Key: risk
    - Value: 90
-- Constraints:
    - Source: cran
    - Version: 1.0.1
ID: 5 (Package: plumber)
-- Data:
    - Key: risk
    - Value: 95
-- Constraints:
    - Source: cran
    - Repo: cran
    - Version: 1.0.1

Given the above set of 5 metadata records, the plumber package with version 1.0.1 in the cran repository will have a risk score of 95.

Editing Metadata#

Custom metadata can be edited using the same rspm create metadata command, by passing the --update-existing flag.

Following the example above for creating new metadata, we can update it like this:

Terminal
# Lower the risk score of all CRAN packages
$ rspm create metadata --source=cran --key=risk --value=5 --update-existing

# List all metadata
$ rspm list metadata
ID: 1 (global)
-- Data:
    - Key: risk
    - Value: 5
-- Constraints:
    - Source: cran

Bulk Edit#

Bulk edits of metadata is done via the rspm create bulk-metadata command. There are no additional flags necessary, the command automatically updates existing records if the value has changed.

Terminal
# View existing metadata
$ rspm list metadata --output-format=json
[
  {
    "id": 1,
    "package_name": "ggplot2",
    "key": "risk",
    "value": "10",
    "constraints": [
      {
        "repo_id": 2,
        "repo": "cran",
      },
      {
        "source_id": 1
        "source_name": "cran"
      }
    ]
  },
  {
    "id": 2,
    "package_name": "ggplot2",
    "key": "risk",
    "value": "5",
    "constraints": [
      {
        "repo_id": 2,
        "repo": "cran",
      },
      {
        "source_id": 1
        "source_name": "cran"
      },
      {
        "version": "1.0.0"
      }
    ]
  }
]

# View the shape of the JSON
$ cat /tmp/metadata.json
[
    {
        "package_name": "ggplot2",
        "key": "risk",
        "value": "20",
        "repo": "cran",
        "source": "cran"
    },
    {
        "package_name": "ggplot2",
        "key": "risk",
        "value": "10",
        "repo": "cran",
        "source": "cran",
        "version": "1.0.0"
    }
]

# Bulk edit the metadata
$ rspm create bulk-metadata --path=/tmp/metadata.json
{
  "affected": [
    {
      "id": 1,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "20",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        }
      ]
    },
    {
      "id": 2,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "10",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        },
        {
          "version": "1.0.0"
        }
      ]
    }
  ],
  "rejected": null
}
Terminal
# View existing metadata
$ rspm list metadata --output-format=json
[
  {
    "id": 1,
    "package_name": "ggplot2",
    "key": "risk",
    "value": "10",
    "constraints": [
      {
        "repo_id": 2,
        "repo": "cran",
      },
      {
        "source_id": 1
        "source_name": "cran"
      }
    ]
  },
  {
    "id": 2,
    "package_name": "ggplot2",
    "key": "risk",
    "value": "5",
    "constraints": [
      {
        "repo_id": 2,
        "repo": "cran",
      },
      {
        "source_id": 1
        "source_name": "cran"
      },
      {
        "version": "1.0.0"
      }
    ]
  }
]

# View the shape of the CSV
$ cat /tmp/metadata.csv
"value","key","source","repo","version","package_name"
"20","risk","cran","cran","","ggplot2"
"10","risk","cran","cran","1.0.0","ggplot2"

# Bulk edit the metadata
$ rspm create bulk-metadata --csv-in=/tmp/metadata.csv
{
  "affected": [
    {
      "id": 1,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "20",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        }
      ]
    },
    {
      "id": 2,
      "package_name": "ggplot2",
      "key": "risk",
      "value": "10",
      "constraints": [
        {
          "repo_id": 2,
          "repo": "cran",
        },
        {
          "source_id": 1
          "source_name": "cran"
        },
        {
          "version": "1.0.0"
        }
      ]
    }
  ],
  "rejected": null
}

Remote Usage#

The metadata commands can also be used remotely, e.g. rspm create metadata. This allows automating metadata management.

When generating a token to set metadata remotely, the rspm create token command must include either --scope=metadata:admin or --scope=global:admin. The metadata:admin scope gives full access to create, update, delete, and list metadata.

For more information on remotely adding or editing metadata, refer to the Admin CLI - Remote Use section.

Remote usage of custom metadata commands is available at the Advanced tier.