Skip to content

Commit 2061279

Browse files
authored
Merge pull request #57 from pulibrary/i6065_cicognara_staging
I6065 cicognara staging - move to containers!
2 parents 994945f + 03015e0 commit 2061279

10 files changed

Lines changed: 460 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
name: Issue Template
3+
about: 'Generic template providing a baseline for any kind of issue'
4+
title: ''
5+
labels: ''
6+
assignees: ''
7+
8+
---
9+
10+
### Summary or User Story
11+
12+
13+
14+
### Acceptance Criteria
15+
16+
This section can be completed by the OPS team. Some requirements to consider
17+
including:
18+
19+
- [ ] The UI implemented for this issue meets accessibility requirements
20+
- [ ] New functionality is documented
21+
22+
23+
### First step
24+
25+
This section can be completed by the OPS team
26+
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
name: Create and publish a Docker image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_NAME: ${{ github.repository }}
15+
16+
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
17+
jobs:
18+
build-and-push-image:
19+
runs-on: ubuntu-latest
20+
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
21+
permissions:
22+
contents: read
23+
packages: write
24+
#
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v4
28+
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
29+
- name: Log in to the Container registry
30+
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
31+
with:
32+
registry: ${{ env.REGISTRY }}
33+
username: ${{ github.actor }}
34+
password: ${{ secrets.GITHUB_TOKEN }}
35+
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
36+
- name: Extract metadata (tags, labels) for Docker
37+
id: meta
38+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
39+
with:
40+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
41+
tags: |
42+
type=ref,event=branch
43+
type=ref,event=pr
44+
type=sha
45+
env:
46+
DOCKER_METADATA_PR_HEAD_SHA: true
47+
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
48+
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
49+
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
50+
- name: Build and push Docker image
51+
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
52+
with:
53+
context: .
54+
push: true
55+
tags: ${{ steps.meta.outputs.tags }}
56+
labels: ${{ steps.meta.outputs.labels }}
57+
file: Dockerfile
58+
container-vuln-scan:
59+
needs: build-and-push-image
60+
runs-on: ubuntu-latest
61+
if:
62+
steps:
63+
- name: Checkout code
64+
uses: actions/checkout@v2
65+
- name: Extract metadata (tags, labels) for Docker
66+
id: meta
67+
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
68+
with:
69+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
70+
tags: |
71+
type=ref,event=branch
72+
type=ref,event=pr
73+
type=sha
74+
env:
75+
DOCKER_METADATA_PR_HEAD_SHA: true
76+
- name: Run Trivy vulnerability scanner
77+
uses: aquasecurity/[email protected]
78+
id: runscanner
79+
continue-on-error: true
80+
env:
81+
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
82+
with:
83+
image-ref: 'ghcr.io/pulibrary/digital-cicognara-library:${{ steps.meta.outputs.version }}'
84+
format: 'table'
85+
exit-code: '1'
86+
ignore-unfixed: true
87+
vuln-type: 'os,library'
88+
severity: 'CRITICAL,HIGH'
89+
output: 'vulnerabilities.table'
90+
- name: Set variables
91+
id: scanner
92+
if: ${{ always() }}
93+
run: |
94+
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
95+
echo "results<<$EOF" >> $GITHUB_OUTPUT
96+
echo "$(cat vulnerabilities.table)" >> $GITHUB_OUTPUT
97+
echo "$EOF" >> $GITHUB_OUTPUT
98+
- name: Output variable
99+
if: ${{ always() }}
100+
env:
101+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
102+
WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
103+
SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }}
104+
run: echo "${{ env.SCANNER_OUTPUTS }}"
105+
- name: Find Comment for scan
106+
if: github.event_name == 'pull_request'
107+
uses: peter-evans/find-comment@v3
108+
id: fc
109+
with:
110+
issue-number: ${{ github.event.pull_request.number }}
111+
comment-author: 'github-actions[bot]'
112+
body-includes: 'Container Scanning Status: '
113+
- name: Create or update comment
114+
if: github.event_name == 'pull_request'
115+
uses: peter-evans/create-or-update-comment@v4
116+
env:
117+
SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }}
118+
with:
119+
comment-id: ${{ steps.fc.outputs.comment-id }}
120+
issue-number: ${{ github.event.pull_request.number }}
121+
body: |
122+
## Container Scanning Status: ${{ steps.runscanner.outcome != 'success' && '❌ Failure' || '✅ Success' }}
123+
```
124+
${{ env.SCANNER_OUTPUTS }}
125+
```
126+
edit-mode: replace
127+
- name: Create issue
128+
if: steps.runscanner.outcome != 'success' && github.event_name != 'pull_request'
129+
uses: JasonEtco/create-an-issue@v2
130+
env:
131+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
132+
WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
133+
SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }}
134+
with:
135+
filename: .github/failed-vuln-check.md
136+
update_existing: true
137+
- name: Find existing security issue
138+
id: issues
139+
if: steps.runscanner.outcome == 'success' && github.event_name != 'pull_request'
140+
uses: lee-dohm/select-matching-issues@v1
141+
with:
142+
query: 'Container Vulnerability Scanner Failed is:open '
143+
token: ${{ secrets.GITHUB_TOKEN }}
144+
- name: Close found issues
145+
continue-on-error: true
146+
env:
147+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
148+
if: steps.runscanner.outcome == 'success' && github.event_name != 'pull_request'
149+
run: cat ${{ steps.issues.outputs.path }} | xargs gh issue close -c 'Container Scan Passing on Merge to Main'
150+

.github/workflows/jekyll.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# This workflow uses actions that are not certified by GitHub.
2+
# They are provided by a third-party and are governed by
3+
# separate terms of service, privacy policy, and support
4+
# documentation.
5+
6+
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
7+
name: Deploy Jekyll site to Pages
8+
9+
on:
10+
# Runs on pushes targeting the default branch
11+
push:
12+
branches: ["main"]
13+
14+
# Allows you to run this workflow manually from the Actions tab
15+
workflow_dispatch:
16+
17+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
18+
permissions:
19+
contents: read
20+
pages: write
21+
id-token: write
22+
23+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
24+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
25+
concurrency:
26+
group: "pages"
27+
cancel-in-progress: false
28+
29+
jobs:
30+
# Build job
31+
build:
32+
runs-on: ubuntu-latest
33+
steps:
34+
- name: Checkout
35+
uses: actions/checkout@v3
36+
- name: Setup Ruby
37+
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
38+
with:
39+
ruby-version: '3.1' # Not needed with a .ruby-version file
40+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
41+
cache-version: 0 # Increment this number if you need to re-download cached gems
42+
- name: Setup Pages
43+
id: pages
44+
uses: actions/configure-pages@v3
45+
- name: Build with Jekyll
46+
# Outputs to the './_site' directory by default
47+
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
48+
env:
49+
JEKYLL_ENV: production
50+
- name: Upload artifact
51+
# Automatically uploads an artifact from the './_site' directory by default
52+
uses: actions/upload-pages-artifact@v2
53+
54+
# Deployment job
55+
deploy:
56+
environment:
57+
name: github-pages
58+
url: ${{ steps.deployment.outputs.page_url }}
59+
runs-on: ubuntu-latest
60+
needs: build
61+
steps:
62+
- name: Deploy to GitHub Pages
63+
id: deployment
64+
uses: actions/deploy-pages@v2
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Run nightly vulnerability check
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 * * *'
6+
7+
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
13+
jobs:
14+
container-vuln-scan:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v2
19+
- name: Run Trivy vulnerability scanner
20+
uses: aquasecurity/[email protected]
21+
id: runscanner
22+
continue-on-error: true
23+
env:
24+
TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
25+
with:
26+
image-ref: 'ghcr.io/pulibrary/digital-cicognara-library:main'
27+
format: 'table'
28+
exit-code: '1'
29+
ignore-unfixed: true
30+
vuln-type: 'os,library'
31+
severity: 'CRITICAL,HIGH'
32+
output: 'vulnerabilities.table'
33+
- name: Set variables
34+
id: scanner
35+
if: job.steps.runscanner.status == failure()
36+
run: |
37+
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
38+
echo "results<<$EOF" >> $GITHUB_OUTPUT
39+
echo "$(cat vulnerabilities.table)" >> $GITHUB_OUTPUT
40+
echo "$EOF" >> $GITHUB_OUTPUT
41+
- name: Output variable
42+
if: job.steps.runscanner.status == failure()
43+
env:
44+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45+
WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
46+
SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }}
47+
run: echo "${{ env.SCANNER_OUTPUTS }}"
48+
- name: Create issue
49+
if: steps.runscanner.outcome != 'success'
50+
uses: JasonEtco/create-an-issue@v2
51+
env:
52+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53+
WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
54+
SCANNER_OUTPUTS: ${{ steps.scanner.outputs.results }}
55+
with:
56+
filename: .github/failed-vuln-check.md
57+
update_existing: true
58+
- name: Find existing security issue
59+
id: issues
60+
if: steps.runscanner.outcome == 'success'
61+
uses: lee-dohm/select-matching-issues@v1
62+
with:
63+
query: 'Container Vulnerability Scanner Failed is:open '
64+
token: ${{ secrets.GITHUB_TOKEN }}
65+
- name: Close found issues
66+
continue-on-error: true
67+
env:
68+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
69+
if: steps.runscanner.outcome == 'success'
70+
run: cat ${{ steps.issues.outputs.path }} | xargs gh issue close -c 'Container Scan Passing on Merge to Main'
71+

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Get the newest nginx
2+
FROM nginx:latest
3+
4+
# Create the www directory within /usr/share/nginx/html
5+
RUN mkdir -p /usr/share/nginx/html/www
6+
7+
# Copy the _site directory into the newly created www directory
8+
COPY ./apps/cicognara-static/_site /usr/share/nginx/html/www
9+
10+
# Copy the custom nginx configuration file
11+
COPY default.conf /etc/nginx/conf.d/default.conf
12+
13+
# Expose port 80
14+
EXPOSE 80

bin/deploy

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/bin/bash
2+
ENV=$1
3+
BRANCH_NAME="${BRANCH:-main}"
4+
REPOSITORY="${REPO:-digital-cicognara-library}"
5+
JOB_NAME="${JOBNAME:-digital-cicognara-library}"
6+
7+
# Make sure we're on VPN
8+
if ! nslookup nomad-host-prod1.lib.princeton.edu 2>&1 >/dev/null; then
9+
echo "Unable to connect to nomad-host-prod1. Ensure you're on VPN."
10+
exit 1
11+
fi
12+
13+
## Get Github Token
14+
if ! command -v gh &>/dev/null; then
15+
if [ -z "$GITHUB_TOKEN" ]; then
16+
echo "gh must be installed or a token passed with GITHUB_TOKEN. Run 'brew install gh'."
17+
exit 1
18+
fi
19+
fi
20+
21+
GH_TOKEN="${GITHUB_TOKEN:-$(gh auth token 2>/dev/null)}"
22+
23+
if [ "$GH_TOKEN" = "" ]; then
24+
echo "Github token not set. Run 'gh auth login' and follow the directions."
25+
exit 1
26+
fi
27+
28+
if [[ -z "${ENV}" ]]; then
29+
echo "Missing Environment. Command: 'BRANCH=main ./bin/deploy staging'."
30+
exit
31+
fi
32+
33+
# Create Github Deployment
34+
DEPLOY_OUTPUT=$(curl -s -X POST -H "Accept: application/vnd.github+json-H" -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: Bearer ${GH_TOKEN}" --data "{\"ref\":\"${BRANCH_NAME}\",\"description\":\"Deploy from Nomad script\", \"auto_merge\": false, \"environment\": \"${ENV}\", \"required_contexts\": [] }" "https://api.github.com/repos/pulibrary/${REPOSITORY}/deployments")
35+
regex='"id": ([0-9]+),'
36+
[[ $DEPLOY_OUTPUT =~ $regex ]]
37+
DEPLOY_ID=${BASH_REMATCH[1]}
38+
39+
if [[ -z "${DEPLOY_ID}" ]]; then
40+
echo "Unable to fetch Deploy ID."
41+
exit 1
42+
fi
43+
44+
# Create "Started" Deployment Status
45+
curl -s -X POST -H "Accept: application/vnd.github+json-H" -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: Bearer ${GH_TOKEN}" --data "{\"environment\":\"${ENV}\",\"state\":\"in_progress\",\"log_url\": \"https://nomad.lib.princeton.edu/ui/jobs/${JOB_NAME}-${ENV}\", \"description\":\"Deployment started.\"}" "https://api.github.com/repos/pulibrary/${REPOSITORY}/deployments/${DEPLOY_ID}/statuses" >/dev/null
46+
47+
# Deploy using nomad-host-prod1, which has the nomad management key.
48+
49+
curl -H 'Cache-Control: no-cache' -s "https://raw.githubusercontent.com/pulibrary/${REPOSITORY}/${BRANCH_NAME}/${ENV}.hcl" | nomad job run -var "branch_or_sha=sha-$(git ls-remote https://github.com/pulibrary/${REPOSITORY}.git ${BRANCH_NAME} | awk '{ print substr($1,1,7) }')" -
50+
EOF
51+
retcode=$?
52+
53+
if [ $retcode -eq 0 ]; then
54+
# Create "Completed Successfully" Deployment Status
55+
curl -s -X POST -H "Accept: application/vnd.github+json-H" -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: Bearer ${GH_TOKEN}" --data "{\"environment\":\"${ENV}\",\"state\":\"success\",\"log_url\": \"https://nomad.lib.princeton.edu/ui/jobs/${JOB_NAME}-${ENV}\", \"description\":\"Deployment finished successfully.\"}" "https://api.github.com/repos/pulibrary/${REPOSITORY}/deployments/${DEPLOY_ID}/statuses" >/dev/null
56+
else
57+
# Create "Failed" Deployment Status
58+
curl -s -X POST -H "Accept: application/vnd.github+json-H" -H "Content-Type: application/x-www-form-urlencoded" -H "Authorization: Bearer ${GH_TOKEN}" --data "{\"environment\":\"${ENV}\",\"state\":\"failure\",\"log_url\": \"https://nomad.lib.princeton.edu/ui/jobs/${JOB_NAME}-${ENV}\", \"description\":\"Deployment failed.\"}" "https://api.github.com/repos/pulibrary/${REPOSITORY}/deployments/${DEPLOY_ID}/statuses" >/dev/null
59+
fi

0 commit comments

Comments
 (0)