ci: move scan/release to self-hosted, use NORA for cache and images

- Add NORA (localhost:5000) as internal registry for image push and cache
- Replace type=gha cache with type=registry pointing to NORA
- Move scan and release jobs from ubuntu-latest to self-hosted runner
- Upload binary as artifact in build, download in release (no docker pull)
- Generate SBOM from NORA image instead of ghcr.io
- Add driver-opts: network=host to buildx for localhost registry access
This commit is contained in:
2026-02-25 00:19:37 +00:00
parent 161d7f706a
commit fb0f80ac5a

View File

@@ -6,6 +6,7 @@ on:
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
NORA: localhost:5000
IMAGE_NAME: ${{ github.repository }} IMAGE_NAME: ${{ github.repository }}
jobs: jobs:
@@ -30,22 +31,33 @@ jobs:
cargo build --release --target x86_64-unknown-linux-musl --package nora-registry cargo build --release --target x86_64-unknown-linux-musl --package nora-registry
cp target/x86_64-unknown-linux-musl/release/nora ./nora cp target/x86_64-unknown-linux-musl/release/nora ./nora
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: nora-binary-${{ github.run_id }}
path: ./nora
retention-days: 1
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- name: Log in to Container Registry - name: Log in to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v3
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
# ── Alpine (standard) ──────────────────────────────────────────────────── # ── Alpine ───────────────────────────────────────────────────────────────
- name: Extract metadata (alpine) - name: Extract metadata (alpine)
id: meta-alpine id: meta-alpine
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: |
${{ env.NORA }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
@@ -60,15 +72,17 @@ jobs:
push: true push: true
tags: ${{ steps.meta-alpine.outputs.tags }} tags: ${{ steps.meta-alpine.outputs.tags }}
labels: ${{ steps.meta-alpine.outputs.labels }} labels: ${{ steps.meta-alpine.outputs.labels }}
cache-from: type=gha,scope=alpine cache-from: type=registry,ref=${{ env.NORA }}/${{ env.IMAGE_NAME }}-cache:alpine
cache-to: type=gha,mode=max,scope=alpine cache-to: type=registry,ref=${{ env.NORA }}/${{ env.IMAGE_NAME }}-cache:alpine,mode=max
# ── RED OS ─────────────────────────────────────────────────────────────── # ── RED OS ───────────────────────────────────────────────────────────────
- name: Extract metadata (redos) - name: Extract metadata (redos)
id: meta-redos id: meta-redos
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: |
${{ env.NORA }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: suffix=-redos,onlatest=true flavor: suffix=-redos,onlatest=true
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
@@ -84,15 +98,17 @@ jobs:
push: true push: true
tags: ${{ steps.meta-redos.outputs.tags }} tags: ${{ steps.meta-redos.outputs.tags }}
labels: ${{ steps.meta-redos.outputs.labels }} labels: ${{ steps.meta-redos.outputs.labels }}
cache-from: type=gha,scope=redos cache-from: type=registry,ref=${{ env.NORA }}/${{ env.IMAGE_NAME }}-cache:redos
cache-to: type=gha,mode=max,scope=redos cache-to: type=registry,ref=${{ env.NORA }}/${{ env.IMAGE_NAME }}-cache:redos,mode=max
# ── Astra Linux SE ─────────────────────────────────────────────────────── # ── Astra Linux SE ───────────────────────────────────────────────────────
- name: Extract metadata (astra) - name: Extract metadata (astra)
id: meta-astra id: meta-astra
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: |
${{ env.NORA }}/${{ env.IMAGE_NAME }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: suffix=-astra,onlatest=true flavor: suffix=-astra,onlatest=true
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
@@ -108,12 +124,12 @@ jobs:
push: true push: true
tags: ${{ steps.meta-astra.outputs.tags }} tags: ${{ steps.meta-astra.outputs.tags }}
labels: ${{ steps.meta-astra.outputs.labels }} labels: ${{ steps.meta-astra.outputs.labels }}
cache-from: type=gha,scope=astra cache-from: type=registry,ref=${{ env.NORA }}/${{ env.IMAGE_NAME }}-cache:astra
cache-to: type=gha,mode=max,scope=astra cache-to: type=registry,ref=${{ env.NORA }}/${{ env.IMAGE_NAME }}-cache:astra,mode=max
scan: scan:
name: Scan (${{ matrix.name }}) name: Scan (${{ matrix.name }})
runs-on: ubuntu-latest runs-on: [self-hosted, nora]
needs: build needs: build
permissions: permissions:
contents: read contents: read
@@ -132,28 +148,19 @@ jobs:
suffix: "-astra" suffix: "-astra"
steps: steps:
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set version tag (strip leading v) - name: Set version tag (strip leading v)
id: ver id: ver
run: echo "tag=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT run: echo "tag=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
# ── CVE scan of the pushed image ────────────────────────────────────────
# Images are FROM scratch — no OS packages, only binary CVE scan
- name: Trivy — image scan (${{ matrix.name }}) - name: Trivy — image scan (${{ matrix.name }})
uses: aquasecurity/trivy-action@0.30.0 uses: aquasecurity/trivy-action@0.30.0
with: with:
scan-type: image scan-type: image
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }}${{ matrix.suffix }} image-ref: ${{ env.NORA }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }}${{ matrix.suffix }}
format: sarif format: sarif
output: trivy-image-${{ matrix.name }}.sarif output: trivy-image-${{ matrix.name }}.sarif
severity: HIGH,CRITICAL severity: HIGH,CRITICAL
exit-code: 1 # block release on HIGH/CRITICAL vulnerabilities exit-code: 1
- name: Upload Trivy image results to GitHub Security tab - name: Upload Trivy image results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4 uses: github/codeql-action/upload-sarif@v4
@@ -164,56 +171,46 @@ jobs:
release: release:
name: GitHub Release name: GitHub Release
runs-on: ubuntu-latest runs-on: [self-hosted, nora]
needs: [build, scan] needs: [build, scan]
permissions: permissions:
contents: write contents: write
packages: read # to pull image for SBOM generation packages: read
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set version tag (strip leading v) - name: Set version tag (strip leading v)
id: ver id: ver
run: echo "tag=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT run: echo "tag=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
# ── Binary — extract from Docker image ────────────────────────────────── - name: Download binary artifact
- name: Extract binary from image uses: actions/download-artifact@v4
with:
name: nora-binary-${{ github.run_id }}
path: ./artifacts
- name: Prepare binary
run: | run: |
docker create --name nora-extract \ cp ./artifacts/nora ./nora-linux-amd64
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }}
docker cp nora-extract:/usr/local/bin/nora ./nora-linux-amd64
docker rm nora-extract
chmod +x ./nora-linux-amd64 chmod +x ./nora-linux-amd64
sha256sum ./nora-linux-amd64 > nora-linux-amd64.sha256 sha256sum ./nora-linux-amd64 > nora-linux-amd64.sha256
echo "Binary size: $(du -sh nora-linux-amd64 | cut -f1)" echo "Binary size: $(du -sh nora-linux-amd64 | cut -f1)"
cat nora-linux-amd64.sha256 cat nora-linux-amd64.sha256
# ── SBOM — Software Bill of Materials ───────────────────────────────────
- name: Generate SBOM (SPDX) - name: Generate SBOM (SPDX)
uses: anchore/sbom-action@v0 uses: anchore/sbom-action@v0
with: with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }} image: ${{ env.NORA }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }}
format: spdx-json format: spdx-json
output-file: nora-${{ github.ref_name }}.sbom.spdx.json output-file: nora-${{ github.ref_name }}.sbom.spdx.json
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate SBOM (CycloneDX) - name: Generate SBOM (CycloneDX)
uses: anchore/sbom-action@v0 uses: anchore/sbom-action@v0
with: with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }} image: ${{ env.NORA }}/${{ env.IMAGE_NAME }}:${{ steps.ver.outputs.tag }}
format: cyclonedx-json format: cyclonedx-json
output-file: nora-${{ github.ref_name }}.sbom.cdx.json output-file: nora-${{ github.ref_name }}.sbom.cdx.json
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1