Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ccb1e66
Wire free production readiness stack
njrini99-code Jun 30, 2026
cea85e3
fix(readiness): close route secret and dependency findings
njrini99-code Jun 30, 2026
399d664
fix(ops): close 24h GitHub issues for CI, secrets, and tooling
njrini99-code Jun 30, 2026
5a6cc85
fix(readiness): close 24h ops issues (#351–#365)
njrini99-code Jun 30, 2026
b9cda23
feat(routes): wire Next.js route bug catcher static checks
njrini99-code Jun 30, 2026
f2deea6
feat(routes): add route bug catcher playbook and hygiene hardening
njrini99-code Jun 30, 2026
19edb0e
fix(semgrep): document push token action revalidate exceptions
njrini99-code Jun 30, 2026
a3b487d
fix(ci): restore routes:check and clear semgrep on device-token path
njrini99-code Jun 30, 2026
69e4594
fix(golf): suppress semgrep on guarded round-submit fallback
njrini99-code Jun 30, 2026
8d271d4
fix(e2e): stabilize route crawler auth redirect waits
njrini99-code Jun 30, 2026
66c14b3
fix(ci): clear Review Gate semgrep on baseball games actions
njrini99-code Jun 30, 2026
fdb57f5
feat(ops): complete bug-discovery stack install
njrini99-code Jun 30, 2026
4479cc4
fix(ci): satisfy actionlint on Meticulous advisory workflow
njrini99-code Jun 30, 2026
26958c1
fix(ci): Meticulous advisory placeholder without unresolved action
njrini99-code Jun 30, 2026
e9b5b94
feat(ops): add visual baselines and verify:bugs entry points
njrini99-code Jun 30, 2026
2cbcf99
fix(ci): ZAP workflow env indirection for semgrep gate
njrini99-code Jun 30, 2026
ed2e716
fix(ci): supply Supabase env for visual regression job
njrini99-code Jun 30, 2026
cad174e
fix(ci): supply Supabase env for route crawler job
njrini99-code Jun 30, 2026
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
107 changes: 107 additions & 0 deletions .github/workflows/free-production-readiness.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Free Production Readiness

on:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
business-contracts:
name: Business contracts
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Run low-gray business contracts
run: npm run verify:business

- name: Run advisory source-shape contracts
run: npm run test:business:advisory
continue-on-error: true

route-hygiene:
name: Route Hygiene P0/P1
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Check route hygiene
run: npm run routes:check

- name: Upload route hygiene reports
if: always()
uses: actions/upload-artifact@v7
with:
name: route-hygiene-reports
path: docs/operations/generated/
if-no-files-found: ignore
retention-days: 14

static-radar:
name: Static radar advisory
runs-on: ubuntu-latest
continue-on-error: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep static radar steps running independently

In this workflow, static-radar is intended to collect Semgrep, dependency-cruiser, and jscpd advisory reports, but putting continue-on-error only on the job does not make later steps run after an earlier step fails; the default step condition remains success-only. In a fresh CI run, any nonzero exit from Semgrep prevents the dependency and duplicate-code reports from being generated or uploaded, so each radar step needs its own continue-on-error or the later report steps need if: always().

Useful? React with 👍 / 👎.

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Install Semgrep CE
run: python -m pip install semgrep

- name: Run Semgrep Helm rules
run: npm run analyze:semgrep
continue-on-error: true

- name: Run dependency-cruiser
run: npm run analyze:deps
continue-on-error: true

- name: Run duplicate-code radar
run: npm run analyze:duplicates
continue-on-error: true

- name: Run Helm auditor
if: always()
run: npm run auditor:all

- name: Upload static radar reports
if: always()
uses: actions/upload-artifact@v7
with:
name: static-radar-reports
path: |
docs/operations/generated/
docs/operations/revealed-bugs/production-readiness/
if-no-files-found: ignore
retention-days: 14
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ scripts/rotate-demo-passwords.mjs
/test-results/
/playwright-report/

# Production-readiness generated reports.
/docs/operations/generated/
/.stryker-tmp/

# Large generated showcase binaries (repo already ignores GolfHelm-Prospect-Deck.pptx).
GolfHelm-CoachHelm-Showcase.pdf
GolfHelm-Fairway-Guide.pdf
Expand Down
89 changes: 89 additions & 0 deletions .semgrep/helm-rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
rules:
- id: helm-service-role-in-client-code
severity: ERROR
languages: [typescript, javascript]
message: Service-role/admin Supabase client must not be imported from client-facing code.
paths:
include:
- /src/**/*.ts
- /src/**/*.tsx
exclude:
- /src/lib/supabase/admin.ts
- /src/**/*.test.ts
- /src/**/*.test.tsx
- /src/contracts/**
patterns:
- pattern-either:
- pattern: import $X from '@/lib/supabase/admin'
- pattern: import { $X } from '@/lib/supabase/admin'
- pattern: createAdminClient(...)
- pattern-not-inside: |
"use server";
...

- id: helm-golf-file-links-baseball-auth-or-dashboard
severity: ERROR
languages: [typescript]
message: Golf files must not link or redirect to Baseball auth/dashboard routes.
patterns:
- pattern-either:
- pattern: '"/baseball/$PATH"'
- pattern: "'/baseball/$PATH'"
paths:
include:
- /src/app/golf/**/*.ts
- /src/app/golf/**/*.tsx

- id: helm-baseball-file-links-golf-auth-or-dashboard
severity: ERROR
languages: [typescript]
message: Baseball files must not link or redirect to Golf auth/dashboard routes.
patterns:
- pattern-either:
- pattern: '"/golf/$PATH"'
- pattern: "'/golf/$PATH'"
- metavariable-regex:
metavariable: $PATH
regex: ^(login|signup|dashboard).*
paths:
include:
- /src/app/baseball/**/*.ts
- /src/app/baseball/**/*.tsx

- id: helm-success-true-inside-catch
severity: ERROR
languages: [typescript, javascript]
message: Catch blocks must not return success:true.
pattern: |
catch ($ERR) {
...
return { ..., success: true, ... };
}

- id: helm-llm-call-in-client-component
severity: ERROR
languages: [typescript]
message: LLM generation must stay server-side.
patterns:
- pattern-either:
- pattern: generateText(...)
- pattern: streamText(...)
- pattern-inside: |
"use client";
...

- id: helm-catch-collapses-error-to-empty
severity: WARNING
languages: [typescript, javascript]
message: Catch block collapses a failure to []/null; prefer an explicit error state.
pattern-either:
- pattern: |
catch ($ERR) {
...
return [];
}
- pattern: |
catch ($ERR) {
...
return null;
}
Loading
Loading