@synopackageland/cli 0.10.0 → 0.10.2
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 +56 -0
- package/dist/capability-overlays.js +1 -1
- package/dist/error-registry.js +1 -0
- package/dist/runtime/executor-build.js +10 -0
- package/dist/runtime/executor-digests.json +22 -0
- package/dist/runtime/executor-inspect.js +3 -0
- package/dist/runtime/executor-policy-check.d.ts +14 -0
- package/dist/runtime/executor-policy-check.js +72 -0
- package/dist/standalone/dsm-window.js +15 -3
- package/dist/validate.js +4 -1
- package/package.json +2 -2
- package/schema/bridge-manifest.v1.schema.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.2 (2026-10-14)
|
|
4
|
+
|
|
5
|
+
Builds with SDK 0.10.2 and templates 0.10.2: `init` writes SDK v0.10.2 (Go
|
|
6
|
+
module, Rust crate tag and `backend.sdk`) and `@synopackageland/sdk` 0.10.2.
|
|
7
|
+
The executor digest table adds SDK 0.10.2 and keeps 0.10.0 and 0.10.1. SDK
|
|
8
|
+
0.10.2's executor changed (it adds `check-policy`), so an App rebuilt on it
|
|
9
|
+
carries a new executor digest; when its policy digest does not change, the
|
|
10
|
+
upgrade puts the new executor in place without approval. The lifecycle
|
|
11
|
+
digests equal 0.10.1.
|
|
12
|
+
|
|
13
|
+
繁中摘要:使用 SDK 0.10.2 與 templates 0.10.2;digest 表新增 SDK 0.10.2(保留
|
|
14
|
+
0.10.0、0.10.1)。executor 變更(新增 check-policy),policy digest 不變的 App
|
|
15
|
+
升級時自動換 executor,不需重新核准;lifecycle digest 與 0.10.1 相同。
|
|
16
|
+
|
|
17
|
+
- `check` and `build` have the App's SDK executor validate the executor policy
|
|
18
|
+
(`executor check-policy`, SDK 0.10.2 and later, which `init` now writes; built for this host from the
|
|
19
|
+
App's SDK version, or from `SYNOPKGLAND_SDK_DIR`). A policy the executor
|
|
20
|
+
would refuse fails with `EXECUTOR_POLICY_REJECTED`, the executor's reason and
|
|
21
|
+
the dsm-package.yaml part to fix, instead of failing only at approval on the
|
|
22
|
+
NAS. Apps without delegate or rootOps, and SDKs before check-policy, are not
|
|
23
|
+
checked.
|
|
24
|
+
- Fix: `inspect` reports an SDK it cannot download as `SDK_DOWNLOAD_FAILED`
|
|
25
|
+
with the GOPRIVATE hint. It was `SPK_INSPECTION_FAILED` ("Executor inventory
|
|
26
|
+
invalid", "do not install an SPK that fails inspection"), which blamed a
|
|
27
|
+
valid SPK for the machine's Go setup.
|
|
28
|
+
- Fix: a DSM window (and a Portal or standalone launch) passes the App
|
|
29
|
+
`ctx.displayName` in the DSM language: the translated `i18n.info.<locale>.displayname`,
|
|
30
|
+
the name DSM shows in the window title, else the English `displayname`. It
|
|
31
|
+
was always the English name, so a narrow-window header and the title bar
|
|
32
|
+
disagreed under a translated DSM.
|
|
33
|
+
|
|
34
|
+
## 0.10.1 (2026-10-13)
|
|
35
|
+
|
|
36
|
+
Builds with SDK 0.10.1 and templates 0.10.1: `init` writes SDK v0.10.1 (Go
|
|
37
|
+
module, Rust crate tag and `backend.sdk`) and `@synopackageland/sdk` 0.10.1.
|
|
38
|
+
The executor digest table adds SDK 0.10.1 and keeps 0.10.0. SDK 0.10.1's
|
|
39
|
+
executor changed, so an App rebuilt on it carries a new executor digest and
|
|
40
|
+
its pins are approved again; the lifecycle digests equal 0.10.0. The bridge
|
|
41
|
+
manifest schema is synced from the SDK (`capabilities.root` also serves
|
|
42
|
+
`executor.status` and `executor.control`).
|
|
43
|
+
|
|
44
|
+
繁中摘要:使用 SDK 0.10.1 與 templates 0.10.1;digest 表新增 SDK 0.10.1(保留
|
|
45
|
+
0.10.0)。executor 變更,改用 SDK 0.10.1 重建的 App 要重新核准 executor digest,
|
|
46
|
+
lifecycle digest 與 0.10.0 相同。
|
|
47
|
+
|
|
48
|
+
- A Python, Node.js or Rust App with root-ops and a Vue UI borrows
|
|
49
|
+
`native-go-root-ops/frontend`, as a Go App gets it from its overlay: its
|
|
50
|
+
`ExecutorGate.vue` holds the App's pages until an administrator approves
|
|
51
|
+
the executor (templates 0.10.1).
|
|
52
|
+
- Fix: in a DSM window with root operations (`capabilities.rootOps`, and so a
|
|
53
|
+
`portal` App), the App root now fills the window body below the root panels.
|
|
54
|
+
It had no height, so an App root asking for `height:100%` collapsed to its
|
|
55
|
+
content: a loading overlay covered only the top of the window, and a dialog
|
|
56
|
+
centred on the App root was placed above the window. Windows without root
|
|
57
|
+
operations are unchanged.
|
|
58
|
+
|
|
3
59
|
## 0.10.0 (2026-10-13)
|
|
4
60
|
|
|
5
61
|
Builds with SDK 0.10.0 and templates 0.10.0: `init` writes SDK v0.10.0 (Go
|
|
@@ -22,7 +22,7 @@ function bridgeOverlays(template) {
|
|
|
22
22
|
return {
|
|
23
23
|
// The example hashes a file the caller picks, which the runtime reads only for an App with files.
|
|
24
24
|
jobs: { overlays: [`${template}-jobs`], borrowed: ['native-go-jobs/frontend'], removed: [], permissions: {}, implied: ['files'], methods: ['hash.submit', 'hash.get', 'hash.cancel'] },
|
|
25
|
-
'root-ops': { overlays: [`${template}-root-ops`], borrowed: ['native-go-root-ops/root'], removed: [], permissions: {}, methods: ['whoami.run'] },
|
|
25
|
+
'root-ops': { overlays: [`${template}-root-ops`], borrowed: ['native-go-root-ops/root', 'native-go-root-ops/frontend'], removed: [], permissions: {}, methods: ['whoami.run'] },
|
|
26
26
|
delegate: {
|
|
27
27
|
overlays: [`${template}-delegate`], borrowed: ['native-go-jobs/frontend', 'native-go-delegate/frontend'], removed: [],
|
|
28
28
|
permissions: { 'app.status': 'authenticated', 'report.save': 'authenticated' }, methods: ['report.save'],
|
package/dist/error-registry.js
CHANGED
|
@@ -757,6 +757,7 @@ for (const [code, description, suggestion] of [
|
|
|
757
757
|
["TEMPLATES_MISSING", "@synopackageland/templates was not found.", "Reinstall @synopackageland/cli, or point SYNOPKGLAND_TEMPLATES_DIR at a templates checkout."],
|
|
758
758
|
["EXECUTOR_PIN_REQUIRED", "A package that declares rootOps or delegate was built without the executor artifact.", "Use synopkgland build so the CLI compiles and pins the executor; do not call the low-level SPK API directly."],
|
|
759
759
|
["EXECUTOR_POLICY", "capabilities.delegate has invalid operations or scope, or a binary root program lacks the file for this architecture, so the executor policy cannot be generated.", "Use the delegate declaration init/add produces and fix scope and operations against the manifest reference; for binary root programs provide root/<arch>/<name> for every arch in arches."],
|
|
760
|
+
["EXECUTOR_POLICY_REJECTED", "The executor of the App's SDK version refuses the policy the CLI generated, so the NAS would refuse it at approval.", "The reason names the refused part: policy root/stop/purge → root.programs (schema, run, job), root.stop, uninstall.purge; policy scope/operation/destination/move/lifetime → capabilities.delegate; policy portal → portal; policy entry → entry. Fix that part of dsm-package.yaml; if it already matches the manifest reference, use the SDK version this CLI release names."],
|
|
760
761
|
["EXECUTOR_ROOT_PROGRAMS_UNSUPPORTED", "The root settings in dsm-package.yaml need an executor that supports root program settings, which the App's SDK version lacks.", "Use an SDK with root programs, stop and root_state (executor/stop_step.go), or remove the root settings."],
|
|
761
762
|
["EXECUTOR_PACKAGE", "The package name pinned into the root task is invalid.", "package must start with a letter and contain only alphanumerics (2-64 characters)."],
|
|
762
763
|
["EXECUTOR_DIGEST", "The sha256 pin for the executor or policy is malformed.", "Build again so the CLI recomputes the pin; do not hand-edit pins inside the SPK."],
|
|
@@ -9,6 +9,7 @@ import { executorTasks } from './executor-tasks.js';
|
|
|
9
9
|
import { copyModule, verifyExecutorDigests } from './executor-source.js';
|
|
10
10
|
import { requiredSdk } from './sdk-source.js';
|
|
11
11
|
import { rootProgramsUnsupported } from './root-programs.js';
|
|
12
|
+
import { executorPolicyProblem } from './executor-policy-check.js';
|
|
12
13
|
/** CLI-owned build flags; the release digest table is computed the same way, so they must not change within an SDK minor. */
|
|
13
14
|
const GO_BUILD = ['build', '-trimpath', '-buildvcs=false', '-ldflags', '-s -w -buildid=', '-o'];
|
|
14
15
|
function failure(error) {
|
|
@@ -75,6 +76,15 @@ export async function buildExecutor(m, arch, work, run, options = {}) {
|
|
|
75
76
|
if (unsupported)
|
|
76
77
|
throw new StandaloneBuildError('EXECUTOR_ROOT_PROGRAMS_UNSUPPORTED', unsupported);
|
|
77
78
|
const policyText = executorPolicyText(policy);
|
|
79
|
+
let refused;
|
|
80
|
+
try {
|
|
81
|
+
refused = executorPolicyProblem(source, sdk.version, m.package, policyText, options.env);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw failure(error);
|
|
85
|
+
}
|
|
86
|
+
if (refused)
|
|
87
|
+
throw new StandaloneBuildError('EXECUTOR_POLICY_REJECTED', refused);
|
|
78
88
|
const pins = { package: m.package, executorDigest, policyDigest: sha256(policyText) };
|
|
79
89
|
return { ...pins, binary, lifecycleBinary, policy, policyText, tasks: executorTasks(pins, sdk.executorDir), implementation: 'executor', sdk: sdk.version, warnings };
|
|
80
90
|
}
|
|
@@ -9,5 +9,27 @@
|
|
|
9
9
|
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
10
10
|
},
|
|
11
11
|
"goToolchain": "go1.26.9"
|
|
12
|
+
},
|
|
13
|
+
"0.10.1": {
|
|
14
|
+
"x86_64": "51b538e6ec1cb8fa2a4e00291eda097969352d6e2d9a3e7ade5da5359f1065de",
|
|
15
|
+
"aarch64": "9038b5ad7b4822e967f18390ca28b6f0021a3044ed461809b3f7333f17400840",
|
|
16
|
+
"armv7": "22d872cc618e3af4a052955186d36a6851e9f96ad959ee8ea7d3fbb5eec968bd",
|
|
17
|
+
"lifecycle": {
|
|
18
|
+
"x86_64": "d65500c4f04713a32b45d360059281391acfa5e00ee24895fdd2de7b82735372",
|
|
19
|
+
"aarch64": "94f6cd119186ff482b8aea56541dd1f9d53c147566bc1efdca6f5a1c86198331",
|
|
20
|
+
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
21
|
+
},
|
|
22
|
+
"goToolchain": "go1.26.9"
|
|
23
|
+
},
|
|
24
|
+
"0.10.2": {
|
|
25
|
+
"x86_64": "bb7aebb120562633e852d590007870489b7839ea2c943db897b7a71dea743fae",
|
|
26
|
+
"aarch64": "2fd8365aabfa2ea2ea7c767f89fa8222d7f4fc04cbdde6b7d510c74002a5bb89",
|
|
27
|
+
"armv7": "6f757614eab802fa07c2601c801bcf2c14ad3076d7c01f9ed20d62744ef13979",
|
|
28
|
+
"lifecycle": {
|
|
29
|
+
"x86_64": "d65500c4f04713a32b45d360059281391acfa5e00ee24895fdd2de7b82735372",
|
|
30
|
+
"aarch64": "94f6cd119186ff482b8aea56541dd1f9d53c147566bc1efdca6f5a1c86198331",
|
|
31
|
+
"armv7": "cafc97c89f5645c14a8cf31d6d9f258394ed6f2d086478a7aebd04d57c274b4e"
|
|
32
|
+
},
|
|
33
|
+
"goToolchain": "go1.26.9"
|
|
12
34
|
}
|
|
13
35
|
}
|
|
@@ -43,6 +43,9 @@ export function inspectExecutor(dir, pkg, arch) {
|
|
|
43
43
|
return { executor: { executorDigest, policyDigest, policy, implementation: plan.implementation, sdk: plan.sdk, tasks: tasks.map(task => ({ ...task, state: 'unknown' })) }, findings: [] };
|
|
44
44
|
}
|
|
45
45
|
catch (e) {
|
|
46
|
+
// A failed SDK download is this machine's Go setup (GOPRIVATE), not a defect of the SPK.
|
|
47
|
+
if (e.message.startsWith('[SDK_DOWNLOAD_FAILED]'))
|
|
48
|
+
throw e;
|
|
46
49
|
return { findings: ['Executor inventory invalid: ' + e.message] };
|
|
47
50
|
}
|
|
48
51
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type StandaloneManifest } from '../standalone/manifest.js';
|
|
2
|
+
/**
|
|
3
|
+
* Why the SDK executor would refuse the policy, such as `invalid policy: policy root`;
|
|
4
|
+
* undefined when it accepts it or its SDK predates check-policy. The executor is
|
|
5
|
+
* built for this host from executorDir, so its own rules decide, not a copy in the CLI.
|
|
6
|
+
*/
|
|
7
|
+
export declare function executorPolicyRefusal(executorDir: string, pkg: string, policyText: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
8
|
+
/** The EXECUTOR_POLICY_REJECTED message for a policy the SDK executor refuses; undefined when it accepts it. */
|
|
9
|
+
export declare function executorPolicyProblem(executorDir: string, sdkVersion: string, pkg: string, policyText: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
10
|
+
/** The policy of each architecture `check` would build, checked by the App's SDK executor; Apps without executor need none. */
|
|
11
|
+
export declare function manifestPolicyProblem(m: StandaloneManifest, env?: NodeJS.ProcessEnv): {
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
} | undefined;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { PINNED_GO_HINT, PINNED_GO_TOOLCHAIN } from '../build-spk/go-toolchain.js';
|
|
6
|
+
import { sdkBackend } from '../standalone/manifest.js';
|
|
7
|
+
import { executorPolicy, executorPolicyText } from './executor-policy.js';
|
|
8
|
+
import { requiredSdk } from './sdk-source.js';
|
|
9
|
+
/** The executor subcommand that validates a policy on stdin as load() does (SDK 0.10.2 and later). */
|
|
10
|
+
const CHECK_POLICY = 'check-policy';
|
|
11
|
+
/**
|
|
12
|
+
* Why the SDK executor would refuse the policy, such as `invalid policy: policy root`;
|
|
13
|
+
* undefined when it accepts it or its SDK predates check-policy. The executor is
|
|
14
|
+
* built for this host from executorDir, so its own rules decide, not a copy in the CLI.
|
|
15
|
+
*/
|
|
16
|
+
export function executorPolicyRefusal(executorDir, pkg, policyText, env = process.env) {
|
|
17
|
+
const main = join(executorDir, 'main.go');
|
|
18
|
+
if (!existsSync(main) || !readFileSync(main, 'utf8').includes(`"${CHECK_POLICY}"`))
|
|
19
|
+
return undefined;
|
|
20
|
+
const dir = mkdtempSync(join(tmpdir(), 'synopkgland-check-policy-'));
|
|
21
|
+
try {
|
|
22
|
+
const binary = join(dir, 'executor');
|
|
23
|
+
const { GOOS: _os, GOARCH: _arch, ...host } = env;
|
|
24
|
+
const build = spawnSync('go', ['build', '-o', binary, '.'], { cwd: executorDir, env: { ...host, GOTOOLCHAIN: PINNED_GO_TOOLCHAIN, GOFLAGS: '', GOWORK: 'off', CGO_ENABLED: '0' }, encoding: 'utf8' });
|
|
25
|
+
if (build.error || build.status !== 0)
|
|
26
|
+
throw new Error(`[EXECUTOR_BUILD_FAILED] Building the SDK executor for this host to check the policy failed. ${PINNED_GO_HINT}\n${build.stderr || build.error?.message}`);
|
|
27
|
+
const result = spawnSync(binary, [CHECK_POLICY, '--package', pkg], { input: policyText, encoding: 'utf8' });
|
|
28
|
+
if (result.status === 0)
|
|
29
|
+
return undefined;
|
|
30
|
+
const reason = /^executor: (.*)$/m.exec(result.stderr ?? '')?.[1];
|
|
31
|
+
if (result.status === 1 && reason)
|
|
32
|
+
return reason;
|
|
33
|
+
throw new Error(`[EXECUTOR_BUILD_FAILED] executor ${CHECK_POLICY} did not run: ${result.stderr || result.error?.message}`);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
rmSync(dir, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Where in dsm-package.yaml each executor refusal comes from. */
|
|
40
|
+
const POLICY_FIX = [
|
|
41
|
+
[/policy (root|stop|purge)/, 'fix root.programs (schema, run, job), root.stop or uninstall.purge in dsm-package.yaml'],
|
|
42
|
+
[/policy (scope|operation|destination|move|lifetime)/, 'fix capabilities.delegate in dsm-package.yaml'],
|
|
43
|
+
[/policy portal/, 'fix portal in dsm-package.yaml'],
|
|
44
|
+
[/policy entry/, 'fix entry in dsm-package.yaml'],
|
|
45
|
+
];
|
|
46
|
+
/** The EXECUTOR_POLICY_REJECTED message for a policy the SDK executor refuses; undefined when it accepts it. */
|
|
47
|
+
export function executorPolicyProblem(executorDir, sdkVersion, pkg, policyText, env = process.env) {
|
|
48
|
+
const reason = executorPolicyRefusal(executorDir, pkg, policyText, env);
|
|
49
|
+
if (!reason)
|
|
50
|
+
return undefined;
|
|
51
|
+
const fix = POLICY_FIX.find(([pattern]) => pattern.test(reason))?.[1] ?? 'fix the declaration in dsm-package.yaml';
|
|
52
|
+
return `The executor of SDK ${sdkVersion} refuses this App's policy (executor: ${reason}), so the NAS would refuse it at approval: ${fix}.`
|
|
53
|
+
+ ' If dsm-package.yaml already matches the manifest reference, this CLI and the SDK disagree: use the SDK version this CLI release names.';
|
|
54
|
+
}
|
|
55
|
+
/** The policy of each architecture `check` would build, checked by the App's SDK executor; Apps without executor need none. */
|
|
56
|
+
export function manifestPolicyProblem(m, env = process.env) {
|
|
57
|
+
if (!m.capabilities.delegate && !m.capabilities.rootOps)
|
|
58
|
+
return undefined;
|
|
59
|
+
try {
|
|
60
|
+
const sdk = requiredSdk(sdkBackend(m), env);
|
|
61
|
+
for (const text of new Set(m.arches.map(arch => executorPolicyText(executorPolicy(m, arch))))) {
|
|
62
|
+
const message = executorPolicyProblem(sdk.executorDir, sdk.version, m.package, text, env);
|
|
63
|
+
if (message)
|
|
64
|
+
return { code: 'EXECUTOR_POLICY_REJECTED', message };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
const coded = /^\[([A-Z0-9_]+)\] ([\s\S]*)$/.exec(error.message);
|
|
69
|
+
return { code: coded?.[1] ?? 'EXECUTOR_BUILD_FAILED', message: coded?.[2] ?? error.message };
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
@@ -72,6 +72,15 @@ export function entryLauncherAccess(entry) {
|
|
|
72
72
|
export function appTitle(manifest) {
|
|
73
73
|
return { displayname: manifest.displayname, description: manifest.description, info: manifest.i18n?.info };
|
|
74
74
|
}
|
|
75
|
+
/** The app name by locale, as `ui/texts` names the window: `createI18n(lang, ...).t("app_title")`. */
|
|
76
|
+
function displayNameCatalogs(manifest) {
|
|
77
|
+
const catalogs = { en: { app_title: manifest.displayname } };
|
|
78
|
+
for (const [locale, text] of Object.entries(manifest.i18n?.info ?? {})) {
|
|
79
|
+
if (text?.displayname)
|
|
80
|
+
catalogs[locale] = { app_title: text.displayname };
|
|
81
|
+
}
|
|
82
|
+
return catalogs;
|
|
83
|
+
}
|
|
75
84
|
/** `ui/config`: registers the DSM main-menu app and its window class. */
|
|
76
85
|
export function renderUiConfig(manifest, icons = packageIcons(manifest.icon)) {
|
|
77
86
|
const icon = windowIconTemplate(icons);
|
|
@@ -268,7 +277,7 @@ ${root ? root.mount : ""} ${ns}.loadApp(function (app) {
|
|
|
268
277
|
root.lang = i18n.locale;
|
|
269
278
|
try {
|
|
270
279
|
me.mounted = app.mount(root, Ext.apply(ctx, {
|
|
271
|
-
displayName: ${JSON.stringify(manifest.
|
|
280
|
+
displayName: ${ns}.createI18n(lang, ${JSON.stringify(displayNameCatalogs(manifest))}).t("app_title"),
|
|
272
281
|
call: call,
|
|
273
282
|
files: {endpoint: ${JSON.stringify(cgiUrl(pkg))}, token: function () { return SYNO.SDS.Session && SYNO.SDS.Session.SynoToken; }},
|
|
274
283
|
reopen: me.reopenEvents.subscribe,
|
|
@@ -363,6 +372,9 @@ const ROOT_PANEL_CSS = [
|
|
|
363
372
|
".dsmapp-rootpanel-actions button{margin-right:8px;padding:4px 14px}",
|
|
364
373
|
".dsmapp-rootpanel-primary{background:#057feb;color:#fff;border:1px solid #057feb;border-radius:3px}",
|
|
365
374
|
".dsmapp-rootpanel-hint{color:#526070;font-size:12px}.dsmapp-rootpanel [hidden]{display:none}",
|
|
375
|
+
// The panels keep their height; the App root fills the rest of the window body, as without root operations.
|
|
376
|
+
".dsmapp-rootwindow{display:flex;flex-direction:column;height:100%}",
|
|
377
|
+
".dsmapp-rootwindow>.dsmapp-rootpanels{flex:none}.dsmapp-rootwindow>.dsmapp-root{flex:1 1 0;min-height:0}",
|
|
366
378
|
].join("");
|
|
367
379
|
/**
|
|
368
380
|
* A Vue app approves in the SDK's ExecutorSettings, which also carries an
|
|
@@ -374,7 +386,7 @@ function settingsOnlyApproval(manifest) {
|
|
|
374
386
|
/**
|
|
375
387
|
* The capabilities.rootOps: true additions to the window: the exact tasks and panel
|
|
376
388
|
* text, the access runtime wired to DSM's own password confirmation and the
|
|
377
|
-
* AppWindow's WebAPI channel, and the panel above the app.
|
|
389
|
+
* AppWindow's WebAPI channel, and the panel above the app, which fills the rest.
|
|
378
390
|
*/
|
|
379
391
|
function renderRootParts(ns, manifest) {
|
|
380
392
|
return {
|
|
@@ -394,7 +406,7 @@ ${PASSWORD_CONFIRM}
|
|
|
394
406
|
|
|
395
407
|
`,
|
|
396
408
|
html: `autoScroll: true,
|
|
397
|
-
html: '<style>${ROOT_PANEL_CSS}</style><div class="dsmapp-rootpanels"></div><div class="dsmapp-root"></div>'`,
|
|
409
|
+
html: '<style>${ROOT_PANEL_CSS}</style><div class="dsmapp-rootwindow"><div class="dsmapp-rootpanels"></div><div class="dsmapp-root"></div></div>'`,
|
|
398
410
|
mount: ` var session = function () {
|
|
399
411
|
var current = SYNO.SDS.Session || {};
|
|
400
412
|
return { name: current.user, admin: current.is_admin === true };
|
package/dist/validate.js
CHANGED
|
@@ -9,6 +9,7 @@ import { classifyComposeRoute, collectComposeInterpolations, collectVolumeSource
|
|
|
9
9
|
import { usesAuthGateway } from "./contract/web-launch.js";
|
|
10
10
|
import { isNativeLayout, loadNativeLayout } from "./standalone/native-layout.js";
|
|
11
11
|
import { loadStandaloneManifest } from "./standalone/manifest.js";
|
|
12
|
+
import { manifestPolicyProblem } from "./runtime/executor-policy-check.js";
|
|
12
13
|
import { COMPOSE_FILENAME, CONTRACT_FILENAME, DSM_PACKAGE_FILENAME, } from "./discovery.js";
|
|
13
14
|
import { declaredPrivilegeFlags } from "./compose/privilege.js";
|
|
14
15
|
export function validateProject(project, options = {}) {
|
|
@@ -29,7 +30,9 @@ export function validateProject(project, options = {}) {
|
|
|
29
30
|
}
|
|
30
31
|
if (hasStandalone) {
|
|
31
32
|
const loaded = isNativeLayout(project.root) ? loadNativeLayout(project.root) : loadStandaloneManifest(project.root);
|
|
32
|
-
|
|
33
|
+
const policy = loaded.ok && "capabilities" in loaded.manifest ? manifestPolicyProblem(loaded.manifest) : undefined;
|
|
34
|
+
const problems = loaded.ok ? (policy ? [policy] : []) : loaded.errors;
|
|
35
|
+
return !problems.length ? { ok: true, errors: [] } : { ok: false, errors: problems.map(error => ({
|
|
33
36
|
...error, span: { file: DSM_PACKAGE_FILENAME, line: 1, column: 1 },
|
|
34
37
|
suggestion: getErrorCode(error.code)?.suggestion ?? "Fix the schema 2 fields and capability declarations in dsm-package.yaml.",
|
|
35
38
|
})) };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Syno Package Land Developer Kit CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"prepublishOnly": "npm run build"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@synopackageland/templates": "0.10.
|
|
27
|
+
"@synopackageland/templates": "0.10.2",
|
|
28
28
|
"ajv": "^8.17.1",
|
|
29
29
|
"commander": "^13.1.0",
|
|
30
30
|
"tar": "^7.4.3",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"identity": { "const": "standalone", "$comment": "The SDK's App sign-in (identity.*) authenticates instead of DSM." },
|
|
60
60
|
"portal": { "type": "boolean", "$comment": "true serves portal.status, to the browser and as the svc portal.status." },
|
|
61
61
|
"jobs": { "type": "boolean", "$comment": "Added in v1 (additive). true offers the svc bg.submit, bg.get and bg.cancel on the package's job store." },
|
|
62
|
-
"root": { "type": "boolean", "$comment": "Added in v1 (additive). true offers the svc root.run, root.start, root.jobs.list, root.jobs.get and root.jobs.stop: the runtime forwards them to the package's executor with the request's DSM session, and the executor's policy and the App privilege decide." },
|
|
62
|
+
"root": { "type": "boolean", "$comment": "Added in v1 (additive). true offers the svc root.run, root.start, root.jobs.list, root.jobs.get and root.jobs.stop: the runtime forwards them to the package's executor with the request's DSM session, and the executor's policy and the App privilege decide. It also serves the browser routes executor.status and executor.control (README, Executor routes)." },
|
|
63
63
|
"delegate": {
|
|
64
64
|
"type": "object",
|
|
65
65
|
"additionalProperties": false,
|