Skip to content

Commit

Permalink
feat(breaking): strips down deps by removing google-cloud/kms from im…
Browse files Browse the repository at this point in the history
…port-path
  • Loading branch information
Figedi committed Oct 17, 2024
1 parent 8df4097 commit 583dfe7
Show file tree
Hide file tree
Showing 17 changed files with 60 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
.eslintcache
.DS_Store

src/run.ts
run.ts
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ Example to decrypt an encrypted file with a GCP-KMS keyring:
import { readFile } from "node:fs/promises";
import { GoogleKmsKeyDecryptor } from "@figedi/sops/kms";
import { SopsClient } from "@figedi/sops";
import { KeyManagementServiceClient } from '@google-cloud/kms';

const run = async () => {

const decryptor = await GoogleKmsKeyDecryptor.create('<your gcp project id>', '<path to a service-account.json>');
const decryptor = new GoogleKmsKeyDecryptor(new KeyManagementServiceClient({ projectId: '<your gcp project id>', keyFilename: '<path to a service-account.json>' }));
const sopsClient = new SopsClient(decryptor);
const testFile = await readFile('<path to a sops encrypted file>', { encoding: 'utf-8'})

Expand Down
18 changes: 6 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@
"vitest": "^2.1.3"
},
"dependencies": {
"@types/lodash": "^4.17.10",
"lodash": "^4.17.21",
"es-toolkit": "^1.25.2",
"yaml": "^2.6.0"
},
"optionalDependencies": {
Expand Down
20 changes: 10 additions & 10 deletions src/decryptors/google-kms/google-kms-key-decryptor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { KeyManagementServiceClient } from '@google-cloud/kms';
import { beforeAll, describe, expect, it } from 'vitest';
import { CheckSumMismatchError } from '../../errors';
import { uncoverPaths } from '../../helpers';
import { getEncryptedSecret, getEncryptedSecretWrongMac, getUnencryptedSecret } from '../../shared.specFiles/fixtures';
import { encryptJson } from '../../shared.specFiles/sops.spec-utils';
import { SopsClient } from '../../sops-client';
import { IKeyDecryptor } from '../../types';
import { GoogleKmsKeyDecryptor } from './google-kms-key-decryptor';
import { setupStubbedKms } from './shared.specFiles/kms.stub';
import { CheckSumMismatchError } from '../../errors.js';
import { uncoverPaths } from '../../helpers.js';
import { getEncryptedSecret, getEncryptedSecretWrongMac, getUnencryptedSecret } from '../../shared.specFiles/fixtures/secret.fixture.js';
import { encryptJson } from '../../shared.specFiles/sops.spec-utils.js';
import { SopsClient } from '../../sops-client.js';
import type { IKeyDecryptor } from '../../types.js';
import { GoogleKmsKeyDecryptor } from './google-kms-key-decryptor.js';
import { setupStubbedKms } from './shared.specFiles/kms.stub.js';

describe('SopsClient with KmsKeyDecryptor', () => {
describe('specs tooling', () => {
Expand All @@ -16,7 +16,7 @@ describe('SopsClient with KmsKeyDecryptor', () => {
theThing: '42',
};
const { key, iv, kms } = setupStubbedKms('random-password');
const sopsClient = new SopsClient(GoogleKmsKeyDecryptor.createWithKmsClient(kms));
const sopsClient = new SopsClient(new GoogleKmsKeyDecryptor(kms));
const encryptedData = encryptJson(key, iv, data);
const decryptedData = await sopsClient.decrypt(encryptedData);

Expand Down Expand Up @@ -64,7 +64,7 @@ describe('SopsClient with KmsKeyDecryptor', () => {
key = deps.key;
iv = deps.iv;
kms = deps.kms;
keyDecryptor = GoogleKmsKeyDecryptor.createWithKmsClient(kms);
keyDecryptor = new GoogleKmsKeyDecryptor(kms);
sopsClient = new SopsClient(keyDecryptor);
});

Expand Down
29 changes: 3 additions & 26 deletions src/decryptors/google-kms/google-kms-key-decryptor.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
import { stat } from 'node:fs/promises';
import type { KeyManagementServiceClient } from '@google-cloud/kms';
import { resolvePathOrObj } from '../../helpers';
import { IKeyDecryptor, ISopsEncryptedJSON } from '../../types';
import { resolvePathOrObj } from '../../helpers.js';
import type { IKeyDecryptor, ISopsEncryptedJSON } from '../../types.js';

export class GoogleKmsKeyDecryptor implements IKeyDecryptor {
private constructor(private client: KeyManagementServiceClient) {}

public static async create(projectId?: string, serviceAccountPath?: string) {
const mod = await import('@google-cloud/kms');
// in k8s, there might a service-account mounted
if (serviceAccountPath) {
try {
stat(serviceAccountPath);
return new GoogleKmsKeyDecryptor(new mod.KeyManagementServiceClient({ projectId, keyFilename: serviceAccountPath }));
} catch (e) {
if (e.code !== 'ENOENT') {
throw e;
}
}
}

// implicit authorization for non-k8s envs
return new GoogleKmsKeyDecryptor(new mod.KeyManagementServiceClient({ projectId }));
}

public static createWithKmsClient(client: KeyManagementServiceClient): IKeyDecryptor {
return new GoogleKmsKeyDecryptor(client);
}
constructor(private client: KeyManagementServiceClient) {}

public async canDecrypt(objOrPath: string | ISopsEncryptedJSON) {
const { content } = await resolvePathOrObj(objOrPath);
Expand Down
4 changes: 2 additions & 2 deletions src/decryptors/google-kms/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './shared.specFiles/kms.stub';
export * from './google-kms-key-decryptor';
export * from './shared.specFiles/kms.stub.js';
export * from './google-kms-key-decryptor.js';
6 changes: 3 additions & 3 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { readFile, stat } from 'node:fs/promises';
import { isAbsolute } from 'node:path';
import { chunk, isArray, isPlainObject } from 'lodash';
import { chunk, isPlainObject } from 'es-toolkit';
import yaml from 'yaml';
import { ISopsEncryptedJSON } from './types';
import type { ISopsEncryptedJSON } from './types.js';

export const uncoverPaths = (tree: any): any[][] => {
const doUncover = (t: any, walkedPaths: (string | number)[] = []): any[][] => {
if (isArray(t)) {
if (Array.isArray(t)) {
return t.reduce((acc, v, k) => [...acc, ...doUncover(v, [...walkedPaths, k])], []);
}
if (isPlainObject(t)) {
Expand Down
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from './sops-client';
export * from './types';
export * from './errors';
export * from './sops-client.js';
export * from './types.js';
export * from './errors.js';

// @note test files are exported under different alias
2 changes: 1 addition & 1 deletion src/kms.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// export-alias for named import @figedi/sops/kms (includes spec-files)
export * from './decryptors/google-kms';
export * from './decryptors/google-kms/index.js';
2 changes: 1 addition & 1 deletion src/shared.specFiles/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './secret.fixture';
export * from './secret.fixture.js';
12 changes: 9 additions & 3 deletions src/shared.specFiles/fixtures/secret.fixture.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { ISopsEncryptedJSON } from '../../types';
import { encryptJson } from '../sops.spec-utils';
import baseJson = require('./secrets.json');
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { ISopsEncryptedJSON } from '../../types.js';
import { encryptJson } from '../sops.spec-utils.js';

// @ts-expect-error target is not commonjs 🤷‍♂️
const __dirname = import.meta.dirname ?? dirname(fileURLToPath(import.meta.url));

const baseJson = JSON.parse(readFileSync(join(__dirname, './secrets.json'), { encoding: 'utf-8' }));
export const getUnencryptedSecret = (): Record<string, any> => baseJson;
export const getEncryptedSecret = (key: Buffer, iv: Buffer): ISopsEncryptedJSON => encryptJson(key, iv, baseJson);

Expand Down
6 changes: 3 additions & 3 deletions src/shared.specFiles/sops.spec-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createCipheriv, createHash } from 'node:crypto';
import { set } from 'lodash';
import { uncoverPaths } from '../helpers';
import { ISopsEncryptedJSON } from '../types';
import { set } from 'es-toolkit/compat';
import { uncoverPaths } from '../helpers.js';
import { ISopsEncryptedJSON } from '../types.js';

/**
* Encrypts a given string-value (e.g. a stringified object) in a sops-like fashion:
Expand Down
11 changes: 6 additions & 5 deletions src/sops-client.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createDecipheriv, createHash } from 'node:crypto';
import { omit, set } from 'lodash';
import { CheckSumMismatchError, SopsKeyNotSupportedError } from './errors';
import { resolvePathOrObj, uncoverPaths } from './helpers';
import { IKeyDecryptor, ISopsEncryptedJSON } from './types';
import { omit } from 'es-toolkit';
import { set } from 'es-toolkit/compat';
import { CheckSumMismatchError, SopsKeyNotSupportedError } from './errors.js';
import { resolvePathOrObj, uncoverPaths } from './helpers.js';
import type { IKeyDecryptor, ISopsEncryptedJSON } from './types.js';

export class SopsClient {
constructor(private keyDecryptor: IKeyDecryptor) {}
Expand Down Expand Up @@ -51,7 +52,7 @@ export class SopsClient {
};

private decryptSopsJsonWithKey = async <TResult = Record<string, any>>(key: Buffer, sopsJson: ISopsEncryptedJSON): Promise<TResult> => {
const paths = uncoverPaths(omit(sopsJson, 'sops'));
const paths = uncoverPaths(omit(sopsJson, ['sops']));
const digest = createHash('sha512');

const decryptedJson = paths.reduce((acc, [nodePath, scalarValue]) => {
Expand Down
2 changes: 1 addition & 1 deletion src/test.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// export-alias for named import @figedi/sops/test
export * from './shared.specFiles/sops.spec-utils';
export * from './shared.specFiles/sops.spec-utils.js';
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"compilerOptions": {
"module": "commonjs",
"module": "NodeNext",
"target": "esnext",
"moduleResolution": "NodeNext",
"rootDir": "./src",
"sourceRoot": "./src",
"outDir": "./dist",
Expand All @@ -15,7 +16,6 @@
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"pretty": true,
"typeRoots": [
Expand Down
13 changes: 6 additions & 7 deletions tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { defineConfig } from "tsup";
import { defineConfig } from 'tsup';

export default defineConfig({
entry: ["src/index.ts", "src/test.ts", "src/kms.ts"],
entry: ['src/index.ts', 'src/test.ts', 'src/kms.ts'],
splitting: false,
sourcemap: true,
clean: true,
dts: true,
outDir: "dist",
target: "es2022",
format: ["cjs", "esm"],
tsconfig: "./tsconfig.json",
onSuccess: "tsc --project tsconfig.json --emitDeclarationOnly --declaration",
outDir: 'dist',
target: 'es2022',
format: ['cjs', 'esm'],
tsconfig: './tsconfig.json',
});

0 comments on commit 583dfe7

Please sign in to comment.