diff --git a/.github/workflows/gh-ci-fix-command.yml b/.github/workflows/gh-ci-fix-command.yml new file mode 100644 index 00000000..0fcd723b --- /dev/null +++ b/.github/workflows/gh-ci-fix-command.yml @@ -0,0 +1,43 @@ +name: On-Demand GitHub Actions Pin Fix + +on: + workflow_dispatch: + inputs: + pr: + description: 'PR Number' + type: string + required: true + comment-id: + description: 'Comment ID (Optional)' + type: string + required: false + +permissions: + contents: write + workflows: write + pull-requests: write + +env: + AIRBYTE_ANALYTICS_ID: ${{ vars.AIRBYTE_ANALYTICS_ID }} + +jobs: + gh-ci-fix: + name: Pin GitHub Actions + runs-on: ubuntu-latest + steps: + - name: Authenticate as GitHub App + uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2.1.4 + id: get-app-token + with: + owner: "airbytehq" + repositories: "PyAirbyte" + app-id: ${{ secrets.OCTAVIA_BOT_APP_ID }} + private-key: ${{ secrets.OCTAVIA_BOT_PRIVATE_KEY }} + + - name: Run Poe Command + uses: aaronsteers/poe-command-processor@04330aa7047b6b182ff280a962cbbcd99d6eb683 # v1.3.0 + with: + command: "gh-ci-fix" + github-token: ${{ steps.get-app-token.outputs.token }} + pr: ${{ github.event.inputs.pr }} + comment-id: ${{ github.event.inputs.comment-id }} diff --git a/.github/workflows/slash_command_dispatch.yml b/.github/workflows/slash_command_dispatch.yml index 5209d9a5..37d49f6f 100644 --- a/.github/workflows/slash_command_dispatch.yml +++ b/.github/workflows/slash_command_dispatch.yml @@ -34,6 +34,7 @@ jobs: fix-pr test-pr poetry-lock + gh-ci-fix static-args: | pr=${{ github.event.issue.number }} comment-id=${{ github.event.comment.id }} diff --git a/.github/workflows/validate-pinned-actions.yml b/.github/workflows/validate-pinned-actions.yml new file mode 100644 index 00000000..6e41ce84 --- /dev/null +++ b/.github/workflows/validate-pinned-actions.yml @@ -0,0 +1,51 @@ +name: Validate Pinned Actions + +on: + pull_request: + paths: + - '.github/workflows/**' + - '**/action.yml' + - '**/action.yaml' + +permissions: + contents: read + pull-requests: write + +jobs: + validate-pinned-actions: + name: Validate Actions are SHA-pinned + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + + - name: Set up Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.10' + + - name: Set up Poetry + uses: Gr1N/setup-poetry@48b0f77c8c1b1b19cb962f0f00dff7b4be8f81ec # v9 + with: + poetry-version: "2.2.0" + + - name: Install dependencies + run: poetry install + + - name: Install pinact CLI + run: | + go install github.com/suzuki-shunsuke/pinact/cmd/pinact@latest + + - name: Validate all actions are pinned + run: | + if ! poetry run poe gh-ci-check; then + echo "❌ Some GitHub Actions are not pinned to SHA hashes!" + echo "" + echo "To fix this, use the slash command '/gh-ci-fix' on this PR." + echo "" + echo "Or run locally:" + echo " poetry run poe gh-ci-fix" + exit 1 + else + echo "✅ All GitHub Actions are properly pinned to SHA hashes." + fi diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 3def3762..202d72f4 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -72,6 +72,21 @@ This repo uses a policy of SHA-pinning GitHub Actions, for hardened security. To pin your GitHub actions, you can use the [pinact](https://github.com/suzuki-shunsuke/pinact) tool: ```bash +# Install pinact CLI tool +go install github.com/suzuki-shunsuke/pinact/cmd/pinact@latest + +# Pin all GitHub Actions in workflow files +pinact run + +# Pin actions in a specific file +pinact run .github/workflows/python_lint.yml + +# Check if actions are pinned (dry-run) +pinact run --dry-run +``` + +You can also use the `/gh-ci-fix` slash command on pull requests to automatically pin actions. + # Convert from from fixed version to sha # Example: actions/checkout@v4 -> actions/checkout@08e... # v4.3.0 pinact run [optional_file] diff --git a/pyproject.toml b/pyproject.toml index d5e3d282..2c160cd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -199,6 +199,11 @@ fix = { shell = "ruff format . && ruff check --fix -s || ruff format ." } fix-unsafe = { shell = "ruff format . && ruff check --fix --unsafe-fixes . && ruff format ." } fix-and-check = { shell = "poe fix && poe check" } +# GitHub Actions CI tasks +install = { shell = "poetry install" } +gh-ci-check = { shell = "$HOME/go/bin/pinact run --check", help = "Check if GitHub Actions are pinned to SHA hashes" } +gh-ci-fix = { shell = "$HOME/go/bin/pinact run", help = "Pin GitHub Actions to their SHA hashes" } + # MCP Server Tasks mcp-serve-local = { cmd = "poetry run airbyte-mcp", help = "Start the MCP server with STDIO transport" } mcp-serve-http = { cmd = "poetry run python -c \"from airbyte.mcp.server import app; app.run(transport='http', host='127.0.0.1', port=8000)\"", help = "Start the MCP server with HTTP transport" }