-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from im-open/transfer
ARCH-1919 - Transfer to Infra-Purple
- Loading branch information
Showing
13 changed files
with
698 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
* @im-open/swat | ||
* @im-open/infra-purple |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,3 +60,291 @@ jobs: | |
# The npm script to run to build the action. This is typically 'npm run build' if the | ||
# action needs to be compiled. For composite-run-steps actions this is typically empty. | ||
build-command: 'npm run build' | ||
|
||
test: | ||
runs-on: ubuntu-latest | ||
|
||
env: | ||
ORG: 'im-open' | ||
THIS_REPO: 'setup-deploy-keys' | ||
INTERNAL_REPO_TO_CLONE: 'im-open/internal-repo-for-testing' | ||
INTERNAL_REPO_TO_CLONE_DIR: 'internal-repo-for-testing' | ||
|
||
# The private key which will be used to clone the internal & empty deploy-keys-testing repo. | ||
# The repo does not contain anything sensitive, it is just marked as internal so the key can be tested here. | ||
# This SSH key was generated as a readonly key (so no push abilities). | ||
INTERNAL_REPO_TO_CLONE_KEY: ${{ secrets.SSH_KEY_TESTING_REPO }} | ||
SSH_DEPLOY_KEY_INFO: | | ||
[ | ||
{ "orgAndRepo": "im-open/internal-repo-for-testing", "envName" : "INTERNAL_REPO_TO_CLONE_KEY" } | ||
] | ||
steps: | ||
#-------------------------------------- | ||
# SETUP | ||
#-------------------------------------- | ||
- name: Fail test job if fork | ||
run: | | ||
if [ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]; then | ||
echo "This test job requires secrets that PRs from forks will not have access to. Before this PR can be merged, the tests should be run on an intermediate branch created by repository owners." | ||
exit 1 | ||
fi | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: Setup - Checkout the action | ||
if: always() | ||
uses: actions/checkout@v3 | ||
|
||
- name: Setup - Verify the internal repo to clone dir does not exist | ||
if: always() | ||
run: ./test/assert-dir-does-not-exist.sh --path "./${{ env.INTERNAL_REPO_TO_CLONE_DIR }}" | ||
|
||
- name: Setup - Verify the ssh-agent is not running | ||
if: always() | ||
run: ./test/assert-ssh-agent-is-not-running.sh | ||
|
||
- name: Setup - Verify .gitconfig does not contain any insteadOf urls (because it does not exist) | ||
if: always() | ||
run: | | ||
if [ -f "~/.gitconfig" ] | ||
then | ||
echo "The .gitconfig file exists which is unexpected" | ||
exit 1 | ||
else | ||
echo "The .gitconfig file does not exist which is expected. No insteadOf rules exist." | ||
exit 0 | ||
fi | ||
- name: Setup - Verify the ssh config has no configuration (because it does not exist) | ||
working-directory: /home/runner | ||
if: always() | ||
run: | | ||
TARGET_FILE=".ssh/config" | ||
if [ -f "$TARGET_FILE" ] | ||
then | ||
echo "$TARGET_FILE exists which is NOT expected. Contents:" | ||
cat $TARGET_FILE | ||
exit 1 | ||
else | ||
echo "$TARGET_FILE does not exist which is expected." | ||
fi | ||
#-------------------------------------------- | ||
# VALIDATE STARTING CONDITIONS/NO PERMISSIONS | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When an internal repo is cloned with the default PAT | ||
if: always() | ||
id: internal-failure | ||
continue-on-error: true # This is needed because we expect the step to fail. We need it to "pass" in order for the test job to succeed. | ||
run: git clone [email protected]:${{ env.INTERNAL_REPO_TO_CLONE }}.git | ||
|
||
- name: Then the outcome should be failure because of lack of permissions to clone an internal repo | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.internal-failure.outcome }}" | ||
|
||
- name: And the directory for the internal repo to clone should not exist | ||
if: always() | ||
run: ./test/assert-dir-does-not-exist.sh --path "./${{ env.INTERNAL_REPO_TO_CLONE_DIR }}" | ||
|
||
- name: And the ssh-agent should be running | ||
if: always() | ||
run: ./test/assert-ssh-agent-is-running.sh | ||
|
||
#-------------------------------------------- | ||
# SETUP DEPLOY KEYS AND CLONE INTERNAL REPO | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When setup-deploy-keys is run with a key for the internal repo | ||
if: always() | ||
id: setup-deploy-keys | ||
uses: ./ | ||
with: | ||
deploy-key-info: ${{ env.SSH_DEPLOY_KEY_INFO }} | ||
|
||
- name: And the internal repo is cloned | ||
if: always() | ||
id: internal-success | ||
run: git clone [email protected]:${{ env.INTERNAL_REPO_TO_CLONE }}.git | ||
|
||
- name: Then the outcome should be success | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "success" --actual "${{ steps.internal-success.outcome }}" | ||
|
||
- name: And the ssh-agent should be running | ||
if: always() | ||
run: ./test/assert-ssh-agent-is-running.sh | ||
|
||
- name: And the directory for the internal repo to clone dir should exist | ||
if: always() | ||
run: ./test/assert-dir-exists.sh --path "./${{ env.INTERNAL_REPO_TO_CLONE_DIR }}" | ||
|
||
- name: And the .gitconfig should exist with 3 entries for ${{ env.INTERNAL_REPO_TO_CLONE }} insteadOf urls | ||
if: always() | ||
run: | | ||
configEntries=$(git config --get-regexp "${{ steps.setup-deploy-keys.outputs.key-filename }}") | ||
count=0 | ||
while IFS=$'\n' read -ra ENTRIES; do | ||
for i in "${ENTRIES[@]}"; do | ||
count=$((count+1)) | ||
echo -e "\nEntry $count: '$i'" | ||
done | ||
done <<< "$configEntries" | ||
if [ $count -ne 3 ] | ||
then | ||
echo -e "\nExpected 3 insteadOf entries in .gitconfig but found $count" | ||
exit 1 | ||
else | ||
echo -e "\nThere were 3 insteadOf entries in the .gitconfig as expected." | ||
fi | ||
- name: And the ssh config should exist with an entry for ${{ env.INTERNAL_REPO_TO_CLONE }} | ||
if: always() | ||
run: | | ||
TARGET_FILE="/home/runner/.ssh/config" | ||
if [ -f "$TARGET_FILE" ] | ||
then | ||
echo "$TARGET_FILE exists which is expected." | ||
actualContent=$(cat $TARGET_FILE) | ||
else | ||
echo "$TARGET_FILE does not exist which is not expected" | ||
exit 1 | ||
fi | ||
rawExpectedContent=$(cat ./test/files/expected-ssh-host.txt) | ||
hostKey="${{ steps.setup-deploy-keys.outputs.key-filename }}" | ||
expectedContent=$(echo "${rawExpectedContent//REPLACEME/"$hostKey"}" ) | ||
./test/assert-values-match.sh --name "ssh config" --expected "$expectedContent" --actual "$actualContent" | ||
#-------------------------------------------- | ||
# UN-PARSEABLE INPUT | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When setup-deploy-keys is run with an un-parseable input | ||
uses: ./ | ||
if: always() | ||
id: unparseable | ||
continue-on-error: true # This is needed because we expect the step to fail. We need it to "pass" in order for the test job to succeed. | ||
with: | ||
deploy-key-info: '[ orgAndRepo=im-open/internal-repo-for-testing, envName=INTERNAL_REPO_TO_CLONE_KEY ]' | ||
|
||
- name: Then the outcome should be failure | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.unparseable.outcome }}" | ||
|
||
- name: And the validation-error output should be 'argument-parsing' | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "validation-error" --expected "argument-parsing" --actual "${{ steps.unparseable.outputs.validation-error }}" | ||
|
||
#-------------------------------------------- | ||
# EMPTY ARRAY | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When setup-deploy-keys is run with an empty array | ||
uses: ./ | ||
if: always() | ||
id: empty-array | ||
continue-on-error: true # This is needed because we expect the step to fail. We need it to "pass" in order for the test job to succeed. | ||
with: | ||
deploy-key-info: '[]' | ||
|
||
- name: Then the outcome should be failure | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.empty-array.outcome }}" | ||
|
||
- name: And the validation-error output should be 'empty-keys' | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "validation-error" --expected "empty-keys" --actual "${{ steps.empty-array.outputs.validation-error }}" | ||
|
||
#-------------------------------------------- | ||
# EMPTY orgAndRepo ARG | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When setup-deploy-keys is run with a missing orgAndRepo | ||
uses: ./ | ||
if: always() | ||
id: missing-orgAndRepo | ||
continue-on-error: true # This is needed because we expect the step to fail. We need it to "pass" in order for the test job to succeed. | ||
with: | ||
deploy-key-info: | | ||
[ | ||
{ "orgAndRepo": "", "envName" : "INTERNAL_REPO_TO_CLONE_KEY" } | ||
] | ||
- name: Then the outcome should be failure | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.missing-orgAndRepo.outcome }}" | ||
|
||
- name: And the validation-error output should be 'missing-orgAndRepo' | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "validation-error" --expected "missing-orgAndRepo" --actual "${{ steps.missing-orgAndRepo.outputs.validation-error }}" | ||
|
||
#-------------------------------------------- | ||
# EMPTY envName ARG | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When setup-deploy-keys is run with a missing envName | ||
uses: ./ | ||
if: always() | ||
id: missing-envName | ||
continue-on-error: true # This is needed because we expect the step to fail. We need it to "pass" in order for the test job to succeed. | ||
with: | ||
deploy-key-info: | | ||
[ | ||
{ "orgAndRepo": "im-open/internal-repo-for-testing", "envName" : "" } | ||
] | ||
- name: Then the outcome should be failure | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.missing-envName.outcome }}" | ||
|
||
- name: And the validation-error output should be 'missing-envName' | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "validation-error" --expected "missing-envName" --actual "${{ steps.missing-envName.outputs.validation-error }}" | ||
|
||
#-------------------------------------------- | ||
# UNPOPULATED ENV VAR FOR SECRET | ||
#-------------------------------------------- | ||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" | ||
|
||
- name: When setup-deploy-keys is run with an unpopulated env var | ||
uses: ./ | ||
if: always() | ||
id: unpopulated-env | ||
continue-on-error: true # This is needed because we expect the step to fail. We need it to "pass" in order for the test job to succeed. | ||
with: | ||
deploy-key-info: | | ||
[ | ||
{ "orgAndRepo": "im-open/internal-repo-for-testing", "envName" : "UNPOPULATED_ENV_VARIABLE" } | ||
] | ||
- name: Then the outcome should be failure | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "step outcome" --expected "failure" --actual "${{ steps.unpopulated-env.outcome }}" | ||
|
||
- name: And the validation-error output should be 'unpopulated-env-var' | ||
if: always() | ||
run: ./test/assert-values-match.sh --name "validation-error" --expected "unpopulated-env-var" --actual "${{ steps.unpopulated-env.outputs.validation-error }}" | ||
|
||
- name: '-------------------------------------------------------------------------------------------------------' | ||
run: echo "" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,20 +10,23 @@ This modified action will take care of: | |
- Adding `insteadOf` rules in the git config. These rules will rewrite git urls it encounters for the provided org/repo and point to the applicable alias entry that was added to the ssh config. This will ensure it uses the right deploy key when interacting with different private repositories. | ||
|
||
These entries and `insteadOf` rules are necessary when using multiple deploy keys because of the way GitHub handles requests. From [webfactory/ssh-agent]: | ||
> When using Github deploy keys, GitHub servers will accept the first known key. But since deploy keys are scoped to a single repository, this might not be the key needed to access a particular repository. Thus, you will get the error message fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists. if the wrong key/repository combination is tried. | ||
> When using Github deploy keys, GitHub servers will accept the first known key. But since deploy keys are scoped to a single repository, this might not be the key needed to access a particular repository. Thus, you will get the error message fatal: "*Could not read from remote repository. Please make sure you have the correct access rights and the repository exists*" if the wrong key/repository combination is tried. | ||
More details on context, usage, troubleshooting or known issues and limitations can be found on the original repository [webfactory/ssh-agent]. | ||
|
||
## Index <!-- omit in toc --> | ||
|
||
- [Setup Deploy Keys](#setup-deploy-keys) | ||
- [Inputs](#inputs) | ||
- [Outputs](#outputs) | ||
- [validation-error Output](#validation-error-output) | ||
- [Usage Examples](#usage-examples) | ||
- [Contributing](#contributing) | ||
- [Incrementing the Version](#incrementing-the-version) | ||
- [Source Code Changes](#source-code-changes) | ||
- [Recompiling Manually](#recompiling-manually) | ||
- [Updating the README.md](#updating-the-readmemd) | ||
- [Tests](#tests) | ||
- [Code of Conduct](#code-of-conduct) | ||
- [License](#license) | ||
|
||
|
@@ -33,6 +36,35 @@ More details on context, usage, troubleshooting or known issues and limitations | |
|-------------------|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| `deploy-key-info` | true | An array of deploy key info objects that contain the org/repo that the deploy key is intended for as well as the name of the environment variable that contains the private key's value. | | ||
|
||
## Outputs | ||
|
||
This action has two outputs which can be used by the workflows but are generally reserved for testing. | ||
| Output | Description | | ||
|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| `validation-error` | A string with a short description of a validation error that occurred. Generally used for testing but can be used programmatically to detect which types of validation errors the action is encountering. | | ||
| `key-filename` | The name of the file where the key was written to disk. Generally used for testing because the output only reflects the last key that was processed. | | ||
|
||
### validation-error Output | ||
|
||
The `validation-error` output will only contain one validation error at a time. If multiple keys or multiple error conditions exist, this output cannot reliably indicate those conditions. The output was designed to be used for testing specific error conditions and may not be suitable for regular production use. | ||
|
||
- `argument-parsing` - This occurs when there is an error JSON parsing the `deploy-key-info` argument. It should be a string containing a parseable JSON array of objects that contain two arguments: | ||
|
||
```yml | ||
[ | ||
# orgAndRepo should contain the organization/repository that the deploy key is being setup for. | ||
# envName is the name of an environment variable that contains the private key for accessing | ||
# the orgAndRepo. It is not the value of the actual environment variable. | ||
{ orgAndRepo: 'im-open/repo-1', envName: 'NAME_OF_ENV_WITH_PRIVATE_KEY_1'}, | ||
{ orgAndRepo: 'im-open/repo-2', envName: 'NAME_OF_ENV_WITH_PRIVATE_KEY_2'} | ||
] | ||
``` | ||
|
||
- `empty-keys` - The `deploy-key-info` argument was an empty array. | ||
- `missing-orgAndRepo` - One of the provided deploy keys is missing the `orgAndRepo` argument. | ||
- `missing-envName` - One of the provided deploy keys is missing the `envName` argument. | ||
- `unpopulated-env-var` - One of the environment variables provided as an `envName` has not been populated. | ||
|
||
## Usage Examples | ||
|
||
```yml | ||
|
@@ -54,7 +86,7 @@ jobs: | |
|
||
- name: Setup deploy keys for use with Terraform | ||
# You may also reference just the major or major.minor version | ||
uses: im-open/[email protected].3 | ||
uses: im-open/[email protected].4 | ||
with: | ||
deploy-key-info: | | ||
[ | ||
|
@@ -82,6 +114,7 @@ When creating PRs, please review the following guidelines: | |
- [ ] At least one of the commit messages contains the appropriate `+semver:` keywords listed under [Incrementing the Version] for major and minor increments. | ||
- [ ] The action has been recompiled. See [Recompiling Manually] for details. | ||
- [ ] The README.md has been updated with the latest version of the action. See [Updating the README.md] for details. | ||
- [ ] Any tests in the [build-and-review-pr] workflow are passing | ||
|
||
### Incrementing the Version | ||
|
||
|
@@ -116,6 +149,12 @@ npm run build | |
|
||
If changes are made to the action's [source code], the [usage examples] section of this file should be updated with the next version of the action. Each instance of this action should be updated. This helps users know what the latest tag is without having to navigate to the Tags page of the repository. See [Incrementing the Version] for details on how to determine what the next version will be or consult the first workflow run for the PR which will also calculate the next version. | ||
|
||
### Tests | ||
|
||
The [build-and-review-pr] workflow includes tests which are linked to a status check. That status check needs to succeed before a PR is merged to the default branch. When a PR comes from a branch, the workflow has access to secrets which are required to run the tests successfully. | ||
|
||
When a PR comes from a fork, the workflow cannot access any secrets, so the tests won't have the necessary permissions to run. When a PR comes from a fork, the changes should be reviewed, then merged into an intermediate branch by repository owners so tests can be run against the PR changes. Once the tests have passed, changes can be merged into the default branch. | ||
|
||
## Code of Conduct | ||
|
||
This project has adopted the [im-open's Code of Conduct](https://github.com/im-open/.github/blob/main/CODE_OF_CONDUCT.md). | ||
|
Oops, something went wrong.