diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index 24e5b776..da494e23 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -4,14 +4,14 @@ runs: using: "composite" steps: - name: Cache Bun - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }} restore-keys: ${{ runner.os }}-bun- path: ~/.bun - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version-file: package.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..a6d83453 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" + - "github_actions" + groups: + actions: + patterns: + - "*" diff --git a/.github/renovate.json b/.github/renovate.json deleted file mode 100644 index 257f6176..00000000 --- a/.github/renovate.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended", - ":semanticCommits", - ":dependencyDashboard", - "helpers:pinGitHubActionDigests", - "group:allNonMajor" - ], - "schedule": ["before 6am on monday"], - "labels": ["dependencies"], - "rangeStrategy": "bump", - "lockFileMaintenance": { - "enabled": true, - "schedule": ["before 6am on monday"] - }, - "packageRules": [ - { - "description": "Auto-merge non-major dev dependency updates", - "matchDepTypes": ["devDependencies"], - "matchUpdateTypes": ["minor", "patch"], - "automerge": true - }, - { - "description": "Auto-merge GitHub Action digest pins and updates", - "matchManagers": ["github-actions"], - "matchUpdateTypes": ["pin", "digest", "minor", "patch"], - "automerge": true, - "commitMessagePrefix": "chore(ci):" - } - ] -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1871124..0d6a06b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,16 +17,18 @@ jobs: typecheck: name: Typecheck runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: ./.github/actions/setup-bun - run: bun run typecheck test: name: Test runs-on: ubuntu-latest + timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: ./.github/actions/setup-bun - name: Configure git for tests run: | @@ -38,17 +40,64 @@ jobs: build: name: Build (web) runs-on: ubuntu-latest + timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - uses: ./.github/actions/setup-bun - name: Build workspace UI run: bun run --cwd frontend/workspace build - name: Build docs site run: bun run --cwd frontend/docs build + # frontend/landing is standalone (own lockfile, not a workspace member), + # so the root typecheck/build jobs never touch it. + landing: + name: Build (landing) + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: ./.github/actions/setup-bun + - name: Install + working-directory: frontend/landing + run: bun install --frozen-lockfile + - name: Typecheck + working-directory: frontend/landing + run: bunx tsc -b + - name: Build + working-directory: frontend/landing + run: bun run build + + # Packages with no typecheck task and scripts that otherwise only ever + # execute during a release — catch syntax errors before release day. + smoke: + name: Smoke (launcher + scripts) + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: ./.github/actions/setup-bun + - name: Launcher parses + run: node --check tooling/launcher/bin/synsci.mjs + - name: npm bin wrapper parses + run: node --check backend/cli/bin/openscience + - name: Install script parses + run: bash -n install && bash -n frontend/landing/public/install + - name: Install script copies are in sync + run: diff -q install frontend/landing/public/install + - name: Release scripts parse + # transpile-only: bundling would follow imports into third-party + # packages with exports quirks (giget via node-fetch-native) + run: | + for f in tooling/repo/*.ts; do + bun -e "new Bun.Transpiler({ loader: 'ts' }).transformSync(await Bun.file('$f').text())" + echo "OK $f" + done + actionlint: name: Lint workflows runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@v4 - - uses: raven-actions/actionlint@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e3a851d9..02f24972 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -8,6 +8,10 @@ on: schedule: - cron: "30 5 * * 1" +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + permissions: contents: read @@ -15,6 +19,7 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + timeout-minutes: 30 permissions: security-events: write actions: read @@ -24,12 +29,12 @@ jobs: matrix: language: ["javascript-typescript"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3 with: languages: ${{ matrix.language }} - name: Analyze - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 77f7372d..0c7cfc3b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -2,6 +2,10 @@ name: E2E on: workflow_dispatch: + # Nightly rather than per-PR: the suite is long and browser-heavy. Promote + # to a PR trigger once it has a green track record. + schedule: + - cron: "17 3 * * *" permissions: contents: read @@ -27,12 +31,13 @@ jobs: # PR with full audit context (see commits b47b779/d7ad855/ # 21aae5d/6a9dcd0/0f1d7c1 for the diagnosis chain). runs-on: ${{ matrix.settings.host }} + timeout-minutes: 60 defaults: run: shell: bash steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -155,7 +160,7 @@ jobs: - name: Upload Playwright artifacts if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: playwright-${{ matrix.settings.name }}-${{ github.run_attempt }} if-no-files-found: ignore diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml index 726513ce..2024d3ff 100644 --- a/.github/workflows/gitleaks.yml +++ b/.github/workflows/gitleaks.yml @@ -6,24 +6,36 @@ on: pull_request: workflow_dispatch: +concurrency: + group: gitleaks-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + permissions: contents: read env: GITLEAKS_VERSION: 8.30.1 + # sha256 of gitleaks_8.30.1_linux_x64.tar.gz, from the release's checksums.txt + GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb jobs: gitleaks: name: Gitleaks runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - name: Install gitleaks run: | - curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ - | tar -xz gitleaks + curl -sSL -o gitleaks.tar.gz "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" + echo "${GITLEAKS_SHA256} gitleaks.tar.gz" | sha256sum -c - + tar -xzf gitleaks.tar.gz gitleaks sudo install gitleaks /usr/local/bin/gitleaks - - name: Scan + - name: Scan working tree run: gitleaks dir . --redact --exit-code 1 + # `dir` only sees the checkout; a secret committed and later deleted + # passes it forever. `git` mode scans the full fetched history. + - name: Scan git history + run: gitleaks git . --redact --exit-code 1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3bd9aa99..5a654432 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -28,6 +28,7 @@ permissions: jobs: version: runs-on: ubuntu-latest + timeout-minutes: 15 if: github.repository == 'synthetic-sciences/OpenScience' steps: - name: Require a bump or version input @@ -36,7 +37,7 @@ jobs: echo "::error::Provide 'bump' or 'version'. An empty dispatch would publish a 0.0.0-main preview to npm as if it were a release." exit 1 - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 @@ -56,8 +57,9 @@ jobs: build-cli: needs: version runs-on: ubuntu-latest + timeout-minutes: 90 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-tags: true @@ -71,7 +73,7 @@ jobs: GH_TOKEN: ${{ github.token }} - name: Cache CLI build - uses: actions/cache/save@v4 + uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: backend/cli/dist key: cli-build-${{ github.run_id }} @@ -84,14 +86,15 @@ jobs: - version - build-cli runs-on: ubuntu-latest + timeout-minutes: 60 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - uses: ./.github/actions/setup-bun - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "24" registry-url: "https://registry.npmjs.org" @@ -102,7 +105,7 @@ jobs: git config user.name "openscience" - name: Restore CLI build - uses: actions/cache/restore@v4 + uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: backend/cli/dist key: cli-build-${{ github.run_id }} @@ -130,10 +133,11 @@ jobs: # Previews (no release output) shouldn't create a production deployment. if: needs.version.outputs.release != '' runs-on: ubuntu-latest + timeout-minutes: 10 permissions: deployments: write steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: VERSION: ${{ needs.version.outputs.version }} TAG: ${{ needs.version.outputs.tag }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index d54cb66f..5a610cca 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -13,26 +13,27 @@ jobs: analysis: name: Scorecard analysis runs-on: ubuntu-latest + timeout-minutes: 15 permissions: security-events: write id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@v2.4.3 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif publish_results: true - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: SARIF file path: results.sarif retention-days: 5 - name: Upload to code scanning - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@411c4c9a36b3fca4d674f06b6396b2c6d23522c6 # v3 with: sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index da3f5e69..4ef07a42 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,8 +12,9 @@ permissions: jobs: stale: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/stale@v10 + - uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10 with: days-before-stale: 90 days-before-close: 7