Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
self-hosted-runner:
labels:
- ci-pool-typescript
- ci-pool-go
- ci-pool-ops
154 changes: 97 additions & 57 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: CI

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

Expand All @@ -12,61 +13,92 @@ concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
GOFLAGS: -mod=readonly
GOTOOLCHAIN: local

jobs:
contract:
uses: dinglebear-ai/workflows/.github/workflows/fleet-contract.yml@542ea7b7e5ca2d4e21f3277bfcf158584fee90ec
with:
profile: go
implementation-ref: 542ea7b7e5ca2d4e21f3277bfcf158584fee90ec

frontend:
runs-on: ubuntu-24.04
timeout-minutes: 25
uses: dinglebear-ai/workflows/.github/workflows/fast-node.yml@542ea7b7e5ca2d4e21f3277bfcf158584fee90ec
with:
node-version: "24.18.0"
working-directory: web
cache-dependency-path: web/package-lock.json
install-command: npm ci --no-audit --no-fund
audit-command: npm audit --omit=dev --audit-level=high
lint-command: npm run lint
typecheck-command: npm run typecheck
test-command: npm run test:coverage
# fast-node.yml runs steps in a fixed order (test, then contract-command,
# then build-command), so build-command itself always executes AFTER the
# contract check. The Next.js export must exist before build-embed.mjs
# (run with --skip-build) and the asset diff can succeed, so the build
# is folded into contract-command and build-command is left unset.
# check-web-assets.sh also defaults to a repo-root-relative path, so it
# needs an explicit argument now that this step runs from web/.
contract-command: >-
npm run build &&
node scripts/build-embed.mjs --apply --skip-build &&
../scripts/check-web-assets.sh ../public/assets/_next &&
git diff --exit-code -- ../public/
timeout-minutes: 25

# fast-go.yml has no hook for repo-specific system packages: its
# "vulnerability" job (govulncheck) has no command input at all, and cgo
# preprocessing for the image/video plugins needs headers that aren't on
# the runner image. Both fast-go.yml sub-jobs failed identically on missing
# native deps, so backend is a bespoke job (matching backend-evidence)
# instead of a fast-go.yml call.
backend:
name: Backend build, vet, and tests
runs-on: [self-hosted, ci-pool-go]
timeout-minutes: 45
env:
GOFLAGS: -mod=readonly
GOTOOLCHAIN: local
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
persist-credentials: false
- name: Assert submitted revision
run: test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24.18.0
cache: npm
cache-dependency-path: web/package-lock.json
- run: npm ci --prefix web --no-audit --no-fund
- run: npm run lint --prefix web
- run: npm run typecheck --if-present --prefix web
- run: npm run test:coverage --prefix web
- run: npm audit --prefix web --omit=dev --audit-level=high
- run: npm run build --prefix web
- run: node web/scripts/build-embed.mjs --apply --skip-build
- run: ./scripts/check-web-assets.sh
- name: Embedded assets match frontend source
run: git diff --exit-code -- public/
- run: npx playwright install --with-deps chromium
- run: npm run test:e2e --prefix web
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
if: always()
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
name: frontend-test-artifacts-${{ github.sha }}
path: |
web/coverage/
web/playwright-report/
web/test-results/
if-no-files-found: warn
retention-days: 14
go-version: "1.26.5"
cache: true
- name: Native build dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libjpeg-dev libtiff-dev libpng-dev libwebp-dev libraw-dev libheif-dev \
libgif-dev libvips-dev libavcodec-dev libavdevice-dev libavfilter-dev \
libavformat-dev libswresample-dev libswscale-dev libavutil-dev
- run: go mod download && go mod verify
- run: go generate -x ./server/...
- run: go vet ./server/... ./cmd/...
- run: go test -count=1 ./server/... ./cmd/...
- run: CGO_ENABLED=1 go test -race -count=1 ./server/... ./cmd/...
- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@v1.6.0
- run: govulncheck ./server/... ./cmd/...
- name: Module files remain readonly
run: git diff --exit-code -- go.mod go.sum

backend:
runs-on: ubuntu-24.04
timeout-minutes: 45
backend-evidence:
name: Backend coverage and benchmarks
runs-on: [self-hosted, ci-pool-go]
timeout-minutes: 30
env:
GOFLAGS: -mod=readonly
GOTOOLCHAIN: local
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
persist-credentials: false
- name: Assert submitted revision
run: test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version: 1.26.5
cache-dependency-path: go.sum
go-version: "1.26.5"
cache: true
- name: Native build dependencies
run: |
sudo apt-get update
Expand All @@ -76,7 +108,6 @@ jobs:
libavformat-dev libswresample-dev libswscale-dev libavutil-dev
- run: go mod download && go mod verify
- run: go generate -x ./server/...
- run: go vet ./server/... ./cmd/...
- run: go test -count=1 -covermode=atomic -coverprofile=coverage-go.out ./server/... ./cmd/...
- run: ./scripts/check-go-coverage.sh coverage-go.out
- name: Critical-package coverage ratchet
Expand All @@ -86,11 +117,7 @@ jobs:
./server/pkg/workflow/trigger ./server/plugin/plg_handler_mcp \
./server/plugin/plg_handler_console ./server/plugin/plg_backend_dav
GO_COVERAGE_MIN=16.6 ./scripts/check-go-coverage.sh coverage-go-critical.out
- run: CGO_ENABLED=1 go test -race -count=1 ./server/... ./cmd/...
- run: go test -run '^$' -bench . -benchmem ./server/... ./cmd/... | tee benchmarks.txt
- run: go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./server/... ./cmd/...
- name: Module files remain readonly
run: git diff --exit-code -- go.mod go.sum
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: benchmarks-${{ github.sha }}
Expand All @@ -102,18 +129,19 @@ jobs:
retention-days: 30

sbom:
runs-on: ubuntu-24.04
runs-on: [self-hosted, ci-pool-go]
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
persist-credentials: false
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version: 1.26.5
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
go-version: "1.26.5"
cache: true
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24.18.0
node-version: "24.18.0"
cache: npm
cache-dependency-path: web/package-lock.json
- run: make sbom
Expand All @@ -126,10 +154,10 @@ jobs:

image:
needs: [frontend, backend]
runs-on: ubuntu-24.04
runs-on: [self-hosted, ci-pool-ops]
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
persist-credentials: false
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
Expand Down Expand Up @@ -173,3 +201,15 @@ jobs:
exit-code: "1"
ignore-unfixed: true
severity: CRITICAL,HIGH

gate:
name: CI
if: always()
needs: [contract, frontend, backend, backend-evidence, sbom, image]
runs-on: [self-hosted, ci-pool-ops]
timeout-minutes: 2
steps:
- name: Require every fast lane
env:
RESULTS: ${{ join(needs.*.result, ' ') }}
run: test "$RESULTS" = "success success success success success success"
109 changes: 109 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Release

on:
release:
types: [published]

permissions: {}

concurrency:
group: filestash-release-${{ github.event.release.tag_name }}
cancel-in-progress: false

jobs:
web:
permissions:
contents: read
uses: dinglebear-ai/workflows/.github/workflows/hosted-web-release.yml@542ea7b7e5ca2d4e21f3277bfcf158584fee90ec
with:
checkout-ref: ${{ github.event.release.tag_name }}
node-version: "24.18.0"
working-directory: web
cache-dependency-path: web/package-lock.json
install-command: npm ci --no-audit --no-fund
coverage-command: npm run test:coverage
build-command: >-
npm run build &&
node scripts/build-embed.mjs --apply --skip-build &&
../scripts/check-web-assets.sh
e2e-command: npm run test:e2e
artifact-name: filestash-web-${{ github.event.release.tag_name }}
artifact-path: public/
diagnostic-path: |
web/coverage/
web/playwright-report/
web/test-results/
timeout-minutes: 45

container:
needs: web
permissions:
contents: read
packages: write
attestations: write
id-token: write
uses: dinglebear-ai/workflows/.github/workflows/hosted-container-release.yml@542ea7b7e5ca2d4e21f3277bfcf158584fee90ec
with:
checkout-ref: ${{ github.event.release.tag_name }}
image: ghcr.io/${{ github.repository }}
release-tag: ${{ github.event.release.tag_name }}
dockerfile: docker/Dockerfile
build-args: BUILD_REF=${{ github.sha }}
smoke-command: |
set -euo pipefail
name="filestash-release-smoke-${GITHUB_RUN_ID}"
trap 'docker rm -f "$name" >/dev/null 2>&1 || true' EXIT
docker run -d --name "$name" "$IMAGE_REF" >/dev/null
for _ in {1..45}; do
health="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "$name")"
[[ "$health" == healthy ]] && exit 0
[[ "$health" == unhealthy ]] && break
sleep 2
done
docker logs "$name"
exit 1
cache-scope: filestash-release
timeout-minutes: 60
secrets:
REGISTRY_USERNAME: ${{ github.actor }}
REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}

sbom:
needs: web
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
ref: ${{ github.event.release.tag_name }}
persist-credentials: false
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version: "1.26.5"
cache: true
- uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: "24.18.0"
cache: npm
cache-dependency-path: web/package-lock.json
- run: make sbom
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: cyclonedx-sbom-${{ github.event.release.tag_name }}
path: dist/*.cdx.json
if-no-files-found: error
retention-days: 30

publish:
needs: [container, sbom]
permissions:
contents: write
attestations: write
id-token: write
uses: dinglebear-ai/workflows/.github/workflows/github-release.yml@542ea7b7e5ca2d4e21f3277bfcf158584fee90ec
with:
release-tag: ${{ github.event.release.tag_name }}
artifact-pattern: cyclonedx-sbom-*
artifact-path: release-artifacts
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pipeline {
sh '''
docker buildx build \
--file docker/Dockerfile \
--platform linux/amd64,linux/arm64 \
--platform linux/amd64 \
--build-arg BUILD_REF=${REVISION} \
--provenance=mode=max \
--sbom=true \
Expand Down
6 changes: 6 additions & 0 deletions docs/frontend-migration.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
---
title: Next.js Frontend Migration
created: 2026-07-30
updated: 2026-07-30
---

# Next.js Frontend Migration

The React/Aurora frontend is a static export embedded in the Filestash Go binary.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ require (
golang.org/x/sys v0.47.0 // indirect
golang.org/x/text v0.40.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 // indirect
google.golang.org/grpc v1.80.0 // indirect
google.golang.org/grpc v1.82.1 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
modernc.org/libc v1.72.1 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,12 @@ google.golang.org/api v0.276.0 h1:nVArUtfLEihtW+b0DdcqRGK1xoEm2+ltAihyztq7MKY=
google.golang.org/api v0.276.0/go.mod h1:Fnag/EWUPIcJXuIkP1pjoTgS5vdxlk3eeemL7Do6bvw=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7 h1:XzmzkmB14QhVhgnawEVsOn6OFsnpyxNPRY9QV01dNB0=
google.golang.org/genproto v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:L43LFes82YgSonw6iTXTxXUX1OlULt4AQtkik4ULL/I=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI=
google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y=
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 h1:XF8+t6QQiS0o9ArVan/HW8Q7cycNPGsJf6GA2nXxYAg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
Expand Down
Loading
Loading