diff --git a/packages/signing-utils/src/garasign.sh b/packages/signing-utils/src/garasign.sh index 9207cc79..42567951 100644 --- a/packages/signing-utils/src/garasign.sh +++ b/packages/signing-utils/src/garasign.sh @@ -47,9 +47,6 @@ gpg_sign() { } jsign_sign() { - if [ -z ${alias+omitted} ]; then echo "Alias must be set when signing with jsign" && exit 1; fi - if [ -z ${timestampUrl+omitted} ]; then echo "Timestamp URL must be set when signing with jsign" && exit 1; fi - docker run \ -e GRS_CONFIG_USER1_USERNAME="${garasign_username}" \ -e GRS_CONFIG_USER1_PASSWORD="${garasign_password}" \ @@ -57,7 +54,7 @@ jsign_sign() { -v $directory:$directory \ -w $directory \ artifactory.corp.mongodb.com/release-tools-container-registry-local/garasign-jsign \ - /bin/bash -c "jsign -t '$timestampUrl' -a '$alias' '$file'" + /bin/bash -c "jsign -t 'http://timestamp.digicert.com' -a 'mongo-authenticode-2021' '$file'" } if [[ $method == "gpg" ]]; then diff --git a/packages/signing-utils/src/signing-clients/index.ts b/packages/signing-utils/src/signing-clients/index.ts index 0d5e491b..c3ad752b 100644 --- a/packages/signing-utils/src/signing-clients/index.ts +++ b/packages/signing-utils/src/signing-clients/index.ts @@ -8,22 +8,12 @@ import { RemoteSigningClient } from './remote-signing-client'; export { LocalSigningClient } from './local-signing-client'; export { RemoteSigningClient } from './remote-signing-client'; -export type SigningOptions = - | { - method: 'gpg'; - } - | { - method: 'jsign'; - // The alias of the certificate used for signing in the keystore - certificateAlias: 'compass' | 'mongosh'; - // The URL of the timestamping authority. - timestampUrl?: string; - }; +export type SigningMethod = 'gpg' | 'jsign'; export type SigningClientOptions = { workingDirectory: string; signingScript: string; - signingOptions: SigningOptions; + signingMethod: SigningMethod; }; /** Options for signing a file remotely over an SSH connection. */ @@ -38,8 +28,9 @@ export type RemoteSigningOptions = { port?: number; /** Buffer or string that contains a private key for either key-based or hostbased user authentication (OpenSSH format). */ privateKey?: Buffer | string; + /** The method to sign with. Use gpg on linux and jsign on windows. */ + signingMethod: SigningMethod; - signingOptions: SigningOptions; /** * The path of the working directory in which to sign files **on the remote ssh server**. Defaults to `/home/ubuntu/garasign`. */ @@ -49,7 +40,9 @@ export type RemoteSigningOptions = { /** Options for signing a file locally. */ export type LocalSigningOptions = { - signingOptions: SigningOptions; + /** The method to sign with. Use gpg on linux and jsign on windows. */ + signingMethod: SigningMethod; + client: 'local'; }; @@ -76,13 +69,13 @@ export async function getSigningClient( return new RemoteSigningClient(sshClient, { workingDirectory: options.workingDirectory ?? '/home/ubuntu/garasign', signingScript, - signingOptions: options.signingOptions, + signingMethod: options.signingMethod, }); } if (options.client === 'local') { return new LocalSigningClient({ signingScript, - signingOptions: options.signingOptions, + signingMethod: options.signingMethod, }); } // @ts-expect-error `client` is a discriminated union - we should never reach here but we throw on the off-chance we do. diff --git a/packages/signing-utils/src/signing-clients/local-signing-client.spec.ts b/packages/signing-utils/src/signing-clients/local-signing-client.spec.ts index 3f12b8ff..bcd13a71 100644 --- a/packages/signing-utils/src/signing-clients/local-signing-client.spec.ts +++ b/packages/signing-utils/src/signing-clients/local-signing-client.spec.ts @@ -31,9 +31,7 @@ describe('LocalSigningClient', function () { it('executes the signing script correctly', async function () { const localSigningClient = new LocalSigningClient({ signingScript: signingScript, - signingOptions: { - method: 'gpg', - }, + signingMethod: 'gpg', }); await localSigningClient.sign(fileToSign); @@ -60,9 +58,7 @@ describe('LocalSigningClient', function () { it('sign() rejects', async function () { const localSigningClient = new LocalSigningClient({ signingScript: signingScript, - signingOptions: { - method: 'gpg', - }, + signingMethod: 'gpg', }); const error = await localSigningClient.sign(fileToSign).catch((e) => e); @@ -72,9 +68,7 @@ describe('LocalSigningClient', function () { it('includes the stdout and stderr of the failed script in the error', async function () { const localSigningClient = new LocalSigningClient({ signingScript: signingScript, - signingOptions: { - method: 'gpg', - }, + signingMethod: 'gpg', }); const error: Error = await localSigningClient diff --git a/packages/signing-utils/src/signing-clients/local-signing-client.ts b/packages/signing-utils/src/signing-clients/local-signing-client.ts index 79042667..f62c5d7b 100644 --- a/packages/signing-utils/src/signing-clients/local-signing-client.ts +++ b/packages/signing-utils/src/signing-clients/local-signing-client.ts @@ -1,6 +1,6 @@ import path from 'path'; import { spawnSync } from 'child_process'; -import { debug, getEnv, mapSigningOptionsForScript } from '../utils'; +import { debug, getEnv } from '../utils'; import type { SigningClient, SigningClientOptions } from '.'; const localClientDebug = debug.extend('LocalSigningClient'); @@ -27,7 +27,7 @@ export class LocalSigningClient implements SigningClient { try { const env = { ...getEnv(), - ...mapSigningOptionsForScript(this.options.signingOptions), + method: this.options.signingMethod, }; const { stdout, stderr, status } = spawnSync( diff --git a/packages/signing-utils/src/signing-clients/remote-signing-client.spec.ts b/packages/signing-utils/src/signing-clients/remote-signing-client.spec.ts index 0f83125d..80d91d71 100644 --- a/packages/signing-utils/src/signing-clients/remote-signing-client.spec.ts +++ b/packages/signing-utils/src/signing-clients/remote-signing-client.spec.ts @@ -46,9 +46,7 @@ describe('RemoteSigningClient', function () { const remoteSigningClient = new RemoteSigningClient(getMockedSSHClient(), { workingDirectory: workingDirectoryPath, signingScript: signingScript, - signingOptions: { - method: 'gpg', - }, + signingMethod: 'gpg', }); await remoteSigningClient.sign(fileToSign); diff --git a/packages/signing-utils/src/signing-clients/remote-signing-client.ts b/packages/signing-utils/src/signing-clients/remote-signing-client.ts index 5b4223cd..d34224ea 100644 --- a/packages/signing-utils/src/signing-clients/remote-signing-client.ts +++ b/packages/signing-utils/src/signing-clients/remote-signing-client.ts @@ -1,6 +1,6 @@ import path from 'path'; import type { SSHClient } from '../ssh-client'; -import { debug, getEnv, mapSigningOptionsForScript } from '../utils'; +import { debug, getEnv } from '../utils'; import type { SigningClient, SigningClientOptions } from '.'; export class RemoteSigningClient implements SigningClient { @@ -34,9 +34,6 @@ export class RemoteSigningClient implements SigningClient { private async signRemoteFile(file: string) { const env = getEnv(); - const signingOptions = mapSigningOptionsForScript( - this.options.signingOptions - ); /** * Passing env variables as an option to ssh.exec() doesn't work as ssh config * (`sshd_config.AllowEnv`) does not allow to pass env variables by default. @@ -52,9 +49,7 @@ export class RemoteSigningClient implements SigningClient { `export artifactory_username=${env.artifactory_username}`, // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `export artifactory_password=${env.artifactory_password}`, - ...(Object.keys(signingOptions) as (keyof typeof signingOptions)[]).map( - (k) => `export ${k}=${signingOptions[k] as string}` - ), + `export method=${this.options.signingMethod}`, `./garasign.sh '${file}'`, ]; const command = cmds.join(' && '); @@ -76,6 +71,13 @@ export class RemoteSigningClient implements SigningClient { await this.sshClient.downloadFile(remotePath, file); debug(`SFTP: Downloaded signed file to ${file}`); + + // For signing using gpg, `.sig` file is created along side the file being signed. + // We also have to download it back and put it in the same path as original file. + if (this.options.signingMethod === 'gpg') { + await this.sshClient.downloadFile(`${remotePath}.sig`, `${file}.sig`); + debug(`SFTP: Downloaded signature file to ${file}`); + } } catch (error) { debug({ error }); } finally { diff --git a/packages/signing-utils/src/utils.ts b/packages/signing-utils/src/utils.ts index 36bb05eb..f4919932 100644 --- a/packages/signing-utils/src/utils.ts +++ b/packages/signing-utils/src/utils.ts @@ -1,5 +1,4 @@ import { debug as debugFn } from 'debug'; -import type { SigningOptions } from './signing-clients'; export const debug = debugFn('signing-utils'); @@ -20,23 +19,3 @@ export function getEnv() { artifactory_password, }; } - -const DEFAULT_JSIGN_TIMESTAMP_URL = 'http://timestamp.digicert.com'; - -export function mapSigningOptionsForScript(options: SigningOptions) { - if (options.method === 'gpg') { - return { - method: options.method, - }; - } - - if (options.method === 'jsign') { - return { - method: options.method, - alias: options.certificateAlias, - timestampUrl: options.timestampUrl ?? DEFAULT_JSIGN_TIMESTAMP_URL, - }; - } - - return {}; -}