@grafana/plugin-ui 0.17.3 → 0.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/NOTICE +18 -0
  2. package/dist/cjs/index.cjs +3 -3
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/cjs/secret-scanner.cjs +3032 -0
  5. package/dist/cjs/secret-scanner.cjs.map +1 -0
  6. package/dist/cjs/secret-scanner.d.cts +273 -0
  7. package/dist/esm/node_modules/js-yaml/dist/js-yaml.js +3 -3
  8. package/dist/esm/node_modules/js-yaml/dist/js-yaml.js.map +1 -1
  9. package/dist/esm/secret-scanner/core/constants.js +4 -0
  10. package/dist/esm/secret-scanner/core/constants.js.map +1 -0
  11. package/dist/esm/secret-scanner/core/detection/embedded.js +80 -0
  12. package/dist/esm/secret-scanner/core/detection/embedded.js.map +1 -0
  13. package/dist/esm/secret-scanner/core/detection/entropy.js +19 -0
  14. package/dist/esm/secret-scanner/core/detection/entropy.js.map +1 -0
  15. package/dist/esm/secret-scanner/core/detection/highEntropy.js +24 -0
  16. package/dist/esm/secret-scanner/core/detection/highEntropy.js.map +1 -0
  17. package/dist/esm/secret-scanner/core/detection/literals.js +135 -0
  18. package/dist/esm/secret-scanner/core/detection/literals.js.map +1 -0
  19. package/dist/esm/secret-scanner/core/detection/nameDetector.js +48 -0
  20. package/dist/esm/secret-scanner/core/detection/nameDetector.js.map +1 -0
  21. package/dist/esm/secret-scanner/core/detection/placeholders.js +10 -0
  22. package/dist/esm/secret-scanner/core/detection/placeholders.js.map +1 -0
  23. package/dist/esm/secret-scanner/core/detection/position.js +39 -0
  24. package/dist/esm/secret-scanner/core/detection/position.js.map +1 -0
  25. package/dist/esm/secret-scanner/core/detection/ruleDetectors.js +59 -0
  26. package/dist/esm/secret-scanner/core/detection/ruleDetectors.js.map +1 -0
  27. package/dist/esm/secret-scanner/core/k6Rewriter.js +44 -0
  28. package/dist/esm/secret-scanner/core/k6Rewriter.js.map +1 -0
  29. package/dist/esm/secret-scanner/core/memoizeLatest.js +18 -0
  30. package/dist/esm/secret-scanner/core/memoizeLatest.js.map +1 -0
  31. package/dist/esm/secret-scanner/core/scanCode.js +70 -0
  32. package/dist/esm/secret-scanner/core/scanCode.js.map +1 -0
  33. package/dist/esm/secret-scanner/core/scanText.js +51 -0
  34. package/dist/esm/secret-scanner/core/scanText.js.map +1 -0
  35. package/dist/esm/secret-scanner/core/secretScanner.utils.js +33 -0
  36. package/dist/esm/secret-scanner/core/secretScanner.utils.js.map +1 -0
  37. package/dist/esm/secret-scanner/monaco/installSecretScanner.js +117 -0
  38. package/dist/esm/secret-scanner/monaco/installSecretScanner.js.map +1 -0
  39. package/dist/esm/secret-scanner/panel/SecretReferenceModal.js +21 -0
  40. package/dist/esm/secret-scanner/panel/SecretReferenceModal.js.map +1 -0
  41. package/dist/esm/secret-scanner/panel/SecretScannerPanel.js +75 -0
  42. package/dist/esm/secret-scanner/panel/SecretScannerPanel.js.map +1 -0
  43. package/dist/esm/secret-scanner/react/useIgnoredSecrets.js +25 -0
  44. package/dist/esm/secret-scanner/react/useIgnoredSecrets.js.map +1 -0
  45. package/dist/esm/secret-scanner/react/useLocalStorageList.js +38 -0
  46. package/dist/esm/secret-scanner/react/useLocalStorageList.js.map +1 -0
  47. package/dist/esm/secret-scanner/react/useMonacoSecretScanner.js +28 -0
  48. package/dist/esm/secret-scanner/react/useMonacoSecretScanner.js.map +1 -0
  49. package/dist/esm/secret-scanner/react/useSecretScanner.js +57 -0
  50. package/dist/esm/secret-scanner/react/useSecretScanner.js.map +1 -0
  51. package/dist/esm/secret-scanner/rules/rules.generated.js +2083 -0
  52. package/dist/esm/secret-scanner/rules/rules.generated.js.map +1 -0
  53. package/dist/esm/secret-scanner.d.ts +273 -0
  54. package/dist/esm/secret-scanner.js +15 -0
  55. package/dist/esm/secret-scanner.js.map +1 -0
  56. package/package.json +37 -3
@@ -0,0 +1,273 @@
1
+ import * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
2
+ import React from 'react';
3
+
4
+ type SecretConfidence = 'high' | 'medium' | 'low';
5
+ type SecretRewrite = 'literal' | 'template-interpolation' | 'none';
6
+ interface SecretRange {
7
+ start: number;
8
+ end: number;
9
+ }
10
+ interface SecretFinding {
11
+ id: string;
12
+ type: string;
13
+ label: string;
14
+ confidence: SecretConfidence;
15
+ secret: string;
16
+ range: SecretRange;
17
+ line: number;
18
+ column: number;
19
+ literal?: SecretRange;
20
+ rewrite?: SecretRewrite;
21
+ }
22
+ interface DetectionResult {
23
+ type: string;
24
+ label: string;
25
+ confidence: SecretConfidence;
26
+ secret: string;
27
+ }
28
+
29
+ /**
30
+ * Converts a character offset into a 1-based {line, column}.
31
+ */
32
+ declare function offsetToPosition(text: string, offset: number): {
33
+ line: number;
34
+ column: number;
35
+ };
36
+
37
+ /** Shannon entropy in bits per character — high for random tokens. */
38
+ declare function shannonEntropy(value: string): number;
39
+
40
+ /**
41
+ * Code-first scanner: flags likely hardcoded secrets in a script.
42
+ *
43
+ * String-literal aware (AST-based) rather than raw-text, so reported ranges line
44
+ * up with what the user sees and a rewrite can edit the original text.
45
+ *
46
+ * For plain-text outside a literal, use `scanText`.
47
+ *
48
+ * Orchestration only; the detectors live in `./detection`.
49
+ */
50
+
51
+ /**
52
+ * A code scanner with its own memo. Prefer this to the shared {@link scanCode}
53
+ * when more than one surface scans independently — see `memoizeLatest`.
54
+ */
55
+ declare function createCodeScanner(): (script: string) => SecretFinding[];
56
+ /** Shared code scanner, for a host with a single scanning surface. */
57
+ declare const scanCode: (script: string) => SecretFinding[];
58
+
59
+ /**
60
+ * A text scanner with its own memo. Prefer this to the shared {@link scanText}
61
+ * when more than one surface scans independently — see `memoizeLatest`.
62
+ */
63
+ declare function createTextScanner(): (text: string) => SecretFinding[];
64
+ /** Shared text scanner, for a host with a single scanning surface. */
65
+ declare const scanText: (text: string) => SecretFinding[];
66
+
67
+ /**
68
+ * Memoizes the latest input only — a scanner sees an evolving document, so anything older is not relevant.
69
+ */
70
+ declare function memoizeLatest<T>(compute: (input: string) => T[]): (input: string) => T[];
71
+
72
+ /**
73
+ * How long to wait after the last edit before re-scanning. A scan runs every
74
+ * detector over the whole document (and, for code scans, re-parses it), so
75
+ * running it on every keystroke blocks typing. Debouncing coalesces a burst of
76
+ * edits into one scan.
77
+ */
78
+ declare const DEFAULT_DEBOUNCE_MS = 1500;
79
+
80
+ interface ApplyResult {
81
+ text: string;
82
+ addedImport: boolean;
83
+ needsAsync: boolean;
84
+ applied: boolean;
85
+ }
86
+ /**
87
+ * Turns a finding into a reference to a managed secret
88
+ *
89
+ * Implement this to target something other than k6; pass it to
90
+ * `useSecretScanner` (or call it directly). {@link k6SecretRewriter} is the
91
+ * default.
92
+ */
93
+ interface SecretRewriter {
94
+ apply(text: string, finding: SecretFinding, secretName: string): ApplyResult;
95
+ reference(secretName: string, binding?: string): string;
96
+ }
97
+
98
+ /**
99
+ * The k6 {@link SecretRewriter}: rewrites a detected hardcoded secret into a
100
+ * reference to the managed Secrets store, matching the syntax documented in the
101
+ * in-product Secrets guide:
102
+ *
103
+ * import secrets from 'k6/secrets'
104
+ * const value = await secrets.get('my-secret')
105
+ *
106
+ * This is the only k6-specific piece of the library. Everything else — the
107
+ * detectors, the finding shape, the hooks, the panel — is runtime-agnostic.
108
+ */
109
+
110
+ declare function buildSecretReference(secretName: string, binding?: string): string;
111
+ declare function applySecretReference(script: string, finding: SecretFinding, secretName: string): ApplyResult;
112
+ declare const k6SecretRewriter: SecretRewriter;
113
+
114
+ /**
115
+ * Suggests a Secrets-store-compatible name for a finding. Secret names must be
116
+ * lowercase and may only contain letters, numbers, dashes and periods (see
117
+ * `secretSchema`), so we derive the suggestion from the detector type and
118
+ * de-duplicate against existing names.
119
+ */
120
+ declare function suggestSecretName(finding: Pick<SecretFinding, 'type'>, existingNames?: string[]): string;
121
+ declare function maskSecret(secret: string): string;
122
+ /**
123
+ * Stable signature for remembering an "ignore" choice across edits and reloads.
124
+ * Hashing (FNV-1a) keeps the plaintext out of local storage, and deriving it
125
+ * from content rather than position keeps it stable when the secret moves —
126
+ * unlike the finding `id`.
127
+ */
128
+ declare function getFindingSignature(finding: Pick<SecretFinding, 'type' | 'secret'>): string;
129
+
130
+ type MonacoNamespace = typeof monacoType;
131
+ type IStandaloneCodeEditor = monacoType.editor.IStandaloneCodeEditor;
132
+
133
+ /** Marker `code` identifying the scanner's diagnostics for the quick fix. */
134
+ declare const SECRET_MARKER_CODE = "hardcoded-secret";
135
+ interface InstallSecretScannerOptions {
136
+ languages?: string[];
137
+ enabled?: boolean;
138
+ markerMessage?: (finding: SecretFinding) => string;
139
+ quickFix?: {
140
+ title?: string;
141
+ run: (finding: SecretFinding) => void;
142
+ };
143
+ scan?: (code: string) => SecretFinding[];
144
+ debounceMs?: number;
145
+ }
146
+ interface SecretScannerInstallation {
147
+ refresh(): void;
148
+ dispose(): void;
149
+ }
150
+ /**
151
+ * Gutter markers for detected secrets plus an optional "Move to Secrets Manager"
152
+ * quick fix.
153
+ */
154
+ declare function installSecretScanner(monaco: MonacoNamespace, editor: IStandaloneCodeEditor, options?: InstallSecretScannerOptions): SecretScannerInstallation;
155
+
156
+ interface UseSecretScannerParams {
157
+ text: string;
158
+ scan?: (text: string) => SecretFinding[];
159
+ rewriter?: SecretRewriter;
160
+ onChange?: (text: string) => void;
161
+ enabled?: boolean;
162
+ ignoreStorageKey?: string;
163
+ debounceMs?: number;
164
+ }
165
+ interface SecretReference {
166
+ finding: SecretFinding;
167
+ secretName: string;
168
+ reference: string;
169
+ }
170
+ interface SecretMigration {
171
+ finding: SecretFinding | null;
172
+ request: (finding: SecretFinding) => void;
173
+ cancel: () => void;
174
+ apply: (finding: SecretFinding, secretName: string) => void;
175
+ }
176
+ /** The fallback flow for a secret that couldn't be inserted automatically. */
177
+ interface SecretReferenceFallback {
178
+ pending: SecretReference | null;
179
+ dismiss: () => void;
180
+ }
181
+ interface SecretScanner {
182
+ /** Detected secrets, minus the ones the user ignored. */
183
+ findings: SecretFinding[];
184
+ ignore: (finding: SecretFinding) => void;
185
+ migration: SecretMigration;
186
+ reference: SecretReferenceFallback;
187
+ }
188
+ /**
189
+ * Headless secret scanner over any string — a code editor's contents, a
190
+ * textarea, a prompt field. Owns detection, debouncing, ignore state and the
191
+ * rewrite.
192
+ */
193
+ declare function useSecretScanner(params: UseSecretScannerParams): SecretScanner;
194
+
195
+ interface UseMonacoSecretScannerParams extends UseSecretScannerParams {
196
+ /** Monaco namespace + editor, injected from the host's editor mount. */
197
+ monaco?: MonacoNamespace;
198
+ editor?: IStandaloneCodeEditor;
199
+ /** Whether the "Move to secret" quick fix is offered. Default true. */
200
+ canMigrate?: boolean;
201
+ /** Languages to register the quick fix for. Default: ts + js. */
202
+ languages?: string[];
203
+ }
204
+ /**
205
+ * Monaco adapter over {@link useSecretScanner}: adds gutter markers and a
206
+ * "Move to Secrets Manager" quick fix on top of the headless scanner.
207
+ *
208
+ * The Monaco pieces are optional — until `monaco` and `editor` are both
209
+ * provided, this behaves exactly like `useSecretScanner`, so a host can mount it
210
+ * before its editor is ready.
211
+ */
212
+ declare function useMonacoSecretScanner(params: UseMonacoSecretScannerParams): SecretScanner;
213
+
214
+ type IgnorableFinding = Pick<SecretFinding, 'type' | 'secret'>;
215
+ /**
216
+ * Remembers which detected secrets the user chose to ignore, persisted in
217
+ * localStorage under `storageKey` (namespace it per document). Tracked by a
218
+ * content-derived signature, never the plaintext.
219
+ */
220
+ declare function useIgnoredSecrets(storageKey?: string): {
221
+ isIgnored: (finding: IgnorableFinding) => boolean;
222
+ ignore: (finding: IgnorableFinding) => void;
223
+ };
224
+
225
+ interface SecretFindingSummary {
226
+ id: string;
227
+ label: string;
228
+ confidence: SecretConfidence;
229
+ secret: string;
230
+ line?: number;
231
+ }
232
+ interface SecretFindingsPanelProps<T extends SecretFindingSummary> {
233
+ findings: T[];
234
+ onMove?: (finding: T) => void;
235
+ onIgnore?: (finding: T) => void;
236
+ hidden?: boolean;
237
+ showLine?: boolean;
238
+ description?: NonNullable<React.ReactNode>;
239
+ moveLabel?: React.ReactNode;
240
+ ignoreLabel?: React.ReactNode;
241
+ }
242
+ interface SecretScannerPanelProps extends Omit<SecretFindingsPanelProps<SecretFinding>, 'findings' | 'onMove' | 'onIgnore'> {
243
+ scanner: SecretScanner;
244
+ readOnly?: boolean;
245
+ }
246
+ /**
247
+ * Presentational: takes findings and renders them. Accepts any finding shape
248
+ * carrying the fields in `SecretFindingSummary`, so a host can pass its own.
249
+ * For a panel driven by `useSecretScanner`, use `SecretScannerPanel`.
250
+ */
251
+ declare function SecretFindingsPanel<T extends SecretFindingSummary>({ findings, onMove, onIgnore, hidden, showLine, description, moveLabel, ignoreLabel, }: SecretFindingsPanelProps<T>): React.JSX.Element | null;
252
+ /**
253
+ * "Move to secret" calls `scanner.migration.request(finding)`, which sets
254
+ * `scanner.migration.finding`; render your own create-secret modal off that, and
255
+ * call `scanner.migration.apply` once the secret exists.
256
+ */
257
+ declare function SecretScannerPanel({ scanner, readOnly, ...rest }: SecretScannerPanelProps): React.JSX.Element;
258
+
259
+ interface SecretReferenceModalProps {
260
+ reference: SecretReference | null;
261
+ onDismiss: () => void;
262
+ snippet?: string;
263
+ title?: string;
264
+ description?: NonNullable<React.ReactNode>;
265
+ }
266
+ /**
267
+ * Shown after a secret is created for a finding that couldn't be rewritten in
268
+ * place. Purely presentational — render it off `scanner.reference.pending`.
269
+ */
270
+ declare function SecretReferenceModal({ reference, onDismiss, snippet, title, description, }: SecretReferenceModalProps): React.JSX.Element | null;
271
+
272
+ export { DEFAULT_DEBOUNCE_MS, SECRET_MARKER_CODE, SecretFindingsPanel, SecretReferenceModal, SecretScannerPanel, applySecretReference, buildSecretReference, createCodeScanner, createTextScanner, getFindingSignature, installSecretScanner, k6SecretRewriter, maskSecret, memoizeLatest, offsetToPosition, scanCode, scanText, shannonEntropy, suggestSecretName, useIgnoredSecrets, useMonacoSecretScanner, useSecretScanner };
273
+ export type { ApplyResult, DetectionResult, IStandaloneCodeEditor, InstallSecretScannerOptions, MonacoNamespace, SecretConfidence, SecretFinding, SecretFindingSummary, SecretMigration, SecretRange, SecretReference, SecretReferenceFallback, SecretRewrite, SecretRewriter, SecretScanner, SecretScannerInstallation, UseMonacoSecretScannerParams, UseSecretScannerParams };
@@ -0,0 +1,15 @@
1
+ export { createCodeScanner, scanCode } from './secret-scanner/core/scanCode.js';
2
+ export { createTextScanner, scanText } from './secret-scanner/core/scanText.js';
3
+ export { memoizeLatest } from './secret-scanner/core/memoizeLatest.js';
4
+ export { DEFAULT_DEBOUNCE_MS } from './secret-scanner/core/constants.js';
5
+ export { applySecretReference, buildSecretReference, k6SecretRewriter } from './secret-scanner/core/k6Rewriter.js';
6
+ export { getFindingSignature, maskSecret, suggestSecretName } from './secret-scanner/core/secretScanner.utils.js';
7
+ export { SECRET_MARKER_CODE, installSecretScanner } from './secret-scanner/monaco/installSecretScanner.js';
8
+ export { useSecretScanner } from './secret-scanner/react/useSecretScanner.js';
9
+ export { useMonacoSecretScanner } from './secret-scanner/react/useMonacoSecretScanner.js';
10
+ export { useIgnoredSecrets } from './secret-scanner/react/useIgnoredSecrets.js';
11
+ export { SecretFindingsPanel, SecretScannerPanel } from './secret-scanner/panel/SecretScannerPanel.js';
12
+ export { SecretReferenceModal } from './secret-scanner/panel/SecretReferenceModal.js';
13
+ export { offsetToPosition } from './secret-scanner/core/detection/position.js';
14
+ export { shannonEntropy } from './secret-scanner/core/detection/entropy.js';
15
+ //# sourceMappingURL=secret-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-scanner.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/plugin-ui",
3
- "version": "0.17.3",
3
+ "version": "0.17.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+ssh://git@github.com/grafana/plugin-ui.git"
@@ -15,6 +15,9 @@
15
15
  "*": {
16
16
  "test": [
17
17
  "dist/cjs/test-utils.d.cts"
18
+ ],
19
+ "secret-scanner": [
20
+ "dist/cjs/secret-scanner.d.cts"
18
21
  ]
19
22
  }
20
23
  },
@@ -39,6 +42,16 @@
39
42
  "types": "./dist/cjs/test-utils.d.cts",
40
43
  "default": "./dist/cjs/test-utils.cjs"
41
44
  }
45
+ },
46
+ "./secret-scanner": {
47
+ "import": {
48
+ "types": "./dist/esm/secret-scanner.d.ts",
49
+ "default": "./dist/esm/secret-scanner.js"
50
+ },
51
+ "require": {
52
+ "types": "./dist/cjs/secret-scanner.d.cts",
53
+ "default": "./dist/cjs/secret-scanner.cjs"
54
+ }
42
55
  }
43
56
  },
44
57
  "sideEffects": false,
@@ -46,6 +59,7 @@
46
59
  "build": "tsc -p ./tsconfig.build.json && rollup -c rollup.config.ts --configPlugin esbuild",
47
60
  "dev": "tsc -p ./tsconfig.build.json && rollup -c rollup.config.ts --configPlugin esbuild -w",
48
61
  "clean": "rm -rf ./dist ./compiled ./storybook-static",
62
+ "gen:secret-rules": "node ./scripts/generate-secret-rules.mjs",
49
63
  "test": "jest --watch",
50
64
  "test:ci": "jest --ci",
51
65
  "spellcheck": "cspell -c cspell.config.json \"**/*.{ts,tsx,js,md,mdx,yml,yaml,json,scss,css}\"",
@@ -63,6 +77,9 @@
63
77
  "@hello-pangea/dnd": "17.0.0",
64
78
  "@marcbachmann/cel-js": "7.6.1",
65
79
  "@react-awesome-query-builder/ui": "6.6.15",
80
+ "acorn": "8.17.0",
81
+ "acorn-loose": "8.5.2",
82
+ "acorn-typescript": "1.4.13",
66
83
  "lodash": "4.18.1",
67
84
  "prismjs": "1.30.0",
68
85
  "react-calendar": "4.8.0",
@@ -120,6 +137,7 @@
120
137
  "jest-fetch-mock": "3.2.0",
121
138
  "lefthook": "2.1.10",
122
139
  "mockdate": "3.0.5",
140
+ "monaco-editor": "0.34.1",
123
141
  "prettier": "3.9.5",
124
142
  "publint": "0.3.21",
125
143
  "react": "18.3.1",
@@ -130,6 +148,7 @@
130
148
  "rollup-plugin-esbuild": "6.2.1",
131
149
  "rollup-plugin-node-externals": "9.0.1",
132
150
  "rxjs": "7.8.2",
151
+ "smol-toml": "1.7.0",
133
152
  "storybook": "10.5.0",
134
153
  "ts-node": "10.9.2",
135
154
  "typescript": "5.9.3"
@@ -142,15 +161,30 @@
142
161
  "@testing-library/jest-dom": "^6.9.1",
143
162
  "@testing-library/react": "^16.3.2",
144
163
  "@testing-library/user-event": "^14.6.1",
164
+ "monaco-editor": ">=0.30",
145
165
  "react": "^18.0.0 || ^19.0.0",
146
166
  "react-dom": "^18.0.0 || ^19.0.0"
147
167
  },
168
+ "peerDependenciesMeta": {
169
+ "monaco-editor": {
170
+ "optional": true
171
+ }
172
+ },
148
173
  "files": [
149
- "dist"
174
+ "dist",
175
+ "NOTICE"
150
176
  ],
151
177
  "engines": {
152
178
  "node": ">=24",
153
179
  "yarn": ">=4.16.0"
154
180
  },
155
- "packageManager": "yarn@4.17.1"
181
+ "packageManager": "yarn@4.17.1",
182
+ "resolutions": {
183
+ "undici": "8.9.0",
184
+ "js-yaml@^3.13.1": "3.15.1",
185
+ "js-yaml@^4.1.0": "4.3.1",
186
+ "fast-uri": "3.1.5",
187
+ "brace-expansion@^1.1.7": "1.1.18",
188
+ "brace-expansion@^5.0.5": "5.0.9"
189
+ }
156
190
  }