Complete v1 API reference docs, pre-launch

This commit is contained in:
Tuan Dang
2023-01-14 19:02:12 +07:00
parent b63360813a
commit 315810bd74
28 changed files with 2216 additions and 222 deletions

View File

@ -18,7 +18,8 @@
"paths": {
"/api/v1/secret/{secretId}/secret-versions": {
"get": {
"description": "",
"summary": "Return secret versions",
"description": "Return secret versions",
"parameters": [
{
"name": "secretId",
@ -26,10 +27,13 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of secret"
},
{
"name": "offset",
"description": "Number of versions to skip",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -37,6 +41,8 @@
},
{
"name": "limit",
"description": "Maximum number of versions to return",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -45,17 +51,39 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretVersions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SecretVersion"
},
"description": "Secret versions"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v1/secret/{secretId}/secret-versions/rollback": {
"post": {
"description": "",
"summary": "Roll back secret to a version.",
"description": "Roll back secret to a version.",
"parameters": [
{
"name": "secretId",
@ -63,25 +91,47 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of secret"
}
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secret": {
"type": "object",
"$ref": "#/components/schemas/Secret",
"description": "Secret rolled back to"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"example": "any"
"type": "integer",
"description": "Version of secret to roll back to"
}
}
}
@ -115,7 +165,8 @@
},
"/api/v1/workspace/{workspaceId}/secret-snapshots": {
"get": {
"description": "",
"summary": "Return project secret snapshot ids",
"description": "Return project secret snapshots ids",
"parameters": [
{
"name": "workspaceId",
@ -123,10 +174,13 @@
"required": true,
"schema": {
"type": "string"
}
},
"description": "ID of project"
},
{
"name": "offset",
"description": "Number of secret snapshots to skip",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -134,6 +188,8 @@
},
{
"name": "limit",
"description": "Maximum number of secret snapshots to return",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -142,12 +198,33 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"secretSnapshots": {
"type": "array",
"items": {
"$ref": "#/components/schemas/SecretSnapshot"
},
"description": "Project secret snapshots"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v1/workspace/{workspaceId}/secret-snapshots/count": {
@ -175,8 +252,8 @@
},
"/api/v1/workspace/{workspaceId}/secret-snapshots/rollback": {
"post": {
"summary": "Roll back project secrets to those captured in a secret snapshot version",
"description": "Roll back project secrets to those captured in a secret snapshot version",
"summary": "Roll back project secrets to those captured in a secret snapshot version.",
"description": "Roll back project secrets to those captured in a secret snapshot version.",
"parameters": [
{
"name": "workspaceId",
@ -194,11 +271,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of secrets captured in the secret snapshot"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Secrets rolled back to"
}
}
}
}
}
@ -232,18 +314,31 @@
},
"/api/v1/workspace/{workspaceId}/logs": {
"get": {
"description": "",
"summary": "Return project (audit) logs",
"description": "Return project (audit) logs",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
},
{
"name": "userId",
"description": "ID of project member",
"required": false,
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "offset",
"description": "Number of logs to skip",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -251,6 +346,8 @@
},
{
"name": "limit",
"description": "Maximum number of logs to return",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -258,20 +355,21 @@
},
{
"name": "sortBy",
"in": "query",
"description": "Order to sort the logs by",
"schema": {
"type": "string"
}
},
{
"name": "userId",
"in": "query",
"schema": {
"type": "string"
}
"type": "string",
"enum": [
"oldest",
"recent"
]
},
"required": false,
"in": "query"
},
{
"name": "actionNames",
"description": "Names of log actions (comma-separated)",
"required": false,
"in": "query",
"schema": {
"type": "string"
@ -280,12 +378,33 @@
],
"responses": {
"200": {
"description": "OK"
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"logs": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Log"
},
"description": "Project logs"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v1/action/{actionId}": {
@ -2117,8 +2236,13 @@
"application/json": {
"schema": {
"type": "object",
"$ref": "#/components/schemas/CurrentUser",
"description": "Current user on request"
"properties": {
"user": {
"type": "object",
"$ref": "#/components/schemas/CurrentUser",
"description": "Current user on request"
}
}
}
}
}
@ -2279,6 +2403,170 @@
}
}
},
"/api/v2/workspace/{workspaceId}/memberships": {
"get": {
"summary": "Return project memberships",
"description": "Return project memberships",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"memberships": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Membership"
},
"description": "Memberships of project"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
]
}
},
"/api/v2/workspace/{workspaceId}/memberships/{membershipId}": {
"delete": {
"summary": "Delete project membership",
"description": "Delete project membership",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
},
{
"name": "membershipId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of membership"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
"$ref": "#/components/schemas/Membership",
"description": "Deleted membership"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
]
},
"patch": {
"summary": "Update project membership",
"description": "Update project membership",
"parameters": [
{
"name": "workspaceId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of project"
},
{
"name": "membershipId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "ID of membership"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
"$ref": "#/components/schemas/Membership",
"description": "Updated membership"
}
}
}
}
}
},
"400": {
"description": "Bad Request"
}
},
"security": [
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"role": {
"type": "string",
"description": "Role of membership - either admin or member"
}
}
}
}
}
}
}
},
"/api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}": {
"post": {
"description": "",
@ -2565,11 +2853,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of newly-created secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Newly-created secrets for the given project and environment"
}
}
}
}
}
@ -2608,18 +2901,49 @@
"get": {
"summary": "Read secrets",
"description": "Read secrets from a project and environment",
"parameters": [],
"parameters": [
{
"name": "workspaceId",
"description": "ID of project",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "environment",
"description": "Environment within project",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "content",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Secrets for the given project and environment"
}
}
}
}
}
@ -2629,27 +2953,7 @@
{
"apiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of project"
},
"environment": {
"type": "string",
"description": "Environment within project"
}
}
}
}
}
}
]
},
"patch": {
"summary": "Update secret(s)",
@ -2661,11 +2965,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of newly-updated secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Updated secrets"
}
}
}
}
}
@ -2703,11 +3012,16 @@
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Array of deleted secrets"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Secret"
},
"description": "Deleted secrets"
}
}
}
}
}
@ -2942,6 +3256,52 @@
}
}
},
"Membership": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"email": {
"type": "string",
"example": ""
},
"firstName": {
"type": "string",
"example": ""
},
"lastName": {
"type": "string",
"example": ""
},
"publicKey": {
"type": "string",
"example": ""
},
"updatedAt": {
"type": "string",
"example": ""
},
"createdAt": {
"type": "string",
"example": ""
}
}
},
"workspace": {
"type": "string",
"example": ""
},
"role": {
"type": "string",
"example": "admin"
}
}
},
"ProjectKey": {
"type": "object",
"properties": {
@ -3127,6 +3487,187 @@
"example": ""
}
}
},
"Log": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"user": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"email": {
"type": "string",
"example": ""
},
"firstName": {
"type": "string",
"example": ""
},
"lastName": {
"type": "string",
"example": ""
}
}
},
"workspace": {
"type": "string",
"example": ""
},
"actionNames": {
"type": "array",
"example": [
"addSecrets"
],
"items": {
"type": "string"
}
},
"actions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"example": "addSecrets"
},
"user": {
"type": "string",
"example": ""
},
"workspace": {
"type": "string",
"example": ""
},
"payload": {
"type": "array",
"items": {
"type": "object",
"properties": {
"oldSecretVersion": {
"type": "string",
"example": ""
},
"newSecretVersion": {
"type": "string",
"example": ""
}
}
}
}
}
}
},
"channel": {
"type": "string",
"example": "cli"
},
"ipAddress": {
"type": "string",
"example": "192.168.0.1"
},
"updatedAt": {
"type": "string",
"example": ""
},
"createdAt": {
"type": "string",
"example": ""
}
}
},
"SecretSnapshot": {
"type": "object",
"properties": {
"workspace": {
"type": "string",
"example": ""
},
"version": {
"type": "number",
"example": 1
},
"secretVersions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
}
}
}
}
}
},
"SecretVersion": {
"type": "object",
"properties": {
"_id": {
"type": "string",
"example": ""
},
"secret": {
"type": "string",
"example": ""
},
"version": {
"type": "number",
"example": 1
},
"workspace": {
"type": "string",
"example": ""
},
"type": {
"type": "string",
"example": ""
},
"user": {
"type": "string",
"example": ""
},
"environment": {
"type": "string",
"example": ""
},
"isDeleted": {
"type": "string",
"example": ""
},
"secretKeyCiphertext": {
"type": "string",
"example": ""
},
"secretKeyIV": {
"type": "string",
"example": ""
},
"secretKeyTag": {
"type": "string",
"example": ""
},
"secretValueCiphertext": {
"type": "string",
"example": ""
},
"secretValueIV": {
"type": "string",
"example": ""
},
"secretValueTag": {
"type": "string",
"example": ""
}
}
}
},
"securitySchemes": {

View File

@ -58,11 +58,16 @@ export const createSecrets = async (req: Request, res: Response) => {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of newly-created secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Newly-created secrets for the given project and environment"
}
}
}
}
}
@ -205,36 +210,32 @@ export const getSecrets = async (req: Request, res: Response) => {
"apiKeyAuth": []
}]
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "ID of project"
},
"environment": {
"type": "string",
"description": "Environment within project"
}
}
}
}
}
}
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['environment'] = {
"description": "Environment within project",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Secrets for the given project and environment"
}
}
}
}
}
@ -307,9 +308,6 @@ export const getSecrets = async (req: Request, res: Response) => {
* @param res
*/
export const updateSecrets = async (req: Request, res: Response) => {
// TODO: fix update secret schema
/*
#swagger.summary = 'Update secret(s)'
#swagger.description = 'Update secret(s)'
@ -339,15 +337,20 @@ export const updateSecrets = async (req: Request, res: Response) => {
content: {
"application/json": {
"schema": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of newly-updated secrets for the given project and environment"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Updated secrets"
}
}
}
}
}
}
}
*/
const channel = req.headers?.['user-agent']?.toLowerCase().includes('mozilla') ? 'web' : 'cli';
@ -544,12 +547,17 @@ export const deleteSecrets = async (req: Request, res: Response) => {
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of deleted secrets"
"schema": {
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Deleted secrets"
}
}
}
}
}

View File

@ -18,8 +18,13 @@ export const getMe = async (req: Request, res: Response) => {
"application/json": {
"schema": {
"type": "object",
$ref: "#/components/schemas/CurrentUser",
"description": "Current user on request"
"properties": {
"user": {
"type": "object",
$ref: "#/components/schemas/CurrentUser",
"description": "Current user on request"
}
}
}
}
}

View File

@ -1,7 +1,9 @@
import { Request, Response } from 'express';
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose';
import {
Workspace,
Secret,
Membership,
MembershipOrg,
Integration,
@ -242,4 +244,222 @@ export const getWorkspaceServiceTokenData = async (
return res.status(200).send({
serviceTokenData
});
}
/**
* Return memberships for workspace with id [workspaceId]
* @param req
* @param res
* @returns
*/
export const getWorkspaceMemberships = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return project memberships'
#swagger.description = 'Return project memberships'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"memberships": {
"type": "array",
"items": {
$ref: "#/components/schemas/Membership"
},
"description": "Memberships of project"
}
}
}
}
}
}
*/
let memberships;
try {
const { workspaceId } = req.params;
memberships = await Membership.find({
workspace: workspaceId
}).populate('user', '+publicKey');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get workspace members'
});
}
return res.status(200).send({
memberships
});
}
/**
* Delete workspace membership with id [membershipId]
* @param req
* @param res
* @returns
*/
export const deleteWorkspaceMembership = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Delete project membership'
#swagger.description = 'Delete project membership'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['membershipId'] = {
"description": "ID of membership",
"required": true,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
$ref: "#/components/schemas/Membership",
"description": "Deleted membership"
}
}
}
}
}
}
*/
let membership;
try {
const {
membershipId
} = req.params;
membership = await Membership.findByIdAndDelete(membershipId);
if (!membership) throw new Error('Failed to delete workspace membership');
await Key.deleteMany({
receiver: membership.user,
workspace: membership.workspace
});
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete workspace membership'
});
}
return res.status(200).send({
membership
});
}
/**
* Update role of membership with id [membershipId] to role [role]
* @param req
* @param res
* @returns
*/
export const updateWorkspaceMembership = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Update project membership'
#swagger.description = 'Update project membership'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['membershipId'] = {
"description": "ID of membership",
"required": true,
"type": "string"
}
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"role": {
"type": "string",
"description": "Role of membership - either admin or member",
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
"schema": {
"type": "object",
"properties": {
"membership": {
$ref: "#/components/schemas/Membership",
"description": "Updated membership"
}
}
}
}
}
}
*/
let membership;
try {
const {
membershipId
} = req.params;
const { role } = req.body;
membership = await Membership.findByIdAndUpdate(
membershipId,
{
role
}, {
new: true
}
);
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to update workspace membership'
});
}
return res.status(200).send({
membership
});
}

View File

@ -10,6 +10,51 @@ import { EESecretService } from '../../services';
* @param res
*/
export const getSecretVersions = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return secret versions'
#swagger.description = 'Return secret versions'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['secretId'] = {
"description": "ID of secret",
"required": true,
"type": "string"
}
#swagger.parameters['offset'] = {
"description": "Number of versions to skip",
"required": false,
"type": "string"
}
#swagger.parameters['limit'] = {
"description": "Maximum number of versions to return",
"required": false,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"secretVersions": {
"type": "array",
"items": {
$ref: "#/components/schemas/SecretVersion"
},
"description": "Secret versions"
}
}
}
}
}
}
*/
let secretVersions;
try {
const { secretId } = req.params;
@ -44,6 +89,54 @@ import { EESecretService } from '../../services';
* @returns
*/
export const rollbackSecretVersion = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Roll back secret to a version.'
#swagger.description = 'Roll back secret to a version.'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['secretId'] = {
"description": "ID of secret",
"required": true,
"type": "string"
}
#swagger.requestBody = {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"version": {
"type": "integer",
"description": "Version of secret to roll back to"
}
}
}
}
}
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"secret": {
"type": "object",
$ref: "#/components/schemas/Secret",
"description": "Secret rolled back to"
}
}
}
}
}
}
*/
let secret;
try {
const { secretId } = req.params;

View File

@ -19,6 +19,51 @@ import { getLatestSecretVersionIds } from '../../helpers/secretVersion';
* @param res
*/
export const getWorkspaceSecretSnapshots = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return project secret snapshot ids'
#swagger.description = 'Return project secret snapshots ids'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['offset'] = {
"description": "Number of secret snapshots to skip",
"required": false,
"type": "string"
}
#swagger.parameters['limit'] = {
"description": "Maximum number of secret snapshots to return",
"required": false,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"secretSnapshots": {
"type": "array",
"items": {
$ref: "#/components/schemas/SecretSnapshot"
},
"description": "Project secret snapshots"
}
}
}
}
}
}
*/
let secretSnapshots;
try {
const { workspaceId } = req.params;
@ -79,8 +124,8 @@ export const getWorkspaceSecretSnapshotsCount = async (req: Request, res: Respon
*/
export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Roll back project secrets to those captured in a secret snapshot version'
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version'
#swagger.summary = 'Roll back project secrets to those captured in a secret snapshot version.'
#swagger.description = 'Roll back project secrets to those captured in a secret snapshot version.'
#swagger.security = [{
"apiKeyAuth": []
@ -113,11 +158,16 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
content: {
"application/json": {
schema: {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Array of secrets captured in the secret snapshot"
"type": "object",
"properties": {
"secrets": {
"type": "array",
"items": {
$ref: "#/components/schemas/Secret"
},
"description": "Secrets rolled back to"
}
}
}
}
}
@ -276,6 +326,72 @@ export const rollbackWorkspaceSecretSnapshot = async (req: Request, res: Respons
* @returns
*/
export const getWorkspaceLogs = async (req: Request, res: Response) => {
/*
#swagger.summary = 'Return project (audit) logs'
#swagger.description = 'Return project (audit) logs'
#swagger.security = [{
"apiKeyAuth": []
}]
#swagger.parameters['workspaceId'] = {
"description": "ID of project",
"required": true,
"type": "string"
}
#swagger.parameters['userId'] = {
"description": "ID of project member",
"required": false,
"type": "string"
}
#swagger.parameters['offset'] = {
"description": "Number of logs to skip",
"required": false,
"type": "string"
}
#swagger.parameters['limit'] = {
"description": "Maximum number of logs to return",
"required": false,
"type": "string"
}
#swagger.parameters['sortBy'] = {
"description": "Order to sort the logs by",
"schema": {
"type": "string",
"@enum": ["oldest", "recent"]
},
"required": false
}
#swagger.parameters['actionNames'] = {
"description": "Names of log actions (comma-separated)",
"required": false,
"type": "string"
}
#swagger.responses[200] = {
content: {
"application/json": {
schema: {
"type": "object",
"properties": {
"logs": {
"type": "array",
"items": {
$ref: "#/components/schemas/Log"
},
"description": "Project logs"
}
}
}
}
}
}
*/
let logs
try {
const { workspaceId } = req.params;

View File

@ -2,6 +2,7 @@ import requireAuth from './requireAuth';
import requireBotAuth from './requireBotAuth';
import requireSignupAuth from './requireSignupAuth';
import requireWorkspaceAuth from './requireWorkspaceAuth';
import requireMembershipAuth from './requireMembershipAuth';
import requireOrganizationAuth from './requireOrganizationAuth';
import requireIntegrationAuth from './requireIntegrationAuth';
import requireIntegrationAuthorizationAuth from './requireIntegrationAuthorizationAuth';
@ -16,6 +17,7 @@ export {
requireBotAuth,
requireSignupAuth,
requireWorkspaceAuth,
requireMembershipAuth,
requireOrganizationAuth,
requireIntegrationAuth,
requireIntegrationAuthorizationAuth,

View File

@ -0,0 +1,57 @@
import { Request, Response, NextFunction } from 'express';
import { UnauthorizedRequestError } from '../utils/errors';
import {
Membership,
} from '../models';
import { validateMembership } from '../helpers/membership';
type req = 'params' | 'body' | 'query';
/**
* Validate membership with id [membershipId] and that user with id
* [req.user._id] can modify that membership.
* @param {Object} obj
* @param {String[]} obj.acceptedRoles - accepted workspace roles for JWT auth
* @param {String[]} obj.location - location of [workspaceId] on request (e.g. params, body) for parsing
*/
const requireMembershipAuth = ({
acceptedRoles,
location = 'params'
}: {
acceptedRoles: string[];
location?: req;
}) => {
return async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const { membershipId } = req[location];
const membership = await Membership.findById(membershipId);
if (!membership) throw new Error('Failed to find target membership');
const userMembership = await Membership.findOne({
workspace: membership.workspace
});
if (!userMembership) throw new Error('Failed to validate own membership')
const targetMembership = await validateMembership({
userId: req.user._id.toString(),
workspaceId: membership.workspace.toString(),
acceptedRoles
});
req.targetMembership = targetMembership;
} catch (err) {
return next(UnauthorizedRequestError({
message: 'Unable to validate workspace membership'
}));
}
}
}
export default requireMembershipAuth;

View File

@ -4,7 +4,7 @@ import { body, param } from 'express-validator';
import { requireAuth, validateRequest } from '../../middleware';
import { membershipController } from '../../controllers/v1';
router.get( // used for CLI (deprecate)
router.get( // used for old CLI (deprecate)
'/:workspaceId/connect',
requireAuth({
acceptedAuthModes: ['jwt']

View File

@ -3,6 +3,7 @@ const router = express.Router();
import { body, param, query } from 'express-validator';
import {
requireAuth,
requireMembershipAuth,
requireWorkspaceAuth,
validateRequest
} from '../../middleware';
@ -67,4 +68,54 @@ router.get(
workspaceController.getWorkspaceServiceTokenData
);
// TODO: /POST to create membership
router.get( // new - TODO: rewire dashboard to this route
'/:workspaceId/memberships',
param('workspaceId').exists().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
}),
workspaceController.getWorkspaceMemberships
);
router.delete( // TODO - rewire dashboard to this route
'/:workspaceId/memberships/:membershipId',
param('workspaceId').exists().trim(),
param('membershipId').exists().trim(),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
}),
requireMembershipAuth({
acceptedRoles: [ADMIN]
}),
workspaceController.deleteWorkspaceMembership
);
router.patch( // TODO - rewire dashboard to this route
'/:workspaceId/memberships/:membershipId',
param('workspaceId').exists().trim(),
param('membershipId').exists().trim(),
body('role').exists().isString().trim().isIn([ADMIN, MEMBER]),
validateRequest,
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN],
}),
requireMembershipAuth({
acceptedRoles: [ADMIN]
}),
workspaceController.updateWorkspaceMembership
);
export default router;

View File

@ -8,6 +8,7 @@ declare global {
user: any;
workspace: any;
membership: any;
targetMembership: any;
organization: any;
membershipOrg: any;
integration: any;

View File

@ -53,6 +53,19 @@ const generateOpenAPISpec = async () => {
updatedAt: '',
createdAt: ''
},
Membership: {
user: {
_id: '',
email: '',
firstName: '',
lastName: '',
publicKey: '',
updatedAt: '',
createdAt: ''
},
workspace: '',
role: 'admin'
},
ProjectKey: {
encryptedkey: '',
nonce: '',
@ -103,6 +116,61 @@ const generateOpenAPISpec = async () => {
secretCommentTag: '',
updatedAt: '',
createdAt: ''
},
Log: {
_id: '',
user: {
_id: '',
email: '',
firstName: '',
lastName: ''
},
workspace: '',
actionNames: [
'addSecrets'
],
actions: [
{
name: 'addSecrets',
user: '',
workspace: '',
payload: [
{
oldSecretVersion: '',
newSecretVersion: ''
}
]
}
],
channel: 'cli',
ipAddress: '192.168.0.1',
updatedAt: '',
createdAt: ''
},
SecretSnapshot: {
workspace: '',
version: 1,
secretVersions: [
{
_id: ''
}
]
},
SecretVersion: {
_id: '',
secret: '',
version: 1,
workspace: '',
type: '',
user: '',
environment: '',
isDeleted: '',
secretKeyCiphertext: '',
secretKeyIV: '',
secretKeyTag: '',
secretValueCiphertext: '',
secretValueIV: '',
secretValueTag: '',
}
}
};

View File

@ -0,0 +1,4 @@
---
title: "Roll Back to Version"
openapi: "POST /api/v1/secret/{secretId}/secret-versions/rollback"
---

View File

@ -0,0 +1,4 @@
---
title: "Get Versions"
openapi: "GET /api/v1/secret/{secretId}/secret-versions"
---

View File

@ -0,0 +1,4 @@
---
title: "Delete Membership"
openapi: "DELETE /api/v2/workspace/{workspaceId}/memberships/{membershipId}"
---

View File

@ -0,0 +1,4 @@
---
title: "Get Logs"
openapi: "GET /api/v1/workspace/{workspaceId}/logs"
---

View File

@ -0,0 +1,4 @@
---
title: "Get Memberships"
openapi: "GET /api/v2/workspace/{workspaceId}/memberships"
---

View File

@ -0,0 +1,4 @@
---
title: "Roll Back to Snapshot"
openapi: "POST /api/v1/workspace/{workspaceId}/secret-snapshots/rollback"
---

View File

@ -0,0 +1,4 @@
---
title: "Get Snapshots"
openapi: "GET /api/v1/workspace/{workspaceId}/secret-snapshots"
---

View File

@ -0,0 +1,4 @@
---
title: "Update Membership"
openapi: "PATCH /api/v2/workspace/{workspaceId}/memberships/{membershipId}"
---

View File

@ -1,4 +1,4 @@
---
title: "Get Project Key"
title: "Get Key"
openapi: "GET /api/v2/workspace/{workspaceId}/encrypted-key"
---

View File

@ -13,52 +13,140 @@ Prerequisites:
1. Get your (encrypted) private key.
2. Decrypt your (encrypted) private key with your password.
3. Get the project key for the project.
4. Decrypt the project key with your private key.
5. Encrypt your secrets with the project key.
6. Send (encrypted) secrets to the Infical API
3. Get the (encrypted) project key for the project.
4. Decrypt the (encrypted) project key with your private key.
5. Encrypt your secret(s) with the project key.
6. Send (encrypted) secret(s) to the Infical API
## Example
```js
const axios = require("axios");
const aes = require("aes-256-gcm");
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
const crypto = require('crypto');
const axios = require('axios');
const WORKSPACE_KEY = "3a7a243eb62078c13f09203e75e8cb32";
const ALGORITHM = 'aes-256-gcm';
const BLOCK_SIZE_BYTES = 16;
const secretKey = "SOME_KEY";
const secretValue = "SOME_VALUE";
const encrypt = (
text,
secret
) => {
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
// encrypt key of secret
const {
ciphertext: secretKeyCiphertext,
iv: secretKeyIV,
tag: secretKeyTag,
} = aes.encrypt(secretKey, WORKSPACE_KEY);
let ciphertext = cipher.update(text, 'utf8', 'base64');
ciphertext += cipher.final('base64');
return {
ciphertext,
iv: iv.toString('base64'),
tag: cipher.getAuthTag().toString('base64')
};
}
// encrypt value of secret
const {
ciphertext: secretValueCiphertext,
iv: secretValueIV,
tag: secretValueTag,
} = aes.encrypt(secretKey, WORKSPACE_KEY);
const decrypt = (ciphertext, iv, tag, secret) => {
const decipher = crypto.createDecipheriv(
ALGORITHM,
secret,
Buffer.from(iv, 'base64')
);
decipher.setAuthTag(Buffer.from(tag, 'base64'));
// construct request body
const secret = {
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag,
};
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
cleartext += decipher.final('utf8');
return cleartext;
}
const createSecrets = async () => {
const API_KEY = 'your_api_key';
const PSWD = 'your_pswd';
const WORKSPACE_ID = 'your_workspace_id';
const SECRET_KEY = 'SOME_KEY';
const SECRET_VALUE = 'SOME_VALUE';
// 1. get (encrypted) private key
const user = await axios.get(
'https://api.infisical.com/api/v2/users/me', {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 2. decrypt your (encrypted) private key with your password
const privateKey = decrypt({
ciphertext: user.encryptedPrivateKey,
iv: user.iv,
tag: user.tag,
secret: PSWD.slice(0, 32).padStart(32, '0');
});
// 3. get the (encrypted) project key for the project
const encryptedProjectKey = await axios.get(
`https://api.infisical.com/api/v2/workspace/${WORKSPACE_ID}`, {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 4. decrypt the project key with your private key
const projectKey = nacl.box.open(
util.decodeBase64(encryptedProjectKey),
util.decodeBase64(projectKey.nonce),
util.decodeBase64(projectKey.sender.publicKey),
util.decodeBase64(privateKey)
);
// 5. encrypt your secret(s) with the project key
const {
ciphertext: secretKeyCiphertext,
iv: secretKeyIV,
tag: secretKeyTag
} = encrypt(SECRET_KEY, projectKey);
const {
ciphertext: secretValueCiphertext,
iv: secretValueIV,
tag: secretValueTag
} = encrypt(SECRET_VALUE, projectKey);
const secret = {
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
}
// 6. Send (encrypted) secret(s) to the Infisical API
await axios.post(
`https://api.infisical.com/api/v2/secrets`,
{
workspaceId: WORKSPACE_ID,
environment: 'dev',
secrets: secret
},
{
headers: {
'X-API-KEY': API_KEY
}
}
);
}
createSecrets();
```
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl in every major language.
are ports of NaCl available in every major language.
</Info>
<Tip>
It can be useful to perform steps 1-4 ahead of time and store away your
private key (and even project key) for later use. The Infisical CLI works by
securely storing your private key via your OS keyring.
</Tip>

View File

@ -0,0 +1,34 @@
---
title: "Delete secrets"
---
In this example, we demonstrate how to delete secrets
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
## Example
```js
const deleteSecrets = async () => {
const API_KEY = "your_api_key";
const SECRET_ID = "ID"; // ID of secret to delete
// 6. Send ID(s) of secret(s) to delete to the Infisical API
await axios.delete(
`https://api.infisical.com/api/v2/secrets`,
{
secretIds: SECRET_ID,
},
{
headers: {
"X-API-KEY": API_KEY,
},
}
);
};
deleteSecrets();
```

View File

@ -2,9 +2,141 @@
title: "Retrieve secrets"
---
In this example, we demonstrate how to retrieve secrets from a project and environment.
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
## Flow
1. Get your (encrypted) private key.
2. Decrypt your (encrypted) private key with your password.
3. Get the project key for the project.
4. Decrypt the project key with your private key.
3. Get the (encrypted) project key for the project.
4. Decrypt the (encrypted) project key with your private key.
5. Get secrets for a project and environment.
6. Decrypt the secrets in your project.
6. Decrypt the (encrypted) secrets
## Example
```js
const crypto = require('crypto');
const axios = require('axios');
const ALGORITHM = 'aes-256-gcm';
const BLOCK_SIZE_BYTES = 16;
const encrypt = (
text,
secret
) => {
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
let ciphertext = cipher.update(text, 'utf8', 'base64');
ciphertext += cipher.final('base64');
return {
ciphertext,
iv: iv.toString('base64'),
tag: cipher.getAuthTag().toString('base64')
};
}
const decrypt = (ciphertext, iv, tag, secret) => {
const decipher = crypto.createDecipheriv(
ALGORITHM,
secret,
Buffer.from(iv, 'base64')
);
decipher.setAuthTag(Buffer.from(tag, 'base64'));
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
cleartext += decipher.final('utf8');
return cleartext;
}
const retrieveSecrets = async () => {
const API_KEY = 'your_api_key';
const PSWD = 'your_pswd';
const WORKSPACE_ID = 'your_workspace_id';
// 1. get (encrypted) private key
const user = await axios.get(
'https://api.infisical.com/api/v2/users/me', {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 2. decrypt your (encrypted) private key with your password
const privateKey = decrypt({
ciphertext: user.encryptedPrivateKey,
iv: user.iv,
tag: user.tag,
secret: PSWD.slice(0, 32).padStart(32, '0');
});
// 3. get the (encrypted) project key for the project
const encryptedProjectKey = await axios.get(
`https://api.infisical.com/api/v2/workspace/${WORKSPACE_ID}`, {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 4. decrypt the project key with your private key
const projectKey = nacl.box.open(
util.decodeBase64(encryptedProjectKey),
util.decodeBase64(projectKey.nonce),
util.decodeBase64(projectKey.sender.publicKey),
util.decodeBase64(privateKey)
);
// 5. get (encrypted) secrets for a project and environment.
const encryptedSecrets = await axios.get(
'https://api.infisical.com/api/v2/secrets', {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 6. decrypt the (encrypted) secrets
const secrets = encryptedSecrets.map((encryptedSecret) => {
const secretKey = decrypt({
ciphertext: encryptedSecret.secretKeyCiphertext,
iv: encryptedSecret.secretKeyIV,
tag: encryptedSecret.secretKeyTag
secret: projectKey
});
const secretValue = decrypt({
ciphertext: encryptedSecret.secretValueCiphertext,
iv: encryptedSecret.secretValueIV,
tag: encryptedSecret.secretValueTag
secret: projectKey
});
return ({
secretKey,
secretValue
});
});
}
retrieveSecrets();
```
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl available in every major language.
</Info>
<Tip>
It can be useful to perform steps 1-4 ahead of time and store away your
private key (and even project key) for later use. The Infisical CLI works by
securely storing your private key via your OS keyring.
</Tip>

View File

@ -2,9 +2,151 @@
title: "Update secrets"
---
In this example, we demonstrate how to update secrets
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
- Grasp a basic understanding of the system and its underlying cryptography [here](/api-reference/overview/introduction).
## Flow
1. Get your (encrypted) private key.
2. Decrypt your (encrypted) private key with your password.
3. Get the project key for the project.
4. Decrypt the project key with your private key.
5. Encrypt your secrets with the project key.
6. Send (encrypted) updated secrets to the Infical API
5. Encrypt your secret(s) with the project key.
6. Send (encrypted) updated secret(s) to the Infical API
## Example
```js
const crypto = require('crypto');
const axios = require('axios');
const ALGORITHM = 'aes-256-gcm';
const BLOCK_SIZE_BYTES = 16;
const encrypt = (
text,
secret
) => {
const iv = crypto.randomBytes(BLOCK_SIZE_BYTES);
const cipher = crypto.createCipheriv(ALGORITHM, secret, iv);
let ciphertext = cipher.update(text, 'utf8', 'base64');
ciphertext += cipher.final('base64');
return {
ciphertext,
iv: iv.toString('base64'),
tag: cipher.getAuthTag().toString('base64')
};
}
const decrypt = (ciphertext, iv, tag, secret) => {
const decipher = crypto.createDecipheriv(
ALGORITHM,
secret,
Buffer.from(iv, 'base64')
);
decipher.setAuthTag(Buffer.from(tag, 'base64'));
let cleartext = decipher.update(ciphertext, 'base64', 'utf8');
cleartext += decipher.final('utf8');
return cleartext;
}
const updateSecrets = async () => {
const API_KEY = 'your_api_key';
const PSWD = 'your_pswd';
const WORKSPACE_ID = 'your_workspace_id';
const SECRET_ID = 'ID' // ID of secret to update
const SECRET_KEY = 'SOME_KEY';
const SECRET_VALUE = 'SOME_VALUE';
// 1. get (encrypted) private key
const user = await axios.get(
'https://api.infisical.com/api/v2/users/me', {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 2. decrypt your (encrypted) private key with your password
const privateKey = decrypt({
ciphertext: user.encryptedPrivateKey,
iv: user.iv,
tag: user.tag,
secret: PSWD.slice(0, 32).padStart(32, '0');
});
// 3. get the (encrypted) project key for the project
const encryptedProjectKey = await axios.get(
`https://api.infisical.com/api/v2/workspace/${WORKSPACE_ID}`, {
headers: {
'X-API-KEY': API_KEY
}
}
);
// 4. decrypt the project key with your private key
const projectKey = nacl.box.open(
util.decodeBase64(encryptedProjectKey),
util.decodeBase64(projectKey.nonce),
util.decodeBase64(projectKey.sender.publicKey),
util.decodeBase64(privateKey)
);
// 5. encrypt your secret(s) with the project key
const {
ciphertext: secretKeyCiphertext,
iv: secretKeyIV,
tag: secretKeyTag
} = encrypt(SECRET_KEY, projectKey);
const {
ciphertext: secretValueCiphertext,
iv: secretValueIV,
tag: secretValueTag
} = encrypt(SECRET_VALUE, projectKey);
const secret = {
id: SECRET_ID,
secretKeyCiphertext,
secretKeyIV,
secretKeyTag,
secretValueCiphertext,
secretValueIV,
secretValueTag
}
// 6. Send (encrypted) secret(s) to the Infisical API
await axios.patch(
`https://api.infisical.com/api/v2/secrets`,
{
secrets: secret
},
{
headers: {
'X-API-KEY': API_KEY
}
}
);
}
updateSecrets();
```
<Info>
This example uses [TweetNaCl.js](https://tweetnacl.js.org/#/), a port of
TweetNacl/Nacl, to perform asymmeric decryption of the project key but there
are ports of NaCl available in every major language.
</Info>
<Tip>
It can be useful to perform steps 1-4 ahead of time and store away your
private key (and even project key) for later use. The Infisical CLI works by
securely storing your private key via your OS keyring.
</Tip>

View File

@ -2,8 +2,13 @@
title: "Introduction"
---
<Warning>
Infisical's REST API is currently unavailable and scheduled to go live on Jan
16!
</Warning>
Infisical's REST API provides users an alternative way to programmatically access and manage
secrets via HTTP requests. This can be useful for automating tasks, such as
secrets via HTTPS requests. This can be useful for automating tasks, such as
rotating credentials, or for integrating secret management into a larger system.
With the REST API, users can create, read, update, and delete secrets, as well as manage access control, query audit logs, and more.
@ -17,3 +22,10 @@ Using Infisical's API to manage secrets requires a basic understanding of the sy
- Each project has an (encrypted) project key used to encrypt the secrets within that project; Infisical stores copies of the project key, for each member of that project, encrypted under each member's public key.
- Secrets are encrypted symmetrically by your copy of the project key belonging to the project containing.
- Infisical uses AES256-GCM and [TweetNaCl.js](https://tweetnacl.js.org/#/) for symmetric and asymmetric encryption/decryption operations.
<Info>
Infisical's system ensures greater security such that secrets are
encrypted/decrypted on the client-side but requires users to properly
implement cryptographic operations to maintain end-to-end encryption (E2EE).
We're
</Info>

View File

@ -150,7 +150,8 @@
"pages": [
"api-reference/overview/examples/create-secrets",
"api-reference/overview/examples/retrieve-secrets",
"api-reference/overview/examples/update-secrets"
"api-reference/overview/examples/update-secrets",
"api-reference/overview/examples/delete-secrets"
]
}
]
@ -167,7 +168,13 @@
{
"group": "Projects",
"pages": [
"api-reference/endpoints/workspaces/workspace-key"
"api-reference/endpoints/workspaces/memberships",
"api-reference/endpoints/workspaces/update-membership",
"api-reference/endpoints/workspaces/delete-membership",
"api-reference/endpoints/workspaces/workspace-key",
"api-reference/endpoints/workspaces/logs",
"api-reference/endpoints/workspaces/secret-snapshots",
"api-reference/endpoints/workspaces/rollback-snapshot"
]
},
{
@ -176,7 +183,9 @@
"api-reference/endpoints/secrets/create",
"api-reference/endpoints/secrets/read",
"api-reference/endpoints/secrets/update",
"api-reference/endpoints/secrets/delete"
"api-reference/endpoints/secrets/delete",
"api-reference/endpoints/secrets/versions",
"api-reference/endpoints/secrets/rollback-version"
]
}
]

View File

@ -11,48 +11,81 @@ servers:
paths:
/api/v1/secret/{secretId}/secret-versions:
get:
description: ''
summary: Return secret versions
description: Return secret versions
parameters:
- name: secretId
in: path
required: true
schema:
type: string
description: ID of secret
- name: offset
description: Number of versions to skip
required: false
in: query
schema:
type: string
- name: limit
description: Maximum number of versions to return
required: false
in: query
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
secretVersions:
type: array
items:
$ref: '#/components/schemas/SecretVersion'
description: Secret versions
'400':
description: Bad Request
security:
- apiKeyAuth: []
/api/v1/secret/{secretId}/secret-versions/rollback:
post:
description: ''
summary: Roll back secret to a version.
description: Roll back secret to a version.
parameters:
- name: secretId
in: path
required: true
schema:
type: string
description: ID of secret
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
secret:
type: object
$ref: '#/components/schemas/Secret'
description: Secret rolled back to
'400':
description: Bad Request
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
version:
example: any
type: integer
description: Version of secret to roll back to
/api/v1/secret-snapshot/{secretSnapshotId}:
get:
description: ''
@ -69,26 +102,44 @@ paths:
description: Bad Request
/api/v1/workspace/{workspaceId}/secret-snapshots:
get:
description: ''
summary: Return project secret snapshot ids
description: Return project secret snapshots ids
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
- name: offset
description: Number of secret snapshots to skip
required: false
in: query
schema:
type: string
- name: limit
description: Maximum number of secret snapshots to return
required: false
in: query
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
secretSnapshots:
type: array
items:
$ref: '#/components/schemas/SecretSnapshot'
description: Project secret snapshots
'400':
description: Bad Request
security:
- apiKeyAuth: []
/api/v1/workspace/{workspaceId}/secret-snapshots/count:
get:
description: ''
@ -105,60 +156,107 @@ paths:
description: Bad Request
/api/v1/workspace/{workspaceId}/secret-snapshots/rollback:
post:
description: ''
summary: >-
Roll back project secrets to those captured in a secret snapshot
version.
description: >-
Roll back project secrets to those captured in a secret snapshot
version.
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
secrets:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Secrets rolled back to
'400':
description: Bad Request
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
version:
example: any
type: integer
description: Version of secret snapshot to roll back to
/api/v1/workspace/{workspaceId}/logs:
get:
description: ''
summary: Return project (audit) logs
description: Return project (audit) logs
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
- name: userId
description: ID of project member
required: false
in: query
schema:
type: string
- name: offset
description: Number of logs to skip
required: false
in: query
schema:
type: string
- name: limit
description: Maximum number of logs to return
required: false
in: query
schema:
type: string
- name: sortBy
in: query
description: Order to sort the logs by
schema:
type: string
- name: userId
enum:
- oldest
- recent
required: false
in: query
schema:
type: string
- name: actionNames
description: Names of log actions (comma-separated)
required: false
in: query
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
logs:
type: array
items:
$ref: '#/components/schemas/Log'
description: Project logs
'400':
description: Bad Request
security:
- apiKeyAuth: []
/api/v1/action/{actionId}:
get:
description: ''
@ -1285,8 +1383,11 @@ paths:
application/json:
schema:
type: object
$ref: '#/components/schemas/CurrentUser'
description: Current user on request
properties:
user:
type: object
$ref: '#/components/schemas/CurrentUser'
description: Current user on request
'400':
description: Bad Request
security:
@ -1379,6 +1480,107 @@ paths:
description: OK
'400':
description: Bad Request
/api/v2/workspace/{workspaceId}/memberships:
get:
summary: Return project memberships
description: Return project memberships
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
memberships:
type: array
items:
$ref: '#/components/schemas/Membership'
description: Memberships of project
'400':
description: Bad Request
security:
- apiKeyAuth: []
/api/v2/workspace/{workspaceId}/memberships/{membershipId}:
delete:
summary: Delete project membership
description: Delete project membership
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
- name: membershipId
in: path
required: true
schema:
type: string
description: ID of membership
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
membership:
$ref: '#/components/schemas/Membership'
description: Deleted membership
'400':
description: Bad Request
security:
- apiKeyAuth: []
patch:
summary: Update project membership
description: Update project membership
parameters:
- name: workspaceId
in: path
required: true
schema:
type: string
description: ID of project
- name: membershipId
in: path
required: true
schema:
type: string
description: ID of membership
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
membership:
$ref: '#/components/schemas/Membership'
description: Updated membership
'400':
description: Bad Request
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
role:
type: string
description: Role of membership - either admin or member
/api/v2/secret/batch-create/workspace/{workspaceId}/environment/{environment}:
post:
description: ''
@ -1554,12 +1756,15 @@ paths:
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: >-
Array of newly-created secrets for the given project and
environment
type: object
properties:
secrets:
type: array
items:
$ref: '#/components/schemas/Secret'
description: >-
Newly-created secrets for the given project and
environment
security:
- apiKeyAuth: []
requestBody:
@ -1581,32 +1786,38 @@ paths:
get:
summary: Read secrets
description: Read secrets from a project and environment
parameters: []
parameters:
- name: workspaceId
description: ID of project
required: true
in: query
schema:
type: string
- name: environment
description: Environment within project
required: true
in: query
schema:
type: string
- name: content
in: query
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Array of secrets for the given project and environment
type: object
properties:
secrets:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Secrets for the given project and environment
security:
- apiKeyAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
workspaceId:
type: string
description: ID of project
environment:
type: string
description: Environment within project
patch:
summary: Update secret(s)
description: Update secret(s)
@ -1617,12 +1828,13 @@ paths:
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: >-
Array of newly-updated secrets for the given project and
environment
type: object
properties:
secrets:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Updated secrets
security:
- apiKeyAuth: []
requestBody:
@ -1645,10 +1857,13 @@ paths:
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Array of deleted secrets
type: object
properties:
secrets:
type: array
items:
$ref: '#/components/schemas/Secret'
description: Deleted secrets
security:
- apiKeyAuth: []
requestBody:
@ -1783,12 +1998,51 @@ components:
encryptedPrivateKey:
type: string
example: ''
iv:
type: string
example: ''
tag:
type: string
example: ''
updatedAt:
type: string
example: ''
createdAt:
type: string
example: ''
Membership:
type: object
properties:
user:
type: object
properties:
_id:
type: string
example: ''
email:
type: string
example: ''
firstName:
type: string
example: ''
lastName:
type: string
example: ''
publicKey:
type: string
example: ''
updatedAt:
type: string
example: ''
createdAt:
type: string
example: ''
workspace:
type: string
example: ''
role:
type: string
example: admin
ProjectKey:
type: object
properties:
@ -1925,6 +2179,135 @@ components:
createdAt:
type: string
example: ''
Log:
type: object
properties:
_id:
type: string
example: ''
user:
type: object
properties:
_id:
type: string
example: ''
email:
type: string
example: ''
firstName:
type: string
example: ''
lastName:
type: string
example: ''
workspace:
type: string
example: ''
actionNames:
type: array
example:
- addSecrets
items:
type: string
actions:
type: array
items:
type: object
properties:
name:
type: string
example: addSecrets
user:
type: string
example: ''
workspace:
type: string
example: ''
payload:
type: array
items:
type: object
properties:
oldSecretVersion:
type: string
example: ''
newSecretVersion:
type: string
example: ''
channel:
type: string
example: cli
ipAddress:
type: string
example: 192.168.0.1
updatedAt:
type: string
example: ''
createdAt:
type: string
example: ''
SecretSnapshot:
type: object
properties:
workspace:
type: string
example: ''
version:
type: number
example: 1
secretVersions:
type: array
items:
type: object
properties:
_id:
type: string
example: ''
SecretVersion:
type: object
properties:
_id:
type: string
example: ''
secret:
type: string
example: ''
version:
type: number
example: 1
workspace:
type: string
example: ''
type:
type: string
example: ''
user:
type: string
example: ''
environment:
type: string
example: ''
isDeleted:
type: string
example: ''
secretKeyCiphertext:
type: string
example: ''
secretKeyIV:
type: string
example: ''
secretKeyTag:
type: string
example: ''
secretValueCiphertext:
type: string
example: ''
secretValueIV:
type: string
example: ''
secretValueTag:
type: string
example: ''
securitySchemes:
bearerAuth:
type: http