mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 19:28:51 +00:00
feat(secret-sync): add re2 on replacements
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
import RE2 from "re2";
|
||||||
|
|
||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
@@ -13,6 +14,8 @@ import {
|
|||||||
TZabbixHostListResponse
|
TZabbixHostListResponse
|
||||||
} from "./zabbix-connection-types";
|
} from "./zabbix-connection-types";
|
||||||
|
|
||||||
|
const TRAILING_SLASH_REGEX = new RE2("/+$");
|
||||||
|
|
||||||
export const getZabbixConnectionListItem = () => {
|
export const getZabbixConnectionListItem = () => {
|
||||||
return {
|
return {
|
||||||
name: "Zabbix" as const,
|
name: "Zabbix" as const,
|
||||||
@@ -26,7 +29,7 @@ export const validateZabbixConnectionCredentials = async (config: TZabbixConnect
|
|||||||
await blockLocalAndPrivateIpAddresses(instanceUrl);
|
await blockLocalAndPrivateIpAddresses(instanceUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiUrl = `${instanceUrl.replace(/\/$/, "")}/api_jsonrpc.php`;
|
const apiUrl = `${instanceUrl.replace(TRAILING_SLASH_REGEX, "")}/api_jsonrpc.php`;
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
@@ -66,7 +69,7 @@ export const listZabbixHosts = async (appConnection: TZabbixConnection): Promise
|
|||||||
await blockLocalAndPrivateIpAddresses(instanceUrl);
|
await blockLocalAndPrivateIpAddresses(instanceUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiUrl = `${instanceUrl.replace(/\/$/, "")}/api_jsonrpc.php`;
|
const apiUrl = `${instanceUrl.replace(TRAILING_SLASH_REGEX, "")}/api_jsonrpc.php`;
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import RE2 from "re2";
|
||||||
|
|
||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||||
@@ -13,6 +15,14 @@ import {
|
|||||||
|
|
||||||
import { ZabbixSyncScope } from "./zabbix-sync-enums";
|
import { ZabbixSyncScope } from "./zabbix-sync-enums";
|
||||||
|
|
||||||
|
const TRAILING_SLASH_REGEX = new RE2("/+$");
|
||||||
|
const MACRO_START_REGEX = new RE2("^\\{\\$");
|
||||||
|
const MACRO_END_REGEX = new RE2("\\}$");
|
||||||
|
|
||||||
|
const extractMacroKey = (macro: string): string => {
|
||||||
|
return macro.replace(MACRO_START_REGEX, "").replace(MACRO_END_REGEX, "");
|
||||||
|
};
|
||||||
|
|
||||||
// Helper function to handle Zabbix API responses and errors
|
// Helper function to handle Zabbix API responses and errors
|
||||||
const handleZabbixResponse = <T>(response: ZabbixApiResponse<T>): T => {
|
const handleZabbixResponse = <T>(response: ZabbixApiResponse<T>): T => {
|
||||||
if (response.data.error) {
|
if (response.data.error) {
|
||||||
@@ -34,7 +44,7 @@ const handleZabbixResponse = <T>(response: ZabbixApiResponse<T>): T => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listZabbixSecrets = async (apiToken: string, instanceUrl: string, hostId?: string): Promise<TZabbixSecret[]> => {
|
const listZabbixSecrets = async (apiToken: string, instanceUrl: string, hostId?: string): Promise<TZabbixSecret[]> => {
|
||||||
const apiUrl = `${instanceUrl.replace(/\/$/, "")}/api_jsonrpc.php`;
|
const apiUrl = `${instanceUrl.replace(TRAILING_SLASH_REGEX, "")}/api_jsonrpc.php`;
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
jsonrpc: "2.0" as const,
|
jsonrpc: "2.0" as const,
|
||||||
@@ -66,7 +76,7 @@ const putZabbixSecrets = async (
|
|||||||
destinationConfig: TZabbixSyncWithCredentials["destinationConfig"],
|
destinationConfig: TZabbixSyncWithCredentials["destinationConfig"],
|
||||||
existingSecrets: TZabbixSecret[]
|
existingSecrets: TZabbixSecret[]
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const apiUrl = `${instanceUrl.replace(/\/$/, "")}/api_jsonrpc.php`;
|
const apiUrl = `${instanceUrl.replace(TRAILING_SLASH_REGEX, "")}/api_jsonrpc.php`;
|
||||||
const hostId = destinationConfig.scope === ZabbixSyncScope.Host ? destinationConfig.hostId : undefined;
|
const hostId = destinationConfig.scope === ZabbixSyncScope.Host ? destinationConfig.hostId : undefined;
|
||||||
|
|
||||||
const existingMacroMap = new Map(existingSecrets.map((secret) => [secret.macro, secret]));
|
const existingMacroMap = new Map(existingSecrets.map((secret) => [secret.macro, secret]));
|
||||||
@@ -147,7 +157,7 @@ const deleteZabbixSecrets = async (
|
|||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
if (keys.length === 0) return;
|
if (keys.length === 0) return;
|
||||||
|
|
||||||
const apiUrl = `${instanceUrl.replace(/\/$/, "")}/api_jsonrpc.php`;
|
const apiUrl = `${instanceUrl.replace(TRAILING_SLASH_REGEX, "")}/api_jsonrpc.php`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get existing macros to find their IDs
|
// Get existing macros to find their IDs
|
||||||
@@ -214,7 +224,7 @@ export const ZabbixSyncFns = {
|
|||||||
.filter(
|
.filter(
|
||||||
(secret) =>
|
(secret) =>
|
||||||
matchesSchema(secret.macro, environment?.slug || "", secretSync.syncOptions.keySchema) &&
|
matchesSchema(secret.macro, environment?.slug || "", secretSync.syncOptions.keySchema) &&
|
||||||
!shapedSecretMapKeys.includes(secret.macro.replace(/^\{\$/, "").replace(/\}$/, ""))
|
!shapedSecretMapKeys.includes(extractMacroKey(secret.macro))
|
||||||
)
|
)
|
||||||
.map((secret) => secret.macro);
|
.map((secret) => secret.macro);
|
||||||
|
|
||||||
@@ -238,7 +248,7 @@ export const ZabbixSyncFns = {
|
|||||||
|
|
||||||
const shapedSecretMapKeys = Object.keys(secretMap).map((key) => key.toUpperCase());
|
const shapedSecretMapKeys = Object.keys(secretMap).map((key) => key.toUpperCase());
|
||||||
const keys = secrets
|
const keys = secrets
|
||||||
.filter((secret) => shapedSecretMapKeys.includes(secret.macro.replace(/^\{\$/, "").replace(/\}$/, "")))
|
.filter((secret) => shapedSecretMapKeys.includes(extractMacroKey(secret.macro)))
|
||||||
.map((secret) => secret.macro);
|
.map((secret) => secret.macro);
|
||||||
|
|
||||||
await deleteZabbixSecrets(apiToken, instanceUrl, keys, hostId);
|
await deleteZabbixSecrets(apiToken, instanceUrl, keys, hostId);
|
||||||
@@ -259,7 +269,7 @@ export const ZabbixSyncFns = {
|
|||||||
const secrets = await listZabbixSecrets(apiToken, instanceUrl, hostId);
|
const secrets = await listZabbixSecrets(apiToken, instanceUrl, hostId);
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
secrets.map((secret) => [
|
secrets.map((secret) => [
|
||||||
secret.macro.replace(/^\{\$/, "").replace(/\}$/, ""),
|
extractMacroKey(secret.macro),
|
||||||
{ value: secret.value ?? "", comment: secret.description }
|
{ value: secret.value ?? "", comment: secret.description }
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ Infisical supports the use of [API Tokens](https://www.zabbix.com/documentation/
|
|||||||
"app": "zabbix",
|
"app": "zabbix",
|
||||||
"method": "api-token",
|
"method": "api-token",
|
||||||
"credentials": {
|
"credentials": {
|
||||||
"instanceUrl": "https://zabbix.example.com",
|
"instanceUrl": "https://zabbix.example.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ description: "Learn how to configure a Zabbix Sync for Infisical."
|
|||||||
- **Zabbix Connection**: The Zabbix Connection to authenticate with.
|
- **Zabbix Connection**: The Zabbix Connection to authenticate with.
|
||||||
- **Scope**: The Zabbix scope to sync secrets to.
|
- **Scope**: The Zabbix scope to sync secrets to.
|
||||||
- **Global**: Secrets will be synced globally.
|
- **Global**: Secrets will be synced globally.
|
||||||
- **Host**: Secrets will be synced to the specified host
|
- **Host**: Secrets will be synced to the specified host.
|
||||||
- **Macro Type**: The type of macro to use when syncing secrets to Zabbix.
|
- **Macro Type**: The type of macro to use when syncing secrets to Zabbix. Currently only **Text** and **Secret** macros are supported.
|
||||||
The remaining fields are determined by the selected **Scope**:
|
The remaining fields are determined by the selected **Scope**:
|
||||||
<AccordionGroup>
|
<AccordionGroup>
|
||||||
<Accordion title="Host">
|
<Accordion title="Host">
|
||||||
|
|||||||
+3
-1
@@ -5,6 +5,8 @@ import { GenericFieldLabel } from "@app/components/v2";
|
|||||||
import { ZabbixSyncScope } from "@app/hooks/api/appConnections/zabbix";
|
import { ZabbixSyncScope } from "@app/hooks/api/appConnections/zabbix";
|
||||||
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||||
|
|
||||||
|
const isTextMacro = (macroType: number) => macroType === 0;
|
||||||
|
|
||||||
export const ZabbixSyncReviewFields = () => {
|
export const ZabbixSyncReviewFields = () => {
|
||||||
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.Zabbix }>();
|
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.Zabbix }>();
|
||||||
const scope = watch("destinationConfig.scope");
|
const scope = watch("destinationConfig.scope");
|
||||||
@@ -22,7 +24,7 @@ export const ZabbixSyncReviewFields = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<GenericFieldLabel label="Macro Type">
|
<GenericFieldLabel label="Macro Type">
|
||||||
{macroType === 0 ? "Text" : "Secret"}
|
{isTextMacro(macroType) ? "Text" : "Secret"}
|
||||||
</GenericFieldLabel>
|
</GenericFieldLabel>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
+3
-1
@@ -6,6 +6,8 @@ type Props = {
|
|||||||
secretSync: TZabbixSync;
|
secretSync: TZabbixSync;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isTextMacro = (macroType: number) => macroType === 0;
|
||||||
|
|
||||||
export const ZabbixSyncDestinationSection = ({ secretSync }: Props) => {
|
export const ZabbixSyncDestinationSection = ({ secretSync }: Props) => {
|
||||||
const {
|
const {
|
||||||
destinationConfig: { macroType }
|
destinationConfig: { macroType }
|
||||||
@@ -24,7 +26,7 @@ export const ZabbixSyncDestinationSection = ({ secretSync }: Props) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<GenericFieldLabel label="Macro Type">
|
<GenericFieldLabel label="Macro Type">
|
||||||
{macroType === 0 ? "Text" : "Secret"}
|
{isTextMacro(macroType) ? "Text" : "Secret"}
|
||||||
</GenericFieldLabel>
|
</GenericFieldLabel>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user