ReviqueInc GitHub Repository Analysis
Comprehensive health, security, and maintainability audit across 2 active repositories
Executive Summary
Portfolio Health Score: B (72/100)
The ReviqueInc active repository portfolio consists of two repositories: revique-web, a modern React/TypeScript frontend deployed to Cloudflare Workers, and revique-api, a TypeScript Node.js API deployed to AWS ECS/Fargate via CDK. Both repos have GitHub Actions CI/CD pipelines in place with solid foundations. Key gaps are the absence of branch protection rules, disabled Dependabot, unpinned third-party actions, no dependency or container image scanning, and revique-web deploying without a test gate.
-
Third-party actions not pinned to commit SHAs (all 6 workflows)
cloudflare/wrangler-action@v3 and aws-actions/configure-aws-credentials@v4 use mutable version tags — supply chain attack risk with full secret access.
-
revique-api/ci.yml missing permissions block
GITHUB_TOKEN defaults to write permissions on contents, issues, and pull-requests. Any action in the CI job can write to the repo.
-
Hardcoded infrastructure values in revique-web workflow env blocks
AWS API Gateway URLs, Cognito Identity Pool IDs, IoT endpoints, and reCAPTCHA keys committed in plain YAML as fallback values.
-
No branch protection on main, develop, or uat branches
Both repos allow direct force-pushes. No required reviews or CI status checks before merge.
-
revique-web deploys to all environments without running tests
The three deploy workflows build and push to Cloudflare without any lint, typecheck, or test step — unlike revique-api which gates on all three.
-
Add permissions: contents: read to revique-api/ci.yml
One-line fix that immediately reduces the blast radius of any compromised CI step.
-
Add timeout-minutes: 30 to all 6 workflow jobs
Prevents runaway deploys from holding the concurrency slot for 6 hours.
-
Remove duplicate setup-node calls from deploy-production.yml and deploy-uat.yml
Delete the "Setup Node for Wrangler" step — saves ~30s per deploy, fixes Node version override.
-
Enable Dependabot on both repositories
One-click in GitHub Settings → Security → Dependabot. Adds automated CVE alerts for npm dependencies.
-
Add npm audit step to all CI and deploy workflows
Single line:
npm audit --audit-level=high. Catches known CVEs before they ship.
Repository Comparison Table
| Repository | Status | Language | Default Branch | Branches | Last Push | Open PRs | Contributors | Workflows | Branch Protection | Dependabot | README | Tests | TODOs | Health Score |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| revique-web | ACTIVE | React / TypeScript | main |
68 | 2026-05-08 | 7 | — | 4 workflows | NONE | DISABLED | YES | Partial | 39 | 68 |
| revique-api | ACTIVE | TypeScript / Node.js | develop |
— | 2026-05-15 | — | — | 2 workflows | NONE | DISABLED | — | Yes (CI) | — | 76 |
revique-web
ACTIVE PRIMARYParallel Revique web app — modern React/TypeScript frontend hosted on Cloudflare Workers
1. Repository Overview & Metadata
| Property | Value |
|---|---|
| Framework | React 19 Vite 5 TypeScript 5.5 |
| UI Library | Chakra UI v3 Framer Motion |
| Deployment | Cloudflare Workers Static Assets |
| Branch Flow | feature/* → develop → uat → main |
| Created | 2026-05-01 |
| Last Updated | 2026-05-08 (today) |
| Stars | 1 |
| Private | Yes |
| Topics/Tags | None configured |
| Wiki | Disabled |
2. CI/CD & Workflows
| Workflow File | Trigger | Target | Status |
|---|---|---|---|
deploy-develop.yml | Push to develop, manual | Cloudflare develop env | Active / Passing |
deploy-uat.yml | Push to uat, manual (with ref input) | Cloudflare UAT env | Active |
deploy-production.yml | Manual only (requires ref input) | Cloudflare production | Active |
request-uat-promotion.yml | Manual (source/target branch inputs) | PR creation + Slack | Active |
Recent Run Activity (last 20 runs)
npm run lint and test step before deploy jobs.3. Branch Strategy & Pull Requests
The branch strategy follows a trunk-based model: feature/* → develop → uat → main. Codex-generated branches follow the naming convention codex/RWA-XXX-description.
Open Pull Requests (7)
| PR # | Title | Author | Opened |
|---|---|---|---|
| #91 | Batch develop merge 20260508-0544 | farhan-revique | 2026-05-08 |
| #90 | RWA-608: Restore child appointment service list | farhan-revique | 2026-05-08 |
| #89 | RWA-607: Autofill appointment duration from selected service | farhan-revique | 2026-05-08 |
| #42 | RWA-568: Open no-show reschedule in appointment drawer | farhan-revique | 2026-05-07 |
| #41 | RWA-566: Harden schedule checkout handoff | farhan-revique | 2026-05-07 |
| #25 | RWA-554: Enable Add Notes save | farhan-revique | 2026-05-06 |
| #20 | RWA-549: Add transaction history actions | farhan-revique | 2026-05-06 |
main, develop, or uat. All 30 sampled closed PRs were merged (100% merge rate) — but without required reviews, any collaborator can merge unreviewed code directly to production-bound branches.4. Security & Dependencies
Runtime Dependencies (27)
| Package | Version Spec | Category |
|---|---|---|
| react / react-dom | ^19 | Core Framework |
| @chakra-ui/react | ^3.19.1 | UI Library |
| axios | ^1.9.0 | HTTP Client |
| react-router-dom | ^7.5.2 | Routing |
| react-hook-form | ^7.56.1 | Forms |
| dayjs | ^1.11.13 | Date/Time |
| framer-motion | ^12.9.2 | Animation |
| xlsx | ^0.18.5 | Excel Export |
| jspdf / jspdf-autotable | ^3.0.1 / ^5.0.2 | PDF Generation |
| recharts | ^2.15.3 | Charts |
| styled-components | ^6.4.1 | CSS-in-JS |
| react-payment-inputs | ^1.2.0 | Payment UI |
| @react-pdf/renderer | ^4.3.0 | PDF Rendering |
| vite-plugin-pwa | ^1.0.1 | PWA Support |
xlsx@0.18.5 (SheetJS Community Edition) is known to have had security advisories in older builds. Recommend verifying this is the latest community edition and consider switching to exceljs for AGPL-free licensing.Secret Scan Results
.js, .ts, .env, or .json files. API keys appear to be properly managed via GitHub Actions environment variables (vars.*).Code Quality Indicators
- ESLint configured (
eslint.config.js) - Prettier configured (via devDependency)
- lint-staged configured for pre-commit formatting
- Husky devDependency present (though
.husky/directory not found in shallow clone — verifypreparescript runs) - TypeScript strict mode via
typescript-eslint
- No unit tests found (only 1 test-related file detected)
- 39 TODO/FIXME/HACK comments in source code
- No SECURITY.md policy
5. Code Quality & Documentation
Documentation Files
- README.md — present and informative
- CONTRIBUTING.md — missing
- CHANGELOG.md — missing
- LICENSE — missing
- SECURITY.md — missing
Project Structure
src/components/pages/— page components (patient, dashboard, checkout, scheduling, admin)src/components/common/— shared UI (sidebar, header, listing, datepicker)src/utils/— hooks, context, API clients, typeslegacy-admin/— embedded legacy admin moduledocs/— internal documentation directoryscripts/— build/utility scripts
TODO/FIXME/HACK Distribution
Recommendations
| Priority | Action |
|---|---|
| HIGH | Enable branch protection on main, develop, and uat branches |
| HIGH | Enable Dependabot for npm dependencies |
| MED | Add a test step to CI pipeline (even basic lint check gates) |
| MED | Add LICENSE file (MIT or Apache recommended for internal clarity) |
| MED | Prune merged/stale branches — 68 is excessive |
| LOW | Add repository topics/tags |
| LOW | Track TODOs as GitHub Issues |
revique-api
ACTIVE BACKENDTypeScript Node.js REST API — containerised and deployed to AWS ECS/Fargate via AWS CDK
1. Repository Overview & Stack
| Property | Value |
|---|---|
| Runtime | Node.js (TypeScript — transpiled to dist/) |
| Infrastructure | AWS CDK (CloudFormation stacks) |
| Compute | AWS ECS Fargate |
| Database | AWS Aurora Serverless (RDS) |
| Auth | OIDC → AWS STS (no long-lived keys stored in GitHub) |
| Migrations | Run as ECS one-shot task post-deploy |
| Docker | Dockerfile present — image built in CI |
| Environments | dev / uat / prod (GitHub Environments) |
| Branch Flow | feature/* → develop (CI) → manual deploy to dev/uat/prod |
2. CI/CD Workflows
| Workflow File | Trigger | Purpose | Status |
|---|---|---|---|
ci.yml |
PR → develop, push → develop | Lint, typecheck, test, build, docker build | Active |
deploy.yml |
Manual (env + region inputs) | CDK deploy, ECS update, DB migrations | Active |
permissions: block on ci.yml (GITHUB_TOKEN over-broad), no container image scan, no concurrency on CI, Docker image discarded after CI (deploy rebuilds independently).3. Security & Dependencies
- OIDC-based AWS authentication — no long-lived credentials in GitHub secrets
- Lint, typecheck, and full test suite run before any deployment
- Pre-deployment validation checks AWS role is configured before AWS calls
- GitHub environment protection rules supported (dev/uat/prod environments)
- npm caching via setup-node — faster installs
- No
permissions:block on ci.yml — GITHUB_TOKEN defaults to write access - Third-party action (
aws-actions/configure-aws-credentials@v4) not pinned to SHA - No Dependabot configured for npm dependencies
- No container image vulnerability scanning (Trivy / Snyk)
- No secret scanning (gitleaks / truffleHog)
- No
npm auditstep - No timeout on any job
4. Recommendations
| Priority | Action |
|---|---|
| CRITICAL | Add permissions: contents: read to ci.yml |
| CRITICAL | Pin aws-actions/configure-aws-credentials to a commit SHA |
| HIGH | Add container image scan with Trivy after docker build in ci.yml |
| HIGH | Add npm audit --audit-level=high to ci.yml and deploy.yml |
| HIGH | Fix Slack webhook — prod deploys should use a prod webhook, not dev |
| MEDIUM | Add concurrency: to ci.yml to cancel superseded runs |
| MEDIUM | Add timeout-minutes: 30 to all jobs |
| MEDIUM | Publish CI Docker image to ECR; deploy.yml should pull it instead of rebuilding |
| LOW | Enable Dependabot for npm dependencies |
| LOW | Add branch protection rules on develop |
Pipeline Analysis — revique-web
4 WORKFLOWSDetailed breakdown of every workflow file, jobs, steps, and issues found
deploy-develop.yml — Deploy to Cloudflare Develop
Triggers
| push | develop branch |
| workflow_dispatch | Manual (no inputs) |
| Path filters | None — all pushes trigger deploy |
Configuration
| Runner | ubuntu-latest |
| Environment | develop |
| Concurrency | ✓ deploy-develop, cancel-in-progress: true |
| Timeout | Not set |
| Permissions | contents: read |
Steps
| # | Step Name | Action / Command | Notes |
|---|---|---|---|
| 1 | Checkout | actions/checkout@v4 | |
| 2 | Resolve deployment commit | git rev-parse HEAD | Sets sha + short_sha outputs |
| 3 | Setup Node | actions/setup-node@v4 | Reads .nvmrc · npm cache ✓ |
| 4 | Install dependencies | npm ci --legacy-peer-deps | |
| 5 | Build composed app | npm run build:composed | |
| 6 | Notify Slack — active | .github/scripts/notify-slack-deployment.sh | continue-on-error: true |
| 7 | Deploy to Cloudflare Workers | cloudflare/wrangler-action@v3 | --env develop |
| 8 | Notify Slack — result | .github/scripts/notify-slack-deployment.sh | if: always() |
Actions Used
| Action | Version | Publisher | SHA Pinned? |
|---|---|---|---|
| actions/checkout | @v4 | GitHub | Tag only |
| actions/setup-node | @v4 | GitHub | Tag only |
| cloudflare/wrangler-action | @v3 | Cloudflare (3rd party) | NOT pinned ⚠ |
Secrets Used
SLACK_WEBHOOK_DEV_GITHUB_ACTIONSCLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
Issues Found
| Severity | Issue |
|---|---|
| CRITICAL | cloudflare/wrangler-action@v3 not pinned to commit SHA — supply chain attack risk |
| CRITICAL | Hardcoded fallback values in env block: AWS endpoints, Cognito IDs, IoT URLs, reCAPTCHA keys committed in YAML |
| HIGH | No test gate — deploys without lint, typecheck, or tests |
| HIGH | No dependency scan (npm audit) |
| MEDIUM | No timeout-minutes — job can run up to 6 hours if Cloudflare deploy hangs |
| LOW | No path filters — deploys on docs-only commits too |
deploy-production.yml — Manual Production Deploy
Triggers
| workflow_dispatch | Manual only |
| Input: ref | Branch, tag, or SHA to deploy (required, default: main) |
Configuration
| Runner | ubuntu-latest |
| Environment | production |
| Concurrency | ✓ deploy-production, cancel-in-progress: false |
| Timeout | Not set |
| Permissions | contents: read |
Steps
| # | Step Name | Action / Command | Issue |
|---|---|---|---|
| 1 | Checkout | actions/checkout@v4 | |
| 2 | Resolve deployment commit | git rev-parse | |
| 3 | Setup Node | actions/setup-node@v4 (.nvmrc, npm cache) | |
| 4 | Install dependencies | npm ci --legacy-peer-deps | |
| 5 | Build composed app | npm run build:composed | |
| 6 | Setup Node for Wrangler | actions/setup-node@v4 (node 22) | DUPLICATE — wastes ~30s |
| 7 | Notify Slack — active | notify-slack-deployment.sh | |
| 8 | Deploy to Cloudflare Workers | cloudflare/wrangler-action@v3 | |
| 9 | Notify Slack — result | notify-slack-deployment.sh |
deploy-uat.yml — UAT Deploy with Approval Gate
Triggers
| push | uat branch |
| workflow_dispatch | Optional ref input (default: uat) |
Jobs
request-approval | Notify Slack, await environment gate |
deploy | Build + deploy to Cloudflare UAT |
environment: uat enables GitHub environment protection rules (required reviewers, wait timers). Best deployment gate pattern in revique-web.setup-node call in deploy job (step 4 with .nvmrc, step 10 with node 22). Remove step 10.request-uat-promotion.yml — UAT Promotion Request
Inputs
| source_branch | Branch to promote from (default: develop) |
| target_branch | Branch to promote to (default: uat) |
| post_slack | Post Slack notification (boolean, default: true) |
Configuration
| Environment | codex-full-access |
| Permissions | contents: read, pull-requests: write |
| Concurrency | NOT set — race condition risk |
What It Does
- Fetches full history (
fetch-depth: 0) to compute promotion delta - Calculates commits ahead/behind, changed files, changed areas, concerns
- Auto-detects sensitive changes (payments, auth, config files)
- Creates or updates a UAT promotion PR via
gh pr create/edit - Posts rich Slack notification with summary and PR link
Pipeline Analysis — revique-api
2 WORKFLOWSDetailed breakdown of every workflow file, jobs, steps, and issues found
ci.yml — Continuous Integration
Triggers
| pull_request | Targeting develop |
| push | To develop |
| Path filters | None |
Configuration
| Runner | ubuntu-latest |
| Permissions | MISSING — default over-broad |
| Concurrency | NOT set |
| Timeout | Not set |
| Matrix | None |
Steps
| # | Step | Command | Notes |
|---|---|---|---|
| 1 | Checkout | actions/checkout@v4 | |
| 2 | Setup Node | actions/setup-node@v4 | Reads .nvmrc · npm cache ✓ |
| 3 | Install | npm ci | |
| 4 | Lint | npm run lint | ✓ Quality gate |
| 5 | Typecheck | npm run typecheck | ✓ Quality gate |
| 6 | Test | npm test | ✓ Quality gate |
| 7 | Build | npm run build | ✓ |
| 8 | Synthesize infrastructure | npm run infra:synth | ✓ CDK synthesis |
| 9 | Build Docker image | docker build --tag revique-api:ci . | Image discarded after job |
Issues Found
| Severity | Issue |
|---|---|
| CRITICAL | No permissions: block — GITHUB_TOKEN has default write access to contents, issues, pull-requests |
| HIGH | Docker image built but not scanned — OS/package vulnerabilities undetected |
| HIGH | No npm audit step — known CVEs in dependencies ship undetected |
| MEDIUM | No concurrency: — rapid pushes queue multiple full CI runs (~5-10 min each) |
| MEDIUM | Docker image discarded — deploy.yml rebuilds independently (tested ≠ deployed artifact) |
| MEDIUM | No timeout — job can run up to 6 hours if Docker build hangs |
| LOW | No test coverage artifact upload — coverage trends invisible |
deploy.yml — Multi-Environment Deploy (CDK + ECS + Migrations)
Triggers
| workflow_dispatch | Manual only |
| Input: environment | dev / uat / prod (required) |
| Input: aws_region | AWS region (required, default: us-east-1) |
Configuration
| Runner | ubuntu-latest |
| Permissions | contents: read · id-token: write |
| Concurrency | ✓ per-environment group |
| AWS Auth | ✓ OIDC — no static keys |
| Timeout | Not set |
Steps
| # | Step | Notes |
|---|---|---|
| 1 | Checkout | |
| 2 | Resolve deployment commit | sha + short_sha |
| 3 | Notify Slack — active | continue-on-error: true |
| 4 | Setup Node + npm cache | |
| 5 | Install (npm ci) | |
| 6 | Lint ✓ | Pre-deploy gate |
| 7 | Typecheck ✓ | Pre-deploy gate |
| 8 | Test ✓ | Pre-deploy gate |
| 9 | Build ✓ | |
| 10 | Validate AWS role configured | Exits early if AWS_ROLE_TO_ASSUME is empty ✓ |
| 11 | Configure AWS credentials | aws-actions/configure-aws-credentials@v4 (OIDC) ✓ |
| 12 | Synthesize infrastructure | npm run infra:synth |
| 13 | Deploy infrastructure + service | npm run infra:deploy (CDK) |
| 14 | Run DB migrations | ECS run-task → wait → check exit code ✓ |
| 15 | Notify Slack — result | if: always() |
Issues Found
| Severity | Issue |
|---|---|
| CRITICAL | aws-actions/configure-aws-credentials@v4 not pinned to commit SHA — this action has direct AWS account access |
| HIGH | All environments (dev/uat/prod) use SLACK_WEBHOOK_DEV_GITHUB_ACTIONS — prod failures go to dev channel |
| HIGH | No npm audit step before deploying to production |
| MEDIUM | No timeout — ECS migration task could hang indefinitely |
| LOW | Docker image rebuilt from source independently of CI (tested artifact may differ from deployed artifact) |
Speed & Security Improvement Plan
20 IMPROVEMENTSPrioritised action plan for both repos — with ready-to-paste YAML snippets
Speed Improvements
Security Improvements
Ready-to-Use Code Snippets
Applies to all 6 workflows. Replace version tags on third-party actions with pinned commit SHAs. Verify current SHAs from each action's GitHub releases page.
# BEFORE (mutable — dangerous for third-party actions):
uses: cloudflare/wrangler-action@v3
uses: aws-actions/configure-aws-credentials@v4
# AFTER (pinned to specific commit SHA):
uses: cloudflare/wrangler-action@392e85aa28f1ef5bbe8bee4cecc4ab4c4f73f66f # v3.14.1
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
# GitHub-owned actions are lower risk but can also be pinned:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
Add at the workflow level (before the jobs block). Fixes the over-broad GITHUB_TOKEN and prevents queued duplicate runs.
name: CI
on:
pull_request:
branches: [develop]
push:
branches: [develop]
permissions:
contents: read # checkout only — no write access needed
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true # cancel older run when new push arrives
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 20
# ... rest of job unchanged
Move all infrastructure values to GitHub environment variables. Add a validation step to fail fast if a required variable is not configured.
# BEFORE (exposes AWS infra in workflow YAML):
env:
VITE_BASE_URL: ${{ vars.VITE_BASE_URL_DEV || vars.VITE_BASE_URL || 'https://atg96ts3g3.execute-api.us-east-2.amazonaws.com/v1' }}
REACT_APP_IDENTITY_POOL_ID: ${{ vars.REACT_APP_IDENTITY_POOL_ID || 'us-east-2:1b4b834c-...' }}
# AFTER (all values required in GitHub environment — no fallbacks):
env:
VITE_BASE_URL: ${{ vars.VITE_BASE_URL_DEV || vars.VITE_BASE_URL }}
REACT_APP_IDENTITY_POOL_ID: ${{ vars.REACT_APP_IDENTITY_POOL_ID }}
# Add this step immediately after Checkout:
- name: Validate required environment variables
run: |
: "${VITE_BASE_URL:?Set VITE_BASE_URL in the GitHub develop environment}"
: "${REACT_APP_IDENTITY_POOL_ID:?Set REACT_APP_IDENTITY_POOL_ID in the GitHub environment}"
: "${REACT_APP_IOT_ENDPOINT:?Set REACT_APP_IOT_ENDPOINT in the GitHub environment}"
- name: Build Docker image
run: docker build --tag revique-api:ci .
- name: Scan container image with Trivy
uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # v0.24.0
with:
image-ref: revique-api:ci
format: table
exit-code: '1'
severity: CRITICAL,HIGH
ignore-unfixed: true
# For revique-api (standard install):
- name: Install
run: npm ci
- name: Audit dependencies
run: npm audit --audit-level=high
# For revique-web (uses --legacy-peer-deps):
- name: Install dependencies
run: npm ci --legacy-peer-deps
- name: Audit dependencies
run: npm audit --audit-level=high --legacy-peer-deps
- name: Install dependencies
run: npm ci --legacy-peer-deps
- name: Audit dependencies
run: npm audit --audit-level=high --legacy-peer-deps
- name: Lint
run: npm run lint
- name: Typecheck
run: npm run typecheck
# Add when tests are available:
# - name: Test
# run: npm test
- name: Build composed app
run: npm run build:composed
- name: Checkout
uses: actions/checkout@SHA # pinned SHA
- name: Scan for secrets with gitleaks
uses: gitleaks/gitleaks-action@cb7149a9b57195b609c63e8518d2b7e1a8b32c8e # v2.3.7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# BEFORE (dev webhook used for all environments):
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_DEV_GITHUB_ACTIONS }}
# AFTER (prod events go to prod channel):
env:
SLACK_WEBHOOK_URL: ${{ inputs.environment == 'prod' && secrets.SLACK_WEBHOOK_PROD_GITHUB_ACTIONS || secrets.SLACK_WEBHOOK_DEV_GITHUB_ACTIONS }}
# Also: add SLACK_WEBHOOK_PROD_GITHUB_ACTIONS secret to the prod GitHub environment.
# Add timeout to all jobs:
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 30 # CI: 20, short deploys: 30, full CDK deploy: 45
# Remove this block from deploy-production.yml and deploy-uat.yml:
# - name: Setup Node for Wrangler <-- DELETE THIS STEP
# uses: actions/setup-node@v4
# with:
# node-version: 22
Create this file in both repos at .github/workflows/codeql.yml. GitHub CodeQL is free for public repos and for private repos up to a team plan.
name: CodeQL SAST
on:
push:
branches: [develop, main]
pull_request:
branches: [develop]
schedule:
- cron: '0 8 * * 1' # weekly Monday scan
permissions:
contents: read
security-events: write
jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
language: [javascript-typescript]
steps:
- name: Checkout
uses: actions/checkout@SHA # pinned SHA
- name: Initialize CodeQL
uses: github/codeql-action/init@SHA # pinned SHA
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@SHA # same pinned SHA
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@SHA # same pinned SHA
with:
category: "/language:${{ matrix.language }}"
name: Dependency Review
on:
pull_request:
branches: [develop, main]
permissions:
contents: read
pull-requests: write
jobs:
dependency-review:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@SHA # pinned SHA
- uses: actions/dependency-review-action@SHA # pinned SHA
with:
fail-on-severity: high
comment-summary-in-pr: true
on:
push:
branches: [develop]
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/CODEOWNERS'
- '.gitignore'
workflow_dispatch: # manual trigger always runs regardless of paths
Split the monolithic verify job into parallel jobs. Saves 2-4 minutes on each CI run.
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-and-typecheck:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@SHA
- uses: actions/setup-node@SHA
with: { node-version-file: .nvmrc, cache: npm }
- run: npm ci
- run: npm audit --audit-level=high
- run: npm run lint
- run: npm run typecheck
test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@SHA
- uses: actions/setup-node@SHA
with: { node-version-file: .nvmrc, cache: npm }
- run: npm ci
- run: npm test
build-and-scan:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@SHA
- uses: actions/setup-node@SHA
with: { node-version-file: .nvmrc, cache: npm }
- run: npm ci
- run: npm run build
- run: npm run infra:synth
- run: docker build --tag revique-api:ci .
- uses: aquasecurity/trivy-action@SHA
with:
image-ref: revique-api:ci
exit-code: '1'
severity: CRITICAL,HIGH
These settings are configured in GitHub repository Settings, not in workflow YAML files.
| Setting | Where | Recommended Value |
|---|---|---|
| Require PR before merging | Settings → Branches → main, develop, uat | Enabled · Required approvals: 1 |
| Require status checks to pass | Settings → Branches (same rule) | Add CI workflow as required check |
| Restrict force-push | Settings → Branches → Do not allow force pushes | Enabled on main and uat |
| Environment protection reviewers | Settings → Environments → uat, production | Add 1+ required reviewers |
| Dependabot alerts | Settings → Security → Dependabot alerts | Enabled on both repos |
| Dependabot auto-updates | Settings → Security → Dependabot version updates | Enabled · weekly schedule |
GitHub Actions Deep Analysis
6 WORKFLOWS 20 ISSUES FOUNDComprehensive audit of all CI/CD pipelines across revique-web and revique-api
| Repo | File | Purpose | Triggers | Jobs | Caching | Slack | Permissions Block | Security Score | Health |
|---|---|---|---|---|---|---|---|---|---|
revique-web |
deploy-develop.yml |
Build & deploy to Cloudflare develop env | push→develop, manual | 1 | npm ✓ | ✓ | contents:read | 6/10 |
MODERATE |
revique-web |
deploy-production.yml |
Manual production deploy to Cloudflare | manual only (ref input) | 1 | npm ✓ | ✓ | contents:read | 6/10 |
MODERATE |
revique-web |
deploy-uat.yml |
UAT deploy with approval job & Cloudflare | push→uat, manual | 2 | npm ✓ | ✓ | contents:read | 7/10 |
GOOD |
revique-web |
request-uat-promotion.yml |
Compute diff, create/update PR, post to Slack | manual (3 inputs) | 1 | N/A | ✓ | contents:read, pr:write | 7/10 |
MODERATE |
revique-api |
ci.yml |
PR/push CI: lint, typecheck, test, build, docker | PR→develop, push→develop | 1 | npm ✓ | ✗ None | MISSING | 4/10 |
WEAK |
revique-api |
deploy.yml |
Multi-env deploy: CDK infra + ECS + DB migrations | manual (env + region inputs) | 1 | npm ✓ | ✓ | contents:read, id-token:write | 8/10 |
GOOD |
Per-Workflow Breakdown
revique-web / deploy-develop.yml — Deploy Develop
Basic Info
| Runner | ubuntu-latest |
| Environment | develop |
| Timeout | Not set |
| Concurrency | group: deploy-develop, cancel-in-progress: true |
Triggers
- push to
developbranch - workflow_dispatch (manual)
Path / Tag Filters
None — all pushes to develop trigger a deploy regardless of what changed
Steps (in order)
| # | Step | Action / Command | Notes |
|---|---|---|---|
| 1 | Checkout | actions/checkout@v4 | |
| 2 | Resolve deployment commit | git rev-parse HEAD / --short | Outputs sha, short_sha |
| 3 | Setup Node | actions/setup-node@v4 | Reads .nvmrc, npm cache ✓ |
| 4 | Install dependencies | npm ci --legacy-peer-deps | |
| 5 | Build composed app | npm run build:composed | |
| 6 | Notify Slack (active) | notify-slack-deployment.sh | continue-on-error: true |
| 7 | Deploy to Cloudflare Workers | cloudflare/wrangler-action@v3 | command: deploy --env develop |
| 8 | Notify Slack (result) | notify-slack-deployment.sh | if: always(), continue-on-error: true |
Actions & Versions
| Action | Version Used | Publisher | SHA-Pinned? |
|---|---|---|---|
| actions/checkout | @v4 | GitHub (trusted) | Tag only |
| actions/setup-node | @v4 | GitHub (trusted) | Tag only |
| cloudflare/wrangler-action | @v3 | Cloudflare (3rd party) | NOT pinned ⚠ |
Secrets Referenced
SLACK_WEBHOOK_DEV_GITHUB_ACTIONSCLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID
|| 'hardcoded-value' fallbacks embedding AWS API Gateway URLs, Cognito Identity Pool IDs, IoT MQTT endpoints, and reCAPTCHA site keys directly in version-controlled YAML. Move all values to GitHub environment variables with no fallbacks.revique-web / deploy-production.yml — Deploy Production
Basic Info
| Runner | ubuntu-latest |
| Environment | production |
| Timeout | Not set |
| Concurrency | group: deploy-production, cancel-in-progress: false |
Triggers
- workflow_dispatch only (manual — good practice)
- Required input:
ref(branch, tag, or SHA to deploy) - Default:
main
Steps (in order)
| # | Step | Action / Command | Notes |
|---|---|---|---|
| 1 | Checkout | actions/checkout@v4 | Uses inputs.ref |
| 2 | Resolve deployment commit | git rev-parse | |
| 3 | Setup Node | actions/setup-node@v4 | Reads .nvmrc, npm cache ✓ |
| 4 | Install dependencies | npm ci --legacy-peer-deps | |
| 5 | Build composed app | npm run build:composed | |
| 6 | Setup Node for Wrangler | actions/setup-node@v4 | DUPLICATE — node 22, no cache |
| 7 | Notify Slack (active) | notify-slack-deployment.sh | continue-on-error: true |
| 8 | Deploy to Cloudflare Workers | cloudflare/wrangler-action@v3 | no --env flag (defaults to production) |
| 9 | Notify Slack (result) | notify-slack-deployment.sh | if: always() |
actions/setup-node@v4 with Node 22, overriding the version set from .nvmrc in step 3 and discarding the npm cache. Wrangler-action does not require a separate setup-node. Remove step 6.ref input. cancel-in-progress: false prevents concurrent production deploys.revique-web / deploy-uat.yml — Deploy UAT
Basic Info
| Runner | ubuntu-latest (both jobs) |
| Environments | uat (deploy job only) |
| Timeout | Not set |
| Concurrency | group: deploy-uat, cancel-in-progress: false |
Triggers
- push to
uatbranch - workflow_dispatch with optional
refinput (default: uat)
Jobs
| Job | Purpose | Depends On |
|---|---|---|
request-approval | Checkout ref, resolve SHA, notify Slack that approval is pending | — |
deploy | Build and deploy to Cloudflare UAT environment | request-approval |
environment: uat on the deploy job enables GitHub environment protection rules (required reviewers, wait timer). This is the strongest deployment gate in the revique-web workflows.actions/setup-node@v4 twice (step 4 with .nvmrc, step 10 with node 22). Same issue as deploy-production.yml. Remove the second call.revique-web / request-uat-promotion.yml — Request UAT Promotion
Basic Info
| Runner | ubuntu-latest |
| Environment | codex-full-access |
| Concurrency | NOT configured |
| Timeout | Not set |
Inputs
| source_branch | Branch to promote from (default: develop) |
| target_branch | Branch to promote to (default: uat) |
| post_slack | Boolean — whether to post Slack notification (default: true) |
Steps
| # | Step | Notes |
|---|---|---|
| 1 | Checkout (fetch-depth: 0) | Full history needed for git log & rev-list delta |
| 2 | Resolve promotion delta (bash) | Computes commit counts, changed files, concerns, summary |
| 3 | Create or update UAT promotion PR | Uses CODEX_FULL as GH_TOKEN; validates token before use ✓ |
| 4 | Notify Slack UAT promotion request | Conditional on post_slack input; continue-on-error: true |
contents: read, pull-requests: write). Token validated before use with early exit. Bash script uses set -euo pipefail. Rich PR body with concerns auto-detection (dependency changes, sensitive paths, branch divergence).fetch-depth: 0 fetches entire repo history. For large repos this adds significant checkout time. Consider a bounded depth if promotions never span more than N commits.revique-api / ci.yml — CI
Basic Info
| Runner | ubuntu-latest |
| Permissions | MISSING — default over-broad token |
| Concurrency | NOT configured |
| Timeout | Not set |
| Matrix Strategy | None |
Triggers
- pull_request targeting
develop - push to
develop
Steps (in order)
| # | Step | Command |
|---|---|---|
| 1 | Checkout | actions/checkout@v4 |
| 2 | Setup Node | actions/setup-node@v4 — reads .nvmrc, npm cache ✓ |
| 3 | Install | npm ci |
| 4 | Lint | npm run lint ✓ |
| 5 | Typecheck | npm run typecheck ✓ |
| 6 | Test | npm test ✓ |
| 7 | Build | npm run build ✓ |
| 8 | Synthesize infrastructure | npm run infra:synth ✓ |
| 9 | Build Docker image | docker build --tag revique-api:ci . |
permissions:, the GITHUB_TOKEN defaults to read/write on contents, issues, and pull-requests. Any action or injected script can write to the repo or approve PRs on behalf of the token.deploy.yml rebuilds independently, meaning the tested artifact is never the deployed artifact.revique-api / deploy.yml — Deploy
Basic Info
| Runner | ubuntu-latest |
| Environment | Dynamic: dev, uat, or prod |
| Concurrency | per-job, keyed on environment |
| Timeout | Not set |
| AWS Auth | OIDC — no long-lived keys |
Triggers
- workflow_dispatch only
- Required input:
environment(dev / uat / prod) - Required input:
aws_region
Steps (in order)
| # | Step | Notes |
|---|---|---|
| 1 | Checkout | |
| 2 | Resolve deployment commit | sha + short_sha outputs |
| 3 | Notify Slack (active) | continue-on-error: true |
| 4 | Setup Node (npm cache) | |
| 5 | Install | npm ci |
| 6 | Lint ✓ | Pre-deploy quality gate |
| 7 | Typecheck ✓ | Pre-deploy quality gate |
| 8 | Test ✓ | Pre-deploy quality gate |
| 9 | Build ✓ | |
| 10 | Validate AWS deploy config | Exits early if AWS_ROLE_TO_ASSUME not set ✓ |
| 11 | Configure AWS credentials | aws-actions/configure-aws-credentials@v4 — OIDC ✓ |
| 12 | Synthesize infrastructure | npm run infra:synth |
| 13 | Deploy infrastructure and service | npm run infra:deploy (CDK) |
| 14 | Run database migrations | ECS run-task with exit code check ✓ |
| 15 | Notify Slack (result) | if: always() |
id-token: write + aws-actions/configure-aws-credentials). No long-lived AWS credentials stored as secrets.SLACK_WEBHOOK_DEV_GITHUB_ACTIONS is used for ALL environments including production. Production deploy events and failures are routed to the dev channel, not a production monitoring channel.aws-actions/configure-aws-credentials@v4 receives OIDC credentials that grant direct AWS account access. This should be pinned to a specific commit SHA.Cross-Workflow Findings
- All 6 workflows use
actions/checkout@v4andactions/setup-node@v4— consistent, up-to-date tooling - npm caching via
setup-nodein all build workflows — faster installs on cache hit - Slack notifications on start AND completion in all deploy workflows — good operational visibility
- 5 of 6 workflows have explicit
permissions:blocks - 4 of 6 workflows have
concurrency:blocks preventing wasted duplicate runs - Production deploy is manual-only with explicit ref input — prevents accidental auto-deploys
- revique-api
deploy.ymluses OIDC for AWS auth — no long-lived credentials stored as secrets - revique-api CI runs lint + typecheck + test + build — the most thorough quality gate in the portfolio
- UAT workflow uses GitHub environment — supports required reviewer protection rules
- Notification steps use
continue-on-error: true— Slack failures don't block deploys - Deployment SHA always captured and reported — good audit trail in Slack messages
- revique-api
deploy.ymlvalidates required config variables before attempting AWS calls
- No workflow pins third-party actions to commit SHAs — all use floating version tags
- No workflow sets
timeout-minuteson any job - No SAST, dependency scan, secret scan, or container image scan in any workflow
- revique-web deploy workflows deploy without running tests — unlike revique-api which gates on lint + test + typecheck before deploying
- No reusable workflow defined despite 3 near-identical deploy workflows in revique-web
- Docker image built in CI is thrown away — deploy rebuilds independently (tested artifact ≠ deployed artifact)
- No test coverage reporting or artifact upload in any workflow
Security Audit Results
| Severity | Finding | Affected Workflows | Risk |
|---|---|---|---|
| CRITICAL | Third-party actions not pinned to commit SHA — cloudflare/wrangler-action@v3, aws-actions/configure-aws-credentials@v4 |
All deploy workflows | Supply chain attack: a malicious tag push executes arbitrary code with your CLOUDFLARE_API_TOKEN and AWS OIDC credentials |
| CRITICAL | Missing permissions: block on ci.yml — GITHUB_TOKEN defaults to write on contents, issues, pull-requests |
revique-api/ci.yml | Any action or injected script in CI can push code, create issues, or approve PRs using the workflow token |
| CRITICAL | Hardcoded infrastructure fallbacks in workflow env blocks: AWS API Gateway URLs, Cognito Identity Pool IDs, IoT MQTT endpoints, reCAPTCHA site keys | deploy-develop.yml, deploy-production.yml, deploy-uat.yml | Exposes AWS account topology and service identifiers in version-controlled files visible to anyone with repo read access |
| HIGH | No SAST (static analysis security testing) step in any workflow | All 6 workflows | Code security vulnerabilities (injection, insecure dependencies, etc.) not caught before deployment |
| HIGH | No dependency vulnerability scanning (npm audit, Snyk, Dependabot) in any CI or deploy workflow |
All CI/deploy workflows | Known CVEs in npm packages ship to production undetected until a manual scan is run |
| HIGH | Docker image built in ci.yml with no container image scan (Trivy, Snyk) |
revique-api/ci.yml | OS package vulnerabilities in the base image reach production undetected |
| HIGH | No secret scanning (gitleaks, truffleHog) in any workflow | All 6 workflows | Accidentally committed secrets (API keys, tokens, connection strings) are not detected in CI before merging |
| HIGH | revique-web deploy workflows have no test or lint gate before deploying to any environment | deploy-develop.yml, deploy-production.yml, deploy-uat.yml | Broken code ships to all three environments if the build step succeeds but runtime behavior is wrong |
| HIGH | revique-api deploy.yml uses SLACK_WEBHOOK_DEV_GITHUB_ACTIONS for all environments including production |
revique-api/deploy.yml | Production deployment failures are routed to the dev channel — on-call and prod monitors may miss critical alerts |
| MEDIUM | No timeout-minutes on any job — runaway builds consume CI minutes until GitHub's 6-hour limit |
All 6 workflows | A hung Cloudflare deploy or stalled ECS migration holds the concurrency slot for 6 hours, blocking further deploys |
| MEDIUM | Duplicate actions/setup-node@v4 calls in deploy-production.yml and deploy-uat.yml — second call overrides .nvmrc version and discards npm cache |
deploy-production.yml, deploy-uat.yml | ~30s wasted per run; potential Node version mismatch between build and wrangler execution |
| MEDIUM | No concurrency: on ci.yml or request-uat-promotion.yml |
revique-api/ci.yml, request-uat-promotion.yml | Rapid develop pushes queue multiple full CI runs; rapid promotion triggers can create duplicate promotion PRs |
| MEDIUM | CI Docker image discarded — deploy.yml independently rebuilds from source, so the tested and deployed artifacts may differ |
revique-api/ci.yml, revique-api/deploy.yml | Doubles build time; introduces risk that deploy builds a different image than the one tested in CI |
| MEDIUM | No test coverage reporting or coverage artifact upload | revique-api/ci.yml | Coverage regressions go unnoticed; no coverage trend data for code review decisions |
| LOW | No reusable workflow despite 3 near-identical deploy workflows in revique-web | deploy-develop.yml, deploy-production.yml, deploy-uat.yml | Maintenance overhead: fixes or improvements to the shared deploy pattern must be applied to 3 separate files |
| LOW | No path filters on deploy-develop.yml — every develop push triggers a full Cloudflare deploy even for docs-only changes |
deploy-develop.yml | Minor: unnecessary deploys waste CI minutes and Cloudflare deploy quota |
| LOW | No documentation on whether GitHub environment protection rules (required reviewers) are actually configured for uat and production environments |
deploy-uat.yml, deploy-production.yml | The environment: declaration enables protection but does not enforce it — environments may be unprotected at the org level |
Performance Analysis
Estimated Run Time Inefficiencies
| Workflow | Current Issue | Estimated Waste | Fix |
|---|---|---|---|
| deploy-production.yml | Duplicate setup-node call (step 6) | ~30s per run | Remove "Setup Node for Wrangler" step |
| deploy-uat.yml | Duplicate setup-node call in deploy job | ~30s per run | Remove second setup-node step |
| revique-api/ci.yml | No concurrency — queued runs on rapid pushes to develop | Multiple full CI runs (~5–10 min each) per fast-push burst | Add concurrency: group: ci-${{ github.ref }}, cancel-in-progress: true |
| revique-api/deploy.yml | Docker image rebuilt from source independently of CI | ~2–5 min per deploy (duplicate build) | Publish CI image to ECR; deploy.yml pulls the pre-built, pre-tested image |
| request-uat-promotion.yml | Full history clone (fetch-depth: 0) for all promotions |
Variable — grows with repo history size | Use fetch-depth: 200 as a generous upper bound unless promotions routinely exceed 200 commits |
| deploy-develop.yml | No path filters — deploys on docs-only or config-only pushes | ~3–5 min per unnecessary deploy | Add paths-ignore: ['**.md', 'docs/**'] |
Prioritized Recommendations
C1 — Pin third-party actions to commit SHAs
Problem: cloudflare/wrangler-action@v3 and aws-actions/configure-aws-credentials@v4 reference mutable version tags. A compromised publisher account could retag v3/v4 to point to malicious code that exfiltrates your CLOUDFLARE_API_TOKEN and AWS OIDC credentials.
Why dangerous: These actions run in your CI environment with full access to all workflow secrets. This is one of the most common supply-chain attack vectors for GitHub Actions.
# Instead of (mutable — dangerous for third parties):
uses: cloudflare/wrangler-action@v3
uses: aws-actions/configure-aws-credentials@v4
# Pin to a specific commit SHA (verify from the action's GitHub releases):
uses: cloudflare/wrangler-action@392e85aa28f1ef5bbe8bee4cecc4ab4c4f73f66f # v3.14.1
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
# GitHub-owned actions (actions/checkout, actions/setup-node) are lower risk
# but can also be pinned for full supply-chain control:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
C2 — Add permissions block to revique-api/ci.yml
Problem: ci.yml has no permissions: declaration. GitHub's default grants the GITHUB_TOKEN write access to contents, issues, pull-requests, checks, and more. A compromised action or script injection can write to the repo or approve PRs.
name: CI
on:
pull_request:
branches: [develop]
push:
branches: [develop]
permissions:
contents: read # checkout only — no writes needed
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
# ... existing steps unchanged
C3 — Remove hardcoded infrastructure fallback values from workflow env blocks
Problem: deploy-develop.yml, deploy-uat.yml, and deploy-production.yml embed live infrastructure identifiers as YAML fallbacks: AWS API Gateway endpoints, Cognito Identity Pool IDs, IoT MQTT broker addresses, and reCAPTCHA site keys. These are committed to version control.
Fix: Remove all || 'hardcoded-value' fallbacks. Require values to be present in the GitHub environment. Fail fast with an error message if a required variable is absent.
# Before (exposes infrastructure in YAML):
env:
VITE_BASE_URL: ${{ vars.VITE_BASE_URL_DEV || vars.VITE_BASE_URL || 'https://atg96ts3g3.execute-api.us-east-2.amazonaws.com/v1' }}
REACT_APP_IDENTITY_POOL_ID: ${{ vars.REACT_APP_IDENTITY_POOL_ID || 'us-east-2:1b4b834c-d3d6-4ec1-a247-3084a6570e4d' }}
# After (clean — all values in GitHub environment variables):
env:
VITE_BASE_URL: ${{ vars.VITE_BASE_URL_DEV || vars.VITE_BASE_URL }}
REACT_APP_IDENTITY_POOL_ID: ${{ vars.REACT_APP_IDENTITY_POOL_ID }}
# Add a validation step right after checkout:
- name: Validate required environment variables
run: |
: "${VITE_BASE_URL:?Set VITE_BASE_URL in the GitHub develop environment}"
: "${REACT_APP_IDENTITY_POOL_ID:?Set REACT_APP_IDENTITY_POOL_ID in the GitHub environment}"
: "${REACT_APP_IOT_ENDPOINT:?Set REACT_APP_IOT_ENDPOINT in the GitHub environment}"
H1 — Add npm audit to all CI and deploy workflows
Problem: No dependency vulnerability scanning in any workflow. Known CVEs ship to production.
# Add after the Install step in every workflow:
# For revique-api (no legacy-peer-deps):
- name: Audit dependencies
run: npm audit --audit-level=high
# For revique-web (uses --legacy-peer-deps):
- name: Audit dependencies
run: npm audit --audit-level=high --legacy-peer-deps
H2 — Add Trivy container image scan to revique-api/ci.yml
Problem: Docker image is built but never scanned. OS package vulnerabilities in the base image reach production undetected.
- name: Build Docker image
run: docker build --tag revique-api:ci .
- name: Scan container image with Trivy
uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # v0.24.0
with:
image-ref: revique-api:ci
format: table
exit-code: '1'
severity: CRITICAL,HIGH
ignore-unfixed: true
H3 — Add lint/typecheck gate to revique-web deploy workflows
Problem: revique-web deploys to develop, UAT, and production without running any code quality checks. revique-api correctly gates on lint + typecheck + tests before deploying.
# Add between "Install dependencies" and "Build composed app" in all three deploy workflows:
- name: Lint
run: npm run lint
- name: Typecheck
run: npm run typecheck
# Uncomment when tests are added:
# - name: Test
# run: npm test
H4 — Fix revique-api deploy.yml Slack webhook routing for production
Problem: All 3 environments share SLACK_WEBHOOK_DEV_GITHUB_ACTIONS. Production deploy failures arrive in the dev channel, not the prod monitoring channel.
# In deploy.yml env block for both Slack notification steps:
env:
SLACK_WEBHOOK_URL: ${{ inputs.environment == 'prod' && secrets.SLACK_WEBHOOK_PROD_GITHUB_ACTIONS || secrets.SLACK_WEBHOOK_DEV_GITHUB_ACTIONS }}
# Add SLACK_WEBHOOK_PROD_GITHUB_ACTIONS to the prod GitHub environment secrets.
M1 — Add timeout-minutes to all jobs
Current state: No job defines a timeout. GitHub's default is 6 hours. A hung Cloudflare deploy or stalled ECS migration blocks the concurrency slot for 6 hours.
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 30 # deploy workflows: 30-45 min is generous
verify:
runs-on: ubuntu-latest
timeout-minutes: 20 # CI: lint+test+docker should finish in 20 min
M2 — Remove duplicate setup-node calls from deploy-production.yml and deploy-uat.yml
Current state: Both workflows call actions/setup-node@v4 twice. The second "Setup Node for Wrangler" call switches to Node 22 (overriding .nvmrc) and does not restore npm cache. Wrangler runs fine with the Node version already set from .nvmrc.
# Remove this block from both deploy-production.yml and deploy-uat.yml:
# - name: Setup Node for Wrangler
# uses: actions/setup-node@v4
# with:
# node-version: 22
# The first setup-node with node-version-file: .nvmrc is sufficient.
M3 — Add concurrency to ci.yml and request-uat-promotion.yml
# For revique-api/ci.yml — cancel superseded runs on same branch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
# For request-uat-promotion.yml — prevent duplicate promotion PRs:
concurrency:
group: uat-promotion-${{ inputs.source_branch }}-${{ inputs.target_branch }}
cancel-in-progress: false # let the running promotion complete
QW1 — Add gitleaks secret scanning to CI workflows (copy-paste ready)
# Add as first step after checkout in ci.yml and as a pre-deploy step in revique-web:
- name: Scan for secrets
uses: gitleaks/gitleaks-action@cb7149a9b57195b609c63e8518d2b7e1a8b32c8e # v2.3.7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # optional for org key
QW2 — Add path filters to deploy-develop.yml to skip non-code pushes
on:
push:
branches: [develop]
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/CODEOWNERS'
- '.gitignore'
workflow_dispatch:
QW3 — Extract revique-web deploy into a reusable workflow
Create .github/workflows/_deploy-cloudflare.yml called by all three deploy workflows. Eliminates the 3× maintenance burden:
# .github/workflows/_deploy-cloudflare.yml
on:
workflow_call:
inputs:
environment: { required: true, type: string }
wrangler_env: { required: false, type: string, default: '' }
deploy_url: { required: true, type: string }
secrets:
CLOUDFLARE_API_TOKEN: { required: true }
CLOUDFLARE_ACCOUNT_ID: { required: true }
SLACK_WEBHOOK_URL: { required: true }
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
timeout-minutes: 30
permissions:
contents: read
concurrency:
group: deploy-${{ inputs.environment }}
cancel-in-progress: false
steps:
- uses: actions/checkout@SHA # pinned
# ... shared steps ...
- uses: cloudflare/wrangler-action@SHA # pinned
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: >-
deploy ${{ inputs.wrangler_env != '' && format('--env {0}', inputs.wrangler_env) || '' }}
QW4 — Enable GitHub's built-in dependency review on pull requests
Add this free, zero-configuration workflow to both repos. It blocks PRs that introduce known vulnerable dependencies:
# .github/workflows/dependency-review.yml
name: Dependency Review
on:
pull_request:
branches: [develop, uat, main]
permissions:
contents: read
pull-requests: write
jobs:
dependency-review:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@SHA # pinned
- uses: actions/dependency-review-action@SHA # pinned
with:
fail-on-severity: high
comment-summary-in-pr: true
Consolidated Recommendations
Critical (Address Immediately)
| # | Repository | Issue | Action |
|---|---|---|---|
| 1 | Both repos | Third-party actions not pinned to commit SHAs | Pin cloudflare/wrangler-action and aws-actions/configure-aws-credentials to specific commit SHAs. See snippet S1. |
| 2 | revique-api | ci.yml missing permissions block — GITHUB_TOKEN defaults to write | Add permissions: contents: read at the workflow level. See snippet S2. |
| 3 | revique-web | Hardcoded infrastructure fallback values in workflow YAML | Remove all || 'hardcoded-value' fallbacks. Require vars from GitHub environments. See snippet S3. |
| 4 | Both repos | No branch protection on any branch | Enable required PR reviews + CI status checks on main, develop, uat. Prevent force-push. |
High Priority (Address Within 2 Weeks)
| # | Repository | Action |
|---|---|---|
| 5 | Both repos | Add npm audit to all CI and deploy workflows. See snippet S5. |
| 6 | revique-api | Add Trivy container image scan after docker build. See snippet S4. |
| 7 | Both repos | Add gitleaks secret scanning as a first CI step. See snippet S7. |
| 8 | revique-web | Add lint + typecheck gate to all three deploy workflows. See snippet S6. |
| 9 | revique-api | Fix Slack webhook routing — use prod webhook for production deploys. See snippet S8. |
| 10 | Both repos | Add CodeQL SAST workflow for static security analysis. See snippet S10. |
Medium Priority (Address Within 1 Month)
| # | Repository | Action |
|---|---|---|
| 11 | Both repos | Add timeout-minutes to all jobs. Remove duplicate setup-node. See snippet S9. |
| 12 | revique-api | Add concurrency block to ci.yml. See snippet S2. |
| 13 | Both repos | Enable Dependabot for npm dependencies (GitHub Settings → Security). |
| 14 | Both repos | Add GitHub dependency-review action on PRs. See snippet S11. |
| 15 | revique-web | Convert 39 TODO/FIXME comments to tracked GitHub Issues. |
| 16 | revique-web | Add CONTRIBUTING.md, SECURITY.md, and LICENSE file. |
Low Priority / Long-term
| # | Repository | Action |
|---|---|---|
| 17 | revique-web | Introduce unit/integration tests using Vitest. Add to deploy workflows once available. |
| 18 | revique-api | Publish CI Docker image to ECR — deploy.yml pulls pre-built image instead of rebuilding. |
| 19 | revique-api | Split monolithic CI verify job into parallel lint/test/build jobs. See snippet S13. |
| 20 | revique-web | Extract reusable _deploy-cloudflare.yml workflow. Prune 68 stale branches. |
Methodology & Limitations
Data Sources
- GitHub REST API v3 (authenticated read-only access)
- Local shallow clones (
--depth 1) for file-level analysis - Static analysis (grep-based pattern matching)
API Endpoints Used
GET /repos/ReviqueInc/{name}— basic metadataGET /repos/ReviqueInc/{name}/branches— branch listGET /repos/ReviqueInc/{name}/commits— latest commit infoGET /repos/ReviqueInc/{name}/contributors— contributor listGET /repos/ReviqueInc/{name}/contents/.github/workflows— workflow filesGET /repos/ReviqueInc/{name}/actions/runs— CI/CD run historyGET /repos/ReviqueInc/{name}/issues— open issuesGET /repos/ReviqueInc/{name}/pulls— open pull requestsGET /repos/ReviqueInc/{name}/branches/{branch}/protection— branch protectionGET /repos/ReviqueInc/{name}/dependabot/alerts— security alertsGET /repos/ReviqueInc/{name}/contents/{file}— file existence checksGET /repos/ReviqueInc/{name}/topics— repository topics
Local Analysis Performed
- File type distribution (find + extension analysis)
- Test file count (*.test.*, *.spec.*, __tests__)
- TODO/FIXME/HACK grep across JS/TS source (excluding node_modules)
- Config file presence (.eslintrc, .prettierrc, .editorconfig, husky)
- Documentation file presence (README, CONTRIBUTING, LICENSE, SECURITY, CHANGELOG)
- Secret pattern scanning (iE regex — values redacted, only file paths reported)
- Directory structure (maxdepth 3)
- Git commit count via rev-list
Limitations
- Shallow clone (
--depth 1) means commit history metrics show "1 commit" locally — actual commit history is available via API - Commit activity statistics endpoint returned computing/no-data for repos — GitHub caches these asynchronously
- Branch protection check returned "Not Found" for all repos — this indicates protection is NOT configured (the API returns 404 when no protection exists, not an access error)
- Dependabot alerts: disabled for active repos; unavailable for archived repos
revique-webcontributors API returned 0 — likely due to the repo being very new and contributor stats still computing, or commits being authored via token identities- npm outdated analysis was not run to avoid network overhead in CI; dependency version evaluation was done via package.json inspection