diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..6850aa9 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,147 @@ +name: Deploy + +on: + push: + branches: [ main ] + tags: [ 'v*' ] + workflow_dispatch: + inputs: + environment: + description: 'Deployment environment' + required: true + default: 'staging' + type: choice + options: + - staging + - production + +env: + REGISTRY: gitea.nothaft.cloud + IMAGE_NAME: ${{ gitea.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + outputs: + backend-image: ${{ steps.meta-backend.outputs.tags }} + frontend-image: ${{ steps.meta-frontend.outputs.tags }} + version: ${{ steps.meta-backend.outputs.version }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ gitea.actor }} + password: ${{ secrets.GITEA_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Backend Image + - name: Extract backend metadata + id: meta-backend + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-backend + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push backend image + uses: docker/build-push-action@v5 + with: + context: ./backend + file: ./docker/Dockerfile.backend + push: true + tags: ${{ steps.meta-backend.outputs.tags }} + labels: ${{ steps.meta-backend.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + BUILD_DATE=${{ fromJSON(steps.meta-backend.outputs.json).labels['org.opencontainers.image.created'] }} + VERSION=${{ fromJSON(steps.meta-backend.outputs.json).labels['org.opencontainers.image.version'] }} + + # Frontend Image + - name: Extract frontend metadata + id: meta-frontend + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-frontend + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push frontend image + uses: docker/build-push-action@v5 + with: + context: ./frontend + file: ./docker/Dockerfile.frontend + push: true + tags: ${{ steps.meta-frontend.outputs.tags }} + labels: ${{ steps.meta-frontend.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + BUILD_DATE=${{ fromJSON(steps.meta-frontend.outputs.json).labels['org.opencontainers.image.created'] }} + VERSION=${{ fromJSON(steps.meta-frontend.outputs.json).labels['org.opencontainers.image.version'] }} + + deploy-staging: + runs-on: ubuntu-latest + needs: build-and-push + if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event.inputs.environment == 'staging' + environment: staging + + steps: + - name: Deploy to Staging + run: | + echo "Deploying to staging environment" + echo "Backend image: ${{ needs.build-and-push.outputs.backend-image }}" + echo "Frontend image: ${{ needs.build-and-push.outputs.frontend-image }}" + + # Add your deployment commands here + # For example, using SSH to update docker-compose on staging server: + # ssh ${{ secrets.STAGING_HOST }} "cd /opt/minio-webui && docker compose pull && docker compose up -d" + + deploy-production: + runs-on: ubuntu-latest + needs: build-and-push + if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.environment == 'production' + environment: production + + steps: + - name: Deploy to Production + run: | + echo "Deploying to production environment" + echo "Backend image: ${{ needs.build-and-push.outputs.backend-image }}" + echo "Frontend image: ${{ needs.build-and-push.outputs.frontend-image }}" + echo "Version: ${{ needs.build-and-push.outputs.version }}" + + # Add your production deployment commands here + # For example: + # ssh ${{ secrets.PROD_HOST }} "cd /opt/minio-webui && ./scripts/deploy.sh update" + + - name: Create Release Notes + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v1 + with: + generate_release_notes: true + draft: false + prerelease: false \ No newline at end of file diff --git a/.gitea/workflows/test-build.yml b/.gitea/workflows/test-build.yml new file mode 100644 index 0000000..436d7e2 --- /dev/null +++ b/.gitea/workflows/test-build.yml @@ -0,0 +1,182 @@ +name: Test and Build + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main ] + +env: + NODE_VERSION: '20' + DOCKER_BUILDKIT: 1 + +jobs: + # Backend Tests + backend-test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./backend + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + cache-dependency-path: backend/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Run linting + run: npm run lint + + - name: Run tests + run: npm test + env: + NODE_ENV: test + JWT_SECRET: test-secret-key + ADMIN_PASSWORD_HASH: $2b$12$test + + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: backend-coverage + path: backend/coverage + + - name: Security audit + run: npm audit --audit-level=high + continue-on-error: true + + # Frontend Tests + frontend-test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./frontend + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install dependencies + run: npm ci --legacy-peer-deps + + - name: Run linting + run: npm run lint + + - name: Run tests + run: npm test -- --watchAll=false --passWithNoTests + env: + CI: true + + - name: Build application + run: npm run build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: frontend-build + path: frontend/build + + - name: Security audit + run: npm audit --audit-level=high + continue-on-error: true + + # Docker Build Test + docker-build: + runs-on: ubuntu-latest + needs: [backend-test, frontend-test] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Backend Docker Image + uses: docker/build-push-action@v5 + with: + context: ./backend + file: ./docker/Dockerfile.backend + push: false + tags: minio-webui-backend:test + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build Frontend Docker Image + uses: docker/build-push-action@v5 + with: + context: ./frontend + file: ./docker/Dockerfile.frontend + push: false + tags: minio-webui-frontend:test + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test Docker Compose + run: | + # Create test .env file + cat > .env << EOF + NODE_ENV=test + PORT=3000 + LOG_LEVEL=info + ADMIN_PASSWORD_HASH=\$2b\$12\$test + JWT_SECRET=test-secret-key + SESSION_TIMEOUT=1800 + ENABLE_IP_RESTRICTION=false + DEFAULT_MINIO_ALIAS=testminio + MINIO_ENDPOINT=http://minio:9000 + MINIO_ACCESS_KEY=minioadmin + MINIO_SECRET_KEY=minioadmin + EOF + + # Start services + docker compose up -d + + # Wait for services to be healthy + sleep 30 + + # Check if services are running + docker compose ps + + # Test backend health endpoint + curl -f http://localhost:3000/health || exit 1 + + # Test frontend + curl -f http://localhost/health || exit 1 + + # Clean up + docker compose down -v + + # Summary job for branch protection + test-summary: + runs-on: ubuntu-latest + needs: [backend-test, frontend-test, docker-build] + if: always() + + steps: + - name: Test Summary + run: | + echo "## Test Summary" + echo "Backend Tests: ${{ needs.backend-test.result }}" + echo "Frontend Tests: ${{ needs.frontend-test.result }}" + echo "Docker Build: ${{ needs.docker-build.result }}" + + if [ "${{ needs.backend-test.result }}" != "success" ] || \ + [ "${{ needs.frontend-test.result }}" != "success" ] || \ + [ "${{ needs.docker-build.result }}" != "success" ]; then + echo "::error::One or more tests failed" + exit 1 + fi + + echo "All tests passed successfully!" \ No newline at end of file diff --git a/frontend/src/components/Buckets/CreateBucketDialog.tsx b/frontend/src/components/Buckets/CreateBucketDialog.tsx index a2c6131..19743e3 100644 --- a/frontend/src/components/Buckets/CreateBucketDialog.tsx +++ b/frontend/src/components/Buckets/CreateBucketDialog.tsx @@ -35,9 +35,9 @@ interface CreateBucketDialogProps { interface FormData { bucketName: string; - createUser: boolean; - username: string; - password: string; + createUser?: boolean; + username?: string; + password?: string; } const schema = yup.object({ @@ -50,7 +50,7 @@ const schema = yup.object({ ) .min(3, 'Minimum 3 characters') .max(63, 'Maximum 63 characters'), - createUser: yup.boolean(), + createUser: yup.boolean().default(true), username: yup .string() .when('createUser', { @@ -119,12 +119,12 @@ const CreateBucketDialog: React.FC = ({ // Create bucket with user (like the script) await api.post('/buckets/with-user', { bucketName: data.bucketName, - username: data.username, - password: data.password, + username: data.username!, + password: data.password!, }); setCredentials({ - username: data.username, - password: data.password, + username: data.username!, + password: data.password!, }); } else { // Create bucket only