·
Last changedVersion:
This version passed the hardening gate. Hardening applied 8 targeted changes and preserved all other text. Classified findings before hardening: 4. Classified findings closed: 3. Classified findings remaining: 1. Unclassified scanner findings remaining: 0. Review findings closed: 2. Review findings remaining: 19.
1
1
2
1
Expand | File | Group | Subtype | Severity | Status |
|---|---|---|---|---|---|
SKILL.md | Tool & MCP Manipulation | Unauthorized tool use | High | Closed | |
SKILL.md | Supply Chain & Install-Time Trust | — | Medium | Open | |
SKILL.md | Malicious Code & Command Execution | — | Low | Closed | |
SKILL.md | Supply Chain & Install-Time Trust | Install-time download and execute | Low | Closed |
4 findings
Grafana 13 (April 2026) moves from React 18 to React 19. Incompatible plugins will break. Do not upgrade React to 19 — only make forward-compatible changes.
All changes go in one PR. Execute steps in order. Never manually edit yarn.lock.
If PLUGIN_ID is empty, ask the user for the plugin root path.
Build the plugin and run the React 19 compatibility scanner:
Save the output. It flags:
jsxRuntimeImport / __SECRET_INTERNALS → Step 4 fixes thisdefaultProps / propTypes / ReactDOM.render → Step 8 (source fixes)findDOMNode → Step 6 (dependency bump) or Step 8 (source fix)If the build fails (plugin hasn't been built before), skip this step and run react-detect after Step 9 instead. If output says "No breaking changes detected", still proceed — jsx-runtime externalization and grafanaDependency bump are always required.
Re-run react-detect after Step 9 to confirm all issues are resolved.
@grafana/create-pluginThe scaffolding update brings in externals extraction, jest mocks, Docker fixes, and webpack
improvements needed for React 19. Always do this before add externalize-jsx-runtime.
Requires a clean git working tree. Create a feature branch first if not already on one.
yarn install fails with "engine is incompatible"The update runs an intermediate yarn install without --ignore-engines. Complete it manually:
Commit the intermediate state and re-run:
The auto-migration can generate invalid JS on plugins with complex ESLint configs. Do not skip — commit what succeeded, then complete the ESLint 9 migration manually:
Then follow the "Complete ESLint 9 migration" section below to finish.
Always run install and verify:
Commit if there are changes:
The create-plugin update bumps ESLint to v9, which requires flat config (eslint.config.js)
instead of .eslintrc. Whether the auto-migration (004) succeeded, partially succeeded, or
failed, you must ensure ESLint works before proceeding.
Three scenarios:
A) eslint.config.js exists and yarn lint passes — auto-migration succeeded. Proceed.
B) eslint.config.js exists but yarn lint fails — partial migration. Fix the issues:
Common fixes:
Invalid option '--ignore-path' or Invalid option '--ext' → remove those flags from
the lint script in package.json. In ESLint v9 flat config, ignores and file matching
are configured inside eslint.config.js, not via CLI flags. Update to: eslint --cache .Cannot find module 'eslint-plugin-deprecation' → remove the import/reference from
eslint.config.js (replaced by @typescript-eslint/no-deprecated)C) No eslint.config.js exists — auto-migration failed. Create one manually:
If flat.js exists, create eslint.config.js using it as the base:
Then migrate any custom rules from the old .eslintrc into additional config objects in the array.
After creating the flat config:
lint script: "lint": "eslint --cache .".eslintrc (leave .config/.eslintrc — it's scaffolded and harmless)Fix auto-fixable issues with yarn lint --fix. Commit:
Always use the create-plugin add command. Requires a clean git working tree.
Verify:
webpack.config.ts:Commit:
grafanaDependencyIf not already >=12.3.0, update it. The create-plugin add may have already done this.
| Package | Target |
|---|---|
|
|
|
|
|
|
Bump @grafana/data, @grafana/runtime, @grafana/schema, @grafana/ui to ^12.2.0 or later.
Add @grafana/i18n@^12.2.0 if the plugin uses translations or @grafana/scenes requires it.
Bump react and react-dom to ^18.3.0 (surfaces React 19 issues early).
Add @types/react@^18.3.0 and @types/react-dom@^18.3.0 to devDependencies if missing.
Remove from devDependencies if present:
eslint-plugin-deprecation (replaced by @typescript-eslint/no-deprecated)@types/testing-library__jest-dom (replaced by setupTests.d.ts)If yarn install fails with a stale git reference, do not edit yarn.lock. Add a resolutions entry:
Then delete yarn.lock and node_modules and reinstall:
@openfeature/web-sdk peer dependency@grafana/runtime depends on @openfeature/react-sdk which has @openfeature/web-sdk as a
peer dependency. Yarn v1 (classic) does not auto-install peer deps.
Check if the plugin uses yarn classic:
If version starts with 1., check for warnings:
If warnings are found:
Skip condition: Yarn v2+ or npm v7+ (peer deps are auto-installed).
| Pattern | Fix |
|---|---|
|
|
| Move to destructured parameter defaults |
| Leave — still works |
| Remove |
| Use |
| Use JSX or |
| Change to |
| Error | Fix |
|---|---|
| Step 4 not applied — re-run |
| Step 7 — |
|
|
| Bump |
| Add |
Stale git hash in | Add |
For detailed known issues (i18n crash, @grafana/schema type breaks, publicPath mismatch), see
references/known-issues.md.
plugin-ci-workflows@main or >= 6.0.0 → already tests React 19. No changes needed.plugin-actions/e2e-version → add skip-grafana-react-19-preview-image: false.GRAFANA_VERSION=dev-preview-react19 docker compose up --build.Commit message body should list: create-plugin version change, ESLint 9 migration, key dependency bumps, and any source code fixes.
Get started with chainctlchainctl skill install public/grafana/react-19-plugin-migration:latest
Bring Chainguard's hardening pipeline to your first-party skills — custom rulesets, automated remediation, full audit trail.
skills.cgr.dev/public/github.com/grafana/skills/grafana-plugins/react-19-plugin-migration:latest
Apache-2.0
HARDENING.md
LICENSE
SKILL.md
references/known-issues.md