UNPKG

dagger-env

Version:

A type-safe, reusable environment configuration abstraction for Dagger modules.

109 lines 4.29 kB
import { z } from 'zod/v4'; import { $, fs } from 'zx'; import { OPItem, OPSection } from './op.js'; export const InfisicalSecret = z.object({ key: z.string(), value: z.string(), }); /** * Fetches secrets from Infisical via `infisical export` */ async function fetchInfisicalSecrets(config) { const exportedSecrets = InfisicalSecret.array().parse(await $ `infisical export --silent --format=json --projectId ${config.projectId} --env ${config.env} --path ${config.path}`.json()); return exportedSecrets.reduce((acc, s) => { acc[s.key] = s.value; return acc; }, {}); } /** * Fetches secrets from a 1Password item, filtered to the configured sections */ async function fetchOnePasswordSecrets(config) { const opItem = OPItem.parse(await $ `op item get ${config.opItem} --vault ${config.opVault} --format json`.json()); const sectionsToInclude = OPSection.array().parse(config.opSections); return opItem.fields .filter((f) => sectionsToInclude.some((s) => s.id === f.section?.id)) .reduce((acc, f) => { acc[f.label] = f.value; return acc; }, {}); } export function createDaggerCommandRunner(config) { return async function runDaggerCommand(commandName, options) { const { args = {}, env = {}, extraArgs = [] } = options ?? {}; // Run any pre-command setup if (config.beforeCommand) { await config.beforeCommand(); } // Environment variables to pass to the spawned command const envVars = {}; const commandArgs = [...extraArgs]; // Add Docker socket for specific commands if available if (config.dockerCommands?.includes(commandName)) { try { if (await fs.exists('/var/run/docker.sock')) { commandArgs.push('--docker-socket=/var/run/docker.sock'); } } catch { // Ignore if fs is not available or docker socket doesn't exist } } // Fetch secrets from the configured provider let secrets; if ('opVault' in config) { secrets = await fetchOnePasswordSecrets(config); // Pass dagger cloud token in CI because we don't have user auth. // The op:// reference is resolved by the `op run` wrapper below. if (process.env.CI !== undefined) { envVars.DAGGER_CLOUD_TOKEN = `op://${config.opVault}/${config.opItem}/DAGGER_CLOUD_TOKEN`; } } else { secrets = await fetchInfisicalSecrets(config); // Pass dagger cloud token in CI because we don't have user auth if (process.env.CI !== undefined && secrets.DAGGER_CLOUD_TOKEN !== undefined) { envVars.DAGGER_CLOUD_TOKEN = secrets.DAGGER_CLOUD_TOKEN; } } for (const [name, value] of Object.entries(config.additionalSecrets ?? {})) { if (value !== undefined) { secrets[name] = value; } } // Build environment variables for Dagger const daggerEnv = { ...env }; if (process.env.CI !== undefined) { daggerEnv.CI = process.env.CI; } if (process.env.GITHUB_ACTIONS !== undefined) { daggerEnv.GITHUB_ACTIONS = process.env.GITHUB_ACTIONS; } // Validate and serialize dagger options const daggerOptions = config.daggerEnv.getOptionsSchema().parse({ args, env: daggerEnv, secrets, }); envVars.DAGGER_OPTIONS = JSON.stringify(daggerOptions); // Construct the command. 1Password wraps `dagger call` in `op run` // so that op:// references in the environment are resolved. const cmd = [ ...('opVault' in config ? ['op', 'run', '--no-masking', '--'] : []), 'dagger', 'call', commandName, ...commandArgs, '--options=env://DAGGER_OPTIONS', ]; // Execute the command await $({ env: { ...process.env, ...envVars, }, stdio: 'inherit', }) `${cmd}`; }; } //# sourceMappingURL=run-dagger-cmd.js.map