@grafana/plugin-ui 0.17.2 → 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.
- package/NOTICE +18 -0
- package/dist/cjs/index.cjs +3 -3
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/secret-scanner.cjs +3032 -0
- package/dist/cjs/secret-scanner.cjs.map +1 -0
- package/dist/cjs/secret-scanner.d.cts +273 -0
- package/dist/esm/node_modules/js-yaml/dist/js-yaml.js +3 -3
- package/dist/esm/node_modules/js-yaml/dist/js-yaml.js.map +1 -1
- package/dist/esm/secret-scanner/core/constants.js +4 -0
- package/dist/esm/secret-scanner/core/constants.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/embedded.js +80 -0
- package/dist/esm/secret-scanner/core/detection/embedded.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/entropy.js +19 -0
- package/dist/esm/secret-scanner/core/detection/entropy.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/highEntropy.js +24 -0
- package/dist/esm/secret-scanner/core/detection/highEntropy.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/literals.js +135 -0
- package/dist/esm/secret-scanner/core/detection/literals.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/nameDetector.js +48 -0
- package/dist/esm/secret-scanner/core/detection/nameDetector.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/placeholders.js +10 -0
- package/dist/esm/secret-scanner/core/detection/placeholders.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/position.js +39 -0
- package/dist/esm/secret-scanner/core/detection/position.js.map +1 -0
- package/dist/esm/secret-scanner/core/detection/ruleDetectors.js +59 -0
- package/dist/esm/secret-scanner/core/detection/ruleDetectors.js.map +1 -0
- package/dist/esm/secret-scanner/core/k6Rewriter.js +44 -0
- package/dist/esm/secret-scanner/core/k6Rewriter.js.map +1 -0
- package/dist/esm/secret-scanner/core/memoizeLatest.js +18 -0
- package/dist/esm/secret-scanner/core/memoizeLatest.js.map +1 -0
- package/dist/esm/secret-scanner/core/scanCode.js +70 -0
- package/dist/esm/secret-scanner/core/scanCode.js.map +1 -0
- package/dist/esm/secret-scanner/core/scanText.js +51 -0
- package/dist/esm/secret-scanner/core/scanText.js.map +1 -0
- package/dist/esm/secret-scanner/core/secretScanner.utils.js +33 -0
- package/dist/esm/secret-scanner/core/secretScanner.utils.js.map +1 -0
- package/dist/esm/secret-scanner/monaco/installSecretScanner.js +117 -0
- package/dist/esm/secret-scanner/monaco/installSecretScanner.js.map +1 -0
- package/dist/esm/secret-scanner/panel/SecretReferenceModal.js +21 -0
- package/dist/esm/secret-scanner/panel/SecretReferenceModal.js.map +1 -0
- package/dist/esm/secret-scanner/panel/SecretScannerPanel.js +75 -0
- package/dist/esm/secret-scanner/panel/SecretScannerPanel.js.map +1 -0
- package/dist/esm/secret-scanner/react/useIgnoredSecrets.js +25 -0
- package/dist/esm/secret-scanner/react/useIgnoredSecrets.js.map +1 -0
- package/dist/esm/secret-scanner/react/useLocalStorageList.js +38 -0
- package/dist/esm/secret-scanner/react/useLocalStorageList.js.map +1 -0
- package/dist/esm/secret-scanner/react/useMonacoSecretScanner.js +28 -0
- package/dist/esm/secret-scanner/react/useMonacoSecretScanner.js.map +1 -0
- package/dist/esm/secret-scanner/react/useSecretScanner.js +57 -0
- package/dist/esm/secret-scanner/react/useSecretScanner.js.map +1 -0
- package/dist/esm/secret-scanner/rules/rules.generated.js +2083 -0
- package/dist/esm/secret-scanner/rules/rules.generated.js.map +1 -0
- package/dist/esm/secret-scanner.d.ts +273 -0
- package/dist/esm/secret-scanner.js +15 -0
- package/dist/esm/secret-scanner.js.map +1 -0
- package/package.json +41 -7
|
@@ -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 };
|
|
@@ -858,7 +858,7 @@ function requireOmap() {
|
|
|
858
858
|
const _toString = Object.prototype.toString;
|
|
859
859
|
function resolveYamlOmap(data) {
|
|
860
860
|
if (data === null) return true;
|
|
861
|
-
const objectKeys =
|
|
861
|
+
const objectKeys = {};
|
|
862
862
|
const object = data;
|
|
863
863
|
for (let index = 0, length = object.length; index < length; index += 1) {
|
|
864
864
|
const pair = object[index];
|
|
@@ -872,8 +872,8 @@ function requireOmap() {
|
|
|
872
872
|
}
|
|
873
873
|
}
|
|
874
874
|
if (!pairHasKey) return false;
|
|
875
|
-
if (
|
|
876
|
-
|
|
875
|
+
if (_hasOwnProperty.call(objectKeys, pairKey)) return false;
|
|
876
|
+
Object.defineProperty(objectKeys, pairKey, { value: true });
|
|
877
877
|
}
|
|
878
878
|
return true;
|
|
879
879
|
}
|