Implement workaround for swagger-autogen edgecase and expose folders, secret imports API

This commit is contained in:
Tuan Dang
2023-09-13 09:28:29 +01:00
parent d221bf8ae9
commit 4f69257595
28 changed files with 4294 additions and 2353 deletions

View File

@@ -55,7 +55,6 @@
"query-string": "^7.1.3", "query-string": "^7.1.3",
"rate-limit-mongo": "^2.3.2", "rate-limit-mongo": "^2.3.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"swagger-autogen": "^2.22.0",
"swagger-ui-express": "^4.6.2", "swagger-ui-express": "^4.6.2",
"tweetnacl": "^1.0.3", "tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1", "tweetnacl-util": "^0.15.1",
@@ -96,6 +95,7 @@
"npm": "^8.19.3", "npm": "^8.19.3",
"smee-client": "^1.2.3", "smee-client": "^1.2.3",
"supertest": "^6.3.3", "supertest": "^6.3.3",
"swagger-autogen": "^2.23.5",
"ts-jest": "^29.0.3", "ts-jest": "^29.0.3",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"
} }
@@ -10023,6 +10023,7 @@
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
}, },
@@ -15559,6 +15560,7 @@
"version": "2.23.5", "version": "2.23.5",
"resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.23.5.tgz", "resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.23.5.tgz",
"integrity": "sha512-4Tl2+XhZMyHoBYkABnScHtQE0lKPKUD3NBt09mClrI6UKOUYljKlYw1xiFVwsHCTGR2hAXmhT4PpgjruCtt1ZA==", "integrity": "sha512-4Tl2+XhZMyHoBYkABnScHtQE0lKPKUD3NBt09mClrI6UKOUYljKlYw1xiFVwsHCTGR2hAXmhT4PpgjruCtt1ZA==",
"dev": true,
"dependencies": { "dependencies": {
"acorn": "^7.4.1", "acorn": "^7.4.1",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
@@ -15570,6 +15572,7 @@
"version": "7.4.1", "version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -24521,7 +24524,8 @@
"json5": { "json5": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
}, },
"jsonwebtoken": { "jsonwebtoken": {
"version": "9.0.1", "version": "9.0.1",
@@ -28614,6 +28618,7 @@
"version": "2.23.5", "version": "2.23.5",
"resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.23.5.tgz", "resolved": "https://registry.npmjs.org/swagger-autogen/-/swagger-autogen-2.23.5.tgz",
"integrity": "sha512-4Tl2+XhZMyHoBYkABnScHtQE0lKPKUD3NBt09mClrI6UKOUYljKlYw1xiFVwsHCTGR2hAXmhT4PpgjruCtt1ZA==", "integrity": "sha512-4Tl2+XhZMyHoBYkABnScHtQE0lKPKUD3NBt09mClrI6UKOUYljKlYw1xiFVwsHCTGR2hAXmhT4PpgjruCtt1ZA==",
"dev": true,
"requires": { "requires": {
"acorn": "^7.4.1", "acorn": "^7.4.1",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
@@ -28624,7 +28629,8 @@
"acorn": { "acorn": {
"version": "7.4.1", "version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true
} }
} }
}, },

View File

@@ -46,7 +46,6 @@
"query-string": "^7.1.3", "query-string": "^7.1.3",
"rate-limit-mongo": "^2.3.2", "rate-limit-mongo": "^2.3.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"swagger-autogen": "^2.22.0",
"swagger-ui-express": "^4.6.2", "swagger-ui-express": "^4.6.2",
"tweetnacl": "^1.0.3", "tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1", "tweetnacl-util": "^0.15.1",
@@ -114,6 +113,7 @@
"npm": "^8.19.3", "npm": "^8.19.3",
"smee-client": "^1.2.3", "smee-client": "^1.2.3",
"supertest": "^6.3.3", "supertest": "^6.3.3",
"swagger-autogen": "^2.23.5",
"ts-jest": "^29.0.3", "ts-jest": "^29.0.3",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"
}, },

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@ import * as userController from "./userController";
import * as workspaceController from "./workspaceController"; import * as workspaceController from "./workspaceController";
import * as secretScanningController from "./secretScanningController"; import * as secretScanningController from "./secretScanningController";
import * as webhookController from "./webhookController"; import * as webhookController from "./webhookController";
import * as secretImportController from "./secretImportController"; import * as secretImpsController from "./secretImpsController";
import * as roleController from "./roleController"; import * as roleController from "./roleController";
export { export {
@@ -37,5 +37,5 @@ export {
secretScanningController, secretScanningController,
webhookController, webhookController,
roleController, roleController,
secretImportController secretImpsController
}; };

View File

@@ -19,7 +19,81 @@ import {
} from "../../services/ProjectRoleService"; } from "../../services/ProjectRoleService";
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
export const createSecretImport = async (req: Request, res: Response) => { export const createSecretImp = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Create secret import'
#swagger.description = 'Create a new secret import for a specified workspace and environment'
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of the workspace where the secret import will be created",
"example": "someWorkspaceId"
},
"environment": {
"type": "string",
"description": "Environment to import to",
"example": "production"
},
"folderId": {
"type": "string",
"description": "Folder ID. Use root for the root folder.",
"example": "my_folder"
},
"secretImport": {
"type": "object",
"properties": {
"environment": {
"type": "string",
"description": "Import from environment",
"example": "development"
},
"secretPath": {
"type": "string",
"description": "Import from secret path",
"example": "/user/oauth"
}
}
}
},
"required": ["workspaceId", "environment", "folderName"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "successfully created secret import"
}
},
"description": "Confirmation of secret import creation"
}
}
}
}
#swagger.responses[400] = {
description: "Bad Request. For example, 'Secret import already exist'"
}
#swagger.responses[401] = {
description: "Unauthorized request. For example, 'Folder Permission Denied'"
}
#swagger.responses[404] = {
description: "Resource Not Found. For example, 'Failed to find folder'"
}
*/
const { const {
body: { workspaceId, environment, folderId, secretImport } body: { workspaceId, environment, folderId, secretImport }
} = await validateRequest(reqValidator.CreateSecretImportV1, req); } = await validateRequest(reqValidator.CreateSecretImportV1, req);
@@ -129,7 +203,88 @@ export const createSecretImport = async (req: Request, res: Response) => {
// to keep the ordering, you must pass all the imports in here not the only updated one // to keep the ordering, you must pass all the imports in here not the only updated one
// this is because the order decide which import gets overriden // this is because the order decide which import gets overriden
/**
* Update secret import
* @param req
* @param res
* @returns
*/
export const updateSecretImport = async (req: Request, res: Response) => { export const updateSecretImport = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Update a secret import'
#swagger.description = 'Updates an existing secret import based on the provided ID and new import details'
#swagger.parameters['id'] = {
in: 'path',
description: 'ID of the secret import to be updated',
required: true,
type: 'string',
example: 'import12345'
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretImports": {
"type": "array",
"description": "List of new secret imports",
"items": {
"type": "object",
"properties": {
"environment": {
"type": "string",
"description": "Environment of the secret import",
"example": "production"
},
"secretPath": {
"type": "string",
"description": "Path of the secret import",
"example": "/path/to/secret"
}
},
"required": ["environment", "secretPath"]
}
}
},
"required": ["secretImports"]
}
}
}
}
#swagger.responses[200] = {
description: 'Successfully updated the secret import',
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "successfully updated secret import"
}
}
}
}
}
}
#swagger.responses[400] = {
description: 'Bad Request - Import not found',
}
#swagger.responses[403] = {
description: 'Forbidden access due to insufficient permissions',
}
#swagger.responses[401] = {
description: 'Unauthorized access due to invalid token or scope',
}
*/
const { const {
body: { secretImports }, body: { secretImports },
params: { id } params: { id }
@@ -202,7 +357,65 @@ export const updateSecretImport = async (req: Request, res: Response) => {
return res.status(200).json({ message: "successfully updated secret import" }); return res.status(200).json({ message: "successfully updated secret import" });
}; };
/**
* Delete secret import
* @param req
* @param res
* @returns
*/
export const deleteSecretImport = async (req: Request, res: Response) => { export const deleteSecretImport = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Delete secret import'
#swagger.description = 'Delete secret import'
#swagger.parameters['id'] = {
in: 'path',
description: 'ID of the secret import',
required: true,
type: 'string',
example: '12345abcde'
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretImportEnv": {
"type": "string",
"description": "Import from environment",
"example": "someWorkspaceId"
},
"secretImportPath": {
"type": "string",
"description": "Import from secret path",
"example": "production"
}
},
"required": ["id", "secretImportEnv", "secretImportPath"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "successfully delete secret import"
}
},
"description": "Confirmation of secret import deletion"
}
}
}
}
*/
const { const {
params: { id }, params: { id },
body: { secretImportEnv, secretImportPath } body: { secretImportEnv, secretImportPath }
@@ -274,7 +487,66 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
return res.status(200).json({ message: "successfully delete secret import" }); return res.status(200).json({ message: "successfully delete secret import" });
}; };
/**
* Get secret imports
* @param req
* @param res
* @returns
*/
export const getSecretImports = async (req: Request, res: Response) => { export const getSecretImports = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Retrieve secret imports'
#swagger.description = 'Fetches the secret imports based on the workspaceId, environment, and folderId'
#swagger.parameters['workspaceId'] = {
in: 'query',
description: 'ID of the workspace of secret imports to get',
required: true,
type: 'string',
example: 'workspace12345'
}
#swagger.parameters['environment'] = {
in: 'query',
description: 'Environment of secret imports to get',
required: true,
type: 'string',
example: 'production'
}
#swagger.parameters['folderId'] = {
in: 'query',
description: 'ID of the folder containing the secret imports. Default: root',
required: false,
type: 'string',
example: 'folder12345'
}
#swagger.responses[200] = {
description: 'Successfully retrieved secret import',
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretImport": {
"type": "object",
"description": "Details of a secret import"
}
}
}
}
}
}
#swagger.responses[403] = {
description: 'Forbidden access due to insufficient permissions',
}
#swagger.responses[401] = {
description: 'Unauthorized access due to invalid token or scope',
}
*/
const { const {
query: { workspaceId, environment, folderId } query: { workspaceId, environment, folderId }
} = await validateRequest(reqValidator.GetSecretImportsV1, req); } = await validateRequest(reqValidator.GetSecretImportsV1, req);
@@ -326,6 +598,12 @@ export const getSecretImports = async (req: Request, res: Response) => {
return res.status(200).json({ secretImport: importSecDoc }); return res.status(200).json({ secretImport: importSecDoc });
}; };
/**
* Get all secret imports
* @param req
* @param res
* @returns
*/
export const getAllSecretsFromImport = async (req: Request, res: Response) => { export const getAllSecretsFromImport = async (req: Request, res: Response) => {
const { const {
query: { workspaceId, environment, folderId } query: { workspaceId, environment, folderId }

View File

@@ -25,8 +25,87 @@ import {
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import * as reqValidator from "../../validation/folders"; import * as reqValidator from "../../validation/folders";
// verify workspace id/environment /**
* Create folder with name [folderName] for workspace with id [workspaceId]
* and environment [environment]
* @param req
* @param res
* @returns
*/
export const createFolder = async (req: Request, res: Response) => { export const createFolder = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Create a folder'
#swagger.description = 'Create a new folder in a specified workspace and environment'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of the workspace where the folder will be created",
"example": "someWorkspaceId"
},
"environment": {
"type": "string",
"description": "Environment where the folder will reside",
"example": "production"
},
"folderName": {
"type": "string",
"description": "Name of the folder to be created",
"example": "my_folder"
},
"parentFolderId": {
"type": "string",
"description": "ID of the parent folder under which this folder will be created. If not specified, it will be created at the root level.",
"example": "someParentFolderId"
}
},
"required": ["workspaceId", "environment", "folderName"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"folder": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "someFolderId"
},
"name": {
"type": "string",
"example": "my_folder"
}
},
"description": "Details of the created folder"
}
}
}
}
}
}
#swagger.responses[400] = {
description: "Bad Request. For example, 'Folder name cannot contain spaces. Only underscore and dashes'"
}
#swagger.responses[401] = {
description: "Unauthorized request. For example, 'Folder Permission Denied'"
}
*/
const { const {
body: { workspaceId, environment, folderName, parentFolderId } body: { workspaceId, environment, folderName, parentFolderId }
} = await validateRequest(reqValidator.CreateFolderV1, req); } = await validateRequest(reqValidator.CreateFolderV1, req);
@@ -164,7 +243,94 @@ export const createFolder = async (req: Request, res: Response) => {
return res.json({ folder }); return res.json({ folder });
}; };
/**
* Update folder with id [folderId]
* @param req
* @param res
* @returns
*/
export const updateFolderById = async (req: Request, res: Response) => { export const updateFolderById = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Update a folder by ID'
#swagger.description = 'Update the name of a folder in a specified workspace and environment by its ID'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['folderId'] = {
"description": "ID of the folder to be updated",
"required": true,
"type": "string",
"in": "path"
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of the workspace where the folder is located",
"example": "someWorkspaceId"
},
"environment": {
"type": "string",
"description": "Environment where the folder is located",
"example": "production"
},
"name": {
"type": "string",
"description": "New name for the folder",
"example": "updated_folder_name"
}
},
"required": ["workspaceId", "environment", "name"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Successfully updated folder"
},
"folder": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "updated_folder_name"
},
"id": {
"type": "string",
"example": "someFolderId"
}
},
"description": "Details of the updated folder"
}
}
}
}
}
}
#swagger.responses[400] = {
description: "Bad Request. Reasons can include 'The folder doesn't exist' or 'Folder name cannot contain spaces. Only underscore and dashes'"
}
#swagger.responses[401] = {
description: "Unauthorized request. For example, 'Folder Permission Denied'"
}
*/
const { const {
body: { workspaceId, environment, name }, body: { workspaceId, environment, name },
params: { folderId } params: { folderId }
@@ -252,7 +418,92 @@ export const updateFolderById = async (req: Request, res: Response) => {
}); });
}; };
/**
* Delete folder with id [folderId]
* @param req
* @param res
* @returns
*/
export const deleteFolder = async (req: Request, res: Response) => { export const deleteFolder = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Delete a folder by ID'
#swagger.description = 'Delete the specified folder from a specified workspace and environment using its ID'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['folderId'] = {
"description": "ID of the folder to be deleted",
"required": true,
"type": "string",
"in": "path"
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of the workspace where the folder is located",
"example": "someWorkspaceId"
},
"environment": {
"type": "string",
"description": "Environment where the folder is located",
"example": "production"
}
},
"required": ["workspaceId", "environment"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "successfully deleted folders"
},
"folders": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "someFolderId"
},
"name": {
"type": "string",
"example": "someFolderName"
}
}
},
"description": "List of IDs and names of the deleted folders"
}
}
}
}
}
}
#swagger.responses[400] = {
description: "Bad Request. Reasons can include 'The folder doesn't exist'"
}
#swagger.responses[401] = {
description: "Unauthorized request. For example, 'Folder Permission Denied'"
}
*/
const { const {
params: { folderId }, params: { folderId },
body: { environment, workspaceId } body: { environment, workspaceId }
@@ -327,8 +578,104 @@ export const deleteFolder = async (req: Request, res: Response) => {
res.send({ message: "successfully deleted folders", folders: delFolderIds }); res.send({ message: "successfully deleted folders", folders: delFolderIds });
}; };
// TODO: validate workspace /**
* Get folders for workspace with id [workspaceId] and environment [environment]
* considering [parentFolderId] and [parentFolderPath]
* @param req
* @param res
* @returns
*/
export const getFolders = async (req: Request, res: Response) => { export const getFolders = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Retrieve folders based on specific conditions'
#swagger.description = 'Fetches folders from the specified workspace and environment, optionally providing either a parentFolderId or a parentFolderPath to narrow down results'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of the workspace from which the folders are to be fetched",
"required": true,
"type": "string",
"in": "query"
}
#swagger.parameters['environment'] = {
"description": "Environment where the folder is located",
"required": true,
"type": "string",
"in": "query"
}
#swagger.parameters['parentFolderId'] = {
"description": "ID of the parent folder",
"required": false,
"type": "string",
"in": "query"
}
#swagger.parameters['parentFolderPath'] = {
"description": "Path of the parent folder, like /folder1/folder2",
"required": false,
"type": "string",
"in": "query"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"folders": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "someFolderId"
},
"name": {
"type": "string",
"example": "someFolderName"
}
}
},
"description": "List of folders"
},
"dir": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "parentFolderName"
},
"id": {
"type": "string",
"example": "parentFolderId"
}
}
},
"description": "List of directories"
}
}
}
}
}
}
#swagger.responses[400] = {
description: "Bad Request. For instance, 'The folder doesn't exist'"
}
#swagger.responses[401] = {
description: "Unauthorized request. For example, 'Folder Permission Denied'"
}
*/
const { const {
query: { workspaceId, environment, parentFolderId, parentFolderPath } query: { workspaceId, environment, parentFolderId, parentFolderPath }
} = await validateRequest(reqValidator.GetFoldersV1, req); } = await validateRequest(reqValidator.GetFoldersV1, req);

View File

@@ -23,12 +23,98 @@ import {
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
/** /**
* Create new workspace environment named [environmentName] under workspace with id * Create new workspace environment named [environmentName]
* with slug [environmentSlug] under workspace with id
* @param req * @param req
* @param res * @param res
* @returns * @returns
*/ */
export const createWorkspaceEnvironment = async (req: Request, res: Response) => { export const createWorkspaceEnvironment = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Create environment'
#swagger.description = 'Create environment'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
/*
#swagger.summary = 'Create environment'
#swagger.description = 'Create environment'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"environmentName": {
"type": "string",
"description": "Name of the environment",
"example": "development"
},
"environmentSlug": {
"type": "string",
"description": "Slug of the environment",
"example": "dev-environment"
}
},
"required": ["environmentName", "environmentSlug"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Successfully created new environment"
},
"workspace": {
"type": "string",
"example": "someWorkspaceId"
},
"environment": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "someEnvironmentName"
},
"slug": {
"type": "string",
"example": "someEnvironmentSlug"
}
}
}
},
"description": "Response after creating a new environment"
}
}
}
}
*/
const { const {
params: { workspaceId }, params: { workspaceId },
body: { environmentName, environmentSlug } body: { environmentName, environmentSlug }
@@ -156,6 +242,79 @@ export const reorderWorkspaceEnvironments = async (req: Request, res: Response)
* @returns * @returns
*/ */
export const renameWorkspaceEnvironment = async (req: Request, res: Response) => { export const renameWorkspaceEnvironment = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Rename workspace environment'
#swagger.description = 'Rename a specific environment within a workspace'
#swagger.parameters['workspaceId'] = {
"description": "ID of the workspace",
"required": true,
"type": "string",
"in": "path"
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"environmentName": {
"type": "string",
"description": "New name for the environment",
"example": "Staging-Renamed"
},
"environmentSlug": {
"type": "string",
"description": "New slug for the environment",
"example": "staging-renamed"
},
"oldEnvironmentSlug": {
"type": "string",
"description": "Current slug of the environment to rename",
"example": "staging-old"
}
},
"required": ["environmentName", "environmentSlug", "oldEnvironmentSlug"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Successfully update environment"
},
"workspace": {
"type": "string",
"example": "someWorkspaceId"
},
"environment": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "Staging-Renamed"
},
"slug": {
"type": "string",
"example": "staging-renamed"
}
}
}
},
"description": "Details of the renamed environment"
}
}
}
}
*/
const { const {
params: { workspaceId }, params: { workspaceId },
body: { environmentName, environmentSlug, oldEnvironmentSlug } body: { environmentName, environmentSlug, oldEnvironmentSlug }
@@ -259,6 +418,64 @@ export const renameWorkspaceEnvironment = async (req: Request, res: Response) =>
* @returns * @returns
*/ */
export const deleteWorkspaceEnvironment = async (req: Request, res: Response) => { export const deleteWorkspaceEnvironment = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Delete workspace environment'
#swagger.description = 'Delete a specific environment from a workspace'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of the workspace",
"required": true,
"type": "string",
"in": "path"
}
#swagger.requestBody = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"environmentSlug": {
"type": "string",
"description": "Slug of the environment to delete",
"example": "dev-environment"
}
},
"required": ["environmentSlug"]
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Successfully deleted environment"
},
"workspace": {
"type": "string",
"example": "someWorkspaceId"
},
"environment": {
"type": "string",
"example": "dev-environment"
}
},
"description": "Response after deleting an environment from a workspace"
}
}
}
}
*/
const { const {
params: { workspaceId }, params: { workspaceId },
body: { environmentSlug } body: { environmentSlug }
@@ -344,6 +561,58 @@ export const deleteWorkspaceEnvironment = async (req: Request, res: Response) =>
// TODO(akhilmhdh) after rbac this can be completely removed // TODO(akhilmhdh) after rbac this can be completely removed
export const getAllAccessibleEnvironmentsOfWorkspace = async (req: Request, res: Response) => { export const getAllAccessibleEnvironmentsOfWorkspace = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Get all accessible environments of a workspace'
#swagger.description = 'Fetch all environments that the user has access to in a specified workspace'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of the workspace",
"required": true,
"type": "string",
"in": "path"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"accessibleEnvironments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "Development"
},
"slug": {
"type": "string",
"example": "development"
},
"isWriteDenied": {
"type": "boolean",
"example": false
},
"isReadDenied": {
"type": "boolean",
"example": false
}
}
}
}
},
"description": "List of environments the user has access to in the specified workspace"
}
}
}
}
*/
const { const {
params: { workspaceId } params: { workspaceId }
} = await validateRequest(reqValidator.GetAllAccessibileEnvironmentsOfWorkspaceV2, req); } = await validateRequest(reqValidator.GetAllAccessibileEnvironmentsOfWorkspaceV2, req);

View File

@@ -38,7 +38,7 @@ import {
organization as v1OrganizationRouter, organization as v1OrganizationRouter,
password as v1PasswordRouter, password as v1PasswordRouter,
role as v1RoleRouter, role as v1RoleRouter,
secretImport as v1SecretImportRouter, secretImps as v1SecretImpsRouter,
secret as v1SecretRouter, secret as v1SecretRouter,
secretsFolder as v1SecretsFolder, secretsFolder as v1SecretsFolder,
serviceToken as v1ServiceTokenRouter, serviceToken as v1ServiceTokenRouter,
@@ -138,6 +138,7 @@ const main = async () => {
app.use((req, res, next) => { app.use((req, res, next) => {
// default to IP address provided by Cloudflare // default to IP address provided by Cloudflare
// #swagger.ignore = true
const cfIp = req.headers["cf-connecting-ip"]; const cfIp = req.headers["cf-connecting-ip"];
req.realIP = Array.isArray(cfIp) ? cfIp[0] : (cfIp as string) || req.ip; req.realIP = Array.isArray(cfIp) ? cfIp[0] : (cfIp as string) || req.ip;
next(); next();
@@ -153,7 +154,7 @@ const main = async () => {
app.use("/api/v1/sso", eeSSORouter); app.use("/api/v1/sso", eeSSORouter);
app.use("/api/v1/cloud-products", eeCloudProductsRouter); app.use("/api/v1/cloud-products", eeCloudProductsRouter);
// v1 routes (default) // v1 routes
app.use("/api/v1/signup", v1SignupRouter); app.use("/api/v1/signup", v1SignupRouter);
app.use("/api/v1/auth", v1AuthRouter); app.use("/api/v1/auth", v1AuthRouter);
app.use("/api/v1/bot", v1BotRouter); app.use("/api/v1/bot", v1BotRouter);
@@ -162,7 +163,7 @@ const main = async () => {
app.use("/api/v1/organization", v1OrganizationRouter); app.use("/api/v1/organization", v1OrganizationRouter);
app.use("/api/v1/workspace", v1WorkspaceRouter); app.use("/api/v1/workspace", v1WorkspaceRouter);
app.use("/api/v1/membership-org", v1MembershipOrgRouter); app.use("/api/v1/membership-org", v1MembershipOrgRouter);
app.use("/api/v1/membership", v1MembershipRouter); app.use("/api/v1/membership", v1MembershipRouter); //
app.use("/api/v1/key", v1KeyRouter); app.use("/api/v1/key", v1KeyRouter);
app.use("/api/v1/invite-org", v1InviteOrgRouter); app.use("/api/v1/invite-org", v1InviteOrgRouter);
app.use("/api/v1/secret", v1SecretRouter); // deprecate app.use("/api/v1/secret", v1SecretRouter); // deprecate
@@ -173,7 +174,7 @@ const main = async () => {
app.use("/api/v1/folders", v1SecretsFolder); app.use("/api/v1/folders", v1SecretsFolder);
app.use("/api/v1/secret-scanning", v1SecretScanningRouter); app.use("/api/v1/secret-scanning", v1SecretScanningRouter);
app.use("/api/v1/webhooks", v1WebhooksRouter); app.use("/api/v1/webhooks", v1WebhooksRouter);
app.use("/api/v1/secret-imports", v1SecretImportRouter); app.use("/api/v1/secret-imports", v1SecretImpsRouter);
app.use("/api/v1/roles", v1RoleRouter); app.use("/api/v1/roles", v1RoleRouter);
// v2 routes (improvements) // v2 routes (improvements)

View File

@@ -16,7 +16,7 @@ import integration from "./integration";
import integrationAuth from "./integrationAuth"; import integrationAuth from "./integrationAuth";
import secretsFolder from "./secretsFolder"; import secretsFolder from "./secretsFolder";
import webhooks from "./webhook"; import webhooks from "./webhook";
import secretImport from "./secretImport"; import secretImps from "./secretImps";
import role from "./role"; import role from "./role";
export { export {
@@ -38,6 +38,6 @@ export {
integrationAuth, integrationAuth,
secretsFolder, secretsFolder,
webhooks, webhooks,
secretImport, secretImps,
role role
}; };

View File

@@ -1,15 +1,15 @@
import express from "express"; import express from "express";
import { secretImportController } from "../../controllers/v1";
import { requireAuth } from "../../middleware";
import { AuthMode } from "../../variables";
const router = express.Router(); const router = express.Router();
import { requireAuth } from "../../middleware";
import { secretImpsController } from "../../controllers/v1";
import { AuthMode } from "../../variables";
router.post( router.post(
"/", "/",
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
}), }),
secretImportController.createSecretImport secretImpsController.createSecretImp
); );
router.put( router.put(
@@ -17,7 +17,7 @@ router.put(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
}), }),
secretImportController.updateSecretImport secretImpsController.updateSecretImport
); );
router.delete( router.delete(
@@ -25,7 +25,7 @@ router.delete(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
}), }),
secretImportController.deleteSecretImport secretImpsController.deleteSecretImport
); );
router.get( router.get(
@@ -33,7 +33,7 @@ router.get(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
}), }),
secretImportController.getSecretImports secretImpsController.getSecretImports
); );
router.get( router.get(
@@ -41,7 +41,7 @@ router.get(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.SERVICE_TOKEN]
}), }),
secretImportController.getAllSecretsFromImport secretImpsController.getAllSecretsFromImport
); );
export default router; export default router;

View File

@@ -1,13 +1,13 @@
import express from "express"; import express from "express";
const router = express.Router();
import { requireAuth } from "../../middleware";
import { import {
createFolder, createFolder,
deleteFolder, deleteFolder,
getFolders, getFolders,
updateFolderById updateFolderById
} from "../../controllers/v1/secretsFolderController"; } from "../../controllers/v1/secretsFolderController";
import { requireAuth } from "../../middleware";
import { AuthMode } from "../../variables"; import { AuthMode } from "../../variables";
const router = express.Router();
router.post( router.post(
"/", "/",

View File

@@ -7,7 +7,7 @@ import { AuthMode } from "../../variables";
router.post( router.post(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}), }),
environmentController.createWorkspaceEnvironment environmentController.createWorkspaceEnvironment
); );
@@ -15,7 +15,7 @@ router.post(
router.put( router.put(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}), }),
environmentController.renameWorkspaceEnvironment environmentController.renameWorkspaceEnvironment
); );
@@ -31,7 +31,7 @@ router.patch(
router.delete( router.delete(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}), }),
environmentController.deleteWorkspaceEnvironment environmentController.deleteWorkspaceEnvironment
); );
@@ -39,7 +39,7 @@ router.delete(
router.get( router.get(
"/:workspaceId/environments", "/:workspaceId/environments",
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY]
}), }),
environmentController.getAllAccessibleEnvironmentsOfWorkspace environmentController.getAllAccessibleEnvironmentsOfWorkspace
); );

View File

@@ -223,7 +223,8 @@ const generateOpenAPISpec = async () => {
const endpointsFiles = ["../src/index.ts"]; const endpointsFiles = ["../src/index.ts"];
const spec = await swaggerAutogen(outputJSONFile, endpointsFiles, doc); const spec = await swaggerAutogen(outputJSONFile, endpointsFiles, doc);
await fs.writeFile(outputYAMLFile, yaml.dump(spec.data)); await fs.writeFile(outputYAMLFile, yaml.dump(spec.data));
} }
generateOpenAPISpec(); generateOpenAPISpec();

View File

@@ -0,0 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/folders/"
---

View File

@@ -0,0 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/folders/{folderId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/folders/"
---

View File

@@ -0,0 +1,4 @@
---
title: "Update"
openapi: "PATCH /api/v1/folders/{folderId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/secret-imports/"
---

View File

@@ -0,0 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/secret-imports/{id}"
---

View File

@@ -0,0 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/secret-imports/"
---

View File

@@ -0,0 +1,4 @@
---
title: "Update"
openapi: "PUT /api/v1/secret-imports/{id}"
---

View File

@@ -5,7 +5,6 @@ openapi: "POST /api/v3/secrets/{secretName}"
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the You should consult the [examples](https://infisical.com/docs/api-reference/overview/examples/note) for how to use
[introduction](/api-reference/overview/introduction) and [guide for creating this endpoint.
secrets](/api-reference/overview/examples/create-secret).
</Tip> </Tip>

View File

@@ -1,4 +1,4 @@
--- ---
title: "Delete" title: "Delete"
openapi: "DELETE /api/v3/secrets/{secretName}" openapi: "DELETE /api/v3/secrets/{secretName}"
--- ---

View File

@@ -5,7 +5,7 @@ openapi: "GET /api/v3/secrets/"
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the You should consult the [examples](https://infisical.com/docs/api-reference/overview/examples/note) for how to use
[introduction](/api-reference/overview/introduction) and [guide for retrieving this endpoint.
secrets](/api-reference/overview/examples/retrieve-secret).
</Tip> </Tip>

View File

@@ -5,7 +5,6 @@ openapi: "GET /api/v3/secrets/{secretName}"
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the You should consult the [examples](https://infisical.com/docs/api-reference/overview/examples/note) for how to use
[introduction](/api-reference/overview/introduction) and [guide for retrieving this endpoint.
secrets](/api-reference/overview/examples/retrieve-secret).
</Tip> </Tip>

View File

@@ -5,7 +5,7 @@ openapi: "PATCH /api/v3/secrets/{secretName}"
<Tip> <Tip>
Using this route requires understanding Infisical's system and cryptography. Using this route requires understanding Infisical's system and cryptography.
It may be helpful to read through the You should consult the [examples](https://infisical.com/docs/api-reference/overview/examples/note) for how to use
[introduction](/api-reference/overview/introduction) and [guide for updating this endpoint.
secrets](/api-reference/overview/examples/update-secret).
</Tip> </Tip>

View File

@@ -331,6 +331,15 @@
"api-reference/endpoints/environments/delete" "api-reference/endpoints/environments/delete"
] ]
}, },
{
"group": "Folders",
"pages": [
"api-reference/endpoints/folders/list",
"api-reference/endpoints/folders/create",
"api-reference/endpoints/folders/update",
"api-reference/endpoints/folders/delete"
]
},
{ {
"group": "Secrets", "group": "Secrets",
"pages": [ "pages": [
@@ -343,6 +352,15 @@
"api-reference/endpoints/secrets/rollback-version" "api-reference/endpoints/secrets/rollback-version"
] ]
}, },
{
"group": "Secret imports",
"pages": [
"api-reference/endpoints/secret-imports/list",
"api-reference/endpoints/secret-imports/create",
"api-reference/endpoints/secret-imports/update",
"api-reference/endpoints/secret-imports/delete"
]
},
{ {
"group": "Service Tokens", "group": "Service Tokens",
"pages": ["api-reference/endpoints/service-tokens/get"] "pages": ["api-reference/endpoints/service-tokens/get"]

File diff suppressed because it is too large Load Diff