@synopackageland/cli 0.9.7 → 0.10.1
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 +146 -0
- package/README.md +5 -0
- package/dist/add.js +7 -8
- package/dist/build-spk/dsm-arch.js +1 -1
- package/dist/build-spk/dsm-icons.d.ts +8 -1
- package/dist/build-spk/dsm-icons.js +26 -12
- package/dist/build-spk/dsm-version.d.ts +1 -1
- package/dist/build-spk/dsm-version.js +4 -4
- package/dist/build-spk/gateway.js +2 -2
- package/dist/build-spk/generator.js +1 -1
- package/dist/build-spk/png.js +16 -16
- package/dist/capabilities.js +1 -1
- package/dist/capability-overlays.d.ts +16 -5
- package/dist/capability-overlays.js +30 -16
- package/dist/cli.js +107 -107
- package/dist/compose/analyze.js +23 -23
- package/dist/compose/privilege.js +12 -12
- package/dist/contract/i18n.js +3 -3
- package/dist/contract/icon.js +2 -2
- package/dist/contract/posix-all-shares.js +2 -2
- package/dist/contract/schema-validate.js +3 -3
- package/dist/contract/validate.js +16 -16
- package/dist/contract/web-launch.d.ts +2 -1
- package/dist/contract/web-launch.js +3 -2
- package/dist/deploy/deploy.js +8 -8
- package/dist/deploy/homes-values.js +1 -1
- package/dist/deploy/identity-shared.js +1 -1
- package/dist/deploy/native-install-values.js +1 -1
- package/dist/deploy/param-values.js +4 -4
- package/dist/deploy/plan.d.ts +1 -1
- package/dist/deploy/port-preflight.js +3 -3
- package/dist/deploy/run-as-values.js +2 -2
- package/dist/deploy/share-permission-preflight.js +6 -6
- package/dist/deploy/share-values.js +3 -3
- package/dist/error-registry.js +369 -346
- package/dist/errors.js +1 -1
- package/dist/host/dsm-port-profile.d.ts +1 -1
- package/dist/host/dsm-port-profile.js +1 -1
- package/dist/info.js +11 -11
- package/dist/init.d.ts +2 -0
- package/dist/init.js +85 -38
- package/dist/inspect.js +5 -5
- package/dist/portal/alias.d.ts +1 -1
- package/dist/portal/alias.js +4 -4
- package/dist/runtime/executor-build.js +12 -1
- package/dist/runtime/executor-digests.json +14 -91
- package/dist/runtime/executor-inspect.js +11 -4
- package/dist/runtime/executor-policy.d.ts +9 -2
- package/dist/runtime/executor-policy.js +27 -8
- package/dist/runtime/root-programs.d.ts +47 -0
- package/dist/runtime/root-programs.js +153 -0
- package/dist/runtime/sdk-source.d.ts +5 -4
- package/dist/runtime/sdk-source.js +8 -4
- package/dist/skill.js +14 -14
- package/dist/spk/check-info.js +17 -17
- package/dist/spk/check-metadata.js +18 -18
- package/dist/spk/check-payload.js +10 -10
- package/dist/spk/rules.d.ts +57 -57
- package/dist/spk/rules.js +50 -50
- package/dist/spk/validate-spk.js +5 -5
- package/dist/standalone/api-permissions.js +1 -1
- package/dist/standalone/background.d.ts +3 -1
- package/dist/standalone/background.js +8 -4
- package/dist/standalone/binary.js +7 -7
- package/dist/standalone/bridge-app.d.ts +23 -0
- package/dist/standalone/bridge-app.js +141 -0
- package/dist/standalone/bridge-backend.d.ts +40 -0
- package/dist/standalone/bridge-backend.js +95 -0
- package/dist/standalone/bridge-build.d.ts +21 -0
- package/dist/standalone/bridge-build.js +62 -0
- package/dist/standalone/bridge-json.d.ts +16 -0
- package/dist/standalone/bridge-json.js +59 -0
- package/dist/standalone/bridge-runtime.d.ts +16 -0
- package/dist/standalone/bridge-runtime.js +46 -0
- package/dist/standalone/bridge-rust.d.ts +16 -0
- package/dist/standalone/bridge-rust.js +89 -0
- package/dist/standalone/build.js +18 -14
- package/dist/standalone/daemon.js +6 -6
- package/dist/standalone/dsm-window.d.ts +10 -5
- package/dist/standalone/dsm-window.js +69 -18
- package/dist/standalone/i18n.js +18 -18
- package/dist/standalone/inspect-bridge.d.ts +31 -0
- package/dist/standalone/inspect-bridge.js +111 -0
- package/dist/standalone/inspect-spk.d.ts +1 -1
- package/dist/standalone/inspect-spk.js +77 -69
- package/dist/standalone/lifecycle.js +22 -3
- package/dist/standalone/manifest.d.ts +17 -9
- package/dist/standalone/manifest.js +143 -65
- package/dist/standalone/portal-window.js +14 -7
- package/dist/standalone/request-timeout.d.ts +9 -0
- package/dist/standalone/request-timeout.js +13 -0
- package/dist/standalone/root-ops.d.ts +23 -2
- package/dist/standalone/root-ops.js +118 -13
- package/dist/standalone/sdk-check.js +4 -4
- package/dist/standalone/shared-folder.js +7 -7
- package/dist/standalone/spk.d.ts +2 -0
- package/dist/standalone/spk.js +30 -11
- package/dist/standalone/uninstall-hook.js +22 -4
- package/dist/standalone/uninstall.js +7 -7
- package/dist/standalone/window-size.d.ts +17 -0
- package/dist/standalone/window-size.js +31 -0
- package/dist/types.d.ts +1 -1
- package/dist/validate.js +13 -13
- package/package.json +2 -2
- package/schema/bridge-manifest.v1.schema.json +86 -0
- package/skills/reference/create.md +76 -2
- package/skills/reference/ui-json.md +2 -1
- package/skills/reference/ui-vue.md +9 -3
- package/skills/reference/wrap.md +1 -1
- package/dist/standalone/rust-build.d.ts +0 -35
- package/dist/standalone/rust-build.js +0 -127
|
@@ -56,26 +56,26 @@ async function scanPayload(payloadPath, wanted, findings) {
|
|
|
56
56
|
entries = 0;
|
|
57
57
|
}
|
|
58
58
|
if (entries === 0) {
|
|
59
|
-
findings.add("SPK_PAYLOAD_UNREADABLE", "package.tgz
|
|
59
|
+
findings.add("SPK_PAYLOAD_UNREADABLE", "package.tgz is not a readable tar or tar.gz archive, or is empty.", "package.tgz");
|
|
60
60
|
return undefined;
|
|
61
61
|
}
|
|
62
62
|
return files;
|
|
63
63
|
}
|
|
64
64
|
function checkEntryPath(path, type, linkpath, findings) {
|
|
65
65
|
if (path.startsWith("/") || posix.normalize(path).split("/")[0] === "..") {
|
|
66
|
-
findings.add("SPK_PAYLOAD_PATH_UNSAFE", `${path}
|
|
66
|
+
findings.add("SPK_PAYLOAD_PATH_UNSAFE", `${path} extracts outside the package directory.`, at(path));
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
if (type === "SymbolicLink" && linkpath) {
|
|
70
70
|
if (linkpath.startsWith("/")) {
|
|
71
|
-
findings.add("SPK_PAYLOAD_LINK_ABSOLUTE", `${path}
|
|
71
|
+
findings.add("SPK_PAYLOAD_LINK_ABSOLUTE", `${path} is a symlink to the absolute path ${linkpath}; the target is determined by the NAS, not inside the package.`, at(path));
|
|
72
72
|
}
|
|
73
73
|
else if (posix.normalize(posix.join(posix.dirname(path), linkpath)).split("/")[0] === "..") {
|
|
74
|
-
findings.add("SPK_PAYLOAD_LINK_ESCAPE",
|
|
74
|
+
findings.add("SPK_PAYLOAD_LINK_ESCAPE", `The symlink target ${linkpath} of ${path} escapes the package directory.`, at(path));
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
if (type === "Link" && linkpath && (linkpath.startsWith("/") || posix.normalize(linkpath).split("/")[0] === "..")) {
|
|
78
|
-
findings.add("SPK_PAYLOAD_LINK_ESCAPE",
|
|
78
|
+
findings.add("SPK_PAYLOAD_LINK_ESCAPE", `The hard link target ${linkpath} of ${path} is not inside the package.`, at(path));
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
/** Sections the package defines itself in its `texts/<lang>/strings` files. */
|
|
@@ -101,7 +101,7 @@ function checkUiConfig(file, sections, findings) {
|
|
|
101
101
|
}
|
|
102
102
|
catch { /* reported below */ }
|
|
103
103
|
if (typeof config !== "object" || config === null || Array.isArray(config)) {
|
|
104
|
-
findings.add("SPK_UI_CONFIG_INVALID", `${file.path}
|
|
104
|
+
findings.add("SPK_UI_CONFIG_INVALID", `${file.path} is not a JSON object.`, at(file.path));
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
for (const group of Object.values(config)) {
|
|
@@ -116,7 +116,7 @@ function checkUiConfig(file, sections, findings) {
|
|
|
116
116
|
if (!ref)
|
|
117
117
|
continue;
|
|
118
118
|
const own = ref[1] === "synopkgland" || sections.has(ref[1]);
|
|
119
|
-
findings.add(own ? "SPK_UI_TEXTS_MISSING" : "SPK_UI_TEXTS_UNDECLARED", `${file.path}
|
|
119
|
+
findings.add(own ? "SPK_UI_TEXTS_MISSING" : "SPK_UI_TEXTS_UNDECLARED", `${file.path} has ${id}.${field} "${value}" as a string reference, but the entry does not declare "texts"; ${own ? "DSM shows this key directly" : "unless it is a DSM built-in section, DSM shows this key directly"}.`, at(file.path));
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -132,16 +132,16 @@ function checkElf(files, arch, findings) {
|
|
|
132
132
|
continue;
|
|
133
133
|
const machine = file.head[5] === 2 ? file.head.readUInt16BE(18) : file.head.readUInt16LE(18);
|
|
134
134
|
if (noarch) {
|
|
135
|
-
findings.add("SPK_NOARCH_ELF", `${file.path}
|
|
135
|
+
findings.add("SPK_NOARCH_ELF", `${file.path} is an ELF executable, but INFO arch is noarch; a noarch package may contain only scripts, otherwise it cannot run on NAS models with another CPU.`, at(file.path));
|
|
136
136
|
}
|
|
137
137
|
else if (checkable && !machines.has(machine)) {
|
|
138
|
-
findings.add("SPK_ELF_ARCH_MISMATCH",
|
|
138
|
+
findings.add("SPK_ELF_ARCH_MISMATCH", `The ELF machine of ${file.path} is ${machine}, which does not match the CPU of INFO arch "${arch}".`, at(file.path));
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
export async function checkPayload(payloadPath, info, findings) {
|
|
143
143
|
if (startsWith(payloadPath, XZ_MAGIC)) {
|
|
144
|
-
findings.add("SPK_PAYLOAD_XZ", "package.tgz
|
|
144
|
+
findings.add("SPK_PAYLOAD_XZ", "package.tgz is xz-compressed (the Synology toolkit format); inspect cannot read xz and did not check the payload contents.", "package.tgz");
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
147
|
const dirs = uiDirs(info.dsmuidir);
|
package/dist/spk/rules.d.ts
CHANGED
|
@@ -13,252 +13,252 @@ export interface SpkRule {
|
|
|
13
13
|
export declare const SPK_RULES: {
|
|
14
14
|
readonly SPK_NOT_TAR: {
|
|
15
15
|
readonly severity: "error";
|
|
16
|
-
readonly description: "
|
|
16
|
+
readonly description: "The file is not a readable tar archive; an SPK is an uncompressed tar.";
|
|
17
17
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
18
18
|
};
|
|
19
19
|
readonly SPK_ENTRY_UNSAFE: {
|
|
20
20
|
readonly severity: "error";
|
|
21
|
-
readonly description: "SPK
|
|
21
|
+
readonly description: "A path inside the SPK escapes the archive root (an absolute path or ..), or is a link.";
|
|
22
22
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
23
23
|
};
|
|
24
24
|
readonly SPK_ENTRY_UNKNOWN: {
|
|
25
25
|
readonly severity: "warning";
|
|
26
|
-
readonly description: "SPK
|
|
26
|
+
readonly description: "The SPK top level has a file or directory the guide does not list (file names are case-sensitive).";
|
|
27
27
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
28
28
|
};
|
|
29
29
|
readonly SPK_INFO_MISSING: {
|
|
30
30
|
readonly severity: "error";
|
|
31
|
-
readonly description: "
|
|
31
|
+
readonly description: "INFO is missing.";
|
|
32
32
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
33
33
|
};
|
|
34
34
|
readonly SPK_PAYLOAD_MISSING: {
|
|
35
35
|
readonly severity: "error";
|
|
36
|
-
readonly description: "
|
|
36
|
+
readonly description: "package.tgz is missing.";
|
|
37
37
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
38
38
|
};
|
|
39
39
|
readonly SPK_INFO_FIELD_REQUIRED: {
|
|
40
40
|
readonly severity: "error";
|
|
41
|
-
readonly description: "INFO
|
|
41
|
+
readonly description: "INFO is missing a required field (package, version, os_min_ver, description, arch, maintainer).";
|
|
42
42
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields";
|
|
43
43
|
};
|
|
44
44
|
readonly SPK_INFO_DISPLAYNAME_MISSING: {
|
|
45
45
|
readonly severity: "warning";
|
|
46
|
-
readonly description: "INFO
|
|
46
|
+
readonly description: "INFO has no displayname; Package Center shows the package value instead.";
|
|
47
47
|
readonly source: "DSM 7 Developer Guide: INFO Optional Fields";
|
|
48
48
|
};
|
|
49
49
|
readonly SPK_INFO_LINE_INVALID: {
|
|
50
50
|
readonly severity: "warning";
|
|
51
|
-
readonly description: "INFO
|
|
51
|
+
readonly description: "INFO has a line that is not key=\"value\" (blank lines and # comments excepted).";
|
|
52
52
|
readonly source: "DSM 7 Developer Guide: INFO";
|
|
53
53
|
};
|
|
54
54
|
readonly SPK_INFO_VALUE_UNTERMINATED: {
|
|
55
55
|
readonly severity: "error";
|
|
56
|
-
readonly description: "INFO
|
|
56
|
+
readonly description: "An INFO field value has an unterminated quote.";
|
|
57
57
|
readonly source: "DSM 7 Developer Guide: INFO";
|
|
58
58
|
};
|
|
59
59
|
readonly SPK_INFO_FIELD_DUPLICATE: {
|
|
60
60
|
readonly severity: "warning";
|
|
61
|
-
readonly description: "INFO
|
|
61
|
+
readonly description: "INFO sets the same field twice.";
|
|
62
62
|
readonly source: "DSM 7 Developer Guide: INFO";
|
|
63
63
|
};
|
|
64
64
|
readonly SPK_INFO_PACKAGE_INVALID: {
|
|
65
65
|
readonly severity: "error";
|
|
66
|
-
readonly description: "INFO package
|
|
66
|
+
readonly description: "INFO package contains one of : / > < | =.";
|
|
67
67
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (package)";
|
|
68
68
|
};
|
|
69
69
|
readonly SPK_INFO_VERSION_INVALID: {
|
|
70
70
|
readonly severity: "error";
|
|
71
|
-
readonly description: "INFO version
|
|
71
|
+
readonly description: "INFO version is not numbers separated by . - _, or a segment exceeds 2147483647.";
|
|
72
72
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (version)";
|
|
73
73
|
};
|
|
74
74
|
readonly SPK_INFO_VERSION_NO_BUILD: {
|
|
75
75
|
readonly severity: "warning";
|
|
76
|
-
readonly description: "INFO version
|
|
76
|
+
readonly description: "INFO version has no -<build> number (the guide format is [feature number]-[build number]).";
|
|
77
77
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (version)";
|
|
78
78
|
};
|
|
79
79
|
readonly SPK_INFO_OS_VER_INVALID: {
|
|
80
80
|
readonly severity: "error";
|
|
81
|
-
readonly description: "INFO os_min_ver
|
|
81
|
+
readonly description: "INFO os_min_ver or os_max_ver is not <major>.<minor>-<build> (<major>.<minor>.<micro>-<build> is also accepted).";
|
|
82
82
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (os_min_ver), Optional Fields (os_max_ver)";
|
|
83
83
|
};
|
|
84
84
|
readonly SPK_INFO_OS_MIN_VER_LOW: {
|
|
85
85
|
readonly severity: "warning";
|
|
86
|
-
readonly description: "INFO os_min_ver
|
|
86
|
+
readonly description: "INFO os_min_ver is below 7.0-40000.";
|
|
87
87
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (os_min_ver)";
|
|
88
88
|
};
|
|
89
89
|
readonly SPK_INFO_ARCH_UNKNOWN: {
|
|
90
90
|
readonly severity: "warning";
|
|
91
|
-
readonly description: "INFO arch
|
|
91
|
+
readonly description: "INFO arch or exclude_arch has a value that is in neither Appendix A nor the known DSM 7 platforms.";
|
|
92
92
|
readonly source: "DSM 7 Developer Guide: Appendix A Platform and Arch Value Mapping Table";
|
|
93
93
|
};
|
|
94
94
|
readonly SPK_INFO_ARCH_NOARCH_MIXED: {
|
|
95
95
|
readonly severity: "warning";
|
|
96
|
-
readonly description: "INFO arch
|
|
96
|
+
readonly description: "INFO arch has noarch together with other values.";
|
|
97
97
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (arch)";
|
|
98
98
|
};
|
|
99
99
|
readonly SPK_INFO_BOOLEAN_INVALID: {
|
|
100
100
|
readonly severity: "error";
|
|
101
|
-
readonly description: "INFO
|
|
101
|
+
readonly description: "An INFO yes/no field (for example startable, silent_install) is not \"yes\" or \"no\".";
|
|
102
102
|
readonly source: "DSM 7 Developer Guide: INFO Optional Fields";
|
|
103
103
|
};
|
|
104
104
|
readonly SPK_INFO_LANG_UNKNOWN: {
|
|
105
105
|
readonly severity: "warning";
|
|
106
|
-
readonly description: "displayname_<lang>
|
|
106
|
+
readonly description: "The language code of displayname_<lang> or description_<lang> is not in the guide list (enu, cht, chs, jpn...).";
|
|
107
107
|
readonly source: "DSM 7 Developer Guide: INFO Optional Fields (description_[language])";
|
|
108
108
|
};
|
|
109
109
|
readonly SPK_INFO_FIELD_UNKNOWN: {
|
|
110
110
|
readonly severity: "warning";
|
|
111
|
-
readonly description: "INFO
|
|
111
|
+
readonly description: "An INFO field is not in the guide list; DSM does not use it (misspelled field names also show up here).";
|
|
112
112
|
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields, Optional Fields";
|
|
113
113
|
};
|
|
114
114
|
readonly SPK_INFO_ADMINPORT_INVALID: {
|
|
115
115
|
readonly severity: "error";
|
|
116
|
-
readonly description: "INFO adminport
|
|
116
|
+
readonly description: "INFO adminport is not an integer from 0 to 65536.";
|
|
117
117
|
readonly source: "DSM 7 Developer Guide: INFO Optional Fields (adminport)";
|
|
118
118
|
};
|
|
119
119
|
readonly SPK_INFO_CHECKSUM_MISMATCH: {
|
|
120
120
|
readonly severity: "error";
|
|
121
|
-
readonly description: "INFO checksum
|
|
121
|
+
readonly description: "INFO checksum is not the MD5 of package.tgz.";
|
|
122
122
|
readonly source: "DSM 7 Developer Guide: INFO Optional Fields (checksum)";
|
|
123
123
|
};
|
|
124
124
|
readonly SPK_PAYLOAD_UNREADABLE: {
|
|
125
125
|
readonly severity: "error";
|
|
126
|
-
readonly description: "package.tgz
|
|
126
|
+
readonly description: "package.tgz is not a readable tar or tar.gz archive, or is empty.";
|
|
127
127
|
readonly source: "DSM 7 Developer Guide: Package Structure (package.tgz)";
|
|
128
128
|
};
|
|
129
129
|
readonly SPK_PAYLOAD_XZ: {
|
|
130
130
|
readonly severity: "warning";
|
|
131
|
-
readonly description: "package.tgz
|
|
131
|
+
readonly description: "package.tgz is xz-compressed (the Synology toolkit format); inspect cannot read xz and did not check the payload contents.";
|
|
132
132
|
readonly source: "DSM 7 Developer Guide: Pack Stage";
|
|
133
133
|
};
|
|
134
134
|
readonly SPK_PAYLOAD_PATH_UNSAFE: {
|
|
135
135
|
readonly severity: "error";
|
|
136
|
-
readonly description: "package.tgz
|
|
136
|
+
readonly description: "A package.tgz path is absolute or contains .., so it extracts outside the package directory.";
|
|
137
137
|
readonly source: "DSM 7 Developer Guide: Package Structure (package.tgz)";
|
|
138
138
|
};
|
|
139
139
|
readonly SPK_PAYLOAD_LINK_ESCAPE: {
|
|
140
140
|
readonly severity: "error";
|
|
141
|
-
readonly description: "package.tgz
|
|
141
|
+
readonly description: "A package.tgz symlink or hard link points outside the package directory.";
|
|
142
142
|
readonly source: "DSM 7 Developer Guide: Package Structure (package.tgz)";
|
|
143
143
|
};
|
|
144
144
|
readonly SPK_PAYLOAD_LINK_ABSOLUTE: {
|
|
145
145
|
readonly severity: "warning";
|
|
146
|
-
readonly description: "package.tgz
|
|
146
|
+
readonly description: "A package.tgz symlink points at an absolute path; the target is determined by the NAS, not inside the package.";
|
|
147
147
|
readonly source: "DSM 7 Developer Guide: Package Structure (package.tgz)";
|
|
148
148
|
};
|
|
149
149
|
readonly SPK_UI_CONFIG_INVALID: {
|
|
150
150
|
readonly severity: "error";
|
|
151
|
-
readonly description: "dsmuidir
|
|
151
|
+
readonly description: "The config under dsmuidir is not a JSON object.";
|
|
152
152
|
readonly source: "DSM 7 Developer Guide: Integrate DSM, Application Config";
|
|
153
153
|
};
|
|
154
154
|
readonly SPK_UI_TEXTS_MISSING: {
|
|
155
155
|
readonly severity: "error";
|
|
156
|
-
readonly description: "config
|
|
157
|
-
readonly source: "DSM 7.1.1
|
|
156
|
+
readonly description: "The config title/desc references a package string (for example synopkgland:app_title), but the entry does not declare \"texts\"; DSM shows the key directly.";
|
|
157
|
+
readonly source: "Measured on DSM 7.1.1/7.4 (DSM loads texts/<lang>/strings only for entries that declare texts)";
|
|
158
158
|
};
|
|
159
159
|
readonly SPK_UI_TEXTS_UNDECLARED: {
|
|
160
160
|
readonly severity: "warning";
|
|
161
|
-
readonly description: "config
|
|
162
|
-
readonly source: "DSM 7.1.1
|
|
161
|
+
readonly description: "The config title/desc is a section:key string reference but does not declare \"texts\"; unless it is a DSM built-in section, DSM shows the key directly.";
|
|
162
|
+
readonly source: "Measured on DSM 7.1.1/7.4";
|
|
163
163
|
};
|
|
164
164
|
readonly SPK_NOARCH_ELF: {
|
|
165
165
|
readonly severity: "error";
|
|
166
|
-
readonly description: "INFO arch
|
|
167
|
-
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (arch)
|
|
166
|
+
readonly description: "INFO arch is noarch, but package.tgz contains an ELF executable.";
|
|
167
|
+
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (arch), Pack Stage";
|
|
168
168
|
};
|
|
169
169
|
readonly SPK_ELF_ARCH_MISMATCH: {
|
|
170
170
|
readonly severity: "error";
|
|
171
|
-
readonly description: "package.tgz
|
|
172
|
-
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (arch)
|
|
171
|
+
readonly description: "An ELF executable in package.tgz does not match the CPU of INFO arch.";
|
|
172
|
+
readonly source: "DSM 7 Developer Guide: INFO Necessary Fields (arch), Appendix A";
|
|
173
173
|
};
|
|
174
174
|
readonly SPK_SCRIPT_MISSING: {
|
|
175
175
|
readonly severity: "error";
|
|
176
|
-
readonly description: "
|
|
177
|
-
readonly source: "DSM 7 Developer Guide: Package Structure
|
|
176
|
+
readonly description: "scripts/start-stop-status is missing; DSM uses it to start, stop and query the package status.";
|
|
177
|
+
readonly source: "DSM 7 Developer Guide: Package Structure, scripts";
|
|
178
178
|
};
|
|
179
179
|
readonly SPK_SCRIPT_HOOK_MISSING: {
|
|
180
180
|
readonly severity: "warning";
|
|
181
|
-
readonly description: "
|
|
181
|
+
readonly description: "preinst, postinst, preuninst, postuninst, preupgrade or postupgrade is missing; the guide lists them as required, and DSM's behavior without them is unverified.";
|
|
182
182
|
readonly source: "DSM 7 Developer Guide: scripts";
|
|
183
183
|
};
|
|
184
184
|
readonly SPK_SCRIPT_NOT_EXECUTABLE: {
|
|
185
185
|
readonly severity: "error";
|
|
186
|
-
readonly description: "scripts/
|
|
186
|
+
readonly description: "A scripts/ lifecycle script is not executable.";
|
|
187
187
|
readonly source: "DSM 7 Developer Guide: scripts";
|
|
188
188
|
};
|
|
189
189
|
readonly SPK_SCRIPT_NO_INTERPRETER: {
|
|
190
190
|
readonly severity: "warning";
|
|
191
|
-
readonly description: "
|
|
191
|
+
readonly description: "A lifecycle script starts without #! (for example #!/bin/sh) and is not an ELF.";
|
|
192
192
|
readonly source: "DSM 7 Developer Guide: scripts";
|
|
193
193
|
};
|
|
194
194
|
readonly SPK_PRIVILEGE_MISSING: {
|
|
195
195
|
readonly severity: "error";
|
|
196
|
-
readonly description: "
|
|
197
|
-
readonly source: "DSM 7 Developer Guide: conf
|
|
196
|
+
readonly description: "conf/privilege is missing; DSM 7 requires it.";
|
|
197
|
+
readonly source: "DSM 7 Developer Guide: conf, Privilege Config";
|
|
198
198
|
};
|
|
199
199
|
readonly SPK_PRIVILEGE_INVALID: {
|
|
200
200
|
readonly severity: "error";
|
|
201
|
-
readonly description: "conf/privilege
|
|
201
|
+
readonly description: "conf/privilege is not a JSON object, has no defaults.run-as, or run-as is not package/root.";
|
|
202
202
|
readonly source: "DSM 7 Developer Guide: Privilege Config";
|
|
203
203
|
};
|
|
204
204
|
readonly SPK_PRIVILEGE_ROOT: {
|
|
205
205
|
readonly severity: "warning";
|
|
206
|
-
readonly description: "conf/privilege
|
|
206
|
+
readonly description: "conf/privilege requires running as root (defaults, ctrl-script or executable).";
|
|
207
207
|
readonly source: "DSM 7 Developer Guide: Privilege Config";
|
|
208
208
|
};
|
|
209
209
|
readonly SPK_RESOURCE_INVALID: {
|
|
210
210
|
readonly severity: "error";
|
|
211
|
-
readonly description: "conf/resource
|
|
211
|
+
readonly description: "conf/resource is not a JSON object.";
|
|
212
212
|
readonly source: "DSM 7 Developer Guide: Resource Config";
|
|
213
213
|
};
|
|
214
214
|
readonly SPK_RESOURCE_UNKNOWN: {
|
|
215
215
|
readonly severity: "warning";
|
|
216
|
-
readonly description: "conf/resource
|
|
216
|
+
readonly description: "conf/resource has a resource worker id the guide does not list.";
|
|
217
217
|
readonly source: "DSM 7 Developer Guide: Available Workers";
|
|
218
218
|
};
|
|
219
219
|
readonly SPK_CONF_UNKNOWN: {
|
|
220
220
|
readonly severity: "warning";
|
|
221
|
-
readonly description: "conf/
|
|
222
|
-
readonly source: "DSM 7 Developer Guide: conf
|
|
221
|
+
readonly description: "conf/ has a file DSM does not read (known: privilege, resource, PKG_DEPS, PKG_CONX, systemd/).";
|
|
222
|
+
readonly source: "DSM 7 Developer Guide: conf, Systemd User Unit";
|
|
223
223
|
};
|
|
224
224
|
readonly SPK_ICON_MISSING: {
|
|
225
225
|
readonly severity: "error";
|
|
226
|
-
readonly description: "
|
|
226
|
+
readonly description: "PACKAGE_ICON.PNG or PACKAGE_ICON_256.PNG is missing.";
|
|
227
227
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
228
228
|
};
|
|
229
229
|
readonly SPK_ICON_INVALID: {
|
|
230
230
|
readonly severity: "error";
|
|
231
|
-
readonly description: "PACKAGE_ICON.PNG
|
|
231
|
+
readonly description: "PACKAGE_ICON.PNG or PACKAGE_ICON_256.PNG is not a PNG.";
|
|
232
232
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
233
233
|
};
|
|
234
234
|
readonly SPK_ICON_SIZE: {
|
|
235
235
|
readonly severity: "warning";
|
|
236
|
-
readonly description: "PACKAGE_ICON.PNG
|
|
236
|
+
readonly description: "PACKAGE_ICON.PNG is not 64x64, or PACKAGE_ICON_256.PNG is not 256x256.";
|
|
237
237
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
238
238
|
};
|
|
239
239
|
readonly SPK_LICENSE_TOO_LARGE: {
|
|
240
240
|
readonly severity: "error";
|
|
241
|
-
readonly description: "LICENSE
|
|
241
|
+
readonly description: "LICENSE is 1 MB or larger.";
|
|
242
242
|
readonly source: "DSM 7 Developer Guide: Package Structure";
|
|
243
243
|
};
|
|
244
244
|
readonly SPK_WIZARD_INVALID: {
|
|
245
245
|
readonly severity: "warning";
|
|
246
|
-
readonly description: "WIZARD_UIFILES
|
|
246
|
+
readonly description: "A WIZARD_UIFILES wizard file is not a JSON array.";
|
|
247
247
|
readonly source: "DSM 7 Developer Guide: Package Structure (WIZARD_UIFILES)";
|
|
248
248
|
};
|
|
249
249
|
readonly SPK_WIZARD_SCRIPT_NOT_EXECUTABLE: {
|
|
250
250
|
readonly severity: "warning";
|
|
251
|
-
readonly description: "WIZARD_UIFILES
|
|
251
|
+
readonly description: "A WIZARD_UIFILES .sh wizard generator is not executable.";
|
|
252
252
|
readonly source: "DSM 7 Developer Guide: Package Structure (WIZARD_UIFILES)";
|
|
253
253
|
};
|
|
254
254
|
readonly SPK_WIZARD_UNKNOWN: {
|
|
255
255
|
readonly severity: "warning";
|
|
256
|
-
readonly description: "WIZARD_UIFILES
|
|
256
|
+
readonly description: "A WIZARD_UIFILES file name is not install/upgrade/uninstall_uifile[_<lang>][.sh].";
|
|
257
257
|
readonly source: "DSM 7 Developer Guide: Package Structure (WIZARD_UIFILES)";
|
|
258
258
|
};
|
|
259
259
|
readonly SPK_SIGNATURE_INVALID: {
|
|
260
260
|
readonly severity: "warning";
|
|
261
|
-
readonly description: "syno_signature.asc
|
|
261
|
+
readonly description: "syno_signature.asc is not an ASCII-armored PGP signature (the guide's package signing applies only to DSM 6.x, so this file may be omitted).";
|
|
262
262
|
readonly source: "DSM 7 Developer Guide: Sign Package (only for DSM6.X)";
|
|
263
263
|
};
|
|
264
264
|
};
|
package/dist/spk/rules.js
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
const GUIDE = "DSM 7 Developer Guide";
|
|
2
2
|
export const SPK_RULES = {
|
|
3
|
-
SPK_NOT_TAR: { severity: "error", description: "
|
|
4
|
-
SPK_ENTRY_UNSAFE: { severity: "error", description: "SPK
|
|
5
|
-
SPK_ENTRY_UNKNOWN: { severity: "warning", description: "SPK
|
|
6
|
-
SPK_INFO_MISSING: { severity: "error", description: "
|
|
7
|
-
SPK_PAYLOAD_MISSING: { severity: "error", description: "
|
|
8
|
-
SPK_INFO_FIELD_REQUIRED: { severity: "error", description: "INFO
|
|
9
|
-
SPK_INFO_DISPLAYNAME_MISSING: { severity: "warning", description: "INFO
|
|
10
|
-
SPK_INFO_LINE_INVALID: { severity: "warning", description: "INFO
|
|
11
|
-
SPK_INFO_VALUE_UNTERMINATED: { severity: "error", description: "INFO
|
|
12
|
-
SPK_INFO_FIELD_DUPLICATE: { severity: "warning", description: "INFO
|
|
13
|
-
SPK_INFO_PACKAGE_INVALID: { severity: "error", description: "INFO package
|
|
14
|
-
SPK_INFO_VERSION_INVALID: { severity: "error", description: "INFO version
|
|
15
|
-
SPK_INFO_VERSION_NO_BUILD: { severity: "warning", description: "INFO version
|
|
16
|
-
SPK_INFO_OS_VER_INVALID: { severity: "error", description: "INFO os_min_ver
|
|
17
|
-
SPK_INFO_OS_MIN_VER_LOW: { severity: "warning", description: "INFO os_min_ver
|
|
18
|
-
SPK_INFO_ARCH_UNKNOWN: { severity: "warning", description: "INFO arch
|
|
19
|
-
SPK_INFO_ARCH_NOARCH_MIXED: { severity: "warning", description: "INFO arch
|
|
20
|
-
SPK_INFO_BOOLEAN_INVALID: { severity: "error", description: "INFO
|
|
21
|
-
SPK_INFO_LANG_UNKNOWN: { severity: "warning", description: "displayname_<lang>
|
|
22
|
-
SPK_INFO_FIELD_UNKNOWN: { severity: "warning", description: "INFO
|
|
23
|
-
SPK_INFO_ADMINPORT_INVALID: { severity: "error", description: "INFO adminport
|
|
24
|
-
SPK_INFO_CHECKSUM_MISMATCH: { severity: "error", description: "INFO checksum
|
|
25
|
-
SPK_PAYLOAD_UNREADABLE: { severity: "error", description: "package.tgz
|
|
26
|
-
SPK_PAYLOAD_XZ: { severity: "warning", description: "package.tgz
|
|
27
|
-
SPK_PAYLOAD_PATH_UNSAFE: { severity: "error", description: "package.tgz
|
|
28
|
-
SPK_PAYLOAD_LINK_ESCAPE: { severity: "error", description: "package.tgz
|
|
29
|
-
SPK_PAYLOAD_LINK_ABSOLUTE: { severity: "warning", description: "package.tgz
|
|
30
|
-
SPK_UI_CONFIG_INVALID: { severity: "error", description: "dsmuidir
|
|
31
|
-
SPK_UI_TEXTS_MISSING: { severity: "error", description: "config
|
|
32
|
-
SPK_UI_TEXTS_UNDECLARED: { severity: "warning", description: "config
|
|
33
|
-
SPK_NOARCH_ELF: { severity: "error", description: "INFO arch
|
|
34
|
-
SPK_ELF_ARCH_MISMATCH: { severity: "error", description: "package.tgz
|
|
35
|
-
SPK_SCRIPT_MISSING: { severity: "error", description: "
|
|
36
|
-
SPK_SCRIPT_HOOK_MISSING: { severity: "warning", description: "
|
|
37
|
-
SPK_SCRIPT_NOT_EXECUTABLE: { severity: "error", description: "scripts/
|
|
38
|
-
SPK_SCRIPT_NO_INTERPRETER: { severity: "warning", description: "
|
|
39
|
-
SPK_PRIVILEGE_MISSING: { severity: "error", description: "
|
|
40
|
-
SPK_PRIVILEGE_INVALID: { severity: "error", description: "conf/privilege
|
|
41
|
-
SPK_PRIVILEGE_ROOT: { severity: "warning", description: "conf/privilege
|
|
42
|
-
SPK_RESOURCE_INVALID: { severity: "error", description: "conf/resource
|
|
43
|
-
SPK_RESOURCE_UNKNOWN: { severity: "warning", description: "conf/resource
|
|
44
|
-
SPK_CONF_UNKNOWN: { severity: "warning", description: "conf/
|
|
45
|
-
SPK_ICON_MISSING: { severity: "error", description: "
|
|
46
|
-
SPK_ICON_INVALID: { severity: "error", description: "PACKAGE_ICON.PNG
|
|
47
|
-
SPK_ICON_SIZE: { severity: "warning", description: "PACKAGE_ICON.PNG
|
|
48
|
-
SPK_LICENSE_TOO_LARGE: { severity: "error", description: "LICENSE
|
|
49
|
-
SPK_WIZARD_INVALID: { severity: "warning", description: "WIZARD_UIFILES
|
|
50
|
-
SPK_WIZARD_SCRIPT_NOT_EXECUTABLE: { severity: "warning", description: "WIZARD_UIFILES
|
|
51
|
-
SPK_WIZARD_UNKNOWN: { severity: "warning", description: "WIZARD_UIFILES
|
|
52
|
-
SPK_SIGNATURE_INVALID: { severity: "warning", description: "syno_signature.asc
|
|
3
|
+
SPK_NOT_TAR: { severity: "error", description: "The file is not a readable tar archive; an SPK is an uncompressed tar.", source: `${GUIDE}: Package Structure` },
|
|
4
|
+
SPK_ENTRY_UNSAFE: { severity: "error", description: "A path inside the SPK escapes the archive root (an absolute path or ..), or is a link.", source: `${GUIDE}: Package Structure` },
|
|
5
|
+
SPK_ENTRY_UNKNOWN: { severity: "warning", description: "The SPK top level has a file or directory the guide does not list (file names are case-sensitive).", source: `${GUIDE}: Package Structure` },
|
|
6
|
+
SPK_INFO_MISSING: { severity: "error", description: "INFO is missing.", source: `${GUIDE}: Package Structure` },
|
|
7
|
+
SPK_PAYLOAD_MISSING: { severity: "error", description: "package.tgz is missing.", source: `${GUIDE}: Package Structure` },
|
|
8
|
+
SPK_INFO_FIELD_REQUIRED: { severity: "error", description: "INFO is missing a required field (package, version, os_min_ver, description, arch, maintainer).", source: `${GUIDE}: INFO Necessary Fields` },
|
|
9
|
+
SPK_INFO_DISPLAYNAME_MISSING: { severity: "warning", description: "INFO has no displayname; Package Center shows the package value instead.", source: `${GUIDE}: INFO Optional Fields` },
|
|
10
|
+
SPK_INFO_LINE_INVALID: { severity: "warning", description: "INFO has a line that is not key=\"value\" (blank lines and # comments excepted).", source: `${GUIDE}: INFO` },
|
|
11
|
+
SPK_INFO_VALUE_UNTERMINATED: { severity: "error", description: "An INFO field value has an unterminated quote.", source: `${GUIDE}: INFO` },
|
|
12
|
+
SPK_INFO_FIELD_DUPLICATE: { severity: "warning", description: "INFO sets the same field twice.", source: `${GUIDE}: INFO` },
|
|
13
|
+
SPK_INFO_PACKAGE_INVALID: { severity: "error", description: "INFO package contains one of : / > < | =.", source: `${GUIDE}: INFO Necessary Fields (package)` },
|
|
14
|
+
SPK_INFO_VERSION_INVALID: { severity: "error", description: "INFO version is not numbers separated by . - _, or a segment exceeds 2147483647.", source: `${GUIDE}: INFO Necessary Fields (version)` },
|
|
15
|
+
SPK_INFO_VERSION_NO_BUILD: { severity: "warning", description: "INFO version has no -<build> number (the guide format is [feature number]-[build number]).", source: `${GUIDE}: INFO Necessary Fields (version)` },
|
|
16
|
+
SPK_INFO_OS_VER_INVALID: { severity: "error", description: "INFO os_min_ver or os_max_ver is not <major>.<minor>-<build> (<major>.<minor>.<micro>-<build> is also accepted).", source: `${GUIDE}: INFO Necessary Fields (os_min_ver), Optional Fields (os_max_ver)` },
|
|
17
|
+
SPK_INFO_OS_MIN_VER_LOW: { severity: "warning", description: "INFO os_min_ver is below 7.0-40000.", source: `${GUIDE}: INFO Necessary Fields (os_min_ver)` },
|
|
18
|
+
SPK_INFO_ARCH_UNKNOWN: { severity: "warning", description: "INFO arch or exclude_arch has a value that is in neither Appendix A nor the known DSM 7 platforms.", source: `${GUIDE}: Appendix A Platform and Arch Value Mapping Table` },
|
|
19
|
+
SPK_INFO_ARCH_NOARCH_MIXED: { severity: "warning", description: "INFO arch has noarch together with other values.", source: `${GUIDE}: INFO Necessary Fields (arch)` },
|
|
20
|
+
SPK_INFO_BOOLEAN_INVALID: { severity: "error", description: "An INFO yes/no field (for example startable, silent_install) is not \"yes\" or \"no\".", source: `${GUIDE}: INFO Optional Fields` },
|
|
21
|
+
SPK_INFO_LANG_UNKNOWN: { severity: "warning", description: "The language code of displayname_<lang> or description_<lang> is not in the guide list (enu, cht, chs, jpn...).", source: `${GUIDE}: INFO Optional Fields (description_[language])` },
|
|
22
|
+
SPK_INFO_FIELD_UNKNOWN: { severity: "warning", description: "An INFO field is not in the guide list; DSM does not use it (misspelled field names also show up here).", source: `${GUIDE}: INFO Necessary Fields, Optional Fields` },
|
|
23
|
+
SPK_INFO_ADMINPORT_INVALID: { severity: "error", description: "INFO adminport is not an integer from 0 to 65536.", source: `${GUIDE}: INFO Optional Fields (adminport)` },
|
|
24
|
+
SPK_INFO_CHECKSUM_MISMATCH: { severity: "error", description: "INFO checksum is not the MD5 of package.tgz.", source: `${GUIDE}: INFO Optional Fields (checksum)` },
|
|
25
|
+
SPK_PAYLOAD_UNREADABLE: { severity: "error", description: "package.tgz is not a readable tar or tar.gz archive, or is empty.", source: `${GUIDE}: Package Structure (package.tgz)` },
|
|
26
|
+
SPK_PAYLOAD_XZ: { severity: "warning", description: "package.tgz is xz-compressed (the Synology toolkit format); inspect cannot read xz and did not check the payload contents.", source: `${GUIDE}: Pack Stage` },
|
|
27
|
+
SPK_PAYLOAD_PATH_UNSAFE: { severity: "error", description: "A package.tgz path is absolute or contains .., so it extracts outside the package directory.", source: `${GUIDE}: Package Structure (package.tgz)` },
|
|
28
|
+
SPK_PAYLOAD_LINK_ESCAPE: { severity: "error", description: "A package.tgz symlink or hard link points outside the package directory.", source: `${GUIDE}: Package Structure (package.tgz)` },
|
|
29
|
+
SPK_PAYLOAD_LINK_ABSOLUTE: { severity: "warning", description: "A package.tgz symlink points at an absolute path; the target is determined by the NAS, not inside the package.", source: `${GUIDE}: Package Structure (package.tgz)` },
|
|
30
|
+
SPK_UI_CONFIG_INVALID: { severity: "error", description: "The config under dsmuidir is not a JSON object.", source: `${GUIDE}: Integrate DSM, Application Config` },
|
|
31
|
+
SPK_UI_TEXTS_MISSING: { severity: "error", description: "The config title/desc references a package string (for example synopkgland:app_title), but the entry does not declare \"texts\"; DSM shows the key directly.", source: "Measured on DSM 7.1.1/7.4 (DSM loads texts/<lang>/strings only for entries that declare texts)" },
|
|
32
|
+
SPK_UI_TEXTS_UNDECLARED: { severity: "warning", description: "The config title/desc is a section:key string reference but does not declare \"texts\"; unless it is a DSM built-in section, DSM shows the key directly.", source: "Measured on DSM 7.1.1/7.4" },
|
|
33
|
+
SPK_NOARCH_ELF: { severity: "error", description: "INFO arch is noarch, but package.tgz contains an ELF executable.", source: `${GUIDE}: INFO Necessary Fields (arch), Pack Stage` },
|
|
34
|
+
SPK_ELF_ARCH_MISMATCH: { severity: "error", description: "An ELF executable in package.tgz does not match the CPU of INFO arch.", source: `${GUIDE}: INFO Necessary Fields (arch), Appendix A` },
|
|
35
|
+
SPK_SCRIPT_MISSING: { severity: "error", description: "scripts/start-stop-status is missing; DSM uses it to start, stop and query the package status.", source: `${GUIDE}: Package Structure, scripts` },
|
|
36
|
+
SPK_SCRIPT_HOOK_MISSING: { severity: "warning", description: "preinst, postinst, preuninst, postuninst, preupgrade or postupgrade is missing; the guide lists them as required, and DSM's behavior without them is unverified.", source: `${GUIDE}: scripts` },
|
|
37
|
+
SPK_SCRIPT_NOT_EXECUTABLE: { severity: "error", description: "A scripts/ lifecycle script is not executable.", source: `${GUIDE}: scripts` },
|
|
38
|
+
SPK_SCRIPT_NO_INTERPRETER: { severity: "warning", description: "A lifecycle script starts without #! (for example #!/bin/sh) and is not an ELF.", source: `${GUIDE}: scripts` },
|
|
39
|
+
SPK_PRIVILEGE_MISSING: { severity: "error", description: "conf/privilege is missing; DSM 7 requires it.", source: `${GUIDE}: conf, Privilege Config` },
|
|
40
|
+
SPK_PRIVILEGE_INVALID: { severity: "error", description: "conf/privilege is not a JSON object, has no defaults.run-as, or run-as is not package/root.", source: `${GUIDE}: Privilege Config` },
|
|
41
|
+
SPK_PRIVILEGE_ROOT: { severity: "warning", description: "conf/privilege requires running as root (defaults, ctrl-script or executable).", source: `${GUIDE}: Privilege Config` },
|
|
42
|
+
SPK_RESOURCE_INVALID: { severity: "error", description: "conf/resource is not a JSON object.", source: `${GUIDE}: Resource Config` },
|
|
43
|
+
SPK_RESOURCE_UNKNOWN: { severity: "warning", description: "conf/resource has a resource worker id the guide does not list.", source: `${GUIDE}: Available Workers` },
|
|
44
|
+
SPK_CONF_UNKNOWN: { severity: "warning", description: "conf/ has a file DSM does not read (known: privilege, resource, PKG_DEPS, PKG_CONX, systemd/).", source: `${GUIDE}: conf, Systemd User Unit` },
|
|
45
|
+
SPK_ICON_MISSING: { severity: "error", description: "PACKAGE_ICON.PNG or PACKAGE_ICON_256.PNG is missing.", source: `${GUIDE}: Package Structure` },
|
|
46
|
+
SPK_ICON_INVALID: { severity: "error", description: "PACKAGE_ICON.PNG or PACKAGE_ICON_256.PNG is not a PNG.", source: `${GUIDE}: Package Structure` },
|
|
47
|
+
SPK_ICON_SIZE: { severity: "warning", description: "PACKAGE_ICON.PNG is not 64x64, or PACKAGE_ICON_256.PNG is not 256x256.", source: `${GUIDE}: Package Structure` },
|
|
48
|
+
SPK_LICENSE_TOO_LARGE: { severity: "error", description: "LICENSE is 1 MB or larger.", source: `${GUIDE}: Package Structure` },
|
|
49
|
+
SPK_WIZARD_INVALID: { severity: "warning", description: "A WIZARD_UIFILES wizard file is not a JSON array.", source: `${GUIDE}: Package Structure (WIZARD_UIFILES)` },
|
|
50
|
+
SPK_WIZARD_SCRIPT_NOT_EXECUTABLE: { severity: "warning", description: "A WIZARD_UIFILES .sh wizard generator is not executable.", source: `${GUIDE}: Package Structure (WIZARD_UIFILES)` },
|
|
51
|
+
SPK_WIZARD_UNKNOWN: { severity: "warning", description: "A WIZARD_UIFILES file name is not install/upgrade/uninstall_uifile[_<lang>][.sh].", source: `${GUIDE}: Package Structure (WIZARD_UIFILES)` },
|
|
52
|
+
SPK_SIGNATURE_INVALID: { severity: "warning", description: "syno_signature.asc is not an ASCII-armored PGP signature (the guide's package signing applies only to DSM 6.x, so this file may be omitted).", source: `${GUIDE}: Sign Package (only for DSM6.X)` },
|
|
53
53
|
};
|
package/dist/spk/validate-spk.js
CHANGED
|
@@ -22,7 +22,7 @@ export async function validateSpk(spkPath) {
|
|
|
22
22
|
checkOuterEntries(outer.entries, findings);
|
|
23
23
|
info = checkInfo(outer, findings);
|
|
24
24
|
if (!outer.payloadPath)
|
|
25
|
-
findings.add("SPK_PAYLOAD_MISSING", "
|
|
25
|
+
findings.add("SPK_PAYLOAD_MISSING", "package.tgz is missing.", "package.tgz");
|
|
26
26
|
else
|
|
27
27
|
await checkPayload(outer.payloadPath, info, findings);
|
|
28
28
|
checkMetadata({ files: outer.files, modes: new Map(outer.entries.map((entry) => [normalize(entry.path), entry.mode])) }, findings);
|
|
@@ -71,7 +71,7 @@ async function readOuter(spkPath, dir, findings) {
|
|
|
71
71
|
outer.entries.length = 0;
|
|
72
72
|
}
|
|
73
73
|
if (outer.entries.length === 0) {
|
|
74
|
-
findings.add("SPK_NOT_TAR", "
|
|
74
|
+
findings.add("SPK_NOT_TAR", "The file is not a readable tar archive.");
|
|
75
75
|
return undefined;
|
|
76
76
|
}
|
|
77
77
|
return outer;
|
|
@@ -86,19 +86,19 @@ function checkOuterEntries(entries, findings) {
|
|
|
86
86
|
for (const entry of entries) {
|
|
87
87
|
const path = normalize(entry.path);
|
|
88
88
|
if (!isSafeOuter(entry.path, entry.type)) {
|
|
89
|
-
findings.add("SPK_ENTRY_UNSAFE", `${entry.path}
|
|
89
|
+
findings.add("SPK_ENTRY_UNSAFE", `${entry.path} escapes the SPK root or is a link; DSM only extracts regular files and directories.`, entry.path);
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
92
|
const top = path.split("/")[0];
|
|
93
93
|
if (top && !TOP_LEVEL.has(top)) {
|
|
94
|
-
findings.add("SPK_ENTRY_UNKNOWN", `${top}
|
|
94
|
+
findings.add("SPK_ENTRY_UNKNOWN", `${top} is not a known SPK top-level file (file names are case-sensitive).`, top);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
function checkInfo(outer, findings) {
|
|
99
99
|
const text = outer.files.get("INFO");
|
|
100
100
|
if (text === undefined) {
|
|
101
|
-
findings.add("SPK_INFO_MISSING", "
|
|
101
|
+
findings.add("SPK_INFO_MISSING", "INFO is missing.", "INFO");
|
|
102
102
|
return {};
|
|
103
103
|
}
|
|
104
104
|
const fields = parseInfo(text.toString("utf8"), findings);
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { appSdkVersion, sdkSource } from "../runtime/sdk-source.js";
|
|
5
5
|
import { parseDocument } from "yaml";
|
|
6
6
|
/** The App route policy inside each backend kind's directory. */
|
|
7
|
-
export const API_PERMISSIONS_FILE = { go: "internal/api/permissions.json", rust: "permissions.json" };
|
|
7
|
+
export const API_PERMISSIONS_FILE = { go: "internal/api/permissions.json", rust: "permissions.json", python: "permissions.json", node: "permissions.json" };
|
|
8
8
|
/** SDK-owned routes per capability, in the Go module of the SDK version the App requires. */
|
|
9
9
|
const SDK_PERMISSIONS_FILE = "api/sdk-permissions.json";
|
|
10
10
|
export const MAX_PERMISSIONS_BYTES = 65536;
|
|
@@ -16,7 +16,9 @@ export declare function backgroundUnitName(pkg: string): string;
|
|
|
16
16
|
export declare function readBackground(value: unknown, fail: (error: StandaloneError) => void): Background | undefined;
|
|
17
17
|
/** `conf/resource`: only the official user-unit resource. */
|
|
18
18
|
export declare function renderBackgroundResource(): string;
|
|
19
|
-
|
|
19
|
+
/** The worker's arguments: none for a Go App's own worker, `--worker` for the bridge runtime (spec/bridge/v1). */
|
|
20
|
+
export declare const BRIDGE_WORKER_ARGS: readonly ["--worker"];
|
|
21
|
+
export declare function renderBackgroundUnit(pkg: string, args?: readonly string[]): string;
|
|
20
22
|
/** Shell function that stops the worker in lifecycle hooks; call it as `stop_background_worker`. */
|
|
21
23
|
export declare function renderBackgroundWorkerStop(pkg: string): string;
|
|
22
24
|
/**
|