feat(push): Introduce Push Mode Feature for Syncing Local Environment Variables to AWS SSM - #57
Conversation
…ove operation mode handling
…ing in DispatchActionCommandHandler
…andler for command execution
…er maintainability
…ager, ConsoleLogger, and PackageJsonFinder
- Added ExportSsmToEnvCommand and ExportSsmToEnvCommandHandler to handle exporting environment variables from AWS SSM to a local .env file. - Introduced ImportEnvToSsmCommand and ImportEnvToSsmCommandHandler for importing environment variables from a local .env file to AWS SSM. - Created PushSingleVariableCommand and PushSingleVariableCommandHandler for pushing individual environment variables to AWS SSM. - Defined CliOptions type for command line interface options. - Updated tests for new command handlers and removed obsolete tests.
…er tests for improved clarity
…shSingleVariableCommandHandler tests
…portEnvToSsmCommandHandler tests
…mportEnvToSsmCommandHandler
…ispatchActionCommandHandlerBuilder
…xportSsmToEnvCommandHandler and PushSingleVariableCommandHandler
…rors in command handlers and file manager
…te secret storage and retrieval
…tructors refactor(tests): remove empty lines in test files for cleaner code chore(biome): update schema version to 2.1.1
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/envilder/application/pullSsmToEnv/PullSsmToEnvCommandHandler.ts (1)
51-70: Consider removing unnecessary abstraction layer.The
saveEnvFilemethod is a simple wrapper that doesn't add value beyond what theenvFileManageralready provides. Consider callingenvFileManager.saveEnvFiledirectly in thehandlemethod.- private async saveEnvFile( - envFilePath: string, - variables: Record<string, string>, - ): Promise<void> { - await this.envFileManager.saveEnvFile(envFilePath, variables); - }And update the handle method:
- await this.saveEnvFile(command.envFilePath, envilded); + await this.envFileManager.saveEnvFile(command.envFilePath, envilded);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/envilder/application/pullSsmToEnv/PullSsmToEnvCommandHandler.ts(1 hunks)src/envilder/application/pushEnvToSsm/PushEnvToSsmCommandHandler.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/envilder/application/pushEnvToSsm/PushEnvToSsmCommandHandler.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: codeql-fortress (typescript)
- GitHub Check: powerup-test
🔇 Additional comments (3)
src/envilder/application/pullSsmToEnv/PullSsmToEnvCommandHandler.ts (3)
1-6: LGTM - Clean imports and dependency setup.The imports are well-organized, using proper TypeScript import syntax and maintaining clear separation of concerns between domain models, ports, and commands.
7-23: LGTM - Good use of dependency injection and constants.The class structure follows solid dependency injection principles with proper interface usage for testability. The static readonly constants provide good maintainability for error messages.
25-49: LGTM - Well-structured orchestration method.The main
handlemethod provides clear orchestration of the pull operation with proper error handling and logging. The try-catch structure appropriately logs errors before re-throwing them.
…CommandHandler and PushSingleCommandHandler
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
e2e/e2e.test.ts (1)
189-198: Add error handling for AWS SSM operations.The
GetParameterSsmfunction lacks error handling for AWS SDK calls, which could cause test failures due to transient AWS issues or missing parameters.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
e2e/e2e.test.ts(6 hunks)src/envilder/infrastructure/Aws/AwsSsmSecretProvider.ts(1 hunks)tests/apps/cli/Cli.test.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/apps/cli/Cli.test.ts
- src/envilder/infrastructure/Aws/AwsSsmSecretProvider.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: codeql-fortress (typescript)
🔇 Additional comments (5)
e2e/e2e.test.ts (5)
6-6: LGTM! AWS SDK integration looks good.The AWS SDK imports and SSM client initialization are properly implemented for the new push functionality tests.
Also applies to: 14-14
27-28: LGTM! Updated file paths align with new structure.The file paths have been correctly updated to point to the new
e2e/sampledirectory structure.
86-97: LGTM! Test expectations correctly updated.The test name and error message expectations have been properly updated to reflect the current CLI behavior.
172-172: LGTM! Cleanup improvements are appropriate.The cleanup logic has been properly updated to use the newer async/await pattern with better error handling.
Also applies to: 179-179
200-207: LGTM! Parsing robustness issue has been resolved.The
GetSecretFromKeyfunction now correctly usessubstring()instead ofsplit(), which properly handles environment values containing=characters.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (2)
e2e/e2e.test.ts (2)
201-210: Add error handling for AWS SSM operations.The
GetParameterSsmfunction lacks error handling for AWS SDK calls, which could cause test failures due to transient AWS issues or missing parameters.async function GetParameterSsm(ssmPath: string): Promise<string> { - const command = new GetParameterCommand({ - Name: ssmPath, - WithDecryption: true, - }); - const response = await ssmClient.send(command); - const value = response.Parameter?.Value || ''; - console.log(`SSM Value for path ${ssmPath}: ${value}`); - return value; + try { + const command = new GetParameterCommand({ + Name: ssmPath, + WithDecryption: true, + }); + const response = await ssmClient.send(command); + const value = response.Parameter?.Value || ''; + console.log(`SSM Value for path ${ssmPath}: ${value}`); + return value; + } catch (error) { + console.error(`Failed to get SSM parameter ${ssmPath}:`, error); + throw error; + } }
132-153: Improve test isolation with unique SSM paths.The hardcoded SSM path
/Test/SingleVariablecould conflict with other tests or environments running concurrently.it('Should_PushSingle_When_KeyValueAndSsmPathProvided', async () => { // Arrange const key = 'SINGLE_VARIABLE'; const value = 'single-value-test'; - const ssmPath = '/Test/SingleVariable'; + const ssmPath = `/Test/E2E/${Date.now()}/SingleVariable`; const params = ['--key', key, '--value', value, '--ssm-path', ssmPath]; // Ensure SSM parameter doesn't exist before the test await DeleteParameterSsm(ssmPath); // Act const actual = await runCommand(envilder, params); // Assert expect(actual.code).toBe(0); expect(actual.output).toContain(key); expect(actual.output).toContain(ssmPath); // Validate in AWS SSM const ssmValue = await GetParameterSsm(ssmPath); expect(ssmValue).toBe(value); + + // Cleanup SSM parameter + await DeleteParameterSsm(ssmPath); });
🧹 Nitpick comments (1)
README.md (1)
112-114: CLI examples expose secrets in shell historyPassing secret values via
--value=12345leaves them in shell history and process lists.
Advise users to pass secrets through stdin or environment variables (e.g.,read -s VALUE && envilder … --value="$VALUE").
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.gitignore(0 hunks)README.md(2 hunks)e2e/e2e.test.ts(6 hunks)
💤 Files with no reviewable changes (1)
- .gitignore
🔇 Additional comments (4)
e2e/e2e.test.ts (4)
212-226: Good error handling implementation in DeleteParameterSsm.The
DeleteParameterSsmfunction properly handles theParameterNotFounderror case and logs appropriate messages. This addresses the cleanup concerns from previous reviews.
228-235: Good fix for parsing robustness.The parsing logic now correctly uses
substring(key.length + 1)instead ofsplit('=')[1], which properly handles environment values containing=characters.
103-130: Add AWS credentials validation and improve test isolation.The push tests assume AWS credentials are available and have SSM permissions. Consider adding validation to skip tests gracefully when credentials are unavailable. Additionally, the hardcoded SSM paths could conflict with other test runs.
+ beforeAll(async () => { + if (!process.env.AWS_ACCESS_KEY_ID && !process.env.AWS_SECRET_ACCESS_KEY) { + try { + // Try to access AWS credentials + await ssmClient.send(new GetParameterCommand({ Name: '/dummy/test' })); + } catch (error) { + if (error.name === 'UnauthorizedOperation' || error.name === 'CredentialsProviderError') { + console.warn('Skipping SSM E2E tests: AWS credentials not available'); + return test.skip(); + } + } + } + }); it('Should_PushEnvFileToSSM_When_PushFlagIsUsed', async () => { // Arrange const params = ['--push', '--envfile', envFilePath, '--map', mapFilePath]; - const ssmParams = JSON.parse(readFileSync(mapFilePath, 'utf8')) as Record< - string, - string - >; + const ssmParams = JSON.parse(readFileSync(mapFilePath, 'utf8')) as Record<string, string>; + // Make paths unique to avoid conflicts + const uniqueSuffix = Date.now(); + const uniqueSsmParams: Record<string, string> = {}; + for (const [key, path] of Object.entries(ssmParams)) { + uniqueSsmParams[key] = `${path}-${uniqueSuffix}`; + }This ensures tests won't fail in environments without AWS setup and prevents conflicts between test runs.
98-101: Error message format is correctVerified that the CLI throws
Missing required arguments: --map and --envfile
in DispatchActionCommandHandler, and the test’s.toContainassertion exactly matches this message. No changes needed.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
README.md (3)
6-6: Remove the stray closing</p>tag
This duplicate tag is still present and breaks the rendered HTML.-</p>
51-51: Drop the garbled�from the TOC entry
The invalid character still corrupts the Markdown anchor.- - [� Method 1: Push from .env File](#-method-1-push-from-env-file) + - [Method 1: Push from .env File](#method-1-push-from-env-file)
157-157: Fix the heading – remove the leading�
Same encoding glitch as the TOC; leaves an ugly heading and broken anchor.-#### � Method 1: Push from .env File +#### Method 1: Push from .env File
🧹 Nitpick comments (1)
README.md (1)
30-35: GitHub won’t render the<video>tag – embed a GIF or link instead
Markdown on GitHub strips<video>elements, so users will just see raw HTML. Convert the demo to a GIF or link to the video.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
README.md(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: codeql-fortress (typescript)
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
README.md (4)
6-6: Remove stray closing</p>tag
Extraneous closing tag breaks the HTML structure rendered by GitHub; delete it.
48-49: Garbled�character in TOC entry
The leading replacement character produces an invalid anchor; drop it.- - [� Method 1: Push from .env File](#-method-1-push-from-env-file) + - [Method 1: Push from .env File](#method-1-push-from-env-file)
154-154: Same garbled�character in section heading
Remove the invalid glyph to keep the heading clean and linkable.-#### � Method 1: Push from .env File +#### Method 1: Push from .env File
118-124: Mismatched closing fence (`\) breaks Markdown from here down
Close the earlier code block with exactly three back-ticks and remove the quadruple fence.-```` +```
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
README.md(2 hunks)
🧰 Additional context used
🪛 GitHub Check: markdown-lint
README.md
[failure] 28-28:
Multiple headings with the same content [Context: "🎥 Video Demonstration"]
🪛 GitHub Actions: 🏁 Rainbow Road Lint
README.md
[error] 28-28: markdownlint MD024/no-duplicate-heading: Multiple headings with the same content [Context: "🎥 Video Demonstration"]
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: codeql-fortress (typescript)
There was a problem hiding this comment.
Pull Request Overview
Introduces Push Mode to Envilder CLI for syncing local environment variables to AWS SSM and updates docs and tests.
- Added Push Mode (
--push) functionality: supports pushing entire.envfiles and individual variables to AWS SSM Parameter Store. - Enhanced CLI internals: new command handlers, domain interfaces, and error handling for push operations.
- Updated tests, configuration, and documentation to reflect Push Mode feature.
Reviewed Changes
Copilot reviewed 44 out of 51 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| vite.config.ts | Broadened test glob patterns to include new push mode tests |
| src/envilder/infrastructure/EnvManager/EnvFileManager.ts | Added robust JSON parsing and error handling for map files |
| src/envilder/infrastructure/Aws/AwsSsmSecretProvider.ts | Implemented get/set secret operations against AWS SSM |
| src/envilder/application/pushEnvToSsm/PushEnvToSsmCommandHandler.ts | Core logic for pushing variables from .env to AWS SSM |
| README.md | Extended usage guide with Push Mode examples and updated TOC |
Comments suppressed due to low confidence (3)
src/envilder/infrastructure/EnvManager/EnvFileManager.ts:72
- The
escapeEnvValuemethod that replaces newlines is untested. Consider adding unit tests to verify correct escaping of multi-line values.
private escapeEnvValue(value: string): string {
README.md:6
- There is an extra closing
</p>tag here which may lead to invalid HTML. Consider removing the duplicated</p>to maintain proper markup.
</p>
src/envilder/application/pushEnvToSsm/PushEnvToSsmCommandHandler.ts:91
- Running all push operations in parallel may flood AWS SSM if there are many variables. Consider limiting concurrency (e.g., using a queue or p-limit) to avoid throttling.
await Promise.all(variableProcessingPromises);
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
README.md (1)
3-6: Still one stray</p>— remove to restore valid HTML
The duplicate closing paragraph tag slipped through again and breaks the rendered layout.-</p>
🧹 Nitpick comments (1)
README.md (1)
345-348: Sample secret trips gitleaks – replace with a placeholder
Even though it’s fake, leaving a JWT-looking string in docs makes scanners fail CI.-SECRET_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 +SECRET_TOKEN=<SECRET_TOKEN_PLACEHOLDER>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
README.md(2 hunks)
🧰 Additional context used
🪛 Gitleaks (8.26.0)
README.md
348-348: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: powerup-test
- GitHub Check: codeql-fortress (typescript)
🔇 Additional comments (1)
README.md (1)
131-136: Missing closing fence – everything below renders as code
The Step 3 command block is never closed.envilder --map=param-map.json --envfile=.env +```Add the triple back-tick to terminate the block.
Likely an incorrect or invalid review comment.
Description
This PR introduces the highly requested
Push Modefeature to the Envilder CLI, enabling users to securely and efficiently push local environment variables to AWS SSM Parameter Store. Additionally, minor documentation updates have been made to improve usability.Key Changes:
New Feature: Push Mode (
--push):.envfiles or individual environment variables to AWS SSM Parameter Store.--push: Enables push mode.--keyand--value: Specify a single environment variable to push.--ssm-path: Define the SSM path for the variable.--envfileand--map: Push variables from a.envfile using a mapping file..envfile to AWS SSM:Documentation Updates:
Push ModeandPull Modesections to the Usage section for better organization.Why This Change?
Push Modefeature addresses a critical need for syncing local environment variables with AWS SSM, providing a secure and centralized solution.This PR focuses on delivering the
Push Modefeature while also improving the overall user experience through minor documentationSummary by CodeRabbit
.envfiles or single variables to AWS SSM Parameter Store.