mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 02:26:40 +00:00
Merge remote-tracking branch 'origin' into groups-phase-3
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
name: Build patroni
|
||||||
|
on: [workflow_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
patroni-image:
|
||||||
|
name: Build patroni
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: ☁️ Checkout source
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
repository: 'zalando/patroni'
|
||||||
|
- name: Save commit hashes for tag
|
||||||
|
id: commit
|
||||||
|
uses: pr-mpt/actions-commit-hash@v2
|
||||||
|
- name: 🔧 Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
- name: 🐋 Login to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Set up Depot CLI
|
||||||
|
uses: depot/setup-action@v1
|
||||||
|
- name: 🏗️ Build backend and push to docker hub
|
||||||
|
uses: depot/build-push-action@v1
|
||||||
|
with:
|
||||||
|
project: 64mmf0n610
|
||||||
|
token: ${{ secrets.DEPOT_PROJECT_TOKEN }}
|
||||||
|
push: true
|
||||||
|
context: .
|
||||||
|
file: Dockerfile
|
||||||
|
tags: |
|
||||||
|
infisical/patroni:${{ steps.commit.outputs.short }}
|
||||||
|
infisical/patroni:latest
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
name: Build and release CLI
|
name: Build and release CLI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
push:
|
push:
|
||||||
# run only against tags
|
# run only against tags
|
||||||
tags:
|
tags:
|
||||||
@@ -14,6 +16,12 @@ jobs:
|
|||||||
cli-integration-tests:
|
cli-integration-tests:
|
||||||
name: Run tests before deployment
|
name: Run tests before deployment
|
||||||
uses: ./.github/workflows/run-cli-tests.yml
|
uses: ./.github/workflows/run-cli-tests.yml
|
||||||
|
secrets:
|
||||||
|
CLI_TESTS_UA_CLIENT_ID: ${{ secrets.CLI_TESTS_UA_CLIENT_ID }}
|
||||||
|
CLI_TESTS_UA_CLIENT_SECRET: ${{ secrets.CLI_TESTS_UA_CLIENT_SECRET }}
|
||||||
|
CLI_TESTS_SERVICE_TOKEN: ${{ secrets.CLI_TESTS_SERVICE_TOKEN }}
|
||||||
|
CLI_TESTS_PROJECT_ID: ${{ secrets.CLI_TESTS_PROJECT_ID }}
|
||||||
|
CLI_TESTS_ENV_SLUG: ${{ secrets.CLI_TESTS_ENV_SLUG }}
|
||||||
|
|
||||||
goreleaser:
|
goreleaser:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|||||||
@@ -6,7 +6,20 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "cli/**"
|
- "cli/**"
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
workflow_call:
|
workflow_call:
|
||||||
|
secrets:
|
||||||
|
CLI_TESTS_UA_CLIENT_ID:
|
||||||
|
required: true
|
||||||
|
CLI_TESTS_UA_CLIENT_SECRET:
|
||||||
|
required: true
|
||||||
|
CLI_TESTS_SERVICE_TOKEN:
|
||||||
|
required: true
|
||||||
|
CLI_TESTS_PROJECT_ID:
|
||||||
|
required: true
|
||||||
|
CLI_TESTS_ENV_SLUG:
|
||||||
|
required: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
|||||||
@@ -942,6 +942,113 @@ describe.each([{ auth: AuthMode.JWT }, { auth: AuthMode.IDENTITY_ACCESS_TOKEN }]
|
|||||||
const secrets = await getSecrets(seedData1.environment.slug, path);
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
expect(secrets).toEqual([]);
|
expect(secrets).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.each(testRawSecrets)("Bulk create secret raw in path $path", async ({ path, secret }) => {
|
||||||
|
const createSecretReqBody = {
|
||||||
|
projectSlug: seedData1.project.slug,
|
||||||
|
environment: seedData1.environment.slug,
|
||||||
|
secretPath: path,
|
||||||
|
secrets: [
|
||||||
|
{
|
||||||
|
secretKey: secret.key,
|
||||||
|
secretValue: secret.value,
|
||||||
|
secretComment: secret.comment
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const createSecRes = await testServer.inject({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v3/secrets/batch/raw`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${authToken}`
|
||||||
|
},
|
||||||
|
body: createSecretReqBody
|
||||||
|
});
|
||||||
|
expect(createSecRes.statusCode).toBe(200);
|
||||||
|
const createdSecretPayload = JSON.parse(createSecRes.payload);
|
||||||
|
expect(createdSecretPayload).toHaveProperty("secrets");
|
||||||
|
|
||||||
|
// fetch secrets
|
||||||
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
|
expect(secrets).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: secret.key,
|
||||||
|
value: secret.value,
|
||||||
|
type: SecretType.Shared
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteRawSecret({ path, key: secret.key });
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each(testRawSecrets)("Bulk update secret raw in path $path", async ({ secret, path }) => {
|
||||||
|
await createRawSecret({ path, ...secret });
|
||||||
|
const updateSecretReqBody = {
|
||||||
|
projectSlug: seedData1.project.slug,
|
||||||
|
environment: seedData1.environment.slug,
|
||||||
|
secretPath: path,
|
||||||
|
secrets: [
|
||||||
|
{
|
||||||
|
secretValue: "new-value",
|
||||||
|
secretKey: secret.key
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const updateSecRes = await testServer.inject({
|
||||||
|
method: "PATCH",
|
||||||
|
url: `/api/v3/secrets/batch/raw`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${authToken}`
|
||||||
|
},
|
||||||
|
body: updateSecretReqBody
|
||||||
|
});
|
||||||
|
expect(updateSecRes.statusCode).toBe(200);
|
||||||
|
const updatedSecretPayload = JSON.parse(updateSecRes.payload);
|
||||||
|
expect(updatedSecretPayload).toHaveProperty("secrets");
|
||||||
|
|
||||||
|
// fetch secrets
|
||||||
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
|
expect(secrets).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
key: secret.key,
|
||||||
|
value: "new-value",
|
||||||
|
version: 2,
|
||||||
|
type: SecretType.Shared
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
await deleteRawSecret({ path, key: secret.key });
|
||||||
|
});
|
||||||
|
|
||||||
|
test.each(testRawSecrets)("Bulk delete secret raw in path $path", async ({ path, secret }) => {
|
||||||
|
await createRawSecret({ path, ...secret });
|
||||||
|
|
||||||
|
const deletedSecretReqBody = {
|
||||||
|
projectSlug: seedData1.project.slug,
|
||||||
|
environment: seedData1.environment.slug,
|
||||||
|
secretPath: path,
|
||||||
|
secrets: [{ secretKey: secret.key }]
|
||||||
|
};
|
||||||
|
const deletedSecRes = await testServer.inject({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `/api/v3/secrets/batch/raw`,
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${authToken}`
|
||||||
|
},
|
||||||
|
body: deletedSecretReqBody
|
||||||
|
});
|
||||||
|
expect(deletedSecRes.statusCode).toBe(200);
|
||||||
|
const deletedSecretPayload = JSON.parse(deletedSecRes.payload);
|
||||||
|
expect(deletedSecretPayload).toHaveProperty("secrets");
|
||||||
|
|
||||||
|
// fetch secrets
|
||||||
|
const secrets = await getSecrets(seedData1.environment.slug, path);
|
||||||
|
expect(secrets).toEqual([]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
await knex.transaction(async (tx) => {
|
await knex.transaction(async (tx) => {
|
||||||
const duplicateRows = await tx(TableName.OrgMembership)
|
const duplicateRows = await tx(TableName.OrgMembership)
|
||||||
.select("userId", "orgId") // Select the userId and orgId so we can group by them
|
.select("userId", "orgId") // Select the userId and orgId so we can group by them
|
||||||
|
.whereNotNull("userId") // Ensure that the userId is not null
|
||||||
.count("* as cnt") // Count the number of rows for each userId and orgId, so we can make sure there are more than 1 row (a duplicate)
|
.count("* as cnt") // Count the number of rows for each userId and orgId, so we can make sure there are more than 1 row (a duplicate)
|
||||||
.groupBy("userId", "orgId")
|
.groupBy("userId", "orgId")
|
||||||
.havingRaw("count(*) > ?", [1]); // Using havingRaw for direct SQL expressions
|
.havingRaw("count(*) > ?", [1]); // Using havingRaw for direct SQL expressions
|
||||||
|
|||||||
@@ -495,7 +495,11 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "GenSecretApproval"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ export const RAW_SECRETS = {
|
|||||||
},
|
},
|
||||||
CREATE: {
|
CREATE: {
|
||||||
secretName: "The name of the secret to create.",
|
secretName: "The name of the secret to create.",
|
||||||
|
projectSlug: "The slug of the project to create the secret in.",
|
||||||
environment: "The slug of the environment to create the secret in.",
|
environment: "The slug of the environment to create the secret in.",
|
||||||
secretComment: "Attach a comment to the secret.",
|
secretComment: "Attach a comment to the secret.",
|
||||||
secretPath: "The path to create the secret in.",
|
secretPath: "The path to create the secret in.",
|
||||||
@@ -301,11 +302,13 @@ export const RAW_SECRETS = {
|
|||||||
},
|
},
|
||||||
UPDATE: {
|
UPDATE: {
|
||||||
secretName: "The name of the secret to update.",
|
secretName: "The name of the secret to update.",
|
||||||
|
secretComment: "Update comment to the secret.",
|
||||||
environment: "The slug of the environment where the secret is located.",
|
environment: "The slug of the environment where the secret is located.",
|
||||||
secretPath: "The path of the secret to update",
|
secretPath: "The path of the secret to update",
|
||||||
secretValue: "The new value of the secret.",
|
secretValue: "The new value of the secret.",
|
||||||
skipMultilineEncoding: "Skip multiline encoding for the secret value.",
|
skipMultilineEncoding: "Skip multiline encoding for the secret value.",
|
||||||
type: "The type of the secret to update.",
|
type: "The type of the secret to update.",
|
||||||
|
projectSlug: "The slug of the project to update the secret in.",
|
||||||
workspaceId: "The ID of the project to update the secret in."
|
workspaceId: "The ID of the project to update the secret in."
|
||||||
},
|
},
|
||||||
DELETE: {
|
DELETE: {
|
||||||
@@ -313,6 +316,7 @@ export const RAW_SECRETS = {
|
|||||||
environment: "The slug of the environment where the secret is located.",
|
environment: "The slug of the environment where the secret is located.",
|
||||||
secretPath: "The path of the secret.",
|
secretPath: "The path of the secret.",
|
||||||
type: "The type of the secret to delete.",
|
type: "The type of the secret to delete.",
|
||||||
|
projectSlug: "The slug of the project to delete the secret in.",
|
||||||
workspaceId: "The ID of the project where the secret is located."
|
workspaceId: "The ID of the project where the secret is located."
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -1656,4 +1656,263 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
return { secrets };
|
return { secrets };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/batch/raw",
|
||||||
|
config: {
|
||||||
|
rateLimit: secretsLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Create many secrets",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
body: z.object({
|
||||||
|
projectSlug: z.string().trim().describe(RAW_SECRETS.CREATE.projectSlug),
|
||||||
|
environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment),
|
||||||
|
secretPath: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.default("/")
|
||||||
|
.transform(removeTrailingSlash)
|
||||||
|
.describe(RAW_SECRETS.CREATE.secretPath),
|
||||||
|
secrets: z
|
||||||
|
.object({
|
||||||
|
secretKey: z.string().trim().describe(RAW_SECRETS.CREATE.secretName),
|
||||||
|
secretValue: z
|
||||||
|
.string()
|
||||||
|
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim()))
|
||||||
|
.describe(RAW_SECRETS.CREATE.secretValue),
|
||||||
|
secretComment: z.string().trim().optional().default("").describe(RAW_SECRETS.CREATE.secretComment),
|
||||||
|
skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.CREATE.skipMultilineEncoding)
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
secrets: secretRawSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { environment, projectSlug, secretPath, secrets: inputSecrets } = req.body;
|
||||||
|
|
||||||
|
const secrets = await server.services.secret.createManySecretsRaw({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
secretPath,
|
||||||
|
environment,
|
||||||
|
projectSlug,
|
||||||
|
secrets: inputSecrets
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: secrets[0].workspace,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secrets: secrets.map((secret, i) => ({
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: inputSecrets[i].secretKey,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.telemetry.sendPostHogEvents({
|
||||||
|
event: PostHogEventTypes.SecretCreated,
|
||||||
|
distinctId: getTelemetryDistinctId(req),
|
||||||
|
properties: {
|
||||||
|
numberOfSecrets: secrets.length,
|
||||||
|
workspaceId: secrets[0].workspace,
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
|
...req.auditLogInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { secrets };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/batch/raw",
|
||||||
|
config: {
|
||||||
|
rateLimit: secretsLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Update many secrets",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
body: z.object({
|
||||||
|
projectSlug: z.string().trim().describe(RAW_SECRETS.UPDATE.projectSlug),
|
||||||
|
environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment),
|
||||||
|
secretPath: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.default("/")
|
||||||
|
.transform(removeTrailingSlash)
|
||||||
|
.describe(RAW_SECRETS.UPDATE.secretPath),
|
||||||
|
secrets: z
|
||||||
|
.object({
|
||||||
|
secretKey: z.string().trim().describe(RAW_SECRETS.UPDATE.secretName),
|
||||||
|
secretValue: z
|
||||||
|
.string()
|
||||||
|
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim()))
|
||||||
|
.describe(RAW_SECRETS.UPDATE.secretValue),
|
||||||
|
secretComment: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.secretComment),
|
||||||
|
skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.UPDATE.skipMultilineEncoding)
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
secrets: secretRawSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { environment, projectSlug, secretPath, secrets: inputSecrets } = req.body;
|
||||||
|
const secrets = await server.services.secret.updateManySecretsRaw({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
secretPath,
|
||||||
|
environment,
|
||||||
|
projectSlug,
|
||||||
|
secrets: inputSecrets
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: secrets[0].workspace,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secrets: secrets.map((secret, i) => ({
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: inputSecrets[i].secretKey,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.telemetry.sendPostHogEvents({
|
||||||
|
event: PostHogEventTypes.SecretUpdated,
|
||||||
|
distinctId: getTelemetryDistinctId(req),
|
||||||
|
properties: {
|
||||||
|
numberOfSecrets: secrets.length,
|
||||||
|
workspaceId: secrets[0].workspace,
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
|
...req.auditLogInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { secrets };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/batch/raw",
|
||||||
|
config: {
|
||||||
|
rateLimit: secretsLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
description: "Delete many secrets",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
body: z.object({
|
||||||
|
projectSlug: z.string().trim().describe(RAW_SECRETS.DELETE.projectSlug),
|
||||||
|
environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment),
|
||||||
|
secretPath: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.default("/")
|
||||||
|
.transform(removeTrailingSlash)
|
||||||
|
.describe(RAW_SECRETS.DELETE.secretPath),
|
||||||
|
secrets: z
|
||||||
|
.object({
|
||||||
|
secretKey: z.string().trim().describe(RAW_SECRETS.DELETE.secretName)
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
.min(1)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
secrets: secretRawSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { environment, projectSlug, secretPath, secrets: inputSecrets } = req.body;
|
||||||
|
const secrets = await server.services.secret.deleteManySecretsRaw({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
environment,
|
||||||
|
projectSlug,
|
||||||
|
secretPath,
|
||||||
|
secrets: inputSecrets
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
projectId: secrets[0].workspace,
|
||||||
|
...req.auditLogInfo,
|
||||||
|
event: {
|
||||||
|
type: EventType.DELETE_SECRETS,
|
||||||
|
metadata: {
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
secrets: secrets.map((secret, i) => ({
|
||||||
|
secretId: secret.id,
|
||||||
|
secretKey: inputSecrets[i].secretKey,
|
||||||
|
secretVersion: secret.version
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.telemetry.sendPostHogEvents({
|
||||||
|
event: PostHogEventTypes.SecretDeleted,
|
||||||
|
distinctId: getTelemetryDistinctId(req),
|
||||||
|
properties: {
|
||||||
|
numberOfSecrets: secrets.length,
|
||||||
|
workspaceId: secrets[0].workspace,
|
||||||
|
environment: req.body.environment,
|
||||||
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
|
...req.auditLogInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { secrets };
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -575,7 +575,11 @@ export const createManySecretsRawFnFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -680,7 +684,11 @@ export const updateManySecretsRawFnFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Update secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Update secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ import { TSecretQueueFactory } from "./secret-queue";
|
|||||||
import {
|
import {
|
||||||
TAttachSecretTagsDTO,
|
TAttachSecretTagsDTO,
|
||||||
TCreateBulkSecretDTO,
|
TCreateBulkSecretDTO,
|
||||||
|
TCreateManySecretRawDTO,
|
||||||
TCreateSecretDTO,
|
TCreateSecretDTO,
|
||||||
TCreateSecretRawDTO,
|
TCreateSecretRawDTO,
|
||||||
TDeleteBulkSecretDTO,
|
TDeleteBulkSecretDTO,
|
||||||
|
TDeleteManySecretRawDTO,
|
||||||
TDeleteSecretDTO,
|
TDeleteSecretDTO,
|
||||||
TDeleteSecretRawDTO,
|
TDeleteSecretRawDTO,
|
||||||
TFnSecretBlindIndexCheckV2,
|
TFnSecretBlindIndexCheckV2,
|
||||||
@@ -46,6 +48,7 @@ import {
|
|||||||
TGetSecretsRawDTO,
|
TGetSecretsRawDTO,
|
||||||
TGetSecretVersionsDTO,
|
TGetSecretVersionsDTO,
|
||||||
TUpdateBulkSecretDTO,
|
TUpdateBulkSecretDTO,
|
||||||
|
TUpdateManySecretRawDTO,
|
||||||
TUpdateSecretDTO,
|
TUpdateSecretDTO,
|
||||||
TUpdateSecretRawDTO
|
TUpdateSecretRawDTO
|
||||||
} from "./secret-types";
|
} from "./secret-types";
|
||||||
@@ -179,7 +182,11 @@ export const secretServiceFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -275,7 +282,11 @@ export const secretServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -391,7 +402,11 @@ export const secretServiceFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -559,7 +574,11 @@ export const secretServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
|
||||||
);
|
);
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const secretBlindIndex = await interalGenSecBlindIndexByName(projectId, secretName);
|
const secretBlindIndex = await interalGenSecBlindIndexByName(projectId, secretName);
|
||||||
@@ -655,7 +674,11 @@ export const secretServiceFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -724,7 +747,11 @@ export const secretServiceFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Update secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Update secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -810,7 +837,11 @@ export const secretServiceFactory = ({
|
|||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" });
|
if (!folder)
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Folder not found for the given environment slug & secret path",
|
||||||
|
name: "Create secret"
|
||||||
|
});
|
||||||
const folderId = folder.id;
|
const folderId = folder.id;
|
||||||
|
|
||||||
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
const blindIndexCfg = await secretBlindIndexDAL.findOne({ projectId });
|
||||||
@@ -1036,6 +1067,143 @@ export const secretServiceFactory = ({
|
|||||||
return decryptSecretRaw(secret, botKey);
|
return decryptSecretRaw(secret, botKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createManySecretsRaw = async ({
|
||||||
|
actorId,
|
||||||
|
projectSlug,
|
||||||
|
environment,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
secretPath,
|
||||||
|
secrets: inputSecrets = []
|
||||||
|
}: TCreateManySecretRawDTO) => {
|
||||||
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
|
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||||
|
const projectId = project.id;
|
||||||
|
|
||||||
|
const botKey = await projectBotService.getBotKey(projectId);
|
||||||
|
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
|
||||||
|
|
||||||
|
const secrets = await createManySecret({
|
||||||
|
projectId,
|
||||||
|
environment,
|
||||||
|
path: secretPath,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
secrets: inputSecrets.map(({ secretComment, secretKey, secretValue, skipMultilineEncoding }) => {
|
||||||
|
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
|
||||||
|
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
|
||||||
|
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
|
||||||
|
return {
|
||||||
|
secretName: secretKey,
|
||||||
|
skipMultilineEncoding,
|
||||||
|
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
|
||||||
|
secretKeyIV: secretKeyEncrypted.iv,
|
||||||
|
secretKeyTag: secretKeyEncrypted.tag,
|
||||||
|
secretValueCiphertext: secretValueEncrypted.ciphertext,
|
||||||
|
secretValueIV: secretValueEncrypted.iv,
|
||||||
|
secretValueTag: secretValueEncrypted.tag,
|
||||||
|
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
|
||||||
|
secretCommentIV: secretCommentEncrypted.iv,
|
||||||
|
secretCommentTag: secretCommentEncrypted.tag
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
await snapshotService.performSnapshot(secrets[0].folderId);
|
||||||
|
await secretQueueService.syncSecrets({ secretPath, projectId, environment });
|
||||||
|
|
||||||
|
return secrets.map((secret) => decryptSecretRaw({ ...secret, workspace: projectId, environment }, botKey));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateManySecretsRaw = async ({
|
||||||
|
actorId,
|
||||||
|
projectSlug,
|
||||||
|
environment,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
secretPath,
|
||||||
|
secrets: inputSecrets = []
|
||||||
|
}: TUpdateManySecretRawDTO) => {
|
||||||
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
|
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||||
|
const projectId = project.id;
|
||||||
|
|
||||||
|
const botKey = await projectBotService.getBotKey(projectId);
|
||||||
|
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
|
||||||
|
|
||||||
|
const secrets = await updateManySecret({
|
||||||
|
projectId,
|
||||||
|
environment,
|
||||||
|
path: secretPath,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
secrets: inputSecrets.map(({ secretComment, secretKey, secretValue, skipMultilineEncoding }) => {
|
||||||
|
const secretKeyEncrypted = encryptSymmetric128BitHexKeyUTF8(secretKey, botKey);
|
||||||
|
const secretValueEncrypted = encryptSymmetric128BitHexKeyUTF8(secretValue || "", botKey);
|
||||||
|
const secretCommentEncrypted = encryptSymmetric128BitHexKeyUTF8(secretComment || "", botKey);
|
||||||
|
return {
|
||||||
|
secretName: secretKey,
|
||||||
|
type: SecretType.Shared,
|
||||||
|
skipMultilineEncoding,
|
||||||
|
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
|
||||||
|
secretKeyIV: secretKeyEncrypted.iv,
|
||||||
|
secretKeyTag: secretKeyEncrypted.tag,
|
||||||
|
secretValueCiphertext: secretValueEncrypted.ciphertext,
|
||||||
|
secretValueIV: secretValueEncrypted.iv,
|
||||||
|
secretValueTag: secretValueEncrypted.tag,
|
||||||
|
secretCommentCiphertext: secretCommentEncrypted.ciphertext,
|
||||||
|
secretCommentIV: secretCommentEncrypted.iv,
|
||||||
|
secretCommentTag: secretCommentEncrypted.tag
|
||||||
|
};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
await snapshotService.performSnapshot(secrets[0].folderId);
|
||||||
|
await secretQueueService.syncSecrets({ secretPath, projectId, environment });
|
||||||
|
|
||||||
|
return secrets.map((secret) => decryptSecretRaw({ ...secret, workspace: projectId, environment }, botKey));
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteManySecretsRaw = async ({
|
||||||
|
actorId,
|
||||||
|
projectSlug,
|
||||||
|
environment,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
secretPath,
|
||||||
|
secrets: inputSecrets = []
|
||||||
|
}: TDeleteManySecretRawDTO) => {
|
||||||
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
|
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||||
|
const projectId = project.id;
|
||||||
|
|
||||||
|
const botKey = await projectBotService.getBotKey(projectId);
|
||||||
|
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
|
||||||
|
|
||||||
|
const secrets = await deleteManySecret({
|
||||||
|
projectId,
|
||||||
|
environment,
|
||||||
|
path: secretPath,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
secrets: inputSecrets.map(({ secretKey }) => ({ secretName: secretKey, type: SecretType.Shared }))
|
||||||
|
});
|
||||||
|
|
||||||
|
await snapshotService.performSnapshot(secrets[0].folderId);
|
||||||
|
await secretQueueService.syncSecrets({ secretPath, projectId, environment });
|
||||||
|
|
||||||
|
return secrets.map((secret) => decryptSecretRaw({ ...secret, workspace: projectId, environment }, botKey));
|
||||||
|
};
|
||||||
|
|
||||||
const getSecretVersions = async ({
|
const getSecretVersions = async ({
|
||||||
actorId,
|
actorId,
|
||||||
actor,
|
actor,
|
||||||
@@ -1280,6 +1448,9 @@ export const secretServiceFactory = ({
|
|||||||
createSecretRaw,
|
createSecretRaw,
|
||||||
updateSecretRaw,
|
updateSecretRaw,
|
||||||
deleteSecretRaw,
|
deleteSecretRaw,
|
||||||
|
createManySecretsRaw,
|
||||||
|
updateManySecretsRaw,
|
||||||
|
deleteManySecretsRaw,
|
||||||
getSecretVersions,
|
getSecretVersions,
|
||||||
// external services function
|
// external services function
|
||||||
fnSecretBulkDelete,
|
fnSecretBulkDelete,
|
||||||
|
|||||||
@@ -181,6 +181,39 @@ export type TDeleteSecretRawDTO = TProjectPermission & {
|
|||||||
type: SecretType;
|
type: SecretType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TCreateManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
|
||||||
|
secretPath: string;
|
||||||
|
projectSlug: string;
|
||||||
|
environment: string;
|
||||||
|
secrets: {
|
||||||
|
secretKey: string;
|
||||||
|
secretValue: string;
|
||||||
|
secretComment?: string;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TUpdateManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
|
||||||
|
secretPath: string;
|
||||||
|
projectSlug: string;
|
||||||
|
environment: string;
|
||||||
|
secrets: {
|
||||||
|
secretKey: string;
|
||||||
|
secretValue: string;
|
||||||
|
secretComment?: string;
|
||||||
|
skipMultilineEncoding?: boolean;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TDeleteManySecretRawDTO = Omit<TProjectPermission, "projectId"> & {
|
||||||
|
secretPath: string;
|
||||||
|
projectSlug: string;
|
||||||
|
environment: string;
|
||||||
|
secrets: {
|
||||||
|
secretKey: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
export type TGetSecretVersionsDTO = Omit<TProjectPermission, "projectId"> & {
|
export type TGetSecretVersionsDTO = Omit<TProjectPermission, "projectId"> & {
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ var folderCmd = &cobra.Command{
|
|||||||
var getCmd = &cobra.Command{
|
var getCmd = &cobra.Command{
|
||||||
Use: "get",
|
Use: "get",
|
||||||
Short: "Get folders in a directory",
|
Short: "Get folders in a directory",
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
|
||||||
util.RequireLocalWorkspaceFile()
|
|
||||||
util.RequireLogin()
|
|
||||||
},
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
environmentName, _ := cmd.Flags().GetString("env")
|
environmentName, _ := cmd.Flags().GetString("env")
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -204,8 +205,10 @@ var secretsSetCmd = &cobra.Command{
|
|||||||
// decrypt workspace key
|
// decrypt workspace key
|
||||||
plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
|
plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
|
||||||
|
|
||||||
|
infisicalTokenEnv := os.Getenv(util.INFISICAL_TOKEN_NAME)
|
||||||
|
|
||||||
// pull current secrets
|
// pull current secrets
|
||||||
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, SecretsPath: secretsPath}, "")
|
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, SecretsPath: secretsPath, InfisicalToken: infisicalTokenEnv}, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.HandleError(err, "unable to retrieve secrets")
|
util.HandleError(err, "unable to retrieve secrets")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Infisical/infisical-merge/packages/api"
|
"github.com/Infisical/infisical-merge/packages/api"
|
||||||
@@ -13,13 +12,11 @@ import (
|
|||||||
|
|
||||||
func GetAllFolders(params models.GetAllFoldersParameters) ([]models.SingleFolder, error) {
|
func GetAllFolders(params models.GetAllFoldersParameters) ([]models.SingleFolder, error) {
|
||||||
|
|
||||||
if params.InfisicalToken == "" {
|
|
||||||
params.InfisicalToken = os.Getenv(INFISICAL_TOKEN_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
var foldersToReturn []models.SingleFolder
|
var foldersToReturn []models.SingleFolder
|
||||||
var folderErr error
|
var folderErr error
|
||||||
if params.InfisicalToken == "" && params.UniversalAuthAccessToken == "" {
|
if params.InfisicalToken == "" && params.UniversalAuthAccessToken == "" {
|
||||||
|
RequireLogin()
|
||||||
|
RequireLocalWorkspaceFile()
|
||||||
|
|
||||||
log.Debug().Msg("GetAllFolders: Trying to fetch folders using logged in details")
|
log.Debug().Msg("GetAllFolders: Trying to fetch folders using logged in details")
|
||||||
|
|
||||||
|
|||||||
@@ -307,10 +307,6 @@ func FilterSecretsByTag(plainTextSecrets []models.SingleEnvironmentVariable, tag
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectConfigFilePath string) ([]models.SingleEnvironmentVariable, error) {
|
func GetAllEnvironmentVariables(params models.GetAllSecretsParameters, projectConfigFilePath string) ([]models.SingleEnvironmentVariable, error) {
|
||||||
if params.InfisicalToken == "" {
|
|
||||||
params.InfisicalToken = os.Getenv(INFISICAL_TOKEN_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
isConnected := CheckIsConnectedToInternet()
|
isConnected := CheckIsConnectedToInternet()
|
||||||
var secretsToReturn []models.SingleEnvironmentVariable
|
var secretsToReturn []models.SingleEnvironmentVariable
|
||||||
// var serviceTokenDetails api.GetServiceTokenDetailsResponse
|
// var serviceTokenDetails api.GetServiceTokenDetailsResponse
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
title: "Bulk Create"
|
||||||
|
openapi: "POST /api/v3/secrets/batch/raw"
|
||||||
|
---
|
||||||
|
|
||||||
|
<Tip>
|
||||||
|
This endpoint requires you to disable end-to-end encryption. For more information, you should consult this [note](https://infisical.com/docs/api-reference/overview/examples/note).
|
||||||
|
</Tip>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
title: "Bulk Delete"
|
||||||
|
openapi: "DELETE /api/v3/secrets/batch/raw"
|
||||||
|
---
|
||||||
|
|
||||||
|
<Tip>
|
||||||
|
This endpoint requires you to disable end-to-end encryption. For more information, you should consult this [note](https://infisical.com/docs/api-reference/overview/examples/note).
|
||||||
|
</Tip>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
title: "Bulk Update"
|
||||||
|
openapi: "PATCH /api/v3/secrets/batch/raw"
|
||||||
|
---
|
||||||
|
|
||||||
|
<Tip>
|
||||||
|
This endpoint requires you to disable end-to-end encryption. For more information, you should consult this [note](https://infisical.com/docs/api-reference/overview/examples/note).
|
||||||
|
</Tip>
|
||||||
@@ -33,7 +33,7 @@ This approach enables you to fetch secrets from Infisical during Amplify build t
|
|||||||
preBuild:
|
preBuild:
|
||||||
commands:
|
commands:
|
||||||
- sudo curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' | sudo -E bash
|
- sudo curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.rpm.sh' | sudo -E bash
|
||||||
- sudo yum install infisical
|
- sudo yum -y install infisical
|
||||||
```
|
```
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Modify the build command">
|
<Step title="Modify the build command">
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ description: "Learn how to use Helm chart to install Infisical on your Kubernete
|
|||||||
</Step>
|
</Step>
|
||||||
<Step title="Select Infisical version">
|
<Step title="Select Infisical version">
|
||||||
By default, the Infisical version set in your helm chart will likely be outdated.
|
By default, the Infisical version set in your helm chart will likely be outdated.
|
||||||
Choose the latest Infisical docker image tag from here [here](https://hub.docker.com/r/infisical/infisical/tags).
|
Choose the latest Infisical docker image tag from [here](https://hub.docker.com/r/infisical/infisical/tags).
|
||||||
|
|
||||||
|
|
||||||
```yaml values.yaml
|
```yaml values.yaml
|
||||||
|
|||||||
Reference in New Issue
Block a user