Compare commits
14 Commits
feat/preac
...
v0.1.7
| Author | SHA1 | Date | |
|---|---|---|---|
| efc9e5c3dd | |||
| 65c6946e7f | |||
| 3129fa6531 | |||
| 82da27cf8d | |||
| c4dce04d42 | |||
| c2b3356022 | |||
| d067e0b95c | |||
| aec7a331c6 | |||
| 0d636ab680 | |||
| 69c6c6fe09 | |||
| fd552c48cd | |||
| 95b7be5219 | |||
| b8e1468a46 | |||
| 199d92f733 |
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
.env
|
||||
.DS_Store
|
||||
.claude/
|
||||
@@ -1,14 +1,22 @@
|
||||
name: Build and Release
|
||||
name: Build and Release to Staging
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
REGISTRY_HOST: git.ivanch.me
|
||||
REGISTRY_USERNAME: ivanch
|
||||
IMAGE_NAME: ${{ env.REGISTRY_HOST }}/ivanch/vision-start
|
||||
IMAGE_TAG: staging
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Vision Start
|
||||
if: gitea.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-amd64
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
@@ -16,3 +24,47 @@ jobs:
|
||||
run: npm install
|
||||
- name: Run build
|
||||
run: npm run build
|
||||
|
||||
build_vision_start:
|
||||
name: Build Vision Start Image
|
||||
runs-on: ubuntu-amd64
|
||||
needs: build
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Log in to Container Registry
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" \
|
||||
| docker login "${{ env.REGISTRY_HOST }}" \
|
||||
-u "${{ env.REGISTRY_USERNAME }}" \
|
||||
--password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and Push Multi-Arch Image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
|
||||
deploy_vision_start:
|
||||
name: Deploy Vision Start (staging)
|
||||
runs-on: ubuntu-amd64
|
||||
needs: build_vision_start
|
||||
steps:
|
||||
- name: Recreate Container
|
||||
uses: appleboy/ssh-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
cd ${{ secrets.STAGING_DIR }}
|
||||
docker compose pull
|
||||
docker compose up -d --force-recreate
|
||||
|
||||
@@ -5,6 +5,12 @@ on:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
env:
|
||||
REGISTRY_HOST: git.ivanch.me
|
||||
REGISTRY_USERNAME: ivanch
|
||||
IMAGE_NAME: ${{ env.REGISTRY_HOST }}/ivanch/vision-start
|
||||
IMAGE_TAG: latest
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -20,7 +26,7 @@ jobs:
|
||||
- name: Run build
|
||||
run: npm run build
|
||||
- name: Prepare release
|
||||
run: |
|
||||
run: |
|
||||
bash scripts/prepare_release.sh
|
||||
mv dist vision-start/
|
||||
mv manifest.json vision-start/
|
||||
@@ -53,19 +59,17 @@ jobs:
|
||||
virustotal_apikey: ${{ secrets.VIRUSTOTAL_APIKEY }}
|
||||
VIRUS_TOTAL_FILE: vision-start-${{ gitea.ref_name }}.zip
|
||||
run: |
|
||||
# Run the VirusTotal check script and capture output
|
||||
bash scripts/check_virustotal.sh > vt_output.txt 2>&1
|
||||
|
||||
# Run the VirusTotal check script and capture output in real-time
|
||||
set -o pipefail
|
||||
bash scripts/check_virustotal.sh 2>&1 | tee vt_output.txt
|
||||
|
||||
# Extract analysis URL and detection ratio from output
|
||||
ANALYSIS_URL=$(grep "Analysis URL:" vt_output.txt | cut -d' ' -f3- || echo "Not available")
|
||||
DETECTION_RATIO=$(grep "Detection ratio:" vt_output.txt | cut -d' ' -f3- || echo "Not available")
|
||||
|
||||
|
||||
# Set outputs for next job
|
||||
echo "analysis-url=$ANALYSIS_URL" >> $GITEA_OUTPUT
|
||||
echo "detection-ratio=$DETECTION_RATIO" >> $GITEA_OUTPUT
|
||||
|
||||
# Display the full output
|
||||
cat vt_output.txt
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -82,9 +86,53 @@ jobs:
|
||||
with:
|
||||
body: |
|
||||
This is the release for version ${{ gitea.ref_name }}.
|
||||
|
||||
|
||||
**Virus Total Analysis URL:** ${{ needs.virus-total-check.outputs.analysis-url }}
|
||||
**Virus Total Detection Ratio:** ${{ needs.virus-total-check.outputs.detection-ratio }}
|
||||
name: ${{ gitea.ref_name }}
|
||||
tag_name: ${{ gitea.ref_name }}
|
||||
files: vision-start-${{ gitea.ref_name }}.zip
|
||||
files: vision-start-${{ gitea.ref_name }}.zip
|
||||
|
||||
build_vision_start:
|
||||
name: Build Vision Start Image
|
||||
runs-on: ubuntu-amd64
|
||||
needs: [build, virus-total-check]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Log in to Container Registry
|
||||
run: |
|
||||
echo "${{ secrets.REGISTRY_PASSWORD }}" \
|
||||
| docker login "${{ env.REGISTRY_HOST }}" \
|
||||
-u "${{ env.REGISTRY_USERNAME }}" \
|
||||
--password-stdin
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and Push Multi-Arch Image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: |
|
||||
${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
|
||||
|
||||
deploy_vision_start:
|
||||
name: Deploy Vision Start (production)
|
||||
runs-on: ubuntu-amd64
|
||||
needs: build_vision_start
|
||||
steps:
|
||||
- name: Recreate Container
|
||||
uses: appleboy/ssh-action@v0.1.7
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
script: |
|
||||
cd ${{ secrets.PROD_DIR }}
|
||||
docker compose pull
|
||||
docker compose up -d --force-recreate
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
.claude/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN sh scripts/prepare_release.sh
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
COPY manifest.json /usr/share/nginx/html/
|
||||
EXPOSE 80
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -9,7 +9,7 @@ set -e
|
||||
# Configuration
|
||||
FILE_PATH="${VIRUS_TOTAL_FILE:-vision-start.zip}"
|
||||
API_KEY="${virustotal_apikey}"
|
||||
BASE_URL="https://www.virustotal.com/vtapi/v2"
|
||||
BASE_URL="https://www.virustotal.com/api/v3"
|
||||
|
||||
# Check if API key is set
|
||||
if [ -z "$API_KEY" ]; then
|
||||
@@ -38,12 +38,12 @@ echo "Uploading $FILE_PATH to VirusTotal for analysis..."
|
||||
|
||||
# Upload file to VirusTotal
|
||||
UPLOAD_RESPONSE=$(curl -s -X POST \
|
||||
-F "apikey=$API_KEY" \
|
||||
-H "x-apikey: $API_KEY" \
|
||||
-F "file=@$FILE_PATH" \
|
||||
"$BASE_URL/file/scan")
|
||||
"$BASE_URL/files")
|
||||
|
||||
# Extract scan_id from response
|
||||
SCAN_ID=$(echo "$UPLOAD_RESPONSE" | jq -r '.scan_id')
|
||||
SCAN_ID=$(echo "$UPLOAD_RESPONSE" | jq -r '.data.id')
|
||||
|
||||
if [ "$SCAN_ID" == "null" ] || [ -z "$SCAN_ID" ]; then
|
||||
echo "Error: Failed to upload file or get scan ID"
|
||||
@@ -55,54 +55,54 @@ echo "File uploaded successfully. Scan ID: $SCAN_ID"
|
||||
echo "Waiting for analysis to complete..."
|
||||
|
||||
# Wait for analysis to complete and get results
|
||||
MAX_ATTEMPTS=30
|
||||
MAX_ATTEMPTS=60
|
||||
ATTEMPT=0
|
||||
SLEEP_INTERVAL=10
|
||||
|
||||
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
|
||||
echo "Checking analysis status (attempt $((ATTEMPT + 1))/$MAX_ATTEMPTS)..."
|
||||
|
||||
|
||||
# Get scan report
|
||||
REPORT_RESPONSE=$(curl -s -X POST \
|
||||
-d "apikey=$API_KEY" \
|
||||
-d "resource=$SCAN_ID" \
|
||||
"$BASE_URL/file/report")
|
||||
|
||||
REPORT_RESPONSE=$(curl -s -X GET \
|
||||
-H "x-apikey: $API_KEY" \
|
||||
"$BASE_URL/analyses/$SCAN_ID")
|
||||
|
||||
# Check if analysis is complete
|
||||
RESPONSE_CODE=$(echo "$REPORT_RESPONSE" | jq -r '.response_code')
|
||||
|
||||
if [ "$RESPONSE_CODE" == "1" ]; then
|
||||
RESPONSE_CODE=$(echo "$REPORT_RESPONSE" | jq -r '.data.attributes.status')
|
||||
|
||||
if [ "$RESPONSE_CODE" == "completed" ]; then
|
||||
# Analysis complete
|
||||
echo "Analysis completed!"
|
||||
|
||||
|
||||
# Extract results
|
||||
POSITIVES=$(echo "$REPORT_RESPONSE" | jq -r '.positives')
|
||||
TOTAL=$(echo "$REPORT_RESPONSE" | jq -r '.total')
|
||||
PERMALINK=$(echo "$REPORT_RESPONSE" | jq -r '.permalink')
|
||||
|
||||
POSITIVES=$(echo "$REPORT_RESPONSE" | jq -r '.data.attributes.stats.malicious')
|
||||
SUSPICIOUS=$(echo "$REPORT_RESPONSE" | jq -r '.data.attributes.stats.suspicious')
|
||||
# The v3 analyses object has no 'total' field — compute it by summing all stat categories
|
||||
TOTAL=$(echo "$REPORT_RESPONSE" | jq '[.data.attributes.stats | to_entries[].value] | add')
|
||||
ANALYSIS_ID=$(echo "$REPORT_RESPONSE" | jq -r '.data.id')
|
||||
PERMALINK="https://www.virustotal.com/gui/file-analysis/${ANALYSIS_ID}"
|
||||
|
||||
echo "Analysis URL: $PERMALINK"
|
||||
echo "Detection ratio: $POSITIVES/$TOTAL"
|
||||
|
||||
|
||||
# Check if file is safe
|
||||
if [ "$POSITIVES" -eq 0 ]; then
|
||||
if [ "$POSITIVES" -eq 0 ] && [ "$SUSPICIOUS" -eq 0 ]; then
|
||||
echo "✅ File is clean (no threats detected)"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ File contains threats ($POSITIVES detections out of $TOTAL scanners)"
|
||||
echo "❌ File flagged: $POSITIVES malicious, $SUSPICIOUS suspicious (out of $TOTAL scanners)"
|
||||
exit 1
|
||||
fi
|
||||
elif [ "$RESPONSE_CODE" == "0" ]; then
|
||||
# File not found or analysis not complete yet
|
||||
echo "Analysis still in progress..."
|
||||
elif [ "$RESPONSE_CODE" == "-2" ]; then
|
||||
# Still queued for analysis
|
||||
elif [ "$RESPONSE_CODE" == "queued" ]; then
|
||||
echo "File still queued for analysis..."
|
||||
elif [ "$RESPONSE_CODE" == "in-progress" ]; then
|
||||
echo "Analysis still in progress..."
|
||||
else
|
||||
echo "Unexpected response code: $RESPONSE_CODE"
|
||||
echo "Response: $REPORT_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
ATTEMPT=$((ATTEMPT + 1))
|
||||
if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
|
||||
sleep $SLEEP_INTERVAL
|
||||
|
||||
Reference in New Issue
Block a user