Skip to content

Latest commit

 

History

History
363 lines (275 loc) · 16.9 KB

README.md

File metadata and controls

363 lines (275 loc) · 16.9 KB

Grafana Plugin Validator

License Drone Go Report Card

This tool helps speed up the process of publishing plugins to Grafana.com. It runs a series of analyzers to ensure plugins are following best practices, checking for security and structural issues, as well as specific requirements related to publishing. A general overview of these requirements can be found here: https://grafana.com/docs/grafana/latest/developers/plugins/publishing-and-signing-criteria/.

It requires a path to a remote or local ZIP archive of the plugin to be specified, for example:

  • Remote: https://github.com/grafana/clock-panel/releases/download/v2.1.2/grafana-clock-panel-2.1.2.zip
  • Local: file://Users/me/Downloads/grafana-clock-panel-2.1.2.zip

You can additionally provide a link to the source code for the project with -sourceCodeUri to enable additional analyzers such as the Vulnerability Scan.

Installation and usage

Ensure that your version of Go matches the one specified in the go.mod file to avoid compatibility issues

Docker (recommended)

It is easiest to run the tool using the Docker image as it contains all the security scanning tools needed for the full set of analyzers - so you don't need to have these additional tools installed on your system.

docker run --pull=always grafana/plugin-validator-cli [options] [http://yourdomain/plugin_archive.zip]

Example 1 (basic)

docker run --pull=always grafana/plugin-validator-cli https://github.com/grafana/clock-panel/releases/download/v2.1.2/grafana-clock-panel-2.1.2.zip

Example 2 (specifying source code location)

docker run --pull=always grafana/plugin-validator-cli -sourceCodeUri https://github.com/grafana/clock-panel/tree/v2.1.2 https://github.com/grafana/clock-panel/releases/download/v2.1.2/grafana-clock-panel-2.1.2.zip

Using a local archive file with Docker

To run the tool with a local archive you will need to mount it as a docker volume. Here's an example:

docker run --pull=always -v /path/to/plugin_archive.zip:/archive.zip grafana/plugin-validator-cli /archive.zip

Note

If using relative paths your path must start with ./

Using a local archive file and local source code

docker run --pull=always -v /path/to/plugin_archive.zip:/archive.zip -v /path/to/source_code:/source_code grafana/plugin-validator-cli -sourceCodeUri file:///source_code /archive.zip

Note

If using relative paths your path must start with ./

NPX

npx -y @grafana/plugin-validator@latest -sourceCodeUri [options] [path/to/plugin_archive.zip]

Locally

First you must compile and install it:

git clone [email protected]:grafana/plugin-validator.git
cd plugin-validator/pkg/cmd/plugincheck2
go install

Then you can run the utility:

plugincheck2 -sourceCodeUri [source_code_location/] [plugin_archive.zip]

Generating local files For validation

You must create a .zip archive containing the dist/ directory but named as your plugin ID:

PLUGIN_ID=$(grep '"id"' < src/plugin.json | sed -E 's/.*"id" *: *"(.*)".*/\1/')
cp -r dist "${PLUGIN_ID}"
zip -qr "${PLUGIN_ID}.zip" "${PLUGIN_ID}"
npx @grafana/plugin-validator@latest -sourceCodeUri file://. "${PLUGIN_ID}.zip"

You can optionally remove the files that were generated:

rm -r "${PLUGIN_ID}" "${PLUGIN_ID}.zip"

Options

Additional options can be passed to the tool:

❯ plugincheck2 -help
Usage plugincheck2:
  -config string (optional)
        Path to configuration file
  -sourceCodeUri string (optional)
        URI to the source code of the plugin. If set, the source code will be downloaded and analyzed. This can be a ZIP file URL, a URL to git repository or a local file (starting with `file://`)
  -strict (optional)
        If set, plugincheck returns non-zero exit code for warnings
  -checksum string (optional)
        If set, the checksum of the plugin archive will be checked against this value. MD5 and SHA256 are supported.
  -analyzer string (optional)
        If set, only an specific analyzer and it's dependencies will run.
  -severity string (optional)
        If used, it will set the severity of the analyzer (it has the highest priority).

Using a configuration file

You can pass a configuration YAML file to the validator with the -config option. Several configuration examples are available to use here: https://github.com/grafana/plugin-validator/tree/main/config.

Enabling and disabling analyzers via config

If you want to disable an specific check (analyzer) you can define this in your configuration file, adding an analyzers section, and specifying which analyzer or analyzer rules to enable and disable.

For example, disable the version analyzer:

global:
  enabled: true
  jsonOutput: false
  reportAll: false

analyzers:
  version:
    enabled: false

You can also disable specific rules or change their severity level:

global:
  enabled: true
  jsonOutput: false
  reportAll: false

analyzers:
  readme:
    rules:
      missing-readme:
        enabled: true
        severity: warning

Severity levels could be: error, warning, or ok.

Note: Grafana Labs enforces its own configuration for plugins submissions and your own config file can't change these rules.

Source code

You can specify the location of the plugin source code to the validator with the -sourceCodeUri option. Doing so allows for additional analyzers to be run and for a more complete scan.

Supported remote Git services

The following public Git services are supported:

  • GitHub
  • GitLab
  • Bitbucket

Private repositories are not currently supported.

Make sure to include the ref (branch or tag) of the corresponding source code.

For example: you are validating version v2.1.2 and your project is in GitHub. Make sure you create a corresponding tag or branch and use the URL https://github.com/grafana/clock-panel/tree/v2.1.2.

Debug mode

You can run the validator in debug mode to get more information about the running checks and possible errors.

Docker:

docker run --pull=always -e DEBUG=1 grafana/plugin-validator-cli -sourceCodeUri https://github.com/grafana/clock-panel/tree/v2.1.2 https://github.com/grafana/clock-panel/releases/download/v2.1.2/grafana-clock-panel-2.1.2.zip

NPX:

DEBUG=1 npx -y @grafana/plugin-validator@latest -sourceCodeUri https://github.com/grafana/clock-panel/tree/v2.1.2 https://github.com/grafana/clock-panel/releases/download/v2.1.2/grafana-clock-panel-2.1.2.zip

Locally:

DEBUG=1 plugincheck2 -sourceCodeUri https://github.com/grafana/clock-panel/tree/v2.1.2 https://github.com/grafana/clock-panel/releases/download/v2.1.2/grafana-clock-panel-2.1.2.zip

Security tools

This validator makes uses of the following open source security tools:

If you run the validator locally or via NPX you can benefit from installing these tools in your system to make them part of your validation checks.


Analyzers

The tool runs a series of analyzers to ensure submitted plugins are following best practices, and speed up the process of approving a plugin for publishing, detailed in the table below. The Analyzer column includes the name required for altering the behavior of a given check in a configuration file. The Dependencies column specifies whether the analyzer requires the source code for the plugin to be provided with sourceCodeUri or for any additional security scanning tools to be present.

Analyzer Description Dependencies
Archive Name / archivename The name of the archive should be correctly formatted. None
Archive Structure / archive Ensures the contents of the zip file have the expected layout. None
Backend Binary / backendbinary Validates the consistency between the existence of a binary file and plugin.json declarations for backend or alerting. None
Backend Debug / backenddebug Checks that the standalone debug files for backend plugins are not present. None
Binary Permissions / binarypermissions For datasources and apps with binaries, this ensures the plugin can run when extracted on a system. None
Broken Links / brokenlinks Detects if any URL doesn't resolve to a valid location. None
Checksum / checksum Validates that the passed checksum (as a validator arg) is the one calculated from the archive file. checksum
Circular Dependencies / circulardependencies Ensures that there aren't any circular dependencies between plugins (plugin.json, dependencies.plugins field). None
Code Rules / code-rules Checks for forbidden access to environment variables, file system or use of syscall module. semgrep, sourceCodeUri
Developer Jargon / jargon Generally discourages use of code jargon in the documentation. None
Discoverability / discoverability Warns about missing keywords and description that are used for plugin indexing in the catalog. None
Go Manifest / go-manifest Validates the build manifest. None
Go Security Checker / go-sec Inspects source code for security problems by scanning the Go AST. gosec, sourceCodeUri
JS Source Map / jsMap Checks for required module.js.map file(s) in archive. sourceCodeUri
Legacy Grafana Toolkit usage / legacybuilder Detects the usage of the not longer supported Grafana Toolkit. None
Legacy Platform / legacyplatform Detects use of Angular which is deprecated. None
License Type / license Checks the declared license is one of: BSD, MIT, Apache 2.0, LGPL3, GPL3, AGPL3. None
LLM Review / llmreview Runs the code through Gemini LLM to check for security issues or disallowed usage. Gemini API key
Logos / logos Detects whether the plugin includes small and large logos to display in the plugin catalog. None
Manifest (Signing) / manifest When a plugin is signed, the zip file will contain a signed MANIFEST.txt file. None
Metadata / metadata Checks that plugin.json exists and is valid. None
Metadata Paths / metadatapaths Ensures all paths are valid and images referenced exist. None
Metadata Validity / metadatavalid Ensures metadata is valid and matches plugin schema. None
module.js (exists) / modulejs All plugins require a module.js to be loaded. None
Nested includes metadata / includesnested Validates that nested plugins have the correct metadata. None
Nested Metadata / nestedmetadata Recursively checks that all plugin.json exist and are valid. None
No Tracking Scripts / trackingscripts Detects if there are any known tracking scripts, which are not allowed. None
Organization (exists) / org Verifies the org specified in the plugin ID exists. None
package.json / packagejson Ensures that package.json exists and the version matches the plugin.json None
Plugin Name formatting / pluginname Validates the plugin ID used conforms to our naming convention. None
Published / published-plugin Detects whether any version of this plugin exists in the Grafana plugin catalog currently. None
Readme (exists) / readme Ensures a README.md file exists within the zip file. None
Restrictive Dependency / restrictivedep Specifies a valid range of Grafana versions that work with this version of the plugin. None
Screenshots / screenshots Screenshots are specified in plugin.json that will be used in the Grafana plugin catalog. None
SDK Usage / sdkusage Ensures that grafana-plugin-sdk-go is up-to-date. None
Signature / signature Ensures the plugin has a valid signature. None
Source Code / sourcecode A comparison is made between the zip file and the source code to ensure what is released matches the repo associated with it. sourceCodeUri
Type Suffix (panel/app/datasource) / typesuffix Ensures the plugin has a valid type specified. None
Unique README.md / templatereadme Ensures the plugin doesn't re-use the template from the create-plugin tool. None
Unsafe SVG / manifest Checks if any svg files are safe based on a whitelist of elements and attributes. None
Version / version Ensures the version submitted is newer than the currently published plugin. If this is a new/unpublished plugin, this is skipped. None
Virus Scan / virusscan Runs a virus scan on the plugin archive and source code using clamscan (clamav). clamscan
Vulnerability Scanner / osv-scanner Detects critical vulnerabilities in Go modules and yarn lock files. osv-scanner, sourceCodeUri

Output

By default, the tool outputs results in plain text as shown below.

Default:

warning: README.md: possible broken link: https://www.d3js.org (404 Not Found)
detail: README.md might contain broken links. Check that all links are valid and publicly accessible.
warning: README.md contains developer jargon: (yarn)
detail: Move any developer and contributor documentation to a separate file and link to it from the README.md. For example, CONTRIBUTING.md, DEVELOPMENT.md, etc.
error: osv-scanner detected a critical severity issue
detail: SEVERITY: CRITICAL in package immer, vulnerable to CVE-2021-23436
error: osv-scanner detected a critical severity issue
detail: SEVERITY: CRITICAL in package json-schema, vulnerable to CVE-2021-3918
error: Plugin version 0.0.9 is invalid.
detail: The submitted plugin version 0.0.9 is not greater than the latest published version 0.0.9 on grafana.com.

This can be changed to JSON by passing a configuration file which includes:

global:
  jsonOutput: true

Resulting in output similar to:

{
  "id": "briangann-gauge-panel",
  "version": "0.0.9",
  "plugin-validator": {
    "brokenlinks": [
      {
        "Severity": "warning",
        "Title": "README.md: possible broken link: https://www.d3js.org (404 Not Found)",
        "Detail": "README.md might contain broken links. Check that all links are valid and publicly accessible.",
        "Name": "broken-link"
      }
    ],
    "jargon": [
      {
        "Severity": "warning",
        "Title": "README.md contains developer jargon: (yarn)",
        "Detail": "Move any developer and contributor documentation to a separate file and link to it from the README.md. For example, CONTRIBUTING.md, DEVELOPMENT.md, etc.",
        "Name": "developer-jargon"
      }
    ],
    "osv-scanner": [
      {
        "Severity": "error",
        "Title": "osv-scanner detected a critical severity issue",
        "Detail": "SEVERITY: CRITICAL in package immer, vulnerable to CVE-2021-23436",
        "Name": "osv-scanner-critical-severity-vulnerabilities-detected"
      },
      {
        "Severity": "error",
        "Title": "osv-scanner detected a critical severity issue",
        "Detail": "SEVERITY: CRITICAL in package json-schema, vulnerable to CVE-2021-3918",
        "Name": "osv-scanner-critical-severity-vulnerabilities-detected"
      },
    ],
    "version": [
      {
        "Severity": "error",
        "Title": "Plugin version 0.0.9 is invalid.",
        "Detail": "The submitted plugin version 0.0.9 is not greater than the latest published version 0.0.9 on grafana.com.",
        "Name": "wrong-plugin-version"
      }
    ]
  }
}

Severity

By default, the tool will show any warning or error level results from the analyzers. To see all results including successes, you can pass a configuration file which includes:

global:
  reportAll: true

Getting Help

License

Grafana Plugin Validator is distributed under the Apache 2.0 License.