ci.yml 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. go test -race -shuffle=on -count=1 $(cat /tmp/go-packages.txt)
  134. # Brief native-fuzz smoke on the security-/parser-critical decoders. Each runs the
  135. # generated corpus plus 30s of exploration; a crash here is a real input-handling bug.
  136. fuzz-smoke:
  137. runs-on: ubuntu-latest
  138. steps:
  139. - uses: actions/checkout@v7
  140. - uses: actions/setup-go@v7
  141. with:
  142. go-version-file: go.mod
  143. cache: true
  144. - name: Stub internal/web/dist for go:embed
  145. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  146. - name: Fuzz critical parsers (smoke)
  147. run: |
  148. go test -run '^$' -fuzz 'FuzzParseLink$' -fuzztime=30s ./internal/util/link/
  149. go test -run '^$' -fuzz 'FuzzDecodeCertPin$' -fuzztime=30s ./internal/web/runtime/
  150. golangci:
  151. runs-on: ubuntu-latest
  152. steps:
  153. - uses: actions/checkout@v7
  154. - uses: actions/setup-go@v7
  155. with:
  156. go-version-file: go.mod
  157. cache: true
  158. - name: Stub internal/web/dist for go:embed
  159. run: mkdir -p internal/web/dist && touch internal/web/dist/.gitkeep
  160. - name: golangci-lint
  161. uses: golangci/golangci-lint-action@v9
  162. with:
  163. version: latest
  164. frontend:
  165. runs-on: ubuntu-latest
  166. steps:
  167. - uses: actions/checkout@v7
  168. - uses: actions/setup-node@v7
  169. with:
  170. node-version-file: .nvmrc
  171. cache: npm
  172. cache-dependency-path: frontend/package-lock.json
  173. - name: Install
  174. run: npm ci
  175. working-directory: frontend
  176. - name: Verify generated MSW worker is current
  177. run: git diff --exit-code -- public/mockServiceWorker.js package-lock.json
  178. working-directory: frontend
  179. - name: Lint
  180. run: npm run lint
  181. working-directory: frontend
  182. - name: Format check
  183. run: npm run format:check
  184. working-directory: frontend
  185. - name: Typecheck
  186. run: npm run typecheck
  187. working-directory: frontend
  188. - name: Install Playwright Chromium (Storybook story tests)
  189. run: npx playwright install --with-deps chromium
  190. working-directory: frontend
  191. - name: Test
  192. run: npm test
  193. working-directory: frontend
  194. - name: Build
  195. run: npm run build
  196. working-directory: frontend
  197. - name: Build Storybook
  198. run: npm run build-storybook
  199. working-directory: frontend
  200. - name: Audit
  201. run: npm audit --omit=dev --audit-level=high
  202. working-directory: frontend