Skip to content
Closed
Show file tree
Hide file tree
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
17 changes: 10 additions & 7 deletions .github/workflows/deploy-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ jobs:
exit 0
fi

if [ "$unit" != "success" ] || [ "$typecheck" != "success" ]; then
gh api "repos/$REPO/statuses/$SHA" --method POST \
--field state="failure" \
--field context="gate" \
--field description="Required checks did not pass (unit=$unit typecheck=$typecheck)"
exit 0
fi
# Treat "skipped" as passing (docs-only PRs skip code checks)
for v in "$unit" "$typecheck"; do
if [ "$v" != "success" ] && [ "$v" != "skipped" ]; then
gh api "repos/$REPO/statuses/$SHA" --method POST \
--field state="failure" \
--field context="gate" \
--field description="Required checks did not pass (unit=$unit typecheck=$typecheck)"
exit 0
fi
done

gh api "repos/$REPO/statuses/$SHA" --method POST \
--field state="success" \
Expand Down
30 changes: 22 additions & 8 deletions .github/workflows/lint-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,36 @@ name: Lint Code

on:
pull_request:
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'src-tauri/**'
- 'CHANGELOG.md'
- 'LICENSE'
- '.github/workflows/build-desktop.yml'
- '.github/workflows/docker-publish.yml'
push:
branches: [main]

permissions:
contents: read

jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
code: ${{ steps.diff.outputs.code }}
steps:
- id: diff
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "code=true" >> "$GITHUB_OUTPUT"
exit 0
fi
FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.number }}/files" \
--paginate --jq '.[].filename')
CODE=$(echo "$FILES" | grep -vcE '\.md$|^docs/|^src-tauri/|^CHANGELOG\.md$|^LICENSE$|\.github/workflows/(build-desktop|docker-publish)\.yml$' || echo 0)
echo "code=$( [ "$CODE" -gt 0 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"

biome:
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
30 changes: 22 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,36 @@ name: Test

on:
pull_request:
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'src-tauri/**'
- 'CHANGELOG.md'
- 'LICENSE'
- '.github/workflows/build-desktop.yml'
- '.github/workflows/docker-publish.yml'
push:
branches: [main]

permissions:
contents: read

jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
code: ${{ steps.diff.outputs.code }}
steps:
- id: diff
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "code=true" >> "$GITHUB_OUTPUT"
exit 0
fi
FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.number }}/files" \
--paginate --jq '.[].filename')
CODE=$(echo "$FILES" | grep -vcE '\.md$|^docs/|^src-tauri/|^CHANGELOG\.md$|^LICENSE$|\.github/workflows/(build-desktop|docker-publish)\.yml$' || echo 0)
echo "code=$( [ "$CODE" -gt 0 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"
Comment on lines +29 to +30
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 changes failure silently skips required checks

If the changes job fails (e.g. transient gh api rate-limit, network error, or a jq parse error), GitHub marks the downstream unit / typecheck / biome jobs as skipped because their needs: dependency did not succeed. The deploy-gate then sees unit=skipped and typecheck=skipped, treats both as passing, and posts a success gate status — effectively letting a broken code PR through without any test or type coverage.

Consider adding an explicit fallback that sets code=true on any API failure so the downstream jobs run rather than skip:

- id: diff
  env:
    GH_TOKEN: ${{ github.token }}
  run: |
    if [ "${{ github.event_name }}" = "push" ]; then
      echo "code=true" >> "$GITHUB_OUTPUT"
      exit 0
    fi
    FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.number }}/files" \
      --paginate --jq '.[].filename') || { echo "code=true" >> "$GITHUB_OUTPUT"; exit 0; }
    CODE=$(echo "$FILES" | grep -vcE '\.md$|^docs/|^src-tauri/|^CHANGELOG\.md$|^LICENSE$|\.github/workflows/(build-desktop|docker-publish)\.yml$' || echo 0)
    echo "code=$( [ "$CODE" -gt 0 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"

The same applies to the identical changes jobs in lint-code.yml and typecheck.yml.

Comment on lines +23 to +30
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Expression interpolation inside run: shell scripts

${{ github.event_name }}, ${{ github.repository }}, and ${{ github.event.number }} are interpolated directly into the shell script before execution. While all three are GitHub-controlled values (not user-supplied), this pattern is flagged by actionlint and GitHub's own security guidance because it bypasses shell quoting entirely. The preferred approach is to surface them as env: variables (as done for GH_TOKEN) and reference them as $VAR in the shell.

- id: diff
  env:
    GH_TOKEN: ${{ github.token }}
    EVENT_NAME: ${{ github.event_name }}
    GH_REPO: ${{ github.repository }}
    PR_NUMBER: ${{ github.event.number }}
  run: |
    if [ "$EVENT_NAME" = "push" ]; then
      echo "code=true" >> "$GITHUB_OUTPUT"
      exit 0
    fi
    FILES=$(gh api "repos/$GH_REPO/pulls/$PR_NUMBER/files" \
      --paginate --jq '.[].filename')
    CODE=$(echo "$FILES" | grep -vcE '\.md$|^docs/|^src-tauri/|^CHANGELOG\.md$|^LICENSE$|\.github/workflows/(build-desktop|docker-publish)\.yml$' || echo 0)
    echo "code=$( [ "$CODE" -gt 0 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"

The same pattern appears in lint-code.yml (lines 23-30) and typecheck.yml (lines 23-30).

unit:
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
31 changes: 22 additions & 9 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,37 @@ name: Typecheck

on:
pull_request:
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'src-tauri/**'
- 'CHANGELOG.md'
- 'LICENSE'
- '.github/workflows/build-desktop.yml'
- '.github/workflows/docker-publish.yml'
push:
branches: [main]

permissions:
contents: read

jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
code: ${{ steps.diff.outputs.code }}
steps:
- id: diff
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "push" ]; then
echo "code=true" >> "$GITHUB_OUTPUT"
exit 0
fi
FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.number }}/files" \
--paginate --jq '.[].filename')
CODE=$(echo "$FILES" | grep -vcE '\.md$|^docs/|^src-tauri/|^CHANGELOG\.md$|^LICENSE$|\.github/workflows/(build-desktop|docker-publish)\.yml$' || echo 0)
echo "code=$( [ "$CODE" -gt 0 ] && echo true || echo false )" >> "$GITHUB_OUTPUT"

typecheck:
# No secrets needed — run for all PRs including forks

needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
Expand Down
Loading