1import * as codedeploy from "@distilled.cloud/aws/codedeploy";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import * as Binding from "../../Binding.ts";
5import * as Output from "../../Output.ts";
6import { isBindingHost } from "../Lambda/Function.ts";
7import {
8 CreateDeployment,
9 type CreateDeploymentRequest,
10} from "./CreateDeployment.ts";
11import type { DeploymentGroup } from "./DeploymentGroup.ts";
12
13/**
14 * Bespoke (multi-statement IAM): besides `codedeploy:CreateDeployment` on
15 * the group, creating a deployment reads the deployment configuration and
16 * the application revision on the caller's behalf, so the grant also covers
17 * `GetDeploymentConfig` on the account's configs and
18 * `GetApplicationRevision`/`RegisterApplicationRevision` on the group's
19 * application.
20 */
21export const CreateDeploymentHttp = Layer.effect(
22 CreateDeployment,
23 Effect.gen(function* () {
24 const op = yield* codedeploy.createDeployment;
25
26 return Effect.fn(function* <G extends DeploymentGroup>(group: G) {
27 // Outputs yield a DEFERRED effect — resolve again per invocation below.
28 const ApplicationName = yield* group.applicationName;
29 const DeploymentGroupName = yield* group.deploymentGroupName;
30 if (!globalThis.__ALCHEMY_RUNTIME__) {
31 const host = yield* Binding.Host;
32 if (isBindingHost(host)) {
33 yield* host.bind`Allow(${host}, AWS.CodeDeploy.CreateDeployment(${group}))`(
34 {
35 policyStatements: [
36 {
37 Effect: "Allow",
38 Action: ["codedeploy:CreateDeployment"],
39 Resource: [Output.interpolate`${group.deploymentGroupArn}`],
40 },
41 {
42 Effect: "Allow",
43 Action: ["codedeploy:GetDeploymentConfig"],
44 Resource: [
45 Output.map(group.deploymentGroupArn, (arn) =>
46 arn.replace(
47 /:deploymentgroup:.*$/,
48 ":deploymentconfig:*",
49 ),
50 ),
51 ],
52 },
53 {
54 Effect: "Allow",
55 Action: [
56 "codedeploy:GetApplicationRevision",
57 "codedeploy:RegisterApplicationRevision",
58 ],
59 Resource: [
60 Output.map(group.deploymentGroupArn, (arn) =>
61 arn.replace(
62 /:deploymentgroup:([^/]+)\/.*$/,
63 ":application:$1",
64 ),
65 ),
66 ],
67 },
68 ],
69 },
70 );
71 }
72 }
73 return Effect.fn(`AWS.CodeDeploy.CreateDeployment(${group.LogicalId})`)(
74 function* (request?: CreateDeploymentRequest) {
75 return yield* op({
76 ...request,
77 applicationName: yield* ApplicationName,
78 deploymentGroupName: yield* DeploymentGroupName,
79 });
80 },
81 );
82 });
83 }),
84);