suitescript-verify 0.1.0 → 0.2.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/README.md +1 -1
- package/dist/cli.js +2 -0
- package/dist/config.js +23 -2
- package/dist/doctor.js +1 -0
- package/dist/sdf.js +6 -3
- package/package.json +1 -1
- package/templates/sdf/manifest.xml +1 -1
- package/templates/sdf/runner.xml +1 -1
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ define(["N/record"], (record) => ({
|
|
|
33
33
|
}));
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
Every command that reaches the sandbox refuses an account that is not a sandbox (`digits_SBn`). The runner uses the script id `customscript_suitescript_verify_runner` and is limited to a role with the ID `customrole_suitescript_verify`, which you create in the sandbox.
|
|
36
|
+
Every command that reaches the sandbox refuses an account that is not a sandbox (`digits_SBn`). The runner uses the script id `customscript_suitescript_verify_runner` and is limited to a role with the ID `customrole_suitescript_verify`, which you create in the sandbox. A project that names its own role sets `SUITESCRIPT_VERIFY_ROLE_ID` (for example `SUITESCRIPT_VERIFY_ROLE_ID=customrole_my_runner`); the generated SDF project uses it in the manifest and the runner. Like every `SUITESCRIPT_VERIFY_` setting it layers from the committed `verification/.env`, the gitignored `.env.local` and the process environment. The value must match `^customrole_[a-z0-9_]+$`; a bad value stops every command that reaches the sandbox, and the error names the key, never the value. `doctor` reports the id in use.
|
|
37
37
|
|
|
38
38
|
See [docs/verification/README.md](docs/verification/README.md) and [docs/verification/lessons.md](docs/verification/lessons.md).
|
|
39
39
|
|
package/dist/cli.js
CHANGED
|
@@ -64,6 +64,7 @@ async function deploy(args) {
|
|
|
64
64
|
const { files, slugs } = buildSdfProject(config.sdfDir, config.probesDir, {
|
|
65
65
|
deployed: true,
|
|
66
66
|
extraTags: config.extraTags,
|
|
67
|
+
roleId: config.roleId,
|
|
67
68
|
});
|
|
68
69
|
console.log(`Probes in the runner: ${slugs.join(", ") || "(none)"}`);
|
|
69
70
|
console.log(`Files to upload: ${files.join(", ")}`);
|
|
@@ -92,6 +93,7 @@ async function cleanup(args) {
|
|
|
92
93
|
buildSdfProject(config.sdfDir, config.probesDir, {
|
|
93
94
|
deployed: false,
|
|
94
95
|
extraTags: config.extraTags,
|
|
96
|
+
roleId: config.roleId,
|
|
95
97
|
});
|
|
96
98
|
return suitecloud(project, config, [
|
|
97
99
|
"project:deploy",
|
package/dist/config.js
CHANGED
|
@@ -10,6 +10,10 @@ export const layoutKeys = [
|
|
|
10
10
|
];
|
|
11
11
|
/** The committed `.env` may also register extra probe tags: a comma-separated list of tag names, not a path. */
|
|
12
12
|
export const extraTagsKey = "SUITESCRIPT_VERIFY_EXTRA_TAGS";
|
|
13
|
+
/** The committed `.env` may also name the runner role: a NetSuite custom role id. */
|
|
14
|
+
export const roleIdKey = "SUITESCRIPT_VERIFY_ROLE_ID";
|
|
15
|
+
export const defaultRoleId = "customrole_suitescript_verify";
|
|
16
|
+
const roleIdPattern = /^customrole_[a-z0-9_]+$/;
|
|
13
17
|
const tagName = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
14
18
|
/** The tag names in a registration value, without the `@`; blank entries are dropped. */
|
|
15
19
|
export const parseTagList = (value) => value
|
|
@@ -49,11 +53,19 @@ const insideProject = (project, path) => {
|
|
|
49
53
|
const looksSecret = (value) => /-----BEGIN /.test(value) ||
|
|
50
54
|
/^eyJ[\w-]+\.[\w-]+\.[\w-]+$/.test(value) ||
|
|
51
55
|
/^[A-Za-z0-9+_=-]{32,}$/.test(value);
|
|
56
|
+
const roleIdProblem = (file) => ({
|
|
57
|
+
message: `${roleIdKey} in ${file} is not a NetSuite custom role id like customrole_suitescript_verify (lowercase letters, digits and underscores after customrole_).`,
|
|
58
|
+
});
|
|
52
59
|
/** Checks the committed `.env` against the allowlist. Messages name the key, never the value. */
|
|
53
60
|
function checkCommitted(project, committed, file) {
|
|
54
61
|
const problems = [];
|
|
55
62
|
for (const [key, value] of committed) {
|
|
56
|
-
if (key ===
|
|
63
|
+
if (key === roleIdKey) {
|
|
64
|
+
// The pattern is the whole check: a valid id may be long enough to look like a token.
|
|
65
|
+
if (!roleIdPattern.test(value))
|
|
66
|
+
problems.push(roleIdProblem(file));
|
|
67
|
+
}
|
|
68
|
+
else if (key === extraTagsKey) {
|
|
57
69
|
if (!parseTagList(value).every((name) => tagName.test(name))) {
|
|
58
70
|
problems.push({
|
|
59
71
|
message: `${key} in ${file} is not a comma-separated list of tag names like flavor,other.`,
|
|
@@ -67,7 +79,7 @@ function checkCommitted(project, committed, file) {
|
|
|
67
79
|
}
|
|
68
80
|
else if (!layoutKeys.includes(key)) {
|
|
69
81
|
problems.push({
|
|
70
|
-
message: `${key} in ${file} is not a layout key. The committed file holds layout only (${[...layoutKeys, extraTagsKey].join(", ")}); put anything else in .env.local or the process environment.`,
|
|
82
|
+
message: `${key} in ${file} is not a layout key. The committed file holds layout only (${[...layoutKeys, extraTagsKey, roleIdKey].join(", ")}); put anything else in .env.local or the process environment.`,
|
|
71
83
|
});
|
|
72
84
|
}
|
|
73
85
|
else if (!insideProject(project, value)) {
|
|
@@ -125,6 +137,13 @@ export function loadConfig(project, dir, processEnv = process.env) {
|
|
|
125
137
|
}
|
|
126
138
|
}
|
|
127
139
|
const path = (key, fallback) => resolve(project, values[key] || fallback);
|
|
140
|
+
const roleId = values[roleIdKey] || defaultRoleId;
|
|
141
|
+
// The committed file reports its own bad value; this covers .env.local and the environment.
|
|
142
|
+
const committedRole = committed.get(roleIdKey);
|
|
143
|
+
const roleProblems = roleIdPattern.test(roleId) ||
|
|
144
|
+
(committedRole !== undefined && !roleIdPattern.test(committedRole))
|
|
145
|
+
? []
|
|
146
|
+
: [roleIdProblem(".env.local or the environment")];
|
|
128
147
|
const shown = relative(project, envFile).replaceAll("\\", "/");
|
|
129
148
|
return {
|
|
130
149
|
extraTags: parseTagList(values[extraTagsKey] ?? ""),
|
|
@@ -132,8 +151,10 @@ export function loadConfig(project, dir, processEnv = process.env) {
|
|
|
132
151
|
problems: [
|
|
133
152
|
...checkCommitted(project, committed, shown),
|
|
134
153
|
...checkLocalIgnored(project, localFile),
|
|
154
|
+
...roleProblems,
|
|
135
155
|
],
|
|
136
156
|
resultsDir: path("SUITESCRIPT_VERIFY_RESULTS_DIR", "docs/verification/results"),
|
|
157
|
+
roleId,
|
|
137
158
|
root,
|
|
138
159
|
sdfDir: path("SUITESCRIPT_VERIFY_SDF_DIR", join(root, "sdf")),
|
|
139
160
|
values,
|
package/dist/doctor.js
CHANGED
|
@@ -80,6 +80,7 @@ export function runChecks(project, config, env = process.env) {
|
|
|
80
80
|
add("Project files: the probe, results and SDF folders exist and the SDF project has a default auth id", absent.length === 0 && authId !== "", absent.length > 0 ? "agent" : "maintainer", absent.length > 0
|
|
81
81
|
? "Run suitescript-verify init to create the missing folders."
|
|
82
82
|
: "Run account:setup:ci from the SDF folder once the steps above pass, so project.json gets a default auth id.");
|
|
83
|
+
add(`Runner role id: ${config.roleId}`, true, "agent", "");
|
|
83
84
|
return checks;
|
|
84
85
|
}
|
|
85
86
|
export function formatChecks(checks) {
|
package/dist/sdf.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { defaultRoleId } from "./config.js";
|
|
3
4
|
import { fileCabinetFolder } from "./netsuite.js";
|
|
4
5
|
import { isRestlet, listProbes, read, tagProblems, } from "./probes.js";
|
|
5
6
|
import { UsageError } from "./shared.js";
|
|
@@ -24,7 +25,7 @@ export function generateRunner(probes, source) {
|
|
|
24
25
|
* the SDF folder. Only RESTlet probes go in: the runner is a RESTlet. With
|
|
25
26
|
* `deployed: false` the runner's deployment is switched off (cleanup).
|
|
26
27
|
*/
|
|
27
|
-
export function buildSdfProject(sdfDir, probesDir, { deployed, extraTags = [], }) {
|
|
28
|
+
export function buildSdfProject(sdfDir, probesDir, { deployed, extraTags = [], roleId = defaultRoleId, }) {
|
|
28
29
|
const probes = listProbes(probesDir, extraTags).filter(isRestlet);
|
|
29
30
|
const bad = probes.filter((probe) => tagProblems(probe).length > 0);
|
|
30
31
|
if (bad.length > 0) {
|
|
@@ -39,9 +40,11 @@ export function buildSdfProject(sdfDir, probesDir, { deployed, extraTags = [], }
|
|
|
39
40
|
mkdirSync(join(src, "Objects"), { recursive: true });
|
|
40
41
|
writeFileSync(join(sdfDir, "package.json"), template("sdf/package.json"));
|
|
41
42
|
writeFileSync(join(sdfDir, "suitecloud.config.js"), template("sdf/suitecloud.config.js"));
|
|
42
|
-
writeFileSync(join(src, "manifest.xml"), template("sdf/manifest.xml"));
|
|
43
|
+
writeFileSync(join(src, "manifest.xml"), template("sdf/manifest.xml").replaceAll("%%ROLE_ID%%", roleId));
|
|
43
44
|
writeFileSync(join(src, "deploy.xml"), template("sdf/deploy.xml"));
|
|
44
|
-
writeFileSync(join(src, "Objects", "customscript_suitescript_verify_runner.xml"), template("sdf/runner.xml")
|
|
45
|
+
writeFileSync(join(src, "Objects", "customscript_suitescript_verify_runner.xml"), template("sdf/runner.xml")
|
|
46
|
+
.replace("%%DEPLOYED%%", deployed ? "T" : "F")
|
|
47
|
+
.replaceAll("%%ROLE_ID%%", roleId));
|
|
45
48
|
const slugs = probes.map((probe) => probe.slug);
|
|
46
49
|
const files = ["runner.js"];
|
|
47
50
|
writeFileSync(join(folder, "runner.js"), generateRunner(probes, template("runner.template.js")));
|
package/package.json
CHANGED
package/templates/sdf/runner.xml
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<scriptdeployments>
|
|
8
8
|
<scriptdeployment scriptid="customdeploy_suitescript_verify_runner">
|
|
9
9
|
<allroles>F</allroles>
|
|
10
|
-
<audslctrole>[
|
|
10
|
+
<audslctrole>[%%ROLE_ID%%]</audslctrole>
|
|
11
11
|
<isdeployed>%%DEPLOYED%%</isdeployed>
|
|
12
12
|
<loglevel>DEBUG</loglevel>
|
|
13
13
|
<status>RELEASED</status>
|