integration_instructionsIntegration Guide

CI/CD Integration

Integrate EdgeGate into your GitHub Actions workflow to automatically test AI model performance on Qualcomm Snapdragon hardware. Set up in 5 minutes.

bolt

Quick Start

Get hardware regression testing running on your PRs in 4 steps.

1
key

Get Your Credentials

  1. Log in to your EdgeGate Dashboard
  2. Open your Workspace → Settings Integrations
  3. Click Generate CI Secret and copy the secret
  4. Note your Workspace ID from the URL or Settings page
2
lock

Add GitHub Secrets

In your repository, go to Settings → Secrets and variables → Actions and add:

SecretDescription
EDGEGATE_WORKSPACE_IDYour workspace UUID
EDGEGATE_API_SECRETThe CI secret you generated
EDGEGATE_PIPELINE_ID(Optional) Pipeline UUID to run
EDGEGATE_MODEL_ARTIFACT_ID(Optional) Model artifact UUID to test
3
description

Create Workflow File

Create a file at .github/workflows/edgegate.yml in your repository and paste the following content:

.github/workflows/edgegate.yml
yaml
name: EdgeGate AI Test

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

permissions:
  contents: read
  pull-requests: write
  issues: write
  checks: write

jobs:
  edgegate-test:
    name: EdgeGate AI Performance Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Run EdgeGate Test
        uses: actions/github-script@v7
        env:
          WORKSPACE_ID: ${{ secrets.EDGEGATE_WORKSPACE_ID }}
          API_SECRET: ${{ secrets.EDGEGATE_API_SECRET }}
          PIPELINE_ID: ${{ secrets.EDGEGATE_PIPELINE_ID }}
          MODEL_ARTIFACT_ID: ${{ secrets.EDGEGATE_MODEL_ARTIFACT_ID }}
          EDGEGATE_API_URL: https://edgegateapi.frozo.ai
        with:
          script: |
            const crypto = require('crypto');

            const timestamp = new Date().toISOString();
            const nonce = crypto.randomUUID();
            const body = JSON.stringify({
              pipeline_id: process.env.PIPELINE_ID,
              model_artifact_id: process.env.MODEL_ARTIFACT_ID,
              commit_sha: context.sha,
              branch: context.ref,
              pull_request: context.payload.pull_request?.number
            });

            const message = timestamp + '\n' + nonce + '\n' + body;
            const signature = crypto
              .createHmac('sha256', process.env.API_SECRET)
              .update(message)
              .digest('hex');

            const response = await fetch(
              process.env.EDGEGATE_API_URL + '/v1/ci/github/run',
              {
                method: 'POST',
                headers: {
                  'Content-Type': 'application/json',
                  'X-EdgeGate-Workspace': process.env.WORKSPACE_ID,
                  'X-EdgeGate-Timestamp': timestamp,
                  'X-EdgeGate-Nonce': nonce,
                  'X-EdgeGate-Signature': signature,
                },
                body: body,
              }
            );

            const result = await response.json();
            console.log('EdgeGate response:', JSON.stringify(result, null, 2));

            if (!response.ok) {
              core.setFailed('EdgeGate test failed: ' + result.detail);
            } else {
              core.info('Run queued: ' + result.run_id);
            }

Note: For the full production-ready script, please refer to our Integration Guide.

4
merge

Create a PR

The workflow runs automatically on every PR to main. You'll see:

  • Authentication verification
  • bar_chart Performance test results (inference time, peak memory)
  • verified Pass/fail gate status on your PR check
grid_view

Matrix Mode in CI

Run multiple models against multiple devices in one test — and optionally swap in a freshly-built model from CI on every PR.

EdgeGate ships a composite GitHub Action that handles three CI patterns out of the box. Drop one block into your workflow — no JWT, no JSON-by-hand, no bash gymnastics.

hubPattern A — Static matrix

Pipeline is configured once (via dashboard / API) with model_matrix. CI just triggers — server fans out across all M × D cells. Omit model-artifact-id entirely.

.github/workflows/edgegate.yml
yaml
name: EdgeGate AI Test
on:
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/edgegate
        with:
          workspace-id: ${{ secrets.EDGEGATE_WORKSPACE_ID }}
          api-secret:   ${{ secrets.EDGEGATE_API_SECRET }}
          pipeline-id:  ${{ secrets.EDGEGATE_PIPELINE_ID }}
          # model-artifact-id intentionally omitted — matrix is on the pipeline

buildPattern B — Dynamic regression (CI uploads fresh model + baseline matrix)

CI builds a new ONNX model on every PR and you want to regression-test it against a set of known-good baseline models. The action uploads the freshly-built file, swaps it into the pipeline matrix alongside your baselines, then triggers the run — all in one step.

.github/workflows/edgegate.yml
yaml
name: EdgeGate Regression Test
on:
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build model
        run: python scripts/build_model.py --out build/model.onnx
      - uses: ./.github/actions/edgegate
        with:
          workspace-id:           ${{ secrets.EDGEGATE_WORKSPACE_ID }}
          api-secret:             ${{ secrets.EDGEGATE_API_SECRET }}
          pipeline-id:            ${{ secrets.EDGEGATE_PIPELINE_ID }}
          model-path:             build/model.onnx
          baseline-artifact-ids:  ${{ secrets.EDGEGATE_BASELINE_IDS }}
          model-label:            ${{ github.sha }}
      # ↑ Action does: upload model.onnx → POST /v1/ci/github/upload-artifact
      #               replace matrix → POST /v1/ci/github/pipelines/{id}/matrix
      #                                   (fresh + baseline1 + baseline2 ...)
      #               trigger run → POST /v1/ci/github/run
info

How matrix swap works

The action replaces the pipeline's model_matrix wholesale. After the run, the matrix on the pipeline reflects what CI tested most recently. To keep a stable baseline set, store the baseline artifact UUIDs in the EDGEGATE_BASELINE_IDS secret (comma-separated). Hard limit: M × D ≤ 25 cells, M ≤ 10 models per matrix.

shieldAuth model

Pattern B uses three CI endpoints, all HMAC-authenticated with the same EDGEGATE_API_SECRET you already use for runs. No long-lived JWT, no separate upload key.

  • POST /v1/ci/github/upload-artifact — signature covers timestamp\nnonce\nsha256(file). Server re-hashes the upload and refuses on mismatch.
  • POST /v1/ci/github/pipelines/{id}/matrix — standard HMAC; replaces model_matrix; pipeline gates / devices / promptpack untouched.
  • POST /v1/ci/github/run — standard HMAC; matrix-mode triggers omit model_artifact_id.
rocket_launch

Full Integration

For complete on-device AI performance testing on every PR.

1
route

Create a Pipeline

  1. Go to Pipelines → Create Pipeline
  2. Select target devices (e.g., Snapdragon 8 Gen 3, Snapdragon 7s Gen 2)
  3. Define quality gates:
Example gates
yaml
gates:
  - metric: inference_time_ms
    operator: lte
    threshold: 1.0       # Inference ≤ 1.0ms
  - metric: peak_memory_mb
    operator: lte
    threshold: 150.0     # Peak memory ≤ 150MB

Copy the Pipeline ID from the pipeline detail page.

2
upload_file

Upload Your Model

  1. Go to Artifacts → Upload Model
  2. Upload your ONNX, TorchScript, or TFLite model
  3. Copy the Model Artifact ID
3
vpn_key

Add Pipeline Secrets

Add these additional secrets to your GitHub repository:

SecretValue
EDGEGATE_PIPELINE_IDPipeline UUID from step 1
EDGEGATE_MODEL_ARTIFACT_ID(Optional) Model Artifact UUID. Leave unset for matrix pipelines — the model set lives on the pipeline.

Now every PR will trigger full on-device AI regression tests automatically.

model_training

HuggingFace Token (Optional)

Connect a personal HuggingFace token so EdgeGate can import private, gated, or Qualcomm-org repos when uploading models.

By default, model imports from HuggingFace use anonymous access — fine for public repos. To pull models behind a license click-through (gated) or from a private / org-scoped repository, connect a personal token in workspace settings. The token is validated against HuggingFace whoami before being encrypted at rest with envelope encryption (same KMS as the AI Hub token).

1
key

Generate a HuggingFace token

  1. Visit huggingface.co/settings/tokens
  2. Click Create new token Read scope is sufficient.
  3. Copy the token (starts with hf_).
2
link

Connect it to your workspace

  1. Open your workspace → Settings HuggingFace.
  2. Paste the token and click Connect HuggingFace.
  3. You'll see your connected account name and type (user / organization).

Requires Admin role on the workspace. The endpoints exposed (all under /v1/workspaces/{ws}/integrations/huggingface):

MethodPathAction
POST/Connect a token (validates first)
GET/Get integration status
PUT/rotateReplace the stored token
PUT/disablePause without deleting
PUT/enableRe-enable a paused integration
DELETE/Permanently remove

Tip: the same flows are exposed as MCP tools (edgegate_connect_huggingface, edgegate_get_huggingface_integration, edgegate_disconnect_huggingface) — see /docs/mcp.

api

API Reference

All CI requests use HMAC-SHA256 authentication for security.

Authentication Headers

HeaderDescription
X-EdgeGate-WorkspaceWorkspace UUID
X-EdgeGate-TimestampISO 8601 timestamp (e.g. 2026-01-11T12:00:00Z)
X-EdgeGate-NonceUnique request ID (UUID v4)
X-EdgeGate-SignatureHMAC-SHA256 signature

Signature Computation

The signature is an HMAC-SHA256 digest of the message string using your CI secret as the key:

signature.sh
bash
# Message format: timestamp + newline + nonce + newline + body
# For POST requests (with body):
MESSAGE=$(printf '%s\n%s\n%s' "$TIMESTAMP" "$NONCE" "$BODY")
SIGNATURE=$(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

# For GET requests (no body):
MESSAGE=$(printf '%s\n%s\n' "$TIMESTAMP" "$NONCE")
SIGNATURE=$(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

Endpoints

GET/v1/ci/status

Test CI authentication. Returns 200 if your credentials are valid.

Response (200)

{
  "status": "ok",
  "workspace_id": "uuid",
  "message": "CI authentication successful"
}
POST/v1/ci/github/run

Trigger a performance test run on real Snapdragon hardware.

Request Body — single-model pipeline

{
  "pipeline_id": "uuid",
  "model_artifact_id": "uuid",
  "commit_sha": "abc123",
  "branch": "feature/new-model",
  "pull_request": 42
}

Request Body — matrix-mode pipeline

Omit model_artifact_id entirely. The matrix is declared on the pipeline (via dashboard or PUT /v1/pipelines) and CI just triggers — server fans out across all M × D cells.

{
  "pipeline_id": "uuid",
  "commit_sha": "abc123",
  "branch": "feature/new-model",
  "pull_request": 42
}

Response (202)

{
  "run_id": "uuid",
  "status": "queued",
  "pipeline_id": "uuid",
  "message": "Run queued successfully"
}
GET/v1/ci/runs/{run_id}

Poll the status of a run. Use this after triggering a run to wait for completion and check pass/fail results.

Response (200)

{
  "run_id": "uuid",
  "status": "passed",
  "pipeline_id": "uuid",
  "gates_passed": 2,
  "gates_total": 2,
  "metrics": {
    "inference_time_ms": 0.176,
    "peak_memory_mb": 121.51
  },
  "error": null,
  "completed_at": "2026-02-25T12:00:00Z"
}

Possible status values: queued running passed failed error

build

Troubleshooting

error"Invalid signature" error

  1. Verify EDGEGATE_API_SECRET is correctly set (43 characters)
  2. Check timestamp is current (±5 minutes tolerance)
  3. Ensure message format: timestamp\nnonce\nbody

error"Nonce already used" error

Each nonce can only be used once. The workflow generates unique UUIDs automatically. If you're testing manually, generate a new UUID for each request.

errorPipeline/Model not found

Verify the UUIDs are correct and belong to your workspace. Check the pipeline and artifact pages in the dashboard to confirm.

Ready to get started?

Create your free account and add hardware regression testing to your CI/CD pipeline in minutes.