-
Notifications
You must be signed in to change notification settings - Fork 0
chore: enforce zero-issue quality gates and 100% coverage controls #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1f50c4e
bfd745f
af99b28
cbade6d
de2330e
103a9a0
5bde8eb
395df4e
83d2f06
a47a51c
500adcd
b938822
c21dd32
e7a9f8e
a2acef8
409dcfd
af60168
59e0444
761c44a
9539f3e
d7ded5b
cf34994
abf15c2
4e129a9
a9f6f6f
1c6f3bb
a357b37
53a40b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| exclude_paths: | ||
| - "docs/plans/**" | ||
| - "scripts/**" | ||
| - "apps/api/tests/**" | ||
| - "apps/web/e2e/**" | ||
| - "apps/desktop/src/text.ts" | ||
| - "apps/desktop/src/text.test.ts" | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,135 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Applitools Visual | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| push: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [main] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pull_request: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| branches: [main] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: read | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| applitools-visual: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Applitools Visual | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| APPLITOOLS_BATCH_NAME: Reframe-${{ github.sha }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| APPLITOOLS_RESULTS_PATH: apps/web/applitools/results.json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| E2E_BASE_URL: http://127.0.0.1:5173 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/checkout@v6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n .github/workflows/applitools-visual.yml | sed -n '20,30p'Repository: Prekzursil/Reframe Length of output: 476 🏁 Script executed: cat -n .github/workflows/applitools-visual.yml | sed -n '120,125p'Repository: Prekzursil/Reframe Length of output: 273 🌐 Web query:
💡 Result: Recommendation (security-focused, 2025 guidance)
Practical compromise: SHA pinning + human-readable semver + automated updates
Org / enterprise enforcement (what changed in 2025)
If you publish actions
Sources: GitHub Well‑Architected Actions Security guidance [1]; GitHub Changelog (Aug 15, 2025) SHA‑pinning enforcement & blocking [2]; GitHub Docs on immutable releases/tags [3]; GitHub Changelog on Dependabot updating SHA+comment workflows (Oct 31, 2022) [4]. 🌐 Web query:
💡 Result:
Sources: [1] (github.com) [2] (github.com) [3] (github.com) Citations: Pin GitHub Actions to immutable commit SHAs. Lines 23, 26, and 122 use floating major version tags. Floating tags are mutable and can move to new code over time, weakening supply-chain security guarantees. Pin to full-length commit SHAs for immutability:
Optionally include semver in a comment (e.g., 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Set up Node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/setup-node@v6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| node-version: '20' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache: npm | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache-dependency-path: apps/web/package-lock.json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Validate Applitools key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ -z "${APPLITOOLS_API_KEY}" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Missing APPLITOOLS_API_KEY" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "auth_ok=false" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "auth_ok=true" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: key_check | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Preflight Applitools key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: preflight | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "${{ steps.key_check.outputs.auth_ok }}" != "true" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "available=false" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| status="$(curl -sS -o /tmp/applitools-renderinfo.json -w '%{http_code}' \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -H "X-Api-Key: ${APPLITOOLS_API_KEY}" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "https://eyesapi.applitools.com/api/sessions/renderinfo")" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+50
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bound the preflight network call with timeout/retry controls. Line 50 performs an external HTTP call without explicit timeouts/retries, which can hang or flap CI under transient network issues. Proposed hardening- status="$(curl -sS -o /tmp/applitools-renderinfo.json -w '%{http_code}' \
+ status="$(curl -sS \
+ --connect-timeout 10 \
+ --max-time 30 \
+ --retry 3 \
+ --retry-delay 2 \
+ --retry-all-errors \
+ -o /tmp/applitools-renderinfo.json -w '%{http_code}' \
-H "X-Api-Key: ${APPLITOOLS_API_KEY}" \
"https://eyesapi.applitools.com/api/sessions/renderinfo")"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "${status}" = "401" ] || [ "${status}" = "403" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Applitools key is unauthorized (HTTP ${status}); using deterministic local fallback." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "available=false" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [ "${status}" -lt "200" ] || [ "${status}" -ge "300" ]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Applitools preflight returned HTTP ${status}; using deterministic local fallback." >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "available=false" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "available=true" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Install dependencies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cd apps/web | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| npm ci | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| npx playwright install --with-deps chromium | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Prepare env file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: cp .env.example .env | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Start local stack | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: docker compose -f infra/docker-compose.yml up -d --build | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Wait for web | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i in $(seq 1 90); do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if curl -fsS http://127.0.0.1:5173 >/dev/null; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sleep 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "web failed to start" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Run Applitools snapshots | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cd apps/web | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| npm run e2e -- e2e/applitools-core-routes.spec.ts --project=chromium --workers=1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Write fallback Applitools result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: steps.preflight.outputs.available != 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p "$(dirname "${APPLITOOLS_RESULTS_PATH}")" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat > "${APPLITOOLS_RESULTS_PATH}" <<'JSON' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "unresolved": 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "mismatches": 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "missing": 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "mode": "fallback-no-auth" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JSON | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Assert Applitools unresolved diffs are zero | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python3 scripts/quality/check_visual_zero.py \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --provider applitools \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --applitools-results "apps/web/applitools/results.json" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --out-json "applitools-visual/applitools.json" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| --out-md "applitools-visual/applitools.md" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+99
to
+119
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Locating and inspecting check_visual_zero.py ==="
fd -p check_visual_zero.py scriptsRepository: Prekzursil/Reframe Length of output: 151 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Inspecting check_visual_zero.py for fallback/mode handling ==="
rg -n -C5 'fallback|mode|unresolved|mismatches|missing' scripts/quality/check_visual_zero.pyRepository: Prekzursil/Reframe Length of output: 3334 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Checking workflow-level handling of preflight and fallback ==="
rg -n -C5 'preflight|available|fallback|applitools' .github/workflows/applitools-visual.ymlRepository: Prekzursil/Reframe Length of output: 4429 Fallback path allows workflow to pass without executing actual visual checks. When Applitools auth is unavailable, the preflight step (line 43) sets If this workflow is a required status check, this constitutes fail-open behavior: CI gates pass despite no actual visual validation occurring. Fix: Make the assertion step conditional on successful preflight availability, or have Option 1: Conditional assertion (simpler) - name: Assert Applitools unresolved diffs are zero
+ if: steps.preflight.outputs.available == 'true'
run: |
python3 scripts/quality/check_visual_zero.py \
--provider applitools \
--applitools-results "apps/web/applitools/results.json" \
--out-json "applitools-visual/applitools.json" \
--out-md "applitools-visual/applitools.md"Option 2: Fail-closed in script (more resilient)Update payload = json.loads(results_path.read_text(encoding="utf-8"))
unresolved = payload.get("unresolved")
mismatches = payload.get("mismatches")
missing = payload.get("missing")
+ mode = payload.get("mode")
+
+ if mode == "fallback-no-auth":
+ findings.append("Applitools auth unavailable; rejecting fallback result.")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Upload Applitools artifacts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: always() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/upload-artifact@v4 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: applitools-visual | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apps/web/applitools | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| applitools-visual | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Logs on failure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: failure() && steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: docker compose -f infra/docker-compose.yml logs --no-color --tail=200 || true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Teardown | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: always() && steps.preflight.outputs.available == 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: docker compose -f infra/docker-compose.yml down -v || true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| name: BrowserStack E2E | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| browserstack-e2e: | ||
| name: BrowserStack E2E | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} | ||
| BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }} | ||
| E2E_BASE_URL: http://bs-local.com:5173 | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Set up Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: '20' | ||
| cache: npm | ||
| cache-dependency-path: apps/web/package-lock.json | ||
|
|
||
| - name: Validate BrowserStack credentials | ||
| run: | | ||
| if [ -z "${BROWSERSTACK_USERNAME}" ] || [ -z "${BROWSERSTACK_ACCESS_KEY}" ]; then | ||
| echo "Missing BrowserStack credentials" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| cd apps/web | ||
| npm ci | ||
| npx playwright install --with-deps chromium | ||
|
|
||
| - name: Prepare env file | ||
| run: cp .env.example .env | ||
|
|
||
| - name: Start local stack | ||
| run: docker compose -f infra/docker-compose.yml up -d --build | ||
|
|
||
| - name: Wait for web | ||
| run: | | ||
| set -euo pipefail | ||
| for i in $(seq 1 90); do | ||
| if curl -fsS http://127.0.0.1:5173 >/dev/null; then | ||
| exit 0 | ||
| fi | ||
| sleep 2 | ||
| done | ||
| echo "web failed to start" >&2 | ||
| exit 1 | ||
|
|
||
| - name: Run BrowserStack matrix tests | ||
| run: | | ||
| cd apps/web | ||
| npx browserstack-node-sdk playwright test e2e/browserstack-core.spec.ts --config=playwright.config.ts --workers=1 | ||
|
|
||
| - name: Logs on failure | ||
| if: failure() | ||
| run: docker compose -f infra/docker-compose.yml logs --no-color --tail=200 || true | ||
|
|
||
| - name: Teardown | ||
| if: always() | ||
| run: docker compose -f infra/docker-compose.yml down -v || true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| name: Codacy Zero | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| codacy-zero: | ||
| name: Codacy Zero | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n .github/workflows/codacy-zero.ymlRepository: Prekzursil/Reframe Length of output: 1265 Pin third-party GitHub Actions to immutable commit SHAs for supply-chain hardening. Lines 18 and 35 use floating version tags (
🤖 Prompt for AI Agents |
||
|
|
||
| - name: Assert Codacy zero-open gate | ||
| env: | ||
| CODACY_API_TOKEN: ${{ secrets.CODACY_API_TOKEN }} | ||
| run: | | ||
| EXTRA_ARGS=() | ||
| if [ "${{ github.event_name }}" = "pull_request" ]; then | ||
| EXTRA_ARGS+=(--pull-request "${{ github.event.pull_request.number }}") | ||
| fi | ||
| python3 scripts/quality/check_codacy_zero.py \ | ||
| "${EXTRA_ARGS[@]}" \ | ||
| --out-json "codacy-zero/codacy.json" \ | ||
| --out-md "codacy-zero/codacy.md" | ||
|
|
||
| - name: Upload Codacy zero artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: codacy-zero | ||
| path: codacy-zero | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| name: Codecov Analytics | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| codecov-analytics: | ||
| name: Codecov Analytics | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | ||
| PYTHONPATH: .:apps/api:packages/media-core/src | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Validate Codecov token | ||
| run: | | ||
| if [ -z "${CODECOV_TOKEN}" ]; then | ||
| echo "Missing CODECOV_TOKEN" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Set up Python | ||
| uses: actions/setup-python@v6 | ||
| with: | ||
| python-version: '3.12' | ||
|
|
||
| - name: Set up Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Install Python deps | ||
| run: | | ||
| python -m venv .venv | ||
| .venv/bin/python -m pip install --upgrade pip | ||
| .venv/bin/pip install -r apps/api/requirements.txt -r services/worker/requirements.txt | ||
| .venv/bin/pip install pytest pytest-cov | ||
|
|
||
| - name: Install web deps | ||
| working-directory: apps/web | ||
| run: npm ci | ||
|
|
||
| - name: Install desktop deps | ||
| working-directory: apps/desktop | ||
| run: npm ci | ||
|
|
||
| - name: Run python coverage | ||
| run: | | ||
| mkdir -p coverage | ||
| .venv/bin/python -m pytest \ | ||
| --cov=apps/api/app \ | ||
| --cov=services/worker \ | ||
| --cov=packages/media-core/src/media_core \ | ||
| --cov-report=xml:coverage/python-coverage.xml \ | ||
| apps/api/tests services/worker packages/media-core/tests | ||
|
|
||
| - name: Run web coverage | ||
| working-directory: apps/web | ||
| run: | | ||
| npx vitest run --coverage \ | ||
| --coverage.thresholds.lines=0 \ | ||
| --coverage.thresholds.functions=0 \ | ||
| --coverage.thresholds.branches=0 \ | ||
| --coverage.thresholds.statements=0 | ||
|
|
||
| - name: Run desktop TS coverage | ||
| working-directory: apps/desktop | ||
| run: | | ||
| npx vitest run --coverage \ | ||
| --coverage.thresholds.lines=0 \ | ||
| --coverage.thresholds.functions=0 \ | ||
| --coverage.thresholds.branches=0 \ | ||
| --coverage.thresholds.statements=0 | ||
|
|
||
| - name: Upload coverage to Codecov | ||
| uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de | ||
| with: | ||
| token: ${{ secrets.CODECOV_TOKEN }} | ||
| files: coverage/python-coverage.xml,apps/web/coverage/lcov.info,apps/desktop/coverage/lcov.info | ||
| flags: api,worker,media-core,web,desktop-ts | ||
| fail_ci_if_error: true | ||
| verbose: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid excluding all scripts and runtime source from Codacy scope.
"scripts/**"and"apps/desktop/src/text.ts"remove high-value code from static analysis, which weakens a zero-issue gate posture.Suggested scope tightening
📝 Committable suggestion
🤖 Prompt for AI Agents