Skip to content

Commit b958732

Browse files
security: harden mirror workflow with SSH host key verification (#1)
- Add SSH host key verification for GitLab, Codeberg, and Bitbucket to prevent MITM attacks (uses ed25519 keys) - Reduce permissions from read-all to contents: read (least privilege) - Add set -euo pipefail for proper error handling in shell scripts - Add failure reporting steps for clearer error diagnostics - Improve variable handling with proper quoting - Add GitHub Actions log grouping for better readability Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7617e84 commit b958732

1 file changed

Lines changed: 103 additions & 4 deletions

File tree

.github/workflows/mirror.yml

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@ on:
66
branches: [main, master]
77
workflow_dispatch:
88

9-
permissions: read-all
9+
# Principle of least privilege - only request what's needed
10+
permissions:
11+
contents: read
12+
13+
env:
14+
# SSH host keys for verification (prevents MITM attacks)
15+
# These are the official public host keys from each service
16+
GITLAB_HOST_KEY: "gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf"
17+
CODEBERG_HOST_KEY: "codeberg.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIVIC02vnjFyL+I4RHfvIGNtOgJMe769VTF1VR4EB3ZB"
18+
BITBUCKET_HOST_KEY: "bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO"
1019

1120
jobs:
1221
mirror-gitlab:
@@ -16,14 +25,44 @@ jobs:
1625
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
1726
with:
1827
fetch-depth: 0
28+
29+
- name: Setup SSH known_hosts
30+
run: |
31+
mkdir -p ~/.ssh
32+
chmod 700 ~/.ssh
33+
echo "${{ env.GITLAB_HOST_KEY }}" >> ~/.ssh/known_hosts
34+
chmod 600 ~/.ssh/known_hosts
35+
1936
- uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387 # v0.9.0
2037
with:
2138
ssh-private-key: ${{ secrets.GITLAB_SSH_KEY }}
39+
2240
- name: Mirror to GitLab
41+
id: mirror
2342
run: |
24-
git remote add gitlab git@gitlab.com:hyperpolymath/${GITHUB_REPOSITORY#*/}.git || true
43+
set -euo pipefail
44+
REPO_NAME="${GITHUB_REPOSITORY#*/}"
45+
REMOTE_URL="git@gitlab.com:hyperpolymath/${REPO_NAME}.git"
46+
47+
echo "::group::Adding remote"
48+
git remote add gitlab "$REMOTE_URL" 2>/dev/null || git remote set-url gitlab "$REMOTE_URL"
49+
echo "::endgroup::"
50+
51+
echo "::group::Pushing branches"
2552
git push gitlab --all --force
53+
echo "::endgroup::"
54+
55+
echo "::group::Pushing tags"
2656
git push gitlab --tags --force
57+
echo "::endgroup::"
58+
59+
echo "mirror_status=success" >> "$GITHUB_OUTPUT"
60+
61+
- name: Report failure
62+
if: failure()
63+
run: |
64+
echo "::error::GitLab mirror failed. Check SSH key configuration and repository access."
65+
exit 1
2766
2867
mirror-codeberg:
2968
runs-on: ubuntu-latest
@@ -32,14 +71,44 @@ jobs:
3271
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
3372
with:
3473
fetch-depth: 0
74+
75+
- name: Setup SSH known_hosts
76+
run: |
77+
mkdir -p ~/.ssh
78+
chmod 700 ~/.ssh
79+
echo "${{ env.CODEBERG_HOST_KEY }}" >> ~/.ssh/known_hosts
80+
chmod 600 ~/.ssh/known_hosts
81+
3582
- uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387 # v0.9.0
3683
with:
3784
ssh-private-key: ${{ secrets.CODEBERG_SSH_KEY }}
85+
3886
- name: Mirror to Codeberg
87+
id: mirror
3988
run: |
40-
git remote add codeberg git@codeberg.org:hyperpolymath/${GITHUB_REPOSITORY#*/}.git || true
89+
set -euo pipefail
90+
REPO_NAME="${GITHUB_REPOSITORY#*/}"
91+
REMOTE_URL="git@codeberg.org:hyperpolymath/${REPO_NAME}.git"
92+
93+
echo "::group::Adding remote"
94+
git remote add codeberg "$REMOTE_URL" 2>/dev/null || git remote set-url codeberg "$REMOTE_URL"
95+
echo "::endgroup::"
96+
97+
echo "::group::Pushing branches"
4198
git push codeberg --all --force
99+
echo "::endgroup::"
100+
101+
echo "::group::Pushing tags"
42102
git push codeberg --tags --force
103+
echo "::endgroup::"
104+
105+
echo "mirror_status=success" >> "$GITHUB_OUTPUT"
106+
107+
- name: Report failure
108+
if: failure()
109+
run: |
110+
echo "::error::Codeberg mirror failed. Check SSH key configuration and repository access."
111+
exit 1
43112
44113
mirror-bitbucket:
45114
runs-on: ubuntu-latest
@@ -48,11 +117,41 @@ jobs:
48117
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
49118
with:
50119
fetch-depth: 0
120+
121+
- name: Setup SSH known_hosts
122+
run: |
123+
mkdir -p ~/.ssh
124+
chmod 700 ~/.ssh
125+
echo "${{ env.BITBUCKET_HOST_KEY }}" >> ~/.ssh/known_hosts
126+
chmod 600 ~/.ssh/known_hosts
127+
51128
- uses: webfactory/ssh-agent@dc588b651fe13675774614f8e6a936a468676387 # v0.9.0
52129
with:
53130
ssh-private-key: ${{ secrets.BITBUCKET_SSH_KEY }}
131+
54132
- name: Mirror to Bitbucket
133+
id: mirror
55134
run: |
56-
git remote add bitbucket git@bitbucket.org:hyperpolymath/${GITHUB_REPOSITORY#*/}.git || true
135+
set -euo pipefail
136+
REPO_NAME="${GITHUB_REPOSITORY#*/}"
137+
REMOTE_URL="git@bitbucket.org:hyperpolymath/${REPO_NAME}.git"
138+
139+
echo "::group::Adding remote"
140+
git remote add bitbucket "$REMOTE_URL" 2>/dev/null || git remote set-url bitbucket "$REMOTE_URL"
141+
echo "::endgroup::"
142+
143+
echo "::group::Pushing branches"
57144
git push bitbucket --all --force
145+
echo "::endgroup::"
146+
147+
echo "::group::Pushing tags"
58148
git push bitbucket --tags --force
149+
echo "::endgroup::"
150+
151+
echo "mirror_status=success" >> "$GITHUB_OUTPUT"
152+
153+
- name: Report failure
154+
if: failure()
155+
run: |
156+
echo "::error::Bitbucket mirror failed. Check SSH key configuration and repository access."
157+
exit 1

0 commit comments

Comments
 (0)