mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-20 01:48:03 +00:00
Compare commits
43 Commits
ecs-docs
...
admin-ui-f
Author | SHA1 | Date | |
---|---|---|---|
8bc9a5fed6 | |||
55e75bbbef | |||
61ff732ec0 | |||
609b224ca9 | |||
c23e16105b | |||
c10f4ece51 | |||
bcdb1b11bc | |||
01d850f7e8 | |||
2d1b60a520 | |||
8de2302d98 | |||
0529b50ad7 | |||
c74fe0ca73 | |||
d5f8526a84 | |||
782ae7a41d | |||
d355956daf | |||
5b9c0438a2 | |||
11399d73dc | |||
38ed39c2f8 | |||
4e3827780f | |||
644cdf5a67 | |||
0d6ea0d69e | |||
237979a1c6 | |||
4a566cf83f | |||
654b8ab5ca | |||
ac0780266b | |||
7a253ddcc7 | |||
b65677a708 | |||
c1eb97ee53 | |||
937e48dbc5 | |||
b3d4787e21 | |||
72d46efba5 | |||
b6eb08167f | |||
582472e4cc | |||
3b3b76548b | |||
f8416ad891 | |||
31e49672d5 | |||
9248bdf463 | |||
87c061ae9b | |||
e9fa631c8f | |||
cff15b64c4 | |||
136f5a6052 | |||
7e8f9ec9e4 | |||
202efce10d |
6
.github/pull_request_template.md
vendored
6
.github/pull_request_template.md
vendored
@ -1,6 +1,6 @@
|
|||||||
# Description 📣
|
# Description 📣
|
||||||
|
|
||||||
<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. -->
|
<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. Here's how we expect a pull request to be : https://infisical.com/docs/contributing/getting-started/pull-requests -->
|
||||||
|
|
||||||
## Type ✨
|
## Type ✨
|
||||||
|
|
||||||
@ -19,4 +19,6 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- [ ] I have read the [contributing guide](https://infisical.com/docs/contributing/overview), agreed and acknowledged the [code of conduct](https://infisical.com/docs/contributing/code-of-conduct). 📝
|
- [ ] I have read the [contributing guide](https://infisical.com/docs/contributing/getting-started/overview), agreed and acknowledged the [code of conduct](https://infisical.com/docs/contributing/getting-started/code-of-conduct). 📝
|
||||||
|
|
||||||
|
<!-- If you have any questions regarding contribution, here's the FAQ : https://infisical.com/docs/contributing/getting-started/faq -->
|
8
.github/values.yaml
vendored
8
.github/values.yaml
vendored
@ -19,11 +19,11 @@ infisical:
|
|||||||
## @param backend.name Backend name
|
## @param backend.name Backend name
|
||||||
##
|
##
|
||||||
name: infisical
|
name: infisical
|
||||||
replicaCount: 2
|
replicaCount: 3
|
||||||
image:
|
image:
|
||||||
repository: infisical/infisical
|
repository: infisical/staging_infisical
|
||||||
tag: "latest-postgres"
|
tag: "latest"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: Always
|
||||||
|
|
||||||
deploymentAnnotations:
|
deploymentAnnotations:
|
||||||
secrets.infisical.com/auto-reload: "true"
|
secrets.infisical.com/auto-reload: "true"
|
||||||
|
@ -104,7 +104,6 @@ ENV NEXT_PUBLIC_INTERCOM_ID=$INTERCOM_ID \
|
|||||||
WORKDIR /
|
WORKDIR /
|
||||||
|
|
||||||
COPY --from=backend-runner /app /backend
|
COPY --from=backend-runner /app /backend
|
||||||
COPY --from=backend-runner /app/dist/services/smtp/templates /backend/dist/templates
|
|
||||||
|
|
||||||
COPY --from=frontend-runner /app ./backend/frontend-build
|
COPY --from=frontend-runner /app ./backend/frontend-build
|
||||||
|
|
||||||
|
30
README.md
30
README.md
@ -33,7 +33,7 @@
|
|||||||
<img src="https://img.shields.io/github/commit-activity/m/infisical/infisical" alt="git commit activity" />
|
<img src="https://img.shields.io/github/commit-activity/m/infisical/infisical" alt="git commit activity" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://cloudsmith.io/~infisical/repos/">
|
<a href="https://cloudsmith.io/~infisical/repos/">
|
||||||
<img src="https://img.shields.io/badge/Downloads-2.58M-orange" alt="Cloudsmith downloads" />
|
<img src="https://img.shields.io/badge/Downloads-6.95M-orange" alt="Cloudsmith downloads" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://infisical.com/slack">
|
<a href="https://infisical.com/slack">
|
||||||
<img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" />
|
<img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" />
|
||||||
@ -53,17 +53,19 @@ We're on a mission to make secret management more accessible to everyone, not ju
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **[User-friendly dashboard](https://infisical.com/docs/documentation/platform/project)** to manage secrets across projects and environments (e.g. development, production, etc.)
|
- **[User-friendly dashboard](https://infisical.com/docs/documentation/platform/project)** to manage secrets across projects and environments (e.g. development, production, etc.).
|
||||||
- **[Client SDKs](https://infisical.com/docs/sdks/overview)** to fetch secrets for your apps and infrastructure on demand
|
- **[Client SDKs](https://infisical.com/docs/sdks/overview)** to fetch secrets for your apps and infrastructure on demand.
|
||||||
- **[Infisical CLI](https://infisical.com/docs/cli/overview)** to fetch and inject secrets into any framework in local development
|
- **[Infisical CLI](https://infisical.com/docs/cli/overview)** to fetch and inject secrets into any framework in local development and CI/CD.
|
||||||
- **[Native integrations](https://infisical.com/docs/integrations/overview)** with platforms like GitHub, Vercel, Netlify, and more
|
- **[Infisical API](https://infisical.com/docs/api-reference/overview/introduction)** to perform CRUD operation on secrets, users, projects, and any other resource in Infisical.
|
||||||
- [**Automatic Kubernetes deployment secret reloads**](https://infisical.com/docs/documentation/getting-started/kubernetes)
|
- **[Native integrations](https://infisical.com/docs/integrations/overview)** with platforms like [GitHub](https://infisical.com/docs/integrations/cicd/githubactions), [Vercel](https://infisical.com/docs/integrations/cloud/vercel), [AWS](https://infisical.com/docs/integrations/cloud/aws-secret-manager), and tools like [Terraform](https://infisical.com/docs/integrations/frameworks/terraform), [Ansible](https://infisical.com/docs/integrations/platforms/ansible), and more.
|
||||||
- **[Complete control over your data](https://infisical.com/docs/self-hosting/overview)** - host it yourself on any infrastructure
|
- **[Infisical Kubernetes operator](https://infisical.com/docs/documentation/getting-started/kubernetes)** to managed secrets in k8s, automatically reload deployments, and more.
|
||||||
- **[Secret versioning](https://infisical.com/docs/documentation/platform/secret-versioning)** and **[Point-in-Time Recovery]()** to version every secret and project state
|
- **[Infisical Agent](https://infisical.com/docs/infisical-agent/overview)** to inject secrets into your applications without modifying any code logic.
|
||||||
- **[Audit logs](https://infisical.com/docs/documentation/platform/audit-logs)** to record every action taken in a project
|
- **[Self-hosting and on-prem](https://infisical.com/docs/self-hosting/overview)** to get complete control over your data.
|
||||||
- **Role-based Access Controls** per environment
|
- **[Secret versioning](https://infisical.com/docs/documentation/platform/secret-versioning)** and **[Point-in-Time Recovery](https://infisical.com/docs/documentation/platform/pit-recovery)** to version every secret and project state.
|
||||||
- [**Simple on-premise deployments** to AWS, Digital Ocean, and more](https://infisical.com/docs/self-hosting/overview)
|
- **[Audit logs](https://infisical.com/docs/documentation/platform/audit-logs)** to record every action taken in a project.
|
||||||
- [**Secret Scanning and Leak Prevention**](https://infisical.com/docs/cli/scanning-overview)
|
- **[Role-based Access Controls](https://infisical.com/docs/documentation/platform/role-based-access-controls)** to create permission sets on any resource in Infisica and assign those to user or machine identities.
|
||||||
|
- **[Simple on-premise deployments](https://infisical.com/docs/self-hosting/overview)** to AWS, Digital Ocean, and more.
|
||||||
|
- **[Secret Scanning and Leak Prevention](https://infisical.com/docs/cli/scanning-overview)** to prevent secrets from leaking to git.
|
||||||
|
|
||||||
And much more.
|
And much more.
|
||||||
|
|
||||||
@ -115,9 +117,9 @@ Lean about Infisical's code scanning feature [here](https://infisical.com/docs/c
|
|||||||
|
|
||||||
This repo available under the [MIT expat license](https://github.com/Infisical/infisical/blob/main/LICENSE), with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license.
|
This repo available under the [MIT expat license](https://github.com/Infisical/infisical/blob/main/LICENSE), with the exception of the `ee` directory which will contain premium enterprise features requiring a Infisical license.
|
||||||
|
|
||||||
If you are interested in managed Infisical Cloud of self-hosted Enterprise Offering, take a look at [our website](https://infisical.com/) or [book a meeting with us](https://cal.com/vmatsiiako/infisical-demo):
|
If you are interested in managed Infisical Cloud of self-hosted Enterprise Offering, take a look at [our website](https://infisical.com/) or [book a meeting with us](https://infisical.cal.com/vlad/infisical-demo):
|
||||||
|
|
||||||
<a href="https://cal.com/vmatsiiako/infisical-demo"><img alt="Schedule a meeting" src="https://cal.com/book-with-cal-dark.svg" /></a>
|
<a href="[https://infisical.cal.com/vlad/infisical-demo](https://infisical.cal.com/vlad/infisical-demo)"><img alt="Schedule a meeting" src="https://cal.com/book-with-cal-dark.svg" /></a>
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
|
621
backend/package-lock.json
generated
621
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,12 @@
|
|||||||
"name": "backend",
|
"name": "backend",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "./dist/main.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"dev": "tsx watch --clear-screen=false ./src/main.ts | pino-pretty --colorize --colorizeObjects --singleLine",
|
"dev": "tsx watch --clear-screen=false ./src/main.ts | pino-pretty --colorize --colorizeObjects --singleLine",
|
||||||
"dev:docker": "nodemon",
|
"dev:docker": "nodemon",
|
||||||
"build": "rimraf dist && tsup && cp -R ./src/lib/validator/disposable_emails.txt ./dist && cp -R ./src/services/smtp/templates ./dist",
|
"build": "tsup",
|
||||||
"start": "node dist/main.mjs",
|
"start": "node dist/main.mjs",
|
||||||
"type:check": "tsc --noEmit",
|
"type:check": "tsc --noEmit",
|
||||||
"lint:fix": "eslint --fix --ext js,ts ./src",
|
"lint:fix": "eslint --fix --ext js,ts ./src",
|
||||||
@ -44,7 +44,13 @@
|
|||||||
"@types/pg": "^8.10.9",
|
"@types/pg": "^8.10.9",
|
||||||
"@types/picomatch": "^2.3.3",
|
"@types/picomatch": "^2.3.3",
|
||||||
"@types/prompt-sync": "^4.2.3",
|
"@types/prompt-sync": "^4.2.3",
|
||||||
|
"@types/resolve": "^1.20.6",
|
||||||
"@types/uuid": "^9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||||
|
"@typescript-eslint/parser": "^6.20.0",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
|
"eslint-config-airbnb-typescript": "^17.1.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
@ -55,6 +61,7 @@
|
|||||||
"prompt-sync": "^4.2.0",
|
"prompt-sync": "^4.2.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
"tsc-alias": "^1.8.8",
|
||||||
"tsconfig-paths": "^4.2.0",
|
"tsconfig-paths": "^4.2.0",
|
||||||
"tsup": "^8.0.1",
|
"tsup": "^8.0.1",
|
||||||
"tsx": "^4.4.0",
|
"tsx": "^4.4.0",
|
||||||
@ -67,6 +74,7 @@
|
|||||||
"@casl/ability": "^6.5.0",
|
"@casl/ability": "^6.5.0",
|
||||||
"@fastify/cookie": "^9.2.0",
|
"@fastify/cookie": "^9.2.0",
|
||||||
"@fastify/cors": "^8.4.1",
|
"@fastify/cors": "^8.4.1",
|
||||||
|
"@fastify/etag": "^5.1.0",
|
||||||
"@fastify/formbody": "^7.4.0",
|
"@fastify/formbody": "^7.4.0",
|
||||||
"@fastify/helmet": "^11.1.1",
|
"@fastify/helmet": "^11.1.1",
|
||||||
"@fastify/passport": "^2.4.0",
|
"@fastify/passport": "^2.4.0",
|
||||||
@ -79,8 +87,6 @@
|
|||||||
"@octokit/webhooks-types": "^7.3.1",
|
"@octokit/webhooks-types": "^7.3.1",
|
||||||
"@serdnam/pino-cloudwatch-transport": "^1.0.4",
|
"@serdnam/pino-cloudwatch-transport": "^1.0.4",
|
||||||
"@sindresorhus/slugify": "^2.2.1",
|
"@sindresorhus/slugify": "^2.2.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
|
||||||
"@typescript-eslint/parser": "^6.20.0",
|
|
||||||
"@ucast/mongo2js": "^1.3.4",
|
"@ucast/mongo2js": "^1.3.4",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"argon2": "^0.31.2",
|
"argon2": "^0.31.2",
|
||||||
@ -90,9 +96,6 @@
|
|||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"bullmq": "^5.1.1",
|
"bullmq": "^5.1.1",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint": "^8.56.0",
|
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
|
||||||
"eslint-config-airbnb-typescript": "^17.1.0",
|
|
||||||
"fastify": "^4.24.3",
|
"fastify": "^4.24.3",
|
||||||
"fastify-plugin": "^4.5.1",
|
"fastify-plugin": "^4.5.1",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
@ -107,7 +110,6 @@
|
|||||||
"nanoid": "^5.0.4",
|
"nanoid": "^5.0.4",
|
||||||
"node-cache": "^5.1.2",
|
"node-cache": "^5.1.2",
|
||||||
"nodemailer": "^6.9.7",
|
"nodemailer": "^6.9.7",
|
||||||
"ora": "^7.0.1",
|
|
||||||
"passport-github": "^1.1.0",
|
"passport-github": "^1.1.0",
|
||||||
"passport-gitlab2": "^5.0.0",
|
"passport-gitlab2": "^5.0.0",
|
||||||
"passport-google-oauth20": "^2.0.0",
|
"passport-google-oauth20": "^2.0.0",
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
import knex from "knex";
|
import knex from "knex";
|
||||||
|
|
||||||
export type TDbClient = ReturnType<typeof initDbConnection>;
|
export type TDbClient = ReturnType<typeof initDbConnection>;
|
||||||
export const initDbConnection = (dbConnectionUri: string) => {
|
export const initDbConnection = ({ dbConnectionUri, dbRootCert }: { dbConnectionUri: string; dbRootCert?: string }) => {
|
||||||
const db = knex({
|
const db = knex({
|
||||||
client: "pg",
|
client: "pg",
|
||||||
connection: dbConnectionUri
|
connection: {
|
||||||
|
connectionString: dbConnectionUri,
|
||||||
|
ssl: dbRootCert
|
||||||
|
? {
|
||||||
|
rejectUnauthorized: true,
|
||||||
|
ca: Buffer.from(dbRootCert, "base64").toString("ascii")
|
||||||
|
}
|
||||||
|
: false
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
|
@ -79,7 +79,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
async (req, profile, cb) => {
|
async (req, profile, cb) => {
|
||||||
try {
|
try {
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
if (!profile) throw new BadRequestError({ message: "Missing profile" });
|
||||||
const { firstName } = profile;
|
const { firstName } = profile;
|
||||||
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
|
const email = profile?.email ?? (profile?.emailAddress as string); // emailRippling is added because in Rippling the field `email` reserved
|
||||||
|
@ -38,7 +38,8 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.offset(offset);
|
.offset(offset)
|
||||||
|
.orderBy("createdAt", "desc");
|
||||||
if (startDate) {
|
if (startDate) {
|
||||||
void sqlQuery.where("createdAt", ">=", startDate);
|
void sqlQuery.where("createdAt", ">=", startDate);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@ const envSchema = z
|
|||||||
PORT: z.coerce.number().default(4000),
|
PORT: z.coerce.number().default(4000),
|
||||||
REDIS_URL: zpStr(z.string()),
|
REDIS_URL: zpStr(z.string()),
|
||||||
HOST: zpStr(z.string().default("localhost")),
|
HOST: zpStr(z.string().default("localhost")),
|
||||||
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database conntection string")),
|
DB_CONNECTION_URI: zpStr(z.string().describe("Postgres database connection string")),
|
||||||
|
DB_ROOT_CERT: zpStr(z.string().describe("Postgres database base64-encoded CA cert").optional()),
|
||||||
NODE_ENV: z.enum(["development", "test", "production"]).default("production"),
|
NODE_ENV: z.enum(["development", "test", "production"]).default("production"),
|
||||||
SALT_ROUNDS: z.coerce.number().default(10),
|
SALT_ROUNDS: z.coerce.number().default(10),
|
||||||
// TODO(akhilmhdh): will be changed to one
|
// TODO(akhilmhdh): will be changed to one
|
||||||
|
@ -12,7 +12,11 @@ dotenv.config();
|
|||||||
const run = async () => {
|
const run = async () => {
|
||||||
const logger = await initLogger();
|
const logger = await initLogger();
|
||||||
const appCfg = initEnvConfig(logger);
|
const appCfg = initEnvConfig(logger);
|
||||||
const db = initDbConnection(appCfg.DB_CONNECTION_URI);
|
const db = initDbConnection({
|
||||||
|
dbConnectionUri: appCfg.DB_CONNECTION_URI,
|
||||||
|
dbRootCert: appCfg.DB_ROOT_CERT
|
||||||
|
});
|
||||||
|
|
||||||
const smtp = smtpServiceFactory(formatSmtpConfig());
|
const smtp = smtpServiceFactory(formatSmtpConfig());
|
||||||
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
||||||
|
|
||||||
@ -36,7 +40,7 @@ const run = async () => {
|
|||||||
port: appCfg.PORT,
|
port: appCfg.PORT,
|
||||||
host: appCfg.HOST,
|
host: appCfg.HOST,
|
||||||
listenTextResolver: (address) => {
|
listenTextResolver: (address) => {
|
||||||
bootstrap();
|
void bootstrap();
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -5,6 +5,7 @@ import type { FastifyCookieOptions } from "@fastify/cookie";
|
|||||||
import cookie from "@fastify/cookie";
|
import cookie from "@fastify/cookie";
|
||||||
import type { FastifyCorsOptions } from "@fastify/cors";
|
import type { FastifyCorsOptions } from "@fastify/cors";
|
||||||
import cors from "@fastify/cors";
|
import cors from "@fastify/cors";
|
||||||
|
import fastifyEtag from "@fastify/etag";
|
||||||
import fastifyFormBody from "@fastify/formbody";
|
import fastifyFormBody from "@fastify/formbody";
|
||||||
import helmet from "@fastify/helmet";
|
import helmet from "@fastify/helmet";
|
||||||
import type { FastifyRateLimitOptions } from "@fastify/rate-limit";
|
import type { FastifyRateLimitOptions } from "@fastify/rate-limit";
|
||||||
@ -13,11 +14,10 @@ import fasitfy from "fastify";
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
import { Logger } from "pino";
|
import { Logger } from "pino";
|
||||||
|
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { TQueueServiceFactory } from "@app/queue";
|
import { TQueueServiceFactory } from "@app/queue";
|
||||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
|
|
||||||
import { getConfig } from "@lib/config/env";
|
|
||||||
|
|
||||||
import { globalRateLimiterCfg } from "./config/rateLimiter";
|
import { globalRateLimiterCfg } from "./config/rateLimiter";
|
||||||
import { fastifyErrHandler } from "./plugins/error-handler";
|
import { fastifyErrHandler } from "./plugins/error-handler";
|
||||||
import { registerExternalNextjs } from "./plugins/external-nextjs";
|
import { registerExternalNextjs } from "./plugins/external-nextjs";
|
||||||
@ -39,6 +39,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
|||||||
const server = fasitfy({
|
const server = fasitfy({
|
||||||
logger,
|
logger,
|
||||||
trustProxy: true,
|
trustProxy: true,
|
||||||
|
connectionTimeout: 30 * 1000,
|
||||||
ignoreTrailingSlash: true
|
ignoreTrailingSlash: true
|
||||||
}).withTypeProvider<ZodTypeProvider>();
|
}).withTypeProvider<ZodTypeProvider>();
|
||||||
|
|
||||||
@ -50,6 +51,8 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
|||||||
secret: appCfg.COOKIE_SECRET_SIGN_KEY
|
secret: appCfg.COOKIE_SECRET_SIGN_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await server.register(fastifyEtag);
|
||||||
|
|
||||||
await server.register<FastifyCorsOptions>(cors, {
|
await server.register<FastifyCorsOptions>(cors, {
|
||||||
credentials: true,
|
credentials: true,
|
||||||
origin: appCfg.SITE_URL || true
|
origin: appCfg.SITE_URL || true
|
||||||
@ -72,7 +75,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
|||||||
if (appCfg.isProductionMode) {
|
if (appCfg.isProductionMode) {
|
||||||
await server.register(registerExternalNextjs, {
|
await server.register(registerExternalNextjs, {
|
||||||
standaloneMode: appCfg.STANDALONE_MODE,
|
standaloneMode: appCfg.STANDALONE_MODE,
|
||||||
dir: path.join(__dirname, "../"),
|
dir: path.join(__dirname, "../../"),
|
||||||
port: appCfg.PORT
|
port: appCfg.PORT
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ type BootstrapOpt = {
|
|||||||
db: Knex;
|
db: Knex;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bootstrapCb = () => {
|
const bootstrapCb = async () => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
if (!serverCfg.initialized) {
|
if (!serverCfg.initialized) {
|
||||||
console.info(`Welcome to Infisical
|
console.info(`Welcome to Infisical
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@ export const registerExternalNextjs = async (
|
|||||||
server.route({
|
server.route({
|
||||||
method: ["GET", "PUT", "PATCH", "POST", "DELETE"],
|
method: ["GET", "PUT", "PATCH", "POST", "DELETE"],
|
||||||
url: "/*",
|
url: "/*",
|
||||||
|
schema: {
|
||||||
|
hide: true
|
||||||
|
},
|
||||||
handler: (req, res) =>
|
handler: (req, res) =>
|
||||||
nextApp
|
nextApp
|
||||||
.getRequestHandler()(req.raw, res.raw)
|
.getRequestHandler()(req.raw, res.raw)
|
||||||
|
@ -43,6 +43,7 @@ export const fastifySwagger = fp(async (fastify) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await fastify.register(swaggerUI, {
|
await fastify.register(swaggerUI, {
|
||||||
routePrefix: "/docs"
|
routePrefix: "/api/docs",
|
||||||
|
prefix: "/api/docs"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -513,9 +513,9 @@ export const registerRoutes = async (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: () => {
|
handler: async () => {
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
return {
|
return {
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
message: "Ok" as const,
|
message: "Ok" as const,
|
||||||
|
@ -20,8 +20,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: () => {
|
handler: async () => {
|
||||||
const config = getServerCfg();
|
const config = await getServerCfg();
|
||||||
return { config };
|
return { config };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -78,7 +78,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
handler: async (req, res) => {
|
handler: async (req, res) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
if (serverCfg.initialized)
|
if (serverCfg.initialized)
|
||||||
throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" });
|
throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" });
|
||||||
const { user, token } = await server.services.superAdmin.adminSignUp({
|
const { user, token } = await server.services.superAdmin.adminSignUp({
|
||||||
|
@ -42,7 +42,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
async (req, _accessToken, _refreshToken, profile, cb) => {
|
async (req, _accessToken, _refreshToken, profile, cb) => {
|
||||||
try {
|
try {
|
||||||
const email = profile?.emails?.[0]?.value;
|
const email = profile?.emails?.[0]?.value;
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
if (!email)
|
if (!email)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Email not found",
|
message: "Email not found",
|
||||||
@ -84,7 +84,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
try {
|
try {
|
||||||
const ghEmails = await fetchGithubEmails(accessToken);
|
const ghEmails = await fetchGithubEmails(accessToken);
|
||||||
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||||
email,
|
email,
|
||||||
firstName: profile.displayName,
|
firstName: profile.displayName,
|
||||||
@ -120,7 +120,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
||||||
try {
|
try {
|
||||||
const email = profile.emails[0].value;
|
const email = profile.emails[0].value;
|
||||||
const serverCfg = getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||||
email,
|
email,
|
||||||
firstName: profile.displayName,
|
firstName: profile.displayName,
|
||||||
|
@ -49,6 +49,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
200: z.object({
|
200: z.object({
|
||||||
workspaces: z
|
workspaces: z
|
||||||
.object({
|
.object({
|
||||||
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
organization: z.string(),
|
organization: z.string(),
|
||||||
environments: z
|
environments: z
|
||||||
|
@ -13,6 +13,7 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|||||||
import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
|
import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { removeTrailingSlash } from "@app/lib/fn";
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
|
import { getUserAgentType } from "@app/server/plugins/audit-log";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||||
@ -107,6 +108,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
secretPath: req.query.secretPath,
|
secretPath: req.query.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -188,6 +190,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
environment,
|
environment,
|
||||||
secretPath: req.query.secretPath,
|
secretPath: req.query.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -255,7 +258,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -322,7 +325,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -384,7 +387,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -467,18 +470,33 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: Move to telemetry plugin
|
||||||
|
let shouldRecordK8Event = false;
|
||||||
|
if (req.headers["user-agent"] === "k8-operatoer") {
|
||||||
|
const randomNumber = Math.random();
|
||||||
|
if (randomNumber > 0.95) {
|
||||||
|
shouldRecordK8Event = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldCapture =
|
||||||
|
req.query.workspaceId !== "650e71fbae3e6c8572f436d4" &&
|
||||||
|
(req.headers["user-agent"] !== "k8-operator" || shouldRecordK8Event);
|
||||||
|
const approximateNumberTotalSecrets = secrets.length * 20;
|
||||||
|
if (shouldCapture) {
|
||||||
server.services.telemetry.sendPostHogEvents({
|
server.services.telemetry.sendPostHogEvents({
|
||||||
event: PostHogEventTypes.SecretPulled,
|
event: PostHogEventTypes.SecretPulled,
|
||||||
distinctId: getDistinctId(req),
|
distinctId: getDistinctId(req),
|
||||||
properties: {
|
properties: {
|
||||||
numberOfSecrets: secrets.length,
|
numberOfSecrets: shouldRecordK8Event ? approximateNumberTotalSecrets : secrets.length,
|
||||||
workspaceId: req.query.workspaceId,
|
workspaceId: req.query.workspaceId,
|
||||||
environment: req.query.environment,
|
environment: req.query.environment,
|
||||||
secretPath: req.query.secretPath,
|
secretPath: req.query.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return { secrets, imports };
|
return { secrets, imports };
|
||||||
}
|
}
|
||||||
@ -550,7 +568,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.query.workspaceId,
|
workspaceId: req.query.workspaceId,
|
||||||
environment: req.query.environment,
|
environment: req.query.environment,
|
||||||
secretPath: req.query.secretPath,
|
secretPath: req.query.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -711,7 +729,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -890,7 +908,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1005,7 +1023,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1123,7 +1141,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1240,7 +1258,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1345,7 +1363,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
workspaceId: req.body.workspaceId,
|
workspaceId: req.body.workspaceId,
|
||||||
environment: req.body.environment,
|
environment: req.body.environment,
|
||||||
secretPath: req.body.secretPath,
|
secretPath: req.body.secretPath,
|
||||||
|
channel: getUserAgentType(req.headers["user-agent"]),
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -108,7 +108,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await res.setCookie("jid", refreshToken, {
|
void res.setCookie("jid", refreshToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
path: "/",
|
path: "/",
|
||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
@ -159,7 +159,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
|||||||
userAgent
|
userAgent
|
||||||
});
|
});
|
||||||
|
|
||||||
await res.setCookie("jid", refreshToken, {
|
void res.setCookie("jid", refreshToken, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
path: "/",
|
path: "/",
|
||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
|
@ -21,7 +21,11 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||||
)
|
)
|
||||||
.orderBy("createdAt", "asc", "last");
|
.orderBy([
|
||||||
|
{ column: `${TableName.Project}.name`, order: "asc" },
|
||||||
|
{ column: `${TableName.Environment}.position`, order: "asc" }
|
||||||
|
]);
|
||||||
|
|
||||||
const nestedWorkspaces = sqlNestRelationships({
|
const nestedWorkspaces = sqlNestRelationships({
|
||||||
data: workspaces,
|
data: workspaces,
|
||||||
key: "id",
|
key: "id",
|
||||||
@ -41,7 +45,7 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
return nestedWorkspaces.map((workspace) => ({
|
return nestedWorkspaces.map((workspace) => ({
|
||||||
...workspace,
|
...workspace,
|
||||||
organization: workspace.id
|
organization: workspace.orgId
|
||||||
}));
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find all projects" });
|
throw new DatabaseError({ error, name: "Find all projects" });
|
||||||
@ -83,7 +87,7 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
// We need to add the organization field, as it's required for one of our API endpoint responses.
|
// We need to add the organization field, as it's required for one of our API endpoint responses.
|
||||||
return nestedWorkspaces.map((workspace) => ({
|
return nestedWorkspaces.map((workspace) => ({
|
||||||
...workspace,
|
...workspace,
|
||||||
organization: workspace.id
|
organization: workspace.orgId
|
||||||
}));
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find all projects by identity" });
|
throw new DatabaseError({ error, name: "Find all projects by identity" });
|
||||||
@ -102,7 +106,11 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||||
);
|
)
|
||||||
|
.orderBy([
|
||||||
|
{ column: `${TableName.Project}.name`, order: "asc" },
|
||||||
|
{ column: `${TableName.Environment}.position`, order: "asc" }
|
||||||
|
]);
|
||||||
return sqlNestRelationships({
|
return sqlNestRelationships({
|
||||||
data: workspaces,
|
data: workspaces,
|
||||||
key: "id",
|
key: "id",
|
||||||
|
@ -25,10 +25,15 @@ export const fnSecretsFromImports = async ({
|
|||||||
if (!folderIds.length) {
|
if (!folderIds.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const importedSecrets = await secretDAL.find({
|
const importedSecrets = await secretDAL.find(
|
||||||
|
{
|
||||||
$in: { folderId: folderIds },
|
$in: { folderId: folderIds },
|
||||||
type: SecretType.Shared
|
type: SecretType.Shared
|
||||||
});
|
},
|
||||||
|
{
|
||||||
|
sort: [["id", "asc"]]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const importedSecsGroupByFolderId = groupBy(importedSecrets, (i) => i.folderId);
|
const importedSecsGroupByFolderId = groupBy(importedSecrets, (i) => i.folderId);
|
||||||
return allowedImports.map(({ importPath, importEnv }, i) => ({
|
return allowedImports.map(({ importPath, importEnv }, i) => ({
|
||||||
|
@ -47,7 +47,7 @@ export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSe
|
|||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
||||||
|
|
||||||
const tags = await secretTagDAL.find({ projectId });
|
const tags = await secretTagDAL.find({ projectId }, { sort: [["createdAt", "asc"]] });
|
||||||
return tags;
|
return tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,7 +86,8 @@ export const secretDALFactory = (db: TDbClient) => {
|
|||||||
.select(db.ref("id").withSchema(TableName.SecretTag).as("tagId"))
|
.select(db.ref("id").withSchema(TableName.SecretTag).as("tagId"))
|
||||||
.select(db.ref("color").withSchema(TableName.SecretTag).as("tagColor"))
|
.select(db.ref("color").withSchema(TableName.SecretTag).as("tagColor"))
|
||||||
.select(db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug"))
|
.select(db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug"))
|
||||||
.select(db.ref("name").withSchema(TableName.SecretTag).as("tagName"));
|
.select(db.ref("name").withSchema(TableName.SecretTag).as("tagName"))
|
||||||
|
.orderBy("id", "asc");
|
||||||
const data = sqlNestRelationships({
|
const data = sqlNestRelationships({
|
||||||
data: secs,
|
data: secs,
|
||||||
key: "id",
|
key: "id",
|
||||||
|
@ -117,7 +117,7 @@ export const serviceTokenServiceFactory = ({
|
|||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
|
||||||
|
|
||||||
const tokens = await serviceTokenDAL.find({ projectId });
|
const tokens = await serviceTokenDAL.find({ projectId }, { sort: [["createdAt", "desc"]] });
|
||||||
return tokens;
|
return tokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,11 +17,8 @@ type TSuperAdminServiceFactoryDep = {
|
|||||||
|
|
||||||
export type TSuperAdminServiceFactory = ReturnType<typeof superAdminServiceFactory>;
|
export type TSuperAdminServiceFactory = ReturnType<typeof superAdminServiceFactory>;
|
||||||
|
|
||||||
let serverCfg: Readonly<TSuperAdmin>;
|
// eslint-disable-next-line
|
||||||
export const getServerCfg = () => {
|
export let getServerCfg: () => Promise<TSuperAdmin>;
|
||||||
if (!serverCfg) throw new BadRequestError({ name: "Get server cfg", message: "Server cfg not initialized" });
|
|
||||||
return serverCfg;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const superAdminServiceFactory = ({
|
export const superAdminServiceFactory = ({
|
||||||
serverCfgDAL,
|
serverCfgDAL,
|
||||||
@ -30,19 +27,18 @@ export const superAdminServiceFactory = ({
|
|||||||
orgService
|
orgService
|
||||||
}: TSuperAdminServiceFactoryDep) => {
|
}: TSuperAdminServiceFactoryDep) => {
|
||||||
const initServerCfg = async () => {
|
const initServerCfg = async () => {
|
||||||
serverCfg = await serverCfgDAL.findOne({});
|
// TODO(akhilmhdh): bad pattern time less change this later to me itself
|
||||||
if (!serverCfg) {
|
getServerCfg = () => serverCfgDAL.findOne({});
|
||||||
|
|
||||||
|
const serverCfg = await serverCfgDAL.findOne({});
|
||||||
|
if (serverCfg) return;
|
||||||
const newCfg = await serverCfgDAL.create({ initialized: false, allowSignUp: true });
|
const newCfg = await serverCfgDAL.create({ initialized: false, allowSignUp: true });
|
||||||
serverCfg = newCfg;
|
|
||||||
return newCfg;
|
return newCfg;
|
||||||
}
|
|
||||||
return serverCfg;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateServerCfg = async (data: TSuperAdminUpdate) => {
|
const updateServerCfg = async (data: TSuperAdminUpdate) => {
|
||||||
|
const serverCfg = await getServerCfg();
|
||||||
const cfg = await serverCfgDAL.updateById(serverCfg.id, data);
|
const cfg = await serverCfgDAL.updateById(serverCfg.id, data);
|
||||||
serverCfg = cfg;
|
|
||||||
Object.freeze(serverCfg);
|
|
||||||
return cfg;
|
return cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -80,7 +80,8 @@ export const webhookDALFactory = (db: TDbClient) => {
|
|||||||
.select(db.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
.select(db.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||||
.select(db.ref("id").withSchema(TableName.Environment).as("envId"))
|
.select(db.ref("id").withSchema(TableName.Environment).as("envId"))
|
||||||
.select(db.ref("projectId").withSchema(TableName.Environment))
|
.select(db.ref("projectId").withSchema(TableName.Environment))
|
||||||
.select(selectAllTableCols(TableName.Webhook));
|
.select(selectAllTableCols(TableName.Webhook))
|
||||||
|
.orderBy(`${TableName.Webhook}.createdAt`, "asc");
|
||||||
|
|
||||||
return webhooks.map(({ envId, envSlug, envName, ...el }) => ({
|
return webhooks.map(({ envId, envSlug, envName, ...el }) => ({
|
||||||
...el,
|
...el,
|
||||||
|
@ -22,11 +22,9 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@app/*": ["./src/*"],
|
"@app/*": ["./src/*"]
|
||||||
"@lib/*": ["./src/lib/*"],
|
|
||||||
"@server/*": ["./src/server/*"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", "scripts/**/*", "e2e-test/**/*","./.eslintrc.js"],
|
"include": ["src/**/*", "scripts/**/*", "e2e-test/**/*", "./.eslintrc.js", "./tsup.config.js"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,73 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
import fs from "fs/promises";
|
||||||
|
import { replaceTscAliasPaths } from "tsc-alias";
|
||||||
import { defineConfig } from "tsup";
|
import { defineConfig } from "tsup";
|
||||||
|
|
||||||
|
// Instead of using tsx or tsc for building, consider using tsup.
|
||||||
|
// TSX serves as an alternative to Node.js, allowing you to build directly on the Node.js runtime.
|
||||||
|
// Its functionality mirrors Node.js, with the only difference being the absence of a final build step. Production should ideally be launched with TSX.
|
||||||
|
// TSC is effective for creating a final build, but it requires manual copying of all static files such as handlebars, emails, etc.
|
||||||
|
// A significant challenge is the shift towards ESM, as more packages are adopting ESM. If the output is in CommonJS, it may lead to errors.
|
||||||
|
// The suggested configuration offers a balance, accommodating both ESM and CommonJS requirements.
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
shims: true,
|
shims: true,
|
||||||
|
clean: true,
|
||||||
|
minify: false,
|
||||||
|
keepNames: true,
|
||||||
|
splitting: false,
|
||||||
format: "esm",
|
format: "esm",
|
||||||
|
// copy the files to output
|
||||||
loader: {
|
loader: {
|
||||||
".handlebars": "copy",
|
".handlebars": "copy",
|
||||||
".md": "copy"
|
".md": "copy",
|
||||||
|
".txt": "copy"
|
||||||
},
|
},
|
||||||
external: ["../../../frontend/node_modules/next/dist/server/next-server.js"],
|
external: ["../../../frontend/node_modules/next/dist/server/next-server.js"],
|
||||||
outDir: "dist",
|
outDir: "dist",
|
||||||
|
tsconfig: "./tsconfig.json",
|
||||||
entry: ["./src"],
|
entry: ["./src"],
|
||||||
sourceMap: "inline"
|
sourceMap: true,
|
||||||
|
skipNodeModulesBundle: true,
|
||||||
|
esbuildPlugins: [
|
||||||
|
{
|
||||||
|
// esm directory import are not allowed
|
||||||
|
// /folder1 should be explicitly imported as /folder1/index.ts
|
||||||
|
// this plugin will append it automatically on build time to all imports
|
||||||
|
name: "commonjs-esm-directory-import",
|
||||||
|
setup(build) {
|
||||||
|
build.onResolve({ filter: /.*/ }, async (args) => {
|
||||||
|
if (args.importer) {
|
||||||
|
if (args.kind === "import-statement") {
|
||||||
|
const isRelativePath = args.path.startsWith(".");
|
||||||
|
const absPath = isRelativePath
|
||||||
|
? path.join(args.resolveDir, args.path)
|
||||||
|
: path.join(args.path.replace("@app", "./src"));
|
||||||
|
|
||||||
|
const isFile = await fs
|
||||||
|
.stat(`${absPath}.ts`)
|
||||||
|
.then((el) => el.isFile)
|
||||||
|
.catch((err) => err.code === "ENOTDIR");
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: isFile ? `${args.path}.mjs` : `${args.path}/index.mjs`,
|
||||||
|
external: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
async onSuccess() {
|
||||||
|
// this will replace all tsconfig paths
|
||||||
|
await replaceTscAliasPaths({
|
||||||
|
configFile: "tsconfig.json",
|
||||||
|
watch: false,
|
||||||
|
outDir: "dist"
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,17 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis_data:/data
|
- redis_data:/data
|
||||||
|
|
||||||
|
redis-commander:
|
||||||
|
container_name: infisical-dev-redis-commander
|
||||||
|
image: rediscommander/redis-commander
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- REDIS_HOSTS=local:redis:6379
|
||||||
|
ports:
|
||||||
|
- "8085:8081"
|
||||||
|
|
||||||
db-test:
|
db-test:
|
||||||
profiles: ["test"]
|
profiles: ["test"]
|
||||||
image: postgres:14-alpine
|
image: postgres:14-alpine
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
title: "Role-based Access Controls"
|
title: "Role-based Access Controls"
|
||||||
description: "Infisical's Role-based Acccess Controls enable creating permissions for user and machine identities to restrict access to resources and the range of actions that can performed."
|
description: "Infisical's Role-based Access Controls enable creating permissions for user and machine identities to restrict access to resources and the range of actions that can be performed."
|
||||||
---
|
---
|
||||||
|
|
||||||
### General access controls
|
### General access controls
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "Infisical",
|
"name": "Infisical",
|
||||||
"basePath": "/docs",
|
|
||||||
"logo": {
|
"logo": {
|
||||||
"dark": "/docs/logo/dark.svg",
|
"dark": "/logo/dark.svg",
|
||||||
"light": "/docs/logo/light.svg",
|
"light": "/logo/light.svg",
|
||||||
"href": "https://infisical.com"
|
"href": "https://infisical.com"
|
||||||
},
|
},
|
||||||
"favicon": "/favicon.png",
|
"favicon": "/favicon.png",
|
||||||
|
@ -30,11 +30,10 @@ export const AdminDashboardPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto max-w-7xl pb-12 text-white dark:[color-scheme:dark]">
|
<div className="container mx-auto max-w-7xl pb-12 text-white dark:[color-scheme:dark]">
|
||||||
<div className="mb-8">
|
<div className="mx-auto mb-6 w-full max-w-7xl py-6 px-6">
|
||||||
<div className="mb-4 mt-6 flex flex-col items-start justify-between text-xl">
|
<div className="mb-8 flex flex-col items-start justify-between text-xl">
|
||||||
<h1 className="text-3xl font-semibold">Admin Dashboard</h1>
|
<h1 className="text-3xl font-semibold">Admin Dashboard</h1>
|
||||||
<p className="text-base text-bunker-300">Manage your Infisical</p>
|
<p className="text-base text-bunker-300">Manage your Infisical instance.</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{isUserLoading || isNotAllowed ? (
|
{isUserLoading || isNotAllowed ? (
|
||||||
<ContentLoader text={isNotAllowed ? "Redirecting to org page..." : undefined} />
|
<ContentLoader text={isNotAllowed ? "Redirecting to org page..." : undefined} />
|
||||||
@ -60,5 +59,6 @@ export const AdminDashboardPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -61,7 +61,7 @@ export const SignUpPage = () => {
|
|||||||
router.push("/login");
|
router.push("/login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [config?.initialized]);
|
}, []);
|
||||||
|
|
||||||
const { mutateAsync: createAdminUser } = useCreateAdminUser();
|
const { mutateAsync: createAdminUser } = useCreateAdminUser();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user