Refactoring Opportunity
Summary
- File:
src/commands/build-config.ts
- Current size: 246 lines
- Function of concern:
buildConfig spans lines 45–233 (190 lines — 77% of the file)
- Responsibilities identified: 3 distinct concerns in one function body
- Score: 7 (functions >80 lines +2, security-critical credential handling +2, clearly >2 responsibilities +3)
Evidence
buildConfig (lines 45–233) mixes three distinct concerns:
1. Optional struct construction (lines 75–111, ~37 lines)
Builds chrootIdentity and dind inline from raw option fragments:
const chrootIdentity = (
options.chrootIdentityHome !== undefined || ...
) ? { home: ..., user: ..., uid: ..., gid: ... } : undefined;
const dind = (
options.dindPreStageDirs !== undefined || ...
) ? { preStageDirs: ..., ... } : undefined;
These structs are complex enough that they obscure the function's primary purpose.
2. Credential resolution (lines 176–215, ~40 lines)
Directly reads API keys from process.env inline:
openaiApiKey: process.env[OPENAI_ENV.KEY],
anthropicApiKey: process.env[ANTHROPIC_ENV.KEY],
copilotGithubToken: process.env[COPILOT_ENV.GITHUB_TOKEN],
copilotProviderApiKey: process.env[COPILOT_ENV.PROVIDER_API_KEY],
geminiApiKey: process.env[GEMINI_ENV.KEY],
// ... auth type/provider/OIDC mappings via OIDC_AUTH_ENV_MAPPING
The function-level comment acknowledges this: "API keys are resolved from the process environment here to keep credential access centralised in one place" — but inline in a 190-line function is not the same as a dedicated module.
3. Config assembly (lines 113–175, 216–233, ~100 lines)
The mechanical mapping of all parsed options to WrapperConfig fields; this is the function's actual purpose but it is overshadowed by the above two concerns.
Proposed Split
buildConfig could be decomposed into:
-
src/commands/resolve-credentials.ts — resolveApiCredentials(): ApiCredentials
Reads all API keys and auth env vars in one dedicated place. Isolated from option-mapping logic. Easier to stub in tests.
-
src/commands/build-config.ts — buildConfig(inputs) reduced to ~120 lines
Delegates credential resolution to resolveApiCredentials() and calls small helper builders for chrootIdentity and dind sub-objects. The main body becomes a readable field-by-field mapping.
Affected Callers
Files that import from src/commands/build-config.ts and would need updating:
src/commands/validators/config-assembly.ts
src/commands/validators/config-assembly.test-utils.ts
src/commands/validate-options.test.ts
src/commands/build-config.test.ts
Effort Estimate
Low — the extraction is mechanical; no logic changes needed.
Benefits
buildConfig drops from 190 lines to ~120 lines
- Credential resolution becomes independently unit-testable (no need to pass a full
BuildConfigInputs to verify env-var reading)
- Easier security audits: reviewers can focus on
resolve-credentials.ts exclusively for the credential-access surface
chrootIdentity/dind builders become named helpers with clear input/output contracts
Detected by Refactoring Scanner workflow. Run date: 2026-07-01
Generated by Refactoring Opportunity Scanner · 173.9 AIC · ⊞ 7K · ◷
Refactoring Opportunity
Summary
src/commands/build-config.tsbuildConfigspans lines 45–233 (190 lines — 77% of the file)Evidence
buildConfig(lines 45–233) mixes three distinct concerns:1. Optional struct construction (lines 75–111, ~37 lines)
Builds
chrootIdentityanddindinline from raw option fragments:These structs are complex enough that they obscure the function's primary purpose.
2. Credential resolution (lines 176–215, ~40 lines)
Directly reads API keys from
process.envinline:The function-level comment acknowledges this: "API keys are resolved from the process environment here to keep credential access centralised in one place" — but inline in a 190-line function is not the same as a dedicated module.
3. Config assembly (lines 113–175, 216–233, ~100 lines)
The mechanical mapping of all parsed options to
WrapperConfigfields; this is the function's actual purpose but it is overshadowed by the above two concerns.Proposed Split
buildConfigcould be decomposed into:src/commands/resolve-credentials.ts—resolveApiCredentials(): ApiCredentialsReads all API keys and auth env vars in one dedicated place. Isolated from option-mapping logic. Easier to stub in tests.
src/commands/build-config.ts—buildConfig(inputs)reduced to ~120 linesDelegates credential resolution to
resolveApiCredentials()and calls small helper builders forchrootIdentityanddindsub-objects. The main body becomes a readable field-by-field mapping.Affected Callers
Files that import from
src/commands/build-config.tsand would need updating:Effort Estimate
Low — the extraction is mechanical; no logic changes needed.
Benefits
buildConfigdrops from 190 lines to ~120 linesBuildConfigInputsto verify env-var reading)resolve-credentials.tsexclusively for the credential-access surfacechrootIdentity/dindbuilders become named helpers with clear input/output contractsDetected by Refactoring Scanner workflow. Run date: 2026-07-01