Merge branch 'dev' into add-more-openapi

This commit is contained in:
Meier Lukas committed 2025-09-14 16:01:24 +02:00
commit 5332f0d5c0
155 files changed
+8504 -3050

No files matched your search

@@ -25,16 +25,6 @@ export const testConnectionAsync = async (
integrationUrl: integration.url,
});
const formSecrets = integration.secrets
.filter((secret) => secret.value !== null)
.map((secret) => ({
...secret,
// We ensured above that the value is not null
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
value: secret.value!,
source: "form" as const,
}));
const decryptedDbSecrets = dbSecrets
.map((secret) => {
try {
@@ -55,6 +45,15 @@ export const testConnectionAsync = async (
})
.filter((secret) => secret !== null);
const formSecrets = integration.secrets
.map((secret) => ({
...secret,
// If the value is not defined in the form (because we only changed other values) we use the existing value from the db if it exists
value: secret.value ?? decryptedDbSecrets.find((dbSecret) => dbSecret.kind === secret.kind)?.value ?? null,
source: "form" as const,
}))
.filter((secret): secret is SourcedIntegrationSecret<"form"> => secret.value !== null);
const sourcedSecrets = [...formSecrets, ...decryptedDbSecrets];
const secretKinds = getSecretKindOption(integration.kind, sourcedSecrets);
@@ -89,10 +88,10 @@ export const testConnectionAsync = async (
return result;
};
interface SourcedIntegrationSecret {
interface SourcedIntegrationSecret<TSource extends string = "db" | "form"> {
kind: IntegrationSecretKind;
value: string;
source: "db" | "form";
source: TSource;
}
const getSecretKindOption = (kind: IntegrationKind, sourcedSecrets: SourcedIntegrationSecret[]) => {
@@ -111,7 +110,9 @@ const getSecretKindOption = (kind: IntegrationKind, sourcedSecrets: SourcedInteg
}
const onlyFormSecretsKindOptions = matchingSecretKindOptions.filter((secretKinds) =>
sourcedSecrets.filter((secret) => secretKinds.includes(secret.kind)).every((secret) => secret.source === "form"),
secretKinds.every((secretKind) =>
sourcedSecrets.find((secret) => secret.kind === secretKind && secret.source === "form"),
),
);
if (onlyFormSecretsKindOptions.length >= 1) {
@@ -184,12 +184,23 @@ function getProviders(versionInfo: VersionInfo, nodes: V1NodeList) {
if (versionInfo.gitVersion.includes("aks")) providers.add("AKS");
nodes.items.forEach((node) => {
const nodeProviderLabel =
node.metadata?.labels?.["node.kubernetes.io/instance-type"] ?? node.metadata?.labels?.provider ?? "";
const labels = node.metadata?.labels ?? {};
const nodeProviderLabel = labels["node.kubernetes.io/instance-type"] ?? labels.provider ?? "";
if (nodeProviderLabel.includes("aws")) providers.add("EKS");
if (nodeProviderLabel.includes("azure")) providers.add("AKS");
if (nodeProviderLabel.includes("gce")) providers.add("GKE");
if (nodeProviderLabel.includes("k3s")) providers.add("k3s");
const nodeInfo = node.status?.nodeInfo;
if (nodeInfo) {
const osImage = nodeInfo.osImage.toLowerCase();
const kernelVersion = nodeInfo.kernelVersion.toLowerCase();
if (osImage.includes("talos") || kernelVersion.includes("talos")) {
providers.add("Talos");
}
}
});
return Array.from(providers).join(", ");
@@ -265,4 +265,77 @@ describe("testConnectionAsync should run test connection of integration", () =>
],
});
});
test("with input of existing github app", async () => {
// Arrange
const factorySpy = vi.spyOn(homarrIntegrations, "createIntegrationAsync");
const optionsSpy = vi.spyOn(homarrDefinitions, "getAllSecretKindOptions");
factorySpy.mockReturnValue(
Promise.resolve({
testConnectionAsync: async () => await Promise.resolve({ success: true }),
} as homarrIntegrations.PiHoleIntegrationV6),
);
optionsSpy.mockReturnValue([[], ["githubAppId", "githubInstallationId", "privateKey"]]);
const integration = {
id: "new",
name: "GitHub",
url: "https://api.github.com",
kind: "github" as const,
secrets: [
{
kind: "githubAppId" as const,
value: "345",
},
{
kind: "githubInstallationId" as const,
value: "456",
},
{
kind: "privateKey" as const,
value: null,
},
],
};
const dbSecrets = [
{
kind: "githubAppId" as const,
value: "123.encrypted" as const,
},
{
kind: "githubInstallationId" as const,
value: "234.encrypted" as const,
},
{
kind: "privateKey" as const,
value: "privateKey.encrypted" as const,
},
];
// Act
await testConnectionAsync(integration, dbSecrets);
// Assert
expect(factorySpy).toHaveBeenCalledWith({
id: "new",
name: "GitHub",
url: "https://api.github.com",
kind: "github" as const,
decryptedSecrets: [
expect.objectContaining({
kind: "githubAppId",
value: "345",
}),
expect.objectContaining({
kind: "githubInstallationId",
value: "456",
}),
expect.objectContaining({
kind: "privateKey",
value: "privateKey",
}),
],
});
});
});
@@ -9,7 +9,7 @@ import { createTRPCRouter, publicProcedure } from "../../trpc";
export const healthMonitoringRouter = createTRPCRouter({
getSystemHealthStatus: publicProcedure
.concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "mock"))
.concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "truenas", "mock"))
.query(async ({ ctx }) => {
return await Promise.all(
ctx.integrations.map(async (integration) => {
@@ -26,7 +26,7 @@ export const healthMonitoringRouter = createTRPCRouter({
);
}),
subscribeSystemHealthStatus: publicProcedure
.concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "mock"))
.concat(createManyIntegrationMiddleware("query", "openmediavault", "dashDot", "truenas", "mock"))
.subscription(({ ctx }) => {
return observable<{ integrationId: string; healthInfo: SystemHealthMonitoring; timestamp: Date }>((emit) => {
const unsubscribes: (() => void)[] = [];