-
-
Notifications
You must be signed in to change notification settings - Fork 4
feat(sdk-node): add Node.js SDK #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
1353399
feat(sdk-ts): add TypeScript SDK source
macalbert dbe00a2
test(sdk-ts): add unit test suite
macalbert 35a5be6
docs(sdk-ts): update website, docs, and roadmap
macalbert d1a64b8
style(sdk-ts): apply biome formatting to JSON configs
macalbert 856060b
Merge branch 'main' into feat/sdk-typescript
macalbert d526582
fix(sdk-ts): correct vitest coverage config to resolve source files
macalbert 74aaed2
style(sdk-ts): apply biome useOptionalChain auto-fix
macalbert fd8843f
test(sdk-ts): fix AAA conventions and add resolveFile env routing test
macalbert 978dfb3
ci(sdk-ts): add TypeScript SDK to coverage report workflow
macalbert c64ad8c
ci(sdk-ts): add test and publish workflows for TypeScript SDK
macalbert 91fb8fc
ci(sdk-ts): use OIDC provenance for npm publish
macalbert 9415e30
style(sdk-ts): add trailing newline to coverage config
macalbert 5e1cd36
chore: auto-fix formatting on pre-push hook
macalbert 1663f9d
style(coverage): Add trailing newline to coverage config
macalbert 2e39230
revert: restore read-only pre-push format check
macalbert 90dbe70
fix(sdk-ts): use absolute path for test-results.xml output
macalbert 1731f30
fix(sdk-ts): use absolute path for coverage reportsDirectory
macalbert 4dc4ef4
refactor(sdk-ts): change ISecretProvider to batch getSecrets API
macalbert 63ce58d
fix: add biome format to pre-commit hook
macalbert 44e4a98
fix(sdk-ts): add type module, publishConfig, and test scripts to pack…
macalbert f54133a
test(sdk-ts): fix test conventions and strengthen assertions
macalbert f756120
fix(sdk-ts): improve parser validation and facade consistency
macalbert 7b2d54d
style(sdk-ts): reorganize exports, fix indentation, and reorder i18n …
macalbert b54faa6
fix(website): render TypeScript SDK changelog on all locale pages
macalbert d5c9131
style: fix CRLF line endings and biome formatting
macalbert 282e451
fix: align lefthook pre-commit and pre-push hooks to prevent format d…
macalbert d198197
fix: make pnpm format auto-fix check and formatting issues
macalbert b8605d2
fix: add jsonc to lefthook pre-commit glob
macalbert bd9c882
fix: remove broken format:staged script and restore direct pnpx in pr…
macalbert 85b6e58
fix(package): Add missing newline at end of file
macalbert bfed2f2
test(sdk-ts): add acceptance tests and missing unit test coverage
macalbert 588f27f
feat(container): Add names to LocalStack and LowkeyVault containers
macalbert 984983e
fix(sdk-ts): throw when env key not found in environment mapping
macalbert 438cee7
fix(sdk-ts): fix ESM compat, tsconfig paths, and test isolation
macalbert 9715cc9
fix(sdk-ts): remove trailing periods from error messages
macalbert 642dfa9
fix(sdk-ts): add exports field to restrict public entrypoints
macalbert 3e60dbe
docs(sdk-ts): clarify createSecretProvider is not re-exported from ba…
macalbert 35057db
feat(docs): Add SDK release checklist and update version handling
macalbert 79037fa
refactor(sdk): rename TypeScript SDK to Node.js SDK
macalbert File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| --- | ||
| name: sdk-acceptance-testing | ||
| description: >- | ||
| Acceptance testing patterns for Envilder SDKs using TestContainers | ||
| (LocalStack for AWS SSM, Lowkey Vault for Azure Key Vault). Use when | ||
| adding acceptance tests to any SDK, creating container wrappers, or | ||
| updating CI workflows for SDK test infrastructure. | ||
| --- | ||
|
|
||
| # SDK Acceptance Testing | ||
|
|
||
| Patterns for acceptance testing Envilder SDKs against real cloud provider | ||
| emulators. Applies to all SDKs (.NET, Python, TypeScript, Go, Java). | ||
|
|
||
| See [ADR-0001](../../../docs/architecture/adr/0001-sdk-acceptance-test-infrastructure.md) | ||
| for the architectural decision behind these patterns. | ||
|
|
||
| ## When to Use | ||
|
|
||
| - Adding acceptance tests to a new or existing SDK | ||
| - Creating container wrappers for LocalStack or Lowkey Vault | ||
| - Updating CI workflows to support SDK acceptance tests | ||
| - Adding a new SDK and need to replicate test infrastructure | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| Every SDK test directory follows this layout: | ||
|
|
||
| ```txt | ||
| tests/sdks/{lang}/ | ||
| ├── containers/ ← Container wrapper modules | ||
| │ ├── localstack-container.* | ||
| │ └── lowkey-vault-container.* | ||
| ├── acceptance/ ← Acceptance test files | ||
| │ ├── aws-ssm.acceptance.* | ||
| │ └── azure-key-vault.acceptance.* | ||
| └── {unit-tests}/ ← Language-specific unit test dirs | ||
| ``` | ||
|
|
||
| ## secrets-map.json Pattern | ||
|
|
||
| All SDKs reference the **root** `secrets-map.json` at the repository root | ||
| directly. Container wrappers navigate to it via a relative path — there are no | ||
| copies per SDK test directory. | ||
|
|
||
| ```json | ||
| { | ||
| "$config": { | ||
| "provider": "aws", | ||
| "profile": "mac" | ||
| }, | ||
| "LOCALSTACK_AUTH_TOKEN": "/envilder/development/localstack/authToken" | ||
| } | ||
| ``` | ||
|
|
||
| **Resolution behavior:** | ||
|
|
||
| | Environment | How it works | | ||
| |-------------|-------------| | ||
| | Local dev | `$config.profile` resolves AWS credentials from `~/.aws/credentials` | | ||
| | CI (GitHub Actions) | Profile is ignored; OIDC provides credentials via `aws-actions/configure-aws-credentials` | | ||
|
|
||
| **Path resolution example (TypeScript):** | ||
|
|
||
| ```typescript | ||
| // From tests/sdks/nodejs/containers/localstack-container.ts | ||
| const SECRETS_MAP = path.resolve(__dirname, '../../../../secrets-map.json'); | ||
| ``` | ||
|
|
||
| **Fallback pattern:** If the configured provider cannot be created (e.g., Azure | ||
| credentials missing in a CI environment that only has AWS OIDC), fall back to | ||
| AWS provider to resolve the token. | ||
|
|
||
| ## LocalStack Container Wrapper | ||
|
|
||
| ### Requirements | ||
|
|
||
| - Image: `localstack/localstack:stable` | ||
| - Resolve `LOCALSTACK_AUTH_TOKEN` from `secrets-map.json` before starting | ||
| - Throw if token is empty (fail fast) | ||
| - Expose: endpoint URL, SSM client, provider instance | ||
|
|
||
| ### Lifecycle | ||
|
|
||
| ```txt | ||
| 1. Parse secrets-map.json with SDK's own MapFileParser | ||
| 2. Resolve LOCALSTACK_AUTH_TOKEN using SDK's own EnvilderClient | ||
| 3. Start container with token as environment variable | ||
| 4. Expose connection URL for SSM client creation | ||
| ``` | ||
|
|
||
| ## Lowkey Vault Container Wrapper | ||
|
|
||
| ### Requirements | ||
|
|
||
| - Image: `nagyesta/lowkey-vault:7.1.61` (pinned) | ||
| - Ports: 8443 (HTTPS vault), 8080 (HTTP token endpoint) | ||
| - Args: `--server.port=8443 --LOWKEY_VAULT_RELAXED_PORTS=true` | ||
| - Set `IDENTITY_ENDPOINT` and `IDENTITY_HEADER` env vars for | ||
| `DefaultAzureCredential` | ||
| - Self-signed TLS: disable certificate verification in test clients | ||
| - Restore original env vars on teardown | ||
|
|
||
| ### Lifecycle | ||
|
|
||
| ```txt | ||
| 1. Start container with Lowkey Vault args | ||
| 2. Wait for HTTPS port to be ready (health check /ping) | ||
| 3. Set IDENTITY_ENDPOINT = http://{host}:{http_port}/metadata/identity/oauth2/token | ||
| 4. Set IDENTITY_HEADER = "dummy" | ||
| 5. Create SecretClient with TLS verification disabled | ||
| 6. On teardown: restore original IDENTITY_ENDPOINT/IDENTITY_HEADER | ||
| ``` | ||
|
|
||
| ## Acceptance Test Patterns | ||
|
|
||
| ### Test Naming | ||
|
|
||
| Same convention as unit tests: `Should_{Expected}_When_{Condition}` | ||
|
|
||
| ### Standard Tests per Provider | ||
|
|
||
| Every SDK should have at minimum these acceptance tests: | ||
|
|
||
| **AWS SSM:** | ||
|
|
||
| 1. `Should_ResolveSecretFromSsm_When_ParameterExistsInLocalStack` | ||
| 2. `Should_ReturnEmptyForMissingSsmParameter_When_ParameterDoesNotExist` | ||
|
|
||
| **Azure Key Vault:** | ||
|
|
||
| 1. `Should_ResolveSecretFromKeyVault_When_SecretExistsInLowkeyVault` | ||
| 2. `Should_ReturnEmptyForMissingKeyVaultSecret_When_SecretDoesNotExist` | ||
|
|
||
| ### Test Structure (AAA) | ||
|
|
||
| ```typescript | ||
| it('Should_ResolveSecretFromSsm_When_ParameterExistsInLocalStack', async () => { | ||
| // Arrange | ||
| await ssmClient.send(new PutParameterCommand({ | ||
| Name: '/Test/MySecret', | ||
| Value: 'real-secret-from-localstack', | ||
| Type: 'SecureString', | ||
| Overwrite: true, | ||
| })); | ||
| const sut = new EnvilderClient(provider); | ||
| const mapFile: ParsedMapFile = { | ||
| config: {}, | ||
| mappings: new Map([['MY_SECRET', '/Test/MySecret']]), | ||
| }; | ||
|
|
||
| // Act | ||
| const actual = await sut.resolveSecrets(mapFile); | ||
|
|
||
| // Assert | ||
| expect(actual.get('MY_SECRET')).toBe('real-secret-from-localstack'); | ||
| }); | ||
| ``` | ||
|
|
||
| ## CI Workflow Pattern | ||
|
|
||
| ### Required Steps | ||
|
|
||
| ```yaml | ||
| env: | ||
| LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }} | ||
|
|
||
| steps: | ||
| - uses: aws-actions/configure-aws-credentials@v6 | ||
| with: | ||
| role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} | ||
| aws-region: ${{ secrets.AWS_REGION }} | ||
|
|
||
| # ... build steps ... | ||
|
|
||
| - name: Run tests | ||
| run: {test-command} | ||
| env: | ||
| TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE: /var/run/docker.sock | ||
| DOCKER_HOST: unix:///var/run/docker.sock | ||
| ``` | ||
|
|
||
| ### Key Points | ||
|
|
||
| - `LOCALSTACK_AUTH_TOKEN` at job level so container wrapper can read it | ||
| - AWS OIDC credentials for resolving the token from SSM | ||
| - Docker socket env vars for TestContainers compatibility on GitHub runners | ||
| - Acceptance tests run in the same job as unit tests (no separate workflow) | ||
|
|
||
| ## Existing Implementations | ||
|
|
||
| | SDK | Container Wrappers | Acceptance Tests | | ||
| | ---------- | -------------------------------------- | ------------------------------------------------------------------------ | | ||
| | .NET | `tests/sdks/dotnet/Fixtures/` | `tests/sdks/dotnet/Infrastructure/`, `tests/sdks/dotnet/EndToEnd/` | | ||
| | Python | `tests/sdks/python/containers/` | `tests/sdks/python/infrastructure/`, `tests/sdks/python/end_to_end/` | | ||
| | Node.js | `tests/sdks/nodejs/containers/` | `tests/sdks/nodejs/acceptance/` | |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.