Skip to content

Commit

Permalink
Devops 8866 role session name action intial implementation (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
alezkv authored Feb 10, 2023
1 parent e7081ea commit 0f3049a
Show file tree
Hide file tree
Showing 13 changed files with 8,476 additions and 283 deletions.
17 changes: 14 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,30 @@ on: # rebuild any PRs and main branch changes
- main
- 'releases/*'

# permission can be added at job level or workflow level
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout

jobs:
build: # make sure build/ci work properly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- run: |
npm install
- run: |
npm run all
test: # make sure the action works on a clean machine without building
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: ./
id: role-session-name
- uses: aws-actions/configure-aws-credentials@v1
with:
milliseconds: 1000
role-to-assume: arn:aws:iam::141011132967:role/GitHub # 141011132967 DevOpsTest
aws-region: us-east-1
role-session-name: ${{ steps.role-session-name.outputs.role-session-name }}
- run: |
aws sts get-caller-identity
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v16.19.0
66 changes: 13 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
<p align="center">
<a href="https://github.com/actions/typescript-action/actions"><img alt="typescript-action status" src="https://github.com/actions/typescript-action/workflows/build-test/badge.svg"></a>
</p>
# role-session-name-action

# Create a JavaScript Action using TypeScript

Use this template to bootstrap the creation of a TypeScript action.:rocket:

This template includes compilation support, tests, a validation workflow, publishing, and versioning guidance.

If you are new, there's also a simpler introduction. See the [Hello World JavaScript Action](https://github.com/actions/hello-world-javascript-action)

## Create an action from this template

Click the `Use this Template` and provide the new repo details for your action
Get GitHub Action context and combine output based on organization,repository, and runId.
Resulted string supposed to be used as `role-session-name` of `aws-actions/configure-aws-credentials`

## Code in Main

> First, you'll need to have a reasonably modern version of `node` handy. This won't work with versions older than 9, for instance.
Install the dependencies
```bash
$ npm install
Expand All @@ -32,44 +19,18 @@ Run the tests :heavy_check_mark:
```bash
$ npm test

PASS ./index.test.js
✓ throws invalid number (3ms)
wait 500 ms (504ms)
test runs (95ms)

...
```

## Change action.yml

The action.yml defines the inputs and output for your action.

Update the action.yml with your name, description, inputs and outputs for your action.

See the [documentation](https://help.github.com/en/articles/metadata-syntax-for-github-actions)

## Change the Code
> [email protected] test
> jest

Most toolkit and CI/CD operations involve async operations so the action is run in an async function.

```javascript
import * as core from '@actions/core';
PASS __tests__/main.test.ts
...

async function run() {
try {
...
}
catch (error) {
core.setFailed(error.message);
}
}

run()
Test Suites: 1 passed, 1 total
Tests: 105 passed, 105 total
Snapshots: 0 total
Time: 0.994 s, estimated 1 s
Ran all test suites.
```

See the [toolkit documentation](https://github.com/actions/toolkit/blob/master/README.md#packages) for the various packages.

## Publish to a distribution branch

Actions are run from GitHub repos so we will checkin the packed dist folder.
Expand All @@ -93,9 +54,8 @@ See the [versioning documentation](https://github.com/actions/toolkit/blob/maste
You can now validate the action by referencing `./` in a workflow in your repo (see [test.yml](.github/workflows/test.yml))

```yaml
uses: ./
with:
milliseconds: 1000
- uses: ./
id: role-session-name
```
See the [actions tab](https://github.com/actions/typescript-action/actions) for runs of this action! :rocket:
Expand Down
212 changes: 190 additions & 22 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,197 @@
import {wait} from '../src/wait'
import * as process from 'process'
import * as cp from 'child_process'
import * as path from 'path'
import {
roleSessionName,
cutMiddle,
cutTail,
deduplicate,
sanityze
} from '../src/role-session-name'
import {expect, test} from '@jest/globals'

test('throws invalid number', async () => {
const input = parseInt('foo', 10)
await expect(wait(input)).rejects.toThrow('milliseconds not a number')
test.concurrent.each([
['', 1, ''],
['Organization/Repository', 1, 'Organization,Repository,1'],
['Organization/Repository', 1234567890, 'Organization,Repository,1234567890'],
[
'OrganizationOrganization/Repository',
1,
'OrganizationOrganization,Repository,1'
],
[
'OrganizationOrganization/Repository',
1234567890,
'OrganizationOrganization,Repository,1234567890'
],
[
'OrganizationOrganizationOrganization/Repository',
1,
'OrganizationOrganizationOrganization,Repository,1'
],
[
'OrganizationOrganizationOrganization/Repository',
1234567890,
'OrganizationOrganizationOrganization,Repository,1234567890'
],
[
'OrganizationOrganizationOrganization/RepositoryRepository',
1,
'OrganizationOrganizationOrganization,RepositoryRepository,1'
],
[
'OrganizationOrganizationOrganization/RepositoryRepository',
1234567890,
'OrganizationOrganizationOrgani..,RepositoryRepository,1234567890'
],
[
'OrganizationOrganizationOrganization/RepositoryRepositoryRepositoryRepositoryRepositoryRepository',
1,
'OrganizationOrgani..,RepositoryRepositor..epositoryRepository,1'
],
[
'OrganizationOrganizationOrganization/RepositoryRepositoryRepositoryRepositoryRepositoryRepository',
1234567890,
'OrganizationOrgani..,RepositoryRepos..itoryRepository,1234567890'
]
])('roleSessionName %s $i', async (name, runId, expected) => {
expect(roleSessionName(name, runId)).toBe(expected)
})

test('wait 500 ms', async () => {
const start = new Date()
await wait(500)
const end = new Date()
var delta = Math.abs(end.getTime() - start.getTime())
expect(delta).toBeGreaterThan(450)
test.concurrent.each([
['a', /a/g, '-'],
['a', /b/g, 'a'],
['aa', /a/g, '--'],
['aa', /b/g, 'aa'],
['aba', /a/g, '-b-'],
['aba', /b/g, 'a-a'],
['aabb', /a/g, '--bb'],
['aabb', /b/g, 'aa--']
])('sanituze %s %s', async (input, regex, expected) => {
expect(sanityze(input, regex)).toBe(expected)
})

// shows how the runner will run a javascript action with env / stdout protocol
test('test runs', () => {
process.env['INPUT_MILLISECONDS'] = '500'
const np = process.execPath
const ip = path.join(__dirname, '..', 'lib', 'main.js')
const options: cp.ExecFileSyncOptions = {
env: process.env
}
console.log(cp.execFileSync(np, [ip], options).toString())
test.concurrent.each([
['', '', ''],
['a', '', 'a'],
['a', 'a', 'a'],
['a', 'b', 'a'],
['aa', '', 'aa'],
['aa', 'a', 'a'],
['aa', 'b', 'aa'],
['aaa', 'a', 'a'],
['aaa', 'b', 'aaa'],
['aaaba', 'a', 'aba'],
['aaaba', 'b', 'aaaba'],
['aaabaa', 'a', 'aba'],
['aaabaa', 'b', 'aaabaa'],
['aaabaaa', 'a', 'aba'],
['aaabaaa', 'b', 'aaabaaa'],
['aaabbaaa', 'a', 'abba'],
['aaabbaaa', 'b', 'aaabaaa'],
['aaabbbaaab', 'a', 'abbbab'],
['aaabbbaaab', 'b', 'aaabaaab']
])('deduplicate %s %s', async (input, deficit, expected) => {
expect(deduplicate(input, deficit)).toBe(expected)
})

test('sannitize + deduplicate', () => {
expect(
roleSessionName('!#$%^&*()_Organ!#$%ization^&*()_/Repository', 1)
).toBe('-_Organ-ization-_,Repository,1')
})

test.concurrent.each([
['', Number.MIN_SAFE_INTEGER, ''],
['a', Number.MIN_SAFE_INTEGER, 'a'],
['ab', Number.MIN_SAFE_INTEGER, 'ab'],
['abc', Number.MIN_SAFE_INTEGER, 'abc'],
['abcd', Number.MIN_SAFE_INTEGER, 'abcd'],
['abcde', Number.MIN_SAFE_INTEGER, 'abcde'],
['abcdef', Number.MIN_SAFE_INTEGER, 'abc..'],
['abcdefg', Number.MIN_SAFE_INTEGER, 'abc..'],
['abcdefgh', Number.MIN_SAFE_INTEGER, 'abcd..'],
['abcdefghi', Number.MIN_SAFE_INTEGER, 'abcd..'],
['abcdefghij', Number.MIN_SAFE_INTEGER, 'abcde..'],
['abcdefghijk', Number.MIN_SAFE_INTEGER, 'abcde..'],
['abcdefghijkl', Number.MIN_SAFE_INTEGER, 'abcdef..'],
['abcdefghijklm', Number.MIN_SAFE_INTEGER, 'abcdef..'],
['abcdefghijklmn', Number.MIN_SAFE_INTEGER, 'abcdefg..'],
['abcdefghijklmno', Number.MIN_SAFE_INTEGER, 'abcdefg..'],
['abcdefghijklmnop', Number.MIN_SAFE_INTEGER, 'abcdefgh..'],
// ...
['abcdefghijklmnop', -6, 'abcdefgh..'],
['abcdefghijklmnop', -5, 'abcdefghi..'],
['abcdefghijklmnop', -4, 'abcdefghij..'],
['abcdefghijklmnop', -3, 'abcdefghijk..'],
['abcdefghijklmnop', -2, 'abcdefghijkl..'],
['abcdefghijklmnop', -1, 'abcdefghijklm..'],
['abcdefghijklmnop', 0, 'abcdefghijklmnop'],
['', 0, ''],
['a', 0, 'a'],
['ab', 0, 'ab'],
['abc', 0, 'abc'],
// ...
[
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz',
0,
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
],
['', Number.MAX_SAFE_INTEGER, ''],
['a', Number.MAX_SAFE_INTEGER, 'a'],
['ab', Number.MAX_SAFE_INTEGER, 'ab'],
['abc', Number.MAX_SAFE_INTEGER, 'abc'],
// ...
[
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz',
Number.MAX_SAFE_INTEGER,
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
]
])('cutTail %s %i', async (input, deficit, expected) => {
expect(cutTail(input, deficit)).toBe(expected)
})

test.concurrent.each([
['', Number.MIN_SAFE_INTEGER, ''],
['a', Number.MIN_SAFE_INTEGER, 'a'],
['ab', Number.MIN_SAFE_INTEGER, 'ab'],
['abc', Number.MIN_SAFE_INTEGER, 'abc'],
['abcd', Number.MIN_SAFE_INTEGER, 'abcd'],
['abcde', Number.MIN_SAFE_INTEGER, 'abcde'],
['abcdef', Number.MIN_SAFE_INTEGER, 'abcdef'],
['abcdefg', Number.MIN_SAFE_INTEGER, 'ab..fg'],
['abcdefghi', Number.MIN_SAFE_INTEGER, 'ab..hi'],
['abcdefghij', Number.MIN_SAFE_INTEGER, 'ab..ij'],
['abcdefghijk', Number.MIN_SAFE_INTEGER, 'ab..jk'],
['abcdefghijkl', Number.MIN_SAFE_INTEGER, 'abc..jkl'],
['abcdefghijklm', Number.MIN_SAFE_INTEGER, 'abc..klm'],
['abcdefghijklmn', Number.MIN_SAFE_INTEGER, 'abc..lmn'],
['abcdefghijklmno', Number.MIN_SAFE_INTEGER, 'abc..mno'],
['abcdefghijklmnop', Number.MIN_SAFE_INTEGER, 'abcd..mnop'],
// ...
['abcdefghijklmnop', -5, 'abcd..mnop'],
['abcdefghijklmnop', -4, 'abcde..lmnop'],
['abcdefghijklmnop', -3, 'abcde..lmnop'],
['abcdefghijklmnop', -2, 'abcdef..klmnop'],
['abcdefghijklmnop', -1, 'abcdef..klmnop'],
['abcdefghijklmnop', 0, 'abcdefghijklmnop'],
['', 0, ''],
['a', 0, 'a'],
['ab', 0, 'ab'],
['abc', 0, 'abc'],
// ...
[
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz',
0,
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
],
['', Number.MAX_SAFE_INTEGER, ''],
['a', Number.MAX_SAFE_INTEGER, 'a'],
['ab', Number.MAX_SAFE_INTEGER, 'ab'],
['abc', Number.MAX_SAFE_INTEGER, 'abc'],
// ...
[
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz',
Number.MAX_SAFE_INTEGER,
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
]
])('cutMiddle(%s, %i)', async (a, b, expected) => {
expect(cutMiddle(a, b)).toBe(expected)
})
13 changes: 5 additions & 8 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
name: 'Your name here'
description: 'Provide a description here'
author: 'Your name or organization here'
inputs:
milliseconds: # change this
required: true
description: 'input description here'
default: 'default value if applicable'
name: 'Get role-session-name'
description: 'Produce valid role-session-name from `github` context. For use by `aws-actions/configure-aws-credentials`'
outputs:
role-session-name:
description: 'Role session name'
runs:
using: 'node16'
main: 'dist/index.js'
Loading

0 comments on commit 0f3049a

Please sign in to comment.