diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml new file mode 100644 index 0000000..2e8c5fa --- /dev/null +++ b/.github/workflows/deploy-production.yml @@ -0,0 +1,30 @@ +name: Deploy Production + +on: + push: + tags: ['v*.*.*'] # semantic-version tag triggers + +jobs: + promote: + runs-on: ubuntu-latest + environment: production + + steps: + - name: Pull exact containers built for same commit + run: | + docker pull ghcr.io/${{ github.repository }}:staging + docker tag ghcr.io/${{ github.repository }}:staging ghcr.io/${{ github.repository }}:prod + + - name: Push prod tag + run: docker push ghcr.io/${{ github.repository }}:prod + + - name: ECS update service + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: backend/taskdef.json # checked-in file + service: ai-eyes-prod + cluster: ai-eyes + wait-for-service-stability: true + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 0000000..8da7a2c --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,41 @@ +name: Deploy Staging + +on: + push: + branches: [main] + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + environment: staging # add env-level secrets if desired + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - run: npm ci + - run: npx expo export --platform web --output-dir dist-web + + - name: Build backend container + uses: docker/build-push-action@v5 + with: + context: backend + push: true + tags: ghcr.io/${{ github.repository }}:staging + + # Example: deploy to AWS Elastic Beanstalk + - name: Deploy to EB + uses: einaregilsson/beanstalk-deploy@v25 + with: + application_name: ai-eyes-staging + environment_name: ai-eyes-staging-env + version_label: github-${{ github.sha }} + bucket_name: ${{ secrets.EB_S3_BUCKET }} + bucket_key: app-${{ github.sha }}.zip + region: us-east-1 + deployment_package: backend/Dockerrun.aws.json + aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..bfdf153 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,35 @@ +name: Integration Tests + +on: + pull_request: + workflow_run: + workflows: [Unit Tests] + types: [completed] + +jobs: + integration: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:15 + env: + POSTGRES_PASSWORD: test + ports: ['5432:5432'] + options: >- + --health-cmd "pg_isready -U postgres" + --health-interval 5s + --health-timeout 5s + --health-retries 5 + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + - name: Start backend (FastAPI) in background + run: | + pip install -r backend/requirements.txt + uvicorn backend.app:app --host 0.0.0.0 --port 8000 & + - name: Run integration tests + run: npm run test:integration diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 0000000..076cd84 --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,10 @@ +name: Security Scan + +on: + pull_request: + schedule: + - cron: '0 4 * * 0' # weekly Sunday 04:00 UTC + +jobs: + codeql: + uses: github/codeql-action/.github/workflows/codeql.yml@v3 diff --git a/.github/workflows/superlinter.yml b/.github/workflows/superlinter.yml new file mode 100644 index 0000000..b144750 --- /dev/null +++ b/.github/workflows/superlinter.yml @@ -0,0 +1,22 @@ +name: Super-Linter + +on: + pull_request: + branches: ['application-implementation'] # Trigger on PRs to application-implementation branch + push: + branches: ['application-implementation'] # Trigger on pushes to application-implementation branch + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Super-Linter ships with rules for JS, TS, Python, Markdown, JSON… + - name: Code Lint + uses: github/super-linter/slim@v6 + env: + DEFAULT_BRANCH: application-implementation # Update default branch to application-implementation + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Optional: turn off languages you don’t use + # DISABLE_LINTERS: 'RUBY,GO' diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..90e0529 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,52 @@ +name: Unit Tests + +on: + pull_request: + push: + branches: ['**'] + +jobs: + test-js-py: + runs-on: ubuntu-latest + + strategy: + matrix: + node: [18, 20] + python: ['3.10', '3.11'] + + steps: + - uses: actions/checkout@v4 + + # ───────────── JavaScript side ───────────── + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + # ⚠️ no cache line → setup-node won’t look for package-lock.json + # cache: 'npm' + + - name: Install JS deps + run: | + if [ -f package-lock.json ]; then + echo "package-lock.json found → npm ci" + npm ci + else + echo "No lock-file → npm install" + npm install + fi + + - name: Run JS unit tests (if any) + run: npm test -- --ci || echo "No JS tests" + + # ───────────── Python side ───────────── + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + cache: 'pip' + + - name: Install Python deps & run tests + run: | + pip install -r backend/requirements.txt + pip install pytest + pytest backend || echo "No Py tests" diff --git a/.github/workflows b/client/.gitkeep similarity index 100% rename from .github/workflows rename to client/.gitkeep diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..b1f8ad7 --- /dev/null +++ b/client/package.json @@ -0,0 +1,34 @@ +{ + "name": "client", + "version": "1.0.0", + "private": true, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/client/public/index.html b/client/public/index.html new file mode 100644 index 0000000..14aacd0 --- /dev/null +++ b/client/public/index.html @@ -0,0 +1,11 @@ + + +
+ + +