Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b60abf0
Added AWS KSM Support for KSM JavaScript SDK (#712)
satish-metron Nov 21, 2025
e2e8371
Update AWS KMS integration to v1.0.0 and remove package-level workflows
stas-schaller Nov 21, 2025
ae6e9a7
Add npm publish workflow
stas-schaller Nov 21, 2025
647727b
Add unit tests and test workflow
stas-schaller Nov 21, 2025
1abc647
Track package-lock.json for npm caching
stas-schaller Nov 21, 2025
9a71773
Prepare package for npm publish
stas-schaller Nov 21, 2025
0b384ee
Update core dependency to 17.3.0
stas-schaller Nov 21, 2025
49d75af
Temp: add push trigger for workflow registration
stas-schaller Nov 24, 2025
54b5380
Revert: remove temp push trigger
stas-schaller Nov 24, 2025
3fa7c49
fix: upgrade pino to v10 to resolve CVE-2025-57319 (fast-redact vulne…
stas-schaller Nov 24, 2025
63a2f31
fix: update yarn.lock to remove fast-redact (CVE-2025-57319)
stas-schaller Nov 24, 2025
0344bad
Update SBOM name to include 'javascript' for SDK identification
stas-schaller Nov 25, 2025
2296290
feat: add build-only option to publish workflow
stas-schaller Nov 26, 2025
162913c
fix(aws): add publishConfig and fix repository format for npm publish
stas-schaller Dec 16, 2025
e6bc0a2
fix: update @aws-sdk/client-kms to 3.975.0 to resolve GHSA-6475-r3vj-…
stas-schaller Jan 27, 2026
8d6f1eb
fix: regenerate package-lock.json to resolve @smithy/config-resolver …
stas-schaller Jan 27, 2026
edba657
fix: install node_modules before SBOM generation
stas-schaller Jan 27, 2026
3f9e401
fix: update @isaacs/brace-expansion to 5.0.1
stas-schaller Feb 4, 2026
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
115 changes: 115 additions & 0 deletions .github/workflows/publish.npm.storage.aws.kms.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: Publish AWS Storage to NPM
on:
workflow_dispatch:
inputs:
publish:
description: 'Publish to NPM (uncheck to build only)'
required: false
default: true
type: boolean

jobs:
generate-sbom:
runs-on: ubuntu-latest
steps:
- name: Get the source code
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'

- name: Install package dependencies
run: npm install
working-directory: ./sdk/javascript/packages/aws

- name: Install Syft
run: |
echo "Installing Syft v1.18.1..."
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /tmp/bin v1.18.1
echo "/tmp/bin" >> $GITHUB_PATH

- name: Install Manifest CLI
run: |
echo "Installing Manifest CLI v0.18.3..."
curl -sSfL https://raw.githubusercontent.com/manifest-cyber/cli/main/install.sh | sh -s -- -b /tmp/bin v0.18.3

- name: Create Syft configuration
run: |
cat > syft-config.yaml << 'EOF'
package:
search:
scope: all-layers
cataloger:
enabled: true
java:
enabled: false
python:
enabled: false
nodejs:
enabled: true
EOF

- name: Generate and upload SBOM
env:
MANIFEST_API_KEY: ${{ secrets.MANIFEST_TOKEN }}
run: |
JAVASCRIPT_SDK_DIR="./sdk/javascript"

# Get version from package.json
echo "Detecting AWS Storage version..."
if [ -f "${JAVASCRIPT_SDK_DIR}/packages/aws/package.json" ]; then
VERSION=$(grep -o '"version": "[^"]*"' "${JAVASCRIPT_SDK_DIR}/packages/aws/package.json" | cut -d'"' -f4)
echo "Detected version: ${VERSION}"
else
VERSION="1.0.0"
echo "Could not detect version, using default: ${VERSION}"
fi

echo "Generating SBOM with Manifest CLI..."
/tmp/bin/manifest sbom "${JAVASCRIPT_SDK_DIR}/packages/aws" \
--generator=syft \
--name=keeper-secrets-manager-javascript-storage-aws-kms \
--version=${VERSION} \
--output=spdx-json \
--file=aws-storage-sbom.json \
--api-key=${MANIFEST_API_KEY} \
--publish=true \
--asset-label=application,sbom-generated,nodejs,aws-storage \
--generator-config=syft-config.yaml

echo "SBOM generated and uploaded successfully: aws-storage-sbom.json"
echo "---------- SBOM Preview (first 20 lines) ----------"
head -n 20 aws-storage-sbom.json

publish-npm:
Comment on lines +13 to +86

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI about 1 month ago

In general, the fix is to add an explicit permissions: block that grants only the minimal required access for the GITHUB_TOKEN. Since neither job interacts with repository contents in a write fashion (no pushes, releases, PR updates, etc.), we can safely set contents: read only. This both adheres to least privilege and documents the intended permissions.

The single best way here, without changing existing behavior, is to add a workflow‑level permissions: block, right after the name: or on: section. This will apply to all jobs that don’t define their own permissions: block. For this workflow, a minimal and appropriate configuration is:

permissions:
  contents: read

This gives the jobs just enough permission for actions (like actions/checkout) that rely on reading repository contents, while disallowing writes. No imports, methods, or additional YAML keys are needed beyond inserting this permissions mapping into .github/workflows/publish.npm.storage.aws.kms.yml.

Suggested changeset 1
.github/workflows/publish.npm.storage.aws.kms.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/publish.npm.storage.aws.kms.yml b/.github/workflows/publish.npm.storage.aws.kms.yml
--- a/.github/workflows/publish.npm.storage.aws.kms.yml
+++ b/.github/workflows/publish.npm.storage.aws.kms.yml
@@ -1,4 +1,6 @@
 name: Publish AWS Storage to NPM
+permissions:
+  contents: read
 on:
   workflow_dispatch:
     inputs:
EOF
@@ -1,4 +1,6 @@
name: Publish AWS Storage to NPM
permissions:
contents: read
on:
workflow_dispatch:
inputs:
Copilot is powered by AI and may make mistakes. Always verify output.
needs: generate-sbom
if: ${{ github.event.inputs.publish == 'true' }}
environment: prod
runs-on: ubuntu-latest

defaults:
run:
working-directory: ./sdk/javascript/packages/aws

steps:
- name: Get the source code
uses: actions/checkout@v3

- name: Retrieve secrets from KSM
id: ksmsecrets
uses: Keeper-Security/ksm-action@master
with:
keeper-secret-config: ${{ secrets.KSM_KSM_CONFIG }}
secrets: |
NScQiZwrHJFCPv1gL8TX6Q/field/password > env:NPM_TOKEN

- name: Install dependencies
run: npm install

- name: Build package
run: npm run build

- name: Publish package
run: npm publish
Comment on lines +87 to +115

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI about 1 month ago

In general, the fix is to explicitly declare a permissions block that limits the GITHUB_TOKEN to the least privileges required by the workflow. This can be done at the workflow root (applies to all jobs) or per job. Because both generate-sbom and publish-npm only need to read repository contents (checkout), we can safely set permissions: contents: read at the workflow level. Neither job needs to write to the repo, manage issues/PRs, or interact with other GitHub resources.

The best fix with minimal functional impact is: add a top‑level permissions block just under the name: (and before on: or before jobs:) specifying contents: read. This keeps behavior the same (they already only read contents) while ensuring the token cannot be used to perform unintended write operations against the repository. No other scopes appear necessary: publishing to npm uses NPM_TOKEN from secrets; SBOM generation and upload use MANIFEST_API_KEY, not GITHUB_TOKEN. Concretely, edit .github/workflows/publish.npm.storage.aws.kms.yml to insert:

permissions:
  contents: read

immediately after line 1, or otherwise at the workflow root.

Suggested changeset 1
.github/workflows/publish.npm.storage.aws.kms.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/publish.npm.storage.aws.kms.yml b/.github/workflows/publish.npm.storage.aws.kms.yml
--- a/.github/workflows/publish.npm.storage.aws.kms.yml
+++ b/.github/workflows/publish.npm.storage.aws.kms.yml
@@ -1,4 +1,6 @@
 name: Publish AWS Storage to NPM
+permissions:
+  contents: read
 on:
   workflow_dispatch:
     inputs:
EOF
@@ -1,4 +1,6 @@
name: Publish AWS Storage to NPM
permissions:
contents: read
on:
workflow_dispatch:
inputs:
Copilot is powered by AI and may make mistakes. Always verify output.
38 changes: 38 additions & 0 deletions .github/workflows/test.javascript.storage.aws.kms.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Test JavaScript Storage - AWS KMS

on:
push:
branches:
- 'release/storage/javascript/aws-kms/**'
paths:
- 'sdk/javascript/packages/aws/**'
- '.github/workflows/test.javascript.storage.aws.kms.yml'
pull_request:
branches:
- 'release/storage/javascript/aws-kms/**'
paths:
- 'sdk/javascript/packages/aws/**'
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./sdk/javascript/packages/aws
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
cache-dependency-path: sdk/javascript/packages/aws/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test
Comment on lines +19 to +38

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium test

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 4 months ago

To resolve the issue, an explicit permissions block should be added to limit the permissions granted to the workflow's jobs. The least-privilege starting point is typically contents: read, which allows jobs to clone and read the repository content but does not permit write operations. This block can be added either at the root level of the workflow, applying to all jobs, or just to the specific job. Since the workflow contains only one job (test), either location is acceptable, but best practice is to place it at the root for future extensibility. The modification involves editing .github/workflows/test.javascript.storage.aws.kms.yml by inserting the following block after the name: and before the on: section:

permissions:
  contents: read

No new imports, methods, or definitions are required beyond adding this block.

Suggested changeset 1
.github/workflows/test.javascript.storage.aws.kms.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/test.javascript.storage.aws.kms.yml b/.github/workflows/test.javascript.storage.aws.kms.yml
--- a/.github/workflows/test.javascript.storage.aws.kms.yml
+++ b/.github/workflows/test.javascript.storage.aws.kms.yml
@@ -1,4 +1,6 @@
 name: Test JavaScript Storage - AWS KMS
+permissions:
+  contents: read
 
 on:
   push:
EOF
@@ -1,4 +1,6 @@
name: Test JavaScript Storage - AWS KMS
permissions:
contents: read

on:
push:
Copilot is powered by AI and may make mistakes. Always verify output.
26 changes: 26 additions & 0 deletions sdk/javascript/packages/aws/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"sourceType": "module",
"ecmaVersion": "latest"
},
"plugins": [
"@typescript-eslint",
"prettier",
"jest"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended",
"plugin:jest/style",
"plugin:prettier/recommended"
],
"rules": {
"prettier/prettier": "error",
"no-console": "error"
},
"ignorePatterns": ["node_modules/", "dist/", "coverage/"]
}
1 change: 1 addition & 0 deletions sdk/javascript/packages/aws/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
yarn.lock
120 changes: 120 additions & 0 deletions sdk/javascript/packages/aws/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# AWS KSM
Keeper Secrets Manager integrates with AWS KMS in order to provide protection for Keeper Secrets Manager configuration files. With this integration, you can protect connection details on your machine while taking advantage of Keeper's zero-knowledge encryption of all your secret credentials.

## Features
* Encrypt and Decrypt your Keeper Secrets Manager configuration files with AWS KMS.
* Protect against unauthorized access to your Secrets Manager connections.
* Requires only minor changes to code for immediate protection. Works with all Keeper Secrets Manager Javascript SDK functionality.

## Prerequisites
* Supports the JavaScript Secrets Manager SDK.
* Requires `@aws-sdk/client-kms` package.
* Key needs `Encrypt` and `Decrypt` permissions.

## Setup

1. Install KSM Storage Module

The Secrets Manager AWS KSM module can be installed using npm.

> `npm install @keeper-security/secrets-manager-aws`

2. Configure AWS Connection

By default the @aws-sdk library will utilize the default connection session setup with the AWS CLI with the aws configure command. If you would like to specify the connection details, the two configuration files located at `~/.aws/config` and `~/.aws/credentials` can be manually edited.

See the AWS documentation for more information on setting up an AWS session [here](https://docs.aws.amazon.com/cli/latest/reference/configure/)

Alternatively, configuration variables can be provided explicitly as an access key using the AwsSessionConfig data class and providing `awsAccessKeyId` , `awsSecretAccessKey` and `region` variables.

You will need an AWS Access Key to use the AWS KMS integration.

For more information on AWS Access Keys see the [AWS documentation](https://aws.amazon.com/premiumsupport/knowledge-center/create-access-key/)

3. Add AWS KMS Storage to Your Code

Now that the AWS connection has been configured, you need to tell the Secrets Manager SDK to utilize the KMS as storage.

To do this, use `AWSKeyValueStorage` as your Secrets Manager storage in the `SecretsManager` constructor.

The storage will require an AWS Key ID, as well as the name of the Secrets Manager configuration file which will be encrypted by AWS KMS.
```
import {AWSKeyValueStorage,AWSSessionConfig,LoggerLogLevelOptions} from "@keeper-security/secrets-manager-aws";

const getKeeperRecordsAWS = async () => {

const accessKeyId ="<YOUR AWS ACCESS KEY>>";
const secretAccessKey = "<YOUR AWS SECRET_ACCESS_KEY>";
const regionName = "<YOUR AWS REGION>";

const awsSessionConfig = new AWSSessionConfig(accessKeyId, secretAccessKey, regionName);

// oneTimeToken is used only once to initialize the storage
// after the first run, subsequent calls will use ksm-config.txt
const oneTimeToken = <one time token>;
const logLevel = LoggerLogLevelOptions.Debug;
const keyId = 'arn:aws:kms:ap-south-1:<accountName>:key/<keyId>';
const storage = await new AWSKeyValueStorage(keyId,config_path,awsSessionConfig,logLevel).init();

await initializeStorage(storage, oneTimeToken);

// Using token only to generate a config (for later usage)
// requires at least one access operation to bind the token

const {records} = await getSecrets({storage: storage});
console.log(records);

const firstRecord = records[0];
const firstRecordPassword = firstRecord.data.fields.find((x: { type: string; }) => x.type === 'bankAccount');
console.log(firstRecordPassword.value[0]);
}
console.log("start");
getKeeperRecordsAWS();
```

## Change Key operation and using default credentials from AWS
```
import {AWSKeyValueStorage,AWSSessionConfig} from "@keeper-security/secrets-manager-aws";

const getKeeperRecordsAWS = async () => {

const awsSessionConfig2 = new AWSSessionConfig();
let config_path = "<path to client-config-aws.json>";
const oneTimeToken = "US:kYKVGFJ2605-9UBF4VXd14AztMPXcxZ56zC9gr7O-Cw";
const keyId = 'arn:aws:kms:ap-south-1:<accountName>:key/<keyId>';
const keyId2 = "arn:aws:kms:<cloud-region>:<accountNumber>:key/<keyId2>"
const storage = await new AWSKeyValueStorage(keyId,config_path).init();
await storage.changeKey(keyId2);
await initializeStorage(storage, oneTimeToken);

const {records} = await getSecrets({storage: storage});
console.log(records);

const firstRecord = records[0];
const firstRecordPassword = firstRecord.data.fields.find((x: { type: string; }) => x.type === 'bankAccount');
console.log(firstRecordPassword.value[0]);
}
console.log("start");
getKeeperRecordsAWS();
```

## Decrypt config operation
we can decrypt config and save locally the decrypted file original config
```
const storage = await new AWSKeyValueStorage(keyId,config_path).init();
await storage.decryptConfig();
```

## Logging
We support logging for the AWS KSM integration. Supported log levels are as follows
* trace
* debug
* info
* warn
* error
* fatal
All these levels should be accessed from the LoggerLogLevelOptions enum. If no log level is set, the default log level is info. We can set the logging level to debug to get more information about the integration.

You're ready to use the KSM integration Using the AWS KMS Integration 👍

Once setup, the Secrets Manager AWS KMS integration supports all Secrets Manager JavaScript SDK functionality. Your code will need to be able to access the AWS KMS APIs in order to manage the decryption of the configuration file when run.
11 changes: 11 additions & 0 deletions sdk/javascript/packages/aws/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";

/** @type {import('eslint').Linter.Config[]} */
export default [
{ files: ["src/*.ts}"] },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
];
9 changes: 9 additions & 0 deletions sdk/javascript/packages/aws/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
"roots": [
"<rootDir>/test"
],
"transform": {
"^.+\\.(ts|tsx)$": "ts-jest"
},
"testEnvironment": "node"
}
Loading
Loading