Merge pull request #3272 from akhilmhdh/feat/metadata-audit-log

Permission metadata data in audit log
This commit is contained in:
Maidul Islam
2025-03-20 13:47:52 -04:00
committed by GitHub
14 changed files with 382 additions and 376 deletions
+1
View File
@@ -106,6 +106,7 @@ declare module "@fastify/request-context" {
claims: Record<string, string>; claims: Record<string, string>;
}; };
}; };
identityPermissionMetadata?: Record<string, unknown>; // filled by permission service
} }
} }
@@ -1,8 +1,10 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { requestContext } from "@fastify/request-context";
import { ActionProjectType } from "@app/db/schemas"; import { ActionProjectType } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { ActorType } from "@app/services/auth/auth-type";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission"; import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
import { TPermissionServiceFactory } from "../permission/permission-service"; import { TPermissionServiceFactory } from "../permission/permission-service";
@@ -81,8 +83,12 @@ export const auditLogServiceFactory = ({
if (!data.projectId && !data.orgId) if (!data.projectId && !data.orgId)
throw new BadRequestError({ message: "Must specify either project id or org id" }); throw new BadRequestError({ message: "Must specify either project id or org id" });
} }
const el = { ...data };
return auditLogQueue.pushToLog(data); if (el.actor.type === ActorType.USER || el.actor.type === ActorType.IDENTITY) {
const permissionMetadata = requestContext.get("identityPermissionMetadata");
el.actor.metadata.permission = permissionMetadata;
}
return auditLogQueue.pushToLog(el);
}; };
return { return {
@@ -290,6 +290,7 @@ interface UserActorMetadata {
userId: string; userId: string;
email?: string | null; email?: string | null;
username: string; username: string;
permission?: Record<string, unknown>;
} }
interface ServiceActorMetadata { interface ServiceActorMetadata {
@@ -300,6 +301,7 @@ interface ServiceActorMetadata {
interface IdentityActorMetadata { interface IdentityActorMetadata {
identityId: string; identityId: string;
name: string; name: string;
permission?: Record<string, unknown>;
} }
interface ScimClientActorMetadata {} interface ScimClientActorMetadata {}
@@ -244,22 +244,20 @@ export const permissionServiceFactory = ({
const rules = buildProjectPermissionRules(rolePermissions.concat(additionalPrivileges)); const rules = buildProjectPermissionRules(rolePermissions.concat(additionalPrivileges));
const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false }); const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false });
const metadataKeyValuePair = escapeHandlebarsMissingDict( const unescapedMetadata = objectify(
objectify( userProjectPermission.metadata,
userProjectPermission.metadata, (i) => i.key,
(i) => i.key, (i) => i.value
(i) => i.value
),
"identity.metadata"
); );
const templateValue = { const metadataKeyValuePair = escapeHandlebarsMissingDict(unescapedMetadata, "identity.metadata");
id: userProjectPermission.userId, requestContext.set("identityPermissionMetadata", { metadata: unescapedMetadata });
username: userProjectPermission.username,
metadata: metadataKeyValuePair
};
const interpolateRules = templatedRules( const interpolateRules = templatedRules(
{ {
identity: templateValue identity: {
id: userProjectPermission.userId,
username: userProjectPermission.username,
metadata: metadataKeyValuePair
}
}, },
{ data: false } { data: false }
); );
@@ -331,15 +329,16 @@ export const permissionServiceFactory = ({
? escapeHandlebarsMissingDict(unescapedIdentityAuthInfo as never, "identity.auth") ? escapeHandlebarsMissingDict(unescapedIdentityAuthInfo as never, "identity.auth")
: {}; : {};
const metadataKeyValuePair = escapeHandlebarsMissingDict(unescapedMetadata, "identity.metadata"); const metadataKeyValuePair = escapeHandlebarsMissingDict(unescapedMetadata, "identity.metadata");
const templateValue = {
id: identityProjectPermission.identityId, requestContext.set("identityPermissionMetadata", { metadata: unescapedMetadata, auth: unescapedIdentityAuthInfo });
username: identityProjectPermission.username,
metadata: metadataKeyValuePair,
auth: identityAuthInfo
};
const interpolateRules = templatedRules( const interpolateRules = templatedRules(
{ {
identity: templateValue identity: {
id: identityProjectPermission.identityId,
username: identityProjectPermission.username,
metadata: metadataKeyValuePair,
auth: identityAuthInfo
}
}, },
{ data: false } { data: false }
); );
@@ -440,14 +439,13 @@ export const permissionServiceFactory = ({
), ),
"identity.metadata" "identity.metadata"
); );
const templateValue = {
id: userProjectPermission.userId,
username: userProjectPermission.username,
metadata: metadataKeyValuePair
};
const interpolateRules = templatedRules( const interpolateRules = templatedRules(
{ {
identity: templateValue identity: {
id: userProjectPermission.userId,
username: userProjectPermission.username,
metadata: metadataKeyValuePair
}
}, },
{ data: false } { data: false }
); );
@@ -487,14 +485,13 @@ export const permissionServiceFactory = ({
), ),
"identity.metadata" "identity.metadata"
); );
const templateValue = {
id: identityProjectPermission.identityId,
username: identityProjectPermission.username,
metadata: metadataKeyValuePair
};
const interpolateRules = templatedRules( const interpolateRules = templatedRules(
{ {
identity: templateValue identity: {
id: identityProjectPermission.identityId,
username: identityProjectPermission.username,
metadata: metadataKeyValuePair
}
}, },
{ data: false } { data: false }
); );
+61 -5
View File
@@ -9,20 +9,76 @@ description: "Track evert event action performed within Infisical projects."
If you're using Infisical Cloud, then it is available under the **Pro**, If you're using Infisical Cloud, then it is available under the **Pro**,
and **Enterprise Tier** with varying retention periods. If you're self-hosting Infisical, and **Enterprise Tier** with varying retention periods. If you're self-hosting Infisical,
then you should contact [email protected] to purchase an enterprise license to use it. then you should contact [email protected] to purchase an enterprise license to use it.
</Info> </Info>
Infisical provides audit logs for security and compliance teams to monitor information access. Infisical provides audit logs for security and compliance teams to monitor information access.
With the Audit Log functionality, teams can: With the Audit Log functionality, teams can:
- **Track** 40+ different events; - **Track** 40+ different events;
- **Filter** audit logs by event, actor, source, date or any combination of these filters; - **Filter** audit logs by event, actor, source, date or any combination of these filters;
- **Inspect** extensive metadata in the event of any suspicious activity or incident review. - **Inspect** extensive metadata in the event of any suspicious activity or incident review.
![Audit logs](../../images/platform/audit-logs/audit-logs-table.png) ![Audit logs](../../images/platform/audit-logs/audit-logs-table.png)
## Audit Log Structure
Each log contains the following data: Each log contains the following data:
- **Event**: The underlying action such as create, list, read, update, or delete secret(s). | Field | Type | Description | Purpose |
- **Actor**: The entity responsible for performing or causing the event; this can be a user or service. | ------------------------- | -------- | --------------------------------------------------------- | ------------------------------------------------------------- |
- **Timestamp**: The date and time at which point the event occurred. | **event** | Object | Contains details about the action performed | Captures what happened |
- **Source** (User agent + IP): The software (user agent) and network address (IP) from which the event was initiated. | event.type | String | The specific action that occurred (e.g., "create-secret") | Identifies the exact operation |
- **Metadata**: Additional data to provide context for each event. For example, this could be the path at which a secret was fetched from etc. | event.metadata | Object | Context-specific details about the event | Provides detailed information relevant to the specific action |
| **actor** | Object | Information about who performed the action | Identifies the responsible entity |
| actor.type | String | Category of actor (user, service, identity, etc.) | Distinguishes between human and non-human actors |
| actor.metadata | Object | Details about the specific actor | Provides identity information |
| actor.metadata.userId | String | Unique identifier for user actors | Links to specific user account |
| actor.metadata.email | String | Email address for user actors | Email of the executing user |
| actor.metadata.username | String | Username for user actors | Username of the executing user |
| actor.metadata.serviceId | String | Identifier for service actors | ID of specific service token |
| actor.metadata.identityId | String | Identifier for identity actors | ID to specific identity |
| actor.metadata.permission | Object | Permission context for the action | Shows permission template data when action was performed |
| **orgId** | String | Organization identifier | Indicates which organization the action occurred in |
| **projectId** | String | Project identifier | Indicates which project the action affected |
| **ipAddress** | String | Source IP address | Shows where the request originated from |
| **userAgent** | String | Client application information | Identifies browser or application used |
| **userAgentType** | String | Category of client (web, CLI, SDK, etc.) | Classifies the access method |
| **timestamp** | DateTime | When the action occurred | Records the exact time of the event |
<Accordion title="Example Payload">
```json
{
"id": "[UUID]",
"ipAddress": "[IP_ADDRESS]",
"userAgent": "[USER_AGENT_STRING]",
"userAgentType": "web",
"expiresAt": "[TIMESTAMP]",
"createdAt": "[TIMESTAMP]",
"updatedAt": "[TIMESTAMP]",
"orgId": "[ORGANIZATION_UUID]",
"projectId": "[PROJECT_UUID]",
"projectName": "[PROJECT_NAME]",
"event": {
"type": "get-secrets",
"metadata": {
"secretPath": "[PATH]",
"environment": "[ENVIRONMENT_NAME]",
"numberOfSecrets": [NUMBER]
}
},
"actor": {
"type": "user",
"metadata": {
"email": "[EMAIL]",
"userId": "[USER_UUID]",
"username": "[USERNAME]",
"permission": {
"metadata": {},
"auth": {}
}
}
}
}
```
</Accordion>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 430 KiB

+193 -158
View File
@@ -362,26 +362,26 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.26.0", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz",
"integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/template": "^7.25.9", "@babel/template": "^7.26.9",
"@babel/types": "^7.26.0" "@babel/types": "^7.26.10"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.26.3", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz",
"integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/types": "^7.26.3" "@babel/types": "^7.26.10"
}, },
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
@@ -423,9 +423,9 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.26.0", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz",
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
@@ -435,14 +435,14 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.25.9", "version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
"integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.25.9", "@babel/code-frame": "^7.26.2",
"@babel/parser": "^7.25.9", "@babel/parser": "^7.26.9",
"@babel/types": "^7.25.9" "@babel/types": "^7.26.9"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@@ -476,9 +476,9 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.26.3", "version": "7.26.10",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz",
"integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.25.9", "@babel/helper-string-parser": "^7.25.9",
@@ -1010,6 +1010,23 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
"integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
@@ -1028,9 +1045,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-arm64": { "node_modules/@esbuild/openbsd-arm64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
"integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1647,12 +1664,12 @@
} }
}, },
"node_modules/@octokit/endpoint": { "node_modules/@octokit/endpoint": {
"version": "10.1.1", "version": "10.1.3",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
"integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", "integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^13.0.0", "@octokit/types": "^13.6.2",
"universal-user-agent": "^7.0.2" "universal-user-agent": "^7.0.2"
}, },
"engines": { "engines": {
@@ -1674,18 +1691,18 @@
} }
}, },
"node_modules/@octokit/openapi-types": { "node_modules/@octokit/openapi-types": {
"version": "22.2.0", "version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==", "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@octokit/plugin-paginate-rest": { "node_modules/@octokit/plugin-paginate-rest": {
"version": "11.3.6", "version": "11.6.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.6.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.6.0.tgz",
"integrity": "sha512-zcvqqf/+TicbTCa/Z+3w4eBJcAxCFymtc0UAIsR3dEVoNilWld4oXdscQ3laXamTszUZdusw97K8+DrbFiOwjw==", "integrity": "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^13.6.2" "@octokit/types": "^13.10.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"
@@ -1722,14 +1739,15 @@
} }
}, },
"node_modules/@octokit/request": { "node_modules/@octokit/request": {
"version": "9.1.3", "version": "9.2.2",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.3.tgz", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
"integrity": "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==", "integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/endpoint": "^10.0.0", "@octokit/endpoint": "^10.1.3",
"@octokit/request-error": "^6.0.1", "@octokit/request-error": "^6.1.7",
"@octokit/types": "^13.1.0", "@octokit/types": "^13.6.2",
"fast-content-type-parse": "^2.0.0",
"universal-user-agent": "^7.0.2" "universal-user-agent": "^7.0.2"
}, },
"engines": { "engines": {
@@ -1737,12 +1755,12 @@
} }
}, },
"node_modules/@octokit/request-error": { "node_modules/@octokit/request-error": {
"version": "6.1.5", "version": "6.1.7",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.5.tgz", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
"integrity": "sha512-IlBTfGX8Yn/oFPMwSfvugfncK2EwRLjzbrpifNaMY8o/HTEAFqCA1FZxjD9cWvSKBHgrIhc4CSBIzMxiLsbzFQ==", "integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^13.0.0" "@octokit/types": "^13.6.2"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"
@@ -1764,12 +1782,12 @@
} }
}, },
"node_modules/@octokit/types": { "node_modules/@octokit/types": {
"version": "13.6.2", "version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-WpbZfZUcZU77DrSW4wbsSgTPfKcp286q3ItaIgvSbBpZJlu6mnYXAkjZz6LVZPXkEvLIM8McanyZejKTYUHipA==", "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^22.2.0" "@octokit/openapi-types": "^24.2.0"
} }
}, },
"node_modules/@peculiar/asn1-cms": { "node_modules/@peculiar/asn1-cms": {
@@ -4956,9 +4974,9 @@
} }
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.7.9", "version": "1.8.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.6",
@@ -5451,9 +5469,9 @@
"license": "CC-BY-4.0" "license": "CC-BY-4.0"
}, },
"node_modules/canvg": { "node_modules/canvg": {
"version": "3.0.10", "version": "3.0.11",
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
"integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
@@ -7314,6 +7332,22 @@
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
}, },
"node_modules/fast-content-type-parse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "MIT"
},
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -12588,13 +12622,13 @@
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/tsx": { "node_modules/tsx": {
"version": "4.19.2", "version": "4.19.3",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz",
"integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"esbuild": "~0.23.0", "esbuild": "~0.25.0",
"get-tsconfig": "^4.7.5" "get-tsconfig": "^4.7.5"
}, },
"bin": { "bin": {
@@ -12608,9 +12642,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/aix-ppc64": { "node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
"integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -12625,9 +12659,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/android-arm": { "node_modules/tsx/node_modules/@esbuild/android-arm": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
"integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -12642,9 +12676,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/android-arm64": { "node_modules/tsx/node_modules/@esbuild/android-arm64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
"integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -12659,9 +12693,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/android-x64": { "node_modules/tsx/node_modules/@esbuild/android-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
"integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12676,9 +12710,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/darwin-arm64": { "node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
"integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -12693,9 +12727,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/darwin-x64": { "node_modules/tsx/node_modules/@esbuild/darwin-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
"integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12710,9 +12744,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
"integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -12727,9 +12761,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/freebsd-x64": { "node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
"integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12744,9 +12778,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-arm": { "node_modules/tsx/node_modules/@esbuild/linux-arm": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
"integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -12761,9 +12795,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-arm64": { "node_modules/tsx/node_modules/@esbuild/linux-arm64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
"integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -12778,9 +12812,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-ia32": { "node_modules/tsx/node_modules/@esbuild/linux-ia32": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
"integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -12795,9 +12829,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-loong64": { "node_modules/tsx/node_modules/@esbuild/linux-loong64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
"integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -12812,9 +12846,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-mips64el": { "node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
"integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@@ -12829,9 +12863,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-ppc64": { "node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
"integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -12846,9 +12880,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-riscv64": { "node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
"integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -12863,9 +12897,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-s390x": { "node_modules/tsx/node_modules/@esbuild/linux-s390x": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
"integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -12880,9 +12914,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/linux-x64": { "node_modules/tsx/node_modules/@esbuild/linux-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
"integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12897,9 +12931,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/netbsd-x64": { "node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
"integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12914,9 +12948,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/openbsd-x64": { "node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
"integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12931,9 +12965,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/sunos-x64": { "node_modules/tsx/node_modules/@esbuild/sunos-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
"integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12948,9 +12982,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/win32-arm64": { "node_modules/tsx/node_modules/@esbuild/win32-arm64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
"integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -12965,9 +12999,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/win32-ia32": { "node_modules/tsx/node_modules/@esbuild/win32-ia32": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
"integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -12982,9 +13016,9 @@
} }
}, },
"node_modules/tsx/node_modules/@esbuild/win32-x64": { "node_modules/tsx/node_modules/@esbuild/win32-x64": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
"integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -12999,9 +13033,9 @@
} }
}, },
"node_modules/tsx/node_modules/esbuild": { "node_modules/tsx/node_modules/esbuild": {
"version": "0.23.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
"integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
@@ -13012,30 +13046,31 @@
"node": ">=18" "node": ">=18"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/aix-ppc64": "0.23.1", "@esbuild/aix-ppc64": "0.25.1",
"@esbuild/android-arm": "0.23.1", "@esbuild/android-arm": "0.25.1",
"@esbuild/android-arm64": "0.23.1", "@esbuild/android-arm64": "0.25.1",
"@esbuild/android-x64": "0.23.1", "@esbuild/android-x64": "0.25.1",
"@esbuild/darwin-arm64": "0.23.1", "@esbuild/darwin-arm64": "0.25.1",
"@esbuild/darwin-x64": "0.23.1", "@esbuild/darwin-x64": "0.25.1",
"@esbuild/freebsd-arm64": "0.23.1", "@esbuild/freebsd-arm64": "0.25.1",
"@esbuild/freebsd-x64": "0.23.1", "@esbuild/freebsd-x64": "0.25.1",
"@esbuild/linux-arm": "0.23.1", "@esbuild/linux-arm": "0.25.1",
"@esbuild/linux-arm64": "0.23.1", "@esbuild/linux-arm64": "0.25.1",
"@esbuild/linux-ia32": "0.23.1", "@esbuild/linux-ia32": "0.25.1",
"@esbuild/linux-loong64": "0.23.1", "@esbuild/linux-loong64": "0.25.1",
"@esbuild/linux-mips64el": "0.23.1", "@esbuild/linux-mips64el": "0.25.1",
"@esbuild/linux-ppc64": "0.23.1", "@esbuild/linux-ppc64": "0.25.1",
"@esbuild/linux-riscv64": "0.23.1", "@esbuild/linux-riscv64": "0.25.1",
"@esbuild/linux-s390x": "0.23.1", "@esbuild/linux-s390x": "0.25.1",
"@esbuild/linux-x64": "0.23.1", "@esbuild/linux-x64": "0.25.1",
"@esbuild/netbsd-x64": "0.23.1", "@esbuild/netbsd-arm64": "0.25.1",
"@esbuild/openbsd-arm64": "0.23.1", "@esbuild/netbsd-x64": "0.25.1",
"@esbuild/openbsd-x64": "0.23.1", "@esbuild/openbsd-arm64": "0.25.1",
"@esbuild/sunos-x64": "0.23.1", "@esbuild/openbsd-x64": "0.25.1",
"@esbuild/win32-arm64": "0.23.1", "@esbuild/sunos-x64": "0.25.1",
"@esbuild/win32-ia32": "0.23.1", "@esbuild/win32-arm64": "0.25.1",
"@esbuild/win32-x64": "0.23.1" "@esbuild/win32-ia32": "0.25.1",
"@esbuild/win32-x64": "0.25.1"
} }
}, },
"node_modules/tsyringe": { "node_modules/tsyringe": {
@@ -13552,9 +13587,9 @@
} }
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.11", "version": "5.4.14",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -18,7 +18,7 @@ export const AuditLogsPage = () => {
title="Audit logs" title="Audit logs"
description="Audit logs for security and compliance teams to monitor information access." description="Audit logs for security and compliance teams to monitor information access."
/> />
<LogsSection filterClassName="static py-2" showFilters isOrgAuditLogs showActorColumn /> <LogsSection filterClassName="static py-2" showFilters />
</div> </div>
</div> </div>
</div> </div>
@@ -10,7 +10,7 @@ import { ActorType, EventType, UserAgentType } from "@app/hooks/api/auditLogs/en
import { usePopUp } from "@app/hooks/usePopUp"; import { usePopUp } from "@app/hooks/usePopUp";
import { LogsFilter } from "./LogsFilter"; import { LogsFilter } from "./LogsFilter";
import { LogsTable, TAuditLogTableHeader } from "./LogsTable"; import { LogsTable } from "./LogsTable";
import { AuditLogFilterFormData, auditLogFilterFormSchema } from "./types"; import { AuditLogFilterFormData, auditLogFilterFormSchema } from "./types";
type Props = { type Props = {
@@ -25,22 +25,11 @@ type Props = {
showFilters?: boolean; showFilters?: boolean;
filterClassName?: string; filterClassName?: string;
isOrgAuditLogs?: boolean;
showActorColumn?: boolean;
remappedHeaders?: Partial<Record<TAuditLogTableHeader, string>>;
refetchInterval?: number; refetchInterval?: number;
}; };
export const LogsSection = withPermission( export const LogsSection = withPermission(
({ ({ presets, filterClassName, refetchInterval, showFilters }: Props) => {
presets,
filterClassName,
remappedHeaders,
isOrgAuditLogs,
showActorColumn,
refetchInterval,
showFilters
}: Props) => {
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const);
@@ -90,9 +79,6 @@ export const LogsSection = withPermission(
)} )}
<LogsTable <LogsTable
refetchInterval={refetchInterval} refetchInterval={refetchInterval}
remappedHeaders={remappedHeaders}
isOrgAuditLogs={isOrgAuditLogs}
showActorColumn={!!showActorColumn}
filter={{ filter={{
secretPath: debouncedSecretPath || undefined, secretPath: debouncedSecretPath || undefined,
eventMetadata: presets?.eventMetadata, eventMetadata: presets?.eventMetadata,
@@ -1,5 +1,6 @@
import { Fragment } from "react"; import { Fragment } from "react";
import { faFile } from "@fortawesome/free-solid-svg-icons"; import { faFile, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import {
Button, Button,
@@ -11,6 +12,7 @@ import {
Td, Td,
Th, Th,
THead, THead,
Tooltip,
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { useGetAuditLogs } from "@app/hooks/api"; import { useGetAuditLogs } from "@app/hooks/api";
@@ -19,32 +21,13 @@ import { TGetAuditLogsFilter } from "@app/hooks/api/auditLogs/types";
import { LogsTableRow } from "./LogsTableRow"; import { LogsTableRow } from "./LogsTableRow";
type Props = { type Props = {
isOrgAuditLogs?: boolean;
showActorColumn: boolean;
filter?: TGetAuditLogsFilter; filter?: TGetAuditLogsFilter;
remappedHeaders?: Partial<Record<TAuditLogTableHeader, string>>;
refetchInterval?: number; refetchInterval?: number;
}; };
const AUDIT_LOG_LIMIT = 15; const AUDIT_LOG_LIMIT = 15;
const TABLE_HEADERS = [ export const LogsTable = ({ filter, refetchInterval }: Props) => {
"Timestamp (MM/DD/YYYY)",
"Event",
"Project",
"Actor",
"Source",
"Metadata"
] as const;
export type TAuditLogTableHeader = (typeof TABLE_HEADERS)[number];
export const LogsTable = ({
showActorColumn,
isOrgAuditLogs,
filter,
remappedHeaders,
refetchInterval
}: Props) => {
// Determine the project ID for filtering // Determine the project ID for filtering
const filterProjectId = const filterProjectId =
// Use the projectId from the filter if it exists // Use the projectId from the filter if it exists
@@ -69,38 +52,37 @@ export const LogsTable = ({
<Table> <Table>
<THead> <THead>
<Tr> <Tr>
{TABLE_HEADERS.map((header, idx) => { <Th className="w-24" />
if ( <Th className="w-64">
(header === "Project" && !isOrgAuditLogs) || Timestamp
(header === "Actor" && !showActorColumn) <Tooltip
) { className="normal-case"
return null; content="Time displayed in your system's time zone."
} sideOffset={10}
>
return ( <FontAwesomeIcon icon={faInfoCircle} className="ml-1" />
<Th key={`table-header-${idx + 1}`}>{remappedHeaders?.[header] || header}</Th> </Tooltip>
); </Th>
})} <Th>Event</Th>
</Tr> </Tr>
</THead> </THead>
<TBody> <TBody>
{!isPending && {!isPending &&
data?.pages?.map((group, i) => ( data?.pages?.map((group, i) => (
<Fragment key={`audit-log-fragment-${i + 1}`}> <Fragment key={`audit-log-fragment-${i + 1}`}>
{group.map((auditLog) => ( {group.map((auditLog, index) => (
<LogsTableRow <LogsTableRow
showActorColumn={showActorColumn} rowNumber={index + i * AUDIT_LOG_LIMIT + 1}
isOrgAuditLogs={isOrgAuditLogs}
auditLog={auditLog} auditLog={auditLog}
key={`audit-log-${auditLog.id}`} key={`audit-log-${auditLog.id}`}
/> />
))} ))}
</Fragment> </Fragment>
))} ))}
{isPending && <TableSkeleton innerKey="logs-table" columns={5} key="logs" />} {isPending && <TableSkeleton innerKey="logs-table" columns={3} key="logs-loading" />}
{isEmpty && ( {isEmpty && (
<Tr> <Tr>
<Td colSpan={5}> <Td colSpan={3}>
<EmptyState title="No audit logs on file" icon={faFile} /> <EmptyState title="No audit logs on file" icon={faFile} />
</Td> </Td>
</Tr> </Tr>
@@ -1,128 +1,76 @@
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons"; import { faCaretDown, faCaretRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import { Td, Tooltip, Tr } from "@app/components/v2"; import { Td, Tr } from "@app/components/v2";
import { eventToNameMap, userAgentTTypeoNameMap } from "@app/hooks/api/auditLogs/constants"; import { useToggle } from "@app/hooks";
import { ActorType, EventType } from "@app/hooks/api/auditLogs/enums"; import { ActorType } from "@app/hooks/api/auditLogs/enums";
import { Actor, AuditLog } from "@app/hooks/api/auditLogs/types"; import { AuditLog } from "@app/hooks/api/auditLogs/types";
type Props = { type Props = {
auditLog: AuditLog; auditLog: AuditLog;
isOrgAuditLogs?: boolean; rowNumber: number;
showActorColumn: boolean;
}; };
export const LogsTableRow = ({ auditLog, isOrgAuditLogs, showActorColumn }: Props) => { type TagProps = {
const renderActor = (actor: Actor) => { label: string;
if (!actor) { value?: string;
return <Td />; };
} const Tag = ({ label, value }: TagProps) => {
if (!value) return null;
switch (actor.type) {
case ActorType.USER:
return (
<Td>
<p>{actor.metadata.email}</p>
<p>User</p>
</Td>
);
case ActorType.SERVICE:
return (
<Td>
<p>{`${actor.metadata.name}`}</p>
<p>Service token</p>
</Td>
);
case ActorType.IDENTITY:
return (
<Td>
<p>{`${actor.metadata.name}`}</p>
<p>Machine Identity</p>
</Td>
);
case ActorType.PLATFORM:
return (
<Td>
<p>Platform</p>
</Td>
);
case ActorType.KMIP_CLIENT:
return (
<Td>
<p>{actor.metadata.name}</p>
<p>KMIP Client</p>
</Td>
);
case ActorType.UNKNOWN_USER:
return (
<Td>
<div className="flex items-center gap-2">
<p>Unknown User</p>
<Tooltip content="This action was performed by a user who was not authenticated at the time.">
<FontAwesomeIcon className="text-mineshaft-400" icon={faQuestionCircle} />
</Tooltip>
</div>
</Td>
);
default:
return <Td />;
}
};
const formatDate = (dateToFormat: string) => {
const date = new Date(dateToFormat);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
let hours = date.getHours();
const minutes = String(date.getMinutes()).padStart(2, "0");
// convert from 24h to 12h format
const period = hours >= 12 ? "PM" : "AM";
hours %= 12;
hours = hours || 12; // the hour '0' should be '12'
const formattedDate = `${month}-${day}-${year} at ${hours}:${minutes} ${period}`;
return formattedDate;
};
const renderSource = () => {
const { event, actor } = auditLog;
if (event.type === EventType.INTEGRATION_SYNCED) {
if (actor.type === ActorType.USER) {
return (
<Td>
<p>Manually triggered by {actor.metadata.email}</p>
</Td>
);
}
// Platform / automatic syncs
return (
<Td>
<p>Automatically synced by Infisical</p>
</Td>
);
}
return (
<Td>
<p>{userAgentTTypeoNameMap[auditLog.userAgentType]}</p>
<p>{auditLog.ipAddress}</p>
</Td>
);
};
return ( return (
<Tr className={`log-${auditLog.id} h-10 border-x-0 border-b border-t-0`}> <div className="flex items-center space-x-1.5">
<Td>{formatDate(auditLog.createdAt)}</Td> <div className="rounded bg-mineshaft-600 p-0.5 pl-1 font-mono">{label}:</div>
<Td>{`${eventToNameMap[auditLog.event.type]}`}</Td> <div>{value}</div>
{isOrgAuditLogs && <Td>{auditLog?.projectName ?? auditLog?.projectId ?? "N/A"}</Td>} </div>
{showActorColumn && renderActor(auditLog.actor)} );
{renderSource()} };
<Td className="max-w-xs break-all">{JSON.stringify(auditLog.event.metadata || {})}</Td>
</Tr> export const LogsTableRow = ({ auditLog, rowNumber }: Props) => {
const [isOpen, setIsOpen] = useToggle();
return (
<>
<Tr
className="h-10 cursor-pointer border-x-0 border-b border-t-0 hover:bg-mineshaft-700"
role="button"
tabIndex={0}
onClick={() => setIsOpen.toggle()}
onKeyDown={(evt) => {
if (evt.key === "Enter") setIsOpen.toggle();
}}
isHoverable
>
<Td className="flex items-center gap-2 pr-0 align-top">
<FontAwesomeIcon icon={isOpen ? faCaretDown : faCaretRight} />
{rowNumber}
</Td>
<Td className="align-top">
{format(new Date(auditLog.createdAt), "MMM do yyyy, hh:mm a")}
</Td>
<Td>
<div className="flex flex-wrap gap-4 text-sm">
<Tag label="event" value={auditLog.event.type} />
<Tag label="actor" value={auditLog.actor.type} />
{auditLog.actor.type === ActorType.USER && (
<Tag label="user_email" value={auditLog.actor.metadata.email} />
)}
{auditLog.actor.type === ActorType.IDENTITY && (
<Tag label="identity_name" value={auditLog.actor.metadata.name} />
)}
</div>
</Td>
</Tr>
{isOpen && (
<Tr className={`log-${auditLog.id} h-10 border-x-0 border-b border-t-0`}>
<Td colSpan={3} className="px-3 py-2">
<div className="thin-scrollbar my-1 max-h-96 overflow-auto whitespace-pre-wrap rounded border border-mineshaft-600 bg-bunker-800 p-2 font-mono leading-6">
{JSON.stringify(auditLog, null, 4)}
</div>
</Td>
</Tr>
)}
</>
); );
}; };
@@ -45,7 +45,6 @@ export const UserAuditLogsSection = withPermission(
presets={{ presets={{
actorId: orgMembership.user.id actorId: orgMembership.user.id
}} }}
isOrgAuditLogs
/> />
</div> </div>
) )
@@ -29,9 +29,6 @@ export const IntegrationAuditLogsSection = ({ integration }: Props) => {
</div> </div>
<LogsSection <LogsSection
refetchInterval={4000} refetchInterval={4000}
remappedHeaders={{
Metadata: "Sync Status"
}}
showFilters={false} showFilters={false}
presets={{ presets={{
eventMetadata: { integrationId: integration.id }, eventMetadata: { integrationId: integration.id },
@@ -35,9 +35,6 @@ export const SecretSyncAuditLogsSection = ({ secretSync }: Props) => {
{subscription.auditLogs ? ( {subscription.auditLogs ? (
<LogsSection <LogsSection
refetchInterval={4000} refetchInterval={4000}
remappedHeaders={{
Metadata: "Sync Status"
}}
showFilters={false} showFilters={false}
presets={{ presets={{
eventMetadata: { syncId: secretSync.id }, eventMetadata: { syncId: secretSync.id },