Skip to content

Commit 07ad866

Browse files
feat: Policy v1 endpoints (#479)
1 parent 0017cee commit 07ad866

File tree

4 files changed

+712
-1
lines changed

4 files changed

+712
-1
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import type { Swagger } from "atlassian-openapi";
2+
3+
export const openapi: Swagger.SwaggerV3 = {
4+
openapi: "3.0.0",
5+
info: {
6+
title: "Ctrlplane API",
7+
version: "1.0.0",
8+
},
9+
components: {
10+
schemas: {
11+
PolicyTarget: {
12+
type: "object",
13+
properties: {
14+
deploymentSelector: { type: "object", additionalProperties: true },
15+
environmentSelector: { type: "object", additionalProperties: true },
16+
releaseSelector: { type: "object", additionalProperties: true },
17+
},
18+
},
19+
DenyWindow: {
20+
type: "object",
21+
properties: {
22+
timeZone: { type: "string" },
23+
rrule: { type: "object", additionalProperties: true },
24+
dtend: { type: "string", format: "date-time" },
25+
},
26+
required: ["timeZone", "rrule"],
27+
},
28+
DeploymentVersionSelector: {
29+
type: "object",
30+
properties: {
31+
name: { type: "string" },
32+
deploymentVersionSelector: {
33+
type: "object",
34+
additionalProperties: true,
35+
},
36+
description: { type: "string" },
37+
},
38+
required: ["name", "deploymentVersionSelector"],
39+
},
40+
VersionAnyApproval: {
41+
type: "object",
42+
properties: { requiredApprovalsCount: { type: "number" } },
43+
required: ["requiredApprovalsCount"],
44+
},
45+
VersionUserApproval: {
46+
type: "object",
47+
properties: { userId: { type: "string" } },
48+
required: ["userId"],
49+
},
50+
VersionRoleApproval: {
51+
type: "object",
52+
properties: {
53+
roleId: { type: "string" },
54+
requiredApprovalsCount: { type: "number" },
55+
},
56+
required: ["roleId", "requiredApprovalsCount"],
57+
},
58+
Policy: {
59+
type: "object",
60+
properties: {
61+
id: { type: "string", format: "uuid" },
62+
name: { type: "string" },
63+
description: { type: "string" },
64+
priority: { type: "number" },
65+
createdAt: { type: "string", format: "date-time" },
66+
enabled: { type: "boolean" },
67+
workspaceId: { type: "string", format: "uuid" },
68+
targets: {
69+
type: "array",
70+
items: { $ref: "#/components/schemas/PolicyTarget" },
71+
},
72+
denyWindows: {
73+
type: "array",
74+
items: { $ref: "#/components/schemas/DenyWindow" },
75+
},
76+
deploymentVersionSelector: {
77+
$ref: "#/components/schemas/DeploymentVersionSelector",
78+
},
79+
versionAnyApprovals: {
80+
type: "array",
81+
items: { $ref: "#/components/schemas/VersionAnyApproval" },
82+
},
83+
versionUserApprovals: {
84+
type: "array",
85+
items: { $ref: "#/components/schemas/VersionUserApproval" },
86+
},
87+
versionRoleApprovals: {
88+
type: "array",
89+
items: { $ref: "#/components/schemas/VersionRoleApproval" },
90+
},
91+
},
92+
required: [
93+
"id",
94+
"name",
95+
"priority",
96+
"createdAt",
97+
"enabled",
98+
"workspaceId",
99+
"targets",
100+
"denyWindows",
101+
"versionUserApprovals",
102+
"versionRoleApprovals",
103+
],
104+
},
105+
},
106+
},
107+
paths: {
108+
"/v1/policies": {
109+
post: {
110+
summary: "Create a policy",
111+
operationId: "createPolicy",
112+
requestBody: {
113+
required: true,
114+
content: {
115+
"application/json": {
116+
schema: {
117+
type: "object",
118+
properties: {
119+
name: { type: "string" },
120+
description: { type: "string" },
121+
priority: { type: "number" },
122+
enabled: { type: "boolean" },
123+
workspaceId: { type: "string" },
124+
targets: {
125+
type: "array",
126+
items: { $ref: "#/components/schemas/PolicyTarget" },
127+
},
128+
denyWindows: {
129+
type: "array",
130+
items: {
131+
type: "object",
132+
properties: {
133+
timeZone: { type: "string" },
134+
rrule: { type: "object", additionalProperties: true },
135+
dtend: { type: "string", format: "date-time" },
136+
},
137+
required: ["timeZone"],
138+
},
139+
},
140+
deploymentVersionSelector: {
141+
$ref: "#/components/schemas/DeploymentVersionSelector",
142+
},
143+
versionAnyApprovals: {
144+
type: "array",
145+
items: {
146+
type: "object",
147+
properties: {
148+
requiredApprovalsCount: { type: "number" },
149+
},
150+
},
151+
},
152+
versionUserApprovals: {
153+
type: "array",
154+
items: {
155+
$ref: "#/components/schemas/VersionUserApproval",
156+
},
157+
},
158+
versionRoleApprovals: {
159+
type: "array",
160+
items: {
161+
type: "object",
162+
properties: {
163+
roleId: { type: "string" },
164+
requiredApprovalsCount: { type: "number" },
165+
},
166+
},
167+
required: ["roleId"],
168+
},
169+
},
170+
required: [
171+
"name",
172+
"workspaceId",
173+
"targets",
174+
"denyWindows",
175+
"versionUserApprovals",
176+
"versionRoleApprovals",
177+
],
178+
},
179+
},
180+
},
181+
},
182+
responses: {
183+
200: {
184+
description: "OK",
185+
content: {
186+
"application/json": {
187+
schema: { $ref: "#/components/schemas/Policy" },
188+
},
189+
},
190+
},
191+
500: {
192+
description: "Internal Server Error",
193+
content: {
194+
"application/json": {
195+
schema: {
196+
type: "object",
197+
properties: {
198+
error: { type: "string" },
199+
},
200+
},
201+
},
202+
},
203+
},
204+
},
205+
},
206+
},
207+
},
208+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { NextResponse } from "next/server";
2+
import { INTERNAL_SERVER_ERROR } from "http-status";
3+
import { z } from "zod";
4+
5+
import * as SCHEMA from "@ctrlplane/db/schema";
6+
import { logger } from "@ctrlplane/logger";
7+
import { Permission } from "@ctrlplane/validators/auth";
8+
9+
import { api } from "~/trpc/server";
10+
import { authn, authz } from "../auth";
11+
import { parseBody } from "../body-parser";
12+
import { request } from "../middleware";
13+
14+
const log = logger.child({ route: "/api/v1/policies" });
15+
16+
export const POST = request()
17+
.use(authn)
18+
.use(parseBody(SCHEMA.createPolicy))
19+
.use(
20+
authz(({ ctx, can }) =>
21+
can
22+
.perform(Permission.PolicyCreate)
23+
.on({ type: "workspace", id: ctx.body.workspaceId }),
24+
),
25+
)
26+
.handle<{ body: z.infer<typeof SCHEMA.createPolicy> }>(({ body }) =>
27+
api.policy
28+
.create(body)
29+
.then((policy) => NextResponse.json(policy))
30+
.catch((error) => {
31+
log.error("Failed to create policy", { error });
32+
return NextResponse.json(
33+
{ error: "Failed to create policy" },
34+
{ status: INTERNAL_SERVER_ERROR },
35+
);
36+
}),
37+
);

0 commit comments

Comments
 (0)