Skip to content

Commit ab68811

Browse files
committed
Merge branch 'ssh-deploy-key'
2 parents 47ce62a + b5ac509 commit ab68811

File tree

3 files changed

+91
-28
lines changed

3 files changed

+91
-28
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM alpine:latest
22

3-
RUN apk add --no-cache git
3+
RUN apk add --no-cache git openssh-client
44

55
COPY entrypoint.sh /entrypoint.sh
66

README.md

Lines changed: 60 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
# github-action-push-to-another-repository
22

3-
When to use this GitHub Action? It is useful in case that you have a GitHub repository with a a directory that you want to push to another GitHub repository using GitHub Actions (automated on push, for example). It is also useful if using GitHub Actions you generate certain files that you want to push to another GitHub repository.
3+
When to use this GitHub Action? It can be used if you have a GitHub repository with a directory that you want to push to another GitHub repository using GitHub Actions (automated on push, for example). It is also useful if when using GitHub Actions, you generate certain files that you want to push to another GitHub repository. For example, if you have MarkDown files and want to generate HTML files, then push them into another repository.
44

55
Flow:
66

7-
The [example repository](https://github.com/cpina/push-to-another-repository-example) has a MarkDown file [main.md](https://github.com/cpina/push-to-another-repository-example/blob/main/main.md)), during the [GitHub Actions flow](https://github.com/cpina/push-to-another-repository-example/blob/main/.github/workflows/ci.yml#L19) it executes [build.sh](https://github.com/cpina/push-to-another-repository-example/blob/main/build.sh) and the output/ directory (configurable via [source-directory](https://github.com/cpina/push-to-another-repository-example/blob/main/.github/workflows/ci.yml#L27) appears in the [output repository](https://github.com/cpina/push-to-another-repository-output).
7+
There are two example repositories:
8+
* [Repository 1](https://github.com/cpina/push-to-another-repository-deploy-keys-example): using SSH deploy keys (recommended)
9+
* [Repository 2](https://github.com/cpina/push-to-another-repository-example): using a personal access token setup
810

9-
Please bear in mind: files in the target repository's specified directory are deleted. This is to make sure that it contains only the generated files in the last run without previously generated files.
11+
On a push of the repositories (thanks to the file [.github/workflows/ci.yml](https://github.com/cpina/push-to-another-repository-deploy-keys-example/tree/main/.github/workflows) it uses Pandoc to read the MarkDown file [main.md](https://github.com/cpina/push-to-another-repository-deploy-ssh-example/blob/main/main.md) (via [this step](https://github.com/cpina/push-to-another-repository-example/blob/main/.github/workflows/ci.yml#L19) and the example [build.sh](https://github.com/cpina/push-to-another-repository-deploy-keys-example/blob/main/build.sh). build.sh generates the output/ directory configurable via [source-directory](https://github.com/cpina/push-to-another-repository-deploy-keys-example/blob/main/.github/workflows/ci.yml#L27) appears in the [output repository](https://github.com/cpina/push-to-another-repository-output).
1012

11-
There are different variables to setup the behaviour:
13+
Please bear in mind: files in the target repository's specified directory are deleted. This is to make sure that it contains only the files generated on the last run.
14+
15+
There are different variables to set up the behaviour:
1216

1317
## Inputs
1418
### `source-directory` (argument)
@@ -42,34 +46,67 @@ The string `ORIGIN_COMMIT` is replaced by `$REPOSITORY_URL@commit`.
4246
### `target-directory` (argument) [optional]
4347
The directory to wipe and replace in the target repository. Defaults to wiping the entire repository
4448

45-
### `API_TOKEN_GITHUB` (environment)
46-
E.g.:
47-
`API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}`
49+
### `SSH_DEPLOY_KEY` or `API_TOKEN_GITHUB`
50+
The action, entirely executed in your GitHub continuous integration environment, needs to be able to push to the destination repository.
51+
52+
There are two options to do this:
53+
* Create an SSH deploy key. This key is restricted to the destination repository only
54+
* Create a GitHub Personal Authentication Token: the token has access to all your repositories
55+
56+
Someone with write access to your repository or this action, could technically add code to leak the key. Thus, *it is recommended to use the SSH deploy key method to minimise repercusions* if this was the case.
57+
58+
This action supports both methods to keep backwards compatibility, because in the beginning it only supported the GitHub Personal Authentication token.
59+
60+
## Setup with SSH deploy key
61+
### Generate the key files
62+
63+
* `ssh-keygen -t ed25519 -C "[email protected]"` (the type ed25519 is recommended by [GitHub documentation](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key))
64+
* ssh will ask for a file path: `Enter file in which to save the key`: write a new file name. I suggest the default directory and as a filename: `id_github_name_of_your_repository` to avoid overwriting a previous file. If you will be using this action for multiple repositories, you might want to generate different keys for each one.
65+
* Leave the passphrase empty (otherwise we would need to pass the passphrase to the GitHub Action)
66+
67+
### Set up the deployment key
68+
69+
#### Destination repository
70+
71+
* Go to the GitHub page of the destination repository
72+
* Click on "Settings" (settings for the repository, not the account settings)
73+
* On the left-hand side pane click on "Deploy keys"
74+
* Click on "Add deploy key"
75+
* Title: "GitHub Action push to another repository"
76+
* Key: paste the contents of the file with the public key. This was generated in the "Generate the key files" step and the name is "id_github_name_of_your_repository.pub"
77+
* Enable "Allow write access"barbar
78+
79+
#### Origin repository
80+
81+
* Go to the GitHub page of the origin repository
82+
* On the left-hand side pane click on "Secrets" and then on "Actions"
83+
* Click on "New repository secret"
84+
* Name: "SSH_DEPLOY_KEY"
85+
* Value: paste the contents of the file with the private key. This was generated in the "Generate the key files" step and the name is "id_github_name_of_your_repository"
86+
87+
### Set up the personal access token
88+
89+
You don't need to do this if you chose to set up the deploy keys using the steps above. This method is here for compatibility with the initial approach of this GitHub Action. The personal access token would have access to all your repositories, so if it were to be leaked the damage would be greater.
4890

4991
Generate your personal token following the steps:
50-
* Go to the Github Settings (on the right hand side on the profile picture)
51-
* On the left hand side pane click on "Developer Settings"
92+
* Go to the GitHub Settings (on the right-hand side on the profile picture)
93+
* On the left-hand side pane click on "Developer Settings"
5294
* Click on "Personal Access Tokens" (also available at https://github.com/settings/tokens)
5395
* Generate a new token, choose "Repo". Copy the token.
5496

55-
⚠️ : The "Personal Access Token" that you just generated gives access to any repository to which you have access (it's not possible to restrict it to one repository). Technically anyone with *write* access to a repository where the token is made available via "Add a new secret" (next step), might manage to access it. The action also uses the token; you can verify how it is used in entrypoint.sh . Possible work arounds if you don't want to use the personal access token:
56-
* Use this action's `ssh-deploy-key` branch. I need to write documentation for this (possibly the next 24 hours, but you create a deploy key and add the private key as a variable in the pushing repository. See updates on https://github.com/cpina/github-action-push-to-another-repository/issues/66
57-
* Use this other action: https://github.com/leigholiver/commit-with-deploy-key
58-
* Create a new GitHub user, give access to your destination repository and use this user for the personal access token
59-
60-
**News: ** new branch https://github.com/cpina/github-action-push-to-another-repository/tree/ssh-deploy-key allowing to use SSH_DEPLOY_KEYS. I will do some more testing and write documentation soon.
61-
6297
Then make the token available to the Github Action following the steps:
63-
* Go to the Github page for the repository that you push from, click on "Settings"
64-
* On the left hand side pane click on "Secrets"
65-
* Click on "Add a new secret" and name it "API_TOKEN_GITHUB"
66-
98+
* Go to the GitHub page for the repository that you push from. Click on "Settings"
99+
* On the left-hand side pane click on "Secrets" then "Actions"
100+
* Click on "New repository secret"
101+
* Name: "API_TOKEN_GITHUB"
102+
* Value: paste the token that you copied earlier
67103

68104
## Example usage
69105
```yaml
70106
- name: Pushes to another repository
71107
uses: cpina/github-action-push-to-another-repository@main
72108
env:
109+
SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }}
73110
API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}
74111
with:
75112
source-directory: 'output'
@@ -78,13 +115,14 @@ Then make the token available to the Github Action following the steps:
78115
user-email: [email protected]
79116
target-branch: main
80117
```
118+
(you only need `SSH_DEPLOY_KEY` or `API_TOKEN_GITHUB` depending on the method that you used)
81119

82120
Working example:
83121

84-
https://github.com/cpina/push-to-another-repository-example/blob/main/.github/workflows/ci.yml
122+
https://github.com/cpina/push-to-another-repository-deploy-keys-example/blob/main/.github/workflows/ci.yml
85123

86124
It generates files from:
87-
https://github.com/cpina/push-to-another-repository-example
125+
https://github.com/cpina/push-to-another-repository-deploy-keys-example
88126

89127
To:
90128
https://github.com/cpina/push-to-another-repository-output

entrypoint.sh

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,31 @@ then
2626
USER_NAME="$DESTINATION_GITHUB_USERNAME"
2727
fi
2828

29+
# Verify that there (potentially) some access to the destination repository
30+
# and set up git (with GIT_CMD variable) and GIT_CMD_REPOSITORY
31+
if [ -n "${SSH_DEPLOY_KEY:=}" ]
32+
then
33+
# Inspired by https://github.com/leigholiver/commit-with-deploy-key/blob/main/entrypoint.sh , thanks!
34+
mkdir --parents "$HOME/.ssh"
35+
DEPLOY_KEY_FILE="$HOME/.ssh/deploy_key"
36+
echo "${SSH_DEPLOY_KEY}" > "$DEPLOY_KEY_FILE"
37+
chmod 600 "$DEPLOY_KEY_FILE"
38+
39+
SSH_KNOWN_HOSTS_FILE="$HOME/.ssh/known_hosts"
40+
ssh-keyscan -H github.com > "$SSH_KNOWN_HOSTS_FILE"
41+
42+
export GIT_SSH_COMMAND="ssh -i "$DEPLOY_KEY_FILE" -o UserKnownHostsFile=$SSH_KNOWN_HOSTS_FILE"
43+
44+
GIT_CMD_REPOSITORY="git@$GITHUB_SERVER:$DESTINATION_REPOSITORY_USERNAME/$DESTINATION_REPOSITORY_NAME.git"
45+
46+
elif [ -n "${API_TOKEN_GITHUB:=}" ]
47+
GIT_CMD_REPOSITORY="https://$DESTINATION_REPOSITORY_USERNAME:the_api_token@$GITHUB_SERVER/$DESTINATION_REPOSITORY_USERNAME/$DESTINATION_REPOSITORY_NAME.git"
48+
then
49+
echo "::error::API_TOKEN_GITHUB and SSH_DEPLOY_KEY are empty. Please fill one (recommended the SSH_DEPLOY_KEY"
50+
exit 1
51+
fi
52+
53+
2954
CLONE_DIR=$(mktemp -d)
3055

3156
echo "[+] Git version"
@@ -37,12 +62,12 @@ git config --global user.email "$USER_EMAIL"
3762
git config --global user.name "$USER_NAME"
3863

3964
{
40-
git clone --single-branch --branch "$TARGET_BRANCH" "https://$DESTINATION_REPOSITORY_USERNAME:$API_TOKEN_GITHUB@$GITHUB_SERVER/$DESTINATION_REPOSITORY_USERNAME/$DESTINATION_REPOSITORY_NAME.git" "$CLONE_DIR"
65+
git clone --single-branch --branch "$TARGET_BRANCH" "$GIT_CMD_REPOSITORY" "$CLONE_DIR"
4166
} || {
4267
echo "::error::Could not clone the destination repository. Command:"
43-
echo "::error::git clone --single-branch --branch $TARGET_BRANCH https://$DESTINATION_REPOSITORY_USERNAME:the_api_token@$GITHUB_SERVER/$DESTINATION_REPOSITORY_USERNAME/$DESTINATION_REPOSITORY_NAME.git $CLONE_DIR"
44-
echo "::error::(Note that USER_NAME and API_TOKEN is redacted by GitHub)"
45-
echo "::error::Please verify that the target repository exist AND that it contains the destination branch name, and is accesible by the API_TOKEN_GITHUB"
68+
echo "::error::git clone --single-branch --branch $TARGET_BRANCH $GIT_CMD_REPOSITORY $CLONE_DIR"
69+
echo "::error::(Note that if they exist USER_NAME and API_TOKEN is redacted by GitHub)"
70+
echo "::error::Please verify that the target repository exist AND that it contains the destination branch name, and is accesible by the API_TOKEN_GITHUB OR SSH_DEPLOY_KEY"
4671
exit 1
4772

4873
}
@@ -117,4 +142,4 @@ git diff-index --quiet HEAD || git commit --message "$COMMIT_MESSAGE"
117142

118143
echo "[+] Pushing git commit"
119144
# --set-upstream: sets de branch when pushing to a branch that does not exist
120-
git push "https://$USER_NAME:$API_TOKEN_GITHUB@$GITHUB_SERVER/$DESTINATION_REPOSITORY_USERNAME/$DESTINATION_REPOSITORY_NAME.git" --set-upstream "$TARGET_BRANCH"
145+
git push "$GIT_CMD_REPOSITORY" --set-upstream "$TARGET_BRANCH"

0 commit comments

Comments
 (0)