-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
406 additions
and
1 deletion.
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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Security Policy | ||
|
||
## Supported Versions | ||
|
||
| Version | Supported | | ||
|---------|--------------------| | ||
| 1.x.x | :white_check_mark: | | ||
|
||
## Reporting a Vulnerability | ||
|
||
If you believe you've identified a security vulnerability in `ssp` (a bug that allows something to happen that shouldn't be possible), you can reach us at <[email protected]>. | ||
|
||
You will receive a response from us within 48 hours. If the issue is confirmed, we will release a patch as soon as possible depending on complexity but likely within a few days. | ||
|
||
## Scope | ||
|
||
A "vulnerability in ssp" is a vulnerability in the code distributed through our main source code repository on GitHub. Vulnerabilities that are specific to a given installation (e.g. misconfiguration) should be reported to the owner of that installation and not us. |
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 |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
name-template: "v$RESOLVED_VERSION" | ||
tag-template: "v$RESOLVED_VERSION" | ||
template: | | ||
# Changelog | ||
$CHANGES | ||
See details of [all code changes](https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION) since previous release. | ||
categories: | ||
- title: "🚀 Features" | ||
labels: | ||
- "feature" | ||
- "enhancement" | ||
- title: "🐛 Bug Fixes" | ||
labels: | ||
- "fix" | ||
- "bugfix" | ||
- "bug" | ||
- title: "🧰 Maintenance" | ||
labels: | ||
- "infrastructure" | ||
- "automation" | ||
- "documentation" | ||
- title: "🏎 Performance" | ||
label: "performance" | ||
change-template: "- $TITLE @$AUTHOR (#$NUMBER)" | ||
version-resolver: | ||
major: | ||
labels: | ||
- "type: breaking" | ||
minor: | ||
labels: | ||
- "type: enhancement" | ||
patch: | ||
labels: | ||
- "type: bug" | ||
- "type: maintenance" | ||
- "type: documentation" | ||
default: patch |
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 |
---|---|---|
@@ -0,0 +1,23 @@ | ||
name: Draft release | ||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
draft-release: | ||
permissions: | ||
# write permission is required to create a github release | ||
contents: write | ||
# write permission is required for autolabeler | ||
# otherwise, read permission is required at least | ||
pull-requests: write | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: release-drafter/release-drafter@v6 | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
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 |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: Release | ||
on: | ||
release: | ||
types: [released] | ||
workflow_dispatch: | ||
inputs: | ||
TAG_NAME: | ||
description: "Tag name that the major tag will point to" | ||
required: true | ||
|
||
env: | ||
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} | ||
|
||
permissions: | ||
contents: write | ||
|
||
jobs: | ||
update_tag: | ||
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes | ||
runs-on: ubuntu-latest | ||
environment: | ||
# Note: this environment is protected | ||
name: Release | ||
steps: | ||
- name: Update the ${{ env.TAG_NAME }} tag | ||
id: update-major-tag | ||
uses: actions/[email protected] | ||
with: | ||
source-tag: ${{ env.TAG_NAME }} |
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 |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/.idea | ||
/.idea/** |
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,2 +1,163 @@ | ||
# ssp | ||
# Static Site Preview (SSP) | ||
Deploy static site previews to a self-hosted server via ssh | ||
|
||
## Please note that this is in no way secure a solution for hosting static site previews. | ||
- You should only use this in repositories you **trust**. | ||
- You should only use this on a server | ||
- you **DO NOT** care about. | ||
- where you **DO NOT** have sensitive information stored. | ||
- where you **DO NOT** run other sensitive services. | ||
- Unless you jail the specific ssh user, you are allowing a GitHub Action full ssh access to your server. | ||
- You allow any other repository with access to the same preview server to overwrite each others previews. (This should not happen under normal circumstances, as the GitHub Action uses a hash of repository name + pull request number) | ||
|
||
## Usage | ||
|
||
### GitHub Action | ||
```yml | ||
name: preview | ||
|
||
on: [pull_request] | ||
|
||
jobs: | ||
deploy: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
pull-requests: write | ||
actions: read | ||
|
||
# Deploy to the preview environment | ||
environment: | ||
name: preview-${{ github.event.number }} | ||
url: ${{ steps.deploy-preview.outputs.url }} | ||
steps: | ||
- uses: actions/download-artifact@v4 | ||
with: | ||
path: ./dist | ||
|
||
- name: deploy preview | ||
id: deploy-preview | ||
uses: dafnik/ssp@v1 | ||
# with: | ||
# source: dist/* | ||
# target: /var/www/preview | ||
# host: preview.yxz.abc | ||
# port: 22 | ||
# username: ubuntu | ||
# key: ${{ secrets.PREVIEW_SSH_PRIVATE_KEY }} | ||
# strip_components: 0 | ||
``` | ||
|
||
| Inputs | Default value | Required | Description | | ||
|--------------------|---------------|----------|--------------------------------------------------------------------------------| | ||
| `source` | | x | Path to the files which should be deployed | | ||
| `target` | | x | Preview server target path, must be a directory path. | | ||
| `host` | | x | Preview server domain | | ||
| `port` | `22` | | Preview server ssh port | | ||
| `username` | | x | Preview server ssh username | | ||
| `key` | | x | Preview server ssh key content of private key. ex raw content of ~/.ssh/id_rsa | | ||
| `strip_components` | `0` | | remove the specified number of leading path elements | | ||
|
||
|
||
Furthermore, see [action.yml](action.yml) | ||
|
||
### NGINX Configuration | ||
Preview are going to stored in the `/var/www/preview` directory. | ||
``` | ||
/etc/nginx/site-enabled/preview | ||
``` | ||
|
||
``` | ||
server { | ||
listen 80; | ||
server_name *.preview.xyz.abc; | ||
return 301 https://$server_name$request_uri; | ||
} | ||
server { | ||
listen 443 ssl http2; | ||
server_name ~^(?P<sub>.+)\.preview\.xyz\.abc$; | ||
ssl_certificate /etc/letsencrypt/live/preview.xyz.abc/fullchain.pem; | ||
ssl_certificate_key /etc/letsencrypt/live/preview.xyz.abc/privkey.pem; | ||
# GZIP | ||
gzip on; | ||
gzip_disable "msie6"; | ||
gzip_vary on; | ||
gzip_proxied any; | ||
gzip_comp_level 6; | ||
gzip_buffers 16 8k; | ||
gzip_http_version 1.1; | ||
gzip_min_length 256; | ||
gzip_types text/xml text/javascript font/ttf font/eot font/otf application/rdf+xml application/x-javascript application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; | ||
# Remove X-Powered-By, which is an information leak | ||
fastcgi_hide_header X-Powered-By; | ||
# Do not send nginx server header | ||
server_tokens off; | ||
add_header Access-Control-Allow-Origin *; | ||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; | ||
add_header Referrer-Policy "strict-origin" always; | ||
add_header X-Frame-Options "SAMEORIGIN" always; | ||
add_header X-XSS-Protection "1; mode=block" always; | ||
add_header X-Content-Type-Options "nosniff" always; | ||
access_log on; | ||
error_log off; | ||
root /var/www/preview/$sub; | ||
location / { | ||
index index.html; | ||
} | ||
} | ||
``` | ||
|
||
### Cleanup cron job | ||
Delete previews with not activity in the last 30 days. | ||
```bash | ||
# /home/ubuntu/cronDeleteUnusedPreviews.sh | ||
|
||
# Define the directory to search in. Modify this variable to suit your needs. | ||
SEARCH_DIR="/var/www/preview" | ||
|
||
# Find and delete directories not modified in the last 30 days. | ||
find "$SEARCH_DIR" -type d -mtime +30 -exec rm -rf {} + | ||
|
||
# Explanation: | ||
# - `find "$SEARCH_DIR"`: Start searching in the specified directory. | ||
# - `-type d`: Only look for directories. | ||
# - `-mtime +30`: Find directories that were last modified more than 30 days ago. | ||
# - `-exec rm -rf {} +`: Delete each directory found ({} is replaced by the found directory name). | ||
``` | ||
|
||
Crontab example: | ||
```bash | ||
@daily /home/ubuntu/cronDeleteUnusedPreviews.sh | ||
``` | ||
|
||
## Release instructions | ||
|
||
In order to release a new version of this action: | ||
|
||
1. Locate the semantic version of the [upcoming release][release-list] (a draft is maintained by the [`draft-release` workflow][draft-release]). | ||
|
||
2. Publish the draft release from the `main` branch with semantic version as the tag name, _with_ the checkbox to publish to the GitHub Marketplace checked. :ballot_box_with_check: | ||
|
||
3. After publishing the release, the [`release` workflow][release] will automatically run to create/update the corresponding the major version tag such as `v0`. | ||
|
||
⚠️ Environment approval is required. Check the [Release workflow run list][release-workflow-runs]. | ||
|
||
## License | ||
|
||
The scripts and documentation in this project are released under the [MIT License](LICENSE). | ||
|
||
<!-- references --> | ||
[release-list]: https://github.com/dafnik/ssp/releases | ||
[draft-release]: .github/workflows/draft-release.yml | ||
[release]: .github/workflows/release.yml | ||
[release-workflow-runs]: https://github.com/dafnik/ssp/actions/workflows/release.yml |
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 |
---|---|---|
@@ -0,0 +1,103 @@ | ||
name: 'Static Site Preview (SSP)' | ||
description: 'Deploy static site previews to a self-hosted server via ssh' | ||
author: "Dafnik" | ||
branding: | ||
icon: 'arrow-down-circle' | ||
color: 'purple' | ||
|
||
inputs: | ||
source: | ||
required: true | ||
description: 'Path to the files which should be deployed' | ||
target: | ||
required: true | ||
description: 'Preview server target path, must be a directory path.' | ||
host: | ||
required: true | ||
description: 'Preview server domain' | ||
port: | ||
description: 'Preview server ssh port' | ||
default: '22' | ||
username: | ||
required: true | ||
description: 'Preview server ssh username' | ||
key: | ||
description: 'Preview server ssh key content of private key. ex raw content of ~/.ssh/id_rsa' | ||
strip_components: | ||
description: 'remove the specified number of leading path elements' | ||
default: '0' | ||
delete_treshhold_days: | ||
default: '30' | ||
description: 'Number of days after inactive previews are deleted' | ||
|
||
runs: | ||
using: 'composite' | ||
steps: | ||
- name: Check if run from pull request | ||
shell: bash | ||
if: github.event_name != 'pull_request' | ||
run : | | ||
echo "static-site-preview can only be run from pull request" | ||
echo "Check for pull request like this" | ||
echo "if: github.event_name == 'pull_request'" | ||
exit 1 | ||
- id: setup | ||
shell: bash | ||
name: Setup hash identifier & date | ||
run: | | ||
echo "name=${{ github.event.repository.name }}-${{ github.event.number }}" >> "$GITHUB_OUTPUT" | ||
current_date=$(date '+%Y-%m-%d %H:%M:%S (%Z)') | ||
echo "current_date=$current_date" >> "$GITHUB_OUTPUT" | ||
future_date=$(date -d "+${{ inputs.delete_treshhold_days }} days" '+%Y-%m-%d') | ||
echo "future_date=$future_date" >> "$GITHUB_OUTPUT" | ||
- id: hash | ||
shell: bash | ||
name: Create hash | ||
run: | | ||
echo Hash identifier: "${{ steps.setup.outputs.name }}" | ||
hash=$(echo -n "${{ steps.setup.outputs.name }}" | md5sum | awk '{print $1}') | ||
short_hash=${hash:0:10} | ||
echo "md5=$short_hash" >> "$GITHUB_OUTPUT" | ||
echo "url=https://$short_hash.${{ inputs.host }}" >> "$GITHUB_OUTPUT" | ||
- name: Check if hash is empty | ||
shell: bash | ||
run: | | ||
if [ -z "${{ steps.hash.outputs.md5 }}" ]; then | ||
echo "MD5 hash is empty. Failing the workflow." | ||
exit 1 | ||
else | ||
echo "MD5 hash: ${{ steps.hash.outputs.md5 }}" | ||
fi | ||
- name: Copy source files to target server | ||
uses: appleboy/[email protected] | ||
with: | ||
overwrite: true | ||
host: ${{ inputs.host }} | ||
username: ${{ inputs.username }} | ||
key: ${{ inputs.key }} | ||
port: ${{ inputs.port }} | ||
source: ${{ inputs.source }} | ||
target: "${{ inputs.target }}/${{ steps.hash.outputs.md5 }}" | ||
strip_components: ${{ inputs.strip_components }} | ||
|
||
- name: Create or update sticky pull request comment | ||
uses: marocchino/sticky-pull-request-comment@v2 | ||
with: | ||
message: | | ||
This pull request has been automatically deployed using Dafnik's static site preview (SSP) service. | ||
[Learn more](https://github.com/Dafnik/ssp). | ||
🔎 **Commit:** ${{ github.sha }} | ||
📅 **Updated at:** ${{ steps.setup.outputs.current_date }} | ||
✅ **Preview URL:** <${{ steps.hash.outputs.url }}> | ||
**Note:** If there is no further activity, this preview will be deleted **${{ inputs.delete_treshhold_days }} day(s) from now** on ${{ steps.setup.outputs.future_date }}. | ||
outputs: | ||
url: | ||
description: Deployment url | ||
value: ${{ steps.hash.outputs.url }} |
Oops, something went wrong.