ci: add security scanning and SBOM to release pipeline

- ci.yml: add security job (gitleaks, cargo-audit, cargo-deny, trivy fs)
- release.yml: restructure into build-binary + build-docker matrix + release
  - build binary once on self-hosted, reuse across all Docker builds
  - trivy image scan per matrix variant, results to GitHub Security tab
  - SBOM generation in SPDX and CycloneDX formats attached to release
- deny.toml: cargo-deny policy (allowed licenses, banned openssl, crates.io only)
- Dockerfile: remove Rust build stage, use pre-built binary
- Dockerfile.astra, Dockerfile.redos: FROM scratch for Russian certified OS support
This commit is contained in:
2026-02-23 11:37:27 +00:00
parent 037204a3eb
commit 6ad710ff32
6 changed files with 197 additions and 141 deletions

View File

@@ -27,3 +27,59 @@ jobs:
- name: Run tests
run: cargo test --package nora-registry
security:
name: Security
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # for uploading SARIF to GitHub Security tab
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history required for gitleaks
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
# ── Secrets ────────────────────────────────────────────────────────────
- name: Gitleaks — scan for hardcoded secrets
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ── CVE in Rust dependencies ────────────────────────────────────────────
- name: Install cargo-audit
run: cargo install cargo-audit --locked
- name: cargo audit — RustSec advisory database
run: cargo audit
# ── Licenses, banned crates, supply chain policy ────────────────────────
- name: cargo deny — licenses and banned crates
uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check
arguments: --all-features
# ── CVE scan of source tree and Cargo.lock ──────────────────────────────
- name: Trivy — filesystem scan (Cargo.lock + source)
uses: aquasecurity/trivy-action@master
with:
scan-type: fs
scan-ref: .
format: sarif
output: trivy-fs.sarif
severity: HIGH,CRITICAL
exit-code: 0 # warn only; change to 1 to block the pipeline
- name: Upload Trivy fs results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-fs.sarif
category: trivy-fs

View File

@@ -9,12 +9,36 @@ env:
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
build-binary:
name: Build Binary
runs-on: self-hosted
steps:
- uses: actions/checkout@v4
- name: Set up Rust
run: echo "/home/ai-user/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin" >> $GITHUB_PATH
- name: Build release binary
run: |
RUSTUP_HOME=/home/ai-user/.rustup cargo build --release --package nora-registry
cp target/release/nora ./nora
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: nora-binary
path: nora
retention-days: 1
build-docker:
name: Build & Push (${{ matrix.name }})
runs-on: self-hosted
needs: build-binary
permissions:
contents: read
packages: write
security-events: write # for uploading SARIF to GitHub Security tab
strategy:
fail-fast: false
@@ -33,6 +57,14 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Download binary
uses: actions/download-artifact@v4
with:
name: nora-binary
- name: Make binary executable
run: chmod +x nora
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -68,20 +100,64 @@ jobs:
cache-from: type=gha,scope=${{ matrix.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.name }}
# ── CVE scan of the pushed image ────────────────────────────────────────
- name: Trivy — image scan
uses: aquasecurity/trivy-action@master
with:
scan-type: image
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}${{ matrix.suffix }}
format: sarif
output: trivy-image-${{ matrix.name }}.sarif
severity: HIGH,CRITICAL
exit-code: 0 # warn only; change to 1 to block on vulnerabilities
- name: Upload Trivy image results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-image-${{ matrix.name }}.sarif
category: trivy-image-${{ matrix.name }}
release:
name: GitHub Release
runs-on: ubuntu-latest
needs: build
needs: build-docker
permissions:
contents: write
packages: read # to pull image for SBOM generation
steps:
- 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 }}
# ── SBOM — Software Bill of Materials ───────────────────────────────────
- name: Generate SBOM (SPDX)
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
format: spdx-json
output-file: nora-${{ github.ref_name }}.sbom.spdx.json
- name: Generate SBOM (CycloneDX)
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
format: cyclonedx-json
output-file: nora-${{ github.ref_name }}.sbom.cdx.json
- name: Create Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
files: |
nora-${{ github.ref_name }}.sbom.spdx.json
nora-${{ github.ref_name }}.sbom.cdx.json
body: |
## Docker