@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
|
@@ -8,10 +8,12 @@ A worker stores only a delegation ID and job ID, never session credentials.
|
|
|
8
8
|
## CLI assembly
|
|
9
9
|
|
|
10
10
|
`init --with delegate` and `add delegate` apply base → jobs → delegate.
|
|
11
|
-
The SDK registers `DelegateRoutes` using the trusted manifest scope and
|
|
12
|
-
all
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
The SDK registers `DelegateRoutes` using the trusted manifest scope and lists
|
|
12
|
+
all 17 delegate methods in `sdk-permissions.json`: `delegate.disable` and
|
|
13
|
+
`delegate.enable` require administrators, the others `authenticated`.
|
|
14
|
+
App-owned permissions remain in `permissions.json`. `init --with delegate` sets
|
|
15
|
+
`app.status` to authenticated so ordinary users can mount their panels;
|
|
16
|
+
`add delegate` leaves `permissions.json` unchanged. The CLI binds both
|
|
15
17
|
policy files to the CGI build. SDK policy edits and overrides fail validation.
|
|
16
18
|
|
|
17
19
|
`background.Job.DelegationID` is an optional field in the shared base store.
|
|
@@ -23,7 +25,7 @@ shared store before activating delegate.
|
|
|
23
25
|
```ts
|
|
24
26
|
interface ExecutorSetup {
|
|
25
27
|
status(): Promise<CapabilityStatus>
|
|
26
|
-
authorize(password: string): Promise<CapabilityStatus>
|
|
28
|
+
authorize(password: string, selectedScope?: string): Promise<CapabilityStatus>
|
|
27
29
|
control(action: 'start' | 'stop' | 'purge'): Promise<CapabilityStatus>
|
|
28
30
|
}
|
|
29
31
|
```
|
|
@@ -140,3 +142,122 @@ The fixtures are temporary and are removed after each run.
|
|
|
140
142
|
These tests do not claim DSM kernel ACL, owner, reboot, real task or real executor
|
|
141
143
|
validation. CLI activation and real executor/setup integration belong to the other
|
|
142
144
|
P2 workstreams.
|
|
145
|
+
|
|
146
|
+
## Choose the scope at install and confirm it once
|
|
147
|
+
|
|
148
|
+
New `init` / `add delegate` projects default to `scope: install-selected`.
|
|
149
|
+
The DSM install wizard's native `api_store` combobox dynamically lists local
|
|
150
|
+
shares using the installer's administrator session (`SYNO.Core.Share list v1`).
|
|
151
|
+
A checkbox offers each user's `/home` instead; choosing a share never creates it
|
|
152
|
+
or grants its ACL to the package account. This wizard was measured on vt-nas
|
|
153
|
+
DSM 7.4 through a session-only SSH tunnel. Other DSM versions remain unverified.
|
|
154
|
+
|
|
155
|
+
Installation saves `{schema:1, scope}` in package-owned
|
|
156
|
+
`var/delegate-install.json`. It is **only a pre-selection**. The existing
|
|
157
|
+
administrator enable form displays it alongside the DSM password field. One
|
|
158
|
+
PasswordConfirm authorizes the pinned boot/control tasks and a one-time exact
|
|
159
|
+
selection task. Only the root executor writes
|
|
160
|
+
`/usr/local/etc/synopkgland/<pkg>/delegations/selected-scope.record`
|
|
161
|
+
(`schema`, `scope`, `generation`, root 0600). The package peer cannot call the
|
|
162
|
+
internal selection operation, even with an administrator cookie. Shipped
|
|
163
|
+
executor/policy pins lock the selection mode and operations; the chosen scope
|
|
164
|
+
is protected runtime state, so changing it does not rewrite shipped pins.
|
|
165
|
+
|
|
166
|
+
Settings uses this same form and `ctx.executor.authorize(password, scope)` to
|
|
167
|
+
change the scope. There is no extra dialog or step. A new scope generation
|
|
168
|
+
revokes existing grants and cancels pending saves under the publication fence.
|
|
169
|
+
Changing away and back never revives old grants. Existing destination files
|
|
170
|
+
remain. Selecting another directory for the same destination key replaces only
|
|
171
|
+
that person's previous grant for the key. Every person must select again after
|
|
172
|
+
scope changes. If the package draft differs, the UI shows both and follows the
|
|
173
|
+
protected value. Existing `scope: home` and `shared:<name>` manifests retain their
|
|
174
|
+
fixed-scope API and legacy TTL behavior. Dynamic selection requires the
|
|
175
|
+
`until-revoked` / `files.moveFromStaging` declaration.
|
|
176
|
+
|
|
177
|
+
A scope change on a running executor whose pins verify runs only the selection
|
|
178
|
+
task. It never restarts the executor, so a copy in flight ends `canceled` with
|
|
179
|
+
reason `scope-changed`, not `interrupted`. `authorize` waits about 20 seconds
|
|
180
|
+
for the protected readback. A `blocked` reply that carries `requested: {scope,
|
|
181
|
+
generation}` means the root task may still land: read `ctx.executor.status()`
|
|
182
|
+
(or `delegate.status`) until `selection.scope` equals `requested.scope` with a
|
|
183
|
+
`selection.generation` above `requested.generation` (applied); otherwise it was
|
|
184
|
+
not applied. Submitting the same scope again is safe: the task is pinned to the
|
|
185
|
+
current generation and an already selected scope is answered unchanged.
|
|
186
|
+
|
|
187
|
+
## One typed destination lookup, online and offline
|
|
188
|
+
|
|
189
|
+
The generated Vue template contains the complete administrator setup, confirmed
|
|
190
|
+
scope, scope-limited NasPicker, personal destinations and operations, and admin
|
|
191
|
+
kill switch. Use its existing facade:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import {createBackgroundSaveFacade} from './delegate/facade'
|
|
195
|
+
const sdk = createBackgroundSaveFacade(ctx)
|
|
196
|
+
const current = await sdk.destination('save')
|
|
197
|
+
// current.selection: {scope, root, generation} | null — protected executor evidence
|
|
198
|
+
// current.destination: {id, key, path, username, lifetime} | null — this caller only
|
|
199
|
+
// current.status: active | missing | reselection-required | needs-scope-confirmation | disabled
|
|
200
|
+
if (current.status === 'active') {
|
|
201
|
+
const ref = await sdk.exportExample({key: 'save', job_id: stableJobID})
|
|
202
|
+
// The generated My saves panel queries this reference; admission is not Saved.
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The authenticated CGI is `delegate.destination` with `{key}`; it verifies the
|
|
207
|
+
fresh DSM session and username+UID, configured key, protected scope/generation
|
|
208
|
+
and current grant. Neither browser storage nor the installation draft supplies
|
|
209
|
+
a destination. Errors or missing protected evidence disable new selections.
|
|
210
|
+
|
|
211
|
+
Go uses `service.Destination(ctx, caller, request, "save") (DestinationState,error)`.
|
|
212
|
+
Capture `current.Destination.ID` in the App's own job only when status is active.
|
|
213
|
+
After logout, a producer uses that ID with `service.MoveFromStaging(ctx, params)`.
|
|
214
|
+
It does not use the package draft, pass a virtual destination path, or retain
|
|
215
|
+
session credentials. The executor rechecks scope generation, account, grant,
|
|
216
|
+
directory identity and DSM ACL before writing as the user's nonzero UID.
|
|
217
|
+
|
|
218
|
+
The shipped **Save example file** button calls `delegate.example.export` with
|
|
219
|
+
`{key, job_id}`. `backend/internal/delegate/example.go` is a working producer:
|
|
220
|
+
it obtains this user's active destination, creates a small package-private JSON
|
|
221
|
+
file (0600) under staging, and invokes `MoveFromStaging`. Repeated job IDs repeat
|
|
222
|
+
the original request: they return the original operation, admit only one the
|
|
223
|
+
executor does not know, and never overwrite staging. Adapt this producer for
|
|
224
|
+
daemon/export jobs and keep its stable ID. An uncertain result has no automatic
|
|
225
|
+
retry; only a protected committed receipt means Saved.
|
|
226
|
+
|
|
227
|
+
If admission failed or its reply was lost, call `MoveFromStaging` again later
|
|
228
|
+
with the same params. It queries the original first and re-sends only an
|
|
229
|
+
operation the executor does not know, with the pinned source unchanged (at most
|
|
230
|
+
10 possibly-delivered sends, 2 s backoff doubling to 5 min; the worker sweep
|
|
231
|
+
does the same). Retry on `EXECUTOR_UNAVAILABLE`, `EXECUTOR_TIMEOUT`,
|
|
232
|
+
`EXECUTOR_PROTOCOL`, `canceled`, `EXECUTOR_PAUSED`, `queue-full`,
|
|
233
|
+
`STORAGE_ERROR`, `ADMISSION_PENDING`, and on the package journal codes
|
|
234
|
+
`jobs_busy` (lock busy), `jobs_unavailable` (transient I/O) and `canceled` (the
|
|
235
|
+
caller's deadline or cancel ended the wait). None of these admitted anything a
|
|
236
|
+
retry could duplicate; while the journal is unavailable, a ref the executor
|
|
237
|
+
already knows still answers its state, so a committed move stays committed.
|
|
238
|
+
Terminal: executor refusals such as `APP_DENIED`, `DELEGATION_DENIED`,
|
|
239
|
+
`operation-conflict`, `disabled`, plus `STAGING_CHANGED`, `ADMISSION_EXHAUSTED`,
|
|
240
|
+
`spool_unsafe` and `journal_corrupt` (the package spool needs repair), and
|
|
241
|
+
`operation-not-found` for an accepted operation. See the delegate guide's Admission recovery table.
|
|
242
|
+
|
|
243
|
+
Cancel with the original reference (`CancelOperation`, or
|
|
244
|
+
`delegate.operations.cancel` from the UI); it is idempotent, so repeat it with
|
|
245
|
+
the same reference after a retryable error or a lost reply. `queued` becomes
|
|
246
|
+
`canceled` at once. A copy in flight answers `copying` with code
|
|
247
|
+
`CANCEL_REQUESTED`: accepted and durable, not finished. Poll `OperationStatus`
|
|
248
|
+
on the same reference until `canceled` (writer stopped, part removed, nothing
|
|
249
|
+
published, staging kept), `committed` (publication won; the file stays, drop only
|
|
250
|
+
the app record) or `uncertain` (a publish attempt failed first; keep querying).
|
|
251
|
+
The request survives executor crash, package stop/start and logout.
|
|
252
|
+
Revoke, scope change and disable store their reason (`grant-revoked`,
|
|
253
|
+
`scope-changed`, `integration-disabled`) the same way: a copy in flight answers
|
|
254
|
+
`CANCEL_REQUESTED` with it and settles `canceled` with it across a restart. A
|
|
255
|
+
copy the executor stops without a cancel ends `interrupted`/`EXECUTOR_PAUSED`
|
|
256
|
+
(`interrupted`/`interrupted` after a crash), never `WRITE_FAILED`. A cancel of
|
|
257
|
+
a reference not yet admitted leaves a `canceled` tombstone that a late or
|
|
258
|
+
recovered admission returns instead of copying, and a producer cancel is written
|
|
259
|
+
to the mirror first, so `MoveFromStaging` and the worker sweep forward it rather
|
|
260
|
+
than admit. See the delegate guide's Cancellation table.
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
The pinned scope-selection task also binds the protected generation observed before confirmation. The executor compares it under the publish lock and refuses stale tasks, so a retained task cannot replay an older selection after another confirmation.
|
|
@@ -12,12 +12,14 @@ import (
|
|
|
12
12
|
"strconv"
|
|
13
13
|
"syscall"
|
|
14
14
|
|
|
15
|
+
"dsmapp/internal/app"
|
|
15
16
|
"dsmapp/internal/background"
|
|
16
17
|
"dsmapp/internal/delegate"
|
|
17
18
|
)
|
|
18
19
|
|
|
19
20
|
// Set by `synopkgland build-spk` through -ldflags -X.
|
|
20
21
|
var packageID = "dev"
|
|
22
|
+
var delegateScope, delegateOperationsJSON, delegateDestinationsJSON, delegateLifetime string
|
|
21
23
|
|
|
22
24
|
func main() {
|
|
23
25
|
log.SetFlags(0)
|
|
@@ -35,6 +37,11 @@ func main() {
|
|
|
35
37
|
log.Printf("started as uid %s", strconv.Itoa(info.UID))
|
|
36
38
|
dataDir := "/var/packages/" + packageID + "/var"
|
|
37
39
|
service := &delegate.Service{Client: delegate.Local(packageID), Store: background.NewStore(dataDir + "/background"), StagingDir: dataDir + "/executor-staging"}
|
|
40
|
+
settings, err := app.ParseDelegateConfig(app.Config{DelegateScope: delegateScope, DelegateOperationsJSON: delegateOperationsJSON, DelegateDestinationsJSON: delegateDestinationsJSON, DelegateLifetime: delegateLifetime})
|
|
41
|
+
if err != nil {
|
|
42
|
+
log.Fatal(err)
|
|
43
|
+
}
|
|
44
|
+
service.Scope, service.Operations, service.Destinations, service.Lifetime = settings.Scope, settings.Operations, settings.Destinations, settings.Lifetime
|
|
38
45
|
if err := service.Run(ctx, info); err != nil {
|
|
39
46
|
log.Fatal(err)
|
|
40
47
|
}
|
|
@@ -4,12 +4,22 @@ import (
|
|
|
4
4
|
"dsmapp/internal/api"
|
|
5
5
|
"dsmapp/internal/background"
|
|
6
6
|
"dsmapp/internal/delegate"
|
|
7
|
+
"dsmapp/internal/filestation"
|
|
7
8
|
"path/filepath"
|
|
8
9
|
)
|
|
9
10
|
|
|
10
11
|
// DelegateRoutes is appended by the CLI's delegate capability assembly.
|
|
11
12
|
// scope comes from the trusted manifest, never an HTTP parameter.
|
|
12
13
|
func DelegateRoutes(cfg Config, scope string) []api.Route {
|
|
13
|
-
service := &delegate.Service{ExecutorDigest: cfg.ExecutorDigest, PolicyDigest: cfg.PolicyDigest, Client: delegate.Local(cfg.PackageID), Store: background.NewRequestStore(filepath.Join(cfg.DataDir, "background")), Scope: scope, StagingDir: filepath.Join(cfg.DataDir, "executor-staging")}
|
|
14
|
+
service := &delegate.Service{ExecutorDigest: cfg.ExecutorDigest, PolicyDigest: cfg.PolicyDigest, Client: delegate.Local(cfg.PackageID), Store: background.NewRequestStore(filepath.Join(cfg.DataDir, "background")), Scope: scope, StagingDir: filepath.Join(cfg.DataDir, "executor-staging"), InstallDraftPath: filepath.Join(cfg.DataDir, "delegate-install.json")}
|
|
15
|
+
settings, err := ParseDelegateConfig(cfg)
|
|
16
|
+
if err == nil {
|
|
17
|
+
service.Destinations, service.Operations, service.Lifetime = settings.Destinations, settings.Operations, settings.Lifetime
|
|
18
|
+
}
|
|
19
|
+
if cfg.SessionFiles != nil {
|
|
20
|
+
service.SessionFiles = cfg.SessionFiles
|
|
21
|
+
} else {
|
|
22
|
+
service.SessionFiles = filestation.Local(cfg.DataDir)
|
|
23
|
+
}
|
|
14
24
|
return service.Routes()
|
|
15
25
|
}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
package app
|
|
2
2
|
|
|
3
3
|
func init() {
|
|
4
|
+
for method, params := range map[string]string{
|
|
5
|
+
"delegate.example.export": `{"key":"save","job_id":"example-1"}`,
|
|
6
|
+
"delegate.destination": `{"key":"save"}`,
|
|
7
|
+
"delegate.select_destination": `{"key":"save","path":"/home"}`,
|
|
8
|
+
"delegate.move_from_staging": `{"delegation_id":"grant","job_id":"export-1","staging":"a","name":"a","size":3}`,
|
|
9
|
+
"delegate.operations.get": `{"delegation_id":"grant","job_id":"export-1"}`,
|
|
10
|
+
"delegate.operations.list": `{}`,
|
|
11
|
+
"delegate.operations.cancel": `{"delegation_id":"grant","job_id":"export-1"}`,
|
|
12
|
+
"delegate.disable": `{}`, "delegate.enable": `{}`, "delegate.audit": `{}`,
|
|
13
|
+
} {
|
|
14
|
+
sampleParams[method] = params
|
|
15
|
+
sampleOutcome[method] = "session_required"
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
sampleParams["delegate.status"] = `{}`
|
|
5
19
|
sampleParams["delegate.create"] = `{"job_id":"job1","ops":["files.write"],"path":"/home","ttl_seconds":60}`
|
|
6
20
|
sampleParams["delegate.list"] = `{}`
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
package background
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"context"
|
|
6
|
+
"encoding/json"
|
|
7
|
+
"errors"
|
|
8
|
+
"io"
|
|
9
|
+
"os"
|
|
10
|
+
"strings"
|
|
11
|
+
"time"
|
|
12
|
+
|
|
13
|
+
"golang.org/x/sys/unix"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
// StagingIdentity identifies a package-owned source for cleanup only. It is
|
|
17
|
+
// never a grant, a UID selector for destination writes, or protected authority.
|
|
18
|
+
type StagingIdentity struct {
|
|
19
|
+
Device, Inode, ParentDevice, ParentInode, RootDevice, RootInode uint64
|
|
20
|
+
UID uint32
|
|
21
|
+
Size, ModifiedNS int64
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type MoveBinding struct {
|
|
25
|
+
JobID string `json:"job_id"`
|
|
26
|
+
DelegationID string `json:"delegation_id"`
|
|
27
|
+
Params json.RawMessage `json:"params"`
|
|
28
|
+
Source StagingIdentity `json:"source"`
|
|
29
|
+
Settled bool `json:"settled,omitempty"`
|
|
30
|
+
CleanupDone bool `json:"cleanup_done,omitempty"`
|
|
31
|
+
Refusal string `json:"refusal,omitempty"`
|
|
32
|
+
// Phase records how far admission got. Older mirrors have none and are
|
|
33
|
+
// treated as possibly sent. Attempts counts sends that may have arrived.
|
|
34
|
+
Phase string `json:"phase,omitempty"`
|
|
35
|
+
Attempts int `json:"attempts,omitempty"`
|
|
36
|
+
NextAttempt int64 `json:"next_attempt,omitempty"`
|
|
37
|
+
// CancelRequested is the producer's durable cancel: it is forwarded until
|
|
38
|
+
// the executor answers, and admission is never sent again.
|
|
39
|
+
CancelRequested bool `json:"cancel_requested,omitempty"`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const (
|
|
43
|
+
MoveReserved = "reserved" // durable before transport; no request sent
|
|
44
|
+
MoveSent = "sent" // a request may have reached the executor
|
|
45
|
+
MoveAccepted = "accepted" // the executor returned the operation
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const maxMoveMirrorBytes = 10 << 20
|
|
49
|
+
|
|
50
|
+
func moveBindingName(id string) string { return "move-" + sha256hex([]byte(id)) + ".json" }
|
|
51
|
+
|
|
52
|
+
func readMoveBinding(root *os.Root, id string) (MoveBinding, error) {
|
|
53
|
+
var out MoveBinding
|
|
54
|
+
f, err := root.OpenFile(moveBindingName(id), os.O_RDONLY|unix.O_NOFOLLOW, 0)
|
|
55
|
+
if err != nil {
|
|
56
|
+
return out, err
|
|
57
|
+
}
|
|
58
|
+
defer f.Close()
|
|
59
|
+
if err = checkPrivate(f); err != nil {
|
|
60
|
+
return out, err
|
|
61
|
+
}
|
|
62
|
+
data, err := io.ReadAll(io.LimitReader(f, 16385))
|
|
63
|
+
if err != nil || len(data) > 16384 || json.Unmarshal(data, &out) != nil || out.JobID != id || out.DelegationID == "" || !json.Valid(out.Params) {
|
|
64
|
+
return MoveBinding{}, ErrInvalid
|
|
65
|
+
}
|
|
66
|
+
return out, nil
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
func (s *Store) MoveBinding(ctx context.Context, id string) (MoveBinding, error) {
|
|
70
|
+
var out MoveBinding
|
|
71
|
+
err := s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
|
|
72
|
+
var err error
|
|
73
|
+
out, err = readMoveBinding(root, id)
|
|
74
|
+
return false, err
|
|
75
|
+
})
|
|
76
|
+
return out, err
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ReserveMove fsyncs a mirror before admission. A process crash or ambiguous
|
|
80
|
+
// response leaves this reference for a status query first; only an operation
|
|
81
|
+
// the executor does not know is admitted again, through ClaimAdmission.
|
|
82
|
+
// A short spool lock covers metadata only, not a socket call or file copy.
|
|
83
|
+
func (s *Store) ReserveMove(ctx context.Context, in MoveBinding) (MoveBinding, bool, error) {
|
|
84
|
+
out := in
|
|
85
|
+
fresh := false
|
|
86
|
+
err := s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
|
|
87
|
+
existing, err := readMoveBinding(root, in.JobID)
|
|
88
|
+
if err == nil {
|
|
89
|
+
if existing.DelegationID != in.DelegationID || !bytes.Equal(existing.Params, in.Params) {
|
|
90
|
+
return false, ErrKeyConflict
|
|
91
|
+
}
|
|
92
|
+
out = existing
|
|
93
|
+
return false, nil
|
|
94
|
+
}
|
|
95
|
+
if !errors.Is(err, os.ErrNotExist) {
|
|
96
|
+
return false, err
|
|
97
|
+
}
|
|
98
|
+
dir, err := root.Open(".")
|
|
99
|
+
if err != nil {
|
|
100
|
+
return false, err
|
|
101
|
+
}
|
|
102
|
+
defer dir.Close()
|
|
103
|
+
entries, err := dir.ReadDir(-1)
|
|
104
|
+
if err != nil {
|
|
105
|
+
return false, err
|
|
106
|
+
}
|
|
107
|
+
var used int64
|
|
108
|
+
for _, e := range entries {
|
|
109
|
+
if strings.HasPrefix(e.Name(), "move-") && strings.HasSuffix(e.Name(), ".json") {
|
|
110
|
+
info, err := e.Info()
|
|
111
|
+
if err != nil {
|
|
112
|
+
return false, err
|
|
113
|
+
}
|
|
114
|
+
used += info.Size()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Completed/uncertain mirrors are retained for local replay prevention.
|
|
118
|
+
// The protected executor owns the authoritative operation/history quota.
|
|
119
|
+
encoded, err := json.Marshal(in)
|
|
120
|
+
if err != nil || len(encoded) > 16384 {
|
|
121
|
+
return false, ErrInvalid
|
|
122
|
+
}
|
|
123
|
+
if used+int64(len(encoded)) > maxMoveMirrorBytes {
|
|
124
|
+
return false, ErrQuota
|
|
125
|
+
}
|
|
126
|
+
if err = writeAtomic(root, moveBindingName(in.JobID), in); err != nil {
|
|
127
|
+
return false, err
|
|
128
|
+
}
|
|
129
|
+
fresh = true
|
|
130
|
+
return false, nil
|
|
131
|
+
})
|
|
132
|
+
return out, fresh, err
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// updateMoveBinding rewrites one existing mirror under the spool lock when
|
|
136
|
+
// change reports a modification.
|
|
137
|
+
func (s *Store) updateMoveBinding(ctx context.Context, id string, change func(*MoveBinding) bool) error {
|
|
138
|
+
return s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
|
|
139
|
+
in, err := readMoveBinding(root, id)
|
|
140
|
+
if err != nil || !change(&in) {
|
|
141
|
+
return false, err
|
|
142
|
+
}
|
|
143
|
+
return false, writeAtomic(root, moveBindingName(id), in)
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ClaimAdmission durably records one send before it happens. Concurrent
|
|
148
|
+
// callers serialize here: a claim is refused for accepted, settled, refused
|
|
149
|
+
// or exhausted mirrors, and before the backoff of the previous send ends.
|
|
150
|
+
func (s *Store) ClaimAdmission(ctx context.Context, id string, now time.Time, limit int, backoff func(int) time.Duration) (MoveBinding, bool, error) {
|
|
151
|
+
var out MoveBinding
|
|
152
|
+
claimed := false
|
|
153
|
+
err := s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
|
|
154
|
+
out = *in
|
|
155
|
+
if in.Phase == MoveAccepted || in.Settled || in.CleanupDone || in.Refusal != "" || in.CancelRequested || in.Attempts >= limit || now.UnixNano() < in.NextAttempt {
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
in.Phase, in.Attempts = MoveSent, in.Attempts+1
|
|
159
|
+
in.NextAttempt = now.Add(backoff(in.Attempts)).UnixNano()
|
|
160
|
+
out, claimed = *in, true
|
|
161
|
+
return true
|
|
162
|
+
})
|
|
163
|
+
return out, claimed, err
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ReleaseAdmission returns a claim the executor proved it did not admit, so
|
|
167
|
+
// the bound counts only sends that might have created an operation.
|
|
168
|
+
func (s *Store) ReleaseAdmission(ctx context.Context, id string) error {
|
|
169
|
+
return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
|
|
170
|
+
if in.Phase != MoveSent {
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
in.Phase, in.Attempts, in.NextAttempt = MoveReserved, in.Attempts-1, 0
|
|
174
|
+
return true
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// RequestMoveCancel durably records a cancel of the mirror bound to the grant.
|
|
179
|
+
func (s *Store) RequestMoveCancel(ctx context.Context, id, delegationID string) error {
|
|
180
|
+
return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
|
|
181
|
+
changed := in.DelegationID == delegationID && !in.CancelRequested
|
|
182
|
+
in.CancelRequested = in.CancelRequested || changed
|
|
183
|
+
return changed
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
func (s *Store) AcceptMove(ctx context.Context, id string) error {
|
|
188
|
+
return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
|
|
189
|
+
changed := in.Phase != MoveAccepted
|
|
190
|
+
in.Phase = MoveAccepted
|
|
191
|
+
return changed
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
func (s *Store) FinishMoveMirror(ctx context.Context, id string, cleaned bool, refusal string) error {
|
|
196
|
+
return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
|
|
197
|
+
in.CleanupDone = in.CleanupDone || cleaned
|
|
198
|
+
in.Settled = in.Settled || cleaned
|
|
199
|
+
if refusal != "" {
|
|
200
|
+
in.Refusal = refusal
|
|
201
|
+
}
|
|
202
|
+
return true
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
func (s *Store) moveBindings(ctx context.Context) ([]MoveBinding, error) {
|
|
207
|
+
out := []MoveBinding{}
|
|
208
|
+
err := s.withJournal(ctx, func(root *os.Root, _ *journal) (bool, error) {
|
|
209
|
+
dir, err := root.Open(".")
|
|
210
|
+
if err != nil {
|
|
211
|
+
return false, err
|
|
212
|
+
}
|
|
213
|
+
defer dir.Close()
|
|
214
|
+
entries, err := dir.ReadDir(-1)
|
|
215
|
+
if err != nil {
|
|
216
|
+
return false, err
|
|
217
|
+
}
|
|
218
|
+
for _, entry := range entries {
|
|
219
|
+
if !strings.HasPrefix(entry.Name(), "move-") || !strings.HasSuffix(entry.Name(), ".json") {
|
|
220
|
+
continue
|
|
221
|
+
}
|
|
222
|
+
// Decode the bounded record to recover its non-path job key; verify it
|
|
223
|
+
// again through readMoveBinding before trusting even this local mirror.
|
|
224
|
+
f, err := root.OpenFile(entry.Name(), os.O_RDONLY|unix.O_NOFOLLOW, 0)
|
|
225
|
+
if err != nil {
|
|
226
|
+
return false, err
|
|
227
|
+
}
|
|
228
|
+
err = checkPrivate(f)
|
|
229
|
+
data, readErr := io.ReadAll(io.LimitReader(f, 16385))
|
|
230
|
+
f.Close()
|
|
231
|
+
var key struct {
|
|
232
|
+
JobID string `json:"job_id"`
|
|
233
|
+
}
|
|
234
|
+
if err != nil || readErr != nil || len(data) > 16384 || json.Unmarshal(data, &key) != nil || entry.Name() != moveBindingName(key.JobID) {
|
|
235
|
+
return false, ErrInvalid
|
|
236
|
+
}
|
|
237
|
+
binding, err := readMoveBinding(root, key.JobID)
|
|
238
|
+
if err != nil {
|
|
239
|
+
return false, err
|
|
240
|
+
}
|
|
241
|
+
out = append(out, binding)
|
|
242
|
+
}
|
|
243
|
+
return false, nil
|
|
244
|
+
})
|
|
245
|
+
return out, err
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
func (s *Store) PendingMoves(ctx context.Context) ([]MoveBinding, error) {
|
|
249
|
+
bindings, err := s.moveBindings(ctx)
|
|
250
|
+
out := []MoveBinding{}
|
|
251
|
+
for _, binding := range bindings {
|
|
252
|
+
if !binding.Settled && !binding.CleanupDone && binding.Refusal == "" {
|
|
253
|
+
out = append(out, binding)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return out, err
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// MoveBindings includes settled/refused history. Callers must apply fresh
|
|
260
|
+
// owner authorization; package mirrors never confer destination authority.
|
|
261
|
+
func (s *Store) MoveBindings(ctx context.Context) ([]MoveBinding, error) { return s.moveBindings(ctx) }
|
|
262
|
+
|
|
263
|
+
// Settled mirrors remain available to explicit status calls and idempotency,
|
|
264
|
+
// but terminal operations do not make the worker poll history indefinitely.
|
|
265
|
+
func (s *Store) SettleMoveMirror(ctx context.Context, id string) error {
|
|
266
|
+
return s.updateMoveBinding(ctx, id, func(in *MoveBinding) bool {
|
|
267
|
+
in.Settled = true
|
|
268
|
+
return true
|
|
269
|
+
})
|
|
270
|
+
}
|