@stigmer/server 3.21.0 → 3.22.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/authorization/evaluator.d.ts +7 -1
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js.map +1 -1
- package/dist/authorization/list-read-scope.d.ts.map +1 -1
- package/dist/authorization/list-read-scope.js +19 -11
- package/dist/authorization/list-read-scope.js.map +1 -1
- package/dist/authorization/model/organization.d.ts.map +1 -1
- package/dist/authorization/model/organization.js +2 -0
- package/dist/authorization/model/organization.js.map +1 -1
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +2 -0
- package/dist/domain/agent/controller.js.map +1 -1
- package/dist/domain/agentchannel/controller.d.ts.map +1 -1
- package/dist/domain/agentchannel/controller.js +6 -1
- package/dist/domain/agentchannel/controller.js.map +1 -1
- package/dist/domain/agentchannel/steps.d.ts +19 -0
- package/dist/domain/agentchannel/steps.d.ts.map +1 -1
- package/dist/domain/agentchannel/steps.js +32 -0
- package/dist/domain/agentchannel/steps.js.map +1 -1
- package/dist/domain/agentinstance/controller.d.ts +5 -5
- package/dist/domain/agentinstance/controller.d.ts.map +1 -1
- package/dist/domain/agentinstance/controller.js +6 -1
- package/dist/domain/agentinstance/controller.js.map +1 -1
- package/dist/domain/agentinstance/steps.d.ts +43 -8
- package/dist/domain/agentinstance/steps.d.ts.map +1 -1
- package/dist/domain/agentinstance/steps.js +71 -8
- package/dist/domain/agentinstance/steps.js.map +1 -1
- package/dist/domain/agentshare/controller.d.ts.map +1 -1
- package/dist/domain/agentshare/controller.js +7 -1
- package/dist/domain/agentshare/controller.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +58 -0
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +109 -4
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/artifact/controller.js +21 -25
- package/dist/domain/artifact/controller.js.map +1 -1
- package/dist/domain/channelapp/controller.d.ts.map +1 -1
- package/dist/domain/channelapp/controller.js +2 -0
- package/dist/domain/channelapp/controller.js.map +1 -1
- package/dist/domain/environment/controller.d.ts.map +1 -1
- package/dist/domain/environment/controller.js +2 -0
- package/dist/domain/environment/controller.js.map +1 -1
- package/dist/domain/executioncontext/controller.d.ts.map +1 -1
- package/dist/domain/executioncontext/controller.js +2 -0
- package/dist/domain/executioncontext/controller.js.map +1 -1
- package/dist/domain/executioncontext/steps.d.ts.map +1 -1
- package/dist/domain/executioncontext/steps.js +2 -1
- package/dist/domain/executioncontext/steps.js.map +1 -1
- package/dist/domain/mcpserver/connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/connect.js +8 -7
- package/dist/domain/mcpserver/connect.js.map +1 -1
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +2 -0
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/start-connect.js +8 -7
- package/dist/domain/mcpserver/start-connect.js.map +1 -1
- package/dist/domain/memory/controller.d.ts.map +1 -1
- package/dist/domain/memory/controller.js +6 -1
- package/dist/domain/memory/controller.js.map +1 -1
- package/dist/domain/memory/steps.d.ts +23 -0
- package/dist/domain/memory/steps.d.ts.map +1 -1
- package/dist/domain/memory/steps.js +35 -0
- package/dist/domain/memory/steps.js.map +1 -1
- package/dist/domain/oauthapp/controller.d.ts.map +1 -1
- package/dist/domain/oauthapp/controller.js +2 -0
- package/dist/domain/oauthapp/controller.js.map +1 -1
- package/dist/domain/plugin/controller.d.ts.map +1 -1
- package/dist/domain/plugin/controller.js +5 -24
- package/dist/domain/plugin/controller.js.map +1 -1
- package/dist/domain/schedule/controller.d.ts.map +1 -1
- package/dist/domain/schedule/controller.js +7 -1
- package/dist/domain/schedule/controller.js.map +1 -1
- package/dist/domain/schedule/steps.d.ts +19 -0
- package/dist/domain/schedule/steps.d.ts.map +1 -1
- package/dist/domain/schedule/steps.js +32 -0
- package/dist/domain/schedule/steps.js.map +1 -1
- package/dist/domain/session/steps.d.ts +8 -9
- package/dist/domain/session/steps.d.ts.map +1 -1
- package/dist/domain/session/steps.js +17 -21
- package/dist/domain/session/steps.js.map +1 -1
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +8 -17
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +30 -107
- package/dist/domain/workflow/controller.js.map +1 -1
- package/dist/domain/workflow/version-resolution.d.ts +5 -0
- package/dist/domain/workflow/version-resolution.d.ts.map +1 -0
- package/dist/domain/workflow/version-resolution.js +113 -0
- package/dist/domain/workflow/version-resolution.js.map +1 -0
- package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
- package/dist/domain/workflowinstance/controller.js +6 -1
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/domain/workflowinstance/steps.d.ts +20 -0
- package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
- package/dist/domain/workflowinstance/steps.js +39 -0
- package/dist/domain/workflowinstance/steps.js.map +1 -1
- package/dist/extensions/identity.d.ts +19 -0
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js +22 -3
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +41 -7
- package/dist/extensions/list-read-scope.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.js +13 -2
- package/dist/extensions/list-read-scope.js.map +1 -1
- package/dist/pipeline/steps/authorize-resolved-target.d.ts +88 -0
- package/dist/pipeline/steps/authorize-resolved-target.d.ts.map +1 -0
- package/dist/pipeline/steps/authorize-resolved-target.js +36 -0
- package/dist/pipeline/steps/authorize-resolved-target.js.map +1 -0
- package/dist/pipeline/steps/authorize.d.ts +27 -0
- package/dist/pipeline/steps/authorize.d.ts.map +1 -1
- package/dist/pipeline/steps/authorize.js +49 -10
- package/dist/pipeline/steps/authorize.js.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.js +2 -1
- package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-reserved-labels.js +6 -7
- package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
- package/dist/pipeline/steps/helpers.d.ts +9 -5
- package/dist/pipeline/steps/helpers.d.ts.map +1 -1
- package/dist/pipeline/steps/helpers.js +11 -15
- package/dist/pipeline/steps/helpers.js.map +1 -1
- package/dist/pipeline/steps/version-history.d.ts +11 -0
- package/dist/pipeline/steps/version-history.d.ts.map +1 -1
- package/dist/pipeline/steps/version-history.js +26 -0
- package/dist/pipeline/steps/version-history.js.map +1 -1
- package/package.json +6 -6
- package/src/authorization/__tests__/list-read-scope.test.ts +23 -12
- package/src/authorization/__tests__/skip-lane-inventory.test.ts +160 -0
- package/src/authorization/__tests__/wire-permissions.test.ts +5 -5
- package/src/authorization/evaluator.ts +7 -0
- package/src/authorization/list-read-scope.ts +22 -11
- package/src/authorization/model/__tests__/registry.test.ts +2 -0
- package/src/authorization/model/organization.ts +2 -0
- package/src/domain/agent/controller.ts +10 -0
- package/src/domain/agentchannel/__tests__/create-authorization.test.ts +58 -0
- package/src/domain/agentchannel/controller.ts +19 -0
- package/src/domain/agentchannel/steps.ts +40 -0
- package/src/domain/agentinstance/__tests__/create-authorization.composed.test.ts +243 -0
- package/src/domain/agentinstance/__tests__/create-authorization.test.ts +144 -0
- package/src/domain/agentinstance/controller.ts +24 -5
- package/src/domain/agentinstance/steps.ts +82 -8
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +86 -0
- package/src/domain/agentshare/__tests__/member-audience.test.ts +113 -0
- package/src/domain/agentshare/controller.ts +21 -0
- package/src/domain/agentshare/steps.ts +181 -15
- package/src/domain/artifact/controller.ts +18 -22
- package/src/domain/channelapp/controller.ts +10 -0
- package/src/domain/environment/controller.ts +10 -0
- package/src/domain/executioncontext/__tests__/executioncontext.test.ts +1 -0
- package/src/domain/executioncontext/controller.ts +10 -0
- package/src/domain/executioncontext/steps.ts +2 -1
- package/src/domain/mcpserver/connect.ts +11 -10
- package/src/domain/mcpserver/controller.ts +13 -1
- package/src/domain/mcpserver/start-connect.ts +17 -11
- package/src/domain/memory/__tests__/create-authorization.test.ts +59 -0
- package/src/domain/memory/controller.ts +11 -0
- package/src/domain/memory/steps.ts +41 -0
- package/src/domain/oauthapp/controller.ts +10 -0
- package/src/domain/plugin/controller.ts +22 -36
- package/src/domain/schedule/__tests__/create-authorization.test.ts +58 -0
- package/src/domain/schedule/controller.ts +20 -0
- package/src/domain/schedule/steps.ts +45 -2
- package/src/domain/session/steps.ts +24 -32
- package/src/domain/skill/controller.ts +24 -23
- package/src/domain/workflow/controller.ts +58 -145
- package/src/domain/workflow/version-resolution.ts +166 -0
- package/src/domain/workflowinstance/__tests__/create-authorization.test.ts +109 -0
- package/src/domain/workflowinstance/controller.ts +19 -0
- package/src/domain/workflowinstance/steps.ts +49 -1
- package/src/extensions/__tests__/composed-support.ts +38 -4
- package/src/extensions/__tests__/identity.test.ts +44 -1
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +87 -1
- package/src/extensions/__tests__/list-read-scope.test.ts +63 -0
- package/src/extensions/identity.ts +23 -5
- package/src/extensions/list-read-scope.ts +47 -7
- package/src/pipeline/steps/__tests__/authorize-resolved-target.test.ts +285 -0
- package/src/pipeline/steps/authorize-resolved-target.ts +129 -0
- package/src/pipeline/steps/authorize.ts +70 -13
- package/src/pipeline/steps/guard-memory-capture.ts +2 -1
- package/src/pipeline/steps/guard-reserved-labels.ts +6 -9
- package/src/pipeline/steps/helpers.ts +11 -15
- package/src/pipeline/steps/version-history.ts +34 -0
|
@@ -53,7 +53,6 @@ import type {
|
|
|
53
53
|
UpdateVisibilityInput,
|
|
54
54
|
} from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
|
|
55
55
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
56
|
-
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
57
56
|
|
|
58
57
|
import type { ArtifactStorage } from "../../artifactstorage/artifact-storage.js";
|
|
59
58
|
import type { Logger } from "../../boot/logger.js";
|
|
@@ -70,10 +69,12 @@ import { newPipeline } from "../../pipeline/pipeline.js";
|
|
|
70
69
|
import type { PipelineStep } from "../../pipeline/pipeline.js";
|
|
71
70
|
import { callerIdentityOf } from "../../pipeline/interceptors/auth.js";
|
|
72
71
|
import { RequestContext } from "../../pipeline/request-context.js";
|
|
72
|
+
import { newAuthorizeStep } from "../../pipeline/steps/authorize.js";
|
|
73
73
|
import {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
} from "../../pipeline/steps/authorize.js";
|
|
74
|
+
loadedTargetAsMethod,
|
|
75
|
+
newAuthorizeResolvedTargetStep,
|
|
76
|
+
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
77
|
+
import { versionHistoryTarget } from "../../pipeline/steps/version-history.js";
|
|
77
78
|
import { newAuthorizeVisibilityTransitionStep } from "../../pipeline/steps/visibility-gates.js";
|
|
78
79
|
import {
|
|
79
80
|
newCleanupIamPoliciesStep,
|
|
@@ -677,6 +678,12 @@ async function getByReference(
|
|
|
677
678
|
)
|
|
678
679
|
.addStep(newValidateProtoStep())
|
|
679
680
|
.addStep(newLoadSkillByReferenceStep(deps.store))
|
|
681
|
+
.addStep(
|
|
682
|
+
newAuthorizeResolvedTargetStep(
|
|
683
|
+
deps.authorizer,
|
|
684
|
+
loadedTargetAsMethod(SkillQueryController.method.get),
|
|
685
|
+
),
|
|
686
|
+
)
|
|
680
687
|
.build()
|
|
681
688
|
.execute(reqCtx);
|
|
682
689
|
return reqCtx.get(TARGET_RESOURCE_KEY) as Skill;
|
|
@@ -808,26 +815,20 @@ async function listVersions(
|
|
|
808
815
|
)
|
|
809
816
|
.addStep(newValidateProtoStep())
|
|
810
817
|
.addStep(newResolveSkillBySlugStep(deps.store))
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
await authorizeResolvedResource(
|
|
820
|
-
deps.authorizer,
|
|
821
|
-
stepCtx.callerIdentity,
|
|
822
|
-
{
|
|
823
|
-
permission: IamPermission.can_view,
|
|
824
|
-
resourceKind: ApiResourceKind.skill,
|
|
825
|
-
resourceId: stepCtx.get(LIST_VERSIONS_SKILL_ID_KEY) as string,
|
|
826
|
-
},
|
|
818
|
+
// The Java SkillListVersionsHandler's mid-chain can_view on the RESOLVED
|
|
819
|
+
// skill id; the copy is the Java handler's byte-pinned error_msg, and an
|
|
820
|
+
// unknown slug was already answered NOT_FOUND by the resolve step above.
|
|
821
|
+
.addStep(
|
|
822
|
+
newAuthorizeResolvedTargetStep(
|
|
823
|
+
deps.authorizer,
|
|
824
|
+
versionHistoryTarget(
|
|
825
|
+
ApiResourceKind.skill,
|
|
827
826
|
"unauthorized to view skill version history",
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
827
|
+
LIST_VERSIONS_SKILL_ID_KEY,
|
|
828
|
+
),
|
|
829
|
+
"AuthorizeResolvedSkill",
|
|
830
|
+
),
|
|
831
|
+
)
|
|
831
832
|
.addStep(newLoadAndMapVersionsStep(deps.store))
|
|
832
833
|
.build()
|
|
833
834
|
.execute(reqCtx);
|
|
@@ -45,7 +45,6 @@ import {
|
|
|
45
45
|
ApiResourceKind,
|
|
46
46
|
ApiResourceKindSchema,
|
|
47
47
|
} from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
48
|
-
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
49
48
|
import type {
|
|
50
49
|
ApiResourceReference,
|
|
51
50
|
UpdateVisibilityInput,
|
|
@@ -71,9 +70,13 @@ import { callerIdentityOf } from "../../pipeline/interceptors/auth.js";
|
|
|
71
70
|
import { RequestContext } from "../../pipeline/request-context.js";
|
|
72
71
|
import {
|
|
73
72
|
authorizeDirect,
|
|
74
|
-
authorizeResolvedResource,
|
|
75
73
|
newAuthorizeStep,
|
|
76
74
|
} from "../../pipeline/steps/authorize.js";
|
|
75
|
+
import {
|
|
76
|
+
loadedTargetAsMethod,
|
|
77
|
+
newAuthorizeResolvedTargetStep,
|
|
78
|
+
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
79
|
+
import { versionHistoryTarget } from "../../pipeline/steps/version-history.js";
|
|
77
80
|
import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
|
|
78
81
|
import {
|
|
79
82
|
newAuthorizeVisibilityTransitionStep,
|
|
@@ -90,10 +93,7 @@ import {
|
|
|
90
93
|
newExtractResourceIdStep,
|
|
91
94
|
newLoadExistingForDeleteStep,
|
|
92
95
|
} from "../../pipeline/steps/delete.js";
|
|
93
|
-
import {
|
|
94
|
-
findResourceBySlug,
|
|
95
|
-
requireOrgForReference,
|
|
96
|
-
} from "../../pipeline/steps/helpers.js";
|
|
96
|
+
import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
|
|
97
97
|
import {
|
|
98
98
|
newDeleteSearchIndexStep,
|
|
99
99
|
newIndexSearchStep,
|
|
@@ -150,6 +150,7 @@ import {
|
|
|
150
150
|
newValidateWorkflowSpecStep,
|
|
151
151
|
truncateHash,
|
|
152
152
|
} from "./steps.js";
|
|
153
|
+
import { newLoadWorkflowByReferenceStep } from "./version-resolution.js";
|
|
153
154
|
import type { WorkflowInstanceCreatorProvider } from "./steps.js";
|
|
154
155
|
|
|
155
156
|
export interface WorkflowControllerDeps {
|
|
@@ -192,7 +193,7 @@ export function registerWorkflowServices(
|
|
|
192
193
|
});
|
|
193
194
|
router.service(WorkflowQueryController, {
|
|
194
195
|
get: (id, ctx) => get(deps, id, ctx),
|
|
195
|
-
getByReference: (ref) => getByReference(deps, ref),
|
|
196
|
+
getByReference: (ref, ctx) => getByReference(deps, ref, ctx),
|
|
196
197
|
listVersions: (input, ctx) => listVersions(deps, input, ctx),
|
|
197
198
|
getVersion: (input, ctx) => getVersion(deps, input, callerIdentityOf(ctx)),
|
|
198
199
|
});
|
|
@@ -831,130 +832,47 @@ async function get(
|
|
|
831
832
|
return reqCtx.get(TARGET_RESOURCE_KEY) as Workflow;
|
|
832
833
|
}
|
|
833
834
|
|
|
834
|
-
/** A 64-hex value is an exact content hash; anything else is a tag. */
|
|
835
|
-
const WORKFLOW_HASH_PATTERN = /^[a-f0-9]{64}$/;
|
|
836
|
-
|
|
837
835
|
/**
|
|
838
|
-
* getByReference —
|
|
839
|
-
*
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
836
|
+
* getByReference — the slug/org read plus the version ladder, as a chain:
|
|
837
|
+
* Authorize (a no-op under the lane's skip annotation) → ValidateProto →
|
|
838
|
+
* LoadWorkflowByReference (the ladder, version-resolution.ts) →
|
|
839
|
+
* AuthorizeResolvedTarget, which asks of the loaded head's id exactly what
|
|
840
|
+
* `get` asks by id, so a slug reveals nothing a member could not read
|
|
841
|
+
* through the id. The archived snapshot shares the head's id, so the check
|
|
842
|
+
* on a versioned read is the check on the head.
|
|
845
843
|
*/
|
|
846
844
|
async function getByReference(
|
|
847
845
|
deps: WorkflowControllerDeps,
|
|
848
846
|
ref: ApiResourceReference,
|
|
847
|
+
ctx: HandlerContext,
|
|
849
848
|
): Promise<Workflow> {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
// empty-org reference is under-specified.
|
|
856
|
-
requireOrgForReference(ApiResourceKind.workflow, ref.org);
|
|
857
|
-
|
|
858
|
-
if (
|
|
859
|
-
ref.kind !== ApiResourceKind.api_resource_kind_unknown &&
|
|
860
|
-
ref.kind !== ApiResourceKind.workflow
|
|
861
|
-
) {
|
|
862
|
-
// Go renders both sides with .String(): the NAME for defined values and
|
|
863
|
-
// the bare NUMBER for unknown ones (proto3 open enums preserve them, and
|
|
864
|
-
// ref.kind carries no defined_only rule) — enumToJson would throw on the
|
|
865
|
-
// unknown arm (panel finding).
|
|
866
|
-
const got = ApiResourceKind[ref.kind] ?? String(ref.kind);
|
|
867
|
-
throw invalidArgumentError(
|
|
868
|
-
`kind mismatch: expected ${ApiResourceKind[ApiResourceKind.workflow]}, got ${got}`,
|
|
869
|
-
);
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
let mainWorkflow: Workflow | undefined;
|
|
873
|
-
try {
|
|
874
|
-
mainWorkflow = await findResourceBySlug(
|
|
875
|
-
deps.store,
|
|
876
|
-
ApiResourceKind.workflow,
|
|
877
|
-
WorkflowSchema,
|
|
878
|
-
ref.slug,
|
|
879
|
-
ref.org,
|
|
880
|
-
);
|
|
881
|
-
} catch (error) {
|
|
882
|
-
// Go wraps the slug scan's store failure (query.go:110) — without this
|
|
883
|
-
// the raw storage error would cross the wire as Unknown (panel finding).
|
|
884
|
-
throw internalError(error, "failed to list workflows");
|
|
885
|
-
}
|
|
886
|
-
if (mainWorkflow === undefined) {
|
|
887
|
-
throw notFoundError("workflow", ref.slug);
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
const version = ref.version.trim();
|
|
891
|
-
if (version === "" || version === "latest") {
|
|
892
|
-
return mainWorkflow;
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
if (workflowMatchesVersion(mainWorkflow, version)) {
|
|
896
|
-
return mainWorkflow;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
const archived = await findAuditWorkflowByVersion(
|
|
900
|
-
deps.store,
|
|
901
|
-
mainWorkflow.metadata!.id,
|
|
902
|
-
version,
|
|
849
|
+
const reqCtx = new RequestContext(
|
|
850
|
+
WorkflowQueryController.method.getByReference.input,
|
|
851
|
+
ref,
|
|
852
|
+
callerIdentityOf(ctx),
|
|
853
|
+
kindOf(ctx),
|
|
903
854
|
);
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
)
|
|
925
|
-
let rec: AuditRecord;
|
|
926
|
-
try {
|
|
927
|
-
rec = WORKFLOW_HASH_PATTERN.test(version)
|
|
928
|
-
? await store.getAuditRecordByHash(
|
|
929
|
-
ApiResourceKind.workflow,
|
|
930
|
-
workflowId,
|
|
931
|
-
version,
|
|
932
|
-
)
|
|
933
|
-
: await store.getAuditRecordByTag(
|
|
934
|
-
ApiResourceKind.workflow,
|
|
935
|
-
workflowId,
|
|
936
|
-
version,
|
|
937
|
-
);
|
|
938
|
-
} catch (error) {
|
|
939
|
-
if (error instanceof AuditNotFoundError) {
|
|
940
|
-
return undefined;
|
|
941
|
-
}
|
|
942
|
-
throw internalError(error, "failed to query workflow audit by version");
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
let wf: Workflow;
|
|
946
|
-
try {
|
|
947
|
-
wf = fromBinary(WorkflowSchema, rec.data);
|
|
948
|
-
} catch (error) {
|
|
949
|
-
throw internalError(error, "failed to decode archived workflow version");
|
|
950
|
-
}
|
|
951
|
-
// Overlay the authoritative tag (audit column) onto the snapshot's
|
|
952
|
-
// metadata.version.tag — the snapshot's embedded tag is only correct as
|
|
953
|
-
// of archival time.
|
|
954
|
-
wf.metadata ??= create(ApiResourceMetadataSchema);
|
|
955
|
-
wf.metadata.version ??= create(ApiResourceMetadataVersionSchema);
|
|
956
|
-
wf.metadata.version.tag = rec.tag;
|
|
957
|
-
return wf;
|
|
855
|
+
await newPipeline<typeof WorkflowQueryController.method.getByReference.input>(
|
|
856
|
+
"workflow-get-by-reference",
|
|
857
|
+
deps.logger,
|
|
858
|
+
)
|
|
859
|
+
.addStep(
|
|
860
|
+
newAuthorizeStep(
|
|
861
|
+
WorkflowQueryController.method.getByReference,
|
|
862
|
+
deps.authorizer,
|
|
863
|
+
),
|
|
864
|
+
)
|
|
865
|
+
.addStep(newValidateProtoStep())
|
|
866
|
+
.addStep(newLoadWorkflowByReferenceStep(deps.store))
|
|
867
|
+
.addStep(
|
|
868
|
+
newAuthorizeResolvedTargetStep(
|
|
869
|
+
deps.authorizer,
|
|
870
|
+
loadedTargetAsMethod(WorkflowQueryController.method.get),
|
|
871
|
+
),
|
|
872
|
+
)
|
|
873
|
+
.build()
|
|
874
|
+
.execute(reqCtx);
|
|
875
|
+
return reqCtx.get(TARGET_RESOURCE_KEY) as Workflow;
|
|
958
876
|
}
|
|
959
877
|
|
|
960
878
|
// ---------------------------------------------------------------------------
|
|
@@ -996,28 +914,23 @@ async function listVersions(
|
|
|
996
914
|
)
|
|
997
915
|
.addStep(newValidateProtoStep())
|
|
998
916
|
.addStep(newResolveWorkflowBySlugStep(deps.store))
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
deps.authorizer,
|
|
1011
|
-
stepCtx.callerIdentity,
|
|
1012
|
-
{
|
|
1013
|
-
permission: IamPermission.can_view,
|
|
1014
|
-
resourceKind: ApiResourceKind.workflow,
|
|
1015
|
-
resourceId: stepCtx.get(LIST_VERSIONS_WORKFLOW_ID_KEY) as string,
|
|
1016
|
-
},
|
|
917
|
+
// The Java WorkflowListVersionsHandler's mid-chain can_view on the
|
|
918
|
+
// RESOLVED workflow id (the skip annotation exists because the target
|
|
919
|
+
// resolves from org+slug, not a request field); the copy is the Java
|
|
920
|
+
// handler's byte-pinned error_msg, and the resolve step above already
|
|
921
|
+
// answered NOT_FOUND for an unknown slug, the load-first order both
|
|
922
|
+
// editions share.
|
|
923
|
+
.addStep(
|
|
924
|
+
newAuthorizeResolvedTargetStep(
|
|
925
|
+
deps.authorizer,
|
|
926
|
+
versionHistoryTarget(
|
|
927
|
+
ApiResourceKind.workflow,
|
|
1017
928
|
"unauthorized to view workflow version history",
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
929
|
+
LIST_VERSIONS_WORKFLOW_ID_KEY,
|
|
930
|
+
),
|
|
931
|
+
"AuthorizeResolvedWorkflow",
|
|
932
|
+
),
|
|
933
|
+
)
|
|
1021
934
|
.addStep(newLoadAndMapWorkflowVersionsStep(deps.store))
|
|
1022
935
|
.build()
|
|
1023
936
|
.execute(reqCtx);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow version resolution — the getByReference ladder as a pipeline
|
|
3
|
+
* step, so the lane can carry the resolved-target authorization the
|
|
4
|
+
* position-1 annotation cannot express (the target is a slug, not a field).
|
|
5
|
+
*
|
|
6
|
+
* The ladder is the Go query.go read, moved here from the direct handler
|
|
7
|
+
* without a behaviour change: slug required; org required (a workflow's slug
|
|
8
|
+
* is unique only within an org); kind mismatch refused with Go's rendering
|
|
9
|
+
* (the NAME for defined values, the bare NUMBER for unknown ones, because
|
|
10
|
+
* ref.kind carries no defined_only rule and enumToJson would throw on the
|
|
11
|
+
* unknown arm); the slug scan's store failure wrapped so a raw storage error
|
|
12
|
+
* never crosses the wire as Unknown; empty or "latest" is the current head;
|
|
13
|
+
* a version matching the head's hash or tag is the head; otherwise the
|
|
14
|
+
* audit store by hash or tag, with the snapshot's tag overlaid from the
|
|
15
|
+
* audit column (the source of truth) so callers never see a stale embedded
|
|
16
|
+
* tag after a tag move. The resolved row lands under TARGET_RESOURCE_KEY,
|
|
17
|
+
* the loader contract every getByReference chain shares.
|
|
18
|
+
*
|
|
19
|
+
* Deliberately NOT the shared ladder in pipeline/steps/version-history.ts:
|
|
20
|
+
* that one decodes through the typed audit reads and carries no tag
|
|
21
|
+
* overlay, so folding the two would change what one of them returns for a
|
|
22
|
+
* moved tag. Consolidating them is a separate change with its own proof.
|
|
23
|
+
*
|
|
24
|
+
* Proven by __tests__/workflow.test.ts's getByReference block and the
|
|
25
|
+
* conformance suite's workflow reference arms.
|
|
26
|
+
*/
|
|
27
|
+
import { create, fromBinary } from "@bufbuild/protobuf";
|
|
28
|
+
|
|
29
|
+
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
30
|
+
import type { Workflow } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
31
|
+
import {
|
|
32
|
+
ApiResourceMetadataSchema,
|
|
33
|
+
ApiResourceMetadataVersionSchema,
|
|
34
|
+
} from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
35
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
36
|
+
|
|
37
|
+
import {
|
|
38
|
+
internalError,
|
|
39
|
+
invalidArgumentError,
|
|
40
|
+
notFoundError,
|
|
41
|
+
} from "../../pipeline/errors.js";
|
|
42
|
+
import type { PipelineStep } from "../../pipeline/pipeline.js";
|
|
43
|
+
import type { RequestContext } from "../../pipeline/request-context.js";
|
|
44
|
+
import type { GetByReferenceDesc } from "../../pipeline/steps/authorize-resolved-target.js";
|
|
45
|
+
import {
|
|
46
|
+
findResourceBySlug,
|
|
47
|
+
requireOrgForReference,
|
|
48
|
+
} from "../../pipeline/steps/helpers.js";
|
|
49
|
+
import { TARGET_RESOURCE_KEY } from "../../pipeline/steps/load-target.js";
|
|
50
|
+
import { AuditNotFoundError } from "../../store/interface.js";
|
|
51
|
+
import type { AuditRecord, Store } from "../../store/interface.js";
|
|
52
|
+
|
|
53
|
+
/** A 64-hex value is an exact content hash; anything else is a tag. */
|
|
54
|
+
const WORKFLOW_HASH_PATTERN = /^[a-f0-9]{64}$/;
|
|
55
|
+
|
|
56
|
+
export function newLoadWorkflowByReferenceStep(
|
|
57
|
+
store: Store,
|
|
58
|
+
): PipelineStep<GetByReferenceDesc> {
|
|
59
|
+
return {
|
|
60
|
+
name: "LoadWorkflowByReference",
|
|
61
|
+
async execute(ctx: RequestContext<GetByReferenceDesc>): Promise<void> {
|
|
62
|
+
const ref = ctx.input;
|
|
63
|
+
if (ref.slug === "") {
|
|
64
|
+
throw invalidArgumentError("slug is required in reference");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
requireOrgForReference(ApiResourceKind.workflow, ref.org);
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
ref.kind !== ApiResourceKind.api_resource_kind_unknown &&
|
|
71
|
+
ref.kind !== ApiResourceKind.workflow
|
|
72
|
+
) {
|
|
73
|
+
const got = ApiResourceKind[ref.kind] ?? String(ref.kind);
|
|
74
|
+
throw invalidArgumentError(
|
|
75
|
+
`kind mismatch: expected ${ApiResourceKind[ApiResourceKind.workflow]}, got ${got}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let mainWorkflow: Workflow | undefined;
|
|
80
|
+
try {
|
|
81
|
+
mainWorkflow = await findResourceBySlug(
|
|
82
|
+
store,
|
|
83
|
+
ApiResourceKind.workflow,
|
|
84
|
+
WorkflowSchema,
|
|
85
|
+
ref.slug,
|
|
86
|
+
ref.org,
|
|
87
|
+
);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
throw internalError(error, "failed to list workflows");
|
|
90
|
+
}
|
|
91
|
+
if (mainWorkflow === undefined) {
|
|
92
|
+
throw notFoundError("workflow", ref.slug);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const version = ref.version.trim();
|
|
96
|
+
if (
|
|
97
|
+
version === "" ||
|
|
98
|
+
version === "latest" ||
|
|
99
|
+
workflowMatchesVersion(mainWorkflow, version)
|
|
100
|
+
) {
|
|
101
|
+
ctx.set(TARGET_RESOURCE_KEY, mainWorkflow);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const archived = await findAuditWorkflowByVersion(
|
|
106
|
+
store,
|
|
107
|
+
mainWorkflow.metadata!.id,
|
|
108
|
+
version,
|
|
109
|
+
);
|
|
110
|
+
if (archived === undefined) {
|
|
111
|
+
throw notFoundError("workflow version", `${ref.slug}:${version}`);
|
|
112
|
+
}
|
|
113
|
+
ctx.set(TARGET_RESOURCE_KEY, archived);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function workflowMatchesVersion(wf: Workflow, version: string): boolean {
|
|
119
|
+
if (wf.status === undefined) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
if (WORKFLOW_HASH_PATTERN.test(version)) {
|
|
123
|
+
return wf.status.versionHash === version;
|
|
124
|
+
}
|
|
125
|
+
return wf.metadata?.version?.tag === version;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function findAuditWorkflowByVersion(
|
|
129
|
+
store: Store,
|
|
130
|
+
workflowId: string,
|
|
131
|
+
version: string,
|
|
132
|
+
): Promise<Workflow | undefined> {
|
|
133
|
+
let rec: AuditRecord;
|
|
134
|
+
try {
|
|
135
|
+
rec = WORKFLOW_HASH_PATTERN.test(version)
|
|
136
|
+
? await store.getAuditRecordByHash(
|
|
137
|
+
ApiResourceKind.workflow,
|
|
138
|
+
workflowId,
|
|
139
|
+
version,
|
|
140
|
+
)
|
|
141
|
+
: await store.getAuditRecordByTag(
|
|
142
|
+
ApiResourceKind.workflow,
|
|
143
|
+
workflowId,
|
|
144
|
+
version,
|
|
145
|
+
);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (error instanceof AuditNotFoundError) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
throw internalError(error, "failed to query workflow audit by version");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let wf: Workflow;
|
|
154
|
+
try {
|
|
155
|
+
wf = fromBinary(WorkflowSchema, rec.data);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw internalError(error, "failed to decode archived workflow version");
|
|
158
|
+
}
|
|
159
|
+
// Overlay the authoritative tag (audit column) onto the snapshot's
|
|
160
|
+
// metadata.version.tag — the snapshot's embedded tag is only correct as
|
|
161
|
+
// of archival time.
|
|
162
|
+
wf.metadata ??= create(ApiResourceMetadataSchema);
|
|
163
|
+
wf.metadata.version ??= create(ApiResourceMetadataVersionSchema);
|
|
164
|
+
wf.metadata.version.tag = rec.tag;
|
|
165
|
+
return wf;
|
|
166
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the create lane's authorization question (steps.ts,
|
|
3
|
+
* resolveWorkflowInstanceCreateTargets): a personal instance asks
|
|
4
|
+
* can_execute on the parent workflow with the Java handler's copy; a
|
|
5
|
+
* default instance the server composed in-process for the parent's
|
|
6
|
+
* organization asks nothing; the same label from the wire or for another
|
|
7
|
+
* organization takes the bar; a missing parent throws.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { create } from "@bufbuild/protobuf";
|
|
11
|
+
|
|
12
|
+
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
13
|
+
import { WorkflowInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/api_pb";
|
|
14
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
15
|
+
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
16
|
+
|
|
17
|
+
import type { CallerIdentity } from "../../../extensions/identity.js";
|
|
18
|
+
import {
|
|
19
|
+
DEFAULT_INSTANCE_LABEL,
|
|
20
|
+
RESERVED_LABEL_TRUE,
|
|
21
|
+
} from "../../../pipeline/apiresource-labels.js";
|
|
22
|
+
import { testCallerIdentity } from "../../../pipeline/__tests__/support.js";
|
|
23
|
+
import { RequestContext } from "../../../pipeline/request-context.js";
|
|
24
|
+
import {
|
|
25
|
+
PARENT_WORKFLOW_KEY,
|
|
26
|
+
WORKFLOW_INSTANCE_PARENT_DENIED_MESSAGE,
|
|
27
|
+
resolveWorkflowInstanceCreateTargets,
|
|
28
|
+
} from "../steps.js";
|
|
29
|
+
|
|
30
|
+
const parent = create(WorkflowSchema, {
|
|
31
|
+
metadata: { id: "wf_01parent", name: "nightly", org: "acme" },
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
function ctxFor(
|
|
35
|
+
org: string,
|
|
36
|
+
caller: CallerIdentity,
|
|
37
|
+
labels: Record<string, string> = {},
|
|
38
|
+
stashParent = true,
|
|
39
|
+
) {
|
|
40
|
+
const ctx = new RequestContext(
|
|
41
|
+
WorkflowInstanceSchema,
|
|
42
|
+
create(WorkflowInstanceSchema, {
|
|
43
|
+
metadata: { name: "mine", org, labels },
|
|
44
|
+
spec: { workflowId: parent.metadata!.id },
|
|
45
|
+
}),
|
|
46
|
+
caller,
|
|
47
|
+
ApiResourceKind.workflow_instance,
|
|
48
|
+
);
|
|
49
|
+
if (stashParent) {
|
|
50
|
+
ctx.set(PARENT_WORKFLOW_KEY, parent);
|
|
51
|
+
}
|
|
52
|
+
return ctx;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const DEFAULT_LABELS = { [DEFAULT_INSTANCE_LABEL]: RESERVED_LABEL_TRUE };
|
|
56
|
+
|
|
57
|
+
describe("resolveWorkflowInstanceCreateTargets", () => {
|
|
58
|
+
it("a personal instance asks can_execute on the parent workflow", () => {
|
|
59
|
+
expect(
|
|
60
|
+
resolveWorkflowInstanceCreateTargets(
|
|
61
|
+
ctxFor("acme", testCallerIdentity()),
|
|
62
|
+
),
|
|
63
|
+
).toEqual([
|
|
64
|
+
{
|
|
65
|
+
permission: IamPermission.can_execute,
|
|
66
|
+
resourceKind: ApiResourceKind.workflow,
|
|
67
|
+
resourceId: "wf_01parent",
|
|
68
|
+
deniedMessage: WORKFLOW_INSTANCE_PARENT_DENIED_MESSAGE,
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("a default instance the server composed in-process for the parent's organization asks nothing", () => {
|
|
74
|
+
expect(
|
|
75
|
+
resolveWorkflowInstanceCreateTargets(
|
|
76
|
+
ctxFor(
|
|
77
|
+
"acme",
|
|
78
|
+
testCallerIdentity({ callerClass: "user", origin: "in-process" }),
|
|
79
|
+
DEFAULT_LABELS,
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
).toEqual([]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("the label from the wire, or for another organization, takes the bar", () => {
|
|
86
|
+
expect(
|
|
87
|
+
resolveWorkflowInstanceCreateTargets(
|
|
88
|
+
ctxFor("acme", testCallerIdentity(), DEFAULT_LABELS),
|
|
89
|
+
),
|
|
90
|
+
).toHaveLength(1);
|
|
91
|
+
expect(
|
|
92
|
+
resolveWorkflowInstanceCreateTargets(
|
|
93
|
+
ctxFor(
|
|
94
|
+
"other-org",
|
|
95
|
+
testCallerIdentity({ callerClass: "user", origin: "in-process" }),
|
|
96
|
+
DEFAULT_LABELS,
|
|
97
|
+
),
|
|
98
|
+
),
|
|
99
|
+
).toHaveLength(1);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("a missing parent is a broken chain invariant and throws", () => {
|
|
103
|
+
expect(() =>
|
|
104
|
+
resolveWorkflowInstanceCreateTargets(
|
|
105
|
+
ctxFor("acme", testCallerIdentity(), {}, false),
|
|
106
|
+
),
|
|
107
|
+
).toThrow("parent workflow not found in context");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -53,6 +53,10 @@ import type { PipelineStep } from "../../pipeline/pipeline.js";
|
|
|
53
53
|
import { callerIdentityOf } from "../../pipeline/interceptors/auth.js";
|
|
54
54
|
import { RequestContext } from "../../pipeline/request-context.js";
|
|
55
55
|
import { newAuthorizeStep } from "../../pipeline/steps/authorize.js";
|
|
56
|
+
import {
|
|
57
|
+
loadedTargetAsMethod,
|
|
58
|
+
newAuthorizeResolvedTargetStep,
|
|
59
|
+
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
56
60
|
import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
|
|
57
61
|
import {
|
|
58
62
|
newAuthorizeVisibilityTransitionStep,
|
|
@@ -108,6 +112,7 @@ import {
|
|
|
108
112
|
newRejectDefaultWorkflowInstanceVisibilityUpdateStep,
|
|
109
113
|
newValidateInstanceUpdateStep,
|
|
110
114
|
newValidateSameOrgBusinessRuleStep,
|
|
115
|
+
resolveWorkflowInstanceCreateTargets,
|
|
111
116
|
} from "./steps.js";
|
|
112
117
|
import type { ParentWorkflowLoaderProvider } from "./steps.js";
|
|
113
118
|
|
|
@@ -182,6 +187,14 @@ async function createInstance(
|
|
|
182
187
|
.addStep(newValidateVisibilityStep())
|
|
183
188
|
.addStep(newResolveSlugStep())
|
|
184
189
|
.addStep(newLoadParentWorkflowStep(deps.parentWorkflowLoader, deps.logger))
|
|
190
|
+
// Before the same-org rule, whose refusal names the parent's organization
|
|
191
|
+
// (steps.ts, resolveWorkflowInstanceCreateTargets).
|
|
192
|
+
.addStep(
|
|
193
|
+
newAuthorizeResolvedTargetStep(
|
|
194
|
+
deps.authorizer,
|
|
195
|
+
resolveWorkflowInstanceCreateTargets,
|
|
196
|
+
),
|
|
197
|
+
)
|
|
185
198
|
.addStep(newValidateSameOrgBusinessRuleStep(deps.logger))
|
|
186
199
|
.addStep(newCheckDuplicateStep(deps.store))
|
|
187
200
|
.addStep(newBuildNewStateStep())
|
|
@@ -707,6 +720,12 @@ async function getByReference(
|
|
|
707
720
|
)
|
|
708
721
|
.addStep(newValidateProtoStep())
|
|
709
722
|
.addStep(newLoadByReferenceStep(deps.store, WorkflowInstanceSchema))
|
|
723
|
+
.addStep(
|
|
724
|
+
newAuthorizeResolvedTargetStep(
|
|
725
|
+
deps.authorizer,
|
|
726
|
+
loadedTargetAsMethod(WorkflowInstanceQueryController.method.get),
|
|
727
|
+
),
|
|
728
|
+
)
|
|
710
729
|
.build()
|
|
711
730
|
.execute(reqCtx);
|
|
712
731
|
return reqCtx.get(TARGET_RESOURCE_KEY) as WorkflowInstance;
|