@synopackageland/sdk 0.9.9 → 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/README.md +164 -1
- package/dist/i18n/bridge/de.json +6 -0
- package/dist/i18n/bridge/en.json +6 -0
- package/dist/i18n/bridge/es.json +6 -0
- package/dist/i18n/bridge/fr.json +6 -0
- package/dist/i18n/bridge/it.json +6 -0
- package/dist/i18n/bridge/ja.json +6 -0
- package/dist/i18n/bridge/ko.json +6 -0
- package/dist/i18n/bridge/zh-CN.json +6 -0
- package/dist/i18n/bridge/zh-TW.json +6 -0
- package/dist/i18n/delegate/de.json +9 -2
- package/dist/i18n/delegate/en.json +9 -2
- package/dist/i18n/delegate/es.json +9 -2
- package/dist/i18n/delegate/fr.json +9 -2
- package/dist/i18n/delegate/it.json +9 -2
- package/dist/i18n/delegate/ja.json +9 -2
- package/dist/i18n/delegate/ko.json +9 -2
- package/dist/i18n/delegate/zh-CN.json +9 -2
- package/dist/i18n/delegate/zh-TW.json +9 -2
- package/dist/i18n/shell/de.json +5 -1
- package/dist/i18n/shell/en.json +5 -1
- package/dist/i18n/shell/es.json +5 -1
- package/dist/i18n/shell/fr.json +5 -1
- package/dist/i18n/shell/it.json +5 -1
- package/dist/i18n/shell/ja.json +5 -1
- package/dist/i18n/shell/ko.json +5 -1
- package/dist/i18n/shell/zh-CN.json +5 -1
- package/dist/i18n/shell/zh-TW.json +5 -1
- package/dist/index.js +2553 -2336
- package/dist/src/bridge/i18n.d.ts +5 -0
- package/dist/src/context.d.ts +23 -2
- package/dist/src/delegate/ExecutorApproval.vue.d.ts +19 -0
- package/dist/src/delegate/ExecutorNotice.vue.d.ts +8 -0
- package/dist/src/delegate/copy.d.ts +14 -0
- package/dist/src/delegate/root.d.ts +40 -0
- package/dist/src/index.d.ts +5 -2
- package/dist/src/protocol/v1.d.ts +49 -4
- package/dist/src/shell/AppShell.vue.d.ts +31 -10
- package/dist/src/shell/app-pages.d.ts +37 -0
- package/dist/src/shell/i18n.d.ts +4 -0
- package/dist/src/shell/pages.d.ts +7 -2
- package/dist/src/shell/slot-content.d.ts +2 -0
- package/dist/src/standalone.d.ts +5 -0
- package/dist/src/vue.d.ts +3 -0
- package/dist/style.css +1 -1
- package/dist/vue.js +1945 -1686
- package/package.json +4 -4
- package/spec/protocol/v1/README.md +154 -3
- package/spec/protocol/v1/errors.json +36 -4
- package/spec/protocol/v1/schema/root.jobs.get.json +19 -0
- package/spec/protocol/v1/schema/root.jobs.list.json +11 -0
- package/spec/protocol/v1/schema/root.jobs.stop.json +19 -0
- package/spec/protocol/v1/schema/root.run.json +6 -2
- package/spec/protocol/v1/schema/root.start.json +23 -0
- package/spec/protocol/v1/vectors/files.jsonl +11 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Frontend SDK for DSM packages built with synopkgland: headless client and Vue components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/synopackageland/syno-pkg-land-sdk/tree/main/ts#readme",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"dist",
|
|
33
|
-
"spec"
|
|
33
|
+
"spec/protocol"
|
|
34
34
|
],
|
|
35
35
|
"scripts": {
|
|
36
36
|
"prepack": "test -d node_modules || { echo '@synopackageland/sdk: run npm ci before npm pack' >&2; exit 1; }; npm run build",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@lucide/vue": "^1.48.0",
|
|
43
|
-
"@synopackageland/ui": "^0.9.
|
|
43
|
+
"@synopackageland/ui": "^0.9.4",
|
|
44
44
|
"vue": "^3.5.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependenciesMeta": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@lucide/vue": "1.48.0",
|
|
56
|
-
"@synopackageland/ui": "0.9.
|
|
56
|
+
"@synopackageland/ui": "0.9.4",
|
|
57
57
|
"@types/node": "24.19.2",
|
|
58
58
|
"@vitejs/plugin-vue": "6.0.9",
|
|
59
59
|
"jsdom": "27.4.0",
|
|
@@ -22,8 +22,8 @@ the executor against the vectors here.
|
|
|
22
22
|
accept a connection only from the package user or root (peer credentials).
|
|
23
23
|
2. A connection carries exactly one request and one response.
|
|
24
24
|
3. A request is one line of UTF-8 JSON ending in `\n`. A request line MUST NOT
|
|
25
|
-
exceed 64 KiB including the newline
|
|
26
|
-
`REQUEST_TOO_LARGE`.
|
|
25
|
+
exceed 64 KiB including the newline, or 1 MiB for `root.run` and
|
|
26
|
+
`root.start`; the executor answers `REQUEST_TOO_LARGE`.
|
|
27
27
|
4. The executor MUST answer one line of JSON ending in `\n` and close.
|
|
28
28
|
5. The executor SHOULD close a connection that sends nothing for 15 seconds.
|
|
29
29
|
|
|
@@ -114,6 +114,157 @@ packages.
|
|
|
114
114
|
own files and DSM's generated conf), `unregistered`, or `cleanup-required`
|
|
115
115
|
(anything else, including a failed change).
|
|
116
116
|
|
|
117
|
+
## Root programs
|
|
118
|
+
|
|
119
|
+
Since 0.10.0. Each `root` entry pins a program by its SHA-256 digest; a bare
|
|
120
|
+
digest is a script `root.run` may run with the defaults. The object form is
|
|
121
|
+
`{"digest", "kind", "schema", "run"}`: `kind` `script` (`root/<name>.sh`) or
|
|
122
|
+
`binary` (`root/<name>`), `schema` a closed JSON Schema subset for its params,
|
|
123
|
+
`run` its `timeout_s` (1–120, default 20) and `max_output` (≤ 64 MiB,
|
|
124
|
+
default 1 MiB), `job` its background limits: `timeout_s` (1–604800, default
|
|
125
|
+
86400), `grace_s` (1–60, default 10), `max_concurrent` (1–4, default 1) and
|
|
126
|
+
`nice` (0–19, default 10). `executor/README.md` lists the schema keywords.
|
|
127
|
+
`root.run` needs `run`, `root.start` needs `job`; an entry may have both.
|
|
128
|
+
|
|
129
|
+
Every root program, whatever starts it:
|
|
130
|
+
|
|
131
|
+
- runs as root in `/`, in its own process group, without core dumps, with
|
|
132
|
+
stdin the params JSON (`{}` without params) followed by EOF;
|
|
133
|
+
- gets only `PATH=/usr/syno/bin:/usr/syno/sbin:/usr/bin:/bin`, `LANG=C`,
|
|
134
|
+
`HOME=/` and these variables:
|
|
135
|
+
|
|
136
|
+
| Variable | Set for | Value |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `SYNOPKGLAND_PACKAGE` | all | the package name |
|
|
139
|
+
| `SYNOPKGLAND_ROOT_MODE` | all | `run`, `job`, `stop` or `purge` |
|
|
140
|
+
| `SYNOPKGLAND_REQUESTED_BY` | run, job | the verified DSM user name |
|
|
141
|
+
| `SYNOPKGLAND_REQUEST_ID` | run | 64 hex digits, unique per call |
|
|
142
|
+
| `SYNOPKGLAND_JOB_ID` | job | the job's `job_id` |
|
|
143
|
+
| `SYNOPKGLAND_CONTROL_FD` | job | `4` |
|
|
144
|
+
| `SYNOPKGLAND_PROGRESS_FD` | job | `5` |
|
|
145
|
+
| `SYNOPKGLAND_ROOT_STATE` | all, with `root_state` | the root state directory |
|
|
146
|
+
|
|
147
|
+
- `root.run` MUST require an administrator session whose Application
|
|
148
|
+
Privileges allow the App, and an entry with `run`; params outside the
|
|
149
|
+
schema, or any params without one, are `INVALID_REQUEST`.
|
|
150
|
+
- The executor MUST give the params to the program only as JSON on stdin,
|
|
151
|
+
and MUST set `SYNOPKGLAND_REQUESTED_BY` to the verified user name. The
|
|
152
|
+
environment holds nothing else from the caller.
|
|
153
|
+
- It MUST execute the descriptor whose content it checked against the digest,
|
|
154
|
+
never the path again.
|
|
155
|
+
- A program that exits, whatever its status, is a result: `request_id`,
|
|
156
|
+
`exit_code`, `stderr` and either `output` (UTF-8, in a reply under 64 KiB)
|
|
157
|
+
or `staging` and `size`, a package-owned staging file the client reads and
|
|
158
|
+
removes. Past the timeout the process group is killed (`ROOT_TIMEOUT`);
|
|
159
|
+
output past `max_output` is `limit-exceeded`; a full staging quota is
|
|
160
|
+
`ROOT_STAGING_FULL`; two running programs make a third `ROOT_BUSY`.
|
|
161
|
+
- A `root.run` request MAY be up to 1 MiB; the executor answers within 130
|
|
162
|
+
seconds and a client SHOULD wait 140.
|
|
163
|
+
- `root.run` cannot be canceled: a closed connection does not stop the
|
|
164
|
+
program, which runs until it exits or its timeout. Work that may be stopped
|
|
165
|
+
is a root job (`root.start`, `root.jobs.stop`).
|
|
166
|
+
|
|
167
|
+
## Root jobs
|
|
168
|
+
|
|
169
|
+
Since 0.10.0. `root.start`, `root.jobs.list`, `root.jobs.get` and
|
|
170
|
+
`root.jobs.stop` come together in `operations`. Each requires an administrator
|
|
171
|
+
session whose Application Privileges allow the App, like `root.run`; any such
|
|
172
|
+
administrator sees and stops every job of the package.
|
|
173
|
+
|
|
174
|
+
| op | params | result |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| `root.start` | `name`, `params` (object, optional) | `{"job_id", "state": "running"}` |
|
|
177
|
+
| `root.jobs.list` | none | `{"jobs": [summary, ...]}`, newest first |
|
|
178
|
+
| `root.jobs.get` | `job_id` | job |
|
|
179
|
+
| `root.jobs.stop` | `job_id` | job, `stopping` or already ended |
|
|
180
|
+
|
|
181
|
+
A job is:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"job_id": "<64 hex digits>",
|
|
186
|
+
"name": "clean",
|
|
187
|
+
"state": "running",
|
|
188
|
+
"requested_by": "alice",
|
|
189
|
+
"started_at": "2026-10-13T05:00:00Z",
|
|
190
|
+
"ended_at": "2026-10-13T05:03:12Z",
|
|
191
|
+
"exit_code": 0,
|
|
192
|
+
"cancel_reason": "user",
|
|
193
|
+
"progress": {"percent": 40, "message": "scanning", "phase": "scan"},
|
|
194
|
+
"result": {"freed": 3},
|
|
195
|
+
"output": "first 4 KiB of stdout and stderr"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
- `state` is `running`, `stopping` (a cancel was sent), or an end:
|
|
200
|
+
`succeeded` (exit 0), `failed` (another exit or a signal), `canceled` (it
|
|
201
|
+
ended after a cancel, however it exited), `timed-out` or `interrupted`
|
|
202
|
+
(the executor ended without seeing it end). `ended_at`, `exit_code` (an
|
|
203
|
+
exit, not a signal) and `cancel_reason` appear once they apply; `progress`
|
|
204
|
+
and `result` once the job reported them. `output` is valid UTF-8.
|
|
205
|
+
- A summary is a job without `result`, `output` and the progress `message`
|
|
206
|
+
and `phase`, so the 64 records fit a reply; `root.jobs.get` answers the
|
|
207
|
+
whole job.
|
|
208
|
+
- `root.start` MUST refuse with `ROOT_BUSY` while the entry runs
|
|
209
|
+
`max_concurrent` jobs or the package runs four. Params follow the entry's
|
|
210
|
+
schema as for `root.run`. An entry without `job` is `POLICY_DENIED`.
|
|
211
|
+
- An unknown `job_id` is `ROOT_JOB_NOT_FOUND`. The executor keeps the 64
|
|
212
|
+
newest records; older ones are removed.
|
|
213
|
+
- `root.jobs.stop` of an ended job returns it unchanged.
|
|
214
|
+
- Jobs do not survive the executor: when it stops, every running job is
|
|
215
|
+
canceled, and a job a crashed executor left is `interrupted` (its process
|
|
216
|
+
group is killed when the same process still runs).
|
|
217
|
+
|
|
218
|
+
### Progress and cancel
|
|
219
|
+
|
|
220
|
+
The job reports on fd 5 and is told to stop on fd 4; both are pipes.
|
|
221
|
+
|
|
222
|
+
- **Progress** (fd 5, job to executor): JSON lines of at most 32 KiB, each an
|
|
223
|
+
object with any of `percent` (number 0–100), `message` (string, at most 512
|
|
224
|
+
characters), `phase` (string, at most 64 characters) and `result` (any JSON,
|
|
225
|
+
at most 16 KiB encoded). Each member present replaces the previous one; a
|
|
226
|
+
line with anything else is ignored whole. `result` is the job's answer for
|
|
227
|
+
its caller, kept after it ends.
|
|
228
|
+
- **Cancel** (fd 4, executor to job): one line `{"cancel":"<reason>"}`, with
|
|
229
|
+
reason `user` (`root.jobs.stop`), `stop` (package stop), `upgrade`
|
|
230
|
+
(package upgrade), `purge` (uninstall) or `executor-stop`. EOF on fd 4
|
|
231
|
+
means the executor ended: the job should stop too. The job ends
|
|
232
|
+
gracefully; `grace_s` after the cancel (at most 15 seconds on package stop,
|
|
233
|
+
upgrade and uninstall) the executor kills its process group.
|
|
234
|
+
- **Timeout**: `timeout_s` after the start the process group is killed
|
|
235
|
+
without a cancel (`timed-out`).
|
|
236
|
+
- A job MAY also keep its own progress files (for example in
|
|
237
|
+
`SYNOPKGLAND_ROOT_STATE`) for its App to read; the executor does not
|
|
238
|
+
interpret them.
|
|
239
|
+
- Clients poll `root.jobs.get`; each answer is the job's latest progress. A
|
|
240
|
+
bridge MAY turn successive answers into progress events.
|
|
241
|
+
|
|
242
|
+
## Package stop step
|
|
243
|
+
|
|
244
|
+
Since 0.10.0. A policy MAY carry `"stop": "<name>"`, naming a `root` entry the
|
|
245
|
+
executor runs when the package stops, after its jobs ended, with no session.
|
|
246
|
+
Its argument is `prepare-upgrade` when the package account wrote `upgrade`
|
|
247
|
+
to `var/executor/stop-reason` before the stop request (the
|
|
248
|
+
`executor/lifecycle stop --upgrade` helper does; DSM's `preupgrade` should
|
|
249
|
+
use it), and `stop` otherwise; jobs are canceled with `upgrade` or `stop`
|
|
250
|
+
accordingly. It runs for at most 30 seconds, only while the approval is live
|
|
251
|
+
(as for the purge step), its exit and output go to the executor log, and a
|
|
252
|
+
failure does not stop the stop. `root.run` and `root.start` refuse it with
|
|
253
|
+
`POLICY_DENIED`.
|
|
254
|
+
|
|
255
|
+
## Root state directory
|
|
256
|
+
|
|
257
|
+
Since 0.10.0. A policy with `"root_state": true` gives its root programs a
|
|
258
|
+
directory only root can read: `/volumeN/@synopkgland/<package>`, root:root
|
|
259
|
+
0700, on the volume that holds the package's `var` (DSM's
|
|
260
|
+
`/volumeN/@appdata/<package>`); `/volumeN/@synopkgland` is root:root 0755.
|
|
261
|
+
The executor creates it at start and passes it as `SYNOPKGLAND_ROOT_STATE`;
|
|
262
|
+
when the package `var` is not on a volume it MUST NOT start root programs
|
|
263
|
+
that need it (`ROOT_FAILED`). The directory is outside every package
|
|
264
|
+
directory, so upgrades keep it. At uninstall the purge step sees it; after
|
|
265
|
+
the step the executor deletes it for `delete-state` and keeps it for
|
|
266
|
+
`keep-state`, so a reinstall on the same volume finds it again.
|
|
267
|
+
|
|
117
268
|
## Uninstall purge step
|
|
118
269
|
|
|
119
270
|
Since 0.9.7. A policy MAY carry `"purge": "<name>"`, naming one of its `root`
|
|
@@ -131,7 +282,7 @@ runs as root at uninstall, with no session.
|
|
|
131
282
|
skip the op and log `purge root step skipped: not approved`.
|
|
132
283
|
- The op gets the argument `delete-state` when the package account wrote
|
|
133
284
|
`delete-state` to `var/executor/uninstall` before its request (the
|
|
134
|
-
`executor/lifecycle purge --delete-state` helper does), and
|
|
285
|
+
`executor/lifecycle purge --delete-state` helper does), and `keep-state`
|
|
135
286
|
otherwise. It runs for at most 60 seconds; its exit status and output go to
|
|
136
287
|
the purge log, and a failure MUST NOT stop the rest of the purge.
|
|
137
288
|
|
|
@@ -151,8 +151,40 @@
|
|
|
151
151
|
"kind": "refusal",
|
|
152
152
|
"retryable": false,
|
|
153
153
|
"httpStatus": 500,
|
|
154
|
-
"en": "The root
|
|
155
|
-
"zh-TW": "root
|
|
154
|
+
"en": "The root program could not run, ended by a signal, or its output could not be kept.",
|
|
155
|
+
"zh-TW": "root 程式無法執行、被訊號終止,或其輸出無法保存。"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"code": "ROOT_TIMEOUT",
|
|
159
|
+
"kind": "refusal",
|
|
160
|
+
"retryable": true,
|
|
161
|
+
"httpStatus": 504,
|
|
162
|
+
"en": "The root program ran past its policy timeout and was killed.",
|
|
163
|
+
"zh-TW": "root 程式超過 policy 的時限,已被終止。"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"code": "ROOT_BUSY",
|
|
167
|
+
"kind": "refusal",
|
|
168
|
+
"retryable": true,
|
|
169
|
+
"httpStatus": 429,
|
|
170
|
+
"en": "The package already runs as many root programs as it may.",
|
|
171
|
+
"zh-TW": "此套件同時執行的 root 程式已達上限。"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"code": "ROOT_STAGING_FULL",
|
|
175
|
+
"kind": "refusal",
|
|
176
|
+
"retryable": true,
|
|
177
|
+
"httpStatus": 507,
|
|
178
|
+
"en": "Root output waiting in the staging folder already fills its quota.",
|
|
179
|
+
"zh-TW": "staging 資料夾中等待取走的 root 輸出已達配額。"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"code": "ROOT_JOB_NOT_FOUND",
|
|
183
|
+
"kind": "refusal",
|
|
184
|
+
"retryable": false,
|
|
185
|
+
"httpStatus": 404,
|
|
186
|
+
"en": "No root job of the package has this job_id.",
|
|
187
|
+
"zh-TW": "此套件沒有這個 job_id 的 root 工作。"
|
|
156
188
|
},
|
|
157
189
|
{
|
|
158
190
|
"code": "PORTAL_FAILED",
|
|
@@ -335,8 +367,8 @@
|
|
|
335
367
|
"kind": "refusal",
|
|
336
368
|
"retryable": false,
|
|
337
369
|
"httpStatus": 413,
|
|
338
|
-
"en": "The file is larger than max_bytes.",
|
|
339
|
-
"zh-TW": "檔案超過 max_bytes。"
|
|
370
|
+
"en": "The file is larger than max_bytes, or root output is larger than its policy max_output.",
|
|
371
|
+
"zh-TW": "檔案超過 max_bytes,或 root 輸出超過 policy 的 max_output。"
|
|
340
372
|
},
|
|
341
373
|
{
|
|
342
374
|
"code": "OPERATION_CANCELED",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/root.jobs.get.json",
|
|
4
|
+
"title": "root.jobs.get",
|
|
5
|
+
"description": "Administrator whom Application Privileges allow to use the App: one root job with its state, latest progress and result.",
|
|
6
|
+
"since": "0.10.0",
|
|
7
|
+
"auth": "required",
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"job_id": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"pattern": "^[a-f0-9]{64}$"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"additionalProperties": false,
|
|
16
|
+
"required": [
|
|
17
|
+
"job_id"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/root.jobs.list.json",
|
|
4
|
+
"title": "root.jobs.list",
|
|
5
|
+
"description": "Administrator whom Application Privileges allow to use the App: list the package's root jobs, newest first.",
|
|
6
|
+
"since": "0.10.0",
|
|
7
|
+
"auth": "required",
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {},
|
|
10
|
+
"additionalProperties": false
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/root.jobs.stop.json",
|
|
4
|
+
"title": "root.jobs.stop",
|
|
5
|
+
"description": "Administrator whom Application Privileges allow to use the App: ask a running root job to cancel; it is killed after its grace.",
|
|
6
|
+
"since": "0.10.0",
|
|
7
|
+
"auth": "required",
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"job_id": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"pattern": "^[a-f0-9]{64}$"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"additionalProperties": false,
|
|
16
|
+
"required": [
|
|
17
|
+
"job_id"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/root.run.json",
|
|
4
4
|
"title": "root.run",
|
|
5
|
-
"description": "Administrator: run a root
|
|
5
|
+
"description": "Administrator whom Application Privileges allow to use the App: run a root program pinned by digest in the policy. Params reach the program on stdin as JSON, checked against the entry's schema; the reply carries its exit code, stderr and output, or a staging file for large output.",
|
|
6
6
|
"since": "0.9.0",
|
|
7
7
|
"auth": "required",
|
|
8
8
|
"type": "object",
|
|
9
9
|
"properties": {
|
|
10
10
|
"name": {
|
|
11
11
|
"type": "string",
|
|
12
|
-
"
|
|
12
|
+
"pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$"
|
|
13
|
+
},
|
|
14
|
+
"params": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"description": "The program's params; without a schema in the policy only {} is accepted."
|
|
13
17
|
}
|
|
14
18
|
},
|
|
15
19
|
"additionalProperties": false,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/synopackageland/syno-pkg-land-sdk/spec/protocol/v1/schema/root.start.json",
|
|
4
|
+
"title": "root.start",
|
|
5
|
+
"description": "Administrator whom Application Privileges allow to use the App: start a root job, a pinned program with job limits, in the background. Params reach it on stdin; it reports progress on fd 5 and is told to cancel on fd 4.",
|
|
6
|
+
"since": "0.10.0",
|
|
7
|
+
"auth": "required",
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$"
|
|
13
|
+
},
|
|
14
|
+
"params": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"description": "The job's params; without a schema in the policy only {} is accepted."
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"required": [
|
|
21
|
+
"name"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -7,5 +7,16 @@
|
|
|
7
7
|
{"name":"move-missing-size","request":{"v":1,"op":"files.moveFromStaging","params":{"delegation_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job_id":"export-20261009","staging":"exports/report.csv","name":"report.csv"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{"grants":[{"id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","username":"alice","key":"save","path":"/home/exports"}]},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
8
8
|
{"name":"operation-status-unknown","request":{"v":1,"op":"files.operationStatus","params":{"delegation_id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job_id":"export-20261009"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{"grants":[{"id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","username":"alice","key":"save","path":"/home/exports"}]},"expect":{"ok":false,"code":"operation-not-found"}}
|
|
9
9
|
{"name":"root-run-unpinned","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"whoami"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{},"expect":{"ok":false,"code":"POLICY_DENIED"}}
|
|
10
|
+
{"name":"root-run-params-outside-schema","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"scan","params":{"mode":"slow"}}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{"scan":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","schema":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["fast","full"]}},"required":["mode"]},"run":{}}}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
11
|
+
{"name":"root-run-params-unknown-member","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"scan","params":{"mode":"fast","path":"/"}}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{"scan":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","schema":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["fast","full"]}},"required":["mode"]},"run":{}}}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
12
|
+
{"name":"root-run-params-without-schema","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"scan","params":{"mode":"fast"}}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{"scan":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
13
|
+
{"name":"root-run-job-only-entry","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"scan"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{"scan":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job":{}}}},"state":{},"expect":{"ok":false,"code":"POLICY_DENIED"}}
|
|
10
14
|
{"name":"root-run-purge-step","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"purge"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{"purge":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"},"purge":"purge"},"state":{},"expect":{"ok":false,"code":"POLICY_DENIED"}}
|
|
11
15
|
{"name":"root-run-bad-name","request":{"v":1,"op":"root.run","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"../x"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run"],"destinations":["save"],"lifetime":"until-revoked","root":{}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
16
|
+
{"name":"root-start-run-only-entry","request":{"v":1,"op":"root.start","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"scan"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"scan":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}},"state":{},"expect":{"ok":false,"code":"POLICY_DENIED"}}
|
|
17
|
+
{"name":"root-start-params-outside-schema","request":{"v":1,"op":"root.start","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"name":"clean","params":{"days":0}}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"clean":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","schema":{"type":"object","additionalProperties":false,"properties":{"days":{"type":"integer","minimum":1}}},"job":{}}}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
18
|
+
{"name":"root-jobs-list-empty","request":{"v":1,"op":"root.jobs.list","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"clean":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job":{}}}},"state":{},"expect":{"ok":true,"result":{"jobs":[]}}}
|
|
19
|
+
{"name":"root-jobs-get-unknown","request":{"v":1,"op":"root.jobs.get","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"job_id":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"clean":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job":{}}}},"state":{},"expect":{"ok":false,"code":"ROOT_JOB_NOT_FOUND"}}
|
|
20
|
+
{"name":"root-jobs-stop-unknown","request":{"v":1,"op":"root.jobs.stop","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"job_id":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"clean":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job":{}}}},"state":{},"expect":{"ok":false,"code":"ROOT_JOB_NOT_FOUND"}}
|
|
21
|
+
{"name":"root-jobs-get-bad-id","request":{"v":1,"op":"root.jobs.get","auth":{"dsm_cookie":"admin","dsm_synotoken":"contract-token"},"params":{"job_id":"../x"}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"clean":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job":{}}}},"state":{},"expect":{"ok":false,"code":"INVALID_REQUEST"}}
|
|
22
|
+
{"name":"root-jobs-list-not-admin","request":{"v":1,"op":"root.jobs.list","auth":{"dsm_cookie":"alice","dsm_synotoken":"contract-token"},"params":{}},"policy":{"v":1,"package":"contract","app":"app","scope":"home","operations":["status","delegate.create","delegate.list","delegate.revoke","files.list","files.write","files.moveFromStaging","files.operationStatus","files.cancelOperation","delegate.disable","delegate.enable","delegate.audit","root.run","root.start","root.jobs.list","root.jobs.get","root.jobs.stop"],"destinations":["save"],"lifetime":"until-revoked","root":{"clean":{"digest":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","job":{}}}},"state":{},"expect":{"ok":false,"code":"ADMIN_REQUIRED"}}
|