create-windy 0.2.33 → 0.3.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/dist/cli.js +173 -17
- package/package.json +1 -1
- package/template/.agents/skills/windy-business-module/SKILL.md +10 -1
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +9 -0
- package/template/README.md +3 -1
- package/template/apps/agent-server/Dockerfile +1 -0
- package/template/apps/agent-server/README.md +28 -5
- package/template/apps/agent-server/adk_web_agents/__init__.py +1 -0
- package/template/apps/agent-server/adk_web_agents/safe_debug/__init__.py +3 -0
- package/template/apps/agent-server/adk_web_agents/safe_debug/agent.py +40 -0
- package/template/apps/agent-server/pyproject.toml +1 -1
- package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +191 -16
- package/template/apps/agent-server/src/southwind_agent_server/adk_failure.py +13 -0
- package/template/apps/agent-server/src/southwind_agent_server/adk_model.py +225 -0
- package/template/apps/agent-server/src/southwind_agent_server/adk_tools.py +76 -0
- package/template/apps/agent-server/src/southwind_agent_server/app.py +63 -3
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +35 -0
- package/template/apps/agent-server/src/southwind_agent_server/engine.py +2 -0
- package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +31 -3
- package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +22 -9
- package/template/apps/agent-server/src/southwind_agent_server/provider_audit.py +144 -0
- package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +227 -0
- package/template/apps/agent-server/src/southwind_agent_server/service.py +1 -0
- package/template/apps/agent-server/tests/test_adk_adapter.py +305 -0
- package/template/apps/agent-server/tests/test_adk_web_agent.py +12 -0
- package/template/apps/agent-server/tests/test_api.py +16 -1
- package/template/apps/agent-server/tests/test_openai_provider.py +79 -0
- package/template/apps/agent-server/tests/test_provider_governance.py +215 -0
- package/template/apps/server/package.json +4 -1
- package/template/apps/server/src/agent/provider-input-governance.test.ts +82 -0
- package/template/apps/server/src/agent/provider-input-governance.ts +140 -0
- package/template/apps/server/src/agent/remote-runtime.test.ts +22 -0
- package/template/apps/server/src/agent/remote-runtime.ts +1 -0
- package/template/apps/server/src/agent/run-contracts.ts +2 -0
- package/template/apps/server/src/agent/run-facade.test.ts +52 -2
- package/template/apps/server/src/agent/run-facade.ts +38 -9
- package/template/apps/server/src/agent/tool-registry.ts +2 -6
- package/template/apps/server/src/application-services.ts +50 -0
- package/template/apps/server/src/audit/drizzle-log-store.ts +25 -0
- package/template/apps/server/src/audit/search-summary.ts +2 -6
- package/template/apps/server/src/auth/credential-restriction.ts +1 -0
- package/template/apps/server/src/auth/password.ts +30 -21
- package/template/apps/server/src/auth/routes.test.ts +44 -3
- package/template/apps/server/src/auth/routes.ts +6 -1
- package/template/apps/server/src/auth/runtime.ts +4 -1
- package/template/apps/server/src/auth/service.ts +25 -7
- package/template/apps/server/src/configuration/bootstrap.ts +20 -1
- package/template/apps/server/src/configuration/definition.test.ts +71 -0
- package/template/apps/server/src/configuration/definition.ts +242 -12
- package/template/apps/server/src/configuration/drizzle-repository.ts +36 -2
- package/template/apps/server/src/configuration/repository.ts +27 -2
- package/template/apps/server/src/configuration/routes.ts +4 -1
- package/template/apps/server/src/configuration/service.test.ts +100 -0
- package/template/apps/server/src/configuration/service.ts +50 -10
- package/template/apps/server/src/data-access/scoped-repository.integration.test.ts +3 -2
- package/template/apps/server/src/data-governance/export/service.ts +2 -6
- package/template/apps/server/src/example-modules.ts +4 -1
- package/template/apps/server/src/guards.ts +18 -5
- package/template/apps/server/src/http/request-source.test.ts +85 -0
- package/template/apps/server/src/http/request-source.ts +90 -0
- package/template/apps/server/src/index.ts +45 -45
- package/template/apps/server/src/license/routes.ts +2 -0
- package/template/apps/server/src/license/runtime-service.ts +10 -11
- package/template/apps/server/src/module-bootstrap.ts +2 -2
- package/template/apps/server/src/module-host/initialize-contracts.ts +6 -0
- package/template/apps/server/src/module-host/initialize.ts +30 -44
- package/template/apps/server/src/module-host/request-context.ts +29 -23
- package/template/apps/server/src/module-host/resource-file-policies.test.ts +197 -0
- package/template/apps/server/src/module-host/resource-file-policies.ts +108 -0
- package/template/apps/server/src/module-host/route-declaration.ts +45 -0
- package/template/apps/server/src/module-host/route-installer.ts +27 -3
- package/template/apps/server/src/module-host/storage-port.test.ts +170 -1
- package/template/apps/server/src/module-host/storage-port.ts +134 -1
- package/template/apps/server/src/module-host/storage-scope.ts +89 -0
- package/template/apps/server/src/module-host/tool-handlers.test.ts +305 -0
- package/template/apps/server/src/module-host/tool-handlers.ts +38 -4
- package/template/apps/server/src/module-host/user-directory-composition.test.ts +126 -0
- package/template/apps/server/src/module-host/user-directory-port.test.ts +238 -0
- package/template/apps/server/src/module-host/user-directory-port.ts +139 -0
- package/template/apps/server/src/module-host.ts +4 -0
- package/template/apps/server/src/notification/channel-adapter.ts +46 -0
- package/template/apps/server/src/notification/delivery-policy.test.ts +59 -0
- package/template/apps/server/src/notification/delivery-policy.ts +37 -0
- package/template/apps/server/src/notification/delivery-repository.ts +198 -0
- package/template/apps/server/src/notification/delivery-worker.test.ts +87 -0
- package/template/apps/server/src/notification/delivery-worker.ts +88 -0
- package/template/apps/server/src/notification/drizzle-management.ts +180 -0
- package/template/apps/server/src/notification/drizzle-query.ts +160 -0
- package/template/apps/server/src/notification/drizzle-repository.integration.test.ts +301 -0
- package/template/apps/server/src/notification/drizzle-repository.ts +156 -90
- package/template/apps/server/src/notification/extension-routes.test.ts +119 -0
- package/template/apps/server/src/notification/extension-routes.ts +111 -0
- package/template/apps/server/src/notification/memory-delivery-repository.ts +137 -0
- package/template/apps/server/src/notification/memory-support.ts +72 -0
- package/template/apps/server/src/notification/preference-repository.ts +95 -0
- package/template/apps/server/src/notification/recipient-directory.ts +104 -0
- package/template/apps/server/src/notification/repository.test.ts +171 -0
- package/template/apps/server/src/notification/repository.ts +179 -32
- package/template/apps/server/src/notification/revision-routes.test.ts +186 -0
- package/template/apps/server/src/notification/route-support.ts +225 -0
- package/template/apps/server/src/notification/routes.test.ts +182 -0
- package/template/apps/server/src/notification/routes.ts +225 -132
- package/template/apps/server/src/notification/service.test.ts +104 -0
- package/template/apps/server/src/notification/service.ts +140 -0
- package/template/apps/server/src/notification/smtp-adapter.test.ts +65 -0
- package/template/apps/server/src/notification/smtp-adapter.ts +68 -0
- package/template/apps/server/src/persistence.integration.test.ts +41 -2
- package/template/apps/server/src/route-guards.ts +1 -0
- package/template/apps/server/src/runtime-audit-list.test.ts +39 -0
- package/template/apps/server/src/runtime-development.ts +2 -0
- package/template/apps/server/src/runtime.test.ts +23 -9
- package/template/apps/server/src/runtime.ts +39 -2
- package/template/apps/server/src/scheduler/audit.ts +2 -11
- package/template/apps/server/src/scheduler/definitions.test.ts +6 -0
- package/template/apps/server/src/scheduler/definitions.ts +7 -0
- package/template/apps/server/src/scheduler/recovery-service.ts +2 -11
- package/template/apps/server/src/scheduler/routes.ts +2 -7
- package/template/apps/server/src/search/opensearch-client.test.ts +45 -0
- package/template/apps/server/src/search/opensearch-client.ts +145 -0
- package/template/apps/server/src/search/service.ts +2 -6
- package/template/apps/server/src/settings/routes.ts +15 -3
- package/template/apps/server/src/settings/runtime.ts +10 -1
- package/template/apps/server/src/storage/runtime.ts +13 -0
- package/template/apps/server/src/system/audit-query.ts +33 -4
- package/template/apps/server/src/system/audit-routes.test.ts +58 -4
- package/template/apps/server/src/system/audit-routes.ts +6 -5
- package/template/apps/server/src/system/built-in-roles.ts +1 -0
- package/template/apps/server/src/system/department-organization.ts +320 -0
- package/template/apps/server/src/system/department-routes.test.ts +207 -48
- package/template/apps/server/src/system/department-routes.ts +114 -33
- package/template/apps/server/src/system/drizzle-repository.ts +15 -7
- package/template/apps/server/src/system/drizzle-scoped-repository.ts +5 -3
- package/template/apps/server/src/system/drizzle-system.ts +37 -9
- package/template/apps/server/src/system/drizzle-transaction-context.ts +14 -0
- package/template/apps/server/src/system/identity-route-config.ts +7 -2
- package/template/apps/server/src/system/mutation-runner.ts +23 -0
- package/template/apps/server/src/system/organization-postgres.integration.test.ts +176 -0
- package/template/apps/server/src/system/resource-access-response.ts +12 -6
- package/template/apps/server/src/system/role-department-scope-policy.ts +55 -0
- package/template/apps/server/src/system/route-helpers.ts +2 -5
- package/template/apps/server/src/system/route-types.ts +12 -3
- package/template/apps/server/src/system/routes-validation.test.ts +26 -0
- package/template/apps/server/src/system/routes.test.ts +10 -2
- package/template/apps/server/src/system/routes.ts +70 -36
- package/template/apps/server/src/system/seed.ts +7 -0
- package/template/apps/server/src/work-order/data-scope.integration.test.ts +9 -2
- package/template/apps/server/src/work-order/opensearch-index.test.ts +97 -0
- package/template/apps/server/src/work-order/opensearch-index.ts +313 -0
- package/template/apps/server/src/work-order/search-provider.ts +60 -1
- package/template/apps/server/src/work-order/service.ts +42 -10
- package/template/apps/web/src/app/error-pages.ts +9 -0
- package/template/apps/web/src/components/auth/PasswordChangeForm.vue +16 -11
- package/template/apps/web/src/components/auth/PasswordChangeForm.webtest.ts +14 -0
- package/template/apps/web/src/components/common/FormDialog.vue +16 -2
- package/template/apps/web/src/components/common/ModalLayout.webtest.ts +20 -1
- package/template/apps/web/src/composables/useGlobalSearch.ts +68 -0
- package/template/apps/web/src/composables/usePlatformSettings.ts +8 -7
- package/template/apps/web/src/layout/GlobalSearchResults.vue +58 -0
- package/template/apps/web/src/layout/NavigationSearchDialog.vue +42 -6
- package/template/apps/web/src/layout/NavigationSearchDialog.webtest.ts +71 -0
- package/template/apps/web/src/layout/NotificationMenu.vue +73 -31
- package/template/apps/web/src/layout/NotificationMenu.webtest.ts +44 -1
- package/template/apps/web/src/layout/NotificationMenuItem.vue +61 -0
- package/template/apps/web/src/layout/NotificationPreferencesDialog.vue +181 -0
- package/template/apps/web/src/layout/NotificationPreferencesDialog.webtest.ts +80 -0
- package/template/apps/web/src/lib/date-time.ts +22 -10
- package/template/apps/web/src/lib/date-time.webtest.ts +9 -1
- package/template/apps/web/src/main.ts +14 -1
- package/template/apps/web/src/pages/auth/ChangePasswordPage.vue +16 -1
- package/template/apps/web/src/pages/configuration/components/ModuleConfigVersionList.vue +1 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.vue +10 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationWorkbench.vue +37 -6
- package/template/apps/web/src/pages/errors/PlatformErrorPage.vue +115 -0
- package/template/apps/web/src/pages/errors/PlatformErrorPage.webtest.ts +44 -0
- package/template/apps/web/src/pages/errors/error-page-extension.ts +26 -0
- package/template/apps/web/src/pages/system/SystemNotificationsPage.vue +136 -68
- package/template/apps/web/src/pages/system/SystemNotificationsPage.webtest.ts +224 -12
- package/template/apps/web/src/pages/system/audit-log-presenter.ts +86 -0
- package/template/apps/web/src/pages/system/audit-time-range.ts +28 -0
- package/template/apps/web/src/pages/system/components/AuditActionCell.vue +10 -69
- package/template/apps/web/src/pages/system/components/AuditActionCell.webtest.ts +20 -27
- package/template/apps/web/src/pages/system/components/AuditLogDetailDialog.vue +134 -0
- package/template/apps/web/src/pages/system/components/AuditLogDetailDialog.webtest.ts +76 -0
- package/template/apps/web/src/pages/system/components/AuditLogFilters.vue +116 -52
- package/template/apps/web/src/pages/system/components/AuditLogFilters.webtest.ts +52 -15
- package/template/apps/web/src/pages/system/components/NotificationHistoryDialog.vue +129 -0
- package/template/apps/web/src/pages/system/components/NotificationManagementCard.vue +91 -0
- package/template/apps/web/src/pages/system/components/NotificationPublishDialog.vue +121 -0
- package/template/apps/web/src/pages/system/components/NotificationPublishForm.vue +162 -1
- package/template/apps/web/src/pages/system/components/SystemResourceActions.vue +68 -0
- package/template/apps/web/src/pages/system/components/SystemResourceEditor.vue +74 -0
- package/template/apps/web/src/pages/system/components/SystemResourceFilters.vue +3 -4
- package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +91 -98
- package/template/apps/web/src/pages/system/components/SystemResourcePage.webtest.ts +68 -0
- package/template/apps/web/src/pages/system/components/SystemResourceTable.vue +20 -1
- package/template/apps/web/src/pages/system/components/SystemResourceTable.webtest.ts +28 -7
- package/template/apps/web/src/pages/system/components/department/DepartmentOrganizationForm.vue +210 -0
- package/template/apps/web/src/pages/system/components/department/DepartmentTransitionDialog.vue +112 -0
- package/template/apps/web/src/pages/system/components/user-account/UserAccountForm.vue +17 -4
- package/template/apps/web/src/pages/system/composables/useDepartmentTransitions.ts +79 -0
- package/template/apps/web/src/pages/system/composables/useNotificationPermissions.ts +14 -0
- package/template/apps/web/src/pages/system/composables/useSystemResource.ts +2 -0
- package/template/apps/web/src/pages/system/composables/useSystemResource.webtest.ts +15 -2
- package/template/apps/web/src/pages/system/resource-config.ts +12 -4
- package/template/apps/web/src/router/error-navigation.ts +50 -0
- package/template/apps/web/src/router/error-navigation.webtest.ts +106 -0
- package/template/apps/web/src/router/index.ts +71 -0
- package/template/apps/web/src/router/index.webtest.ts +29 -0
- package/template/apps/web/src/router/manifest-routes.webtest.ts +4 -0
- package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
- package/template/apps/web/src/services/auth-api.ts +5 -0
- package/template/apps/web/src/services/http.ts +43 -6
- package/template/apps/web/src/services/http.webtest.ts +70 -0
- package/template/apps/web/src/services/notification-api.ts +85 -2
- package/template/apps/web/src/services/notification-api.webtest.ts +110 -0
- package/template/apps/web/src/services/search-api.ts +39 -0
- package/template/apps/web/src/services/system-api.ts +18 -0
- package/template/apps/web/vitest.config.ts +1 -0
- package/template/docker-compose.yml +68 -0
- package/template/docs/architecture/ai-egress.md +49 -7
- package/template/docs/architecture/ai-runtime.md +34 -6
- package/template/docs/architecture/data-scope-query-enforcement.md +4 -0
- package/template/docs/architecture/object-storage.md +22 -2
- package/template/docs/architecture/search-provider-protocol.md +38 -2
- package/template/docs/development/custom-error-pages.md +78 -0
- package/template/docs/development/custom-login-page.md +3 -3
- package/template/docs/platform/agent-runtime.md +76 -7
- package/template/docs/platform/audit-reliability.md +46 -2
- package/template/docs/platform/business-user-directory.md +82 -0
- package/template/docs/platform/module-configuration.md +13 -4
- package/template/docs/platform/notifications.md +67 -11
- package/template/docs/platform/organization-membership.md +17 -3
- package/template/docs/platform/system-crud-api.md +16 -0
- package/template/docs/platform/web-system-crud.md +6 -2
- package/template/package.json +4 -0
- package/template/packages/config/index.test.ts +45 -0
- package/template/packages/config/package.json +1 -1
- package/template/packages/config/src/platform.ts +169 -48
- package/template/packages/database/drizzle/0035_material_nightshade.sql +10 -0
- package/template/packages/database/drizzle/0036_hesitant_speed.sql +35 -0
- package/template/packages/database/drizzle/0037_absent_nick_fury.sql +2 -0
- package/template/packages/database/drizzle/0038_uneven_wasp.sql +38 -0
- package/template/packages/database/drizzle/meta/0035_snapshot.json +7331 -0
- package/template/packages/database/drizzle/meta/0036_snapshot.json +7436 -0
- package/template/packages/database/drizzle/meta/0037_snapshot.json +7457 -0
- package/template/packages/database/drizzle/meta/0038_snapshot.json +7749 -0
- package/template/packages/database/drizzle/meta/_journal.json +28 -0
- package/template/packages/database/package.json +1 -1
- package/template/packages/database/src/schema/identity.ts +7 -0
- package/template/packages/database/src/schema/notifications.ts +135 -0
- package/template/packages/database/src/schema-notification-delivery.test.ts +54 -0
- package/template/packages/database/src/schema-workflow-notification.test.ts +40 -1
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/ai-operation-composition.test.ts +68 -0
- package/template/packages/modules/src/ai-operation-composition.ts +115 -0
- package/template/packages/modules/src/manifest.ts +26 -0
- package/template/packages/modules/src/provider-data-policy-composition.test.ts +74 -0
- package/template/packages/modules/src/system-api-permissions.ts +54 -0
- package/template/packages/modules/src/system-audit-actions.ts +15 -0
- package/template/packages/modules/src/system-features.ts +6 -1
- package/template/packages/modules/src/system-module-catalog.test.ts +16 -0
- package/template/packages/modules/src/system-module-catalog.ts +28 -4
- package/template/packages/modules/src/system-modules.test.ts +13 -1
- package/template/packages/modules/src/system-modules.ts +12 -0
- package/template/packages/modules/src/system-permissions.ts +11 -5
- package/template/packages/server-sdk/index.ts +11 -0
- package/template/packages/server-sdk/package.json +3 -2
- package/template/packages/server-sdk/src/ai-operation-registration.ts +2 -1
- package/template/packages/server-sdk/src/module-host.ts +8 -0
- package/template/packages/server-sdk/src/request-context.ts +2 -0
- package/template/packages/server-sdk/src/storage-port.ts +66 -0
- package/template/packages/server-sdk/src/tool-registration.ts +6 -0
- package/template/packages/server-sdk/src/user-directory-port.ts +42 -0
- package/template/packages/shared/package.json +1 -1
- package/template/packages/shared/src/audit.ts +25 -0
- package/template/packages/shared/src/module-configuration.ts +5 -0
- package/template/packages/shared/src/notification.ts +92 -1
- package/template/packages/shared/src/password.ts +7 -2
- package/template/packages/shared/src/platform-settings.ts +2 -0
- package/template/packages/storage/package.json +1 -1
- package/template/packages/storage/src/upload-service.test.ts +16 -0
- package/template/packages/storage/src/upload-service.ts +5 -1
- package/template/scripts/notification-postgres-regression.ts +27 -0
|
@@ -17,6 +17,7 @@ import { createWorkOrderRepository } from "./work-order/repository.js";
|
|
|
17
17
|
import { createDrizzleWorkOrderRepository } from "./work-order/drizzle-repository.js";
|
|
18
18
|
import { createWorkOrderRouteDefinitions } from "./work-order/routes.js";
|
|
19
19
|
import { WorkOrderSearchProvider } from "./work-order/search-provider.js";
|
|
20
|
+
import { createWorkOrderOpenSearchIndex } from "./work-order/opensearch-index.js";
|
|
20
21
|
import { WorkOrderService } from "./work-order/service.js";
|
|
21
22
|
|
|
22
23
|
export interface WorkOrderModuleDependencies {
|
|
@@ -42,6 +43,7 @@ export interface WorkOrderModule {
|
|
|
42
43
|
*/
|
|
43
44
|
export function createWorkOrderModule(): WorkOrderModule {
|
|
44
45
|
let service: WorkOrderService | undefined;
|
|
46
|
+
const searchIndex = createWorkOrderOpenSearchIndex(process.env);
|
|
45
47
|
const requireService = () => {
|
|
46
48
|
if (!service) throw new Error("示例工单模块尚未挂载");
|
|
47
49
|
return service;
|
|
@@ -52,7 +54,7 @@ export function createWorkOrderModule(): WorkOrderModule {
|
|
|
52
54
|
requireService().operationalSnapshot(
|
|
53
55
|
platformDataActor("task_work_order_snapshot", "工单运营快照任务"),
|
|
54
56
|
),
|
|
55
|
-
searchProvider: new WorkOrderSearchProvider(requireService),
|
|
57
|
+
searchProvider: new WorkOrderSearchProvider(requireService, searchIndex),
|
|
56
58
|
});
|
|
57
59
|
return {
|
|
58
60
|
...serverModule,
|
|
@@ -67,6 +69,7 @@ export function createWorkOrderModule(): WorkOrderModule {
|
|
|
67
69
|
? createDrizzleWorkOrderRepository(dependencies.db)
|
|
68
70
|
: createWorkOrderRepository()),
|
|
69
71
|
dependencies.departments,
|
|
72
|
+
searchIndex,
|
|
70
73
|
);
|
|
71
74
|
},
|
|
72
75
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ApiPermissionBinding,
|
|
3
|
+
AuditActor,
|
|
3
4
|
AuditEvent,
|
|
4
5
|
EntitlementKey,
|
|
5
6
|
FeatureFlagDefinition,
|
|
@@ -33,6 +34,7 @@ export interface RequestGuardContext {
|
|
|
33
34
|
actor: RequestActor;
|
|
34
35
|
startedAt: string;
|
|
35
36
|
clientIp?: string;
|
|
37
|
+
userAgent?: string;
|
|
36
38
|
license?: {
|
|
37
39
|
versionKey?: LicenseVersionKey;
|
|
38
40
|
/** V1 兼容字段。新 License 不再包含 Entitlement。 */
|
|
@@ -61,6 +63,7 @@ export interface GuardDecision {
|
|
|
61
63
|
|
|
62
64
|
export interface RequestGuardContextOptions {
|
|
63
65
|
clientIp?: string;
|
|
66
|
+
userAgent?: string;
|
|
64
67
|
resolveActor?: (request: Request) => RequestActor | undefined;
|
|
65
68
|
resolveLicense?: (
|
|
66
69
|
request: Request,
|
|
@@ -86,10 +89,24 @@ export function createRequestGuardContext(
|
|
|
86
89
|
actor: options.resolveActor?.(request) || anonymousActor(),
|
|
87
90
|
startedAt: new Date().toISOString(),
|
|
88
91
|
clientIp: options.clientIp,
|
|
92
|
+
userAgent: options.userAgent,
|
|
89
93
|
license: options.resolveLicense?.(request),
|
|
90
94
|
};
|
|
91
95
|
}
|
|
92
96
|
|
|
97
|
+
export function auditActor(
|
|
98
|
+
context: Pick<RequestGuardContext, "actor" | "clientIp" | "userAgent">,
|
|
99
|
+
): AuditActor {
|
|
100
|
+
return {
|
|
101
|
+
id: context.actor.id,
|
|
102
|
+
type: context.actor.type === "anonymous" ? "user" : context.actor.type,
|
|
103
|
+
name: context.actor.name,
|
|
104
|
+
roleCodes: context.actor.roleCodes,
|
|
105
|
+
ip: context.clientIp,
|
|
106
|
+
userAgent: context.userAgent,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
93
110
|
export function evaluatePermissionGuard(
|
|
94
111
|
context: RequestGuardContext,
|
|
95
112
|
binding: PermissionGuardRequirement,
|
|
@@ -207,11 +224,7 @@ function deniedDecision(
|
|
|
207
224
|
id: randomUUIDv7(),
|
|
208
225
|
action: "security.denied",
|
|
209
226
|
outcome: "denied",
|
|
210
|
-
actor:
|
|
211
|
-
id: context.actor.id,
|
|
212
|
-
type: context.actor.type === "anonymous" ? "user" : context.actor.type,
|
|
213
|
-
name: context.actor.name,
|
|
214
|
-
},
|
|
227
|
+
actor: auditActor(context),
|
|
215
228
|
target: {
|
|
216
229
|
type: "guard",
|
|
217
230
|
id: targetId,
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
requestSourcePolicyFromEnv,
|
|
4
|
+
resolveRequestSource,
|
|
5
|
+
} from "./request-source.js";
|
|
6
|
+
|
|
7
|
+
describe("平台请求来源信任边界", () => {
|
|
8
|
+
test("默认使用直接对端并忽略客户端伪造的转发头", () => {
|
|
9
|
+
const source = resolveRequestSource(
|
|
10
|
+
request("203.0.113.66"),
|
|
11
|
+
"198.51.100.10",
|
|
12
|
+
requestSourcePolicyFromEnv({}),
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
expect(source).toEqual({
|
|
16
|
+
clientIp: "198.51.100.10",
|
|
17
|
+
userAgent: "Windy-Test/1.0",
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("仅显式启用且直接对端受信时采用单一合法转发来源", () => {
|
|
22
|
+
const policy = requestSourcePolicyFromEnv({
|
|
23
|
+
WINDY_TRUST_PROXY: "true",
|
|
24
|
+
WINDY_TRUSTED_PROXY_IPS: "10.0.0.8",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect(
|
|
28
|
+
resolveRequestSource(request("203.0.113.66"), "::1", policy).clientIp,
|
|
29
|
+
).toBe("203.0.113.66");
|
|
30
|
+
expect(
|
|
31
|
+
resolveRequestSource(request("203.0.113.67"), "10.0.0.8", policy)
|
|
32
|
+
.clientIp,
|
|
33
|
+
).toBe("203.0.113.67");
|
|
34
|
+
expect(
|
|
35
|
+
resolveRequestSource(request("203.0.113.68"), "10.0.0.9", policy)
|
|
36
|
+
.clientIp,
|
|
37
|
+
).toBe("10.0.0.9");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("多段或非法转发来源退回直接对端", () => {
|
|
41
|
+
const policy = requestSourcePolicyFromEnv({
|
|
42
|
+
WINDY_TRUST_PROXY: "true",
|
|
43
|
+
});
|
|
44
|
+
for (const forwardedFor of [
|
|
45
|
+
"203.0.113.66, 198.51.100.9",
|
|
46
|
+
"not-an-ip",
|
|
47
|
+
"203.0.113.66:443",
|
|
48
|
+
]) {
|
|
49
|
+
expect(
|
|
50
|
+
resolveRequestSource(request(forwardedFor), "127.0.0.1", policy)
|
|
51
|
+
.clientIp,
|
|
52
|
+
).toBe("127.0.0.1");
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("代理配置默认关闭且错误配置 fail closed", () => {
|
|
57
|
+
expect(requestSourcePolicyFromEnv({})).toEqual({
|
|
58
|
+
trustProxy: false,
|
|
59
|
+
trustedProxyIps: [],
|
|
60
|
+
});
|
|
61
|
+
expect(() =>
|
|
62
|
+
requestSourcePolicyFromEnv({
|
|
63
|
+
WINDY_TRUSTED_PROXY_IPS: "10.0.0.8",
|
|
64
|
+
}),
|
|
65
|
+
).toThrow("WINDY_TRUST_PROXY=true");
|
|
66
|
+
expect(() =>
|
|
67
|
+
requestSourcePolicyFromEnv({ WINDY_TRUST_PROXY: "yes" }),
|
|
68
|
+
).toThrow("只允许 true 或 false");
|
|
69
|
+
expect(() =>
|
|
70
|
+
requestSourcePolicyFromEnv({
|
|
71
|
+
WINDY_TRUST_PROXY: "true",
|
|
72
|
+
WINDY_TRUSTED_PROXY_IPS: "10.0.0.999",
|
|
73
|
+
}),
|
|
74
|
+
).toThrow("无效 IP");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
function request(forwardedFor: string): Request {
|
|
79
|
+
return new Request("https://windy.example.test/api/system/users", {
|
|
80
|
+
headers: {
|
|
81
|
+
"user-agent": "Windy-Test/1.0",
|
|
82
|
+
"x-forwarded-for": forwardedFor,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
|
|
3
|
+
export interface RequestSourcePolicy {
|
|
4
|
+
trustProxy: boolean;
|
|
5
|
+
trustedProxyIps: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface RequestSource {
|
|
9
|
+
clientIp?: string;
|
|
10
|
+
userAgent?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function requestSourcePolicyFromEnv(
|
|
14
|
+
env: Record<string, string | undefined>,
|
|
15
|
+
): RequestSourcePolicy {
|
|
16
|
+
const trustProxy = readBoolean(env.WINDY_TRUST_PROXY);
|
|
17
|
+
const configuredIps = (env.WINDY_TRUSTED_PROXY_IPS || "")
|
|
18
|
+
.split(",")
|
|
19
|
+
.map((value) => value.trim())
|
|
20
|
+
.filter(Boolean);
|
|
21
|
+
if (!trustProxy && configuredIps.length) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"配置 WINDY_TRUSTED_PROXY_IPS 时必须显式设置 WINDY_TRUST_PROXY=true",
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
trustProxy,
|
|
28
|
+
trustedProxyIps: configuredIps.map((value) => {
|
|
29
|
+
const normalized = normalizeIp(value);
|
|
30
|
+
if (!normalized) {
|
|
31
|
+
throw new Error(`WINDY_TRUSTED_PROXY_IPS 包含无效 IP:${value}`);
|
|
32
|
+
}
|
|
33
|
+
return normalized;
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function resolveRequestSource(
|
|
39
|
+
request: Request,
|
|
40
|
+
peerIp: string | undefined,
|
|
41
|
+
policy: RequestSourcePolicy,
|
|
42
|
+
): RequestSource {
|
|
43
|
+
const normalizedPeerIp = normalizeIp(peerIp);
|
|
44
|
+
const forwardedIp = resolveForwardedIp(request, normalizedPeerIp, policy);
|
|
45
|
+
return {
|
|
46
|
+
clientIp: forwardedIp || normalizedPeerIp,
|
|
47
|
+
userAgent: normalizeUserAgent(request.headers.get("user-agent")),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resolveForwardedIp(
|
|
52
|
+
request: Request,
|
|
53
|
+
peerIp: string | undefined,
|
|
54
|
+
policy: RequestSourcePolicy,
|
|
55
|
+
): string | undefined {
|
|
56
|
+
if (!policy.trustProxy || !peerIp || !isTrustedProxy(peerIp, policy)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const header = request.headers.get("x-forwarded-for")?.trim();
|
|
60
|
+
if (!header || header.includes(",")) return undefined;
|
|
61
|
+
return normalizeIp(header);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function isTrustedProxy(peerIp: string, policy: RequestSourcePolicy): boolean {
|
|
65
|
+
if (isLoopback(peerIp)) return true;
|
|
66
|
+
return policy.trustedProxyIps.some((value) => normalizeIp(value) === peerIp);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isLoopback(ip: string): boolean {
|
|
70
|
+
return ip === "::1" || (isIP(ip) === 4 && ip.startsWith("127."));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function normalizeIp(value: string | undefined): string | undefined {
|
|
74
|
+
const candidate = value?.trim().toLowerCase();
|
|
75
|
+
if (!candidate) return undefined;
|
|
76
|
+
const mapped = candidate.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/)?.[1];
|
|
77
|
+
const normalized = mapped && isIP(mapped) === 4 ? mapped : candidate;
|
|
78
|
+
return isIP(normalized) ? normalized : undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function normalizeUserAgent(value: string | null): string | undefined {
|
|
82
|
+
const normalized = value?.trim();
|
|
83
|
+
return normalized ? normalized.slice(0, 1_024) : undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function readBoolean(value: string | undefined): boolean {
|
|
87
|
+
if (value === undefined || value === "" || value === "false") return false;
|
|
88
|
+
if (value === "true") return true;
|
|
89
|
+
throw new Error("WINDY_TRUST_PROXY 只允许 true 或 false");
|
|
90
|
+
}
|
|
@@ -104,6 +104,7 @@ const {
|
|
|
104
104
|
moduleHosts,
|
|
105
105
|
systemRepositories,
|
|
106
106
|
} = await bootstrapServerModules(platformConfig, persistence);
|
|
107
|
+
const features = foundationSnapshot.features;
|
|
107
108
|
// @windy-module system.license begin
|
|
108
109
|
const platformLicenseOptions = createPlatformLicenseRuntimeOptions(process.env);
|
|
109
110
|
const platformLicenseRuntime = new PlatformLicenseRuntime(
|
|
@@ -121,7 +122,7 @@ const runtime = createServerRuntime(process.env, {
|
|
|
121
122
|
: persistence?.licenseResolver,
|
|
122
123
|
// @windy-module system.license end
|
|
123
124
|
featureResolver: persistence ? systemRepositories.features : undefined,
|
|
124
|
-
featureCatalog:
|
|
125
|
+
featureCatalog: features,
|
|
125
126
|
// @windy-module system.audit begin
|
|
126
127
|
auditReader: persistence?.auditReader,
|
|
127
128
|
auditWriter: persistence?.auditWriter,
|
|
@@ -140,7 +141,11 @@ platformLicenseRuntime.setAuditSink(runtime.auditSink);
|
|
|
140
141
|
// @windy-module system.license end
|
|
141
142
|
const { authRepository, authService } = createAuthRuntime({
|
|
142
143
|
repository: persistence?.authRepository,
|
|
143
|
-
sessionTtlSeconds: platformConfig.security.sessionTtlSeconds,
|
|
144
|
+
sessionTtlSeconds: () => platformConfig.security.sessionTtlSeconds,
|
|
145
|
+
passwordPolicy: () => ({
|
|
146
|
+
minLength: platformConfig.security.passwordMinLength,
|
|
147
|
+
maxLength: platformConfig.security.passwordMaxLength,
|
|
148
|
+
}),
|
|
144
149
|
auditWriter: (event) => runtime.auditSink.recordCriticalEvent(event),
|
|
145
150
|
// @windy-module system.audit begin
|
|
146
151
|
auditReader: persistence?.auditReader,
|
|
@@ -152,12 +157,17 @@ const storageRuntime = createStorageRuntime(
|
|
|
152
157
|
persistence?.db,
|
|
153
158
|
moduleHosts.uploadPolicies,
|
|
154
159
|
);
|
|
160
|
+
configurationRuntime.bindStorage(storageRuntime.uploads);
|
|
155
161
|
// @windy-module system.storage end
|
|
156
162
|
// @windy-module system.settings begin
|
|
157
|
-
const platformSettings = createPlatformSettingsRuntime(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
163
|
+
const platformSettings = createPlatformSettingsRuntime(
|
|
164
|
+
persistence?.db,
|
|
165
|
+
{
|
|
166
|
+
softwareName: platformConfig.name,
|
|
167
|
+
logoUrl: platformConfig.logoUrl,
|
|
168
|
+
},
|
|
169
|
+
() => ({ timeZone: platformConfig.regional.timeZone }),
|
|
170
|
+
);
|
|
161
171
|
// @windy-module system.settings end
|
|
162
172
|
// @windy-module system.search begin
|
|
163
173
|
const searchHost = createSearchHost(
|
|
@@ -169,13 +179,14 @@ const searchHost = createSearchHost(
|
|
|
169
179
|
// @windy-module system.scheduler begin
|
|
170
180
|
const moduleTaskDefinitions = createModuleTaskDefinitions(
|
|
171
181
|
moduleHosts,
|
|
172
|
-
|
|
182
|
+
features,
|
|
173
183
|
);
|
|
174
184
|
const {
|
|
175
185
|
bulkDataService,
|
|
176
186
|
scheduler,
|
|
177
187
|
taskDefinitions: scheduledTaskDefinitions,
|
|
178
188
|
notifications: notificationRepository,
|
|
189
|
+
notificationService,
|
|
179
190
|
workflow: workflowService,
|
|
180
191
|
governedExportService,
|
|
181
192
|
durable: durableJobRuntime,
|
|
@@ -187,6 +198,7 @@ const {
|
|
|
187
198
|
storage: storageRuntime,
|
|
188
199
|
moduleTasks: moduleTaskDefinitions,
|
|
189
200
|
bulkRetentionDays: readPositiveInt(process.env.BULK_DATA_RETENTION_DAYS, 7),
|
|
201
|
+
mailConfig: platformConfig.mail,
|
|
190
202
|
installModuleDurableHandlers: moduleHosts.installDurableHandlers,
|
|
191
203
|
});
|
|
192
204
|
const schedulerWorker = new SchedulerWorker(
|
|
@@ -209,33 +221,29 @@ registerAuthRoutes(app, authService, {
|
|
|
209
221
|
sessionCookieName: platformConfig.security.sessionCookieName,
|
|
210
222
|
secureCookie: process.env.NODE_ENV === "production",
|
|
211
223
|
});
|
|
212
|
-
registerProfileRoutes(
|
|
213
|
-
app,
|
|
214
|
-
authRepository,
|
|
215
|
-
runtime,
|
|
216
|
-
foundationSnapshot.features,
|
|
217
|
-
);
|
|
224
|
+
registerProfileRoutes(app, authRepository, runtime, features);
|
|
218
225
|
|
|
219
226
|
// @windy-module system.license begin
|
|
220
227
|
registerPlatformLicenseRoutes(app, platformLicenseRuntime);
|
|
221
228
|
// @windy-module system.license end
|
|
222
229
|
|
|
223
230
|
// @windy-module system.settings begin
|
|
224
|
-
platformSettings.register(app, runtime,
|
|
231
|
+
platformSettings.register(app, runtime, features);
|
|
225
232
|
// @windy-module system.settings end
|
|
226
233
|
// @windy-module system.notification begin
|
|
227
234
|
registerNotificationRoutes(
|
|
228
235
|
app,
|
|
229
236
|
notificationRepository,
|
|
230
237
|
runtime,
|
|
231
|
-
|
|
238
|
+
features,
|
|
239
|
+
notificationService,
|
|
232
240
|
);
|
|
233
241
|
// @windy-module system.notification end
|
|
234
242
|
// @windy-module system.workflow begin
|
|
235
243
|
registerWorkflowRoutes(app, workflowService, runtime);
|
|
236
244
|
// @windy-module system.workflow end
|
|
237
245
|
// @windy-module system.configuration begin
|
|
238
|
-
configurationRuntime.register(app, runtime,
|
|
246
|
+
configurationRuntime.register(app, runtime, features);
|
|
239
247
|
// @windy-module system.configuration end
|
|
240
248
|
// @windy-module system.storage begin
|
|
241
249
|
registerStorageRoutes(
|
|
@@ -248,7 +256,7 @@ registerStorageRoutes(
|
|
|
248
256
|
`/api/platform/files/${fileId}`,
|
|
249
257
|
},
|
|
250
258
|
runtime,
|
|
251
|
-
|
|
259
|
+
features,
|
|
252
260
|
);
|
|
253
261
|
// @windy-module system.storage end
|
|
254
262
|
// @windy-module system.search begin
|
|
@@ -260,27 +268,18 @@ registerAdminBootstrapRoute(app, runtime, {
|
|
|
260
268
|
snapshot: foundationSnapshot,
|
|
261
269
|
loadMenus: () => systemRepositories.menuRegistry.tree(),
|
|
262
270
|
});
|
|
263
|
-
registerSessionContextRoute(app, runtime,
|
|
271
|
+
registerSessionContextRoute(app, runtime, features);
|
|
264
272
|
|
|
265
273
|
registerFoundationRoute(app, runtime, foundationSnapshot, systemRepositories);
|
|
266
274
|
|
|
267
275
|
// @windy-module system.data-governance begin
|
|
268
|
-
registerGovernedUserExportRoutes(
|
|
269
|
-
app,
|
|
270
|
-
governedExportService,
|
|
271
|
-
runtime,
|
|
272
|
-
foundationSnapshot.features,
|
|
273
|
-
);
|
|
276
|
+
registerGovernedUserExportRoutes(app, governedExportService, runtime, features);
|
|
274
277
|
// @windy-module system.data-governance end
|
|
275
|
-
registerSystemRoutes(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
runtime,
|
|
279
|
-
foundationSnapshot.features,
|
|
280
|
-
{ authRepository: persistence?.authRepository },
|
|
281
|
-
);
|
|
278
|
+
registerSystemRoutes(app, systemRepositories, runtime, features, {
|
|
279
|
+
authRepository: persistence?.authRepository,
|
|
280
|
+
});
|
|
282
281
|
// @windy-module system.operations begin
|
|
283
|
-
registerSystemOperationRoutes(app, runtime,
|
|
282
|
+
registerSystemOperationRoutes(app, runtime, features, {
|
|
284
283
|
redisHealthProbe: configurationRuntime.redisHealthProbe,
|
|
285
284
|
onlineUserProvider: () =>
|
|
286
285
|
persistence?.authRepository.listActiveSessions(
|
|
@@ -293,7 +292,13 @@ registerSystemOperationRoutes(app, runtime, foundationSnapshot.features, {
|
|
|
293
292
|
// @windy-module system.agent begin
|
|
294
293
|
const toolHandlers = new Map([
|
|
295
294
|
...createSystemToolHandlers(systemRepositories, runtime),
|
|
296
|
-
...createModuleToolHandlerMap(moduleHosts
|
|
295
|
+
...createModuleToolHandlerMap(moduleHosts, {
|
|
296
|
+
runtime,
|
|
297
|
+
features: foundationSnapshot.features,
|
|
298
|
+
// @windy-module system.storage begin
|
|
299
|
+
storage: storageRuntime,
|
|
300
|
+
// @windy-module system.storage end
|
|
301
|
+
}),
|
|
297
302
|
]);
|
|
298
303
|
const toolRegistry = new GovernedToolRegistry(
|
|
299
304
|
foundationModules,
|
|
@@ -301,10 +306,7 @@ const toolRegistry = new GovernedToolRegistry(
|
|
|
301
306
|
runtime,
|
|
302
307
|
);
|
|
303
308
|
registerAgentRoutes(app, toolRegistry);
|
|
304
|
-
registerMcpRoutes(
|
|
305
|
-
app,
|
|
306
|
-
new PlatformMcpAdapter(toolRegistry, runtime, foundationSnapshot.features),
|
|
307
|
-
);
|
|
309
|
+
registerMcpRoutes(app, new PlatformMcpAdapter(toolRegistry, runtime, features));
|
|
308
310
|
registerAgentPlatformRuntime({
|
|
309
311
|
app,
|
|
310
312
|
platformConfig,
|
|
@@ -315,19 +317,14 @@ registerAgentPlatformRuntime({
|
|
|
315
317
|
});
|
|
316
318
|
// @windy-module system.agent end
|
|
317
319
|
// @windy-module system.scheduler begin
|
|
318
|
-
registerSchedulerRoutes(app, scheduler, runtime,
|
|
320
|
+
registerSchedulerRoutes(app, scheduler, runtime, features);
|
|
319
321
|
// @windy-module system.scheduler end
|
|
320
322
|
// @windy-module system.bulk-data begin
|
|
321
|
-
registerBulkDataRoutes(
|
|
322
|
-
app,
|
|
323
|
-
bulkDataService,
|
|
324
|
-
runtime,
|
|
325
|
-
foundationSnapshot.features,
|
|
326
|
-
);
|
|
323
|
+
registerBulkDataRoutes(app, bulkDataService, runtime, features);
|
|
327
324
|
// @windy-module system.bulk-data end
|
|
328
325
|
installModuleRoutes(moduleHosts, app, {
|
|
329
326
|
runtime,
|
|
330
|
-
features
|
|
327
|
+
features,
|
|
331
328
|
// @windy-module system.scheduler begin
|
|
332
329
|
jobs: durableJobRuntime.service,
|
|
333
330
|
// @windy-module system.scheduler end
|
|
@@ -337,6 +334,9 @@ installModuleRoutes(moduleHosts, app, {
|
|
|
337
334
|
files: storageRuntime.files,
|
|
338
335
|
},
|
|
339
336
|
// @windy-module system.storage end
|
|
337
|
+
userDirectory: {
|
|
338
|
+
repositories: systemRepositories,
|
|
339
|
+
},
|
|
340
340
|
});
|
|
341
341
|
|
|
342
342
|
validateInstalledRuntime({
|
|
@@ -52,6 +52,8 @@ export function registerPlatformLicenseRoutes(
|
|
|
52
52
|
const installed = await licenseRuntime.install(rawLicense, {
|
|
53
53
|
actor: context.guardContext.actor,
|
|
54
54
|
requestId: context.guardContext.requestId,
|
|
55
|
+
clientIp: context.guardContext.clientIp,
|
|
56
|
+
userAgent: context.guardContext.userAgent,
|
|
55
57
|
});
|
|
56
58
|
if (installed.result.status === "rejected") {
|
|
57
59
|
return Response.json(
|
|
@@ -17,7 +17,11 @@ import type {
|
|
|
17
17
|
LicenseFailureReason,
|
|
18
18
|
SignedLicense,
|
|
19
19
|
} from "@southwind-ai/shared";
|
|
20
|
-
import
|
|
20
|
+
import {
|
|
21
|
+
auditActor,
|
|
22
|
+
type RequestActor,
|
|
23
|
+
type RequestGuardContext,
|
|
24
|
+
} from "../guards.js";
|
|
21
25
|
import type { InMemoryAuditSink } from "../runtime.js";
|
|
22
26
|
import type {
|
|
23
27
|
LicenseEntitlementResolver,
|
|
@@ -57,10 +61,10 @@ export interface PlatformLicenseRuntimeOptions {
|
|
|
57
61
|
now?: () => Date;
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
requestId
|
|
63
|
-
|
|
64
|
+
export type LicenseInstallActorContext = Pick<
|
|
65
|
+
RequestGuardContext,
|
|
66
|
+
"actor" | "requestId" | "clientIp" | "userAgent"
|
|
67
|
+
>;
|
|
64
68
|
|
|
65
69
|
export class PlatformLicenseRuntime implements LicenseEntitlementResolver {
|
|
66
70
|
private readonly stateStorage: LicenseStorage;
|
|
@@ -285,12 +289,7 @@ function installAuditEvent(
|
|
|
285
289
|
id: crypto.randomUUID(),
|
|
286
290
|
action: "license.update",
|
|
287
291
|
outcome: success ? "success" : "failure",
|
|
288
|
-
actor:
|
|
289
|
-
id: context.actor.id,
|
|
290
|
-
type: "user",
|
|
291
|
-
name: context.actor.name,
|
|
292
|
-
roleCodes: context.actor.roleCodes,
|
|
293
|
-
},
|
|
292
|
+
actor: auditActor(context),
|
|
294
293
|
target: {
|
|
295
294
|
type: "runtime-license",
|
|
296
295
|
id: result.license?.claims.licenseId || candidate?.claims.licenseId,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from "./module-host.js";
|
|
18
18
|
import type { ServerPersistence } from "./persistence.js";
|
|
19
19
|
// @windy-module system.storage begin
|
|
20
|
-
import {
|
|
20
|
+
import { createPlatformUploadPolicies } from "./storage/runtime.js";
|
|
21
21
|
// @windy-module system.storage end
|
|
22
22
|
import {
|
|
23
23
|
createSystemRepositories,
|
|
@@ -51,7 +51,7 @@ export async function bootstrapServerModules(
|
|
|
51
51
|
installations: installedBusinessModules,
|
|
52
52
|
baseUploadPolicies: [
|
|
53
53
|
// @windy-module system.storage begin
|
|
54
|
-
...
|
|
54
|
+
...createPlatformUploadPolicies(platformConfig),
|
|
55
55
|
// @windy-module system.storage end
|
|
56
56
|
],
|
|
57
57
|
});
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
ModuleAiOperationHandlerRegistration,
|
|
6
6
|
ModuleInitializer,
|
|
7
7
|
ModuleRolePreset,
|
|
8
|
+
ModuleResourceFileAccessPolicy,
|
|
8
9
|
ModuleRouteDefinition,
|
|
9
10
|
ModuleSearchProvider,
|
|
10
11
|
ModuleTaskHandlerRegistration,
|
|
@@ -54,6 +55,7 @@ export interface InitializeModuleHostsInput {
|
|
|
54
55
|
export interface InitializedModuleHosts {
|
|
55
56
|
readonly manifests: readonly ModuleManifest[];
|
|
56
57
|
readonly uploadPolicies: readonly ModuleUploadPolicy[];
|
|
58
|
+
readonly resourceFileAccessPolicies: readonly ModuleResourceFileAccessPolicy[];
|
|
57
59
|
readonly routes: readonly RegisteredModuleRoute[];
|
|
58
60
|
readonly taskHandlers: readonly RegisteredModuleTaskHandler[];
|
|
59
61
|
readonly toolHandlers: readonly RegisteredModuleToolHandler[];
|
|
@@ -63,5 +65,9 @@ export interface InitializedModuleHosts {
|
|
|
63
65
|
manifestOf(moduleName: string): ModuleManifest;
|
|
64
66
|
/** 该模块经 Host 注册的上传用途集合(不含平台基础用途)。 */
|
|
65
67
|
uploadPurposesOf(moduleName: string): ReadonlySet<string>;
|
|
68
|
+
/** 该模块注册的资源文件读取策略。 */
|
|
69
|
+
resourceFileAccessPoliciesOf(
|
|
70
|
+
moduleName: string,
|
|
71
|
+
): readonly ModuleResourceFileAccessPolicy[];
|
|
66
72
|
installDurableHandlers(registry: DurableHandlerRegistry): void;
|
|
67
73
|
}
|