@synopackageland/cli 0.6.0 → 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 -78
- package/dist/add.js +39 -16
- package/dist/authorization-sdk.d.ts +7 -0
- package/dist/authorization-sdk.js +7 -0
- 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 +30 -18
- 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 +46 -13
- 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 +9 -1
- package/dist/standalone/inspect-spk.js +119 -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 +2 -0
- package/dist/standalone/native-authorization-window.js +30 -0
- package/dist/standalone/native-layout.d.ts +82 -0
- package/dist/standalone/native-layout.js +377 -0
- package/dist/standalone/native-root-window.d.ts +26 -0
- package/dist/standalone/native-root-window.js +282 -0
- 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 +91 -0
- package/dist/templates/native-authorization/i18n/de.json +37 -0
- package/dist/templates/native-authorization/i18n/en.json +37 -0
- package/dist/templates/native-authorization/i18n/es.json +37 -0
- package/dist/templates/native-authorization/i18n/fr.json +37 -0
- package/dist/templates/native-authorization/i18n/index.ts +15 -0
- package/dist/templates/native-authorization/i18n/it.json +37 -0
- package/dist/templates/native-authorization/i18n/ja.json +37 -0
- package/dist/templates/native-authorization/i18n/ko.json +37 -0
- package/dist/templates/native-authorization/i18n/zh-CN.json +37 -0
- package/dist/templates/native-authorization/i18n/zh-TW.json +37 -0
- 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/dist/validate.js +2 -1
- package/package.json +12 -2
- package/schema/package-metadata.schema.json +101 -0
- package/schema/synology-app.schema.json +112 -0
- package/skills/SKILL.md +109 -3
- 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 +91 -0
- package/templates/native-authorization/i18n/de.json +37 -0
- package/templates/native-authorization/i18n/en.json +37 -0
- package/templates/native-authorization/i18n/es.json +37 -0
- package/templates/native-authorization/i18n/fr.json +37 -0
- package/templates/native-authorization/i18n/index.ts +15 -0
- package/templates/native-authorization/i18n/it.json +37 -0
- package/templates/native-authorization/i18n/ja.json +37 -0
- package/templates/native-authorization/i18n/ko.json +37 -0
- package/templates/native-authorization/i18n/zh-CN.json +37 -0
- package/templates/native-authorization/i18n/zh-TW.json +37 -0
- 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
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];
|
|
@@ -41,9 +41,15 @@ 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
|
}
|
|
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
|
+
}
|
|
47
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}}
|
|
48
54
|
if os.Geteuid() == 0 {
|
|
49
55
|
cfg.Package = "nobody"
|
|
@@ -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)
|
|
@@ -7,9 +7,16 @@ including newline at most 65536 bytes). Socket access additionally requires exac
|
|
|
7
7
|
Linux SO_PEERCRED UID equality, even for another member of the package group.
|
|
8
8
|
Non-Linux builds support portable tests and refuse privileged service operations.
|
|
9
9
|
|
|
10
|
+
Fixed writer children verify `no_new_privs` with `PR_GET_NO_NEW_PRIVS` on their
|
|
11
|
+
locked Linux thread. DSM kernel 4.4 supports this flag but omits its proc status
|
|
12
|
+
field; a failed syscall or a value other than one still refuses the write.
|
|
13
|
+
Saved IDs and zero capabilities remain mandatory. The parent passes the pinned
|
|
14
|
+
package-owned private source as a read-only FD; destination creation and publish
|
|
15
|
+
remain under the subject UID, and source cleanup runs under the package UID.
|
|
16
|
+
|
|
10
17
|
## Protected inventory and policy
|
|
11
18
|
|
|
12
|
-
Setup must copy the
|
|
19
|
+
Setup must copy the INFO-anchored executor, policy-pinned policy and root scripts into:
|
|
13
20
|
|
|
14
21
|
```
|
|
15
22
|
/usr/local/etc/synopkgland/<package>/ root:root 0700
|
|
@@ -74,7 +81,7 @@ operations and policy-excluded operations are rejected. Replies follow §2.4.
|
|
|
74
81
|
|
|
75
82
|
| Operation | Parameters | Result |
|
|
76
83
|
| --- | --- | --- |
|
|
77
|
-
| status | none | executor_digest, policy_digest, version, ready |
|
|
84
|
+
| status | none | executor_digest, policy_digest, version, ready, disabled |
|
|
78
85
|
| delegate.create | job_id, ops[], scope, path, ttl_seconds | delegation_id, subject {username, uid}, expires_at (RFC3339) |
|
|
79
86
|
| delegate.list | none | delegations[] with public metadata, including revoked/expired records |
|
|
80
87
|
| delegate.revoke | delegation_id; job_id required without cookie | revoked |
|
|
@@ -86,7 +93,7 @@ operations and policy-excluded operations are rejected. Replies follow §2.4.
|
|
|
86
93
|
Create/list require a cookie and SynoToken. Revoke accepts the subject/admin session pair or a matching
|
|
87
94
|
package job ID. Root operations require the session pair independently verified as an
|
|
88
95
|
active administrators member. Delegated operations recheck the account, UID,
|
|
89
|
-
expired=`normal`,
|
|
96
|
+
expired=`normal`, App and File Station privileges, scope,
|
|
90
97
|
job, operation, expiry and revocation. UIDs below 1024 are excluded as system
|
|
91
98
|
accounts. TTL must be 1–2592000 seconds. No cookie/SynoToken/SID/password is persisted.
|
|
92
99
|
|
|
@@ -94,22 +101,26 @@ Paths use File Station spellings `/home[/...]` or `/<share>[/...]`. A delegation
|
|
|
94
101
|
binds the requested directory's canonical path. Symlinks resolving outside that
|
|
95
102
|
directory are denied. `files.write` opens package-owned, singly linked regular
|
|
96
103
|
staging files with no symlink components; its fresh child checks setgroups,
|
|
97
|
-
setresgid and setresuid in order, then
|
|
104
|
+
setresgid and setresuid in order, then real/effective/saved/filesystem IDs and groups, empty capability sets and
|
|
105
|
+
`no_new_privs`. Admin users retain their own nonzero UID and current groups. The child
|
|
98
106
|
opens the destination after dropping identity, verifies its pinned directory and
|
|
99
107
|
scope, and copies into an exclusive hidden `.synopkgland-<job_id>-<random>.part`
|
|
100
108
|
file. After fsync it publishes the complete file with a hard link, then removes
|
|
101
109
|
the temporary name. Existing files and symlinks are never overwritten. The
|
|
102
110
|
executor cleans the exact temporary name as the subject user after a canceled or
|
|
103
111
|
killed child, using a retained directory descriptor; startup performs no scan.
|
|
104
|
-
Successful writes
|
|
112
|
+
Successful writes request exact source cleanup in a separate package-UID child;
|
|
113
|
+
cleanup failure retains the source and never downgrades a committed receipt. DSM ACL inheritance can
|
|
105
114
|
produce a mode different from the requested 0600 (observed 0711 on vt-nas).
|
|
106
115
|
|
|
107
116
|
File Station CheckPermission uses v3 with a fixed non-overwriting probe filename
|
|
108
117
|
and size zero; it creates no file. Missing/failed API data is denied. DSM output
|
|
109
118
|
and root script output are capped at 1 MiB; commands have 20-second deadlines,
|
|
110
119
|
connection read/write deadlines are 15/5 seconds and request execution is bounded
|
|
111
|
-
by 30 seconds. At most 16 connections are admitted.
|
|
112
|
-
|
|
120
|
+
by 30 seconds. At most 16 connections are admitted. Legacy runner APIs use short
|
|
121
|
+
admission leases; revoke/disable persist the fence then drain accepted legacy
|
|
122
|
+
calls outside the commit lock before acknowledging. Bulk copy holds no commit
|
|
123
|
+
lock. Linux command timeouts kill the entire command process group.
|
|
113
124
|
|
|
114
125
|
File Station APIs resolve path strings inside DSM after executor scope validation;
|
|
115
126
|
there is no atomic DSM API for binding that subsequent lookup to our directory
|
|
@@ -122,13 +133,20 @@ items, not assertions of complete race freedom.
|
|
|
122
133
|
|
|
123
134
|
```
|
|
124
135
|
executor serve --package com.example.downloader
|
|
136
|
+
executor supervise --package com.example.downloader
|
|
125
137
|
executor control start --package com.example.downloader
|
|
126
138
|
executor control stop --package com.example.downloader
|
|
127
139
|
executor control purge --package com.example.downloader
|
|
128
140
|
```
|
|
129
141
|
|
|
130
142
|
Root control start launches asynchronously; the caller reads socket status to
|
|
131
|
-
establish readiness.
|
|
143
|
+
establish readiness. It starts `executor supervise`, a root supervisor that runs
|
|
144
|
+
`serve` as its child and restarts it after an abnormal end (signal or non-zero
|
|
145
|
+
exit) with a 1 s backoff doubling to 60 s, reset after a minute of healthy run.
|
|
146
|
+
A restarted `serve --revived` honors a `stop` already in the mailbox. Exit 0
|
|
147
|
+
(root replacement, shutdown, purge), exit 3 (another monitor holds the pidfile)
|
|
148
|
+
or a removed runtime end supervision. A held flock pidfile refuses duplicate
|
|
149
|
+
serve. Root's pinned
|
|
132
150
|
boot/control start can validate and terminate a previous monitor before launching
|
|
133
151
|
its replacement; package-account start only writes the mailbox and cannot replace
|
|
134
152
|
runtime. Stop pauses the listener while the monitor continues. Purge removes this
|
|
@@ -136,7 +154,8 @@ package's protected state and deletes only its verified recorded scheduler tasks
|
|
|
136
154
|
|
|
137
155
|
Run `go test -race ./...` and `bash scripts/ci/gate.sh native-go`. The gate adds
|
|
138
156
|
Linux amd64/arm64 vet, static binary builds and test compilation. Linux-specific
|
|
139
|
-
syscall tests
|
|
157
|
+
syscall tests require a disposable Linux root fixture. This revision was tested
|
|
158
|
+
on a Linux VM; DSM ACL, logout and reboot behavior remain unverified. The
|
|
140
159
|
`testdata/live_probe.py` harness expects isolated disposable accounts and a
|
|
141
160
|
manually copied runtime, reads passwords only from stdin, and logs no credentials.
|
|
142
161
|
The live harness uses DSM's registered `SYNO.Desktop` AppPriv ID as a stand-in for
|
|
@@ -148,12 +167,17 @@ an installed App; installed-package AppPriv integration belongs to setup testing
|
|
|
148
167
|
Package-account hooks atomically write `stop` before upgrades/stops, `start` on
|
|
149
168
|
install/upgrade completion and package start, and `purge` before uninstall.
|
|
150
169
|
`stop` cancels/drains requests and removes the listener without ending the root
|
|
151
|
-
monitor. `start` resumes
|
|
152
|
-
|
|
153
|
-
|
|
170
|
+
monitor. `start` resumes if both package executor and policy hashes equal the approved
|
|
171
|
+
runtime pins. If only the executor changed, the policy hash is unchanged and the
|
|
172
|
+
executor hash equals the single `synopkgland_executor_sha256` key in the
|
|
173
|
+
root-owned `/var/packages/<package>/INFO`, the root monitor copies it into
|
|
174
|
+
`runtime/`, verifies the copy and runs root `control start`, which replaces the
|
|
175
|
+
monitor without reapproval. Any other change stays paused for administrator
|
|
176
|
+
approval. Only root's pinned boot/control path or this anchored install can
|
|
177
|
+
replace a monitor or runtime.
|
|
154
178
|
|
|
155
179
|
At start, scheduler readback must exactly match the canonical lifecycle scripts
|
|
156
|
-
regenerated from the package identity and approved
|
|
180
|
+
regenerated from the package identity and approved policy pin. Package
|
|
157
181
|
setup metadata supplies hints only. The verified names, pins and script hashes
|
|
158
182
|
are stored in root:root 0600 `runtime/tasks.json`. Purge regenerates the scripts
|
|
159
183
|
and revalidates each current definition before EventScheduler v1
|
|
@@ -188,9 +212,10 @@ and `purge` clears state immediately. A root-approved new monitor ignores the
|
|
|
188
212
|
stop file already present at startup; that exception ends after an absence.
|
|
189
213
|
|
|
190
214
|
The boot task checks pending purge/package disappearance before accessing source.
|
|
191
|
-
It verifies retained
|
|
192
|
-
boot
|
|
193
|
-
|
|
215
|
+
It verifies the retained policy pin before offline purge from the root-only
|
|
216
|
+
runtime. Normal boot verifies the copies against the policy pin and the INFO
|
|
217
|
+
executor anchor, installs them and calls root control start to replace a
|
|
218
|
+
previous monitor. Scripts stay within 1 KiB with no percent characters, including the
|
|
194
219
|
longest package name. Partial/tampered retained state requires administrator
|
|
195
220
|
review. All nine uninstall wizard locales name the two tasks and disclose the
|
|
196
221
|
retained DSM storage/infrastructure. `inspect`/`status` cleanup guidance is
|
|
@@ -202,3 +227,89 @@ a directory descriptor and verified with fstat, so boot umask 0077 cannot reduce
|
|
|
202
227
|
validated and never repaired/adopted. The package directory must already have
|
|
203
228
|
root/package-group ownership. The socket is set to root/package-group 0660 and
|
|
204
229
|
verified using Linux O_PATH + fstat on its filesystem inode.
|
|
230
|
+
|
|
231
|
+
## Explicit long-running v1 extension
|
|
232
|
+
|
|
233
|
+
The pinned policy opts in with top-level `destinations: ["save"]` and
|
|
234
|
+
`lifetime: "until-revoked"`, together with `files.moveFromStaging` in the
|
|
235
|
+
operation allowlist. Destination keys match `^[a-z][a-z0-9_-]{0,63}$`; unknown
|
|
236
|
+
keys/lifetimes fail closed. Legacy policies/TTL grants never become permanent.
|
|
237
|
+
The existing v1 envelope, peer UID check, protected runtime and session verifier
|
|
238
|
+
remain unchanged. `root.run` is independent and is never a writer fallback.
|
|
239
|
+
|
|
240
|
+
| Operation | Parameters | Result |
|
|
241
|
+
| --- | --- | --- |
|
|
242
|
+
| delegate.create (permanent) | scope, ops:[files.moveFromStaging], path, destination, lifetime:until-revoked | delegation_id, subject, path, destination, lifetime; zero expiry |
|
|
243
|
+
| files.moveFromStaging | delegation_id, job_id, staging, name, size | job_id, state |
|
|
244
|
+
| files.operationStatus | original delegation_id, job_id | job_id, state, optional code/receipt |
|
|
245
|
+
| files.cancelOperation | original delegation_id, job_id | current operation state |
|
|
246
|
+
| delegate.disable / delegate.enable | none; live administrator session | disabled |
|
|
247
|
+
| delegate.audit | none; live owner/admin session | latest bounded events |
|
|
248
|
+
|
|
249
|
+
Permanent create needs the current user's cookie and SynoToken and a successful
|
|
250
|
+
File Station write check. The executor derives username/UID and exact directory
|
|
251
|
+
identity itself. Permanent revoke is owner-bound even for administrators; admins
|
|
252
|
+
can disable the entire package. Auth-less operation submission/status/cancel is
|
|
253
|
+
for the trusted package producer holding the grant reference and original job ID.
|
|
254
|
+
If credentials are supplied, both must verify and the owner must match; failed
|
|
255
|
+
caller auth never falls back to offline authority. A compromised package backend
|
|
256
|
+
can use all valid grants it holds, as documented in the approved trust model.
|
|
257
|
+
|
|
258
|
+
Grants survive service restart in the protected store. The disabled flag also
|
|
259
|
+
survives; mailbox start/boot never clears it. Disable persists first and revokes
|
|
260
|
+
all legacy/permanent grants. Enable checks the live admin session and completes
|
|
261
|
+
revocation before clearing the flag; it never restores old grants. Repeated enable
|
|
262
|
+
while already enabled is a no-op.
|
|
263
|
+
|
|
264
|
+
Operations are separate `operation-<sha256(job_id)>.record` files, root:root 0600.
|
|
265
|
+
They bind immutable grant/job/staging/name/size and move through queued, copying,
|
|
266
|
+
committed, canceled, interrupted or uncertain. Queued resumes without credentials;
|
|
267
|
+
copying becomes interrupted on restart, or uncertain after durable publish intent.
|
|
268
|
+
Neither state is replayed. Changed input for the same job is `operation-conflict`.
|
|
269
|
+
Committed status alone includes `receipt:{path,size}`. Cleanup failures retain
|
|
270
|
+
committed and add `CLEANUP_PENDING`. No same-name/hash guessing establishes receipt.
|
|
271
|
+
|
|
272
|
+
Limits: 16 GiB per file, actual size+1 read, 16 queued, one active copy per package,
|
|
273
|
+
24-hour attempt, 10 MiB operation metadata. Full journals reject new admissions;
|
|
274
|
+
terminal records are retained to prevent replay. Bulk input bypasses job spools
|
|
275
|
+
and the old 64 MiB wrapper limit. Long copies revalidate account/AppPriv/ACL/path
|
|
276
|
+
with five-second polling and bounded checks; publish revalidates again. A failed
|
|
277
|
+
identity/ACL/path check invalidates the grant and requires a new selection.
|
|
278
|
+
|
|
279
|
+
The fixed child drops identity before opening the destination and creating any
|
|
280
|
+
inode. Every component uses FD-relative O_NOFOLLOW; ancestors use O_PATH so only
|
|
281
|
+
search rights are required. Source is package-owned, regular and singly linked;
|
|
282
|
+
destination is the exact granted device/inode, never a caller-supplied path.
|
|
283
|
+
Part metadata is durable before copying. Publish links the open part inode with
|
|
284
|
+
no replacement, refusing files/symlinks/FIFOs at the final name. Revoke, disable
|
|
285
|
+
and publish share the commit lock. Lost/malformed publish replies drain the child
|
|
286
|
+
before releasing that lock and produce uncertain; a confirmed no-side-effect
|
|
287
|
+
refusal such as `destination-exists` remains interrupted. The lock covers bounded
|
|
288
|
+
publish handshake/fsync, never the bulk copy. During the copy the child watches
|
|
289
|
+
its control pipe: if `serve` dies the pipe closes, so the child stops within one
|
|
290
|
+
1 MiB chunk and unlinks its part (no `PR_SET_PDEATHSIG`, which the identity drop
|
|
291
|
+
clears; works on kernel 3.10). Kernel-blocked filesystem I/O can
|
|
292
|
+
still delay draining; it cannot be declared safely complete by a timeout.
|
|
293
|
+
Legacy `files.write` uses this same child and publish handshake; the executor
|
|
294
|
+
has no other writer, so no child can publish after `serve` is gone.
|
|
295
|
+
|
|
296
|
+
Destination/part cleanup runs as the owner; source cleanup runs as package UID.
|
|
297
|
+
Restart cleans only journaled exact part identity as the current eligible owner;
|
|
298
|
+
changed/missing/inaccessible directories are retained for review, never scanned
|
|
299
|
+
or deleted as root. Subject-controlled directory moves after the final check
|
|
300
|
+
can still complete in the pinned directory object. DSM ACL changes and publication
|
|
301
|
+
are not atomic, and silent UID/inode reuse is not universally detected. A subject
|
|
302
|
+
who owns the destination can mutate its own output; this is not a content sandbox.
|
|
303
|
+
|
|
304
|
+
Structured audit lives in protected `audit.jsonl`/`audit.previous`, at most 50 MiB
|
|
305
|
+
combined, separate from authority. Events include package, username/UID, operation,
|
|
306
|
+
job, location and result; no session credentials. Owner queries are filtered,
|
|
307
|
+
admins can view this package's events. Replies contain at most 256 events/1 MiB.
|
|
308
|
+
Admission events are labeled `admitting` because a subsequent durable write can
|
|
309
|
+
fail. The operation journal, not an admission audit event, establishes completion.
|
|
310
|
+
|
|
311
|
+
The existing status operation reads `Store.Disabled`; protected-store errors set
|
|
312
|
+
`ready:false` rather than assuming enabled. Backend `delegate.status` exposes the
|
|
313
|
+
verified boolean and `disabled` capability state. Backend `delegate.operations.list`
|
|
314
|
+
is strictly empty-params, freshly owner/UID-filtered move-mirror metadata; it is
|
|
315
|
+
not an executor operation. Live completion remains `files.operationStatus`.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"errors"
|
|
6
|
+
"os"
|
|
7
|
+
"os/exec"
|
|
8
|
+
"path/filepath"
|
|
9
|
+
"regexp"
|
|
10
|
+
"strings"
|
|
11
|
+
"syscall"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// Package Center writes the SPK INFO as root. The package account cannot change
|
|
15
|
+
// it, so its executor digest authorizes executor-only upgrades under the
|
|
16
|
+
// administrator-approved policy without a new PasswordConfirm.
|
|
17
|
+
const executorAnchorKey = "synopkgland_executor_sha256"
|
|
18
|
+
|
|
19
|
+
var anchorRE = regexp.MustCompile(`^"([a-f0-9]{64})"$`)
|
|
20
|
+
|
|
21
|
+
type pinState int
|
|
22
|
+
|
|
23
|
+
const (
|
|
24
|
+
pinsDiffer pinState = iota
|
|
25
|
+
pinsMatch
|
|
26
|
+
pinsAnchored
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
func executorAnchor(info string, trusted func(os.FileInfo) bool) (string, error) {
|
|
30
|
+
b, stat, err := readLifecycleFile(info, 65536)
|
|
31
|
+
if err != nil {
|
|
32
|
+
return "", err
|
|
33
|
+
}
|
|
34
|
+
if !trusted(stat) {
|
|
35
|
+
return "", errors.New("untrusted package INFO")
|
|
36
|
+
}
|
|
37
|
+
anchor := ""
|
|
38
|
+
for _, line := range strings.Split(string(b), "\n") {
|
|
39
|
+
value, ok := strings.CutPrefix(line, executorAnchorKey+"=")
|
|
40
|
+
if !ok {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
m := anchorRE.FindStringSubmatch(value)
|
|
44
|
+
if m == nil || anchor != "" {
|
|
45
|
+
return "", errors.New("executor anchor")
|
|
46
|
+
}
|
|
47
|
+
anchor = m[1]
|
|
48
|
+
}
|
|
49
|
+
if anchor == "" {
|
|
50
|
+
return "", errors.New("executor anchor")
|
|
51
|
+
}
|
|
52
|
+
return anchor, nil
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func rootOwnedReadOnly(info os.FileInfo) bool {
|
|
56
|
+
return ownedByRoot(info) && info.Mode().Perm()&0022 == 0
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func packagePins(ctx context.Context, dir, info string, trusted func(os.FileInfo) bool, executorDigest, policyDigest string) pinState {
|
|
60
|
+
if samePackagePins(ctx, dir, executorDigest, policyDigest) {
|
|
61
|
+
return pinsMatch
|
|
62
|
+
}
|
|
63
|
+
dir, err := filepath.EvalSymlinks(dir)
|
|
64
|
+
if err != nil {
|
|
65
|
+
return pinsDiffer
|
|
66
|
+
}
|
|
67
|
+
if pd, err := digestFile(ctx, dir+"/policy.json", maxPolicyBytes); err != nil || pd != policyDigest {
|
|
68
|
+
return pinsDiffer
|
|
69
|
+
}
|
|
70
|
+
anchor, err := executorAnchor(info, trusted)
|
|
71
|
+
if err != nil {
|
|
72
|
+
return pinsDiffer
|
|
73
|
+
}
|
|
74
|
+
if ed, err := digestFile(ctx, dir+"/executor", maxExecutorBytes); err != nil || ed != anchor {
|
|
75
|
+
return pinsDiffer
|
|
76
|
+
}
|
|
77
|
+
return pinsAnchored
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The policy is unchanged, so root scripts (pinned by policy digests) stay too.
|
|
81
|
+
// Verify the protected copy, never the package-reachable source.
|
|
82
|
+
func installAnchored(ctx context.Context, source, info string, trusted func(os.FileInfo) bool, runtime string) error {
|
|
83
|
+
anchor, err := executorAnchor(info, trusted)
|
|
84
|
+
if err != nil {
|
|
85
|
+
return err
|
|
86
|
+
}
|
|
87
|
+
src, err := openRegular(filepath.Join(source, "executor"))
|
|
88
|
+
if err != nil {
|
|
89
|
+
return err
|
|
90
|
+
}
|
|
91
|
+
defer src.Close()
|
|
92
|
+
stat, err := src.Stat()
|
|
93
|
+
if err != nil || stat.Size() > maxExecutorBytes {
|
|
94
|
+
return errors.New("executor size")
|
|
95
|
+
}
|
|
96
|
+
staged, err := os.CreateTemp(runtime, ".executor-")
|
|
97
|
+
if err != nil {
|
|
98
|
+
return err
|
|
99
|
+
}
|
|
100
|
+
defer os.Remove(staged.Name())
|
|
101
|
+
err = copyExact(staged, src, stat.Size())
|
|
102
|
+
if err == nil {
|
|
103
|
+
err = staged.Chmod(0700)
|
|
104
|
+
}
|
|
105
|
+
if err == nil {
|
|
106
|
+
err = staged.Sync()
|
|
107
|
+
}
|
|
108
|
+
if closeErr := staged.Close(); err == nil {
|
|
109
|
+
err = closeErr
|
|
110
|
+
}
|
|
111
|
+
if err != nil {
|
|
112
|
+
return err
|
|
113
|
+
}
|
|
114
|
+
if digest, err := digestFile(ctx, staged.Name(), maxExecutorBytes); err != nil || digest != anchor {
|
|
115
|
+
return errors.New("executor anchor mismatch")
|
|
116
|
+
}
|
|
117
|
+
return os.Rename(staged.Name(), filepath.Join(runtime, "executor"))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Root control start replaces this monitor with the newly installed runtime.
|
|
121
|
+
func startInstalled(runtime, pkg string) error {
|
|
122
|
+
cmd := exec.Command(filepath.Join(runtime, "executor"), "control", "start", "--package", pkg)
|
|
123
|
+
cmd.Env = []string{"PATH=/usr/bin:/bin", "LANG=C"}
|
|
124
|
+
cmd.Dir = "/"
|
|
125
|
+
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
|
126
|
+
if err := cmd.Start(); err != nil {
|
|
127
|
+
return err
|
|
128
|
+
}
|
|
129
|
+
return cmd.Process.Release()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
func approvedPins(state pinState, install, start func() error, log func(string)) bool {
|
|
133
|
+
if state != pinsAnchored {
|
|
134
|
+
return state == pinsMatch
|
|
135
|
+
}
|
|
136
|
+
if err := install(); err != nil {
|
|
137
|
+
log("executor upgrade refused: INFO-anchored executor could not be installed")
|
|
138
|
+
return false
|
|
139
|
+
}
|
|
140
|
+
if err := start(); err != nil {
|
|
141
|
+
log("executor upgrade installed; root start failed")
|
|
142
|
+
return false
|
|
143
|
+
}
|
|
144
|
+
log("executor upgrade: INFO-anchored executor installed under the approved policy")
|
|
145
|
+
return false
|
|
146
|
+
}
|