Skip to content

Commit 7875120

Browse files
authored
Merge pull request #511 from ByteInternet/revise-workflows-standards
Revise workflows based on correct security standards
2 parents 5646171 + 6bc4b7f commit 7875120

7 files changed

Lines changed: 237 additions & 91 deletions

File tree

.github/workflows/cleanup_acceptance.yaml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
name: Cleanup acceptance environments
22

33
on:
4-
pull_request:
4+
pull_request_target:
55
types: [closed]
66

7+
permissions:
8+
contents: read
9+
710
jobs:
811
cleanup:
912
runs-on: ubuntu-latest
1013
container: quay.io/hypernode/deploy:latest-php8.4-node22
1114
environment: acceptance
15+
permissions:
16+
contents: read
1217
steps:
13-
- uses: actions/checkout@v2
14-
- name: Dump env
15-
run: env
18+
- uses: actions/checkout@v4
19+
with:
20+
ref: ${{ github.event.pull_request.base.sha }}
1621
- name: Cleanup acceptance environments
1722
run: hypernode-deploy cleanup acceptance -vvv
1823
env:

.github/workflows/deploy.yaml

Lines changed: 22 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,39 @@
1-
name: Deploy application
1+
name: Deploy to production
22

33
on:
4-
pull_request_target:
54
push:
65
branches:
76
- 'master'
87

9-
env:
10-
COMPOSER_CACHE_DIR: /tmp/composer-cache
8+
concurrency:
9+
group: production
10+
cancel-in-progress: false
11+
12+
permissions:
13+
contents: read
1114

1215
jobs:
1316
build:
1417
runs-on: ubuntu-latest
18+
timeout-minutes: 30
19+
permissions:
20+
contents: read
1521
container: quay.io/hypernode/deploy:latest-php8.4-node22
1622
steps:
17-
- uses: actions/checkout@v3
23+
- uses: actions/checkout@v4
1824
with:
25+
# updated_at.py reads the git log to render per-page timestamps.
1926
fetch-depth: 0
20-
ref: ${{ github.event.pull_request.head.sha || github.sha }}
21-
# Declares the repository safe and not under dubious ownership.
2227
- name: Add repository to git safe directories
2328
run: git config --global --add safe.directory $GITHUB_WORKSPACE
24-
- uses: actions/cache@v3
25-
with:
26-
path: /tmp/composer-cache
27-
key: ${{ runner.os }}-composer
28-
- uses: webfactory/ssh-agent@v0.7.0
29-
with:
30-
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
3129
- name: Set env for production build
32-
if: github.ref == 'refs/heads/master'
3330
run: |
3431
echo "DOCS_BASE_URL=https://docs.hypernode.com/" >> $GITHUB_ENV
3532
echo "DOCS_INDEX_FOLLOW=1" >> $GITHUB_ENV
33+
# The prepare:ssh task fails on an empty ssh-agent, but building needs no
34+
# server access, so satisfy it with a key that grants access to nothing.
35+
- name: Generate a throwaway SSH key for the build
36+
run: mkdir -p ~/.ssh && ssh-keygen -t ed25519 -N '' -q -f ~/.ssh/id_ed25519
3637
- run: hypernode-deploy build -vvv
3738
- name: archive production artifacts
3839
uses: actions/upload-artifact@v4
@@ -41,78 +42,24 @@ jobs:
4142
path: build/build.tgz
4243
retention-days: 5
4344

44-
deploy_acceptance:
45-
needs: build
46-
runs-on: ubuntu-latest
47-
environment:
48-
name: acceptance
49-
url: ${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}
50-
if: github.event_name == 'pull_request_target'
51-
container: quay.io/hypernode/deploy:latest-php8.4-node22
52-
steps:
53-
- uses: actions/checkout@v3
54-
with:
55-
fetch-depth: 0
56-
ref: ${{ github.event.pull_request.head.sha || github.sha }}
57-
- name: download build artifact
58-
uses: actions/download-artifact@v4
59-
with:
60-
name: deployment-build
61-
path: build/
62-
- uses: webfactory/ssh-agent@v0.5.4
63-
with:
64-
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
65-
- run: mkdir -p $HOME/.ssh
66-
- name: deploy to acceptance
67-
run: hypernode-deploy deploy acceptance -vvv --reuse-brancher
68-
env:
69-
HYPERNODE_API_TOKEN: ${{ secrets.HYPERNODE_API_TOKEN }}
70-
- name: Get brancher hostname
71-
id: get_brancher_hostname
72-
run: echo "BRANCHER_URL=https://$(jq .hostnames[0] deployment-report.json -r)" >> $GITHUB_OUTPUT
73-
- name: Get changed pages
74-
id: changed_pages
75-
run: |
76-
git config --global --add safe.directory $(pwd)
77-
commits=${{ github.event.pull_request.commits }}
78-
if [[ -n "$commits" ]]; then
79-
# Prepare enough depth for diffs with target branch
80-
git fetch --depth="$(( commits + 1 ))"
81-
fi
82-
result="$(python3 ci/bin/get_changed_urls.py \
83-
${{ github.event.pull_request.base.sha }} \
84-
${{github.event.pull_request.head.sha}} \
85-
--base-url=${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}
86-
)"
87-
echo "$result"
88-
echo "CHANGED_PAGES<<EOF" >> $GITHUB_OUTPUT
89-
echo "$result" >> $GITHUB_OUTPUT
90-
echo "EOF" >> $GITHUB_OUTPUT
91-
shell: bash
92-
- name: Comment hostname on PR
93-
uses: thollander/actions-comment-pull-request@v1
94-
with:
95-
message: |
96-
Acceptance server is available at ${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}.
97-
${{ steps.changed_pages.outputs.CHANGED_PAGES }}
98-
9945
deploy_production:
10046
needs: build
10147
runs-on: ubuntu-latest
102-
concurrency: production
48+
timeout-minutes: 30
10349
environment:
10450
name: production
105-
url: https://docs.hypernode.io
106-
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
51+
url: https://docs.hypernode.com
52+
permissions:
53+
contents: read
10754
container: quay.io/hypernode/deploy:latest-php8.4-node22
10855
steps:
109-
- uses: actions/checkout@v3
56+
- uses: actions/checkout@v4
11057
- name: download build artifact
11158
uses: actions/download-artifact@v4
11259
with:
11360
name: deployment-build
11461
path: build/
115-
- uses: webfactory/ssh-agent@v0.5.4
62+
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
11663
with:
11764
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
11865
- run: mkdir -p $HOME/.ssh

.github/workflows/lint.yaml

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,31 @@ on:
55

66
permissions:
77
contents: read
8-
pull-requests: write
98

109
jobs:
1110
test:
1211
runs-on: ubuntu-latest
13-
strategy:
14-
matrix:
15-
python-version: ['3.12']
12+
permissions:
13+
contents: read
14+
pull-requests: write
1615

1716
steps:
18-
- uses: actions/checkout@v4
17+
- name: Check out trusted dependency manifests from the base branch
18+
uses: actions/checkout@v4
1919
with:
20-
ref: ${{ github.event.pull_request.head.sha }}
20+
ref: ${{ github.event.pull_request.base.sha }}
2121
- uses: actions/setup-python@v5
2222
with:
23-
python-version: ${{ matrix.python-version }}
24-
- name: Install dependencies
23+
python-version: '3.12'
24+
- name: Install dependencies from the base branch
2525
run: |
2626
pip install -r requirements/base.txt
27+
- name: Check out the pull request head
28+
uses: actions/checkout@v4
29+
with:
30+
ref: ${{ github.event.pull_request.head.sha }}
2731
- name: Check markdown format
2832
run: mdformat docs/
29-
- uses: parkerbxyz/suggest-changes@v2
33+
- uses: parkerbxyz/suggest-changes@e24c62a5a3235e6090721c7b0355b825a3a4ba9a # v3.1.2
3034
with:
3135
event: 'REQUEST_CHANGES'

.github/workflows/pr-build.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Build pull request
2+
3+
on:
4+
pull_request:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
container: quay.io/hypernode/deploy:latest-php8.4-node22
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
- name: Add repository to git safe directories
20+
run: git config --global --add safe.directory $GITHUB_WORKSPACE
21+
# The prepare:ssh task fails on an empty ssh-agent, but building needs no
22+
# server access, so satisfy it with a key that grants access to nothing.
23+
- name: Generate a throwaway SSH key for the build
24+
run: mkdir -p ~/.ssh && ssh-keygen -t ed25519 -N '' -q -f ~/.ssh/id_ed25519
25+
- run: hypernode-deploy build -vvv
26+
- name: archive build artifact
27+
uses: actions/upload-artifact@v4
28+
with:
29+
name: deployment-build
30+
path: build/build.tgz
31+
retention-days: 5

.github/workflows/pr-deploy.yaml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: Deploy pull request to acceptance
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Build pull request"]
6+
types: [completed]
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
deploy_acceptance:
13+
if: >-
14+
github.event.workflow_run.event == 'pull_request' &&
15+
github.event.workflow_run.conclusion == 'success'
16+
runs-on: ubuntu-latest
17+
timeout-minutes: 30
18+
concurrency:
19+
group: acceptance-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
20+
cancel-in-progress: false
21+
environment:
22+
name: acceptance
23+
url: ${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}
24+
permissions:
25+
actions: read
26+
contents: read
27+
pull-requests: write
28+
statuses: write
29+
container: quay.io/hypernode/deploy:latest-php8.4-node22
30+
steps:
31+
- name: Resolve the pull request behind this build
32+
id: pr
33+
uses: actions/github-script@v7
34+
with:
35+
script: |
36+
const run = context.payload.workflow_run;
37+
38+
// Populated for same-repository branches, empty for forks.
39+
let number = (run.pull_requests || []).map((p) => p.number)[0];
40+
if (!number) {
41+
const { data: prs } =
42+
await github.rest.repos.listPullRequestsAssociatedWithCommit({
43+
owner: context.repo.owner,
44+
repo: context.repo.repo,
45+
commit_sha: run.head_sha,
46+
});
47+
number = prs.filter((p) => p.state === 'open').map((p) => p.number)[0];
48+
}
49+
if (!number) {
50+
core.setFailed(`No open pull request found for commit ${run.head_sha}`);
51+
return;
52+
}
53+
54+
const { data: pr } = await github.rest.pulls.get({
55+
owner: context.repo.owner,
56+
repo: context.repo.repo,
57+
pull_number: number,
58+
});
59+
core.setOutput('number', pr.number);
60+
core.setOutput('head_sha', run.head_sha);
61+
core.setOutput('head_ref', pr.head.ref);
62+
core.setOutput('base_sha', pr.base.sha);
63+
64+
- name: Check out the trusted deploy configuration
65+
uses: actions/checkout@v4
66+
with:
67+
ref: ${{ github.event.repository.default_branch }}
68+
fetch-depth: 0
69+
- name: Add repository to git safe directories
70+
run: git config --global --add safe.directory $GITHUB_WORKSPACE
71+
72+
- name: download build artifact
73+
uses: actions/download-artifact@v4
74+
with:
75+
name: deployment-build
76+
path: build/
77+
run-id: ${{ github.event.workflow_run.id }}
78+
github-token: ${{ secrets.GITHUB_TOKEN }}
79+
80+
- uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
81+
with:
82+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
83+
- run: mkdir -p $HOME/.ssh
84+
85+
- name: deploy to acceptance
86+
run: hypernode-deploy deploy acceptance -vvv --reuse-brancher
87+
env:
88+
HYPERNODE_API_TOKEN: ${{ secrets.HYPERNODE_API_TOKEN }}
89+
# workflow_run does not set GITHUB_HEAD_REF, which deploy.php uses to
90+
# label the brancher. Without this every pull request shares one node.
91+
CI_REF: ${{ steps.pr.outputs.head_ref }}
92+
93+
- name: Get brancher hostname
94+
id: get_brancher_hostname
95+
run: echo "BRANCHER_URL=https://$(jq .hostnames[0] deployment-report.json -r)" >> $GITHUB_OUTPUT
96+
97+
- name: Get changed pages
98+
id: changed_pages
99+
env:
100+
BASE_SHA: ${{ steps.pr.outputs.base_sha }}
101+
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
102+
BRANCHER_URL: ${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}
103+
run: |
104+
# The built commit is fetched by SHA as data to diff against (the
105+
# pull request ref may already point at a newer push); it is never
106+
# checked out or executed.
107+
git fetch --no-tags --quiet origin "$HEAD_SHA"
108+
result="$(python3 ci/bin/get_changed_urls.py \
109+
"$BASE_SHA" \
110+
"$HEAD_SHA" \
111+
--base-url="$BRANCHER_URL"
112+
)"
113+
echo "$result"
114+
{
115+
echo "CHANGED_PAGES<<EOF"
116+
echo "$result"
117+
echo "EOF"
118+
} >> "$GITHUB_OUTPUT"
119+
shell: bash
120+
121+
- name: Comment hostname on PR
122+
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
123+
with:
124+
pr-number: ${{ steps.pr.outputs.number }}
125+
comment-tag: acceptance-environment
126+
message: |
127+
Acceptance server is available at ${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}.
128+
${{ steps.changed_pages.outputs.CHANGED_PAGES }}
129+
130+
# workflow_run runs do not appear in the pull request's check list.
131+
- name: Mirror result onto the pull request head commit
132+
if: always() && steps.pr.outputs.head_sha
133+
uses: actions/github-script@v7
134+
env:
135+
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
136+
JOB_STATUS: ${{ job.status }}
137+
BRANCHER_URL: ${{ steps.get_brancher_hostname.outputs.BRANCHER_URL }}
138+
with:
139+
script: |
140+
const ok = process.env.JOB_STATUS === 'success';
141+
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
142+
await github.rest.repos.createCommitStatus({
143+
owner: context.repo.owner,
144+
repo: context.repo.repo,
145+
sha: process.env.HEAD_SHA,
146+
state: ok ? 'success' : 'failure',
147+
context: 'Deploy pull request to acceptance',
148+
target_url: ok ? (process.env.BRANCHER_URL || runUrl) : runUrl,
149+
description: ok
150+
? 'Acceptance environment deployed'
151+
: 'Acceptance deploy failed',
152+
});

0 commit comments

Comments
 (0)