diff --git a/.github/workflows/ci-infra.yml b/.github/workflows/ci-infra.yml index 956e8c35e9..23ad533bcc 100644 --- a/.github/workflows/ci-infra.yml +++ b/.github/workflows/ci-infra.yml @@ -272,3 +272,127 @@ jobs: - name: Run npm audit run: npm audit --audit-level=moderate continue-on-error: true + + # --------------------------------------------------------------------------- + # smalruby-classroom + # --------------------------------------------------------------------------- + smalruby-classroom-unit-tests: + name: "[classroom] Unit Tests" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-classroom + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-classroom/.node-version + cache: npm + cache-dependency-path: infra/smalruby-classroom/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run unit tests + run: npm test + + smalruby-classroom-cdk-build: + name: "[classroom] CDK Build & Synth" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-classroom + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-classroom/.node-version + cache: npm + cache-dependency-path: infra/smalruby-classroom/package-lock.json + - name: Install dependencies + run: npm ci + - name: Build TypeScript + run: npm run build + - name: Synthesize CDK stack + env: + CLASSROOM_CUSTOM_DOMAIN: 'false' + run: npx cdk synth --context stage=stg + + smalruby-classroom-security: + name: "[classroom] Security Audit" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-classroom + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-classroom/.node-version + cache: npm + cache-dependency-path: infra/smalruby-classroom/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run npm audit + run: npm audit --audit-level=moderate + continue-on-error: true + + # --------------------------------------------------------------------------- + # smalruby-admin + # --------------------------------------------------------------------------- + smalruby-admin-unit-tests: + name: "[admin] Unit Tests" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-admin + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-admin/.node-version + cache: npm + cache-dependency-path: infra/smalruby-admin/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run unit tests + run: npm test + + smalruby-admin-cdk-build: + name: "[admin] CDK Build & Synth" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-admin + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-admin/.node-version + cache: npm + cache-dependency-path: infra/smalruby-admin/package-lock.json + - name: Install dependencies + run: npm ci + - name: Build TypeScript + run: npm run build + - name: Synthesize CDK stack + env: + ADMIN_CUSTOM_DOMAIN: 'false' + run: npx cdk synth --context stage=stg + + smalruby-admin-security: + name: "[admin] Security Audit" + runs-on: ubuntu-latest + defaults: + run: + working-directory: infra/smalruby-admin + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6 + with: + node-version-file: infra/smalruby-admin/.node-version + cache: npm + cache-dependency-path: infra/smalruby-admin/package-lock.json + - name: Install dependencies + run: npm ci + - name: Run npm audit + run: npm audit --audit-level=moderate + continue-on-error: true diff --git a/infra/smalruby-admin/.node-version b/infra/smalruby-admin/.node-version new file mode 100644 index 0000000000..b404027604 --- /dev/null +++ b/infra/smalruby-admin/.node-version @@ -0,0 +1 @@ +24.8.0 diff --git a/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts b/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts index c206038ff4..498cd64c22 100644 --- a/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler-notifications.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * お知らせ送信 API tests — EPIC #1111. * diff --git a/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts b/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts index 519ad75d1a..8fd140422e 100644 --- a/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler-recommend-sharing.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * 共有推奨 API tests — EPIC #1106. * diff --git a/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts b/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts index ded1c59009..fc18dea623 100644 --- a/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler-shared-recommendation.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * Admin 推薦 API tests — EPIC #1110. * diff --git a/infra/smalruby-admin/lambda/tests/handler.test.ts b/infra/smalruby-admin/lambda/tests/handler.test.ts index d9cf8f3fdf..fd887e2033 100644 --- a/infra/smalruby-admin/lambda/tests/handler.test.ts +++ b/infra/smalruby-admin/lambda/tests/handler.test.ts @@ -1,3 +1,7 @@ +// このファイルをモジュールにするための宣言。import/export を持たない .ts は TypeScript の +// グローバルスクリプト扱いになり、トップレベルの const がテストファイル間で衝突する(#1144)。 +export {}; + /** * Admin API authorization tests (EPIC #1073, S1 #1081). * diff --git a/infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts b/infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts new file mode 100644 index 0000000000..f0e0b3df85 --- /dev/null +++ b/infra/smalruby-admin/lambda/tests/test-files-are-modules.test.ts @@ -0,0 +1,45 @@ +/** + * テストファイルがモジュールであることを担保する回帰テスト (issue #1144)。admin も同じ構造だったため CI 追加時に検出した (#1155)。 + * + * `import` / `export` を 1 つも持たない .ts ファイルは TypeScript では「モジュール」ではなく + * グローバルスクリプトとして扱われる。その場合トップレベルの const がファイルを跨いで同じ + * スコープに宣言されるため、`mockSend` のような同名の変数を別ファイルで宣言した瞬間に + * TS2451 (Cannot redeclare block-scoped variable) になる。ts-jest はキャッシュが温かい間は + * 型チェックを再利用するので、この診断は cold cache のときだけ suite ごと落ちる = フレークに + * 見えていた。 + */ +import * as fs from 'fs'; +import * as path from 'path'; +import * as ts from 'typescript'; + +const testsDir = __dirname; + +const collectTsFiles = (dir: string): string[] => + fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) return collectTsFiles(full); + return entry.isFile() && full.endsWith('.ts') ? [full] : []; + }); + +describe('lambda/tests の .ts ファイル', () => { + const files = collectTsFiles(testsDir); + + test('検査対象のファイルが見つかる', () => { + expect(files.length).toBeGreaterThan(0); + }); + + test.each(files.map((file) => [path.relative(testsDir, file), file]))( + '%s はモジュール (import/export を持つ) である', + (_relative, file) => { + const source = ts.createSourceFile( + file, + fs.readFileSync(file, 'utf8'), + ts.ScriptTarget.ES2020, + /* setParentNodes */ false, + ts.ScriptKind.TS, + ); + + expect(ts.isExternalModule(source)).toBe(true); + }, + ); +}); diff --git a/infra/smalruby-classroom/.node-version b/infra/smalruby-classroom/.node-version new file mode 100644 index 0000000000..b404027604 --- /dev/null +++ b/infra/smalruby-classroom/.node-version @@ -0,0 +1 @@ +24.8.0