@grafana/sign-plugin 3.1.0-canary.698.89df8be.0 → 3.1.0
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/CHANGELOG.md +85 -0
- package/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/bin/run.js +23 -8
- package/dist/chunk-2Y3K42NH.js +41 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-5G4NZZCD.js +0 -0
- package/dist/chunk-CCIR4QK3.js +140 -0
- package/dist/chunk-H643NG2Y.js +17 -0
- package/dist/chunk-JZ2A43R6.js +24 -0
- package/dist/chunk-KUNFRRHT.js +21 -0
- package/dist/chunk-MBEAHLAV.js +75 -0
- package/dist/chunk-RWF366QA.js +115 -0
- package/dist/chunk-W6EFWLCZ.js +47 -0
- package/dist/commands/index.js +18 -2
- package/dist/commands/sign.command.js +12 -34
- package/dist/commands/version.command.js +8 -9
- package/dist/utils/getCreatePluginVersion.js +7 -0
- package/dist/utils/manifest.js +14 -85
- package/dist/utils/pluginValidation.js +10 -37
- package/dist/utils/request.js +7 -36
- package/dist/utils/utils.output.js +8 -0
- package/dist/utils/utils.version.js +7 -0
- package/package.json +11 -17
- package/src/commands/sign.command.ts +33 -10
- package/src/commands/version.command.ts +2 -2
- package/src/utils/getCreatePluginVersion.ts +18 -0
- package/src/utils/manifest.ts +36 -16
- package/src/utils/utils.output.ts +4 -0
- package/src/utils/utils.version.ts +3 -0
- package/dist/utils/getVersion.js +0 -13
- package/dist/utils/pluginValidation.test.js +0 -13
- package/src/utils/getVersion.ts +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,88 @@
|
|
|
1
|
+
# v3.1.0 (Thu Mar 13 2025)
|
|
2
|
+
|
|
3
|
+
#### 🚀 Enhancement
|
|
4
|
+
|
|
5
|
+
- Feature: Consistent CLI output [#1597](https://github.com/grafana/plugin-tools/pull/1597) ([@jackw](https://github.com/jackw))
|
|
6
|
+
|
|
7
|
+
#### Authors: 1
|
|
8
|
+
|
|
9
|
+
- Jack Westbrook ([@jackw](https://github.com/jackw))
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# v3.0.8 (Thu Jan 09 2025)
|
|
14
|
+
|
|
15
|
+
#### 🐛 Bug Fix
|
|
16
|
+
|
|
17
|
+
- Sign Plugin: Remove console.log on failed version check [#1444](https://github.com/grafana/plugin-tools/pull/1444) ([@jackw](https://github.com/jackw))
|
|
18
|
+
|
|
19
|
+
#### Authors: 1
|
|
20
|
+
|
|
21
|
+
- Jack Westbrook ([@jackw](https://github.com/jackw))
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# v3.0.5 (Wed Dec 11 2024)
|
|
26
|
+
|
|
27
|
+
#### 🐛 Bug Fix
|
|
28
|
+
|
|
29
|
+
- fix(deps): update dependency proxy-agent to v6.5.0 [#1387](https://github.com/grafana/plugin-tools/pull/1387) ([@renovate[bot]](https://github.com/renovate[bot]))
|
|
30
|
+
|
|
31
|
+
#### Authors: 1
|
|
32
|
+
|
|
33
|
+
- [@renovate[bot]](https://github.com/renovate[bot])
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# v3.0.4 (Wed Sep 25 2024)
|
|
38
|
+
|
|
39
|
+
#### 🐛 Bug Fix
|
|
40
|
+
|
|
41
|
+
- Feat: Adding provenance publish config [#1127](https://github.com/grafana/plugin-tools/pull/1127) ([@tolzhabayev](https://github.com/tolzhabayev))
|
|
42
|
+
|
|
43
|
+
#### Authors: 1
|
|
44
|
+
|
|
45
|
+
- Timur Olzhabayev ([@tolzhabayev](https://github.com/tolzhabayev))
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
# v3.0.3 (Tue Jul 09 2024)
|
|
50
|
+
|
|
51
|
+
#### 🐛 Bug Fix
|
|
52
|
+
|
|
53
|
+
- Adjust license text [#994](https://github.com/grafana/plugin-tools/pull/994) ([@academo](https://github.com/academo))
|
|
54
|
+
|
|
55
|
+
#### Authors: 1
|
|
56
|
+
|
|
57
|
+
- Esteban Beltran ([@academo](https://github.com/academo))
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
# v3.0.2 (Tue May 14 2024)
|
|
62
|
+
|
|
63
|
+
#### 🐛 Bug Fix
|
|
64
|
+
|
|
65
|
+
- Chore(deps): Bump proxy-agent from 6.3.1 to 6.4.0 [#792](https://github.com/grafana/plugin-tools/pull/792) ([@dependabot[bot]](https://github.com/dependabot[bot]))
|
|
66
|
+
|
|
67
|
+
#### Authors: 1
|
|
68
|
+
|
|
69
|
+
- [@dependabot[bot]](https://github.com/dependabot[bot])
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
# v3.0.1 (Thu Jan 25 2024)
|
|
74
|
+
|
|
75
|
+
#### 🐛 Bug Fix
|
|
76
|
+
|
|
77
|
+
- Build: Migrate plugin-e2e to Vitest and use tsconfigs/base configs [#694](https://github.com/grafana/plugin-tools/pull/694) ([@jackw](https://github.com/jackw) [@sunker](https://github.com/sunker))
|
|
78
|
+
|
|
79
|
+
#### Authors: 2
|
|
80
|
+
|
|
81
|
+
- Erik Sundell ([@sunker](https://github.com/sunker))
|
|
82
|
+
- Jack Westbrook ([@jackw](https://github.com/jackw))
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
1
86
|
# v3.0.0 (Tue Jan 16 2024)
|
|
2
87
|
|
|
3
88
|
#### 💥 Breaking Change
|
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2024 Grafana Labs
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
package/dist/bin/run.js
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
import "../chunk-5G4NZZCD.js";
|
|
3
|
+
import {
|
|
4
|
+
sign
|
|
5
|
+
} from "../chunk-MBEAHLAV.js";
|
|
6
|
+
import {
|
|
7
|
+
version
|
|
8
|
+
} from "../chunk-H643NG2Y.js";
|
|
9
|
+
import "../chunk-KUNFRRHT.js";
|
|
10
|
+
import "../chunk-RWF366QA.js";
|
|
11
|
+
import "../chunk-CCIR4QK3.js";
|
|
12
|
+
import "../chunk-JZ2A43R6.js";
|
|
13
|
+
import "../chunk-W6EFWLCZ.js";
|
|
14
|
+
import "../chunk-2Y3K42NH.js";
|
|
15
|
+
import "../chunk-3RG5ZIWI.js";
|
|
16
|
+
|
|
17
|
+
// src/bin/run.ts
|
|
18
|
+
import minimist from "minimist";
|
|
19
|
+
var args = process.argv.slice(2);
|
|
20
|
+
var argv = minimist(args);
|
|
21
|
+
var commands = {
|
|
22
|
+
sign,
|
|
23
|
+
version
|
|
9
24
|
};
|
|
10
|
-
|
|
25
|
+
var command = commands[argv._[0]] || commands.sign;
|
|
11
26
|
command(argv);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/utils/request.ts
|
|
2
|
+
import https from "node:https";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { ProxyAgent } from "proxy-agent";
|
|
5
|
+
var agent = new ProxyAgent();
|
|
6
|
+
async function postData(urlString, data, headers) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const url = new URL(urlString);
|
|
9
|
+
const postData2 = JSON.stringify(data);
|
|
10
|
+
const options = {
|
|
11
|
+
hostname: url.hostname,
|
|
12
|
+
port: url.port || 443,
|
|
13
|
+
path: url.pathname,
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: {
|
|
16
|
+
...headers,
|
|
17
|
+
"Content-Type": "application/json"
|
|
18
|
+
},
|
|
19
|
+
agent
|
|
20
|
+
};
|
|
21
|
+
const req = https.request(options, (res) => {
|
|
22
|
+
const chunks = [];
|
|
23
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
24
|
+
res.on("end", () => {
|
|
25
|
+
const results = Buffer.concat(chunks);
|
|
26
|
+
resolve({
|
|
27
|
+
data: results.toString(),
|
|
28
|
+
status: res.statusCode ?? 200
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
res.on("error", reject);
|
|
32
|
+
});
|
|
33
|
+
req.on("error", reject);
|
|
34
|
+
req.write(postData2);
|
|
35
|
+
req.end();
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
postData
|
|
41
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
__require
|
|
10
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CURRENT_APP_VERSION
|
|
3
|
+
} from "./chunk-JZ2A43R6.js";
|
|
4
|
+
|
|
5
|
+
// ../../libs/output/src/index.mts
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { EOL } from "os";
|
|
8
|
+
function isCI() {
|
|
9
|
+
return process.env.CI && process.env.CI !== "false" || // Drone CI plus others
|
|
10
|
+
process.env.GITHUB_ACTIONS === "true";
|
|
11
|
+
}
|
|
12
|
+
if (isCI()) {
|
|
13
|
+
chalk.level = 0;
|
|
14
|
+
}
|
|
15
|
+
var Output = class {
|
|
16
|
+
appName;
|
|
17
|
+
appVersion;
|
|
18
|
+
constructor(name, version) {
|
|
19
|
+
this.appName = name;
|
|
20
|
+
this.appVersion = version;
|
|
21
|
+
}
|
|
22
|
+
write(str) {
|
|
23
|
+
process.stdout.write(str);
|
|
24
|
+
}
|
|
25
|
+
get separator() {
|
|
26
|
+
let separator = "";
|
|
27
|
+
for (let i = 0; i < process.stdout.columns - 1; i++) {
|
|
28
|
+
separator += "\u2014";
|
|
29
|
+
}
|
|
30
|
+
return separator;
|
|
31
|
+
}
|
|
32
|
+
addHorizontalLine(color) {
|
|
33
|
+
const separator = chalk.dim[color](this.separator);
|
|
34
|
+
this.write(`${separator}${EOL}`);
|
|
35
|
+
}
|
|
36
|
+
addNewLine() {
|
|
37
|
+
this.write(EOL);
|
|
38
|
+
}
|
|
39
|
+
writeTitle(color, title, withPrefix = true) {
|
|
40
|
+
if (withPrefix) {
|
|
41
|
+
this.write(`${this.addPrefix(color, title)}${EOL}`);
|
|
42
|
+
} else {
|
|
43
|
+
this.write(`${title}${EOL}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
getStatusIcon(taskStatus) {
|
|
47
|
+
switch (taskStatus) {
|
|
48
|
+
case "success":
|
|
49
|
+
return chalk.green("\u2713");
|
|
50
|
+
case "failure":
|
|
51
|
+
return chalk.red("\u2A2F");
|
|
52
|
+
case "skipped":
|
|
53
|
+
return chalk.yellow("\u2212");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
addPrefix(color, text) {
|
|
57
|
+
const namePrefix = chalk.reset.inverse.bold[color](` ${this.appName} `);
|
|
58
|
+
if (!this.appVersion) {
|
|
59
|
+
return `${namePrefix} ${text}`;
|
|
60
|
+
}
|
|
61
|
+
const nameAndVersionPrefix = chalk.reset.inverse.bold[color](` ${this.appName}@${this.appVersion} `);
|
|
62
|
+
return `${nameAndVersionPrefix} ${text}`;
|
|
63
|
+
}
|
|
64
|
+
writeBody(body) {
|
|
65
|
+
if (!body) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.addNewLine();
|
|
69
|
+
body.forEach((line) => {
|
|
70
|
+
this.write(`${line}${EOL}`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
error({
|
|
74
|
+
title,
|
|
75
|
+
body,
|
|
76
|
+
link,
|
|
77
|
+
withPrefix = true
|
|
78
|
+
}) {
|
|
79
|
+
this.addNewLine();
|
|
80
|
+
this.writeTitle("red", chalk.red.bold(title), withPrefix);
|
|
81
|
+
this.writeBody(body);
|
|
82
|
+
if (link) {
|
|
83
|
+
this.addNewLine();
|
|
84
|
+
this.write(`${chalk.gray("Learn more about this error: ")}
|
|
85
|
+
${chalk.cyan(link)}`);
|
|
86
|
+
}
|
|
87
|
+
this.addNewLine();
|
|
88
|
+
}
|
|
89
|
+
warning({
|
|
90
|
+
title,
|
|
91
|
+
body,
|
|
92
|
+
link,
|
|
93
|
+
withPrefix = true
|
|
94
|
+
}) {
|
|
95
|
+
this.addNewLine();
|
|
96
|
+
this.writeTitle("yellow", chalk.yellow.bold(title), withPrefix);
|
|
97
|
+
this.writeBody(body);
|
|
98
|
+
if (link) {
|
|
99
|
+
this.addNewLine();
|
|
100
|
+
this.write(`${chalk.gray("Learn more about this warning: ")}
|
|
101
|
+
${this.formatUrl(link)}`);
|
|
102
|
+
}
|
|
103
|
+
this.addNewLine();
|
|
104
|
+
}
|
|
105
|
+
success({ title, body, withPrefix = true }) {
|
|
106
|
+
this.addNewLine();
|
|
107
|
+
this.writeTitle("green", chalk.green.bold(title), withPrefix);
|
|
108
|
+
this.writeBody(body);
|
|
109
|
+
this.addNewLine();
|
|
110
|
+
}
|
|
111
|
+
log({ title, body, withPrefix = true }) {
|
|
112
|
+
this.addNewLine();
|
|
113
|
+
this.writeTitle("cyan", chalk.cyan.bold(title), withPrefix);
|
|
114
|
+
this.writeBody(body);
|
|
115
|
+
this.addNewLine();
|
|
116
|
+
}
|
|
117
|
+
bulletList(list) {
|
|
118
|
+
return list.map((item) => {
|
|
119
|
+
return ` \u2022 ${item}`;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
formatCode(code) {
|
|
123
|
+
return chalk.italic.cyan(code);
|
|
124
|
+
}
|
|
125
|
+
formatUrl(url) {
|
|
126
|
+
return chalk.reset.blue.underline(url);
|
|
127
|
+
}
|
|
128
|
+
statusList(status, list) {
|
|
129
|
+
return list.map((item) => {
|
|
130
|
+
return ` ${this.getStatusIcon(status)} ${item}`;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/utils/utils.output.ts
|
|
136
|
+
var output = new Output("sign-plugin", CURRENT_APP_VERSION);
|
|
137
|
+
|
|
138
|
+
export {
|
|
139
|
+
output
|
|
140
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
output
|
|
3
|
+
} from "./chunk-CCIR4QK3.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/version.command.ts
|
|
6
|
+
var version = async () => {
|
|
7
|
+
try {
|
|
8
|
+
output.log({ title: "" });
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error(error);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
version
|
|
17
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// ../../libs/version/src/index.mts
|
|
2
|
+
import { findUpSync } from "find-up";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
var __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
6
|
+
function getVersion() {
|
|
7
|
+
const packageJsonPath = findUpSync("package.json", { cwd: __dirname });
|
|
8
|
+
if (!packageJsonPath) {
|
|
9
|
+
throw `Could not find package.json`;
|
|
10
|
+
}
|
|
11
|
+
const pkg = readFileSync(packageJsonPath, "utf8");
|
|
12
|
+
const { version } = JSON.parse(pkg);
|
|
13
|
+
if (!version) {
|
|
14
|
+
throw `Could not find the version of create-plugin`;
|
|
15
|
+
}
|
|
16
|
+
return version;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/utils/utils.version.ts
|
|
20
|
+
var CURRENT_APP_VERSION = getVersion();
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
CURRENT_APP_VERSION
|
|
24
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/utils/getCreatePluginVersion.ts
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
var getCreatePluginVersion = () => {
|
|
5
|
+
try {
|
|
6
|
+
const currDir = process.cwd();
|
|
7
|
+
const crpcJSONPath = resolve(currDir, ".config", ".cprc.json");
|
|
8
|
+
if (!existsSync(crpcJSONPath)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const crpcJSON = readFileSync(crpcJSONPath, "utf-8");
|
|
12
|
+
const { version } = JSON.parse(crpcJSON);
|
|
13
|
+
return version;
|
|
14
|
+
} catch (err) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
getCreatePluginVersion
|
|
21
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCreatePluginVersion
|
|
3
|
+
} from "./chunk-KUNFRRHT.js";
|
|
4
|
+
import {
|
|
5
|
+
buildManifest,
|
|
6
|
+
saveManifest,
|
|
7
|
+
signManifest
|
|
8
|
+
} from "./chunk-RWF366QA.js";
|
|
9
|
+
import {
|
|
10
|
+
output
|
|
11
|
+
} from "./chunk-CCIR4QK3.js";
|
|
12
|
+
import {
|
|
13
|
+
CURRENT_APP_VERSION
|
|
14
|
+
} from "./chunk-JZ2A43R6.js";
|
|
15
|
+
import {
|
|
16
|
+
assertRootUrlIsValid
|
|
17
|
+
} from "./chunk-W6EFWLCZ.js";
|
|
18
|
+
|
|
19
|
+
// src/commands/sign.command.ts
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
var sign = async (argv) => {
|
|
24
|
+
const distDir = argv.distDir ?? "dist";
|
|
25
|
+
const pluginDistDir = path.resolve(distDir);
|
|
26
|
+
const signatureType = argv.signatureType;
|
|
27
|
+
const rootUrls = argv.rootUrls?.split(",") ?? [];
|
|
28
|
+
if (!existsSync(pluginDistDir)) {
|
|
29
|
+
output.error({
|
|
30
|
+
title: "Plugin directory not found.",
|
|
31
|
+
body: [
|
|
32
|
+
`Directory ${chalk.bold(pluginDistDir)} not found.`,
|
|
33
|
+
"Make sure to build the plugin before attempting to sign it."
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
output.log({
|
|
40
|
+
title: "Signing plugin.",
|
|
41
|
+
body: [`Plugin found in ${pluginDistDir}`]
|
|
42
|
+
});
|
|
43
|
+
const manifest = await buildManifest(pluginDistDir);
|
|
44
|
+
if (signatureType) {
|
|
45
|
+
manifest.signatureType = signatureType;
|
|
46
|
+
}
|
|
47
|
+
if (rootUrls && rootUrls.length > 0) {
|
|
48
|
+
rootUrls.forEach(assertRootUrlIsValid);
|
|
49
|
+
manifest.rootUrls = rootUrls;
|
|
50
|
+
}
|
|
51
|
+
manifest.signPlugin = { version: CURRENT_APP_VERSION };
|
|
52
|
+
const createPluginVersion = getCreatePluginVersion();
|
|
53
|
+
if (createPluginVersion) {
|
|
54
|
+
manifest.createPlugin = { version: createPluginVersion };
|
|
55
|
+
}
|
|
56
|
+
const signedManifest = await signManifest(manifest);
|
|
57
|
+
saveManifest(pluginDistDir, signedManifest);
|
|
58
|
+
output.success({
|
|
59
|
+
title: `Plugin signed successsfully.`,
|
|
60
|
+
body: [`Signed manifest saved to ${pluginDistDir}.`]
|
|
61
|
+
});
|
|
62
|
+
} catch (err) {
|
|
63
|
+
if (err instanceof Error) {
|
|
64
|
+
output.error({
|
|
65
|
+
title: "Failed to sign plugin.",
|
|
66
|
+
body: [err.message]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
sign
|
|
75
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
output
|
|
3
|
+
} from "./chunk-CCIR4QK3.js";
|
|
4
|
+
import {
|
|
5
|
+
postData
|
|
6
|
+
} from "./chunk-2Y3K42NH.js";
|
|
7
|
+
|
|
8
|
+
// src/utils/manifest.ts
|
|
9
|
+
import crypto from "crypto";
|
|
10
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
import fs from "node:fs/promises";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
var MANIFEST_FILE = "MANIFEST.txt";
|
|
15
|
+
async function* walk(dir, baseDir) {
|
|
16
|
+
for await (const d of await fs.opendir(dir)) {
|
|
17
|
+
const entry = path.join(dir, d.name);
|
|
18
|
+
if (d.isDirectory()) {
|
|
19
|
+
yield* await walk(entry, baseDir);
|
|
20
|
+
} else if (d.isFile()) {
|
|
21
|
+
yield path.relative(baseDir, entry);
|
|
22
|
+
} else if (d.isSymbolicLink()) {
|
|
23
|
+
const realPath = await fs.realpath(entry);
|
|
24
|
+
if (!realPath.startsWith(baseDir)) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`symbolic link ${path.relative(baseDir, entry)} targets a file outside of the base directory: ${baseDir}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const stats = await fs.stat(realPath);
|
|
30
|
+
if (stats.isFile()) {
|
|
31
|
+
yield path.relative(baseDir, entry);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function buildManifest(dir) {
|
|
37
|
+
const pluginJson = JSON.parse(readFileSync(path.join(dir, "plugin.json"), { encoding: "utf8" }));
|
|
38
|
+
const manifest = {
|
|
39
|
+
plugin: pluginJson.id,
|
|
40
|
+
version: pluginJson.info.version,
|
|
41
|
+
files: {}
|
|
42
|
+
};
|
|
43
|
+
for await (const filePath of await walk(dir, dir)) {
|
|
44
|
+
if (filePath === MANIFEST_FILE) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const sanitisedFilePath = filePath.split(path.sep).join(path.posix.sep);
|
|
48
|
+
manifest.files[sanitisedFilePath] = crypto.createHash("sha256").update(readFileSync(path.join(dir, filePath))).digest("hex");
|
|
49
|
+
}
|
|
50
|
+
return manifest;
|
|
51
|
+
}
|
|
52
|
+
async function signManifest(manifest) {
|
|
53
|
+
const GRAFANA_API_KEY = process.env.GRAFANA_API_KEY;
|
|
54
|
+
const GRAFANA_ACCESS_POLICY_TOKEN = process.env.GRAFANA_ACCESS_POLICY_TOKEN;
|
|
55
|
+
if (!GRAFANA_ACCESS_POLICY_TOKEN && !GRAFANA_API_KEY) {
|
|
56
|
+
output.error({
|
|
57
|
+
title: "Missing GRAFANA_ACCESS_POLICY_TOKEN.",
|
|
58
|
+
body: ["You must create a GRAFANA_ACCESS_POLICY_TOKEN env variable to sign plugins."],
|
|
59
|
+
link: "https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin#generate-an-access-policy-token"
|
|
60
|
+
});
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
if (GRAFANA_API_KEY) {
|
|
64
|
+
output.warning({
|
|
65
|
+
title: "Usage of GRAFANA_API_KEY is deprecated.",
|
|
66
|
+
body: ["Please migrate to using a GRAFANA_ACCESS_POLICY_TOKEN instead."],
|
|
67
|
+
link: "https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin"
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const GRAFANA_COM_URL = process.env.GRAFANA_COM_URL || "https://grafana.com/api";
|
|
71
|
+
const url = GRAFANA_COM_URL + "/plugins/ci/sign";
|
|
72
|
+
const token = GRAFANA_ACCESS_POLICY_TOKEN ? GRAFANA_ACCESS_POLICY_TOKEN : GRAFANA_API_KEY;
|
|
73
|
+
try {
|
|
74
|
+
const info = await postData(url, manifest, {
|
|
75
|
+
Authorization: "Bearer " + token
|
|
76
|
+
});
|
|
77
|
+
if (info.status !== 200) {
|
|
78
|
+
const dataAsArray = Object.entries(JSON.parse(info.data)).map(([key, value]) => `${key}: ${value}`);
|
|
79
|
+
output.error({
|
|
80
|
+
title: "Error signing manifest.",
|
|
81
|
+
body: [
|
|
82
|
+
`Server responded with status code ${chalk.yellow(info.status)} along with:`,
|
|
83
|
+
...output.bulletList(dataAsArray)
|
|
84
|
+
]
|
|
85
|
+
});
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
return info.data;
|
|
89
|
+
} catch (err) {
|
|
90
|
+
const body = err.response?.data?.message ? [err.response.data.message] : [err.message];
|
|
91
|
+
output.error({
|
|
92
|
+
title: "Error signing manifest.",
|
|
93
|
+
body
|
|
94
|
+
});
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function saveManifest(dir, signedManifest) {
|
|
99
|
+
try {
|
|
100
|
+
writeFileSync(path.join(dir, MANIFEST_FILE), signedManifest);
|
|
101
|
+
return true;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
output.error({
|
|
104
|
+
title: "Error saving manifest",
|
|
105
|
+
body: [`Failed to write signed manifest to ${dir}.`]
|
|
106
|
+
});
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
buildManifest,
|
|
113
|
+
signManifest,
|
|
114
|
+
saveManifest
|
|
115
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./chunk-3RG5ZIWI.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/pluginValidation.ts
|
|
6
|
+
var validatePluginJson = (pluginJson) => {
|
|
7
|
+
if (!pluginJson.id) {
|
|
8
|
+
throw new Error("Plugin id is missing in plugin.json");
|
|
9
|
+
}
|
|
10
|
+
if (!pluginJson.info) {
|
|
11
|
+
throw new Error("Plugin info node is missing in plugin.json");
|
|
12
|
+
}
|
|
13
|
+
if (!pluginJson.info.version) {
|
|
14
|
+
throw new Error("Plugin info.version is missing in plugin.json");
|
|
15
|
+
}
|
|
16
|
+
const types = ["panel", "datasource", "app"];
|
|
17
|
+
const type = pluginJson.type;
|
|
18
|
+
if (!types.includes(type)) {
|
|
19
|
+
throw new Error("Invalid plugin type in plugin.json: " + type);
|
|
20
|
+
}
|
|
21
|
+
if (!pluginJson.id.endsWith("-" + type)) {
|
|
22
|
+
throw new Error("[plugin.json] id should end with: -" + type);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var getPluginJson = (path) => {
|
|
26
|
+
let pluginJson;
|
|
27
|
+
try {
|
|
28
|
+
pluginJson = __require(path);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
throw new Error("Unable to find: " + path);
|
|
31
|
+
}
|
|
32
|
+
validatePluginJson(pluginJson);
|
|
33
|
+
return pluginJson;
|
|
34
|
+
};
|
|
35
|
+
var assertRootUrlIsValid = (rootUrl) => {
|
|
36
|
+
try {
|
|
37
|
+
new URL(rootUrl);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
throw new Error(`${rootUrl} is not a valid URL`);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
validatePluginJson,
|
|
45
|
+
getPluginJson,
|
|
46
|
+
assertRootUrlIsValid
|
|
47
|
+
};
|
package/dist/commands/index.js
CHANGED
|
@@ -1,2 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import "../chunk-5G4NZZCD.js";
|
|
2
|
+
import {
|
|
3
|
+
sign
|
|
4
|
+
} from "../chunk-MBEAHLAV.js";
|
|
5
|
+
import {
|
|
6
|
+
version
|
|
7
|
+
} from "../chunk-H643NG2Y.js";
|
|
8
|
+
import "../chunk-KUNFRRHT.js";
|
|
9
|
+
import "../chunk-RWF366QA.js";
|
|
10
|
+
import "../chunk-CCIR4QK3.js";
|
|
11
|
+
import "../chunk-JZ2A43R6.js";
|
|
12
|
+
import "../chunk-W6EFWLCZ.js";
|
|
13
|
+
import "../chunk-2Y3K42NH.js";
|
|
14
|
+
import "../chunk-3RG5ZIWI.js";
|
|
15
|
+
export {
|
|
16
|
+
sign,
|
|
17
|
+
version
|
|
18
|
+
};
|
|
@@ -1,35 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
try {
|
|
15
|
-
console.log('Building manifest...');
|
|
16
|
-
const manifest = await buildManifest(pluginDistDir);
|
|
17
|
-
console.log('Signing manifest...');
|
|
18
|
-
if (signatureType) {
|
|
19
|
-
manifest.signatureType = signatureType;
|
|
20
|
-
}
|
|
21
|
-
if (rootUrls && rootUrls.length > 0) {
|
|
22
|
-
rootUrls.forEach(assertRootUrlIsValid);
|
|
23
|
-
manifest.rootUrls = rootUrls;
|
|
24
|
-
}
|
|
25
|
-
manifest.signPlugin = { version: getVersion() };
|
|
26
|
-
const signedManifest = await signManifest(manifest);
|
|
27
|
-
console.log('Saving signed manifest...');
|
|
28
|
-
saveManifest(pluginDistDir, signedManifest);
|
|
29
|
-
console.log('Signed successfully');
|
|
30
|
-
}
|
|
31
|
-
catch (err) {
|
|
32
|
-
console.warn(err);
|
|
33
|
-
process.exitCode = 1;
|
|
34
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
sign
|
|
3
|
+
} from "../chunk-MBEAHLAV.js";
|
|
4
|
+
import "../chunk-KUNFRRHT.js";
|
|
5
|
+
import "../chunk-RWF366QA.js";
|
|
6
|
+
import "../chunk-CCIR4QK3.js";
|
|
7
|
+
import "../chunk-JZ2A43R6.js";
|
|
8
|
+
import "../chunk-W6EFWLCZ.js";
|
|
9
|
+
import "../chunk-2Y3K42NH.js";
|
|
10
|
+
import "../chunk-3RG5ZIWI.js";
|
|
11
|
+
export {
|
|
12
|
+
sign
|
|
35
13
|
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
version
|
|
3
|
+
} from "../chunk-H643NG2Y.js";
|
|
4
|
+
import "../chunk-CCIR4QK3.js";
|
|
5
|
+
import "../chunk-JZ2A43R6.js";
|
|
6
|
+
import "../chunk-3RG5ZIWI.js";
|
|
7
|
+
export {
|
|
8
|
+
version
|
|
10
9
|
};
|
package/dist/utils/manifest.js
CHANGED
|
@@ -1,85 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
else if (d.isSymbolicLink()) {
|
|
17
|
-
const realPath = await fs.realpath(entry);
|
|
18
|
-
if (!realPath.startsWith(baseDir)) {
|
|
19
|
-
throw new Error(`symbolic link ${path.relative(baseDir, entry)} targets a file outside of the base directory: ${baseDir}`);
|
|
20
|
-
}
|
|
21
|
-
const stats = await fs.stat(realPath);
|
|
22
|
-
if (stats.isFile()) {
|
|
23
|
-
yield path.relative(baseDir, entry);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
export async function buildManifest(dir) {
|
|
29
|
-
const pluginJson = JSON.parse(readFileSync(path.join(dir, 'plugin.json'), { encoding: 'utf8' }));
|
|
30
|
-
const manifest = {
|
|
31
|
-
plugin: pluginJson.id,
|
|
32
|
-
version: pluginJson.info.version,
|
|
33
|
-
files: {},
|
|
34
|
-
};
|
|
35
|
-
for await (const filePath of await walk(dir, dir)) {
|
|
36
|
-
if (filePath === MANIFEST_FILE) {
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
const sanitisedFilePath = filePath.split(path.sep).join(path.posix.sep);
|
|
40
|
-
manifest.files[sanitisedFilePath] = crypto
|
|
41
|
-
.createHash('sha256')
|
|
42
|
-
.update(readFileSync(path.join(dir, filePath)))
|
|
43
|
-
.digest('hex');
|
|
44
|
-
}
|
|
45
|
-
return manifest;
|
|
46
|
-
}
|
|
47
|
-
export async function signManifest(manifest) {
|
|
48
|
-
const GRAFANA_API_KEY = process.env.GRAFANA_API_KEY;
|
|
49
|
-
const GRAFANA_ACCESS_POLICY_TOKEN = process.env.GRAFANA_ACCESS_POLICY_TOKEN;
|
|
50
|
-
if (!GRAFANA_ACCESS_POLICY_TOKEN && !GRAFANA_API_KEY) {
|
|
51
|
-
throw new Error('You must create a GRAFANA_ACCESS_POLICY_TOKEN env variable to sign plugins. Please see: https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin#generate-an-access-policy-token for instructions.');
|
|
52
|
-
}
|
|
53
|
-
if (GRAFANA_API_KEY) {
|
|
54
|
-
console.warn(`\x1b[33m%s\x1b[0m`, 'The usage of GRAFANA_API_KEY is deprecated, please consider using GRAFANA_ACCESS_POLICY_TOKEN instead. For more info visit https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin');
|
|
55
|
-
}
|
|
56
|
-
const GRAFANA_COM_URL = process.env.GRAFANA_COM_URL || 'https://grafana.com/api';
|
|
57
|
-
const url = GRAFANA_COM_URL + '/plugins/ci/sign';
|
|
58
|
-
const token = GRAFANA_ACCESS_POLICY_TOKEN ? GRAFANA_ACCESS_POLICY_TOKEN : GRAFANA_API_KEY;
|
|
59
|
-
try {
|
|
60
|
-
const info = await postData(url, manifest, {
|
|
61
|
-
Authorization: 'Bearer ' + token,
|
|
62
|
-
});
|
|
63
|
-
if (info.status !== 200) {
|
|
64
|
-
console.error('Error: ', info);
|
|
65
|
-
throw new Error('Error signing manifest');
|
|
66
|
-
}
|
|
67
|
-
return info.data;
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
if (err.response?.data?.message) {
|
|
71
|
-
throw new Error('Error signing manifest: ' + err.response.data.message);
|
|
72
|
-
}
|
|
73
|
-
throw new Error('Error signing manifest: ' + err.message);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
export function saveManifest(dir, signedManifest) {
|
|
77
|
-
try {
|
|
78
|
-
writeFileSync(path.join(dir, MANIFEST_FILE), signedManifest);
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
console.error(error);
|
|
83
|
-
throw new Error('Error saving manifest');
|
|
84
|
-
}
|
|
85
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
buildManifest,
|
|
3
|
+
saveManifest,
|
|
4
|
+
signManifest
|
|
5
|
+
} from "../chunk-RWF366QA.js";
|
|
6
|
+
import "../chunk-CCIR4QK3.js";
|
|
7
|
+
import "../chunk-JZ2A43R6.js";
|
|
8
|
+
import "../chunk-2Y3K42NH.js";
|
|
9
|
+
import "../chunk-3RG5ZIWI.js";
|
|
10
|
+
export {
|
|
11
|
+
buildManifest,
|
|
12
|
+
saveManifest,
|
|
13
|
+
signManifest
|
|
14
|
+
};
|
|
@@ -1,38 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const types = ['panel', 'datasource', 'app'];
|
|
12
|
-
const type = pluginJson.type;
|
|
13
|
-
if (!types.includes(type)) {
|
|
14
|
-
throw new Error('Invalid plugin type in plugin.json: ' + type);
|
|
15
|
-
}
|
|
16
|
-
if (!pluginJson.id.endsWith('-' + type)) {
|
|
17
|
-
throw new Error('[plugin.json] id should end with: -' + type);
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
export const getPluginJson = (path) => {
|
|
21
|
-
let pluginJson;
|
|
22
|
-
try {
|
|
23
|
-
pluginJson = require(path);
|
|
24
|
-
}
|
|
25
|
-
catch (e) {
|
|
26
|
-
throw new Error('Unable to find: ' + path);
|
|
27
|
-
}
|
|
28
|
-
validatePluginJson(pluginJson);
|
|
29
|
-
return pluginJson;
|
|
30
|
-
};
|
|
31
|
-
export const assertRootUrlIsValid = (rootUrl) => {
|
|
32
|
-
try {
|
|
33
|
-
new URL(rootUrl);
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
throw new Error(`${rootUrl} is not a valid URL`);
|
|
37
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
assertRootUrlIsValid,
|
|
3
|
+
getPluginJson,
|
|
4
|
+
validatePluginJson
|
|
5
|
+
} from "../chunk-W6EFWLCZ.js";
|
|
6
|
+
import "../chunk-3RG5ZIWI.js";
|
|
7
|
+
export {
|
|
8
|
+
assertRootUrlIsValid,
|
|
9
|
+
getPluginJson,
|
|
10
|
+
validatePluginJson
|
|
38
11
|
};
|
package/dist/utils/request.js
CHANGED
|
@@ -1,36 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const postData = JSON.stringify(data);
|
|
9
|
-
const options = {
|
|
10
|
-
hostname: url.hostname,
|
|
11
|
-
port: url.port || 443,
|
|
12
|
-
path: url.pathname,
|
|
13
|
-
method: 'POST',
|
|
14
|
-
headers: {
|
|
15
|
-
...headers,
|
|
16
|
-
'Content-Type': 'application/json',
|
|
17
|
-
},
|
|
18
|
-
agent,
|
|
19
|
-
};
|
|
20
|
-
const req = https.request(options, (res) => {
|
|
21
|
-
const chunks = [];
|
|
22
|
-
res.on('data', (chunk) => chunks.push(chunk));
|
|
23
|
-
res.on('end', () => {
|
|
24
|
-
const results = Buffer.concat(chunks);
|
|
25
|
-
resolve({
|
|
26
|
-
data: results.toString(),
|
|
27
|
-
status: res.statusCode ?? 200,
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
res.on('error', reject);
|
|
31
|
-
});
|
|
32
|
-
req.on('error', reject);
|
|
33
|
-
req.write(postData);
|
|
34
|
-
req.end();
|
|
35
|
-
});
|
|
36
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
postData
|
|
3
|
+
} from "../chunk-2Y3K42NH.js";
|
|
4
|
+
import "../chunk-3RG5ZIWI.js";
|
|
5
|
+
export {
|
|
6
|
+
postData
|
|
7
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/sign-plugin",
|
|
3
|
-
"version": "3.1.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"directory": "packages/sign-plugin",
|
|
6
6
|
"url": "https://github.com/grafana/plugin-tools"
|
|
@@ -17,35 +17,29 @@
|
|
|
17
17
|
},
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"registry": "https://registry.npmjs.org/",
|
|
20
|
-
"access": "public"
|
|
20
|
+
"access": "public",
|
|
21
|
+
"provenance": true
|
|
21
22
|
},
|
|
22
23
|
"scripts": {
|
|
23
24
|
"clean": "rm -rf ./dist",
|
|
24
|
-
"build": "
|
|
25
|
-
"dev": "
|
|
26
|
-
"lint": "eslint --cache
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch ./src --watch '../../libs'",
|
|
27
|
+
"lint": "eslint --cache ./src",
|
|
27
28
|
"lint:fix": "npm run lint -- --fix",
|
|
28
29
|
"test": "vitest",
|
|
29
30
|
"typecheck": "tsc --noEmit"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
33
|
+
"chalk": "^5.3.0",
|
|
34
|
+
"find-up": "^7.0.0",
|
|
32
35
|
"minimist": "^1.2.2",
|
|
33
|
-
"proxy-agent": "6.
|
|
36
|
+
"proxy-agent": "6.5.0"
|
|
34
37
|
},
|
|
35
38
|
"devDependencies": {
|
|
36
|
-
"@types/minimist": "^1.2.
|
|
37
|
-
},
|
|
38
|
-
"nodemonConfig": {
|
|
39
|
-
"watch": [
|
|
40
|
-
"src/**/*"
|
|
41
|
-
],
|
|
42
|
-
"ext": "*",
|
|
43
|
-
"events": {
|
|
44
|
-
"start": "cls || clear"
|
|
45
|
-
}
|
|
39
|
+
"@types/minimist": "^1.2.5"
|
|
46
40
|
},
|
|
47
41
|
"engines": {
|
|
48
42
|
"node": ">=20"
|
|
49
43
|
},
|
|
50
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "b622bcaa222af1bf67aa602eb2accecad44f1afc"
|
|
51
45
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
1
2
|
import minimist from 'minimist';
|
|
2
3
|
import { existsSync } from 'node:fs';
|
|
3
4
|
import path from 'node:path';
|
|
4
|
-
import {
|
|
5
|
+
import { CURRENT_APP_VERSION } from '../utils/utils.version.js';
|
|
5
6
|
import { buildManifest, saveManifest, signManifest } from '../utils/manifest.js';
|
|
6
7
|
import { assertRootUrlIsValid } from '../utils/pluginValidation.js';
|
|
8
|
+
import { getCreatePluginVersion } from '../utils/getCreatePluginVersion.js';
|
|
9
|
+
import { output } from '../utils/utils.output.js';
|
|
7
10
|
|
|
8
11
|
export const sign = async (argv: minimist.ParsedArgs) => {
|
|
9
12
|
const distDir = argv.distDir ?? 'dist';
|
|
@@ -12,14 +15,23 @@ export const sign = async (argv: minimist.ParsedArgs) => {
|
|
|
12
15
|
const rootUrls: string[] = argv.rootUrls?.split(',') ?? [];
|
|
13
16
|
|
|
14
17
|
if (!existsSync(pluginDistDir)) {
|
|
15
|
-
|
|
18
|
+
output.error({
|
|
19
|
+
title: 'Plugin directory not found.',
|
|
20
|
+
body: [
|
|
21
|
+
`Directory ${chalk.bold(pluginDistDir)} not found.`,
|
|
22
|
+
'Make sure to build the plugin before attempting to sign it.',
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
process.exit(1);
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
try {
|
|
19
|
-
|
|
29
|
+
output.log({
|
|
30
|
+
title: 'Signing plugin.',
|
|
31
|
+
body: [`Plugin found in ${pluginDistDir}`],
|
|
32
|
+
});
|
|
20
33
|
const manifest = await buildManifest(pluginDistDir);
|
|
21
34
|
|
|
22
|
-
console.log('Signing manifest...');
|
|
23
35
|
if (signatureType) {
|
|
24
36
|
manifest.signatureType = signatureType;
|
|
25
37
|
}
|
|
@@ -28,15 +40,26 @@ export const sign = async (argv: minimist.ParsedArgs) => {
|
|
|
28
40
|
manifest.rootUrls = rootUrls;
|
|
29
41
|
}
|
|
30
42
|
|
|
31
|
-
manifest.signPlugin = { version:
|
|
43
|
+
manifest.signPlugin = { version: CURRENT_APP_VERSION };
|
|
44
|
+
const createPluginVersion = getCreatePluginVersion();
|
|
45
|
+
if (createPluginVersion) {
|
|
46
|
+
manifest.createPlugin = { version: createPluginVersion };
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
const signedManifest = await signManifest(manifest);
|
|
33
50
|
|
|
34
|
-
console.log('Saving signed manifest...');
|
|
35
51
|
saveManifest(pluginDistDir, signedManifest);
|
|
36
|
-
|
|
37
|
-
|
|
52
|
+
output.success({
|
|
53
|
+
title: `Plugin signed successsfully.`,
|
|
54
|
+
body: [`Signed manifest saved to ${pluginDistDir}.`],
|
|
55
|
+
});
|
|
38
56
|
} catch (err) {
|
|
39
|
-
|
|
40
|
-
|
|
57
|
+
if (err instanceof Error) {
|
|
58
|
+
output.error({
|
|
59
|
+
title: 'Failed to sign plugin.',
|
|
60
|
+
body: [err.message],
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
process.exit(1);
|
|
41
64
|
}
|
|
42
65
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { output } from '../utils/utils.output.js';
|
|
2
2
|
|
|
3
3
|
export const version = async () => {
|
|
4
4
|
try {
|
|
5
|
-
|
|
5
|
+
output.log({ title: '' });
|
|
6
6
|
} catch (error) {
|
|
7
7
|
console.error(error);
|
|
8
8
|
process.exit(1);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const getCreatePluginVersion = () => {
|
|
5
|
+
try {
|
|
6
|
+
const currDir = process.cwd();
|
|
7
|
+
const crpcJSONPath = resolve(currDir, '.config', '.cprc.json');
|
|
8
|
+
if (!existsSync(crpcJSONPath)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const crpcJSON = readFileSync(crpcJSONPath, 'utf-8');
|
|
13
|
+
const { version } = JSON.parse(crpcJSON);
|
|
14
|
+
return version as string;
|
|
15
|
+
} catch (err) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
};
|
package/src/utils/manifest.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { readFileSync, writeFileSync } from 'node:fs';
|
|
|
3
3
|
import fs from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { postData } from './request.js';
|
|
6
|
+
import { output } from './utils.output.js';
|
|
7
|
+
import chalk from 'chalk';
|
|
6
8
|
|
|
7
9
|
const MANIFEST_FILE = 'MANIFEST.txt';
|
|
8
10
|
|
|
@@ -19,6 +21,9 @@ export interface ManifestInfo {
|
|
|
19
21
|
signPlugin?: {
|
|
20
22
|
version: string;
|
|
21
23
|
};
|
|
24
|
+
createPlugin?: {
|
|
25
|
+
version: string;
|
|
26
|
+
};
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
type RecursiveWalk = AsyncGenerator<string, void | RecursiveWalk>;
|
|
@@ -79,15 +84,19 @@ export async function signManifest(manifest: ManifestInfo): Promise<string> {
|
|
|
79
84
|
const GRAFANA_ACCESS_POLICY_TOKEN = process.env.GRAFANA_ACCESS_POLICY_TOKEN;
|
|
80
85
|
|
|
81
86
|
if (!GRAFANA_ACCESS_POLICY_TOKEN && !GRAFANA_API_KEY) {
|
|
82
|
-
|
|
83
|
-
'
|
|
84
|
-
|
|
87
|
+
output.error({
|
|
88
|
+
title: 'Missing GRAFANA_ACCESS_POLICY_TOKEN.',
|
|
89
|
+
body: ['You must create a GRAFANA_ACCESS_POLICY_TOKEN env variable to sign plugins.'],
|
|
90
|
+
link: 'https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin#generate-an-access-policy-token',
|
|
91
|
+
});
|
|
92
|
+
process.exit(1);
|
|
85
93
|
}
|
|
86
94
|
if (GRAFANA_API_KEY) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
'
|
|
90
|
-
|
|
95
|
+
output.warning({
|
|
96
|
+
title: 'Usage of GRAFANA_API_KEY is deprecated.',
|
|
97
|
+
body: ['Please migrate to using a GRAFANA_ACCESS_POLICY_TOKEN instead.'],
|
|
98
|
+
link: 'https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin',
|
|
99
|
+
});
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
const GRAFANA_COM_URL = process.env.GRAFANA_COM_URL || 'https://grafana.com/api';
|
|
@@ -99,17 +108,25 @@ export async function signManifest(manifest: ManifestInfo): Promise<string> {
|
|
|
99
108
|
Authorization: 'Bearer ' + token,
|
|
100
109
|
});
|
|
101
110
|
if (info.status !== 200) {
|
|
102
|
-
|
|
103
|
-
|
|
111
|
+
const dataAsArray = Object.entries(JSON.parse(info.data)).map(([key, value]) => `${key}: ${value}`);
|
|
112
|
+
output.error({
|
|
113
|
+
title: 'Error signing manifest.',
|
|
114
|
+
body: [
|
|
115
|
+
`Server responded with status code ${chalk.yellow(info.status)} along with:`,
|
|
116
|
+
...output.bulletList(dataAsArray),
|
|
117
|
+
],
|
|
118
|
+
});
|
|
119
|
+
process.exit(1);
|
|
104
120
|
}
|
|
105
121
|
|
|
106
122
|
return info.data;
|
|
107
123
|
} catch (err: any) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
const body = err.response?.data?.message ? [err.response.data.message] : [err.message];
|
|
125
|
+
output.error({
|
|
126
|
+
title: 'Error signing manifest.',
|
|
127
|
+
body,
|
|
128
|
+
});
|
|
129
|
+
process.exit(1);
|
|
113
130
|
}
|
|
114
131
|
}
|
|
115
132
|
|
|
@@ -118,7 +135,10 @@ export function saveManifest(dir: string, signedManifest: string) {
|
|
|
118
135
|
writeFileSync(path.join(dir, MANIFEST_FILE), signedManifest);
|
|
119
136
|
return true;
|
|
120
137
|
} catch (error) {
|
|
121
|
-
|
|
122
|
-
|
|
138
|
+
output.error({
|
|
139
|
+
title: 'Error saving manifest',
|
|
140
|
+
body: [`Failed to write signed manifest to ${dir}.`],
|
|
141
|
+
});
|
|
142
|
+
process.exit(1);
|
|
123
143
|
}
|
|
124
144
|
}
|
package/dist/utils/getVersion.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
5
|
-
export const getVersion = () => {
|
|
6
|
-
const packageJsonPath = resolve(__dirname, '..', '..', 'package.json');
|
|
7
|
-
const pkg = readFileSync(packageJsonPath, 'utf8');
|
|
8
|
-
const { version } = JSON.parse(pkg);
|
|
9
|
-
if (!version) {
|
|
10
|
-
throw `Could not find the version of sign-plugin`;
|
|
11
|
-
}
|
|
12
|
-
return version;
|
|
13
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { getPluginJson, validatePluginJson } from './pluginValidation.js';
|
|
2
|
-
describe('pluginValidation', () => {
|
|
3
|
-
describe('plugin.json', () => {
|
|
4
|
-
test('missing plugin.json file', () => {
|
|
5
|
-
expect(() => getPluginJson(`${__dirname}/mocks/missing-plugin.json`)).toThrowError();
|
|
6
|
-
});
|
|
7
|
-
});
|
|
8
|
-
describe('validatePluginJson', () => {
|
|
9
|
-
test('missing "id" field in the plugin.json file', () => {
|
|
10
|
-
expect(() => validatePluginJson({})).toThrow('Plugin id is missing in plugin.json');
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
});
|
package/src/utils/getVersion.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
6
|
-
|
|
7
|
-
export const getVersion = () => {
|
|
8
|
-
const packageJsonPath = resolve(__dirname, '..', '..', 'package.json');
|
|
9
|
-
const pkg = readFileSync(packageJsonPath, 'utf8');
|
|
10
|
-
const { version } = JSON.parse(pkg);
|
|
11
|
-
if (!version) {
|
|
12
|
-
throw `Could not find the version of sign-plugin`;
|
|
13
|
-
}
|
|
14
|
-
return version;
|
|
15
|
-
};
|