ci.yml 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. name: CI
  2. on:
  3. pull_request:
  4. paths:
  5. - "**.go"
  6. - "go.mod"
  7. - "go.sum"
  8. - "frontend/**"
  9. - ".nvmrc"
  10. - "Makefile"
  11. - ".github/workflows/ci.yml"
  12. push:
  13. branches:
  14. - main
  15. paths:
  16. - "**.go"
  17. - "go.mod"
  18. - "go.sum"
  19. - "frontend/**"
  20. - ".nvmrc"
  21. - "Makefile"
  22. - ".github/workflows/ci.yml"
  23. permissions:
  24. contents: read
  25. jobs:
  26. go-test:
  27. runs-on: ubuntu-latest
  28. steps:
  29. - uses: actions/checkout@v7
  30. - uses: actions/setup-go@v7
  31. with:
  32. go-version-file: go.mod
  33. cache: true
  34. - name: Stub internal/web/dist for go:embed
  35. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  36. - name: Test
  37. run: |
  38. go list ./... | grep -v '/frontend/node_modules/' > /tmp/go-packages.txt
  39. go test -shuffle=on -count=1 $(cat /tmp/go-packages.txt)
  40. postgres-durable-first:
  41. runs-on: ubuntu-latest
  42. services:
  43. postgres:
  44. image: postgres:16
  45. env:
  46. POSTGRES_USER: postgres
  47. POSTGRES_PASSWORD: postgres
  48. POSTGRES_DB: xui_durable
  49. ports:
  50. - 5432:5432
  51. options: >-
  52. --health-cmd "pg_isready -U postgres -d xui_durable"
  53. --health-interval 10s
  54. --health-timeout 5s
  55. --health-retries 5
  56. env:
  57. XUI_DB_TYPE: postgres
  58. XUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable"
  59. steps:
  60. - uses: actions/checkout@v7
  61. - uses: actions/setup-go@v7
  62. with:
  63. go-version-file: go.mod
  64. cache: true
  65. - name: Stub internal/web/dist for go:embed
  66. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  67. - name: PostgreSQL durable-first tests
  68. run: |
  69. set -o pipefail
  70. go test ./internal/web/service -run 'PostgresCommitFailure' -count=1 -v | tee /tmp/postgres-durable-first.log
  71. # Count passes rather than assert no SKIP: a renamed or deleted test
  72. # prints "no tests to run" and exits 0, leaving the step green for nothing.
  73. passed=$(grep -c -- '--- PASS' /tmp/postgres-durable-first.log || true)
  74. if [ "$passed" -lt 1 ]; then
  75. echo "expected at least 1 passing durable-first test, got $passed" >&2
  76. exit 1
  77. fi
  78. - name: PostgreSQL schema and migration tests
  79. run: |
  80. set -o pipefail
  81. go test ./internal/database -run '^(TestHostAutoMigrateCreatesColumns_Postgres|TestMigrate_Postgres)$' -count=1 -v | tee /tmp/postgres-schema.log
  82. # Both must pass. Counting, not SKIP-matching: renaming either test would
  83. # otherwise leave this step green while testing nothing.
  84. passed=$(grep -c -- '--- PASS' /tmp/postgres-schema.log || true)
  85. if [ "$passed" -lt 2 ]; then
  86. echo "expected 2 passing PostgreSQL schema tests, got $passed" >&2
  87. exit 1
  88. fi
  89. codegen:
  90. runs-on: ubuntu-latest
  91. steps:
  92. - uses: actions/checkout@v7
  93. - uses: actions/setup-go@v7
  94. with:
  95. go-version-file: go.mod
  96. cache: true
  97. - uses: actions/setup-node@v7
  98. with:
  99. node-version-file: .nvmrc
  100. - name: Regenerate schemas, examples and OpenAPI
  101. run: npm run gen
  102. working-directory: frontend
  103. - name: Fail if generated files are stale (run 'npm run gen' and commit)
  104. run: git diff --exit-code -- frontend/src/generated frontend/public/openapi.json
  105. govulncheck:
  106. runs-on: ubuntu-latest
  107. steps:
  108. - uses: actions/checkout@v7
  109. - uses: actions/setup-go@v7
  110. with:
  111. go-version-file: go.mod
  112. cache: true
  113. - name: Stub internal/web/dist for go:embed
  114. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  115. - name: Install govulncheck
  116. run: go install golang.org/x/vuln/cmd/govulncheck@latest
  117. - name: Run govulncheck
  118. run: govulncheck ./...
  119. # Race + shuffle hygiene gate: data races and order-dependent tests fail the build.
  120. race:
  121. runs-on: ubuntu-latest
  122. steps:
  123. - uses: actions/checkout@v7
  124. - uses: actions/setup-go@v7
  125. with:
  126. go-version-file: go.mod
  127. cache: true
  128. - name: Stub internal/web/dist for go:embed
  129. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  130. - name: Race + shuffle
  131. run: |
  132. go list ./... | grep -v '/frontend/node_modules/' > /tmp/go-packages.txt
  133. # internal/web/service runs ~10x slower under -race and overruns the 10m default.
  134. go test -race -shuffle=on -count=1 -timeout 25m $(cat /tmp/go-packages.txt)
  135. # Brief native-fuzz smoke on the security-/parser-critical decoders. Each runs the
  136. # generated corpus plus 30s of exploration; a crash here is a real input-handling bug.
  137. fuzz-smoke:
  138. runs-on: ubuntu-latest
  139. steps:
  140. - uses: actions/checkout@v7
  141. - uses: actions/setup-go@v7
  142. with:
  143. go-version-file: go.mod
  144. cache: true
  145. - name: Stub internal/web/dist for go:embed
  146. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  147. - name: Fuzz critical parsers (smoke)
  148. run: |
  149. go test -run '^$' -fuzz 'FuzzParseLink$' -fuzztime=30s ./internal/util/link/
  150. go test -run '^$' -fuzz 'FuzzDecodeCertPin$' -fuzztime=30s ./internal/web/runtime/
  151. golangci:
  152. runs-on: ubuntu-latest
  153. steps:
  154. - uses: actions/checkout@v7
  155. - uses: actions/setup-go@v7
  156. with:
  157. go-version-file: go.mod
  158. cache: true
  159. - name: Stub internal/web/dist for go:embed
  160. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  161. - name: golangci-lint
  162. uses: golangci/golangci-lint-action@v9
  163. with:
  164. version: latest
  165. frontend:
  166. runs-on: ubuntu-latest
  167. steps:
  168. - uses: actions/checkout@v7
  169. - uses: actions/setup-node@v7
  170. with:
  171. node-version-file: .nvmrc
  172. cache: npm
  173. cache-dependency-path: frontend/package-lock.json
  174. - name: Install
  175. run: npm ci
  176. working-directory: frontend
  177. - name: Verify generated MSW worker is current
  178. run: git diff --exit-code -- public/mockServiceWorker.js package-lock.json
  179. working-directory: frontend
  180. - name: Lint
  181. run: npm run lint
  182. working-directory: frontend
  183. - name: Format check
  184. run: npm run format:check
  185. working-directory: frontend
  186. - name: Typecheck
  187. run: npm run typecheck
  188. working-directory: frontend
  189. - name: Install Playwright Chromium (Storybook story tests)
  190. run: npx playwright install --with-deps chromium
  191. working-directory: frontend
  192. - name: Test
  193. run: npm test
  194. working-directory: frontend
  195. - name: Build
  196. run: npm run build
  197. working-directory: frontend
  198. - name: Build Storybook
  199. run: npm run build-storybook
  200. working-directory: frontend
  201. - name: Audit
  202. run: npm audit --omit=dev --audit-level=high
  203. working-directory: frontend