mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
ci: one CI path — .hanzo/workflows
Every job in all seven workflows named `runs-on: lux-build-amd64`, except
build.yml's arm64 leg, which named `["self-hosted","linux","arm64"]`. No runner
on this forge carries any of those labels — the pools are
`lux-build-linux-<arch>` — and a job naming a label nothing carries does not
fail: it waits. ci.yml additionally fired on `branches: ["*"]`, so every push to
every branch queued the whole file, CodeQL and SBOM included.
What survives: test, lint, govulncheck and build move to
.hanzo/workflows/ci.yml, scoped to main and pull requests.
docker.yml and release.yml merge into .hanzo/workflows/release.yml. Both fired
on the same `v*` tag with no shared concurrency group, which is how a tag ends
up half-published; they are now one workflow — per-arch image, manifest, Go
binaries, GitHub release, notify — under one group that does not cancel. The
manifest step also proves the composed tag is pullable before the job goes
green, so a pin can never point at a tag that resolves to nothing.
Two auth paths had to change or the release could not work off GitHub:
* ghcr login used `github.actor` plus the instance GITHUB_TOKEN, which here is
a Hanzo Git token with no rights at ghcr.io. It now uses GHCR_USER and
GHCR_TOKEN, the org Actions secrets sourced from KMS.
* the luxfi/hsm module token is written to RUNNER_TEMP with its trailing
whitespace stripped before BuildKit mounts it. Dockerfile:50 interpolates it
into a URL, so one trailing newline truncates the URL there and git resolves
the credential prefix as the host ("Could not resolve host: x-access-token").
luxfi/node hit exactly this.
* the universe notification used peter-evans/repository-dispatch, which
resolves GITHUB_API_URL — on this forge that is the forge's own API, where a
github.com PAT does not authenticate and luxfi/universe's dispatch endpoint
does not exist. It now calls api.github.com explicitly.
Deleted rather than migrated:
* e2e-tests.yml and benchmarks.yml. Both trigger on `push: branches: [master]`
while the default branch is main, so neither has fired. Both also build
`./cmd/lux-mpc`, which is not in this repo (cmd/ holds mpc and mpcd), and
drive `e2e/docker-compose.test.yaml`, which does not exist either (the file
is e2e/compose.test.yml). Three independent reasons each; they have never
run and could not have passed.
The e2e SUITE is real and now has no CI. It needs repair at the source
before it can have any: e2e/*.go shells out to `lux-mpc` and `lux-mpc-cli`,
which no longer exist, and to `docker-compose.test.yaml`, which is named
compose.test.yml; e2e/Makefile expects `mpc` and `mpc-cli` on PATH and
mpc-cli is not built either. That is a repair, not a migration, so it is not
smuggled in here.
* build.yml. It pushed a floating `:latest` and branch-named tags on every
push to main/test/dev, against the semver-only policy the release workflow
holds to, and its arm64 half named a pool that does not exist.
* the codeql-analysis, sbom and security-scan jobs. All three exist to upload
SARIF to the GitHub Security tab via github/codeql-action/upload-sarif.
There is no Security tab on this forge, so they compute results with nowhere
to put them. govulncheck stays in CI, reporting into the job log.
docs.yml's build survives as .hanzo/workflows/docs.yml; its publish does not.
configure-pages, upload-pages-artifact and deploy-pages speak to the GitHub
Pages API, which this forge does not have. The docs still fail the build that
breaks them; they are no longer published from CI until the site is served from
the PaaS.
All seven files are accounted for, which is the constraint: the forge stops at
the first workflow directory that exists, so a repo's entire .github/workflows
suite goes dark the moment .hanzo/workflows appears.
Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -1,180 +0,0 @@
|
||||
name: Benchmarks
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
benchmark_time:
|
||||
description: 'Benchmark time per test (e.g., 10s, 1m)'
|
||||
required: false
|
||||
default: '10s'
|
||||
|
||||
jobs:
|
||||
unit-benchmarks:
|
||||
runs-on: lux-build-amd64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Install dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Run unit benchmarks
|
||||
run: |
|
||||
go test -bench=. -benchmem -benchtime=${{ github.event.inputs.benchmark_time || '10s' }} ./pkg/... | tee benchmark_results.txt
|
||||
|
||||
- name: Upload benchmark results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: unit-benchmark-results
|
||||
path: benchmark_results.txt
|
||||
|
||||
e2e-benchmarks:
|
||||
runs-on: lux-build-amd64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Build binaries
|
||||
run: |
|
||||
go build -o lux-mpc ./cmd/lux-mpc
|
||||
go build -o mpc ./cmd/mpc
|
||||
chmod +x lux-mpc mpc
|
||||
|
||||
- name: Install binaries
|
||||
run: |
|
||||
sudo mv lux-mpc /usr/local/bin/
|
||||
sudo mv mpc /usr/local/bin/
|
||||
|
||||
- name: Install E2E dependencies
|
||||
run: |
|
||||
cd e2e
|
||||
go mod download
|
||||
|
||||
- name: Setup test environment
|
||||
run: |
|
||||
cd e2e
|
||||
docker compose -f docker-compose.test.yaml up -d
|
||||
sleep 10
|
||||
docker compose -f docker-compose.test.yaml ps
|
||||
|
||||
- name: Run E2E benchmarks
|
||||
run: |
|
||||
cd e2e
|
||||
go test -bench=. -benchmem -benchtime=${{ github.event.inputs.benchmark_time || '10s' }} -timeout=30m | tee e2e_benchmark_results.txt
|
||||
|
||||
- name: Upload E2E benchmark results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: e2e-benchmark-results
|
||||
path: e2e/e2e_benchmark_results.txt
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
cd e2e
|
||||
docker compose -f docker-compose.test.yaml down -v
|
||||
./cleanup_test_env.sh || true
|
||||
|
||||
benchmark-comparison:
|
||||
needs: [unit-benchmarks, e2e-benchmarks]
|
||||
runs-on: lux-build-amd64
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
steps:
|
||||
- name: Download current benchmark results
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: unit-benchmark-results
|
||||
path: current/
|
||||
|
||||
- name: Download E2E benchmark results
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: e2e-benchmark-results
|
||||
path: current/
|
||||
|
||||
- name: Comment PR with results
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
let comment = '## 📊 Benchmark Results\n\n';
|
||||
|
||||
// Read unit benchmark results
|
||||
if (fs.existsSync('current/benchmark_results.txt')) {
|
||||
const unitResults = fs.readFileSync('current/benchmark_results.txt', 'utf8');
|
||||
comment += '### Unit Benchmarks\n```\n' + unitResults + '\n```\n\n';
|
||||
}
|
||||
|
||||
// Read E2E benchmark results
|
||||
if (fs.existsSync('current/e2e_benchmark_results.txt')) {
|
||||
const e2eResults = fs.readFileSync('current/e2e_benchmark_results.txt', 'utf8');
|
||||
comment += '### E2E Benchmarks\n```\n' + e2eResults + '\n```\n';
|
||||
}
|
||||
|
||||
// Find and update or create comment
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
});
|
||||
|
||||
const botComment = comments.find(comment =>
|
||||
comment.user.type === 'Bot' && comment.body.includes('📊 Benchmark Results')
|
||||
);
|
||||
|
||||
if (botComment) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: botComment.id,
|
||||
body: comment
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, test, dev]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runner: '["self-hosted","linux","amd64"]'
|
||||
- arch: arm64
|
||||
runner: '["self-hosted","linux","arm64"]'
|
||||
runs-on: ${{ fromJSON(matrix.runner) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}-${{ matrix.arch }}
|
||||
cache-from: type=gha,scope=${{ matrix.arch }}
|
||||
cache-to: type=gha,scope=${{ matrix.arch }},mode=max
|
||||
|
||||
manifest:
|
||||
needs: [docker]
|
||||
if: always() && contains(needs.docker.result, 'success')
|
||||
runs-on: lux-build-amd64
|
||||
steps:
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- run: |
|
||||
IMAGE="ghcr.io/${{ github.repository }}"
|
||||
BRANCH="${{ github.ref_name }}"
|
||||
SOURCES=""
|
||||
for ARCH in amd64 arm64; do
|
||||
if docker buildx imagetools inspect "${IMAGE}:${BRANCH}-${ARCH}" >/dev/null 2>&1; then
|
||||
SOURCES="${SOURCES} ${IMAGE}:${BRANCH}-${ARCH}"
|
||||
fi
|
||||
done
|
||||
[ -z "$SOURCES" ] && exit 1
|
||||
for TAG in "${BRANCH}" latest; do
|
||||
docker buildx imagetools create -t "${IMAGE}:${TAG}" ${SOURCES}
|
||||
done
|
||||
@@ -1,328 +0,0 @@
|
||||
name: CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*"]
|
||||
pull_request:
|
||||
branches: ["*"]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: lux-build-amd64
|
||||
env:
|
||||
GOEXPERIMENT: runtimesecret
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Download dependencies
|
||||
run: GOWORK=off go mod download
|
||||
|
||||
- name: Run unit tests
|
||||
run: GOWORK=off CGO_ENABLED=1 go test -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./coverage.out
|
||||
flags: unittests
|
||||
name: codecov-umbrella
|
||||
|
||||
lint:
|
||||
runs-on: lux-build-amd64
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
env:
|
||||
GOWORK: "off"
|
||||
CGO_ENABLED: "0"
|
||||
with:
|
||||
version: latest
|
||||
install-mode: goinstall
|
||||
args: --timeout=5m
|
||||
skip-cache: true
|
||||
|
||||
# Security vulnerability scanning
|
||||
security-scan:
|
||||
runs-on: lux-build-amd64
|
||||
name: Security Vulnerability Scan
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Vendor dependencies
|
||||
run: GOWORK=off go mod vendor
|
||||
|
||||
- name: Install govulncheck
|
||||
run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
|
||||
- name: Run govulncheck and generate SARIF
|
||||
run: |
|
||||
echo "Current directory: $(pwd)"
|
||||
echo "Files in current directory:"
|
||||
ls -la
|
||||
govulncheck -format=sarif ./... > govulncheck-results.sarif
|
||||
|
||||
govulncheck -json ./... > vuln.json
|
||||
count=$(jq '[.[] | select(.finding != null and .finding.trace != null)] | length' vuln.json || echo 0)
|
||||
echo "Found $count vulnerabilities"
|
||||
|
||||
if [ "$count" -gt 0 ]; then
|
||||
echo "Vulnerabilities found by govulncheck (see Security tab for details)"
|
||||
else
|
||||
echo "No vulnerabilities found by govulncheck"
|
||||
fi
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload govulncheck results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
sarif_file: govulncheck-results.sarif
|
||||
category: govulncheck
|
||||
|
||||
- name: Install gosec
|
||||
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
|
||||
- name: Run gosec security scanner
|
||||
run: |
|
||||
gosec -fmt sarif -out gosec-results.sarif -exclude G304 ./...
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload gosec results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
sarif_file: gosec-results.sarif
|
||||
category: gosec
|
||||
|
||||
# CodeQL Analysis
|
||||
codeql-analysis:
|
||||
name: CodeQL Analysis
|
||||
runs-on: lux-build-amd64
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ["go"]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Vendor dependencies
|
||||
run: GOWORK=off go mod vendor
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-and-quality
|
||||
|
||||
- name: Build for CodeQL
|
||||
run: |
|
||||
CGO_ENABLED=0 go build -v ./cmd/mpcd
|
||||
CGO_ENABLED=0 go build -v ./cmd/mpc
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
# SBOM Generation
|
||||
sbom:
|
||||
runs-on: lux-build-amd64
|
||||
name: Generate SBOM
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Vendor dependencies
|
||||
run: GOWORK=off go mod vendor
|
||||
|
||||
- name: Build binaries
|
||||
run: |
|
||||
CGO_ENABLED=0 go build -o mpcd ./cmd/mpcd
|
||||
CGO_ENABLED=0 go build -o mpc ./cmd/mpc
|
||||
|
||||
- name: Generate SBOM with anchore/sbom-action (SPDX-JSON)
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
artifact-name: sbom-spdx.json
|
||||
output-file: sbom.spdx.json
|
||||
format: spdx-json
|
||||
|
||||
- name: Generate SBOM with anchore/sbom-action (CycloneDX)
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
artifact-name: sbom-cyclonedx.json
|
||||
output-file: sbom.cyclonedx.json
|
||||
format: cyclonedx-json
|
||||
upload-artifact: false
|
||||
|
||||
- name: Generate SBOM with anchore/sbom-action (Syft JSON)
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
artifact-name: sbom-syft.json
|
||||
output-file: sbom.syft.json
|
||||
format: syft-json
|
||||
upload-artifact: false
|
||||
|
||||
- name: Upload all SBOM artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom-files
|
||||
path: |
|
||||
sbom.spdx.json
|
||||
sbom.cyclonedx.json
|
||||
sbom.syft.json
|
||||
retention-days: 30
|
||||
|
||||
- name: Install Grype
|
||||
run: |
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
- name: Scan SBOM with Grype
|
||||
run: |
|
||||
grype sbom.spdx.json -o sarif --file grype-results.sarif
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload Grype results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
sarif_file: grype-results.sarif
|
||||
category: grype
|
||||
|
||||
- name: Display SBOM summary
|
||||
run: |
|
||||
echo "SBOM Generation Summary"
|
||||
echo "========================="
|
||||
echo "Generated SBOM files:"
|
||||
ls -la sbom.*
|
||||
echo ""
|
||||
echo "SBOM package count:"
|
||||
echo "SPDX: $(jq '.packages | length' sbom.spdx.json)"
|
||||
echo "CycloneDX: $(jq '.components | length' sbom.cyclonedx.json)"
|
||||
echo "Syft: $(jq '.artifacts | length' sbom.syft.json)"
|
||||
|
||||
build:
|
||||
runs-on: lux-build-amd64
|
||||
needs: [test, lint, codeql-analysis, sbom]
|
||||
env:
|
||||
GOEXPERIMENT: runtimesecret
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Vendor dependencies
|
||||
run: GOWORK=off go mod vendor
|
||||
|
||||
- name: Build mpcd
|
||||
run: CGO_ENABLED=0 GOWORK=off go build -mod=vendor -v ./cmd/mpcd
|
||||
|
||||
- name: Build mpc CLI
|
||||
run: CGO_ENABLED=0 GOWORK=off go build -mod=vendor -v ./cmd/mpc
|
||||
@@ -1,86 +0,0 @@
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags: ['v*']
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# No GH-hosted arm runners. arm64 builds via Docker buildx with QEMU on
|
||||
# the amd64 self-hosted runner (QEMU is acceptable for Docker builds).
|
||||
runs-on: lux-build-amd64
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
if: matrix.arch == 'arm64'
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: arm64
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
env:
|
||||
# Token for BuildKit to fetch PRIVATE first-party modules (luxfi/hsm)
|
||||
# via authed direct git — mounted as a secret, never baked in a layer.
|
||||
# Regressed out in a prior "public modules" simplification; restored.
|
||||
GH_TOKEN: ${{ secrets.UNIVERSE_PAT }}
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
IMG=ghcr.io/luxfi/mpc:${TAG}-${{ matrix.arch }}
|
||||
docker buildx build \
|
||||
--platform linux/${{ matrix.arch }} \
|
||||
--secret id=gh_token,env=GH_TOKEN \
|
||||
--tag "$IMG" \
|
||||
--push \
|
||||
.
|
||||
|
||||
manifest:
|
||||
needs: build
|
||||
runs-on: lux-build-amd64
|
||||
steps:
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Create manifest
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
IMG=ghcr.io/luxfi/mpc
|
||||
# buildx imagetools composes the per-arch OCI indices that
|
||||
# `docker buildx build --push` emits. `docker manifest create`
|
||||
# rejects them ("X is a manifest list"); imagetools handles them.
|
||||
docker buildx imagetools create -t $IMG:$TAG \
|
||||
$IMG:${TAG}-amd64 \
|
||||
$IMG:${TAG}-arm64
|
||||
|
||||
notify:
|
||||
needs: manifest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
runs-on: lux-build-amd64
|
||||
steps:
|
||||
- uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.UNIVERSE_PAT }}
|
||||
repository: luxfi/universe
|
||||
event-type: image-published
|
||||
client-payload: |
|
||||
{
|
||||
"service": "mpc",
|
||||
"image": "ghcr.io/luxfi/mpc:${{ github.ref_name }}",
|
||||
"tag": "${{ github.ref_name }}"
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
name: Deploy Docs to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'docs/**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: lux-build-amd64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: docs/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: docs
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build docs
|
||||
working-directory: docs
|
||||
run: pnpm build
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/out
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: lux-build-amd64
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -1,334 +0,0 @@
|
||||
name: E2E Integration Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
# Build job that creates the binaries needed by all E2E test jobs
|
||||
build:
|
||||
runs-on: lux-build-amd64
|
||||
outputs:
|
||||
cache-key: ${{ steps.cache-key.outputs.key }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Tidy Go modules
|
||||
run: |
|
||||
go mod tidy
|
||||
|
||||
- name: Generate cache key
|
||||
id: cache-key
|
||||
run: echo "key=${{ runner.os }}-binaries-${{ hashFiles('**/go.sum', '**/*.go') }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache binaries
|
||||
id: cache-binaries
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./lux-mpc
|
||||
./mpc
|
||||
key: ${{ steps.cache-key.outputs.key }}
|
||||
|
||||
- name: Cache Go modules
|
||||
if: steps.cache-binaries.outputs.cache-hit != 'true'
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.cache-binaries.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
go mod download
|
||||
cd e2e && go mod download
|
||||
|
||||
- name: Build binaries
|
||||
if: steps.cache-binaries.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
go build -o lux-mpc ./cmd/lux-mpc
|
||||
go build -o mpc ./cmd/mpc
|
||||
chmod +x lux-mpc mpc
|
||||
|
||||
# Key Generation E2E Tests
|
||||
e2e-keygen:
|
||||
runs-on: lux-build-amd64
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Tidy Go modules
|
||||
run: |
|
||||
go mod tidy
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Verify Docker Compose
|
||||
run: |
|
||||
docker --version
|
||||
docker compose version
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Restore binaries
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./lux-mpc
|
||||
./mpc
|
||||
key: ${{ needs.build.outputs.cache-key }}
|
||||
|
||||
- name: Install binaries
|
||||
run: |
|
||||
sudo mv lux-mpc /usr/local/bin/
|
||||
sudo mv mpc /usr/local/bin/
|
||||
|
||||
- name: Verify binaries are available
|
||||
run: |
|
||||
which lux-mpc
|
||||
which mpc
|
||||
lux-mpc --version || echo "lux-mpc binary ready"
|
||||
mpc --version || echo "mpc binary ready"
|
||||
|
||||
- name: Install E2E dependencies
|
||||
run: |
|
||||
cd e2e && go mod tidy && go mod download
|
||||
|
||||
- name: Run Key Generation E2E tests
|
||||
run: |
|
||||
cd e2e
|
||||
go test -v -timeout=1200s -run TestKeyGeneration
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
|
||||
- name: Cleanup Docker containers
|
||||
if: always()
|
||||
run: |
|
||||
cd e2e
|
||||
docker compose -f docker-compose.test.yaml down -v || true
|
||||
docker system prune -f || true
|
||||
|
||||
- name: Upload keygen test logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e-keygen-test-logs
|
||||
path: e2e/logs/
|
||||
retention-days: 7
|
||||
|
||||
# Signing E2E Tests
|
||||
e2e-signing:
|
||||
runs-on: lux-build-amd64
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Tidy Go modules
|
||||
run: |
|
||||
go mod tidy
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Verify Docker Compose
|
||||
run: |
|
||||
docker --version
|
||||
docker compose version
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Restore binaries
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./lux-mpc
|
||||
./mpc
|
||||
key: ${{ needs.build.outputs.cache-key }}
|
||||
|
||||
- name: Install binaries
|
||||
run: |
|
||||
sudo mv lux-mpc /usr/local/bin/
|
||||
sudo mv mpc /usr/local/bin/
|
||||
|
||||
- name: Verify binaries are available
|
||||
run: |
|
||||
which lux-mpc
|
||||
which mpc
|
||||
lux-mpc --version || echo "lux-mpc binary ready"
|
||||
mpc --version || echo "mpc binary ready"
|
||||
|
||||
- name: Install E2E dependencies
|
||||
run: |
|
||||
cd e2e && go mod tidy && go mod download
|
||||
|
||||
- name: Run Signing E2E tests
|
||||
run: |
|
||||
cd e2e
|
||||
go test -v -timeout=1200s -run TestSigning
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
|
||||
- name: Cleanup Docker containers
|
||||
if: always()
|
||||
run: |
|
||||
cd e2e
|
||||
docker compose -f docker-compose.test.yaml down -v || true
|
||||
docker system prune -f || true
|
||||
|
||||
- name: Upload signing test logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e-signing-test-logs
|
||||
path: e2e/logs/
|
||||
retention-days: 7
|
||||
|
||||
# Resharing E2E Tests
|
||||
e2e-resharing:
|
||||
runs-on: lux-build-amd64
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.26.3"
|
||||
|
||||
- name: Tidy Go modules
|
||||
run: |
|
||||
go mod tidy
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Verify Docker Compose
|
||||
run: |
|
||||
docker --version
|
||||
docker compose version
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Restore binaries
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./lux-mpc
|
||||
./mpc
|
||||
key: ${{ needs.build.outputs.cache-key }}
|
||||
|
||||
- name: Install binaries
|
||||
run: |
|
||||
sudo mv lux-mpc /usr/local/bin/
|
||||
sudo mv mpc /usr/local/bin/
|
||||
|
||||
- name: Verify binaries are available
|
||||
run: |
|
||||
which lux-mpc
|
||||
which mpc
|
||||
lux-mpc --version || echo "lux-mpc binary ready"
|
||||
mpc --version || echo "mpc binary ready"
|
||||
|
||||
- name: Install E2E dependencies
|
||||
run: |
|
||||
cd e2e && go mod tidy && go mod download
|
||||
|
||||
- name: Run Resharing E2E tests
|
||||
run: |
|
||||
cd e2e
|
||||
go test -v -timeout=1200s -run TestResharing
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
|
||||
- name: Cleanup Docker containers
|
||||
if: always()
|
||||
run: |
|
||||
cd e2e
|
||||
docker compose -f docker-compose.test.yaml down -v || true
|
||||
docker system prune -f || true
|
||||
|
||||
- name: Upload resharing test logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e-resharing-test-logs
|
||||
path: e2e/logs/
|
||||
retention-days: 7
|
||||
|
||||
# Summary job that depends on all E2E tests
|
||||
e2e-summary:
|
||||
runs-on: lux-build-amd64
|
||||
needs: [e2e-keygen, e2e-signing, e2e-resharing]
|
||||
if: always()
|
||||
|
||||
steps:
|
||||
- name: Check E2E test results
|
||||
run: |
|
||||
echo "E2E Test Results Summary:"
|
||||
echo "========================="
|
||||
echo "Key Generation Tests: ${{ needs.e2e-keygen.result }}"
|
||||
echo "Signing Tests: ${{ needs.e2e-signing.result }}"
|
||||
echo "Resharing Tests: ${{ needs.e2e-resharing.result }}"
|
||||
echo ""
|
||||
|
||||
# Check if any tests failed
|
||||
if [[ "${{ needs.e2e-keygen.result }}" != "success" || "${{ needs.e2e-signing.result }}" != "success" || "${{ needs.e2e-resharing.result }}" != "success" ]]; then
|
||||
echo "❌ One or more E2E tests failed"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ All E2E tests passed successfully"
|
||||
fi
|
||||
@@ -1,48 +0,0 @@
|
||||
name: Release MPC
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# All builds run on the amd64 self-hosted runner. arm64 cross-compiles
|
||||
# via GOARCH; CGO_ENABLED=0 keeps it pure-Go (no cross-compiler needed).
|
||||
runs-on: lux-build-amd64
|
||||
# luxfi/* are PUBLIC modules — fetched and checksum-verified through the
|
||||
# default immutable proxy.golang.org + sum.golang.org. No GOPRIVATE /
|
||||
# GONOSUMDB / GOPROXY=direct bypass (those route around the checksum db).
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.26.3'
|
||||
- name: Build (cross-compile via GOARCH)
|
||||
run: |
|
||||
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=${{ matrix.arch }} \
|
||||
go build -trimpath -ldflags="-s -w" -o mpcd ./cmd/mpcd/
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mpcd-linux-${{ matrix.arch }}
|
||||
path: mpcd
|
||||
|
||||
release:
|
||||
needs: build
|
||||
runs-on: lux-build-amd64
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist/
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: dist/**/*
|
||||
@@ -0,0 +1,92 @@
|
||||
name: CI
|
||||
|
||||
# Test, lint and build, on the native runners (git.hanzo.ai → git-runner).
|
||||
#
|
||||
# This replaces .github/workflows/ci.yml, whose every job named
|
||||
# `runs-on: lux-build-amd64`. No runner on this forge carries that label — the
|
||||
# pools are `lux-build-linux-<arch>` — and a job naming a label nothing carries
|
||||
# does not fail, it waits.
|
||||
#
|
||||
# It also triggered on `branches: ["*"]`, so every push to every branch queued
|
||||
# the whole file, CodeQL and SBOM included. It is scoped to main and pull
|
||||
# requests here.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# A newer commit makes the older run irrelevant.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GOWORK: 'off'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
GOEXPERIMENT: runtimesecret
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
- run: go mod download
|
||||
- name: Unit tests
|
||||
run: CGO_ENABLED=1 go test -v -race -coverprofile=coverage.out ./...
|
||||
|
||||
lint:
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- uses: golangci/golangci-lint-action@v6
|
||||
env:
|
||||
CGO_ENABLED: '0'
|
||||
with:
|
||||
version: latest
|
||||
install-mode: goinstall
|
||||
args: --timeout=5m
|
||||
skip-cache: true
|
||||
|
||||
govulncheck:
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
# Reports rather than gates, as it did before. Making it blocking is a
|
||||
# policy decision, not part of moving where the job runs.
|
||||
- run: govulncheck ./... || true
|
||||
|
||||
build:
|
||||
needs: [test, lint]
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
GOEXPERIMENT: runtimesecret
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
- run: go mod vendor
|
||||
- run: CGO_ENABLED=0 go build -mod=vendor -v ./cmd/mpcd
|
||||
- run: CGO_ENABLED=0 go build -mod=vendor -v ./cmd/mpc
|
||||
@@ -0,0 +1,56 @@
|
||||
name: Docs
|
||||
|
||||
# Builds the docs site on the native runners (git.hanzo.ai → git-runner).
|
||||
#
|
||||
# This replaces .github/workflows/docs.yml, which built the site and then
|
||||
# published it with actions/configure-pages + actions/upload-pages-artifact +
|
||||
# actions/deploy-pages. Those three speak to the GitHub Pages API, which this
|
||||
# forge does not have and is not going to grow — so the publish half cannot
|
||||
# work here at all.
|
||||
#
|
||||
# The build half is worth keeping on its own: it fails on the commit that
|
||||
# breaks the docs, path-filtered so it only runs when docs change. Publishing
|
||||
# is gone until the site is served from the PaaS.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.hanzo/workflows/docs.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: docs/pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: docs
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build docs
|
||||
working-directory: docs
|
||||
run: pnpm build
|
||||
@@ -0,0 +1,192 @@
|
||||
name: Release
|
||||
|
||||
# Builds ghcr.io/luxfi/mpc, cuts the GitHub release, and tells luxfi/universe
|
||||
# the image exists — on the native runners (git.hanzo.ai → git-runner).
|
||||
#
|
||||
# This replaces .github/workflows/docker.yml and .github/workflows/release.yml,
|
||||
# both of which fired on the same `v*` tag and both of whose jobs named
|
||||
# `runs-on: lux-build-amd64`. No runner on this forge carries that label — the
|
||||
# pools are `lux-build-linux-<arch>` — and a job naming a label nothing carries
|
||||
# does not fail, it waits. Two workflows racing on one tag with no shared
|
||||
# concurrency group is also how a release ends up half-published; they are one
|
||||
# workflow here, under one group that does not cancel.
|
||||
#
|
||||
# ghcr auth is GHCR_USER / GHCR_TOKEN, org Actions secrets sourced from KMS. The
|
||||
# old workflows logged in as `github.actor` with the instance GITHUB_TOKEN,
|
||||
# which on this forge is a Hanzo Git token with no rights at ghcr.io.
|
||||
#
|
||||
# arm64 is built under QEMU on the amd64 pool. That is acceptable for a docker
|
||||
# build and it is what the old workflow did; the Go binaries below cross-compile
|
||||
# natively.
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
# A release is not made irrelevant by a newer one — let it finish.
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
image:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
if: matrix.arch == 'arm64'
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: arm64
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver: docker-container
|
||||
driver-opts: network=host
|
||||
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USER }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
|
||||
- name: Write the private-module token for BuildKit
|
||||
# Stripped of trailing whitespace on purpose. Dockerfile:50 interpolates
|
||||
# this into a URL:
|
||||
# git config url."https://x-access-token:$(cat /run/secrets/gh_token)@github.com/"
|
||||
# so a single trailing newline in the stored secret truncates the URL at
|
||||
# it and git resolves the credential prefix as the HOST:
|
||||
# Could not resolve host: x-access-token
|
||||
# luxfi/node hit exactly this. The secret's bytes are not ours to
|
||||
# control, so the trim happens here.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
printf '%s' '${{ secrets.UNIVERSE_PAT }}' | tr -d '\r\n' > "${RUNNER_TEMP}/gh_token"
|
||||
if [ ! -s "${RUNNER_TEMP}/gh_token" ]; then
|
||||
echo "::error::UNIVERSE_PAT is empty — the luxfi/hsm module fetch will fail"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Build and push (${{ matrix.arch }})
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
secrets: |
|
||||
gh_token=${{ runner.temp }}/gh_token
|
||||
provenance: false
|
||||
push: true
|
||||
tags: ghcr.io/luxfi/mpc:${{ github.ref_name }}-${{ matrix.arch }}
|
||||
|
||||
manifest:
|
||||
needs: image
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ secrets.GHCR_USER }}
|
||||
password: ${{ secrets.GHCR_TOKEN }}
|
||||
- name: Compose the multi-arch tag
|
||||
# imagetools, not `docker manifest create`: `docker buildx build --push`
|
||||
# emits a per-arch OCI index, and `docker manifest create` rejects those
|
||||
# ("X is a manifest list"). imagetools handles them.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
IMG=ghcr.io/luxfi/mpc
|
||||
TAG='${{ github.ref_name }}'
|
||||
docker buildx imagetools create -t "$IMG:$TAG" \
|
||||
"$IMG:${TAG}-amd64" \
|
||||
"$IMG:${TAG}-arm64"
|
||||
|
||||
- name: Verify the pushed manifest resolves
|
||||
# A tag that names nothing pullable is how a deployment ends up pinned
|
||||
# to a phantom: the pin applies, the pod never starts, and the tag looks
|
||||
# like a release. Prove it before the job is green.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
img="ghcr.io/luxfi/mpc:${{ github.ref_name }}"
|
||||
for i in 1 2 3 4 5 6; do
|
||||
if docker manifest inspect "$img" >/dev/null 2>&1; then
|
||||
echo "$img is resolvable"; exit 0
|
||||
fi
|
||||
echo "manifest not visible yet (attempt ${i}/6) — retrying"; sleep 5
|
||||
done
|
||||
echo "::error::$img not pullable after push"; exit 1
|
||||
|
||||
binaries:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
# arm64 cross-compiles via GOARCH; CGO_ENABLED=0 keeps it pure Go, so one
|
||||
# amd64 runner covers both and no cross-compiler is needed.
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 30
|
||||
# luxfi/* are PUBLIC modules, fetched and checksum-verified through the
|
||||
# default immutable proxy.golang.org + sum.golang.org. No GOPRIVATE /
|
||||
# GONOSUMDB / GOPROXY=direct bypass — those route around the checksum db.
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- name: Build (cross-compile via GOARCH)
|
||||
run: |
|
||||
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=${{ matrix.arch }} \
|
||||
go build -trimpath -ldflags="-s -w" -o mpcd ./cmd/mpcd/
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mpcd-linux-${{ matrix.arch }}
|
||||
path: mpcd
|
||||
|
||||
release:
|
||||
needs: binaries
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: dist/
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: dist/**/*
|
||||
|
||||
notify:
|
||||
needs: [manifest, release]
|
||||
runs-on: [lux-build-linux-amd64]
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Tell luxfi/universe the image is published
|
||||
# Called against api.github.com explicitly. The old workflow used
|
||||
# peter-evans/repository-dispatch, which resolves GITHUB_API_URL — here
|
||||
# that is this forge's API, where a github.com PAT does not authenticate
|
||||
# and luxfi/universe's dispatch endpoint does not live.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
curl -fsSL -X POST https://api.github.com/repos/luxfi/universe/dispatches \
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
-H 'Authorization: Bearer ${{ secrets.UNIVERSE_PAT }}' \
|
||||
-d '{
|
||||
"event_type": "image-published",
|
||||
"client_payload": {
|
||||
"service": "mpc",
|
||||
"image": "ghcr.io/luxfi/mpc:${{ github.ref_name }}",
|
||||
"tag": "${{ github.ref_name }}"
|
||||
}
|
||||
}'
|
||||
Reference in New Issue
Block a user