From a9a9ea086da380c8fd1109a8fc277d7fa4cc324a Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 7 Oct 2026 08:52:03 -0500 Subject: [PATCH] Deploy master automatically after Gitleaks scan --- .gitea/workflows/deploy.yml | 65 +++++++++++++++++++++++++++++++++++ .gitea/workflows/validate.yml | 29 ---------------- README.md | 21 +++++++---- deploy/known_hosts | 1 + 4 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 .gitea/workflows/deploy.yml delete mode 100644 .gitea/workflows/validate.yml create mode 100644 deploy/known_hosts diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..6731745 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,65 @@ +name: Deploy Dashboard +on: + push: + branches: [master] + pull_request: + workflow_dispatch: +concurrency: + group: household-dashboard-${{ github.ref }} + cancel-in-progress: false +env: + GITLEAKS_VERSION: 8.30.1 + GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb +jobs: + gitleaks: + runs-on: shared-ci + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Gitleaks + run: | + set -euo pipefail + curl -fsSLo /tmp/gitleaks.tar.gz "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" + printf '%s %s\n' "$GITLEAKS_SHA256" /tmp/gitleaks.tar.gz | sha256sum --check + tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks + - name: Scan repository history + run: /tmp/gitleaks git --no-banner --redact . + build: + needs: gitleaks + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' + runs-on: shared-ci + env: + IMAGE: git.uuard.com/nicholas/household-dashboard + REVISION: ${{ github.sha }} + steps: + - uses: actions/checkout@v4 + - name: Log in to Gitea registry + uses: docker/login-action@v3 + with: + registry: git.uuard.com + username: nicholas + password: ${{ secrets.REGISTRY_TOKEN }} + - name: Build and push dashboard image + run: | + set -euo pipefail + docker build --label "org.opencontainers.image.revision=$REVISION" --label "org.opencontainers.image.source=https://git.uuard.com/nicholas/household-dashboard" -t "$IMAGE:$REVISION" -t "$IMAGE:master" . + docker push "$IMAGE:$REVISION" + docker push "$IMAGE:master" + deploy: + needs: build + runs-on: household-dashboard-deploy + env: + REVISION: ${{ github.sha }} + steps: + - uses: actions/checkout@v4 + - name: Deploy dashboard + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + run: | + set -euo pipefail + deploy_key=$(mktemp) + chmod 600 "$deploy_key" + trap 'shred -u "$deploy_key"' EXIT + printf '%s\n' "$DEPLOY_SSH_KEY" > "$deploy_key" + ssh -i "$deploy_key" -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile="$PWD/deploy/known_hosts" dashboard-deploy@ward-vm-apps-02.hosts.uuard.com "$REVISION" diff --git a/.gitea/workflows/validate.yml b/.gitea/workflows/validate.yml deleted file mode 100644 index cd73d90..0000000 --- a/.gitea/workflows/validate.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Validate Dashboard -on: - push: - branches: [master] - pull_request: - workflow_dispatch: -jobs: - validate: - runs-on: shared-ci - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.13' - - uses: actions/setup-node@v4 - with: - node-version: '22' - - name: Install Python dependencies - run: | - python -m venv .venv - .venv/bin/pip install -r requirements.lock - - name: Test backend and read-only routes - run: .venv/bin/python -m unittest discover -s tests - - name: Test calendar layout and themes - run: npm test - - name: Validate container configuration - run: docker compose config --quiet - - name: Build container - run: docker build -t household-dashboard:ci . diff --git a/README.md b/README.md index d53aa80..9d58df6 100644 --- a/README.md +++ b/README.md @@ -69,14 +69,21 @@ checkout changes, including untracked files, before checking out that revision; manual host edits are temporary and will disappear on the next deployment. This repository owns the standalone application. Production infrastructure and -SOPS credentials live in `nicholas/home-ops`; its current deployment builds the -app copy at `stacks/apps/automation/household-dashboard`. Creating this repository -does not yet change that deployment to consume this repository. Keep that app -copy synchronized until deployment ownership is migrated. +SOPS credentials live in `nicholas/home-ops`; its deployment references the published image in +`stacks/apps/automation/household-dashboard/compose.yaml`. Application source and +releases are owned here; home-ops no longer builds its duplicate app copy. -The validation Action runs tests, validates Compose, and builds the image. It has -no production credentials and does not automatically deploy. Infrastructure -changes require deploying both apps-02 and edge-01 through home-ops. +Master pushes run Gitleaks, build a Docker image tagged with the commit SHA, push +it to the Gitea registry, and deploy to apps-02. Pull requests run Gitleaks only. +There are no automated test or lint gates. Local tests remain available below. + +Deployment uses a repository-scoped runner and a restricted SSH key. The host +command serializes deployment, pulls the exact image, waits up to two minutes for +readiness, and restores the previous image on failure. The selected image is +stored in an ignored Compose `.env` file, so routine home-ops deployments retain +it. Registry and SSH credentials are Gitea Actions secrets backed up in SOPS; +calendar/weather credentials stay on the host and never reach the workflow. +Infrastructure changes still deploy through home-ops. The host inventory includes this Compose project. Routine source updates require `docker compose up -d --build` to rebuild the application image. diff --git a/deploy/known_hosts b/deploy/known_hosts new file mode 100644 index 0000000..b074654 --- /dev/null +++ b/deploy/known_hosts @@ -0,0 +1 @@ +ward-vm-apps-02.hosts.uuard.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEGksPk9lQi8Mx18CWt/YvzEZS6Q2s0uAXfqS9kQaAGl