Skip to content
Closed
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
123 changes: 98 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,67 @@ on:
push:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
changes:
frontend-ci:
runs-on: ubuntu-latest
outputs:
backend: ${{ steps.filter.outputs.backend }}
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- 'backend/**'
- 'go.work'
- 'go.work.sum'
app:
- 'app/**'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [high] frontend-ci: paths-filter の出力を参照する前に checkout が不足している可能性がある (実際は別の問題: 後続ステップの if 条件が filter 結果を使うが filter ステップ自体は常に実行される設計は問題なし。ただし working-directory 未設定で npm コマンドが正しいディレクトリで動かない)

frontend-ci ジョブ内の npm ci / npm run lint / npx tsc 等の各ステップに working-directory が指定されていない。

タスク仕様には「frontend files are under app/」とあり、リポジトリがモノレポ構成であればフロントエンドのルート (app/frontend/ など) に package.json が存在する可能性が高い。working-directory なしでは npm ci がリポジトリルートの package.json を参照し、存在しない場合は CI が即失敗する。

該当箇所:

      - name: Install dependencies
        if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
        run: npm ci

      - name: Lint
        if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
        run: npm run lint

backend-ci ジョブには defaults.run.working-directory: backend が設定されており、frontend-ci にも同等の設定が必要。

@@ -10,6 +10,9 @@
   frontend-ci:
     runs-on: ubuntu-latest
     timeout-minutes: 20
+    defaults:
+      run:
+        working-directory: app
     steps:

code.ci.path_filter_step_ordering | confidence: 0.72

- 'components/**'
- 'lib/**'
- 'middleware.ts'
- 'next.config.mjs'
- 'package.json'
- 'tsconfig.json'
- 'vitest.config.ts'
- '*.ts'
- '*.tsx'

- uses: actions/setup-node@v4
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
with:
node-version: 20

- uses: actions/cache@v4
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

- name: Install dependencies
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
run: npm ci

backend:
needs: changes
if: needs.changes.outputs.backend == 'true'
- name: Lint
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
run: npm run lint

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [high] frontend-ci ジョブにジョブレベルの if: がなく、パス変更がない場合でも常に起動する

パスフィルタ (dorny/paths-filter@v3) の結果を各ステップの if: で参照しているが、ジョブ自体は無条件に起動する。そのため、checkoutpaths-filter は常に実行され、フィルタが false を返した場合も残りのステップがスキップされるだけでジョブは「成功」として終了する。

  frontend-ci:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4

      - uses: dorny/paths-filter@v3
        id: filter
        ...

      - uses: actions/setup-node@v4
        if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'

これ自体は動作するが、backend-ci も同様のパターンを取っており、PR のたびに両ジョブが必ず起動する。旧 CI の changes ジョブパターン(needs: + ジョブレベル if:)の方が GitHub Actions の課金・並列実行スロットの観点で効率的。少なくとも backend-ciworking-directory: backend と step レベル if: の組み合わせは、go vet 等が ~/go/pkg/mod のキャッシュより先に実行された場合でも問題ないか確認が必要。

code.ci.paths_filter_no_if_condition_job_level | confidence: 0.80

- name: Typecheck
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
run: npx tsc --noEmit

- name: Test
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
run: npx vitest run

- name: Build
if: steps.filter.outputs.app == 'true' || github.ref == 'refs/heads/main'
run: npm run build

backend-ci:
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: backend
Expand All @@ -41,34 +82,66 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
backend:
- 'backend/**'
- '.golangci.yml'
- 'go.work'
- 'go.work.sum'

- uses: actions/setup-go@v5
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
with:
go-version: '1.25'
go-version: '1.24'

- uses: actions/cache@v4
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}

- name: Download dependencies
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
run: go mod download

- name: Run SQLite unit tests
run: go test ./... -count=1 -timeout 60s

- name: Run PostgreSQL integration tests
run: go test -tags integration ./internal/infrastructure/... -count=1 -timeout 120s
env:
DB_TYPE: postgres
DB_DSN: postgres://postgres:postgres@localhost:5432/testdb?sslmode=disable
- name: Vet
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
run: go vet ./...

- name: golangci-lint
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
uses: golangci/golangci-lint-action@v6
with:
version: v2.1
working-directory: backend
args: --timeout=5m

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [high] Go バージョンが 1.25 から 1.24 にダウングレードされた

旧設定では go-version: '1.25' だったが、新設定では go-version: '1.24' に変更されている。

      - uses: actions/setup-go@v5
        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
        with:
          go-version: '1.24'

リポジトリの go.work / go.modgo 1.25 を要求している場合、go buildgo test が "toolchain" 制約エラーで失敗する。意図的なダウングレードであれば go.mod 側も合わせて変更する必要がある。

code.ci.go_version_downgrade | confidence: 0.88

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [high] go-version: '1.25' は 2024 年時点で存在しない Go バージョンであり、セットアップが失敗する

旧 CI から引き継いだ go-version: '1.25' がそのまま残っている。

      - uses: actions/setup-go@v5
        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
        with:
          go-version: '1.25'

タスク要件では go-version: '1.24' と明記されている。1.25 は現時点では未リリースであるため actions/setup-go がエラーを返し、backend-ci ジョブ全体が失敗する。'1.24' に修正すること。

@@ -110,3 +110,3 @@
         with:
-          go-version: '1.25'
+          go-version: '1.24'

code.ci.go_version_nonexistent | confidence: 0.92

- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage
path: backend/coverage.out
- name: Test with race detector
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [high] 外部スクリプトのパイプ実行による Supply Chain Attack リスク

CWE-829: Inclusion of Functionality from Untrusted Control Sphere

該当箇所:

run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.62.0

master ブランチの最新スクリプトを curl | sh で直接実行しています。master ブランチの内容が攻撃者によって改ざんされた場合(または一時的にでも書き換えられた場合)、任意コードがランナー上で実行されます。

また、$(go env GOPATH) のコマンド置換が run: シェル内で展開されるため、環境変数の操作で挿入が可能な点も懸念されます(GitHub Actions のランナー環境では現実的リスクは低いですが)。

推奨対応:

  • curl | sh パターンを避け、公式の golangci/golangci-lint-action@v6 を使用する
  • または、チェックサムを検証してからインストールする
  • スクリプト URL を master ではなくコミットハッシュで固定する
      - name: golangci-lint
        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
        uses: golangci/golangci-lint-action@v6
        with:
          version: v1.62.0
          working-directory: backend
          args: --timeout=5m

sec.sast.injection.script | confidence: 0.90

run: go test -race -coverprofile=coverage.out -covermode=atomic ./...

- name: Run PostgreSQL integration tests
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
run: go test -tags integration ./internal/infrastructure/... -count=1 -timeout 120s
env:
DB_TYPE: postgres
DB_DSN: postgres://postgres:postgres@localhost:5432/testdb?sslmode=disable

- name: Check coverage threshold
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 [critical] golangci-lint を curl | sh でインストールしている — 公式 action を削除した回帰

削除前は golangci/golangci-lint-action@v6 を使用していたが、新コードでは curl パイプインストールに退行している。

      - name: Install golangci-lint
        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
        run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.62.0

問題点:

  1. master ブランチのスクリプトを毎回フェッチするためスクリプト自体が変更される可能性がある (再現性の欠如)
  2. golangci-lint-action はキャッシュ・バイナリ検証・GitHub Annotations 連携を提供するが、手動インストールではこれらが失われる
  3. v1.62.0 と v2.1 (旧設定) は ABI/設定ファイル互換性が異なり、.golangci.yml が v2 向けに書かれている場合は v1.62.0 で設定パースエラーになる
@@ -110,5 +110,6 @@
-      - name: Install golangci-lint
-        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
-        run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.62.0
-
-      - name: golangci-lint
-        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
-        run: golangci-lint run ./... --timeout=5m
+      - name: golangci-lint
+        if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
+        uses: golangci/golangci-lint-action@v6
+        with:
+          version: v1.62.0
+          args: --timeout=5m

code.ci.curl_pipe_sh | confidence: 0.92

run: |
total=$(go tool cover -func=coverage.out | awk '/^total:/ {gsub(/%/,"",$3); print $3}')
awk -v total="$total" 'BEGIN { exit (total >= 60 ? 0 : 1) }' || {
echo "Coverage ${total}% below 60% threshold"
exit 1
}

- name: Build
if: steps.filter.outputs.backend == 'true' || github.ref == 'refs/heads/main'
run: go build ./cmd/server

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛑 [blocker] compat-tests および validate-dashboards ジョブが完全に削除されている

旧 CI に存在した以下の 2 ジョブが diff で丸ごと削除されており、今回の変更後は実行されない:

-  compat-tests:
-    runs-on: ubuntu-latest
-    steps:
-      ...
-      - name: Run compatibility tests
-        run: cd backend && go test ./internal/compat/... -v ...
-  validate-dashboards:
-    runs-on: ubuntu-latest
-    steps:
-      ...
-      - run: node -e "...grafana dashboard validation..."

タスク要件 (PR 本文) には compat-tests / validate-dashboards を削除してよいという記載がなく、これらは既存の品質保証の一部であった。意図的な削除であれば PR 説明に明記し、代替手段を提示すべき。

code.ci.removed_compat_tests | confidence: 0.92


compat-tests:
runs-on: ubuntu-latest
Expand All @@ -77,7 +150,7 @@ jobs:

- uses: actions/setup-go@v5
with:
go-version: '1.25'
go-version: '1.24'

- name: Run compatibility tests
run: cd backend && go test ./internal/compat/... -v -count=1 -timeout 120s 2>&1 | tee compat-results.txt
Expand Down
Loading