Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .env.aws.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# AWS Environment Configuration
# Copy this file to .env and fill in your values

# Environment
NODE_ENV=development

# AWS Configuration
AWS_REGION=us-west-2
AWS_BUCKET_NAME=your-uhrp-bucket-name

# Server Configuration
HTTP_PORT=3104
SERVER_URL=https://your-domain.com
CORS_ORIGIN=*

# BSV Configuration
SERVER_PRIVATE_KEY=your-32-byte-hex-private-key
BSV_NETWORK=testnet
WALLET_STORAGE_URL=https://staging-storage.babbage.systems

# Pricing Configuration (in satoshis)
PER_BYTE_PRICE=0.00001
BASE_PRICE=1000
MIN_HOSTING_MINUTES=15

# Admin Configuration
ADMIN_TOKEN=your-super-secret-admin-token

# Error Tracking (optional)
BUGSNAG_API_KEY=your-bugsnag-api-key

# Notifier Configuration (optional)
NOTIFIER_URL=https://your-notifier-endpoint.com

# AWS Credentials (for local development only)
# In production, use IAM roles instead
# AWS_ACCESS_KEY_ID=your-access-key
# AWS_SECRET_ACCESS_KEY=your-secret-key
50 changes: 50 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# UHRP Storage Server Configuration

# Server Configuration
NODE_ENV=production
PORT=3000
SERVER_URL=https://your-domain.com
HOSTING_DOMAIN=https://your-domain.com

# Storage Provider Configuration
# Choose between 'aws' or 'gcs'
STORAGE_PROVIDER=aws

# Common storage configuration (works for both providers)
STORAGE_BUCKET_NAME=your-bucket-name

# AWS-specific configuration (required when STORAGE_PROVIDER=aws)
AWS_REGION=us-west-2
# AWS credentials are automatically loaded from IAM roles in ECS/EKS
# For local development, use AWS CLI configuration or environment variables:
# AWS_ACCESS_KEY_ID=your-access-key
# AWS_SECRET_ACCESS_KEY=your-secret-key

# GCS-specific configuration (required when STORAGE_PROVIDER=gcs)
GCP_PROJECT_ID=your-project-id
GCP_BUCKET_NAME=your-gcs-bucket-name
# GCS credentials file should be placed at ./storage-creds.json
# Or set GCS_KEY_FILE=/path/to/credentials.json

# Authentication and Security
SERVER_PRIVATE_KEY=your-server-private-key
ADMIN_TOKEN=your-secure-admin-token

# BSV Network Configuration
BSV_NETWORK=mainnet
BSV_WALLET_DIR=./wallet

# Optional: Bugsnag error tracking
BUGSNAG_API_KEY=your-bugsnag-api-key

# Optional: Payment configuration
PAYMENT_KEY=your-payment-key
PAYMENT_URL=https://payment-service.com

# Optional: Minimum hosting time in minutes
MIN_HOSTING_MINUTES=60

# Legacy environment variables (kept for backward compatibility)
# These will be used if STORAGE_BUCKET_NAME is not set
# GCP_BUCKET_NAME=your-gcs-bucket-name # Used by GCS provider
# AWS_BUCKET_NAME=your-s3-bucket-name # Used by AWS provider
93 changes: 49 additions & 44 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -1,66 +1,71 @@
name: Build and push OCI image to Docker Hub
name: Build and Push to GHCR

on:
push:
tags:
- 'v*'
- "v*"
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:

jobs:
check-current-branch:
get_tag:
runs-on: ubuntu-latest
outputs:
branch: ${{ steps.check_step.outputs.branch }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Get current branch
id: check_step
# 1. Get the list of branches ref where this tag exists
# 2. Remove 'origin/' from that result
# 3. Put that string in output
- name: Determine deployment tag
id: deployment_tag
run: |
raw=$(git branch -r --contains ${{ github.ref }})
branch="$(echo ${raw//origin\//} | tr -d '\n')"
echo "{name}=branch" >> $GITHUB_OUTPUT
echo "Branches where this tag exists : $branch."
if [[ '${{ github.ref_type }}' == 'tag' ]]; then
export tag=${{ github.ref_name }}
echo "version tag is $tag"
echo "id=$tag" >> $GITHUB_OUTPUT
else
export tag=latest
echo "version tag is $tag"
echo "id=$tag" >> $GITHUB_OUTPUT
fi
outputs:
deployment_tag: ${{ steps.deployment_tag.outputs.id }}

image:
build-and-push:
needs: [ get_tag ]
runs-on: ubuntu-latest
needs: check-current-branch
if: contains(${{ needs.check.outputs.branch }}, 'main')`
permissions:
contents: read
packages: write
steps:
- name: Check out the repo
- name: Checkout code
uses: actions/checkout@v4

- name: Get build args
id: build_args
run: |
echo "APP_COMMIT=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
echo "APP_VERSION=$(git describe --tags --always --abbrev=0 --match='v[0-9]*.[0-9]*.[0-9]*' 2> /dev/null | sed 's/^.//')" >> "$GITHUB_OUTPUT"

- name: Log in to Docker Hub
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
- name: Build and push frontend Docker image
uses: docker/build-push-action@v5
with:
images: bsvb/uhrp-storage-server
context: . # Build context (root directory, adjust if Dockerfile is elsewhere)
file: ./Dockerfile # Path to Dockerfile
# push: ${{ github.event_name != 'pull_request' }} # Only push on push events, not PRs
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ github.sha }}
ghcr.io/${{ github.repository }}:${{ needs.get_tag.outputs.deployment_tag }}

- name: Build and push image
- name: Build and push frontend Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
context: ./k8s/s3-event-handler # Build context (root directory, adjust if Dockerfile is elsewhere)
file: ./k8s/s3-event-handler/Dockerfile # Path to Dockerfile
# push: ${{ github.event_name != 'pull_request' }} # Only push on push events, not PRs
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APP_COMMIT=${{ steps.build_args.outputs.APP_COMMIT }}
APP_VERSION=${{ steps.build_args.outputs.APP_VERSION }}
tags: |
ghcr.io/${{ github.repository }}-s3-notifier:${{ github.sha }}
ghcr.io/${{ github.repository }}-s3-notifier:${{ needs.get_tag.outputs.deployment_tag }}

139 changes: 139 additions & 0 deletions .github/workflows/deploy-aws.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Deploy to AWS

on:
push:
branches:
- master
- production

env:
AWS_REGION: ${{ secrets.AWS_REGION }}
ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }}
ECS_SERVICE: ${{ github.ref_name == 'production' && 'prod-uhrp-storage-service' || 'staging-uhrp-storage-service' }}
ECS_CLUSTER: ${{ github.ref_name == 'production' && 'prod-uhrp-cluster' || 'staging-uhrp-cluster' }}
TASK_DEFINITION_FAMILY: uhrp-storage-server
LAMBDA_FUNCTION: ${{ github.ref_name == 'production' && 'prod-uhrp-notifier' || 'staging-uhrp-notifier' }}

jobs:
deploy:
name: Deploy to AWS
runs-on: ubuntu-latest
environment: ${{ github.ref_name }}

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1

- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.ref_name }}-${{ github.sha }}
run: |
# Build the Docker image
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest-${{ github.ref_name }}

# Push both tags to ECR
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest-${{ github.ref_name }}

# Output the image URI
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

- name: Download current task definition
run: |
aws ecs describe-task-definition \
--task-definition ${{ env.TASK_DEFINITION_FAMILY }} \
--query taskDefinition > task-definition.json

# Remove fields that shouldn't be in the new definition
jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' task-definition.json > task-definition-clean.json
mv task-definition-clean.json task-definition.json

- name: Update task definition with new image
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: uhrp-storage
image: ${{ steps.build-image.outputs.image }}
environment-variables: |
NODE_ENV=${{ github.ref_name == 'production' && 'production' || 'staging' }}
AWS_BUCKET_NAME=${{ github.ref_name == 'production' && secrets.PROD_AWS_BUCKET_NAME || secrets.STAGING_AWS_BUCKET_NAME }}
SERVER_URL=${{ github.ref_name == 'production' && secrets.PROD_SERVER_URL || secrets.STAGING_SERVER_URL }}
CORS_ORIGIN=${{ github.ref_name == 'production' && secrets.PROD_CORS_ORIGIN || secrets.STAGING_CORS_ORIGIN }}
PER_BYTE_PRICE=${{ github.ref_name == 'production' && secrets.PROD_PER_BYTE_PRICE || secrets.STAGING_PER_BYTE_PRICE }}
BASE_PRICE=${{ github.ref_name == 'production' && secrets.PROD_BASE_PRICE || secrets.STAGING_BASE_PRICE }}
BSV_NETWORK=${{ github.ref_name == 'production' && 'mainnet' || 'testnet' }}
MIN_HOSTING_MINUTES=${{ github.ref_name == 'production' && secrets.PROD_MIN_HOSTING_MINUTES || secrets.STAGING_MIN_HOSTING_MINUTES }}
WALLET_STORAGE_URL=${{ github.ref_name == 'production' && secrets.PROD_WALLET_STORAGE_URL || secrets.STAGING_WALLET_STORAGE_URL }}

- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true

- name: Package and deploy Lambda function
run: |
# Package the notifier
cd notifier
npm ci --production
zip -r ../notifier.zip .
cd ..

# Update Lambda function code
aws lambda update-function-code \
--function-name ${{ env.LAMBDA_FUNCTION }} \
--zip-file fileb://notifier.zip

# Update Lambda environment variables
aws lambda update-function-configuration \
--function-name ${{ env.LAMBDA_FUNCTION }} \
--environment Variables="{
NODE_ENV=${{ github.ref_name == 'production' && 'production' || 'staging' }},
SERVER_PRIVATE_KEY=${{ github.ref_name == 'production' && secrets.PROD_SERVER_PRIVATE_KEY || secrets.STAGING_SERVER_PRIVATE_KEY }},
BSV_NETWORK=${{ github.ref_name == 'production' && 'mainnet' || 'testnet' }},
AWS_BUCKET_NAME=${{ github.ref_name == 'production' && secrets.PROD_AWS_BUCKET_NAME || secrets.STAGING_AWS_BUCKET_NAME }}
}"

# Wait for configuration update to complete
aws lambda wait function-updated \
--function-name ${{ env.LAMBDA_FUNCTION }}

- name: Verify deployment
run: |
echo "🚀 Deployment completed!"
echo "ECS Service: ${{ env.ECS_SERVICE }}"
echo "Lambda Function: ${{ env.LAMBDA_FUNCTION }}"
echo "Image: ${{ steps.build-image.outputs.image }}"

# Get service info
aws ecs describe-services \
--cluster ${{ env.ECS_CLUSTER }} \
--services ${{ env.ECS_SERVICE }} \
--query 'services[0].{desiredCount:desiredCount,runningCount:runningCount,pendingCount:pendingCount}' \
--output table

- name: Send deployment notification
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "✅ Deployment to ${{ github.ref_name }} succeeded"
else
echo "❌ Deployment to ${{ github.ref_name }} failed"
fi
Comment on lines +19 to +139

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 5 months ago

To fix the issue, we will add a permissions block at the workflow level to explicitly define the minimal permissions required for the workflow. Based on the actions used in the workflow, the following permissions are necessary:

  • contents: read for accessing the repository's contents.
  • secrets: read for accessing secrets used in the workflow.

This change will ensure that the workflow adheres to the principle of least privilege.


Suggested changeset 1
.github/workflows/deploy-aws.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/deploy-aws.yaml b/.github/workflows/deploy-aws.yaml
--- a/.github/workflows/deploy-aws.yaml
+++ b/.github/workflows/deploy-aws.yaml
@@ -2,2 +2,6 @@
 
+permissions:
+  contents: read
+  secrets: read
+
 on:
EOF
@@ -2,2 +2,6 @@

permissions:
contents: read
secrets: read

on:
Copilot is powered by AI and may make mistakes. Always verify output.
Loading