Skip to content

Commit

Permalink
feat: initial implemenation of signing action
Browse files Browse the repository at this point in the history
  • Loading branch information
bryantbiggs committed Oct 14, 2021
1 parent 4b9371b commit 8508fe2
Show file tree
Hide file tree
Showing 9 changed files with 928 additions and 38 deletions.
27 changes: 20 additions & 7 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,23 @@ jobs:
LATEST_VERSION=$(aws s3api list-object-versions --bucket ${{ secrets.AWS_S3_BUCKET }} --prefix unsigned/dist.zip --query 'Versions[?IsLatest].[VersionId]' --output text)
echo "LATEST_VERSION=$LATEST_VERSION" >> $GITHUB_ENV
- name: Start signing job
run: |
echo ${{ env.LATEST_VERSION }}
aws signer start-signing-job \
--source 's3={bucketName=${{ secrets.AWS_S3_BUCKET}},version=${{ env.LATEST_VERSION }},key=unsigned/dist.zip}' \
--destination 's3={bucketName=${{ secrets.AWS_S3_BUCKET}},prefix=signed-}' \
--profile-name ${{ secrets.AWS_SIGNING_PROFILE_NAME }}
- name: Test
uses: ./
with:
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
source-s3-bucket: ${{ secrets.AWS_S3_BUCKET }}
source-s3-key: unsigned/dist.zip
source-s3-version: ${{ env.LATEST_VERSION }}
destination-s3-bucket: ${{ secrets.AWS_S3_BUCKET }}
destination-s3-prefix: signed/
profile-name: ${{ secrets.AWS_SIGNING_PROFILE_NAME }}
wait-until-successful: true
max-wait-time: 120

# - name: Start signing job
# run: |
# echo ${{ env.LATEST_VERSION }}
# aws signer start-signing-job \
# --source 's3={bucketName=${{ secrets.AWS_S3_BUCKET}},version=${{ env.LATEST_VERSION }},key=unsigned/dist.zip}' \
# --destination 's3={bucketName=${{ secrets.AWS_S3_BUCKET}},prefix=signed-}' \
# --profile-name ${{ secrets.AWS_SIGNING_PROFILE_NAME }}
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
engine-strict=true
61 changes: 55 additions & 6 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,60 @@
name: 'Your name here'
description: 'Provide a description here'
author: 'Your name or organization here'
name: AWS Lambda Code Signing GitHub Action
author: Clowd Haus, LLC
description: GitHub action which uses AWS Code Signer to sign ✍🏼 AWS Lambda artifacts 📦 from your pipeline
branding:
icon: edit
color: orange

inputs:
milliseconds: # change this
aws-region:
description: AWS Region, e.g. us-east-2
required: true
description: 'input description here'
default: 'default value if applicable'
client-request-token:
description: >-
String that identifies the signing request. All calls after
the first that use this token return the same response as the first call
required: false
source-s3-bucket:
description: Source S3 bucket name
required: true
source-s3-key:
description: Source S3 object key
required: true
source-s3-version:
description: Source S3 object version
required: true
destination-s3-bucket:
description: Destination S3 bucket name
required: true
destination-s3-prefix:
description: Destination S3 object key prefix
required: false
default: 'signed/'
profile-name:
description: >-
Name of the signing profile to use for signing
required: true
profile-owner:
description: >-
The AWS account ID of the signing profile owner
required: false
rename-signed-object:
description: >-
Rename the generated signed object to match the original
`sourceS3Key` with the `destinationS3Prefix`
required: false
default: 'true'
wait-until-successful:
description: >-
Wait until the signed jobs complete successfully
required: false
default: 'true'
max-wait-time:
description: >-
Maximum amount of time, in seconds, to wait for a job to completely successfully
required: false
default: '30'

runs:
using: 'node12'
main: 'dist/index.js'
17 changes: 16 additions & 1 deletion dist/index.js

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@
"release": "semantic-release"
},
"dependencies": {
"@actions/core": "^1.6.0"
"@actions/core": "^1.6.0",
"@aws-sdk/client-signer": "^3.36.1"
},
"devDependencies": {
"@semantic-release/changelog": "^6.0.0",
"@semantic-release/git": "^10.0.0",
"@types/node": "^16.10.5",
"@types/node": "^16.10.9",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@vercel/ncc": "^0.31.1",
Expand All @@ -47,12 +48,16 @@
"prettier": "^2.4.1",
"prettier-plugin-package": "^1.3.0",
"semantic-release": "^18.0.0",
"ts-node": "^10.3.0",
"typescript": "^4.4.4"
},
"resolutions": {
"ansi-regex": "^5.0.1",
"merge": ">=2.1.1"
},
"engines": {
"node": "~12"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
Expand Down
34 changes: 25 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import * as core from '@actions/core';

async function run(): Promise<void> {
import CodeSigner from './sign';
import * as input from './input';

async function run(actionInput: input.Input): Promise<void> {
try {
const ms: string = core.getInput('milliseconds');
core.debug(`Waiting ${ms} milliseconds ...`); // debug is only output if you set the secret `ACTIONS_STEP_DEBUG` to true
const signer = await new CodeSigner(actionInput.awsRegion);
const createSignedJob = await signer.createSignedJob(actionInput.jobCommandInput);
if (createSignedJob && createSignedJob.jobId) {
core.debug(`createSignedJob: ${createSignedJob.jobId}`);
}

if (createSignedJob && createSignedJob.jobId && actionInput.waitUntilSuccessful) {
await signer.waitUntilSuccessful(actionInput.maxWaitTime, createSignedJob.jobId);
}
} catch (error) {
core.setFailed(JSON.stringify(error, null, 4));
}
}

core.debug(new Date().toTimeString());
// await wait(parseInt(ms, 10))
core.debug(new Date().toTimeString());
async function main(): Promise<void> {
const actionInput = input.get();

core.setOutput('time', new Date().toTimeString());
try {
if (actionInput) {
await run(actionInput);
}
} catch (error) {
if (error instanceof Error) core.setFailed(error.message);
core.setFailed((<Error>error).message);
}
}

run();
void main();
68 changes: 68 additions & 0 deletions src/input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Parse action input into a some proper thing.
*/

import * as core from '@actions/core';
import {StartSigningJobCommandInput} from '@aws-sdk/client-signer';

export interface Input {
awsRegion: string;
clientRequestToken?: string;
jobCommandInput: StartSigningJobCommandInput;
renameSignedObject: boolean;
waitUntilSuccessful: boolean;
maxWaitTime: number;
}

// Helper function since only strings are used as inputs
function convertToBoolean(input: string): boolean {
return input.toLowerCase() === 'true';
}

export function get(): Input | undefined {
try {
const awsRegion = core.getInput('aws-region', {required: true});
const clientRequestToken = core.getInput('client-request-token', {required: false});
const sourceS3Bucket = core.getInput('source-s3-bucket', {required: true});
const sourceS3Key = core.getInput('source-s3-key', {required: true});
const sourceS3Version = core.getInput('source-s3-version', {required: true});
const destinationS3Bucket = core.getInput('destination-s3-bucket', {required: true});
const destinationS3Prefix = core.getInput('destination-s3-prefix', {required: true});
const profileName = core.getInput('profile-name', {required: false});
const profileOwner = core.getInput('profile-owner', {required: false});

const renameSignedObject = convertToBoolean(core.getInput('rename-signed-object', {required: false}));
const waitUntilSuccessful = convertToBoolean(core.getInput('wait-until-successful', {required: false}));
const maxWaitTime = parseInt(core.getInput('max-wait-time', {required: false}));

const jobCommandInput: StartSigningJobCommandInput = {
source: {
s3: {
bucketName: sourceS3Bucket,
key: sourceS3Key,
version: sourceS3Version,
},
},
destination: {
s3: {
bucketName: destinationS3Bucket,
prefix: destinationS3Prefix,
},
},
profileName: profileName,
...(profileOwner ? {profileName: profileName} : {}),
};

return {
awsRegion,
clientRequestToken,
jobCommandInput,
renameSignedObject,
waitUntilSuccessful,
maxWaitTime,
};
} catch (error) {
core.setFailed((<Error>error).message);
return;
}
}
63 changes: 63 additions & 0 deletions src/sign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
SignerClient,
StartSigningJobCommand,
StartSigningJobCommandInput,
StartSigningJobResponse,
waitUntilSuccessfulSigningJob,
} from '@aws-sdk/client-signer';
// import {WaiterState} from '@aws-sdk/util-waiter';

import * as core from '@actions/core';

export default class CodeSigner {
readonly region: string;
readonly client: SignerClient;

constructor(region: string) {
this.region = region;
this.client = new SignerClient({region});
}

async createSignedJob(input: StartSigningJobCommandInput): Promise<StartSigningJobResponse> {
try {
const command = new StartSigningJobCommand(input);
// core.debug(JSON.stringify(input, null, 4));
return await this.client.send(command);
} catch (error) {
const {requestId, cfId, extendedRequestId} = error.$metadata;
console.error({requestId, cfId, extendedRequestId});
core.setFailed(JSON.stringify(error, null, 4));
throw error;
}
}

async waitUntilSuccessful(maxWaitTime: number, jobId: string): Promise<void> {
const waiterConfig = {client: this.client, minDelay: 1, maxDelay: 10, maxWaitTime};
// core.debug(`waiterConfig: ${JSON.stringify(waiterConfig, null, 4)}`);

const signingJobInput = {jobId};
core.debug(`signingJobInput: ${JSON.stringify(signingJobInput, null, 4)}`);

try {
const waitResult = await waitUntilSuccessfulSigningJob(waiterConfig, signingJobInput);
core.debug(`waitResult: ${JSON.stringify(waitResult, null, 4)}`);
} catch (error) {
core.setFailed(JSON.stringify(error, null, 4));
}

// switch (waitResult.state) {
// case WaiterState.SUCCESS: {
// core.debug(waitResult.reason);
// return;
// }
// default: {
// core.setFailed(waitResult.reason);
// return;
// }
// }
}

static async renameSignedObject(): Promise<void> {
return;
}
}
Loading

0 comments on commit 8508fe2

Please sign in to comment.