@synopackageland/cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +613 -0
- package/README.md +81 -89
- package/dist/add.js +39 -16
- 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 +39 -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.d.ts +1 -1
- package/dist/build-spk/gateway.js +2 -2
- package/dist/build-spk/generator.js +30 -5
- 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 +15 -7
- 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/plan.js +1 -1
- package/dist/deploy/spk-version.js +1 -1
- package/dist/error-registry.js +43 -15
- package/dist/host/dsm-client.d.ts +8 -4
- package/dist/host/dsm-client.js +10 -4
- package/dist/host/types.d.ts +2 -1
- package/dist/info.js +18 -2
- package/dist/init.d.ts +3 -0
- package/dist/init.js +49 -18
- 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/executor-build.d.ts +1 -1
- package/dist/runtime/executor-build.js +5 -4
- 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 -1
- package/dist/standalone/daemon.js +2 -1
- package/dist/standalone/dsm-window.d.ts +3 -1
- package/dist/standalone/dsm-window.js +72 -15
- package/dist/standalone/inspect-spk.d.ts +8 -0
- package/dist/standalone/inspect-spk.js +105 -26
- 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 +2 -0
- package/dist/standalone/native-layout.d.ts +3 -0
- package/dist/standalone/native-layout.js +37 -5
- 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.js +62 -15
- package/dist/standalone/spk.d.ts +1 -1
- package/dist/standalone/spk.js +25 -7
- package/dist/templates/_daemon/main_test.go +61 -8
- package/dist/templates/_executor/README.md +127 -16
- package/dist/templates/_executor/anchor.go +146 -0
- package/dist/templates/_executor/anchor_test.go +126 -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/dsm.go +23 -10
- 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/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 +72 -20
- 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/platform_linux.go +24 -173
- package/dist/templates/_executor/platform_linux_test.go +9 -65
- package/dist/templates/_executor/platform_other.go +30 -4
- package/dist/templates/_executor/process.go +3 -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 +7 -8
- package/dist/templates/_executor/tasks_review_test.go +1 -1
- package/dist/templates/_executor/tasks_test.go +4 -4
- 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/_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/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/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/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/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-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 +52 -8
- 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-setup.ts +4 -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 +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -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 +46 -0
- package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -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/main_test.go +61 -8
- package/templates/_executor/README.md +127 -16
- package/templates/_executor/anchor.go +146 -0
- package/templates/_executor/anchor_test.go +126 -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/dsm.go +23 -10
- 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/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 +72 -20
- 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/platform_linux.go +24 -173
- package/templates/_executor/platform_linux_test.go +9 -65
- package/templates/_executor/platform_other.go +30 -4
- package/templates/_executor/process.go +3 -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 +7 -8
- package/templates/_executor/tasks_review_test.go +1 -1
- package/templates/_executor/tasks_test.go +4 -4
- 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/_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/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/sdk_policy_test.go +39 -0
- package/templates/native-go/backend/internal/filestation/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/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-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 +52 -8
- 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-setup.ts +4 -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 +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
- package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -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 +46 -0
- package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -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,27 +1,56 @@
|
|
|
1
|
-
import { renderBackgroundControl, backgroundUnitName } from "./background.js";
|
|
1
|
+
import { renderBackgroundControl, renderBackgroundWorkerStart, renderBackgroundWorkerStop, renderUserManagerRecovery, backgroundUnitName } from "./background.js";
|
|
2
2
|
import { renderPackagePostuninst } from "../build-spk/native-lifecycle.js";
|
|
3
3
|
import { renderSharedFolderScript } from "./shared-folder.js";
|
|
4
|
+
import { renderDelegateInstallDraft } from '../build-spk/delegate-scope.js';
|
|
5
|
+
import { renderPortalLifecycle } from "../portal/package.js";
|
|
6
|
+
import { nativePortal } from "./portal.js";
|
|
4
7
|
/** Package-account lifecycle hooks for CGI, daemon and background packages. */
|
|
5
8
|
export function renderStandaloneScript(name, manifest) {
|
|
9
|
+
const portal = nativePortal(manifest);
|
|
10
|
+
const script = renderCapabilityScript(name, manifest);
|
|
11
|
+
return portal ? script.replace("#!/bin/sh\n", () => `#!/bin/sh\n${renderPortalLifecycle(name, portal)}`) : script;
|
|
12
|
+
}
|
|
13
|
+
function renderCapabilityScript(name, manifest) {
|
|
14
|
+
if (name === 'preupgrade' && (manifest.capabilities.rootOps || manifest.capabilities.delegate)) {
|
|
15
|
+
const installed = `\${SYNOPKG_PKGDEST:-/var/packages/${manifest.package}/target}`;
|
|
16
|
+
// Incoming preupgrade sees the OLD payload. Only complete absence is first
|
|
17
|
+
// introduction; a partial or symlinked executor must still fail closed.
|
|
18
|
+
const legacy = manifest.daemon
|
|
19
|
+
? ` if [ -e "${installed}/daemon" ] || [ -L "${installed}/daemon" ]; then\n "${installed}/daemon/control" stop "${installed}" "\${SYNOPKG_PKGVAR:-/var/packages/${manifest.package}/var}" || exit $?\n fi\n`
|
|
20
|
+
: '';
|
|
21
|
+
return renderStandaloneScriptBody(name, manifest).replace('#!/bin/sh\n', `#!/bin/sh\nif [ ! -e "${installed}/executor" ] && [ ! -L "${installed}/executor" ]; then\n${legacy} exit 0\nfi\n`);
|
|
22
|
+
}
|
|
23
|
+
return renderStandaloneScriptBody(name, manifest);
|
|
24
|
+
}
|
|
25
|
+
function renderStandaloneScriptBody(name, manifest) {
|
|
26
|
+
if (manifest.capabilities?.delegate?.scope === 'install-selected' && ['preinst', 'postinst'].includes(name)) {
|
|
27
|
+
const normal = renderCapabilityScript(name, { ...manifest, capabilities: { ...manifest.capabilities, delegate: { ...manifest.capabilities.delegate, scope: 'home' } } });
|
|
28
|
+
return normal.replace('#!/bin/sh\n', () => '#!/bin/sh\n' + renderDelegateInstallDraft(manifest.package, name === 'preinst'));
|
|
29
|
+
}
|
|
30
|
+
if (manifest.daemon && manifest.capabilities?.jobs && (manifest.capabilities.delegate || manifest.capabilities.rootOps)
|
|
31
|
+
&& ['start-stop-status', 'preupgrade', 'preuninst'].includes(name))
|
|
32
|
+
return renderDelegatedDaemonScript(name, manifest);
|
|
6
33
|
if ((manifest.capabilities?.rootOps || manifest.capabilities?.delegate) && ["preuninst", "preupgrade", "start-stop-status"].includes(name)) {
|
|
7
34
|
const helper = `"\${SYNOPKG_PKGDEST:-/var/packages/${manifest.package}/target}/executor/lifecycle"`;
|
|
8
|
-
|
|
35
|
+
// Attempt worker stop first, but let executor shutdown drain requests and
|
|
36
|
+
// close ingress even when it fails; a still-running worker fails the hook.
|
|
37
|
+
const workerStop = manifest.capabilities.jobs ? renderBackgroundWorkerStop(manifest.package) : "";
|
|
38
|
+
const stopWorker = manifest.capabilities.jobs ? "worker_result=0\nstop_background_worker || worker_result=1\n" : "";
|
|
39
|
+
const workerResult = manifest.capabilities.jobs ? 'exit "$worker_result"\n' : "exit 0\n";
|
|
9
40
|
const request = (action) => `${helper} ${action} --package ${manifest.package} || exit $?\n`;
|
|
10
41
|
if (name === "start-stop-status") {
|
|
11
|
-
const normal =
|
|
12
|
-
// Attempt worker stop first. DSM may have already stopped it or deny this
|
|
13
|
-
// lifecycle context; executor shutdown drains requests and closes ingress.
|
|
42
|
+
const normal = renderCapabilityScript(name, { ...manifest, capabilities: { ...manifest.capabilities, rootOps: undefined, delegate: undefined } });
|
|
14
43
|
const stopDaemon = manifest.daemon ? `"/var/packages/${manifest.package}/target/daemon/control" stop "\${SYNOPKG_PKGDEST:-/var/packages/${manifest.package}/target}" "\${SYNOPKG_PKGVAR:-/var/packages/${manifest.package}/var}" || exit $?\n` : "";
|
|
15
|
-
return normal.replace("#!/bin/sh\n", `#!/bin/sh\
|
|
44
|
+
return normal.replace("#!/bin/sh\n", `#!/bin/sh\n${workerStop}if [ "$1" = start ]; then\n${request("start")}fi\nif [ "$1" = stop ]; then\n${stopWorker}${stopDaemon}${request("stop")}${workerResult}fi\n`);
|
|
16
45
|
}
|
|
17
46
|
const action = name === "preuninst" ? '"$action"' : "stop";
|
|
18
47
|
const choose = name === "preuninst" ? 'action=purge\n[ "${SYNOPKG_PKG_STATUS:-}" != UPGRADE ] || action=stop\n' : "";
|
|
19
|
-
return `#!/bin/sh\n${stopWorker}${choose}${request(action)}${manifest.daemon ? renderDaemonScript(name, manifest).replace("#!/bin/sh\n", "") :
|
|
48
|
+
return `#!/bin/sh\n${workerStop}${stopWorker}${choose}${request(action)}${manifest.daemon ? renderDaemonScript(name, manifest).replace("#!/bin/sh\n", "") : workerResult}`;
|
|
20
49
|
}
|
|
21
50
|
if (name === "postuninst")
|
|
22
51
|
return renderPackagePostuninst(manifest.package);
|
|
23
52
|
if ((manifest.capabilities?.rootOps || manifest.capabilities?.delegate) && ["postinst", "postupgrade"].includes(name)) {
|
|
24
|
-
const normal =
|
|
53
|
+
const normal = renderCapabilityScript(name, { ...manifest, capabilities: { ...manifest.capabilities, rootOps: undefined, delegate: undefined } });
|
|
25
54
|
return normal.replace("#!/bin/sh\n", `#!/bin/sh\n"\${SYNOPKG_PKGDEST:-/var/packages/${manifest.package}/target}/executor/lifecycle" start --package ${manifest.package} || exit $?\n`);
|
|
26
55
|
}
|
|
27
56
|
if (manifest.sharedFolder && (name === "postinst" || name === "postupgrade"))
|
|
@@ -40,6 +69,55 @@ esac
|
|
|
40
69
|
}
|
|
41
70
|
return "#!/bin/sh\nexit 0\n";
|
|
42
71
|
}
|
|
72
|
+
/** DSM owns the single user unit; the daemon controller owns only its producer. */
|
|
73
|
+
function renderDelegatedDaemonScript(name, manifest) {
|
|
74
|
+
const pkg = manifest.package;
|
|
75
|
+
const daemon = `"/var/packages/${pkg}/target/daemon/control"`;
|
|
76
|
+
const paths = `"\${SYNOPKG_PKGDEST:-/var/packages/${pkg}/target}" "\${SYNOPKG_PKGVAR:-/var/packages/${pkg}/var}"`;
|
|
77
|
+
const helper = `"\${SYNOPKG_PKGDEST:-/var/packages/${pkg}/target}/executor/lifecycle"`;
|
|
78
|
+
const executor = (action) => `${helper} ${action} --package ${pkg}`;
|
|
79
|
+
const worker = (action) => `/usr/syno/bin/synosystemctl ${action} ${backgroundUnitName(pkg)}`;
|
|
80
|
+
// Try every owner even on failure; never leave protected ingress open merely
|
|
81
|
+
// because a producer could not stop. A partial teardown remains a failure.
|
|
82
|
+
const stop = (daemonAction, executorAction) => `result=0\nstop_background_worker || result=1\n${daemon} ${daemonAction} ${paths} || result=1\n${executor(executorAction)} || result=1\nexit "$result"\n`;
|
|
83
|
+
const workerStop = renderBackgroundWorkerStop(pkg);
|
|
84
|
+
if (name !== 'start-stop-status') {
|
|
85
|
+
if (name === 'preupgrade')
|
|
86
|
+
return `#!/bin/sh\n${workerStop}${stop('stop', 'stop')}`;
|
|
87
|
+
return `#!/bin/sh\n${workerStop}if [ "\${SYNOPKG_PKG_STATUS:-}" = UPGRADE ]; then\n${stop('stop', 'stop')}fi\n${stop(manifest.daemon?.uninstall_args ? 'uninstall' : 'stop', 'purge')}`;
|
|
88
|
+
}
|
|
89
|
+
return `#!/bin/sh
|
|
90
|
+
${workerStop}${renderUserManagerRecovery()}${renderBackgroundWorkerStart(pkg)}case "$1" in
|
|
91
|
+
prestart) recover_user_manager ;;
|
|
92
|
+
prestop) exit 0 ;;
|
|
93
|
+
start)
|
|
94
|
+
${executor('start')} || exit $?
|
|
95
|
+
if ! ${daemon} start ${paths}; then
|
|
96
|
+
${daemon} stop ${paths}
|
|
97
|
+
${executor('stop')}
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
if ! start_background_worker; then
|
|
101
|
+
${worker('stop')}
|
|
102
|
+
${daemon} stop ${paths}
|
|
103
|
+
${executor('stop')}
|
|
104
|
+
exit 1
|
|
105
|
+
fi
|
|
106
|
+
exit 0 ;;
|
|
107
|
+
status)
|
|
108
|
+
${daemon} status ${paths} || exit $?
|
|
109
|
+
worker_state="$(${worker('get-active-status')})" || exit 3
|
|
110
|
+
[ "$worker_state" = active ] && exit 0
|
|
111
|
+
exit 3 ;;
|
|
112
|
+
stop)
|
|
113
|
+
${stop('stop', 'stop')} ;;
|
|
114
|
+
restart)
|
|
115
|
+
"$0" stop || exit $?
|
|
116
|
+
exec "$0" start ;;
|
|
117
|
+
*) exit 1 ;;
|
|
118
|
+
esac
|
|
119
|
+
`;
|
|
120
|
+
}
|
|
43
121
|
function renderDaemonScript(name, manifest) {
|
|
44
122
|
const pkg = manifest.package;
|
|
45
123
|
const control = `"/var/packages/${pkg}/target/daemon/control"`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PackageMetadata } from "../package-metadata.js";
|
|
1
2
|
import { type DelegateCapability } from "../runtime/executor-policy.js";
|
|
2
3
|
import type { ExecutorPins } from "../runtime/executor-tasks.js";
|
|
3
4
|
import { type NativeArchFamily } from "../build-spk/dsm-arch.js";
|
|
@@ -7,6 +8,7 @@ import { type Daemon } from "./daemon.js";
|
|
|
7
8
|
import { type Background } from "./background.js";
|
|
8
9
|
import { type SharedFolder } from "./shared-folder.js";
|
|
9
10
|
import { type ApiPermissions } from "./api-permissions.js";
|
|
11
|
+
import { type PortalDeclaration } from "../portal/alias.js";
|
|
10
12
|
/**
|
|
11
13
|
* `dsm-package.yaml`: a Standalone Package, i.e. an unsigned native SPK that
|
|
12
14
|
* runs as its own DSM package account with a CGI backend and a DSM window UI.
|
|
@@ -31,6 +33,7 @@ export interface StandaloneI18n {
|
|
|
31
33
|
info: Partial<Record<Locale, InfoText>>;
|
|
32
34
|
}
|
|
33
35
|
export interface StandaloneManifest {
|
|
36
|
+
metadata?: PackageMetadata;
|
|
34
37
|
root: string;
|
|
35
38
|
package: string;
|
|
36
39
|
version: string;
|
|
@@ -62,7 +65,16 @@ export interface StandaloneManifest {
|
|
|
62
65
|
daemon?: Daemon;
|
|
63
66
|
/** `install.sharedFolder`: the Shared Folder the install wizard selects or `data-share` creates. */
|
|
64
67
|
sharedFolder?: SharedFolder;
|
|
68
|
+
/** Who may use the app at all; absent keeps the route policy alone. */
|
|
69
|
+
entry?: EntryMode;
|
|
70
|
+
/** `portal`: registers the DSM Application Portal entry; an administrator activates it. */
|
|
71
|
+
portal?: PortalDeclaration;
|
|
65
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* `admin-only`: DSM administrators only. `app-privilege`: administrators and
|
|
75
|
+
* accounts DSM's Control Panel > Application Privileges allows for the app.
|
|
76
|
+
*/
|
|
77
|
+
export type EntryMode = "admin-only" | "app-privilege";
|
|
66
78
|
export interface Capabilities {
|
|
67
79
|
files?: "session";
|
|
68
80
|
identity?: "standalone";
|
|
@@ -81,6 +93,7 @@ export type ManifestResult = {
|
|
|
81
93
|
ok: false;
|
|
82
94
|
errors: StandaloneError[];
|
|
83
95
|
};
|
|
96
|
+
export declare const KNOWN_FIELDS: Set<string>;
|
|
84
97
|
export declare function loadStandaloneManifest(root: string): ManifestResult;
|
|
85
98
|
/**
|
|
86
99
|
* The nearest directory at or above `start` that holds dsm-package.yaml,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateMetadata } from "../package-metadata.js";
|
|
1
2
|
import { validDelegate } from "../runtime/executor-policy.js";
|
|
2
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
4
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -7,17 +8,18 @@ import { checkGlossary, isLocale, loadCatalogs } from "./i18n.js";
|
|
|
7
8
|
import { loadRootOps, ROOT_OPS_DIR } from "./root-ops.js";
|
|
8
9
|
import { readDaemon } from "./daemon.js";
|
|
9
10
|
import { readBackground } from "./background.js";
|
|
10
|
-
import { DEFAULT_MIN_DSM, isDsmAtLeast } from "../build-spk/dsm-version.js";
|
|
11
|
+
import { DEFAULT_MIN_DSM, isDsmAtLeast, PORTAL_MIN_DSM, portalMinDsmMessage } from "../build-spk/dsm-version.js";
|
|
11
12
|
import { readSharedFolder } from "./shared-folder.js";
|
|
12
|
-
import { readApiPermissions } from "./api-permissions.js";
|
|
13
|
+
import { floorAtAdministrators, permitsOrdinaryUsers, readApiPermissions } from "./api-permissions.js";
|
|
14
|
+
import { readPortalDeclaration } from "../portal/alias.js";
|
|
13
15
|
/**
|
|
14
16
|
* `dsm-package.yaml`: a Standalone Package, i.e. an unsigned native SPK that
|
|
15
17
|
* runs as its own DSM package account with a CGI backend and a DSM window UI.
|
|
16
18
|
*/
|
|
17
19
|
export const STANDALONE_MANIFEST = "dsm-package.yaml";
|
|
18
|
-
const KNOWN_FIELDS = new Set([
|
|
20
|
+
export const KNOWN_FIELDS = new Set([
|
|
19
21
|
"schema", "package", "version", "build", "displayname", "description",
|
|
20
|
-
"maintainer", "os_min_ver", "arches", "backend", "ui", "capabilities", "i18n", "daemon", "install",
|
|
22
|
+
"metadata", "maintainer", "os_min_ver", "arches", "backend", "ui", "capabilities", "i18n", "daemon", "install", "entry", "portal",
|
|
21
23
|
]);
|
|
22
24
|
const I18N_FIELDS = new Set(["messages", "glossary", "info"]);
|
|
23
25
|
const INFO_TEXT_FIELDS = new Set(["displayname", "description"]);
|
|
@@ -108,6 +110,14 @@ function readManifest(raw, c) {
|
|
|
108
110
|
const displayname = c.text(raw.displayname, "displayname");
|
|
109
111
|
const description = c.text(raw.description, "description");
|
|
110
112
|
const maintainer = c.text(raw.maintainer, "maintainer");
|
|
113
|
+
let metadata;
|
|
114
|
+
if (raw.metadata !== undefined)
|
|
115
|
+
try {
|
|
116
|
+
metadata = validateMetadata(raw.metadata);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
c.fail("STANDALONE_TEXT_INVALID", "metadata 欄位格式不正確;請檢查文字、email、URLs 與 screenshots。");
|
|
120
|
+
}
|
|
111
121
|
const arches = readArches(raw.arches, c);
|
|
112
122
|
const backend = arches && readBackend(raw.backend, arches, c);
|
|
113
123
|
let permissions;
|
|
@@ -120,8 +130,8 @@ function readManifest(raw, c) {
|
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
const daemon = arches && readDaemon(raw.daemon, c.root, arches, e => c.fail(e.code, e.message));
|
|
123
|
-
if (capabilities.jobs && raw.daemon !== undefined) {
|
|
124
|
-
c.fail("CAPABILITY_COMBINATION_INVALID", "daemon
|
|
133
|
+
if (capabilities.jobs && raw.daemon !== undefined && capabilities.delegate?.lifetime !== 'until-revoked') {
|
|
134
|
+
c.fail("CAPABILITY_COMBINATION_INVALID", "daemon 僅可與明確 until-revoked delegate 的固定 worker 共存;一般 capabilities.jobs 仍互斥。");
|
|
125
135
|
}
|
|
126
136
|
if (backend?.kind === "binary") {
|
|
127
137
|
for (const name of ["files", "jobs", "identity", "delegate"]) {
|
|
@@ -130,10 +140,25 @@ function readManifest(raw, c) {
|
|
|
130
140
|
}
|
|
131
141
|
}
|
|
132
142
|
const sharedFolder = raw.install === undefined ? undefined : readSharedFolder(raw.install, e => c.fail(e.code, e.message));
|
|
143
|
+
const entry = raw.entry === undefined ? undefined : readEntry(raw.entry, backend, permissions?.policy, c);
|
|
144
|
+
if (entry === "admin-only" && permissions) {
|
|
145
|
+
const floored = floorAtAdministrators(permissions.policy);
|
|
146
|
+
if (floored.widened.length) {
|
|
147
|
+
c.fail("STANDALONE_ENTRY_WIDENED", `entry: admin-only 以管理員為所有 route 的下限;permissions.json 的 ${floored.widened.join("、")} 會開放給其他人。請改為 administrators,或改用 entry: app-privilege/省略 entry。`);
|
|
148
|
+
}
|
|
149
|
+
permissions.policy = floored.policy;
|
|
150
|
+
}
|
|
133
151
|
const ui = readUi(raw.ui, c);
|
|
134
152
|
if (capabilities.identity && ui && !ui.build)
|
|
135
153
|
c.fail("CAPABILITY_COMBINATION_INVALID", "capabilities.identity 需要獨立登入頁;plain UI 不支援,請改用 vue UI(init --ui vue)。");
|
|
154
|
+
if (capabilities.delegate?.scope === "install-selected" && ui && !ui.build)
|
|
155
|
+
c.fail("CAPABILITY_COMBINATION_INVALID", "delegate scope install-selected 只能在 Vue 面板確認;plain UI 不支援,請改用 vue UI(init --ui vue)。");
|
|
136
156
|
const i18n = raw.i18n === undefined ? undefined : readI18n(raw.i18n, c);
|
|
157
|
+
const portal = raw.portal === undefined || !packageId ? undefined : readPortalDeclaration(raw.portal, packageId)
|
|
158
|
+
?? c.fail("STANDALONE_PORTAL_INVALID", "portal 必須是 {} 或 { alias: <小寫英數與 -,1–64 字,不可為 DSM 保留路徑> }。");
|
|
159
|
+
if (portal && osMinVer && !isDsmAtLeast(osMinVer, PORTAL_MIN_DSM)) {
|
|
160
|
+
c.fail("STANDALONE_PORTAL_MIN_DSM", portalMinDsmMessage(osMinVer, "portal"));
|
|
161
|
+
}
|
|
137
162
|
if (!packageId || !version || !build || !osMinVer || !displayname || !description || !maintainer
|
|
138
163
|
|| !arches || !backend || !ui || (capabilities.rootOps === true && !rootOps)) {
|
|
139
164
|
return undefined;
|
|
@@ -147,6 +172,7 @@ function readManifest(raw, c) {
|
|
|
147
172
|
displayname,
|
|
148
173
|
description,
|
|
149
174
|
maintainer,
|
|
175
|
+
...(metadata ? { metadata } : {}),
|
|
150
176
|
os_min_ver: osMinVer,
|
|
151
177
|
arches,
|
|
152
178
|
backend,
|
|
@@ -157,8 +183,31 @@ function readManifest(raw, c) {
|
|
|
157
183
|
...(rootOps ? { rootOps } : {}),
|
|
158
184
|
...(daemon ? { daemon } : {}),
|
|
159
185
|
...(sharedFolder ? { sharedFolder } : {}),
|
|
186
|
+
...(entry ? { entry } : {}),
|
|
187
|
+
...(portal ? { portal } : {}),
|
|
160
188
|
};
|
|
161
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* The CGI enforces the entry mode only when the project's backend carries the
|
|
192
|
+
* SDK gate and main wires it; `-X main.entry` on an older main would be
|
|
193
|
+
* silently dropped and leave a registered app ungated.
|
|
194
|
+
*/
|
|
195
|
+
function readEntry(value, backend, policy, c) {
|
|
196
|
+
if (value !== "admin-only" && value !== "app-privilege") {
|
|
197
|
+
return c.fail("STANDALONE_ENTRY_INVALID", "entry 必須是 admin-only 或 app-privilege;省略則維持既有 permissions.json 行為。");
|
|
198
|
+
}
|
|
199
|
+
if (!backend)
|
|
200
|
+
return undefined;
|
|
201
|
+
const main = backend.kind === "go" ? join(backend.dir, backend.main, "main.go") : "";
|
|
202
|
+
if (backend.kind !== "go" || !existsSync(join(backend.dir, "internal/dsm/entry.go"))
|
|
203
|
+
|| !existsSync(main) || !readFileSync(main, "utf8").includes("dsm.NewEntryGate(")) {
|
|
204
|
+
return c.fail("STANDALONE_ENTRY_UNSUPPORTED", "entry 需要 Go backend 內的 SDK entry gate:請從 SDK 範本複製 internal/dsm/entry.go、apppriv.go 與 native bridge,並在 cmd/app/main.go 以 dsm.NewEntryGate 包住 authenticator。");
|
|
205
|
+
}
|
|
206
|
+
if (value === "app-privilege" && !permitsOrdinaryUsers(policy)) {
|
|
207
|
+
return c.fail("STANDALONE_ENTRY_INVALID", "entry: app-privilege 需要至少一個 permissions.json 標為 authenticated 的 route,一般使用者才有功能可用。");
|
|
208
|
+
}
|
|
209
|
+
return value;
|
|
210
|
+
}
|
|
162
211
|
function readRootOps(enabled, c) {
|
|
163
212
|
const dir = join(c.root, ROOT_OPS_DIR);
|
|
164
213
|
if (!enabled) {
|
|
@@ -180,7 +229,7 @@ function readArches(value, c) {
|
|
|
180
229
|
&& new Set(value).size === value.length;
|
|
181
230
|
return ok
|
|
182
231
|
? value
|
|
183
|
-
: c.fail("STANDALONE_ARCHES_INVALID", "arches 必須是不重複的 x86_64/aarch64 清單,至少一個。");
|
|
232
|
+
: c.fail("STANDALONE_ARCHES_INVALID", "arches 必須是不重複的 x86_64/aarch64/armv7 清單,至少一個。");
|
|
184
233
|
}
|
|
185
234
|
function readBackend(value, arches, c) {
|
|
186
235
|
if (!isRecord(value) || !["go", "binary"].includes(String(value.kind))) {
|
|
@@ -314,7 +363,7 @@ function readCapabilities(value, c) {
|
|
|
314
363
|
if (validDelegate(setting))
|
|
315
364
|
result.delegate = setting;
|
|
316
365
|
else
|
|
317
|
-
c.fail("CAPABILITY_INVALID", "delegate requires
|
|
366
|
+
c.fail("CAPABILITY_INVALID", "delegate requires scope home or shared:<name> and legacy files operations, or scope home/shared:<name>/install-selected with exactly files.moveFromStaging, nonempty unique destinations and lifetime: until-revoked.");
|
|
318
367
|
}
|
|
319
368
|
else if (name === "files" && setting === "session")
|
|
320
369
|
result.files = "session";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Shared host flow. CGI plans are never accepted as completed authorization. */
|
|
2
|
-
export declare const AUTHORIZATION_RUNTIME = "function createAuthorizationAccess(options) {\n var busy = null;\n function fail(code) { var error = new Error(code); error.code = code; return error; }\n function status() { return options.call(\"authorization.status\").then(function (d) {\n if (!d || d.command !== \"authorization\" || d.schema_version !== 1 || [\"ready\",\"authorization_required\",\"not_admin\",\"session_expired\",\"unavailable\"].indexOf(d.state) < 0) throw fail(\"authorization_bad_response\");\n return d;\n }); }\n function plan(method) { return options.call(method).then(function (p) {\n if (!p || p.command !== \"authorization\" || p.schema_version !== 1 || p.phase !== \"plan\" || !Array.isArray(p.operations) || p.operations.length === 0 || p.operations.length > options.tasks.length) throw fail(\"authorization_bad_response\");\n var seen = {};\n p.operations.forEach(function (op) { if (seen[op] || !options.tasks.some(function (t) { return t.op === op; })) throw fail(\"authorization_bad_response\"); seen[op] = true; });\n return p;\n }); }\n function exclusive(fn) { if (busy) return busy; busy = Promise.resolve().then(fn).then(function (s) { busy = null; return s; },function (e) { busy = null; throw e; });return busy; }\n function authorize(ops,run) { return ops.reduce(function (previous,op) { return previous.then(function () {\n return options.root.authorize(op).then(function (state) { if (state !== \"ready\") throw fail(\"root_cancelled\"); return run ? options.root.run(op) : null; });\n }); },Promise.resolve()); }\n return {canManage:function () {return !!options.user && options.user().admin === true;},status:status,request:function () { return exclusive(function () {\n return plan(\"authorization.request\").then(function (p) { return authorize(p.operations,p.run === true); }).then(status,function (e) { if (e.code === \"root_cancelled\") return status();throw e; });\n }); },revoke:function () { return exclusive(function () {\n return plan(\"authorization.revoke\").then(function (p) {\n if (p.withdraw === true && typeof options.withdraw !== \"function\") throw fail(\"authorization_bad_response\");\n var disabled = p.withdraw === true ? options.withdraw() : p.disable === true ? authorize([\"helper_disable\"],true) : Promise.resolve();\n return disabled.then(function () { return p.purge === true ? authorize([\"helper_purge\"],true) : null; }).then(function () { return p.operations.reduce(function (previous,op) {return previous.then(function () {return options.root.remove(op);});},Promise.resolve()); });\n }).then(status,function (e) { if (e.code === \"root_cancelled\") return status();throw e; });\n }); }};\n}";
|
|
2
|
+
export declare const AUTHORIZATION_RUNTIME = "function createAuthorizationAccess(options) {\n var busy = null;\n function fail(code) { var error = new Error(code); error.code = code; return error; }\n function status() { return options.call(\"authorization.status\").then(function (d) {\n if (!d || d.command !== \"authorization\" || d.schema_version !== 1 || [\"ready\",\"authorization_required\",\"not_admin\",\"session_expired\",\"unavailable\"].indexOf(d.state) < 0) throw fail(\"authorization_bad_response\");\n // upgrade_reapproval is a reason-only tombstone: it can only explain a pending request.\n if (d.reason === \"upgrade_reapproval\" && d.state !== \"authorization_required\") throw fail(\"authorization_bad_response\");\n return d;\n }); }\n function plan(method) { return options.call(method).then(function (p) {\n if (!p || p.command !== \"authorization\" || p.schema_version !== 1 || p.phase !== \"plan\" || !Array.isArray(p.operations) || p.operations.length === 0 || p.operations.length > options.tasks.length) throw fail(\"authorization_bad_response\");\n var seen = {};\n p.operations.forEach(function (op) { if (seen[op] || !options.tasks.some(function (t) { return t.op === op; })) throw fail(\"authorization_bad_response\"); seen[op] = true; });\n return p;\n }); }\n function exclusive(fn) { if (busy) return busy; busy = Promise.resolve().then(fn).then(function (s) { busy = null; return s; },function (e) { busy = null; throw e; });return busy; }\n function authorize(ops,run) { return ops.reduce(function (previous,op) { return previous.then(function () {\n return options.root.authorize(op).then(function (state) { if (state !== \"ready\") throw fail(\"root_cancelled\"); return run ? options.root.run(op) : null; });\n }); },Promise.resolve()); }\n return {canManage:function () {return !!options.user && options.user().admin === true;},status:status,request:function () { return exclusive(function () {\n return plan(\"authorization.request\").then(function (p) { return authorize(p.operations,p.run === true); }).then(status,function (e) { if (e.code === \"root_cancelled\") return status();throw e; });\n }); },revoke:function () { return exclusive(function () {\n return plan(\"authorization.revoke\").then(function (p) {\n if (p.withdraw === true && typeof options.withdraw !== \"function\") throw fail(\"authorization_bad_response\");\n var disabled = p.withdraw === true ? options.withdraw() : p.disable === true ? authorize([\"helper_disable\"],true) : Promise.resolve();\n return disabled.then(function () { return p.purge === true ? authorize([\"helper_purge\"],true) : null; }).then(function () { return p.operations.reduce(function (previous,op) {return previous.then(function () {return options.root.remove(op);});},Promise.resolve()); });\n }).then(status,function (e) { if (e.code === \"root_cancelled\") return status();throw e; });\n }); }};\n}";
|
|
@@ -4,6 +4,8 @@ export const AUTHORIZATION_RUNTIME = `function createAuthorizationAccess(options
|
|
|
4
4
|
function fail(code) { var error = new Error(code); error.code = code; return error; }
|
|
5
5
|
function status() { return options.call("authorization.status").then(function (d) {
|
|
6
6
|
if (!d || d.command !== "authorization" || d.schema_version !== 1 || ["ready","authorization_required","not_admin","session_expired","unavailable"].indexOf(d.state) < 0) throw fail("authorization_bad_response");
|
|
7
|
+
// upgrade_reapproval is a reason-only tombstone: it can only explain a pending request.
|
|
8
|
+
if (d.reason === "upgrade_reapproval" && d.state !== "authorization_required") throw fail("authorization_bad_response");
|
|
7
9
|
return d;
|
|
8
10
|
}); }
|
|
9
11
|
function plan(method) { return options.call(method).then(function (p) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PackageMetadata } from "../package-metadata.js";
|
|
1
2
|
import type { CommandRunner } from './build.js';
|
|
2
3
|
export declare const LAYOUT_ARCHES: {
|
|
3
4
|
readonly x86_64: readonly [2, 62];
|
|
@@ -21,6 +22,7 @@ type Binary = {
|
|
|
21
22
|
arches?: LayoutArch[];
|
|
22
23
|
};
|
|
23
24
|
export interface NativeLayout {
|
|
25
|
+
metadata?: PackageMetadata;
|
|
24
26
|
root: string;
|
|
25
27
|
package: string;
|
|
26
28
|
version: string;
|
|
@@ -39,6 +41,7 @@ export interface NativeLayout {
|
|
|
39
41
|
payload: string;
|
|
40
42
|
metadata: string;
|
|
41
43
|
binaries: Binary[];
|
|
44
|
+
anchors?: Record<string, string>;
|
|
42
45
|
};
|
|
43
46
|
native: {
|
|
44
47
|
prepare?: Hook;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { validateMetadata, metadataInfoFields } from "../package-metadata.js";
|
|
1
2
|
/** Existing native products: the CLI owns archives/INFO, the project owns its layout. */
|
|
2
3
|
import { createHash } from 'node:crypto';
|
|
3
4
|
import { chmodSync, copyFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
@@ -36,6 +37,20 @@ function inside(root, path) {
|
|
|
36
37
|
fail('path escapes project');
|
|
37
38
|
return full;
|
|
38
39
|
}
|
|
40
|
+
// Package Center writes INFO as root, so product root helpers can trust these
|
|
41
|
+
// payload digests across upgrades. The synopkgland_ prefix stays reserved.
|
|
42
|
+
function anchors(value) {
|
|
43
|
+
const a = object(value, Object.keys(value ?? {}));
|
|
44
|
+
if (Object.keys(a).length > 16)
|
|
45
|
+
fail('at most 16 INFO anchors');
|
|
46
|
+
for (const [key, path] of Object.entries(a)) {
|
|
47
|
+
if (!/^[a-z][a-z0-9_]{0,48}_sha256$/.test(key) || key.startsWith('synopkgland_'))
|
|
48
|
+
fail(`invalid INFO anchor key: ${key}`);
|
|
49
|
+
if (pathText(path).includes('{arch}'))
|
|
50
|
+
fail('INFO anchor path is relative to the architecture payload');
|
|
51
|
+
}
|
|
52
|
+
return a;
|
|
53
|
+
}
|
|
39
54
|
function hook(value) {
|
|
40
55
|
const h = object(value, ['command', 'cwd', 'env']);
|
|
41
56
|
if (!Array.isArray(h.command) || !h.command.length || !h.command.every((x) => typeof x === 'string' && x.length > 0 && !x.includes('\0')))
|
|
@@ -56,13 +71,15 @@ export function isNativeLayout(root) {
|
|
|
56
71
|
}
|
|
57
72
|
export function loadNativeLayout(root) {
|
|
58
73
|
try {
|
|
59
|
-
const m = object(parse(readFileSync(join(root, 'dsm-package.yaml'), 'utf8')), ['schema', 'backend', 'package', 'version', 'build', 'displayname', 'description', 'maintainer', 'os_min_ver', 'privilege', 'arches', 'layout', 'native']);
|
|
74
|
+
const m = object(parse(readFileSync(join(root, 'dsm-package.yaml'), 'utf8')), ['schema', 'backend', 'package', 'version', 'build', 'displayname', 'description', 'maintainer', 'metadata', 'os_min_ver', 'privilege', 'arches', 'layout', 'native']);
|
|
60
75
|
if (m.schema !== 2)
|
|
61
76
|
fail('schema 2 required; migrate schema: 1 to schema: 2 and add backend: {kind: native}');
|
|
62
77
|
const backend = object(m.backend, ['kind']);
|
|
63
78
|
if (backend.kind !== 'native' || (m.privilege !== undefined && m.privilege !== 'none'))
|
|
64
79
|
fail('backend.kind: native and package-only privilege required');
|
|
65
80
|
m.privilege = 'none';
|
|
81
|
+
if (m.metadata !== undefined)
|
|
82
|
+
m.metadata = validateMetadata(m.metadata);
|
|
66
83
|
if (existsSync(join(root, 'compose.yaml')))
|
|
67
84
|
fail('compose.yaml and dsm-package.yaml are mutually exclusive');
|
|
68
85
|
if (!/^[A-Za-z][A-Za-z0-9]{1,63}$/.test(text(m.package)) || !/^\d+(\.\d+){0,3}$/.test(text(m.version)) || !/^7\.\d+(\.\d+)?-\d+$/.test(text(m.os_min_ver)))
|
|
@@ -73,11 +90,13 @@ export function loadNativeLayout(root) {
|
|
|
73
90
|
text(m[k]);
|
|
74
91
|
if (!Array.isArray(m.arches) || !m.arches.length || new Set(m.arches).size !== m.arches.length || m.arches.some((a) => !Object.hasOwn(LAYOUT_ARCHES, a)))
|
|
75
92
|
fail('invalid architecture list');
|
|
76
|
-
const layout = object(m.layout, ['payload', 'metadata', 'binaries']);
|
|
93
|
+
const layout = object(m.layout, ['payload', 'metadata', 'binaries', 'anchors']);
|
|
77
94
|
layout.payload = pathText(layout.payload);
|
|
78
95
|
layout.metadata = pathText(layout.metadata);
|
|
79
96
|
if (!Array.isArray(layout.binaries) || !layout.binaries.length)
|
|
80
97
|
fail('binary assertions required');
|
|
98
|
+
if (layout.anchors !== undefined)
|
|
99
|
+
layout.anchors = anchors(layout.anchors);
|
|
81
100
|
for (const b of layout.binaries) {
|
|
82
101
|
object(b, ['path', 'linkage', 'arches']);
|
|
83
102
|
pathText(b.path);
|
|
@@ -300,8 +319,11 @@ export async function buildNativeLayout(options) {
|
|
|
300
319
|
await createReproducibleTar(target, join(stage, 'package.tgz'), { gzip: true });
|
|
301
320
|
rmSync(target, { recursive: true });
|
|
302
321
|
const fields = { package: m.package, version, arch, os_min_ver: m.os_min_ver, displayname: m.displayname, description: m.description, maintainer: m.maintainer, dsmuidir: 'ui', dsmappname: `SYNO.SDS.${m.package}.Instance`, startable: 'yes', thirdparty: 'yes', checksum: createHash('md5').update(readFileSync(join(stage, 'package.tgz'))).digest('hex') };
|
|
303
|
-
|
|
304
|
-
|
|
322
|
+
const info = [...Object.entries(fields), ...metadataInfoFields(m.metadata), ...anchorFields(m.layout.anchors ?? {}, files)];
|
|
323
|
+
if (new Set(info.map(([k]) => k)).size !== info.length)
|
|
324
|
+
fail('INFO anchor collides with an INFO field');
|
|
325
|
+
writeFileSync(join(stage, 'INFO'), info.map(([k, v]) => `${k}="${v.replace(/([\\"$`])/g, '\\$1')}"\n`).join(''));
|
|
326
|
+
writeFileSync(join(stage, 'native-layout.json'), JSON.stringify({ format: 1, arch, binaries: binaries.map(({ path, linkage }) => ({ path, linkage })), files, ...(m.layout.anchors ? { anchors: m.layout.anchors } : {}) }));
|
|
305
327
|
const output = join(options.outDir ?? join(m.root, 'dist'), `${m.package}-${version}-${arch}.spk`);
|
|
306
328
|
mkdirSync(dirname(output), { recursive: true });
|
|
307
329
|
await createReproducibleTar(stage, output);
|
|
@@ -319,7 +341,7 @@ export function inspectNativeLayout(dir, payload, info) {
|
|
|
319
341
|
try {
|
|
320
342
|
if (!/^[A-Za-z][A-Za-z0-9]{1,63}$/.test(info.package ?? '') || !/^\d+(\.\d+){0,3}-\d+$/.test(info.version ?? '') || !/^7\.\d+(\.\d+)?-\d+$/.test(info.os_min_ver ?? ''))
|
|
321
343
|
fail('invalid native INFO identity/version/DSM');
|
|
322
|
-
const inv = object(JSON.parse(readFileSync(join(dir, 'native-layout.json'), 'utf8')), ['format', 'arch', 'binaries', 'files']);
|
|
344
|
+
const inv = object(JSON.parse(readFileSync(join(dir, 'native-layout.json'), 'utf8')), ['format', 'arch', 'binaries', 'files', 'anchors']);
|
|
323
345
|
if (inv.format !== 1 || inv.arch !== info.arch || !Object.hasOwn(LAYOUT_ARCHES, inv.arch))
|
|
324
346
|
fail('invalid native layout inventory');
|
|
325
347
|
checkLayoutMetadata(dir, true, info.package);
|
|
@@ -337,9 +359,19 @@ export function inspectNativeLayout(dir, payload, info) {
|
|
|
337
359
|
}
|
|
338
360
|
if (createHash('md5').update(readFileSync(join(dir, 'package.tgz'))).digest('hex') !== info.checksum)
|
|
339
361
|
fail('package checksum mismatch');
|
|
362
|
+
checkInfoAnchors(readFileSync(join(dir, 'INFO'), 'utf8'), inv.anchors === undefined ? {} : anchors(inv.anchors), actual);
|
|
340
363
|
return [];
|
|
341
364
|
}
|
|
342
365
|
catch (e) {
|
|
343
366
|
return [String(e)];
|
|
344
367
|
}
|
|
345
368
|
}
|
|
369
|
+
function anchorFields(declared, files) {
|
|
370
|
+
return Object.entries(declared).map(([key, path]) => [key, files.find(f => f.path === path)?.sha256 ?? fail(`INFO anchor file missing: ${path}`)]);
|
|
371
|
+
}
|
|
372
|
+
function checkInfoAnchors(info, declared, files) {
|
|
373
|
+
const lines = info.split('\n').filter(line => /^[a-z0-9_]+_sha256=/.test(line));
|
|
374
|
+
const expected = anchorFields(declared, files).map(([key, digest]) => `${key}="${digest}"`);
|
|
375
|
+
if (JSON.stringify(lines.sort()) !== JSON.stringify(expected.sort()))
|
|
376
|
+
fail('INFO anchors do not match the payload');
|
|
377
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type PortalLocale = "en" | "zh-TW" | "zh-CN" | "ja" | "ko" | "de" | "fr" | "es" | "it";
|
|
2
|
+
/** SDK-owned portal panel text, shared by the plain panel and the Vue template. */
|
|
3
|
+
export declare const PORTAL_MESSAGES: Record<string, Record<PortalLocale, string>>;
|
|
4
|
+
/**
|
|
5
|
+
* `createPortalAccess(options)` → `ctx.portal`, plain ES5 for DSM's desktop.
|
|
6
|
+
*
|
|
7
|
+
* An administrator reads and sets the alias with DSM's own
|
|
8
|
+
* SYNO.Core.AppPortal API in their own session, after SYNO.API.Info shows the
|
|
9
|
+
* API; DSM itself refuses everyone else (105). An ordinary user reads the
|
|
10
|
+
* alias only through the package backend's `portal.status`. Anything
|
|
11
|
+
* unexpected reads as `unavailable`; an administrator then gets only the
|
|
12
|
+
* Control Panel shortcut.
|
|
13
|
+
*
|
|
14
|
+
* `status()` resolves `{state, alias?, url?, canManage, controlPanel,
|
|
15
|
+
* defaultAlias}`; `apply(alias)` and `disable()` resolve the new status or
|
|
16
|
+
* reject `{code}`; `openControlPanel()` opens Login Portal > Applications.
|
|
17
|
+
* `messages` is the panel text in the window's locale; `mountPanel(element)`
|
|
18
|
+
* renders a plain panel for UIs without their own.
|
|
19
|
+
*/
|
|
20
|
+
export declare const PORTAL_RUNTIME: string;
|
|
21
|
+
export {};
|