Merge pull request #822 from Yacht-sh/develop #140
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build And Publish Images | |
| on: | |
| push: | |
| branches: | |
| - master | |
| - develop | |
| workflow_dispatch: | |
| concurrency: | |
| group: image-publish-${{ github.ref_name }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| verify-frontend: | |
| name: Verify Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci --legacy-peer-deps --no-audit --no-fund | |
| - name: Lint frontend | |
| working-directory: frontend | |
| run: npm run lint | |
| - name: Audit frontend runtime dependencies | |
| working-directory: frontend | |
| run: | | |
| npm audit --omit=dev --json > audit.json || true | |
| node - <<'NODE' | |
| const fs = require("fs"); | |
| const report = JSON.parse(fs.readFileSync("audit.json", "utf8")); | |
| const allowlist = new Set(["GHSA-5j4c-8p2g-v4jx", "1111465"]); | |
| const severities = new Set(["high", "critical"]); | |
| const findings = []; | |
| const packages = report.vulnerabilities || {}; | |
| for (const [pkg, vuln] of Object.entries(packages)) { | |
| const entries = Array.isArray(vuln.via) ? vuln.via : []; | |
| for (const entry of entries) { | |
| if (!entry || typeof entry !== "object") { | |
| continue; | |
| } | |
| const source = String( | |
| entry.source || entry.url || entry.name || "" | |
| ); | |
| const severity = String(entry.severity || "").toLowerCase(); | |
| if (!severities.has(severity)) { | |
| continue; | |
| } | |
| if (allowlist.has(source)) { | |
| continue; | |
| } | |
| findings.push(`${pkg}: ${source} (${severity})`); | |
| } | |
| } | |
| if (findings.length) { | |
| console.error("Unallowlisted frontend vulnerabilities found:"); | |
| for (const finding of findings) { | |
| console.error(` - ${finding}`); | |
| } | |
| process.exit(1); | |
| } | |
| console.log("Frontend audit passed with current allowlist."); | |
| NODE | |
| - name: Build frontend | |
| working-directory: frontend | |
| run: npm run build | |
| verify-backend: | |
| name: Verify Backend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Install backend system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| build-essential \ | |
| pkg-config \ | |
| libffi-dev \ | |
| libssl-dev \ | |
| libpq-dev \ | |
| default-libmysqlclient-dev \ | |
| libjpeg-dev \ | |
| zlib1g-dev \ | |
| libyaml-dev \ | |
| python3-dev | |
| - name: Install backend dependencies | |
| working-directory: backend | |
| run: | | |
| python -m pip install --upgrade pip setuptools wheel | |
| python -m pip install --no-cache-dir -r requirements.txt | |
| python -m pip install --no-cache-dir bandit pip-audit | |
| - name: Validate backend dependency graph | |
| run: python -m pip check | |
| - name: Compile backend sources | |
| run: python -m compileall backend | |
| - name: Run Bandit | |
| run: bandit -q -r backend/api | |
| - name: Audit backend dependencies | |
| run: pip-audit -r backend/requirements.txt --progress-spinner=off | |
| verify-agent: | |
| name: Verify Agent | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Install agent dependencies | |
| working-directory: agent | |
| run: | | |
| python -m pip install --upgrade pip setuptools wheel | |
| python -m pip install --no-cache-dir -r requirements.txt | |
| python -m pip install --no-cache-dir bandit pip-audit | |
| - name: Compile agent sources | |
| run: python -m compileall agent | |
| - name: Run Bandit on agent | |
| run: bandit -q -r agent | |
| - name: Audit agent dependencies | |
| run: pip-audit -r agent/requirements.txt --progress-spinner=off | |
| publish-main-image: | |
| name: Publish Main Image | |
| runs-on: ubuntu-latest | |
| needs: | |
| - verify-frontend | |
| - verify-backend | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Prepare image metadata | |
| id: prep | |
| run: | | |
| timestamp="$(date -u +%Y%m%d-%H%M%S)" | |
| if [ "${GITHUB_REF_NAME}" = "master" ]; then | |
| channel_tag="latest" | |
| version_tag="${timestamp}" | |
| app_version="${timestamp}" | |
| elif [ "${GITHUB_REF_NAME}" = "develop" ]; then | |
| channel_tag="dev-latest" | |
| version_tag="dev-${timestamp}" | |
| app_version="dev-${timestamp}" | |
| else | |
| echo "Unsupported ref ${GITHUB_REF_NAME}" >&2 | |
| exit 1 | |
| fi | |
| { | |
| echo "channel_tag=${channel_tag}" | |
| echo "version_tag=${version_tag}" | |
| echo "app_version=${app_version}" | |
| echo "owner_lc=${GITHUB_REPOSITORY_OWNER,,}" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Extract image metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ steps.prep.outputs.owner_lc }}/yacht | |
| tags: | | |
| type=raw,value=${{ steps.prep.outputs.channel_tag }} | |
| type=raw,value=${{ steps.prep.outputs.version_tag }} | |
| labels: | | |
| org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push main image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: linux/amd64,linux/arm64,linux/arm/v7 | |
| push: true | |
| build-args: | | |
| VUE_APP_VERSION=${{ steps.prep.outputs.app_version }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=main-image-${{ github.ref_name }} | |
| cache-to: type=gha,mode=max,scope=main-image-${{ github.ref_name }} | |
| provenance: mode=max | |
| sbom: true | |
| publish-agent-image: | |
| name: Publish Agent Image | |
| runs-on: ubuntu-latest | |
| needs: | |
| - verify-agent | |
| permissions: | |
| contents: read | |
| packages: write | |
| attestations: write | |
| id-token: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Prepare image metadata | |
| id: prep | |
| run: | | |
| timestamp="$(date -u +%Y%m%d-%H%M%S)" | |
| if [ "${GITHUB_REF_NAME}" = "master" ]; then | |
| channel_tag="latest" | |
| version_tag="${timestamp}" | |
| elif [ "${GITHUB_REF_NAME}" = "develop" ]; then | |
| channel_tag="dev-latest" | |
| version_tag="dev-${timestamp}" | |
| else | |
| echo "Unsupported ref ${GITHUB_REF_NAME}" >&2 | |
| exit 1 | |
| fi | |
| { | |
| echo "channel_tag=${channel_tag}" | |
| echo "version_tag=${version_tag}" | |
| echo "owner_lc=${GITHUB_REPOSITORY_OWNER,,}" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Extract image metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ steps.prep.outputs.owner_lc }}/yacht-agent | |
| tags: | | |
| type=raw,value=${{ steps.prep.outputs.channel_tag }} | |
| type=raw,value=${{ steps.prep.outputs.version_tag }} | |
| labels: | | |
| org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push agent image | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ./agent/Dockerfile | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=agent-image-${{ github.ref_name }} | |
| cache-to: type=gha,mode=max,scope=agent-image-${{ github.ref_name }} | |
| provenance: mode=max | |
| sbom: true |