@synopackageland/cli 0.6.1 → 0.7.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 +846 -0
- package/README.md +81 -89
- package/dist/add.d.ts +4 -1
- package/dist/add.js +45 -17
- package/dist/build-spk/delegate-scope.d.ts +6 -0
- package/dist/build-spk/delegate-scope.js +34 -0
- package/dist/build-spk/dsm-arch.d.ts +7 -1
- package/dist/build-spk/dsm-arch.js +24 -28
- package/dist/build-spk/dsm-platforms.json +42 -0
- package/dist/build-spk/dsm-version.d.ts +11 -0
- package/dist/build-spk/dsm-version.js +17 -0
- package/dist/build-spk/gateway.js +8 -4
- package/dist/build-spk/generator.js +30 -5
- package/dist/build-spk/go-toolchain.d.ts +20 -0
- package/dist/build-spk/go-toolchain.js +44 -0
- package/dist/build-spk/notices.js +4 -1
- package/dist/build-spk/resource-worker.js +3 -0
- package/dist/build-spk/wizard-messages.d.ts +66 -0
- package/dist/build-spk/wizard-messages.js +75 -9
- package/dist/cli.js +28 -14
- package/dist/contract/schema-validate.js +8 -0
- package/dist/contract/validate.js +30 -0
- package/dist/deploy/deploy.d.ts +1 -1
- package/dist/deploy/deploy.js +8 -0
- package/dist/deploy/native-install-values.d.ts +17 -0
- package/dist/deploy/native-install-values.js +32 -0
- package/dist/deploy/plan.d.ts +6 -2
- package/dist/deploy/plan.js +58 -7
- package/dist/deploy/spk-version.js +1 -1
- package/dist/error-registry.js +54 -20
- package/dist/host/dsm-client.d.ts +8 -4
- package/dist/host/dsm-client.js +63 -21
- package/dist/host/dsm-http.js +24 -2
- package/dist/host/types.d.ts +3 -1
- package/dist/info.js +45 -10
- package/dist/init.d.ts +3 -0
- package/dist/init.js +50 -19
- package/dist/package-metadata.d.ts +21 -0
- package/dist/package-metadata.js +101 -0
- package/dist/portal/alias.d.ts +25 -0
- package/dist/portal/alias.js +48 -0
- package/dist/portal/package.d.ts +33 -0
- package/dist/portal/package.js +116 -0
- package/dist/runtime/delegate-contract.d.ts +79 -0
- package/dist/runtime/delegate-contract.js +27 -0
- package/dist/runtime/dsm-version.d.ts +6 -0
- package/dist/runtime/dsm-version.js +8 -0
- package/dist/runtime/executor-build.js +10 -6
- package/dist/runtime/executor-inspect.d.ts +3 -0
- package/dist/runtime/executor-inspect.js +11 -5
- package/dist/runtime/executor-policy.d.ts +12 -0
- package/dist/runtime/executor-policy.js +43 -3
- package/dist/runtime/executor-scope-task.d.ts +4 -0
- package/dist/runtime/executor-scope-task.js +21 -0
- package/dist/runtime/executor-tasks.d.ts +2 -1
- package/dist/runtime/executor-tasks.js +4 -4
- package/dist/skill.js +1 -0
- package/dist/standalone/api-permissions.d.ts +10 -0
- package/dist/standalone/api-permissions.js +19 -2
- package/dist/standalone/background.d.ts +16 -0
- package/dist/standalone/background.js +69 -2
- package/dist/standalone/binary.d.ts +1 -1
- package/dist/standalone/binary.js +22 -8
- package/dist/standalone/build.d.ts +1 -1
- package/dist/standalone/build.js +38 -8
- package/dist/standalone/daemon.d.ts +1 -0
- package/dist/standalone/daemon.js +10 -5
- package/dist/standalone/dsm-window.d.ts +3 -1
- package/dist/standalone/dsm-window.js +78 -49
- package/dist/standalone/inspect-spk.d.ts +8 -0
- package/dist/standalone/inspect-spk.js +110 -27
- package/dist/standalone/lifecycle.js +86 -8
- package/dist/standalone/manifest.d.ts +13 -0
- package/dist/standalone/manifest.js +57 -8
- package/dist/standalone/native-authorization-window.d.ts +1 -1
- package/dist/standalone/native-authorization-window.js +9 -1
- package/dist/standalone/native-layout.d.ts +3 -0
- package/dist/standalone/native-layout.js +37 -5
- package/dist/standalone/native-root-window.d.ts +4 -2
- package/dist/standalone/native-root-window.js +33 -18
- package/dist/standalone/portal-window.d.ts +21 -0
- package/dist/standalone/portal-window.js +155 -0
- package/dist/standalone/portal.d.ts +4 -0
- package/dist/standalone/portal.js +4 -0
- package/dist/standalone/resource.d.ts +5 -3
- package/dist/standalone/resource.js +6 -3
- package/dist/standalone/root-window.d.ts +4 -1
- package/dist/standalone/root-window.js +193 -36
- package/dist/standalone/spk.d.ts +1 -1
- package/dist/standalone/spk.js +25 -7
- package/dist/templates/_daemon/go.mod +1 -1
- package/dist/templates/_daemon/main.go +6 -3
- package/dist/templates/_daemon/main_test.go +82 -9
- package/dist/templates/_daemon/testdata/child.go +3 -0
- package/dist/templates/_executor/README.md +130 -16
- package/dist/templates/_executor/anchor.go +156 -0
- package/dist/templates/_executor/anchor_test.go +161 -0
- package/dist/templates/_executor/apppriv_review_test.go +1 -1
- package/dist/templates/_executor/cancel_contract_test.go +236 -0
- package/dist/templates/_executor/copy.go +64 -0
- package/dist/templates/_executor/copy_test.go +88 -0
- package/dist/templates/_executor/digest_review_test.go +2 -2
- package/dist/templates/_executor/dsm.go +63 -13
- package/dist/templates/_executor/dsm_test.go +95 -1
- package/dist/templates/_executor/executor.go +260 -49
- package/dist/templates/_executor/executor_test.go +36 -6
- package/dist/templates/_executor/go.mod +2 -0
- package/dist/templates/_executor/identity.go +27 -1
- package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/dist/templates/_executor/identity_linux.go +82 -0
- package/dist/templates/_executor/identity_security_test.go +43 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
- package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/dist/templates/_executor/lifecycle_test.go +11 -0
- package/dist/templates/_executor/link_linux.go +28 -0
- package/dist/templates/_executor/long_running_test.go +530 -0
- package/dist/templates/_executor/main.go +83 -25
- package/dist/templates/_executor/managed.go +3 -3
- package/dist/templates/_executor/managed_test.go +3 -3
- package/dist/templates/_executor/move_linux.go +490 -0
- package/dist/templates/_executor/move_linux_test.go +460 -0
- package/dist/templates/_executor/move_validation.go +46 -0
- package/dist/templates/_executor/move_validation_test.go +187 -0
- package/dist/templates/_executor/operations.go +926 -0
- package/dist/templates/_executor/path_test.go +18 -0
- package/dist/templates/_executor/pid.go +37 -0
- package/dist/templates/_executor/pid_test.go +113 -0
- package/dist/templates/_executor/platform_linux.go +24 -173
- package/dist/templates/_executor/platform_linux_test.go +9 -65
- package/dist/templates/_executor/platform_other.go +38 -4
- package/dist/templates/_executor/process.go +3 -0
- package/dist/templates/_executor/purge_log.go +18 -0
- package/dist/templates/_executor/records.go +242 -0
- package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/dist/templates/_executor/scope_client.go +37 -0
- package/dist/templates/_executor/scope_contract.go +12 -0
- package/dist/templates/_executor/selected_scope.go +146 -0
- package/dist/templates/_executor/selected_scope_test.go +186 -0
- package/dist/templates/_executor/status_disabled_test.go +33 -0
- package/dist/templates/_executor/store.go +4 -3
- package/dist/templates/_executor/supervise.go +109 -0
- package/dist/templates/_executor/supervise_test.go +130 -0
- package/dist/templates/_executor/task_race_review_test.go +1 -1
- package/dist/templates/_executor/tasks.go +52 -15
- package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
- package/dist/templates/_executor/tasks_review_test.go +1 -1
- package/dist/templates/_executor/tasks_test.go +62 -5
- package/dist/templates/_executor/upgrade_watch_test.go +13 -5
- package/dist/templates/_executor/watch.go +8 -0
- package/dist/templates/_executor/watch_test.go +23 -2
- package/dist/templates/_executor/write_review_linux_test.go +4 -12
- package/dist/templates/_gateway/go.mod +2 -0
- package/dist/templates/_shared/AGENTS.md +129 -0
- package/dist/templates/binary/dsm-package.yaml +24 -0
- package/dist/templates/binary/i18n/messages/de.json +4 -0
- package/dist/templates/binary/i18n/messages/en.json +4 -0
- package/dist/templates/binary/i18n/messages/es.json +4 -0
- package/dist/templates/binary/i18n/messages/fr.json +4 -0
- package/dist/templates/binary/i18n/messages/it.json +4 -0
- package/dist/templates/binary/i18n/messages/ja.json +4 -0
- package/dist/templates/binary/i18n/messages/ko.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/dist/templates/binary/ui/app.js +19 -4
- package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/dist/templates/native-authorization/i18n/de.json +1 -0
- package/dist/templates/native-authorization/i18n/en.json +1 -0
- package/dist/templates/native-authorization/i18n/es.json +2 -1
- package/dist/templates/native-authorization/i18n/fr.json +1 -0
- package/dist/templates/native-authorization/i18n/it.json +11 -10
- package/dist/templates/native-authorization/i18n/ja.json +1 -0
- package/dist/templates/native-authorization/i18n/ko.json +10 -9
- package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/dist/templates/native-go/README.md +43 -10
- package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
- package/dist/templates/native-go/backend/go.mod +1 -1
- package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
- package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/dist/templates/native-go/backend/internal/api/server.go +18 -5
- package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
- package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
- package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
- package/dist/templates/native-go/backend/internal/background/store.go +16 -14
- package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/dist/templates/native-go/backend/internal/filestation/client.go +39 -3
- package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
- package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/dist/templates/native-go/backend/internal/identity/README.md +5 -1
- package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
- package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/dist/templates/native-go/backend/internal/identity/service.go +1 -1
- package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/dist/templates/native-go/dsm-package.yaml +20 -1
- package/dist/templates/native-go/i18n/glossary.json +2 -1
- package/dist/templates/native-go/i18n/messages/de.json +1 -0
- package/dist/templates/native-go/i18n/messages/en.json +1 -0
- package/dist/templates/native-go/i18n/messages/es.json +1 -0
- package/dist/templates/native-go/i18n/messages/fr.json +1 -0
- package/dist/templates/native-go/i18n/messages/it.json +1 -0
- package/dist/templates/native-go/i18n/messages/ja.json +1 -0
- package/dist/templates/native-go/i18n/messages/ko.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/dist/templates/native-go/ui/app.css +10 -0
- package/dist/templates/native-go/ui/app.js +11 -1
- package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
- package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/dist/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
- package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/dist/templates/native-go-delegate/test.sh +1 -0
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/dist/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
- package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- package/dist/templates/native-go-vue/README.md +4 -0
- package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/dist/templates/native-go-vue/frontend/package.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
- package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
- package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
- package/package.json +5 -1
- package/schema/package-metadata.schema.json +101 -0
- package/schema/synology-app.schema.json +112 -0
- package/skills/SKILL.md +106 -4
- package/skills/reference/create.md +101 -2
- package/skills/reference/deploy.md +2 -2
- package/skills/reference/files.md +113 -2
- package/skills/reference/identity.md +70 -1
- package/skills/reference/portal.md +17 -0
- package/skills/reference/ui-vue.md +12 -0
- package/templates/_daemon/go.mod +1 -1
- package/templates/_daemon/main.go +6 -3
- package/templates/_daemon/main_test.go +82 -9
- package/templates/_daemon/testdata/child.go +3 -0
- package/templates/_executor/README.md +130 -16
- package/templates/_executor/anchor.go +156 -0
- package/templates/_executor/anchor_test.go +161 -0
- package/templates/_executor/apppriv_review_test.go +1 -1
- package/templates/_executor/cancel_contract_test.go +236 -0
- package/templates/_executor/copy.go +64 -0
- package/templates/_executor/copy_test.go +88 -0
- package/templates/_executor/digest_review_test.go +2 -2
- package/templates/_executor/dsm.go +63 -13
- package/templates/_executor/dsm_test.go +95 -1
- package/templates/_executor/executor.go +260 -49
- package/templates/_executor/executor_test.go +36 -6
- package/templates/_executor/go.mod +2 -0
- package/templates/_executor/identity.go +27 -1
- package/templates/_executor/identity_kernel_linux_test.go +60 -0
- package/templates/_executor/identity_linux.go +82 -0
- package/templates/_executor/identity_security_test.go +43 -0
- package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
- package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
- package/templates/_executor/internal/taskscript/boot.sh +9 -9
- package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
- package/templates/_executor/internal/taskscript/control.sh +15 -10
- package/templates/_executor/internal/taskscript/tasks.go +5 -3
- package/templates/_executor/lifecycle_test.go +11 -0
- package/templates/_executor/link_linux.go +28 -0
- package/templates/_executor/long_running_test.go +530 -0
- package/templates/_executor/main.go +83 -25
- package/templates/_executor/managed.go +3 -3
- package/templates/_executor/managed_test.go +3 -3
- package/templates/_executor/move_linux.go +490 -0
- package/templates/_executor/move_linux_test.go +460 -0
- package/templates/_executor/move_validation.go +46 -0
- package/templates/_executor/move_validation_test.go +187 -0
- package/templates/_executor/operations.go +926 -0
- package/templates/_executor/path_test.go +18 -0
- package/templates/_executor/pid.go +37 -0
- package/templates/_executor/pid_test.go +113 -0
- package/templates/_executor/platform_linux.go +24 -173
- package/templates/_executor/platform_linux_test.go +9 -65
- package/templates/_executor/platform_other.go +38 -4
- package/templates/_executor/process.go +3 -0
- package/templates/_executor/purge_log.go +18 -0
- package/templates/_executor/records.go +242 -0
- package/templates/_executor/scope_cancel_contract_test.go +91 -0
- package/templates/_executor/scope_client.go +37 -0
- package/templates/_executor/scope_contract.go +12 -0
- package/templates/_executor/selected_scope.go +146 -0
- package/templates/_executor/selected_scope_test.go +186 -0
- package/templates/_executor/status_disabled_test.go +33 -0
- package/templates/_executor/store.go +4 -3
- package/templates/_executor/supervise.go +109 -0
- package/templates/_executor/supervise_test.go +130 -0
- package/templates/_executor/task_race_review_test.go +1 -1
- package/templates/_executor/tasks.go +52 -15
- package/templates/_executor/tasks_dsm71_test.go +114 -0
- package/templates/_executor/tasks_review_test.go +1 -1
- package/templates/_executor/tasks_test.go +62 -5
- package/templates/_executor/upgrade_watch_test.go +13 -5
- package/templates/_executor/watch.go +8 -0
- package/templates/_executor/watch_test.go +23 -2
- package/templates/_executor/write_review_linux_test.go +4 -12
- package/templates/_gateway/go.mod +2 -0
- package/templates/_shared/AGENTS.md +129 -0
- package/templates/binary/dsm-package.yaml +24 -0
- package/templates/binary/i18n/messages/de.json +4 -0
- package/templates/binary/i18n/messages/en.json +4 -0
- package/templates/binary/i18n/messages/es.json +4 -0
- package/templates/binary/i18n/messages/fr.json +4 -0
- package/templates/binary/i18n/messages/it.json +4 -0
- package/templates/binary/i18n/messages/ja.json +4 -0
- package/templates/binary/i18n/messages/ko.json +4 -0
- package/templates/binary/i18n/messages/zh-CN.json +4 -0
- package/templates/binary/i18n/messages/zh-TW.json +4 -0
- package/templates/binary/ui/app.js +19 -4
- package/templates/native-authorization/AuthorizationGate.vue +5 -3
- package/templates/native-authorization/i18n/de.json +1 -0
- package/templates/native-authorization/i18n/en.json +1 -0
- package/templates/native-authorization/i18n/es.json +2 -1
- package/templates/native-authorization/i18n/fr.json +1 -0
- package/templates/native-authorization/i18n/it.json +11 -10
- package/templates/native-authorization/i18n/ja.json +1 -0
- package/templates/native-authorization/i18n/ko.json +10 -9
- package/templates/native-authorization/i18n/zh-CN.json +6 -5
- package/templates/native-authorization/i18n/zh-TW.json +6 -5
- package/templates/native-go/README.md +43 -10
- package/templates/native-go/backend/cmd/app/main.go +27 -7
- package/templates/native-go/backend/go.mod +1 -1
- package/templates/native-go/backend/internal/api/entry_test.go +47 -0
- package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
- package/templates/native-go/backend/internal/api/registry.go +11 -0
- package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
- package/templates/native-go/backend/internal/api/server.go +18 -5
- package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
- package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
- package/templates/native-go/backend/internal/app/portal.go +30 -0
- package/templates/native-go/backend/internal/app/portal_test.go +55 -0
- package/templates/native-go/backend/internal/app/routes.go +8 -2
- package/templates/native-go/backend/internal/background/runner.go +1 -1
- package/templates/native-go/backend/internal/background/store.go +16 -14
- package/templates/native-go/backend/internal/dsm/admin.go +8 -2
- package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
- package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
- package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
- package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
- package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
- package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
- package/templates/native-go/backend/internal/dsm/entry.go +177 -0
- package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
- package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
- package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
- package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
- package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
- package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
- package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
- package/templates/native-go/backend/internal/filestation/client.go +39 -3
- package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
- package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
- package/templates/native-go/backend/internal/filestation/service.go +1 -1
- package/templates/native-go/backend/internal/identity/README.md +5 -1
- package/templates/native-go/backend/internal/identity/dsm.go +24 -5
- package/templates/native-go/backend/internal/identity/http.go +1 -1
- package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
- package/templates/native-go/backend/internal/identity/service.go +1 -1
- package/templates/native-go/backend/internal/portal/portal.go +138 -0
- package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
- package/templates/native-go/dsm-package.yaml +20 -1
- package/templates/native-go/i18n/glossary.json +2 -1
- package/templates/native-go/i18n/messages/de.json +1 -0
- package/templates/native-go/i18n/messages/en.json +1 -0
- package/templates/native-go/i18n/messages/es.json +1 -0
- package/templates/native-go/i18n/messages/fr.json +1 -0
- package/templates/native-go/i18n/messages/it.json +1 -0
- package/templates/native-go/i18n/messages/ja.json +1 -0
- package/templates/native-go/i18n/messages/ko.json +1 -0
- package/templates/native-go/i18n/messages/zh-CN.json +1 -0
- package/templates/native-go/i18n/messages/zh-TW.json +1 -0
- package/templates/native-go/ui/app.css +10 -0
- package/templates/native-go/ui/app.js +11 -1
- package/templates/native-go-delegate/DELEGATE.md +126 -5
- package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
- package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
- package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
- package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
- package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
- package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
- package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
- package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
- package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
- package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
- package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
- package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
- package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
- package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
- package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
- package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
- package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
- package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
- package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
- package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
- package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
- package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
- package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
- package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
- package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
- package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
- package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
- package/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
- package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
- package/templates/native-go-delegate/test.sh +1 -0
- package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
- package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
- package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
- package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
- package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
- package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
- package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
- package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
- package/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
- package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
- package/templates/native-go-vue/README.md +4 -0
- package/templates/native-go-vue/frontend/package-lock.json +4 -4
- package/templates/native-go-vue/frontend/package.json +1 -1
- package/templates/native-go-vue/frontend/src/App.vue +18 -13
- package/templates/native-go-vue/frontend/src/context.ts +31 -0
- package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
- package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
- package/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
- package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
- package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
- package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
- package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
- package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
- package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
- package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
- package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
- package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
- package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
- package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
- package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
- package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
- package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
- package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
- package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
- package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
- package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
- package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
- package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
- package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
- package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
- package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
- package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
- package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
|
@@ -1,28 +1,47 @@
|
|
|
1
1
|
import { bootDefinition, controlDefinition } from '../runtime/executor-tasks.js';
|
|
2
|
+
import { executorScopeTask } from '../runtime/executor-scope-task.js';
|
|
3
|
+
import { versionUnsupported } from '../runtime/dsm-version.js';
|
|
2
4
|
export { executorTasks as rootTasks } from '../runtime/executor-tasks.js';
|
|
3
5
|
/** Exact readback is authoritative. PasswordConfirm tokens are reused immediately,
|
|
4
6
|
* across both Root APIs, and never persisted (DSM validity is about 300 seconds). */
|
|
5
7
|
export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
6
8
|
var eventAPI = "SYNO.Core.EventScheduler", taskAPI = "SYNO.Core.TaskScheduler";
|
|
7
|
-
var busy = null;
|
|
8
|
-
|
|
9
|
+
var busy = null, legacy = false;
|
|
10
|
+
var versionUnsupported = ${versionUnsupported.toString()};
|
|
11
|
+
function fail(code, detail) { var e = new Error(code); e.code = code; if (detail) e.detail = detail; return e; }
|
|
9
12
|
function reason(e) {
|
|
10
13
|
var code = String(e && e.code || "executor_bad_response");
|
|
14
|
+
if (e && e.passwordConfirm) return code + (code === "dsm_3121" ? ": DSM rejected the administrator password." : ": administrator password confirmation failed.") + " Nothing was created.";
|
|
15
|
+
if (e && e.detail) return code + ": " + e.detail;
|
|
11
16
|
return code + (code === "105" || code === "dsm_105" ? ": DSM denied administrator scheduler access. Check the DSM session and scheduler; a NAS restart resolved this on the measured DSM. No automatic retry was made." : ": scheduler readback or operation failed.");
|
|
12
17
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
// AppWindow.sendWebAPI encodes JSON parameters. Preserve their native types;
|
|
19
|
+
// pre-encoding turns objects/booleans into strings and DSM rejects create.
|
|
20
|
+
function send(api, method, version, params) { return options.send(api, method, version, params || {}); }
|
|
21
|
+
// DSM 7.1 has no Root APIs: TaskScheduler stops at list v2 (offset) and get v3.
|
|
22
|
+
// Only an unsupported method version on a read selects that profile, which
|
|
23
|
+
// then creates through the plain scheduler APIs. Writes never fall back.
|
|
24
|
+
function taskRead(method, version, params, legacyVersion, legacyParams) {
|
|
25
|
+
if (legacy) return send(taskAPI, method, legacyVersion, legacyParams);
|
|
26
|
+
return send(taskAPI, method, version, params).catch(function (e) {
|
|
27
|
+
if (!versionUnsupported(e && e.code)) throw e;
|
|
28
|
+
legacy = true;
|
|
29
|
+
return send(taskAPI, method, legacyVersion, legacyParams);
|
|
18
30
|
});
|
|
19
|
-
return encoded;
|
|
20
31
|
}
|
|
21
|
-
function
|
|
32
|
+
function create(boot, params, confirmation) {
|
|
33
|
+
if (legacy) return send(boot ? eventAPI : taskAPI, "create", boot ? 1 : 3, params);
|
|
34
|
+
params.SynoConfirmPWToken = confirmation.token;
|
|
35
|
+
return send(boot ? eventAPI + ".Root" : taskAPI + ".Root", "create", boot ? 1 : 4, params);
|
|
36
|
+
}
|
|
37
|
+
function remove(task, ref) {
|
|
38
|
+
var boot = task.kind === "boot";
|
|
39
|
+
return send(boot ? eventAPI : taskAPI, "delete", boot ? 1 : 2, boot ? ref : {tasks: [ref]});
|
|
40
|
+
}
|
|
22
41
|
function admin() { if (!options.user() || options.user().admin !== true) throw fail("admin_required"); }
|
|
23
42
|
function find(task) {
|
|
24
43
|
var boot = task.kind === "boot";
|
|
25
|
-
return
|
|
44
|
+
return (boot ? send(eventAPI, "list", 1, {}) : taskRead("list", 3, {start: 0, limit: 500}, 2, {offset: 0, limit: 500})).then(function (data) {
|
|
26
45
|
var records = boot ? data : data && data.tasks;
|
|
27
46
|
if (!Array.isArray(records) || records.length > 500 || (!boot && (!Number.isInteger(data.total) || data.total !== records.length))) throw fail("executor_bad_response");
|
|
28
47
|
var named = records.filter(function (r) { return r && (boot ? r.task_name : r.name) === task.name; });
|
|
@@ -31,7 +50,7 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
31
50
|
var summary = named[0];
|
|
32
51
|
if (!boot && !/^[0-9]+$/.test(String(summary.id))) throw fail("executor_bad_response");
|
|
33
52
|
var ref = boot ? {task_name: task.name} : {id: summary.id, real_owner: "root"};
|
|
34
|
-
var detail =
|
|
53
|
+
var detail = boot ? send(eventAPI, "get", 1, ref) : taskRead("get", 4, ref, 3, ref);
|
|
35
54
|
return detail.then(function (r) {
|
|
36
55
|
var owner = r && r.owner;
|
|
37
56
|
var root = owner === "root" || (boot && owner && owner["0"] === "root");
|
|
@@ -54,15 +73,30 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
54
73
|
return result;
|
|
55
74
|
});
|
|
56
75
|
}
|
|
76
|
+
// Removes, newest first, the tasks one approval created and still reads as
|
|
77
|
+
// exactly ours. Resolves with the last refusal's reason, if any.
|
|
78
|
+
function withdraw(created) {
|
|
79
|
+
var failed;
|
|
80
|
+
return created.reduceRight(function (withdrawn, task) {
|
|
81
|
+
return withdrawn.then(function () { return find(task); }).then(function (current) {
|
|
82
|
+
if (current.state === "ready") return remove(task, current.ref);
|
|
83
|
+
}).catch(function (e) { failed = reason(e); });
|
|
84
|
+
}, Promise.resolve()).then(function () { return failed; });
|
|
85
|
+
}
|
|
57
86
|
function definition(task) { return task.kind === "boot" ? (${bootDefinition.toString()})(task) : (${controlDefinition.toString()})(task); }
|
|
58
|
-
function approve(password) {
|
|
87
|
+
function approve(password, selectedScope) {
|
|
88
|
+
var selectionTask;
|
|
89
|
+
if (selectedScope !== undefined) selectionTask = (${executorScopeTask.toString()})(options.pins, selectedScope, options.user() && options.user().name, 0);
|
|
59
90
|
return read().then(function (before) {
|
|
60
91
|
if (before.state === "blocked" || before.state === "unsupported") return before;
|
|
61
|
-
if (before.state === "ready") return start(before);
|
|
62
|
-
return options.confirmPassword(password).
|
|
92
|
+
if (before.state === "ready" && !selectionTask) return start(before);
|
|
93
|
+
return options.confirmPassword(password).catch(function (e) {
|
|
94
|
+
throw {code: e && e.code, passwordConfirm: true};
|
|
95
|
+
}).then(function (confirmation) {
|
|
63
96
|
if (!confirmation || confirmation.confirmed !== true) return {state: "cancelled", tasks: before.tasks};
|
|
64
|
-
|
|
65
|
-
|
|
97
|
+
// DSM 7.1 confirms the password server-side but issues no create token.
|
|
98
|
+
if (!legacy && (typeof confirmation.token !== "string" || !confirmation.token)) throw fail("executor_confirmation_missing");
|
|
99
|
+
var errors = {}, created = [], withdrawFailed;
|
|
66
100
|
// Delete only a verified, same-header outdated task, then create the pinned
|
|
67
101
|
// replacement. set has no measured wire contract. Re-read before each write.
|
|
68
102
|
var chain = Promise.resolve();
|
|
@@ -71,32 +105,106 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
71
105
|
return find(task).then(function (current) {
|
|
72
106
|
if (current.state === "ready") return;
|
|
73
107
|
if (current.state === "blocked") throw fail(current.reason);
|
|
74
|
-
var
|
|
75
|
-
|
|
76
|
-
return removed.then(function () {
|
|
77
|
-
var params = definition(task); params.SynoConfirmPWToken = confirmation.token;
|
|
78
|
-
return send(boot ? eventAPI + ".Root" : taskAPI + ".Root", "create", boot ? 1 : 4, params);
|
|
79
|
-
});
|
|
108
|
+
var removed = current.ref ? remove(task, current.ref) : Promise.resolve();
|
|
109
|
+
return removed.then(function () { return create(task.kind === "boot", definition(task), confirmation); }).then(function () { created.push(task); });
|
|
80
110
|
}).catch(function (e) { errors[task.kind] = reason(e); });
|
|
81
111
|
});
|
|
82
112
|
});
|
|
83
|
-
|
|
113
|
+
// A partial approval must not leave an enabled root bootup task that no
|
|
114
|
+
// control task or uninstall inventory owns: withdraw what it created.
|
|
115
|
+
return chain.then(function () {
|
|
116
|
+
if (Object.keys(errors).length) return withdraw(created).then(function (failed) { withdrawFailed = failed; });
|
|
117
|
+
}).then(read).then(function (after) {
|
|
84
118
|
Object.keys(errors).forEach(function (kind) {
|
|
85
119
|
if (after.tasks[kind].state !== "ready") { after.tasks[kind].state = "blocked"; after.tasks[kind].reason = errors[kind]; after.state = "blocked"; after.reason = errors[kind]; }
|
|
86
120
|
});
|
|
87
|
-
|
|
121
|
+
if (withdrawFailed) { after.state = "blocked"; after.reason = (after.reason ? after.reason + " " : "") + "Withdrawing the tasks this approval created failed: " + withdrawFailed; }
|
|
122
|
+
// A scope change must not restart a running executor: the boot task
|
|
123
|
+
// stops it, which interrupts in-flight copies instead of canceling them.
|
|
124
|
+
return after.state === "ready" ? (selectionTask ? running(after) : Promise.resolve(null)).then(function (live) { return live || start(after); }).then(function (started) {
|
|
125
|
+
// Without a running executor there is no task inventory, so uninstall
|
|
126
|
+
// cannot find these tasks: withdraw what this approval created.
|
|
127
|
+
if (started.state === "ready" || !created.length) return started;
|
|
128
|
+
return withdraw(created).then(function (failed) {
|
|
129
|
+
return read().then(function (current) {
|
|
130
|
+
current.state = "blocked";
|
|
131
|
+
current.reason = started.reason + (failed ? " Withdrawing the tasks this approval created failed: " + failed : " The tasks this approval created were withdrawn.");
|
|
132
|
+
current.retry = !failed;
|
|
133
|
+
return current;
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}).then(function (started) {
|
|
137
|
+
if (!selectionTask || started.state !== "ready") return started;
|
|
138
|
+
var generation = started.executor.selection ? started.executor.selection.generation : 0;
|
|
139
|
+
if (started.executor.selection && (!Number.isSafeInteger(generation) || generation <= 0)) throw fail("executor_selection_invalid");
|
|
140
|
+
selectionTask = (${executorScopeTask.toString()})(options.pins, selectedScope, options.user() && options.user().name, generation);
|
|
141
|
+
// The root task may still land after this reply. requested lets the
|
|
142
|
+
// app converge by readback: applied once status().executor.selection
|
|
143
|
+
// shows this scope above this generation. A resubmit is pinned and safe.
|
|
144
|
+
return selectScope(selectionTask, confirmation, started, selectedScope).catch(function (e) {
|
|
145
|
+
return {state: "blocked", reason: reason(e), tasks: started.tasks, requested: {scope: selectedScope, generation: generation}};
|
|
146
|
+
});
|
|
147
|
+
}) : after;
|
|
88
148
|
});
|
|
89
149
|
});
|
|
90
150
|
});
|
|
91
151
|
}
|
|
92
|
-
function
|
|
152
|
+
function selectScope(task, confirmation, verified, selectedScope) {
|
|
153
|
+
function removeExact() {
|
|
154
|
+
return find(task).then(function (current) {
|
|
155
|
+
if (current.state === "ready") return remove(task, current.ref);
|
|
156
|
+
if (current.ref) throw fail("executor_selection_cleanup_conflict");
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return find(task).then(function (current) {
|
|
160
|
+
if (current.state === "blocked" || current.state === "unsupported") throw fail("executor_selection_conflict");
|
|
161
|
+
var removed = current.ref ? remove(task, current.ref) : Promise.resolve();
|
|
162
|
+
return removed.then(function () { return create(false, definition(task), confirmation); });
|
|
163
|
+
}).then(function () { return find(task); }).then(function (current) {
|
|
164
|
+
if (current.state !== "ready") throw fail("executor_selection_readback_mismatch");
|
|
165
|
+
return send(taskAPI, "run", 2, {tasks: [current.ref]});
|
|
166
|
+
}).then(function () {
|
|
167
|
+
function readSelection(attempts) {
|
|
168
|
+
return health(verified, 0).then(function (current) {
|
|
169
|
+
if (current.state === "ready" && current.executor.selection && current.executor.selection.scope === selectedScope && Number.isSafeInteger(current.executor.selection.generation) && current.executor.selection.generation > 0) return current;
|
|
170
|
+
if (attempts > 1 && options.wait) return options.wait(500).then(function () { verified.state = "ready"; return readSelection(attempts - 1); });
|
|
171
|
+
throw fail("executor_selection_unconfirmed");
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return readSelection(40);
|
|
175
|
+
}).then(function (result) { return removeExact().then(function () { return result; }); }, function (error) {
|
|
176
|
+
return removeExact().then(function () { throw error; });
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// Why a status reply is not the approved, running executor; null when it is.
|
|
180
|
+
function mismatch(status) {
|
|
181
|
+
if (!status || status.ready !== true) return "the approved executor is not answering" + (status && (status.reason || status.state) ? " (" + (status.reason || status.state) + ")" : "") + ".";
|
|
182
|
+
if (!options.pins || status.executor_digest !== options.pins.executorDigest || status.policy_digest !== options.pins.policyDigest) return "the running executor reports other digests than this package pins.";
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
function pinned(status) { return mismatch(status) === null; }
|
|
186
|
+
function running(verified) {
|
|
187
|
+
return options.call("executor.status", {}).then(function (status) {
|
|
188
|
+
if (!pinned(status)) return null;
|
|
189
|
+
verified.executor = status; return verified;
|
|
190
|
+
}, function () { return null; });
|
|
191
|
+
}
|
|
192
|
+
// budget: how long to keep asking after a start (ms). The wait doubles from
|
|
193
|
+
// 500 ms to 2 s so an open window does not poll the executor twice a second.
|
|
194
|
+
function health(verified, budget, delay) {
|
|
93
195
|
if (verified.state !== "ready") return Promise.resolve(verified);
|
|
196
|
+
delay = Math.min(delay || 500, 2000);
|
|
94
197
|
return options.call("executor.status", {}).then(function (status) {
|
|
95
|
-
|
|
198
|
+
var why = mismatch(status);
|
|
199
|
+
if (why) throw fail("executor_status_mismatch", why);
|
|
96
200
|
verified.executor = status; return verified;
|
|
201
|
+
}, function (e) {
|
|
202
|
+
throw fail(e && e.code, "the executor status request failed.");
|
|
97
203
|
}).catch(function (e) {
|
|
98
|
-
if (
|
|
99
|
-
|
|
204
|
+
if (budget >= delay && options.wait) return options.wait(delay).then(function () { return health(verified, budget - delay, delay * 2); });
|
|
205
|
+
// The tasks are approved: approving again runs start, which restarts the
|
|
206
|
+
// executor without a password, so the panel offers it.
|
|
207
|
+
verified.state = "blocked"; verified.reason = reason(e); verified.retry = true; return verified;
|
|
100
208
|
});
|
|
101
209
|
}
|
|
102
210
|
function start(verified) {
|
|
@@ -104,13 +212,17 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
104
212
|
return send(eventAPI, "run", 1, verified.tasks.boot.ref);
|
|
105
213
|
}).then(function () {
|
|
106
214
|
// run can succeed for a nonexistent task. Read both definitions again.
|
|
107
|
-
return read().then(function (after) { return health(after,
|
|
215
|
+
return read().then(function (after) { return health(after, 10000); });
|
|
108
216
|
}).catch(function (e) { verified.state = "blocked"; verified.reason = reason(e); return verified; });
|
|
109
217
|
}
|
|
218
|
+
// The window panel and the app's own settings share this access; each
|
|
219
|
+
// result reaches every view so neither shows a stale state.
|
|
220
|
+
var listeners = [];
|
|
221
|
+
function publish(result) { listeners.forEach(function (listener) { listener(result); }); return result; }
|
|
110
222
|
return {
|
|
111
|
-
status: function () { return read().then(function (verified) { return health(verified,
|
|
112
|
-
authorize: function (password) {
|
|
113
|
-
if (!busy) busy = approve(password).catch(function (e) { return {state: "blocked", reason: reason(e), tasks: {}}; }).then(function (r) { busy = null; return r; });
|
|
223
|
+
status: function () { return read().then(function (verified) { return health(verified, 0); }).then(publish); },
|
|
224
|
+
authorize: function (password, selectedScope) {
|
|
225
|
+
if (!busy) busy = Promise.resolve().then(function () { return approve(password, selectedScope); }).catch(function (e) { return {state: "blocked", reason: reason(e), tasks: {}, retry: !!(e && e.passwordConfirm)}; }).then(function (r) { busy = null; return publish(r); });
|
|
114
226
|
return busy;
|
|
115
227
|
},
|
|
116
228
|
control: function (action) {
|
|
@@ -119,9 +231,10 @@ export const ROOT_RUNTIME = `function createRootAccess(options) {
|
|
|
119
231
|
if (verified.state !== "ready") throw fail("executor_not_ready");
|
|
120
232
|
return options.call("executor.control", {action: action}).then(function () {
|
|
121
233
|
return send(taskAPI, "run", 2, {tasks: [verified.tasks.control.ref]});
|
|
122
|
-
}).then(read).then(function (after) { return action === "start" ? health(after,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
234
|
+
}).then(read).then(function (after) { return action === "start" ? health(after, 10000) : after; });
|
|
235
|
+
}).then(publish);
|
|
236
|
+
},
|
|
237
|
+
subscribe: function (listener) { listeners.push(listener); }
|
|
125
238
|
};
|
|
126
239
|
}`;
|
|
127
240
|
export const ROOT_PANEL = `function mountRootPanel(host, access, i18n, tasks, admin) {
|
|
@@ -129,9 +242,53 @@ export const ROOT_PANEL = `function mountRootPanel(host, access, i18n, tasks, ad
|
|
|
129
242
|
var status = document.createElement("p"), approve = document.createElement("button"), retry = document.createElement("button");
|
|
130
243
|
approve.textContent = "Approve background access"; retry.textContent = "Check status";
|
|
131
244
|
host.appendChild(status); host.appendChild(approve); host.appendChild(retry);
|
|
132
|
-
function show(result) { status.textContent = result.state + (result.reason ? ": " + result.reason : ""); approve.hidden = result.state !== "needs-admin-approval"; }
|
|
245
|
+
function show(result) { status.textContent = result.state + (result.reason ? ": " + result.reason : ""); approve.hidden = result.state !== "needs-admin-approval" && result.retry !== true; }
|
|
133
246
|
function run(fn) { approve.disabled = retry.disabled = true; return fn().then(show, function(e) { show({state: "blocked", reason: e.message || e.code}); }).then(function() { approve.disabled = retry.disabled = false; }); }
|
|
247
|
+
access.subscribe(show);
|
|
134
248
|
approve.onclick = function() { return run(function() { return access.authorize(); }); };
|
|
135
249
|
retry.onclick = function() { return run(function() { return access.status(); }); };
|
|
136
250
|
run(function() { return access.status().then(function(result) { return result.tasks && result.tasks.boot && result.tasks.control && result.tasks.boot.state === "ready" && result.tasks.control.state === "ready" ? access.control("start") : result; }); });
|
|
137
251
|
}`;
|
|
252
|
+
/** Administrator password confirmation in the window's own session: a supplied
|
|
253
|
+
* password, or a masked form when none is given. */
|
|
254
|
+
export const PASSWORD_CONFIRM = `function createPasswordConfirm(win) {
|
|
255
|
+
var versionUnsupported = ${versionUnsupported.toString()};
|
|
256
|
+
function send(password, version) {
|
|
257
|
+
return new Promise(function (resolve, reject) {
|
|
258
|
+
win.sendWebAPI({api: "SYNO.Core.User.PasswordConfirm", method: "auth", version: version, params: {password: password}, scope: win,
|
|
259
|
+
callback: function (success, response) {
|
|
260
|
+
if (!success) reject({code: "dsm_" + ((response && response.code) || "error")});
|
|
261
|
+
else resolve({confirmed: true, token: response && response.SynoConfirmPWToken});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
// DSM 7.1 has PasswordConfirm v1 only, which checks the password but issues no
|
|
267
|
+
// token. Only an unsupported version is retried; a wrong password is not.
|
|
268
|
+
function auth(password) {
|
|
269
|
+
return send(password, 2).catch(function (error) {
|
|
270
|
+
if (!versionUnsupported(error.code)) throw error;
|
|
271
|
+
return send(password, 1);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return function (suppliedPassword) {
|
|
275
|
+
if (typeof suppliedPassword === "string" && suppliedPassword) return auth(suppliedPassword);
|
|
276
|
+
return new Promise(function (resolve, reject) {
|
|
277
|
+
var form = document.createElement("form"), label = document.createElement("label"), input = document.createElement("input");
|
|
278
|
+
var submit = document.createElement("button"), cancel = document.createElement("button");
|
|
279
|
+
label.textContent = "Confirm your DSM administrator password";
|
|
280
|
+
input.type = "password"; input.autocomplete = "current-password"; input.required = true;
|
|
281
|
+
label.appendChild(input); form.appendChild(label);
|
|
282
|
+
submit.type = "submit"; submit.textContent = "Approve"; form.appendChild(submit);
|
|
283
|
+
cancel.type = "button"; cancel.textContent = "Cancel"; form.appendChild(cancel);
|
|
284
|
+
win.body.dom.appendChild(form); input.focus();
|
|
285
|
+
function close() { input.value = ""; if (form.parentNode) form.parentNode.removeChild(form); }
|
|
286
|
+
cancel.onclick = function () { close(); resolve({confirmed: false}); };
|
|
287
|
+
form.onsubmit = function (event) {
|
|
288
|
+
event.preventDefault(); submit.disabled = cancel.disabled = true;
|
|
289
|
+
var password = input.value; input.value = "";
|
|
290
|
+
auth(password).then(function (result) { close(); resolve(result); }, function (error) { close(); reject(error); });
|
|
291
|
+
};
|
|
292
|
+
});
|
|
293
|
+
};
|
|
294
|
+
}`;
|
package/dist/standalone/spk.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface AssembleOptions {
|
|
|
14
14
|
outputPath: string;
|
|
15
15
|
executor?: ExecutorArtifact;
|
|
16
16
|
daemonControl?: string;
|
|
17
|
-
/** The compiled background worker, required exactly when
|
|
17
|
+
/** The compiled background worker, required exactly when capabilities.jobs is enabled. */
|
|
18
18
|
backgroundWorker?: string;
|
|
19
19
|
}
|
|
20
20
|
/**
|
package/dist/standalone/spk.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { metadataInfoFields } from "../package-metadata.js";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
|
|
3
4
|
import { tmpdir } from "node:os";
|
|
@@ -8,6 +9,7 @@ import { renderNativePrivilege } from "../build-spk/native-lifecycle.js";
|
|
|
8
9
|
import { renderUninstallWizardFiles } from "../build-spk/uninstall-wizard.js";
|
|
9
10
|
import { renderInstallWizardFiles, renderNativeInstallWizard } from "../build-spk/install-wizard.js";
|
|
10
11
|
import { writeWizardUiFiles } from "../build-spk/wizard-i18n.js";
|
|
12
|
+
import { renderDelegateScopeSteps } from '../build-spk/delegate-scope.js';
|
|
11
13
|
import { createReproducibleTar } from "../build-spk/reproducible-archive.js";
|
|
12
14
|
import { renderStandaloneScript } from "./lifecycle.js";
|
|
13
15
|
import { DSM_LANGS, LOCALES } from "./i18n.js";
|
|
@@ -17,7 +19,10 @@ import { hostScriptName, renderHostAdapterScript } from "./host-adapter.js";
|
|
|
17
19
|
import { copyDaemonPayload } from "./daemon.js";
|
|
18
20
|
import { BACKGROUND_UNIT_DIR, BACKGROUND_WORKER_PAYLOAD, backgroundUnitName, renderBackgroundUnit } from "./background.js";
|
|
19
21
|
import { renderStandaloneResource } from "./resource.js";
|
|
22
|
+
import { nativePortal } from "./portal.js";
|
|
23
|
+
import { PORTAL_JSON_RELPATH, PORTAL_MUSTACHE_RELPATH, renderPortalJson, renderPortalMustache, renderPortalWizardStep } from "../portal/package.js";
|
|
20
24
|
import { executorPlan } from "../runtime/executor-build.js";
|
|
25
|
+
import { EXECUTOR_ANCHOR } from "../runtime/executor-inspect.js";
|
|
21
26
|
import { renderSharedFolderUpgradeWizardFiles, sharedFolderInstallSteps } from "./shared-folder.js";
|
|
22
27
|
const FILE_MODE = 0o644;
|
|
23
28
|
const EXEC_MODE = 0o755;
|
|
@@ -77,6 +82,11 @@ export async function assembleStandaloneSpk(options) {
|
|
|
77
82
|
copyStandaloneNotices(manifest.root, manifest.ui.dir, join(staging, 'package'), manifest.backend.kind === 'go' || Boolean(manifest.daemon), manifest.backend.kind === 'go' ? manifest.backend.dir : undefined);
|
|
78
83
|
if (manifest.daemon)
|
|
79
84
|
copyFileSync(new URL('../../templates/_shared/LICENSES/TEMPLATE.txt', import.meta.url), join(staging, 'package', 'LICENSES', 'DAEMON-LICENSE.txt'));
|
|
85
|
+
const portal = nativePortal(manifest);
|
|
86
|
+
if (portal) {
|
|
87
|
+
writeFile(join(staging, "package", PORTAL_JSON_RELPATH), renderPortalJson(portal));
|
|
88
|
+
writeFile(join(staging, "package", PORTAL_MUSTACHE_RELPATH), renderPortalMustache());
|
|
89
|
+
}
|
|
80
90
|
if (options.executor) {
|
|
81
91
|
const executorDir = join(staging, "package", "executor");
|
|
82
92
|
mkdirSync(executorDir);
|
|
@@ -93,11 +103,11 @@ export async function assembleStandaloneSpk(options) {
|
|
|
93
103
|
await createReproducibleTar(join(staging, "package"), packageTgz, { gzip: true });
|
|
94
104
|
rmSync(join(staging, "package"), { recursive: true, force: true });
|
|
95
105
|
const checksum = createHash("md5").update(readFileSync(packageTgz)).digest("hex");
|
|
96
|
-
writeFile(join(staging, "sdk-package.json"), JSON.stringify({ schema: 2, backend: manifest.backend.kind, capabilities: Object.keys(manifest.capabilities).sort() }));
|
|
97
|
-
writeFile(join(staging, "INFO"), renderInfo(manifest, options.arch, checksum));
|
|
106
|
+
writeFile(join(staging, "sdk-package.json"), JSON.stringify({ schema: 2, backend: manifest.backend.kind, capabilities: Object.keys(manifest.capabilities).sort(), ...(manifest.entry ? { entry: manifest.entry } : {}) }));
|
|
107
|
+
writeFile(join(staging, "INFO"), renderInfo(manifest, options.arch, checksum, options.executor?.executorDigest));
|
|
98
108
|
mkdirSync(join(staging, "conf"));
|
|
99
109
|
writeFile(join(staging, "conf", "privilege"), renderNativePrivilege());
|
|
100
|
-
const resource = renderStandaloneResource(manifest);
|
|
110
|
+
const resource = renderStandaloneResource(manifest, portal);
|
|
101
111
|
if (resource)
|
|
102
112
|
writeFile(join(staging, "conf", "resource"), resource);
|
|
103
113
|
if (manifest.capabilities.jobs) {
|
|
@@ -109,7 +119,10 @@ export async function assembleStandaloneSpk(options) {
|
|
|
109
119
|
writeFile(join(staging, "scripts", name), renderStandaloneScript(name, manifest), EXEC_MODE);
|
|
110
120
|
}
|
|
111
121
|
const folder = manifest.sharedFolder;
|
|
112
|
-
const
|
|
122
|
+
const steps = manifest.capabilities.delegate?.scope === 'install-selected'
|
|
123
|
+
? (t) => [...renderDelegateScopeSteps(t), ...(folder ? sharedFolderInstallSteps(manifest.package, folder)(t) : [])]
|
|
124
|
+
: folder ? sharedFolderInstallSteps(manifest.package, folder) : renderNativeInstallWizard;
|
|
125
|
+
const install = renderInstallWizardFiles(manifest.package, portal ? (t) => [...steps(t), renderPortalWizardStep(t, portal.alias)] : steps);
|
|
113
126
|
writeWizardUiFiles(staging, {
|
|
114
127
|
...install.static,
|
|
115
128
|
...install.dynamic,
|
|
@@ -130,10 +143,10 @@ function writeFile(path, content, mode = FILE_MODE) {
|
|
|
130
143
|
chmodSync(path, mode);
|
|
131
144
|
}
|
|
132
145
|
function quote(value) {
|
|
133
|
-
return `"${value}"`;
|
|
146
|
+
return `"${value.replace(/([\\"$`])/g, "\\$1")}"`;
|
|
134
147
|
}
|
|
135
148
|
/** Manifest validation already refused quotes, backslashes and newlines. */
|
|
136
|
-
function renderInfo(manifest, arch, checksum) {
|
|
149
|
+
function renderInfo(manifest, arch, checksum, executorDigest) {
|
|
137
150
|
const fields = [
|
|
138
151
|
["package", manifest.package],
|
|
139
152
|
["version", manifest.spkVersion],
|
|
@@ -148,7 +161,12 @@ function renderInfo(manifest, arch, checksum) {
|
|
|
148
161
|
["startable", "yes"],
|
|
149
162
|
["checksum", checksum],
|
|
150
163
|
];
|
|
151
|
-
|
|
164
|
+
// Package Center writes INFO as root; root tasks accept only this executor.
|
|
165
|
+
if (executorDigest)
|
|
166
|
+
fields.push([EXECUTOR_ANCHOR, executorDigest]);
|
|
167
|
+
fields.push(...metadataInfoFields(manifest.metadata));
|
|
168
|
+
// Background packages need prestart: it runs before DSM's systemd-user-unit acquire.
|
|
169
|
+
if (manifest.daemon || manifest.capabilities.jobs)
|
|
152
170
|
fields.push(["precheckstartstop", "yes"]);
|
|
153
171
|
for (const locale of LOCALES) {
|
|
154
172
|
const text = manifest.i18n?.info[locale];
|
|
@@ -28,6 +28,9 @@ type deadlines struct {
|
|
|
28
28
|
Start int `json:"start"`
|
|
29
29
|
Stop int `json:"stop"`
|
|
30
30
|
Status int `json:"status"`
|
|
31
|
+
// Uninstall bounds uninstall_args separately from Stop: a revoke on a
|
|
32
|
+
// loaded NAS can take longer than stopping the daemon.
|
|
33
|
+
Uninstall int `json:"uninstall"`
|
|
31
34
|
}
|
|
32
35
|
type config struct {
|
|
33
36
|
Package string `json:"package"`
|
|
@@ -88,7 +91,7 @@ func load(dest, data string) (*controller, error) {
|
|
|
88
91
|
if cfg.Exec == "" || filepath.IsAbs(cfg.Exec) || filepath.Clean(cfg.Exec) != cfg.Exec || strings.HasPrefix(cfg.Exec, "../") {
|
|
89
92
|
return nil, errors.New("invalid fixed executable")
|
|
90
93
|
}
|
|
91
|
-
if cfg.Timeouts.Start < 2 || cfg.Timeouts.Start > 120 || cfg.Timeouts.Stop < 2 || cfg.Timeouts.Stop > 120 || cfg.Timeouts.Status < 1 || cfg.Timeouts.Status > 10 {
|
|
94
|
+
if cfg.Timeouts.Start < 2 || cfg.Timeouts.Start > 120 || cfg.Timeouts.Stop < 2 || cfg.Timeouts.Stop > 120 || cfg.Timeouts.Status < 1 || cfg.Timeouts.Status > 10 || cfg.Timeouts.Uninstall < 2 || cfg.Timeouts.Uninstall > 120 {
|
|
92
95
|
return nil, errors.New("invalid daemon deadlines")
|
|
93
96
|
}
|
|
94
97
|
hash := sha256.Sum256(raw)
|
|
@@ -162,7 +165,7 @@ func (c *controller) run(action string) (int, error) {
|
|
|
162
165
|
budget += c.Timeouts.Start
|
|
163
166
|
}
|
|
164
167
|
if action == "uninstall" {
|
|
165
|
-
budget += c.Timeouts.
|
|
168
|
+
budget += c.Timeouts.Uninstall + 2
|
|
166
169
|
}
|
|
167
170
|
if action != "start" && action != "stop" && action != "status" && action != "restart" && action != "uninstall" {
|
|
168
171
|
return 1, errors.New("unsupported daemon action")
|
|
@@ -414,7 +417,7 @@ func (c *controller) uninstall() error {
|
|
|
414
417
|
select {
|
|
415
418
|
case err := <-done:
|
|
416
419
|
return err
|
|
417
|
-
case <-time.After(time.Duration(c.Timeouts.
|
|
420
|
+
case <-time.After(time.Duration(c.Timeouts.Uninstall) * time.Second):
|
|
418
421
|
cmd.Process.Signal(syscall.SIGTERM)
|
|
419
422
|
}
|
|
420
423
|
select {
|
|
@@ -41,10 +41,16 @@ func fixture(t *testing.T, mode string) (string, string, string) {
|
|
|
41
41
|
if err != nil {
|
|
42
42
|
t.Fatal(err)
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
app := filepath.Join(dest, "daemon/payload/app")
|
|
45
|
+
if err := os.WriteFile(app, raw, 0755); err != nil {
|
|
45
46
|
t.Fatal(err)
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
// macOS verifies a newly written executable on its first exec, which takes
|
|
49
|
+
// seconds on a loaded host; pay it here, not inside a one-second budget.
|
|
50
|
+
if raw, err := exec.Command(app, "cleanup").CombinedOutput(); err != nil {
|
|
51
|
+
t.Fatalf("payload warm-up: %v %s", err, raw)
|
|
52
|
+
}
|
|
53
|
+
cfg := config{Package: "DaemonFixture", Exec: "app", Args: []string{"${SYNOPKG_PKGVAR}/a space", "$(touch BAD)'", "${SYNOPKG_PKGDEST}"}, Env: map[string]string{"APP_MODE": mode}, Timeouts: deadlines{Start: 2, Stop: 2, Status: 1, Uninstall: 2}}
|
|
48
54
|
if os.Geteuid() == 0 {
|
|
49
55
|
cfg.Package = "nobody"
|
|
50
56
|
} else {
|
|
@@ -91,22 +97,69 @@ func runControl(control, action, dest, data string) (int, string) {
|
|
|
91
97
|
return -1, err.Error()
|
|
92
98
|
}
|
|
93
99
|
|
|
100
|
+
// Readiness only proves the child stayed alive for a second, not that it reached
|
|
101
|
+
// main: on a loaded host a stop can kill it before it writes its line. Spawn
|
|
102
|
+
// identity therefore comes from the inventory, and log content is awaited.
|
|
103
|
+
func recordedChild(t *testing.T, data string) int {
|
|
104
|
+
t.Helper()
|
|
105
|
+
raw, err := os.ReadFile(filepath.Join(data, "daemon/daemon.pid"))
|
|
106
|
+
if err != nil {
|
|
107
|
+
t.Fatal(err)
|
|
108
|
+
}
|
|
109
|
+
var r record
|
|
110
|
+
if err := json.Unmarshal(raw, &r); err != nil || r.Child < 1 {
|
|
111
|
+
t.Fatalf("daemon inventory: %v %s", err, raw)
|
|
112
|
+
}
|
|
113
|
+
return r.Child
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func awaitChildLines(t *testing.T, data string, want int) {
|
|
117
|
+
t.Helper()
|
|
118
|
+
path := filepath.Join(data, "daemon/daemon.log")
|
|
119
|
+
for deadline := time.Now().Add(10 * time.Second); ; time.Sleep(20 * time.Millisecond) {
|
|
120
|
+
raw, _ := os.ReadFile(path)
|
|
121
|
+
if got := strings.Count(string(raw), `"uid":`); got >= want || time.Now().After(deadline) {
|
|
122
|
+
if got != want {
|
|
123
|
+
t.Fatalf("child lines=%d want=%d: %s", got, want, raw)
|
|
124
|
+
}
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
94
130
|
func TestDaemonLifecycle(t *testing.T) {
|
|
95
131
|
control, dest, data := fixture(t, "normal")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
want
|
|
99
|
-
|
|
100
|
-
if rc, out := runControl(control, step.action, dest, data); rc != step.want {
|
|
101
|
-
t.Fatalf("%s rc=%d want=%d: %s", step.action, rc, step.want, out)
|
|
132
|
+
step := func(action string, want int) {
|
|
133
|
+
t.Helper()
|
|
134
|
+
if rc, out := runControl(control, action, dest, data); rc != want {
|
|
135
|
+
t.Fatalf("%s rc=%d want=%d: %s", action, rc, want, out)
|
|
102
136
|
}
|
|
103
137
|
}
|
|
138
|
+
step("status", 3)
|
|
139
|
+
step("stop", 0)
|
|
140
|
+
step("start", 0)
|
|
141
|
+
awaitChildLines(t, data, 1)
|
|
142
|
+
first := recordedChild(t, data)
|
|
143
|
+
step("status", 0)
|
|
144
|
+
step("start", 0)
|
|
145
|
+
if child := recordedChild(t, data); child != first {
|
|
146
|
+
t.Fatalf("duplicate start spawned another child: %d replaced %d", child, first)
|
|
147
|
+
}
|
|
148
|
+
step("restart", 0)
|
|
149
|
+
if child := recordedChild(t, data); child == first {
|
|
150
|
+
t.Fatalf("restart kept child %d", child)
|
|
151
|
+
}
|
|
152
|
+
awaitChildLines(t, data, 2)
|
|
153
|
+
step("stop", 0)
|
|
154
|
+
step("stop", 0)
|
|
155
|
+
step("status", 3)
|
|
156
|
+
step("unknown", 1)
|
|
104
157
|
raw, err := os.ReadFile(filepath.Join(data, "daemon/daemon.log"))
|
|
105
158
|
if err != nil {
|
|
106
159
|
t.Fatal(err)
|
|
107
160
|
}
|
|
108
161
|
if strings.Count(string(raw), `"uid":`) != 2 {
|
|
109
|
-
t.Fatalf("
|
|
162
|
+
t.Fatalf("unexpected child spawn: %s", raw)
|
|
110
163
|
}
|
|
111
164
|
if strings.Contains(string(raw), "must-not-leak") {
|
|
112
165
|
t.Fatalf("ambient environment leaked: %s", raw)
|
|
@@ -197,6 +250,26 @@ func TestUninstallCleanup(t *testing.T) {
|
|
|
197
250
|
}
|
|
198
251
|
}
|
|
199
252
|
|
|
253
|
+
// A revoke on uninstall can outlast the stop deadline on a loaded NAS; it has
|
|
254
|
+
// its own budget instead of Stop-1.
|
|
255
|
+
func TestUninstallCommandHasItsOwnBudget(t *testing.T) {
|
|
256
|
+
control, dest, data := fixture(t, "normal")
|
|
257
|
+
path := filepath.Join(dest, "daemon/config.json")
|
|
258
|
+
raw, _ := os.ReadFile(path)
|
|
259
|
+
var cfg config
|
|
260
|
+
json.Unmarshal(raw, &cfg)
|
|
261
|
+
cfg.UninstallArgs = []string{"cleanup-slow"}
|
|
262
|
+
cfg.Timeouts.Uninstall = 5
|
|
263
|
+
raw, _ = json.Marshal(cfg)
|
|
264
|
+
os.WriteFile(path, raw, 0644)
|
|
265
|
+
if rc, out := runControl(control, "start", dest, data); rc != 0 {
|
|
266
|
+
t.Fatalf("start: %d %s", rc, out)
|
|
267
|
+
}
|
|
268
|
+
if rc, out := runControl(control, "uninstall", dest, data); rc != 0 {
|
|
269
|
+
t.Fatalf("slow uninstall within its budget failed: %d %s", rc, out)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
200
273
|
func TestPackageAccountIdentity(t *testing.T) {
|
|
201
274
|
control, dest, data := fixture(t, "normal")
|
|
202
275
|
path := filepath.Join(dest, "daemon/config.json")
|