diff --git a/.github/workflows/publish-dashboard.yml b/.github/workflows/publish-dashboard.yml index 03ab8435..a99ab50a 100644 --- a/.github/workflows/publish-dashboard.yml +++ b/.github/workflows/publish-dashboard.yml @@ -1,4 +1,4 @@ -name: Publish Dashboard image to GHCR +name: Publish Dashboard Image on: push: @@ -9,13 +9,8 @@ on: types: [published] workflow_dispatch: -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository_owner }}/exosphere-dashboard - SHA_TAG: ${{ github.sha }} - jobs: - publish-image-on-ghcr: + build-and-publish: runs-on: ubuntu-latest if: github.repository == 'exospherehost/exospherehost' @@ -23,85 +18,43 @@ jobs: contents: read packages: write - outputs: - tags: ${{ steps.meta.outputs.tags }} - json: ${{ steps.meta.outputs.json }} - steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 with: platforms: arm64 - - uses: docker/setup-buildx-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Log in to GHCR + - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Generate tags & labels - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw,value=beta-latest - type=sha,format=short - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: ./dashboard - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - provenance: true - sbom: true - - publish-image-on-docker: - runs-on: ubuntu-latest - if: github.repository == 'exospherehost/exospherehost' - - permissions: - contents: read - packages: write - - outputs: - tags: ${{ steps.meta.outputs.tags }} - json: ${{ steps.meta.outputs.json }} - - steps: - - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - - - uses: docker/setup-buildx-action@v3 - - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Generate tags & labels + - name: Generate tags & labels for both registries id: meta uses: docker/metadata-action@v5 with: - images: ${{ env.IMAGE_NAME }} + images: | + ghcr.io/exospherehost/exosphere-dashboard + exospherehost/exosphere-dashboard tags: | - type=raw,value=beta-latest + type=raw,value=latest type=sha,format=short - - name: Build and push + - name: Build and push to both registries uses: docker/build-push-action@v5 with: context: ./dashboard @@ -110,4 +63,4 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} provenance: true - sbom: true + sbom: true \ No newline at end of file diff --git a/.github/workflows/publish-state-manager.yml b/.github/workflows/publish-state-manager.yml new file mode 100644 index 00000000..24251bc0 --- /dev/null +++ b/.github/workflows/publish-state-manager.yml @@ -0,0 +1,101 @@ +name: Publish State Manager Image + +on: + push: + branches: [main] + paths: + - 'state-manager/**' + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + services: + mongodb: + image: mongo:7 + ports: + - 27017:27017 + options: >- + --health-cmd "mongosh --eval 'db.runCommand(\"ping\")'" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + env: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: password + MONGO_INITDB_DATABASE: test_db + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: state-manager/go.mod + + - name: Run test suite + working-directory: state-manager + env: + MONGO_URI: mongodb://admin:password@localhost:27017/?authSource=admin + MONGO_DATABASE_NAME: test_exosphere_state_manager + STATE_MANAGER_SECRET: test-secret-key + SECRETS_ENCRYPTION_KEY: ${{ secrets.STATE_MANAGER_ENCRYPTION_KEY }} + run: | + go test -v ./... + + publish: + runs-on: ubuntu-latest + needs: test + if: github.repository == 'exospherehost/exospherehost' + + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Generate tags & labels for both registries + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/exospherehost/exosphere-state-manager + exospherehost/exosphere-state-manager + tags: | + type=raw,value=latest + type=sha,format=short + + - name: Build and push to both registries + uses: docker/build-push-action@v5 + with: + context: ./state-manager + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + provenance: true + sbom: true \ No newline at end of file diff --git a/.github/workflows/publish-state-mangaer.yml b/.github/workflows/publish-state-mangaer.yml deleted file mode 100644 index b7494d5c..00000000 --- a/.github/workflows/publish-state-mangaer.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: Publish State Manager image to GHCR - -on: - push: - branches: [main] - paths: - - 'state-manager/**' - workflow_dispatch: - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository_owner }}/exosphere-state-manager - SHA_TAG: ${{ github.sha }} - -jobs: - test: - runs-on: ubuntu-latest - services: - mongodb: - image: mongo:7 - ports: - - 27017:27017 - options: >- - --health-cmd "mongosh --eval 'db.runCommand(\"ping\")'" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - env: - MONGO_INITDB_ROOT_USERNAME: admin - MONGO_INITDB_ROOT_PASSWORD: password - MONGO_INITDB_DATABASE: test_db - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - - name: Install uv - uses: astral-sh/setup-uv@v6 - with: - enable-cache: true - - - name: Install dev dependencies with uv - working-directory: state-manager - run: | - uv sync --group dev - - - name: Run full test suite with coverage - working-directory: state-manager - env: - MONGO_URI: mongodb://admin:password@localhost:27017 - MONGO_DATABASE_NAME: test_exosphere_state_manager - STATE_MANAGER_SECRET: test-secret-key - SECRETS_ENCRYPTION_KEY: YTzpUlBGLSwm-3yKJRJTZnb0_aQuQQHyz64s8qAERVU= - run: | - uv run pytest tests/ --cov=app --cov-report=xml --cov-report=term-missing --cov-report=html -v --junitxml=full-pytest-report.xml - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - slug: exospherehost/exospherehost - files: state-manager/coverage.xml - flags: unit-tests - name: state-manager-coverage-report - fail_ci_if_error: true - - publish-image-on-ghcr: - runs-on: ubuntu-latest - needs: test - if: github.repository == 'exospherehost/exospherehost' - - permissions: - contents: read - packages: write - - outputs: - tags: ${{ steps.meta.outputs.tags }} - json: ${{ steps.meta.outputs.json }} - - steps: - - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - - - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Generate tags & labels - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw, value=beta-latest - type=sha, value=${{ env.SHA_TAG }} - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: ./state-manager - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - provenance: true - sbom: true - - publish-image-on-docker-hub: - runs-on: ubuntu-latest - needs: test - if: github.repository == 'exospherehost/exospherehost' - - permissions: - contents: read - packages: write - - outputs: - tags: ${{ steps.meta.outputs.tags }} - json: ${{ steps.meta.outputs.json }} - - steps: - - uses: actions/checkout@v4 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: arm64 - - - uses: docker/setup-buildx-action@v3 - - - name: Log in to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Generate tags & labels - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=raw, value=beta-latest - type=sha, value=${{ env.SHA_TAG }} - - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: ./state-manager - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - provenance: true - sbom: true \ No newline at end of file diff --git a/.gitignore b/.gitignore index 774ebbf6..f938d0d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ # Ignore temp directory and temp files at repository root /temp* -!/temp/.gitkeep \ No newline at end of file +!/temp/.gitkeep + +.env \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..53ee2297 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,51 @@ +services: + exosphere-state-manager: + image: ghcr.io/exospherehost/exosphere-state-manager:${EXOSPHERE_TAG:-latest} + pull_policy: always + container_name: exosphere-state-manager + restart: unless-stopped + environment: + - MONGO_URI=${MONGO_URI:?missing MONGO_URI} + - STATE_MANAGER_SECRET=${STATE_MANAGER_SECRET:?missing STATE_MANAGER_SECRET} + - MONGO_DATABASE_NAME=${MONGO_DATABASE_NAME:-exosphere} + - SECRETS_ENCRYPTION_KEY=${SECRETS_ENCRYPTION_KEY:?missing SECRETS_ENCRYPTION_KEY} + ports: + - "8000:8000" + networks: + - exosphere-network + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + exosphere-dashboard: + image: ghcr.io/exospherehost/exosphere-dashboard:${EXOSPHERE_TAG:-latest} + pull_policy: always + container_name: exosphere-dashboard + restart: unless-stopped + environment: + # Server-side secure configuration (NOT exposed to browser) + - EXOSPHERE_STATE_MANAGER_URI=${EXOSPHERE_STATE_MANAGER_URI:-http://exosphere-state-manager:8000} + - EXOSPHERE_API_KEY=${EXOSPHERE_API_KEY:?missing EXOSPHERE_API_KEY} + # Client-side configuration (exposed to browser) + - NEXT_PUBLIC_DEFAULT_NAMESPACE=${NEXT_PUBLIC_DEFAULT_NAMESPACE:-default} + depends_on: + exosphere-state-manager: + condition: service_healthy + ports: + - "3000:3000" + networks: + - exosphere-network + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000', (res) => process.exit(res.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + +networks: + exosphere-network: + driver: bridge + attachable: true