1import * as Lambda from "@/AWS/Lambda";
2import * as Organizations from "@/AWS/Organizations";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Stream from "effect/Stream";
6import { HttpServerRequest } from "effect/http/HttpServerRequest";
7import * as HttpServerResponse from "effect/http/HttpServerResponse";
8import path from "pathe";
9
10const main = path.resolve(import.meta.dirname, "handler.ts");
11
12// A well-formed-but-nonexistent handshake id — drives the typed error paths
13// for the handshake bindings (proving the IAM grant + typed union; an IAM gap
14// would surface AccessDeniedException instead).
15const NONEXISTENT_HANDSHAKE_ID = "h-abcd1234efgh5678";
16
17// A well-formed-but-nonexistent create-account request id.
18const NONEXISTENT_CAR_ID = "car-abcd1234abcd1234abcd1234abcd1234";
19
20export class OrganizationsTestFunction extends Lambda.Function<Lambda.Function>()(
21 "OrganizationsTestFunction",
22) {}
23
24export default OrganizationsTestFunction.make(
25 {
26 main,
27 functionUrl: true,
28 },
29 Effect.gen(function* () {
30 // --- account-level bindings (Organizations is a management-account
31 // singleton; these are the organization-tree, policy, delegation,
32 // vending, and handshake APIs an org-automation function uses) ---
33 const describeOrganization = yield* Organizations.DescribeOrganization();
34 const listRoots = yield* Organizations.ListRoots();
35 const listAccounts = yield* Organizations.ListAccounts();
36 const listAccountsForParent = yield* Organizations.ListAccountsForParent();
37 const listOrganizationalUnitsForParent =
38 yield* Organizations.ListOrganizationalUnitsForParent();
39 const listChildren = yield* Organizations.ListChildren();
40 const listParents = yield* Organizations.ListParents();
41 const listPolicies = yield* Organizations.ListPolicies();
42 const listPoliciesForTarget = yield* Organizations.ListPoliciesForTarget();
43 const listTargetsForPolicy = yield* Organizations.ListTargetsForPolicy();
44 const describeEffectivePolicy =
45 yield* Organizations.DescribeEffectivePolicy();
46 const listAccountsWithInvalidEffectivePolicy =
47 yield* Organizations.ListAccountsWithInvalidEffectivePolicy();
48 const listEffectivePolicyValidationErrors =
49 yield* Organizations.ListEffectivePolicyValidationErrors();
50 const listDelegatedAdministrators =
51 yield* Organizations.ListDelegatedAdministrators();
52 const listDelegatedServicesForAccount =
53 yield* Organizations.ListDelegatedServicesForAccount();
54 const listAWSServiceAccessForOrganization =
55 yield* Organizations.ListAWSServiceAccessForOrganization();
56 const listTagsForResource = yield* Organizations.ListTagsForResource();
57 const describeCreateAccountStatus =
58 yield* Organizations.DescribeCreateAccountStatus();
59 const listCreateAccountStatus =
60 yield* Organizations.ListCreateAccountStatus();
61 const inviteAccountToOrganization =
62 yield* Organizations.InviteAccountToOrganization();
63 const acceptHandshake = yield* Organizations.AcceptHandshake();
64 const declineHandshake = yield* Organizations.DeclineHandshake();
65 const cancelHandshake = yield* Organizations.CancelHandshake();
66 const describeHandshake = yield* Organizations.DescribeHandshake();
67 const listHandshakesForAccount =
68 yield* Organizations.ListHandshakesForAccount();
69 const listHandshakesForOrganization =
70 yield* Organizations.ListHandshakesForOrganization();
71
72 // --- event source ---
73 // Deploy-time: creates the EventBridge rule (default bus, source
74 // aws.organizations) targeting this Function. Runtime firing needs a
75 // real organization change in us-east-1 of the management account, so
76 // the test only verifies the subscription deploys.
77 yield* Organizations.consumeOrganizationsEvents(
78 { events: ["CreateAccountResult", "MoveAccount"] },
79 (events) =>
80 Stream.runForEach(events, (event) =>
81 Effect.log(`organizations event: ${event.detail.eventName}`),
82 ),
83 );
84
85 const bound = {
86 describeOrganization,
87 listRoots,
88 listAccounts,
89 listAccountsForParent,
90 listOrganizationalUnitsForParent,
91 listChildren,
92 listParents,
93 listPolicies,
94 listPoliciesForTarget,
95 listTargetsForPolicy,
96 describeEffectivePolicy,
97 listAccountsWithInvalidEffectivePolicy,
98 listEffectivePolicyValidationErrors,
99 listDelegatedAdministrators,
100 listDelegatedServicesForAccount,
101 listAWSServiceAccessForOrganization,
102 listTagsForResource,
103 describeCreateAccountStatus,
104 listCreateAccountStatus,
105 inviteAccountToOrganization,
106 acceptHandshake,
107 declineHandshake,
108 cancelHandshake,
109 describeHandshake,
110 listHandshakesForAccount,
111 listHandshakesForOrganization,
112 };
113
114 // The testing account is the management account of a standing
115 // organization, so the read paths return live data; every route still
116 // tolerates the typed not-in-organization / access-denied tags so the
117 // fixture stays correct on any account.
118 const rootId = describeOrganization().pipe(
119 Effect.flatMap(() => listRoots()),
120 Effect.map((r) => r.Roots?.[0]?.Id),
121 );
122
123 const managementAccountId = describeOrganization().pipe(
124 Effect.map((r) => r.Organization?.MasterAccountId),
125 );
126
127 return {
128 fetch: Effect.gen(function* () {
129 const request = yield* HttpServerRequest;
130 const url = new URL(request.originalUrl);
131 const pathname = url.pathname;
132
133 if (request.method === "GET" && pathname === "/bindings") {
134 return yield* HttpServerResponse.json({
135 bound: Object.keys(bound),
136 });
137 }
138
139 if (request.method === "GET" && pathname === "/organization") {
140 const result = yield* describeOrganization().pipe(
141 Effect.map((r) => ({
142 ok: true as const,
143 id: r.Organization?.Id ?? null,
144 managementAccountId: r.Organization?.MasterAccountId ?? null,
145 })),
146 Effect.catchTag(
147 ["AccessDeniedException", "AWSOrganizationsNotInUseException"],
148 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
149 ),
150 );
151 return yield* HttpServerResponse.json(result);
152 }
153
154 if (request.method === "GET" && pathname === "/roots") {
155 const result = yield* listRoots().pipe(
156 Effect.map((r) => ({
157 ok: true as const,
158 count: r.Roots?.length ?? 0,
159 rootId: r.Roots?.[0]?.Id ?? null,
160 })),
161 Effect.catchTag(
162 ["AccessDeniedException", "AWSOrganizationsNotInUseException"],
163 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
164 ),
165 );
166 return yield* HttpServerResponse.json(result);
167 }
168
169 if (request.method === "GET" && pathname === "/accounts") {
170 const result = yield* listAccounts().pipe(
171 Effect.map((r) => ({
172 ok: true as const,
173 count: r.Accounts?.length ?? 0,
174 })),
175 Effect.catchTag(
176 ["AccessDeniedException", "AWSOrganizationsNotInUseException"],
177 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
178 ),
179 );
180 return yield* HttpServerResponse.json(result);
181 }
182
183 if (request.method === "GET" && pathname === "/accounts-for-parent") {
184 const result = yield* Effect.gen(function* () {
185 const parent = yield* rootId;
186 if (parent === undefined) {
187 return { ok: false as const, tag: "NoRoot" };
188 }
189 const r = yield* listAccountsForParent({ ParentId: parent });
190 return { ok: true as const, count: r.Accounts?.length ?? 0 };
191 }).pipe(
192 Effect.catchTag(
193 [
194 "AccessDeniedException",
195 "AWSOrganizationsNotInUseException",
196 "ParentNotFoundException",
197 ],
198 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
199 ),
200 );
201 return yield* HttpServerResponse.json(result);
202 }
203
204 if (request.method === "GET" && pathname === "/ous-for-parent") {
205 const result = yield* Effect.gen(function* () {
206 const parent = yield* rootId;
207 if (parent === undefined) {
208 return { ok: false as const, tag: "NoRoot" };
209 }
210 const r = yield* listOrganizationalUnitsForParent({
211 ParentId: parent,
212 });
213 return {
214 ok: true as const,
215 count: r.OrganizationalUnits?.length ?? 0,
216 };
217 }).pipe(
218 Effect.catchTag(
219 [
220 "AccessDeniedException",
221 "AWSOrganizationsNotInUseException",
222 "ParentNotFoundException",
223 ],
224 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
225 ),
226 );
227 return yield* HttpServerResponse.json(result);
228 }
229
230 if (request.method === "GET" && pathname === "/children") {
231 const result = yield* Effect.gen(function* () {
232 const parent = yield* rootId;
233 if (parent === undefined) {
234 return { ok: false as const, tag: "NoRoot" };
235 }
236 const r = yield* listChildren({
237 ParentId: parent,
238 ChildType: "ACCOUNT",
239 });
240 return { ok: true as const, count: r.Children?.length ?? 0 };
241 }).pipe(
242 Effect.catchTag(
243 [
244 "AccessDeniedException",
245 "AWSOrganizationsNotInUseException",
246 "ParentNotFoundException",
247 ],
248 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
249 ),
250 );
251 return yield* HttpServerResponse.json(result);
252 }
253
254 if (request.method === "GET" && pathname === "/parents") {
255 const result = yield* Effect.gen(function* () {
256 const accountId = yield* managementAccountId;
257 if (accountId === undefined) {
258 return { ok: false as const, tag: "NoOrganization" };
259 }
260 const r = yield* listParents({ ChildId: accountId });
261 return { ok: true as const, count: r.Parents?.length ?? 0 };
262 }).pipe(
263 Effect.catchTag(
264 [
265 "AccessDeniedException",
266 "AWSOrganizationsNotInUseException",
267 "ChildNotFoundException",
268 ],
269 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
270 ),
271 );
272 return yield* HttpServerResponse.json(result);
273 }
274
275 if (request.method === "GET" && pathname === "/policies") {
276 const result = yield* listPolicies({
277 Filter: "SERVICE_CONTROL_POLICY",
278 }).pipe(
279 Effect.map((r) => ({
280 ok: true as const,
281 count: r.Policies?.length ?? 0,
282 })),
283 Effect.catchTag(
284 ["AccessDeniedException", "AWSOrganizationsNotInUseException"],
285 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
286 ),
287 );
288 return yield* HttpServerResponse.json(result);
289 }
290
291 if (request.method === "GET" && pathname === "/policies-for-target") {
292 const result = yield* Effect.gen(function* () {
293 const target = yield* rootId;
294 if (target === undefined) {
295 return { ok: false as const, tag: "NoRoot" };
296 }
297 const r = yield* listPoliciesForTarget({
298 TargetId: target,
299 Filter: "SERVICE_CONTROL_POLICY",
300 });
301 return { ok: true as const, count: r.Policies?.length ?? 0 };
302 }).pipe(
303 Effect.catchTag(
304 [
305 "AccessDeniedException",
306 "AWSOrganizationsNotInUseException",
307 "TargetNotFoundException",
308 ],
309 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
310 ),
311 );
312 return yield* HttpServerResponse.json(result);
313 }
314
315 if (request.method === "GET" && pathname === "/targets-for-policy") {
316 // Discover a policy id from the SCP list (p-FullAWSAccess exists in
317 // every organization with SCPs available), then read its targets —
318 // proves ListTargetsForPolicy's grant end-to-end.
319 const result = yield* Effect.gen(function* () {
320 const r = yield* listPolicies({
321 Filter: "SERVICE_CONTROL_POLICY",
322 });
323 const policyId = r.Policies?.[0]?.Id;
324 if (policyId === undefined) {
325 return { ok: false as const, tag: "NoPolicy" };
326 }
327 const t = yield* listTargetsForPolicy({ PolicyId: policyId });
328 return { ok: true as const, count: t.Targets?.length ?? 0 };
329 }).pipe(
330 Effect.catchTag(
331 [
332 "AccessDeniedException",
333 "AWSOrganizationsNotInUseException",
334 "PolicyNotFoundException",
335 ],
336 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
337 ),
338 );
339 return yield* HttpServerResponse.json(result);
340 }
341
342 if (request.method === "GET" && pathname === "/effective-policy") {
343 // The standing organization has no tag policies enabled, so the
344 // grant is proved by the typed EffectivePolicyNotFoundException /
345 // ConstraintViolationException rather than live content.
346 const result = yield* describeEffectivePolicy({
347 PolicyType: "TAG_POLICY",
348 }).pipe(
349 Effect.map((r) => ({
350 ok: true as const,
351 policyType: r.EffectivePolicy?.PolicyType ?? null,
352 })),
353 Effect.catchTag(
354 [
355 "AccessDeniedException",
356 "AWSOrganizationsNotInUseException",
357 "ConstraintViolationException",
358 "EffectivePolicyNotFoundException",
359 "TargetNotFoundException",
360 ],
361 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
362 ),
363 );
364 return yield* HttpServerResponse.json(result);
365 }
366
367 if (
368 request.method === "GET" &&
369 pathname === "/invalid-effective-policy-accounts"
370 ) {
371 const result = yield* listAccountsWithInvalidEffectivePolicy({
372 PolicyType: "TAG_POLICY",
373 }).pipe(
374 Effect.map((r) => ({
375 ok: true as const,
376 count: r.Accounts?.length ?? 0,
377 })),
378 Effect.catchTag(
379 [
380 "AccessDeniedException",
381 "AWSOrganizationsNotInUseException",
382 "ConstraintViolationException",
383 "EffectivePolicyNotFoundException",
384 "InvalidInputException",
385 "UnsupportedAPIEndpointException",
386 ],
387 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
388 ),
389 );
390 return yield* HttpServerResponse.json(result);
391 }
392
393 if (
394 request.method === "GET" &&
395 pathname === "/effective-policy-validation-errors"
396 ) {
397 const result = yield* Effect.gen(function* () {
398 const accountId = yield* managementAccountId;
399 if (accountId === undefined) {
400 return { ok: false as const, tag: "NoOrganization" };
401 }
402 const r = yield* listEffectivePolicyValidationErrors({
403 AccountId: accountId,
404 PolicyType: "TAG_POLICY",
405 });
406 return {
407 ok: true as const,
408 count: r.EffectivePolicyValidationErrors?.length ?? 0,
409 };
410 }).pipe(
411 Effect.catchTag(
412 [
413 "AccessDeniedException",
414 "AccountNotFoundException",
415 "AWSOrganizationsNotInUseException",
416 "ConstraintViolationException",
417 "EffectivePolicyNotFoundException",
418 "InvalidInputException",
419 "UnsupportedAPIEndpointException",
420 ],
421 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
422 ),
423 );
424 return yield* HttpServerResponse.json(result);
425 }
426
427 if (
428 request.method === "GET" &&
429 pathname === "/delegated-administrators"
430 ) {
431 const result = yield* listDelegatedAdministrators().pipe(
432 Effect.map((r) => ({
433 ok: true as const,
434 count: r.DelegatedAdministrators?.length ?? 0,
435 })),
436 Effect.catchTag(
437 [
438 "AccessDeniedException",
439 "AWSOrganizationsNotInUseException",
440 "ConstraintViolationException",
441 ],
442 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
443 ),
444 );
445 return yield* HttpServerResponse.json(result);
446 }
447
448 if (request.method === "GET" && pathname === "/delegated-services") {
449 // The management account is never a delegated administrator, so
450 // the typed AccountNotRegisteredException proves the grant.
451 const result = yield* Effect.gen(function* () {
452 const accountId = yield* managementAccountId;
453 if (accountId === undefined) {
454 return { ok: false as const, tag: "NoOrganization" };
455 }
456 const r = yield* listDelegatedServicesForAccount({
457 AccountId: accountId,
458 });
459 return {
460 ok: true as const,
461 count: r.DelegatedServices?.length ?? 0,
462 };
463 }).pipe(
464 Effect.catchTag(
465 [
466 "AccessDeniedException",
467 "AccountNotFoundException",
468 "AccountNotRegisteredException",
469 "AWSOrganizationsNotInUseException",
470 "ConstraintViolationException",
471 ],
472 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
473 ),
474 );
475 return yield* HttpServerResponse.json(result);
476 }
477
478 if (request.method === "GET" && pathname === "/service-access") {
479 const result = yield* listAWSServiceAccessForOrganization().pipe(
480 Effect.map((r) => ({
481 ok: true as const,
482 count: r.EnabledServicePrincipals?.length ?? 0,
483 })),
484 Effect.catchTag(
485 [
486 "AccessDeniedException",
487 "AWSOrganizationsNotInUseException",
488 "ConstraintViolationException",
489 ],
490 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
491 ),
492 );
493 return yield* HttpServerResponse.json(result);
494 }
495
496 if (request.method === "GET" && pathname === "/tags") {
497 const result = yield* Effect.gen(function* () {
498 const accountId = yield* managementAccountId;
499 if (accountId === undefined) {
500 return { ok: false as const, tag: "NoOrganization" };
501 }
502 const r = yield* listTagsForResource({ ResourceId: accountId });
503 return { ok: true as const, count: r.Tags?.length ?? 0 };
504 }).pipe(
505 Effect.catchTag(
506 [
507 "AccessDeniedException",
508 "AWSOrganizationsNotInUseException",
509 "TargetNotFoundException",
510 ],
511 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
512 ),
513 );
514 return yield* HttpServerResponse.json(result);
515 }
516
517 if (
518 request.method === "GET" &&
519 pathname === "/create-account-statuses"
520 ) {
521 const result = yield* listCreateAccountStatus().pipe(
522 Effect.map((r) => ({
523 ok: true as const,
524 count: r.CreateAccountStatuses?.length ?? 0,
525 })),
526 Effect.catchTag(
527 [
528 "AccessDeniedException",
529 "AWSOrganizationsNotInUseException",
530 "UnsupportedAPIEndpointException",
531 ],
532 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
533 ),
534 );
535 return yield* HttpServerResponse.json(result);
536 }
537
538 if (
539 request.method === "GET" &&
540 pathname === "/create-account-status-not-found"
541 ) {
542 const tag = yield* describeCreateAccountStatus({
543 CreateAccountRequestId: NONEXISTENT_CAR_ID,
544 }).pipe(
545 Effect.map(() => "Found"),
546 Effect.catchTag(
547 [
548 "AccessDeniedException",
549 "AWSOrganizationsNotInUseException",
550 "CreateAccountStatusNotFoundException",
551 "InvalidInputException",
552 "UnsupportedAPIEndpointException",
553 ],
554 (e) => Effect.succeed(e._tag),
555 ),
556 );
557 return yield* HttpServerResponse.json({ tag });
558 }
559
560 if (request.method === "GET" && pathname === "/handshakes-account") {
561 const result = yield* listHandshakesForAccount().pipe(
562 Effect.map((r) => ({
563 ok: true as const,
564 count: r.Handshakes?.length ?? 0,
565 })),
566 Effect.catchTag(
567 ["AccessDeniedException", "ConcurrentModificationException"],
568 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
569 ),
570 );
571 return yield* HttpServerResponse.json(result);
572 }
573
574 if (request.method === "GET" && pathname === "/handshakes-org") {
575 const result = yield* listHandshakesForOrganization().pipe(
576 Effect.map((r) => ({
577 ok: true as const,
578 count: r.Handshakes?.length ?? 0,
579 })),
580 Effect.catchTag(
581 [
582 "AccessDeniedException",
583 "AWSOrganizationsNotInUseException",
584 "ConcurrentModificationException",
585 ],
586 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
587 ),
588 );
589 return yield* HttpServerResponse.json(result);
590 }
591
592 if (request.method === "GET" && pathname === "/handshake-not-found") {
593 const tag = yield* describeHandshake({
594 HandshakeId: NONEXISTENT_HANDSHAKE_ID,
595 }).pipe(
596 Effect.map(() => "Found"),
597 Effect.catchTag(
598 [
599 "AccessDeniedException",
600 "HandshakeNotFoundException",
601 "InvalidInputException",
602 ],
603 (e) => Effect.succeed(e._tag),
604 ),
605 );
606 return yield* HttpServerResponse.json({ tag });
607 }
608
609 if (
610 request.method === "GET" &&
611 pathname === "/accept-handshake-not-found"
612 ) {
613 const tag = yield* acceptHandshake({
614 HandshakeId: NONEXISTENT_HANDSHAKE_ID,
615 }).pipe(
616 Effect.map(() => "Found"),
617 Effect.catchTag(
618 [
619 "AccessDeniedException",
620 "AWSOrganizationsNotInUseException",
621 "HandshakeNotFoundException",
622 "InvalidInputException",
623 ],
624 (e) => Effect.succeed(e._tag),
625 ),
626 );
627 return yield* HttpServerResponse.json({ tag });
628 }
629
630 if (
631 request.method === "GET" &&
632 pathname === "/decline-handshake-not-found"
633 ) {
634 const tag = yield* declineHandshake({
635 HandshakeId: NONEXISTENT_HANDSHAKE_ID,
636 }).pipe(
637 Effect.map(() => "Found"),
638 Effect.catchTag(
639 [
640 "AccessDeniedException",
641 "HandshakeNotFoundException",
642 "InvalidInputException",
643 ],
644 (e) => Effect.succeed(e._tag),
645 ),
646 );
647 return yield* HttpServerResponse.json({ tag });
648 }
649
650 if (
651 request.method === "GET" &&
652 pathname === "/cancel-handshake-not-found"
653 ) {
654 const tag = yield* cancelHandshake({
655 HandshakeId: NONEXISTENT_HANDSHAKE_ID,
656 }).pipe(
657 Effect.map(() => "Found"),
658 Effect.catchTag(
659 [
660 "AccessDeniedException",
661 "HandshakeNotFoundException",
662 "InvalidInputException",
663 ],
664 (e) => Effect.succeed(e._tag),
665 ),
666 );
667 return yield* HttpServerResponse.json({ tag });
668 }
669
670 if (request.method === "GET" && pathname === "/invite-invalid") {
671 // A syntactically invalid target id — proves the grant via the
672 // typed InvalidInputException without ever creating a real
673 // handshake.
674 const tag = yield* inviteAccountToOrganization({
675 Target: { Id: "not-a-valid-account-id", Type: "ACCOUNT" },
676 }).pipe(
677 Effect.map(() => "Invited"),
678 Effect.catchTag(
679 [
680 "AccessDeniedException",
681 "AWSOrganizationsNotInUseException",
682 "ConstraintViolationException",
683 "HandshakeConstraintViolationException",
684 "InvalidInputException",
685 ],
686 (e) => Effect.succeed(e._tag),
687 ),
688 );
689 return yield* HttpServerResponse.json({ tag });
690 }
691
692 return yield* HttpServerResponse.json(
693 { error: "Not found", method: request.method, pathname },
694 { status: 404 },
695 );
696 }).pipe(Effect.orDie),
697 };
698 }).pipe(
699 Effect.provide(
700 Layer.mergeAll(
701 Lambda.EventSource,
702 Organizations.DescribeOrganizationHttp,
703 Organizations.ListRootsHttp,
704 Organizations.ListAccountsHttp,
705 Organizations.ListAccountsForParentHttp,
706 Organizations.ListOrganizationalUnitsForParentHttp,
707 Organizations.ListChildrenHttp,
708 Organizations.ListParentsHttp,
709 Organizations.ListPoliciesHttp,
710 Organizations.ListPoliciesForTargetHttp,
711 Organizations.ListTargetsForPolicyHttp,
712 Organizations.DescribeEffectivePolicyHttp,
713 Organizations.ListAccountsWithInvalidEffectivePolicyHttp,
714 Organizations.ListEffectivePolicyValidationErrorsHttp,
715 Organizations.ListDelegatedAdministratorsHttp,
716 Organizations.ListDelegatedServicesForAccountHttp,
717 Organizations.ListAWSServiceAccessForOrganizationHttp,
718 Organizations.ListTagsForResourceHttp,
719 Organizations.DescribeCreateAccountStatusHttp,
720 Organizations.ListCreateAccountStatusHttp,
721 Organizations.InviteAccountToOrganizationHttp,
722 Organizations.AcceptHandshakeHttp,
723 Organizations.DeclineHandshakeHttp,
724 Organizations.CancelHandshakeHttp,
725 Organizations.DescribeHandshakeHttp,
726 Organizations.ListHandshakesForAccountHttp,
727 Organizations.ListHandshakesForOrganizationHttp,
728 ),
729 ),
730 ),
731);