Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions apps/server-nestjs/src/config/argocd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const nonEmptyString = z.string().transform(value => value.trim() || undefined)

const argocdFeatureSchema = z.object({
USE_ARGOCD: flagSchema.default(true),
ARGO_NAMESPACE: z.string().default('argocd'),
ARGOCD_URL: optionalUrl(z.string()).optional(),
ARGOCD_INTERNAL_URL: optionalUrl(z.string()).optional(),
ARGOCD_EXTRA_REPOSITORIES: nonEmptyString.optional(),
DSO_ENV_CHART_VERSION: z.string().default('dso-env-1.6.0'),
DSO_NS_CHART_VERSION: z.string().default('dso-ns-1.1.5'),
VAULT__DEPLOY_VAULT_CONNECTION_IN_NS: flagSchema.default(false),
})

export type ArgoCDConfig = z.infer<typeof argocdFeatureSchema>

export const KEY = 'argocd' as const

export type ArgoCDAppConfig = ArgoCDConfig

export const argocdConfigFactory = registerAs(KEY, () =>
argocdFeatureSchema.parse({
USE_ARGOCD: process.env.USE_ARGOCD,
ARGO_NAMESPACE: process.env.ARGO_NAMESPACE,
ARGOCD_URL: process.env.ARGOCD_URL,
ARGOCD_INTERNAL_URL: process.env.ARGOCD_INTERNAL_URL,
ARGOCD_EXTRA_REPOSITORIES: process.env.ARGOCD_EXTRA_REPOSITORIES,
DSO_ENV_CHART_VERSION: process.env.DSO_ENV_CHART_VERSION,
DSO_NS_CHART_VERSION: process.env.DSO_NS_CHART_VERSION,
VAULT__DEPLOY_VAULT_CONNECTION_IN_NS: process.env.VAULT__DEPLOY_VAULT_CONNECTION_IN_NS,
}))

export default argocdConfigFactory
64 changes: 64 additions & 0 deletions apps/server-nestjs/src/config/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const nonEmptyString = z.string().transform(value => value.trim() || undefined)

const baseConfigurationSchema = z
.object({
NODE_ENV: z.enum(['development', 'production', 'test']).optional(),
INTEGRATION: flagSchema.optional(),
CI: flagSchema.optional(),
DEV_SETUP: flagSchema.optional(),
DOCKER: flagSchema.optional(),
SERVER_HOST: z.string().default('localhost'),
SERVER_PORT: z.string().transform(Number).default('0'),
APP_VERSION: z.string().optional(),
DB_URL: z.string().url().optional(),
SESSION_SECRET: z.string().min(32).optional(),
CONTACT_EMAIL: z.string().email().default('cloudpinative-relations@interieur.gouv.fr'),
MOCK_PLUGINS: flagSchema.optional(),
PROJECTS_ROOT_DIR: nonEmptyString.optional(),
PLUGINS_DIR: z.string().default('/plugins'),
HTTP_PROXY: optionalUrl(z.string()).optional(),
HTTPS_PROXY: optionalUrl(z.string()).optional(),
})
.passthrough()
.transform(config => ({
...config,
NODE_ENV: config.NODE_ENV === 'test' ? 'test' : config.NODE_ENV === 'development' ? 'development' : 'production',
}))

export type BaseConfig = z.infer<typeof baseConfigurationSchema>

export const KEY = 'base' as const

export type BaseAppConfig = BaseConfig

export const baseConfigFactory = registerAs(KEY, () =>
baseConfigurationSchema.parse({
NODE_ENV: process.env.NODE_ENV,
INTEGRATION: process.env.INTEGRATION,
CI: process.env.CI,
DEV_SETUP: process.env.DEV_SETUP,
DOCKER: process.env.DOCKER,
SERVER_HOST: process.env.SERVER_HOST,
SERVER_PORT: process.env.SERVER_PORT,
APP_VERSION: process.env.APP_VERSION,
DB_URL: process.env.DB_URL,
SESSION_SECRET: process.env.SESSION_SECRET,
CONTACT_EMAIL: process.env.CONTACT_EMAIL,
MOCK_PLUGINS: process.env.MOCK_PLUGINS,
PROJECTS_ROOT_DIR: process.env.PROJECTS_ROOT_DIR,
PLUGINS_DIR: process.env.PLUGINS_DIR,
HTTP_PROXY: process.env.HTTP_PROXY,
HTTPS_PROXY: process.env.HTTPS_PROXY,
}))

export default baseConfigFactory
9 changes: 9 additions & 0 deletions apps/server-nestjs/src/config/configuration.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type { ArgoCDConfig } from './argocd'
export type { BaseConfig } from './base'
export type { GitlabConfig } from './gitlab'
export type { HarborConfig } from './harbor'
export type { KeycloakConfig } from './keycloak'
export type { NexusConfig } from './nexus'
export type { OpenCdsConfig } from './opencds'
export type { SonarqubeConfig } from './sonarqube'
export type { VaultConfig } from './vault'
36 changes: 36 additions & 0 deletions apps/server-nestjs/src/config/gitlab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const gitlabFeatureSchema = z.object({
USE_GITLAB: flagSchema.default(true),
GITLAB_TOKEN: z.string().min(1, 'GITLAB_TOKEN is required'),
GITLAB_URL: optionalUrl(z.string()).optional(),
GITLAB_INTERNAL_URL: optionalUrl(z.string()).optional(),
GITLAB_MIRROR_TOKEN_EXPIRATION_DAYS: z.coerce.number().int().positive().default(180),
GITLAB_MIRROR_TOKEN_ROTATION_THRESHOLD_DAYS: z.coerce.number().int().positive().default(90),
})

export type GitlabConfig = z.infer<typeof gitlabFeatureSchema>

export const KEY = 'gitlab' as const

export type GitlabAppConfig = GitlabConfig

export const gitlabConfigFactory = registerAs(KEY, () =>
gitlabFeatureSchema.parse({
USE_GITLAB: process.env.USE_GITLAB,
GITLAB_TOKEN: process.env.GITLAB_TOKEN,
GITLAB_URL: process.env.GITLAB_URL,
GITLAB_INTERNAL_URL: process.env.GITLAB_INTERNAL_URL,
GITLAB_MIRROR_TOKEN_EXPIRATION_DAYS: process.env.GITLAB_MIRROR_TOKEN_EXPIRATION_DAYS,
GITLAB_MIRROR_TOKEN_ROTATION_THRESHOLD_DAYS: process.env.GITLAB_MIRROR_TOKEN_ROTATION_THRESHOLD_DAYS,
}))

export default gitlabConfigFactory
44 changes: 44 additions & 0 deletions apps/server-nestjs/src/config/harbor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const harborFeatureSchema = z.object({
USE_HARBOR: flagSchema.default(true),
HARBOR_URL: optionalUrl(z.string()).optional(),
HARBOR_INTERNAL_URL: optionalUrl(z.string()).optional(),
HARBOR_ADMIN: z.string().min(1, 'HARBOR_ADMIN is required'),
HARBOR_ADMIN_PASSWORD: z.string().min(1, 'HARBOR_ADMIN_PASSWORD is required'),
HARBOR_RULE_TEMPLATE: z.string().min(1).optional(),
HARBOR_RULE_COUNT: z.coerce.number().int().nonnegative().optional(),
HARBOR_RETENTION_CRON: z.string().default('0 22 2 * * *'),
HARBOR_ROBOT_ROTATION_THRESHOLD_DAYS: z.coerce.number().int().positive().default(90),
HARBOR_PROJECT_SLUG_CACHE_TTL_MS: z.coerce.number().int().positive().default(300_000),
})

export type HarborConfig = z.infer<typeof harborFeatureSchema>

export const KEY = 'harbor' as const

export type HarborAppConfig = HarborConfig

export const harborConfigFactory = registerAs(KEY, () =>
harborFeatureSchema.parse({
USE_HARBOR: process.env.USE_HARBOR,
HARBOR_URL: process.env.HARBOR_URL,
HARBOR_INTERNAL_URL: process.env.HARBOR_INTERNAL_URL,
HARBOR_ADMIN: process.env.HARBOR_ADMIN,
HARBOR_ADMIN_PASSWORD: process.env.HARBOR_ADMIN_PASSWORD,
HARBOR_RULE_TEMPLATE: process.env.HARBOR_RULE_TEMPLATE,
HARBOR_RULE_COUNT: process.env.HARBOR_RULE_COUNT,
HARBOR_RETENTION_CRON: process.env.HARBOR_RETENTION_CRON,
HARBOR_ROBOT_ROTATION_THRESHOLD_DAYS: process.env.HARBOR_ROBOT_ROTATION_THRESHOLD_DAYS,
HARBOR_PROJECT_SLUG_CACHE_TTL_MS: process.env.HARBOR_PROJECT_SLUG_CACHE_TTL_MS,
}))

export default harborConfigFactory
59 changes: 59 additions & 0 deletions apps/server-nestjs/src/config/keycloak.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const nonEmptyString = z.string().transform(value => value.trim() || undefined)

const keycloakFeatureSchema = z.object({
USE_KEYCLOAK: flagSchema.default(true),
KEYCLOAK_PROTOCOL: z.string().default('https'),
KEYCLOAK_DOMAIN: nonEmptyString,
KEYCLOAK_PUBLIC_PROTOCOL: z.string().default('https'),
KEYCLOAK_PUBLIC_DOMAIN: nonEmptyString,
KEYCLOAK_REALM: nonEmptyString,
KEYCLOAK_CLIENT_ID: nonEmptyString,
KEYCLOAK_CLIENT_SECRET: nonEmptyString,
KEYCLOAK_ADMIN: nonEmptyString,
KEYCLOAK_ADMIN_PASSWORD: nonEmptyString,
KEYCLOAK_REDIRECT_URI: optionalUrl(z.string()).optional(),
KEYCLOAK_JWKS_CACHE_TTL_MS: z.coerce.number().int().positive().default(300_000),
KEYCLOAK_JWKS_TIMEOUT_MS: z.coerce.number().int().positive().default(5_000),
KEYCLOAK_OPENID_CONFIGURATION_CACHE_TTL_MS: z.coerce.number().int().positive().default(300_000),
ADMIN_KC_USER_ID: z.preprocess(
value => (typeof value === 'string' ? value.split(',').map(part => part.trim()).filter(Boolean) : value),
z.array(z.string()).default([]),
),
})

export type KeycloakConfig = z.infer<typeof keycloakFeatureSchema>

export const KEY = 'keycloak' as const

export type KeycloakAppConfig = KeycloakConfig

export const keycloakConfigFactory = registerAs(KEY, () =>
keycloakFeatureSchema.parse({
USE_KEYCLOAK: process.env.USE_KEYCLOAK,
KEYCLOAK_PROTOCOL: process.env.KEYCLOAK_PROTOCOL,
KEYCLOAK_DOMAIN: process.env.KEYCLOAK_DOMAIN,
KEYCLOAK_PUBLIC_PROTOCOL: process.env.KEYCLOAK_PUBLIC_PROTOCOL,
KEYCLOAK_PUBLIC_DOMAIN: process.env.KEYCLOAK_PUBLIC_DOMAIN,
KEYCLOAK_REALM: process.env.KEYCLOAK_REALM,
KEYCLOAK_CLIENT_ID: process.env.KEYCLOAK_CLIENT_ID,
KEYCLOAK_CLIENT_SECRET: process.env.KEYCLOAK_CLIENT_SECRET,
KEYCLOAK_ADMIN: process.env.KEYCLOAK_ADMIN,
KEYCLOAK_ADMIN_PASSWORD: process.env.KEYCLOAK_ADMIN_PASSWORD,
KEYCLOAK_REDIRECT_URI: process.env.KEYCLOAK_REDIRECT_URI,
KEYCLOAK_JWKS_CACHE_TTL_MS: process.env.KEYCLOAK_JWKS_CACHE_TTL_MS,
KEYCLOAK_JWKS_TIMEOUT_MS: process.env.KEYCLOAK_JWKS_TIMEOUT_MS,
KEYCLOAK_OPENID_CONFIGURATION_CACHE_TTL_MS: process.env.KEYCLOAK_OPENID_CONFIGURATION_CACHE_TTL_MS,
ADMIN_KC_USER_ID: process.env.ADMIN_KC_USER_ID,
}))

export default keycloakConfigFactory
36 changes: 36 additions & 0 deletions apps/server-nestjs/src/config/nexus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const nexusFeatureSchema = z.object({
USE_NEXUS: flagSchema.default(true),
NEXUS_URL: optionalUrl(z.string()).optional(),
NEXUS_INTERNAL_URL: optionalUrl(z.string()).optional(),
NEXUS_ADMIN: z.string().min(1, 'NEXUS_ADMIN is required'),
NEXUS_ADMIN_PASSWORD: z.string().min(1, 'NEXUS_ADMIN_PASSWORD is required'),
NEXUS__SECRET_EXPOSE_INTERNAL_URL: flagSchema.default(false),
})

export type NexusConfig = z.infer<typeof nexusFeatureSchema>

export const KEY = 'nexus' as const

export type NexusAppConfig = NexusConfig

export const nexusConfigFactory = registerAs(KEY, () =>
nexusFeatureSchema.parse({
USE_NEXUS: process.env.USE_NEXUS,
NEXUS_URL: process.env.NEXUS_URL,
NEXUS_INTERNAL_URL: process.env.NEXUS_INTERNAL_URL,
NEXUS_ADMIN: process.env.NEXUS_ADMIN,
NEXUS_ADMIN_PASSWORD: process.env.NEXUS_ADMIN_PASSWORD,
NEXUS__SECRET_EXPOSE_INTERNAL_URL: process.env.NEXUS__SECRET_EXPOSE_INTERNAL_URL,
}))

export default nexusConfigFactory
34 changes: 34 additions & 0 deletions apps/server-nestjs/src/config/opencds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const nonEmptyString = z.string().transform(value => value.trim() || undefined)

const opencdsFeatureSchema = z.object({
USE_OPENCDS: flagSchema.default(true),
OPENCDS_URL: optionalUrl(z.string()).optional(),
OPENCDS_API_TOKEN: nonEmptyString,
OPENCDS_API_TLS_REJECT_UNAUTHORIZED: flagSchema.default(false),
})

export type OpenCdsConfig = z.infer<typeof opencdsFeatureSchema>

export const KEY = 'opencds' as const

export type OpenCdsAppConfig = OpenCdsConfig

export const openCdsConfigFactory = registerAs(KEY, () =>
opencdsFeatureSchema.parse({
USE_OPENCDS: process.env.USE_OPENCDS,
OPENCDS_URL: process.env.OPENCDS_URL,
OPENCDS_API_TOKEN: process.env.OPENCDS_API_TOKEN,
OPENCDS_API_TLS_REJECT_UNAUTHORIZED: process.env.OPENCDS_API_TLS_REJECT_UNAUTHORIZED,
}))

export default openCdsConfigFactory
40 changes: 40 additions & 0 deletions apps/server-nestjs/src/config/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { registerAs } from '@nestjs/config'
import z from 'zod'

const flagSchema = z
.preprocess(val => (val === undefined ? 'false' : val), z.enum(['true', 'false', '']))
.transform(val => val === 'true')
.default(false)

const optionalUrl = (schema: z.ZodString) => schema.url().optional().or(z.literal('').transform(() => undefined))

const nonEmptyString = z.string().transform(value => value.trim() || undefined)

const registryFeatureSchema = z.object({
USE_REGISTRY: flagSchema.default(true),
REGISTRY_URL: optionalUrl(z.string()).optional(),
REGISTRY_INTERNAL_URL: optionalUrl(z.string()).optional(),
REGISTRY_ADMIN: nonEmptyString,
REGISTRY_ADMIN_PASSWORD: nonEmptyString,
REGISTRY_RULE_TEMPLATE: nonEmptyString.optional(),
REGISTRY_RULE_COUNT: z.coerce.number().int().nonnegative().optional(),
REGISTRY_RETENTION_CRON: z.string().default('0 22 2 * * *'),
REGISTRY_ROBOT_ROTATION_THRESHOLD_DAYS: z.coerce.number().int().positive().default(90),
REGISTRY_PROJECT_SLUG_CACHE_TTL_MS: z.coerce.number().int().positive().default(300_000),
})

export type RegistryConfig = z.infer<typeof registryFeatureSchema>

export default registerAs('registry', () =>
registryFeatureSchema.parse({
USE_REGISTRY: process.env.USE_REGISTRY,
REGISTRY_URL: process.env.REGISTRY_URL,
REGISTRY_INTERNAL_URL: process.env.REGISTRY_INTERNAL_URL,
REGISTRY_ADMIN: process.env.REGISTRY_ADMIN,
REGISTRY_ADMIN_PASSWORD: process.env.REGISTRY_ADMIN_PASSWORD,
REGISTRY_RULE_TEMPLATE: process.env.REGISTRY_RULE_TEMPLATE,
REGISTRY_RULE_COUNT: process.env.REGISTRY_RULE_COUNT,
REGISTRY_RETENTION_CRON: process.env.REGISTRY_RETENTION_CRON,
REGISTRY_ROBOT_ROTATION_THRESHOLD_DAYS: process.env.REGISTRY_ROBOT_ROTATION_THRESHOLD_DAYS,
REGISTRY_PROJECT_SLUG_CACHE_TTL_MS: process.env.REGISTRY_PROJECT_SLUG_CACHE_TTL_MS,
}))
Loading
Loading