Executive Summary

Active Repository Portfolio Health
72
/ 100

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.

2
Total Active Repos
6
GitHub Actions Workflows
0/2
Branch Protection
0/2
Dependabot Enabled
2/2
CI/CD Workflows
1/2
Tests in CI
0/6
SHA-Pinned Actions
39
TODOs/FIXMEs
🔴 Top Critical Issues
  1. 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.

  2. 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.

  3. 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.

  4. No branch protection on main, develop, or uat branches

    Both repos allow direct force-pushes. No required reviews or CI status checks before merge.

  5. 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.

🟢 Top Quick Wins
  1. Add permissions: contents: read to revique-api/ci.yml

    One-line fix that immediately reduces the blast radius of any compromised CI step.

  2. Add timeout-minutes: 30 to all 6 workflow jobs

    Prevents runaway deploys from holding the concurrency slot for 6 hours.

  3. 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.

  4. Enable Dependabot on both repositories

    One-click in GitHub Settings → Security → Dependabot. Adds automated CVE alerts for npm dependencies.

  5. 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 PRIMARY

Parallel Revique web app — modern React/TypeScript frontend hosted on Cloudflare Workers

Language: JavaScript/TypeScript Default Branch: main Branches: 68 Last Push: 2026-05-08 Size: 4,266 KB
1. Repository Overview & Metadata
Active
Status
68
Branches
7
Open PRs
831
Total Files
PropertyValue
FrameworkReact 19 Vite 5 TypeScript 5.5
UI LibraryChakra UI v3 Framer Motion
DeploymentCloudflare Workers Static Assets
Branch Flowfeature/* → develop → uat → main
Created2026-05-01
Last Updated2026-05-08 (today)
Stars1
PrivateYes
Topics/TagsNone configured
WikiDisabled
68 branches is very high for a single repository. Many are Codex-generated feature branches (RWA-549 through RWA-608) and batch branches that should be pruned after merging.
2. CI/CD & Workflows
revique-web is the only repository with GitHub Actions workflows configured. 349 total runs recorded, all recent runs successful.
Workflow FileTriggerTargetStatus
deploy-develop.ymlPush to develop, manualCloudflare develop envActive / Passing
deploy-uat.ymlPush to uat, manual (with ref input)Cloudflare UAT envActive
deploy-production.ymlManual only (requires ref input)Cloudflare productionActive
request-uat-promotion.ymlManual (source/target branch inputs)PR creation + SlackActive

Recent Run Activity (last 20 runs)

Branch Commit Notify
16 runs
100% ✓
Deploy Develop
4 runs
100% ✓
Gap: No automated test runner in CI pipeline. Workflows deploy directly without a lint/test gate. Recommend adding an npm run lint and test step before deploy jobs.
Gap: Production deploy is manual-only (good for safety), but there is no automated smoke test or rollback step configured.
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 #TitleAuthorOpened
#91Batch develop merge 20260508-0544farhan-revique2026-05-08
#90RWA-608: Restore child appointment service listfarhan-revique2026-05-08
#89RWA-607: Autofill appointment duration from selected servicefarhan-revique2026-05-08
#42RWA-568: Open no-show reschedule in appointment drawerfarhan-revique2026-05-07
#41RWA-566: Harden schedule checkout handofffarhan-revique2026-05-07
#25RWA-554: Enable Add Notes savefarhan-revique2026-05-06
#20RWA-549: Add transaction history actionsfarhan-revique2026-05-06
Critical: No branch protection rules on 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.
PRs #20 and #25 have been open for 2+ days. Consider setting a SLA for PR review turnaround.
4. Security & Dependencies
Dependabot disabled. With 27 runtime dependencies and 21 devDependencies, automated vulnerability scanning is essential and currently absent.

Runtime Dependencies (27)

PackageVersion SpecCategory
react / react-dom^19Core Framework
@chakra-ui/react^3.19.1UI Library
axios^1.9.0HTTP Client
react-router-dom^7.5.2Routing
react-hook-form^7.56.1Forms
dayjs^1.11.13Date/Time
framer-motion^12.9.2Animation
xlsx^0.18.5Excel Export
jspdf / jspdf-autotable^3.0.1 / ^5.0.2PDF Generation
recharts^2.15.3Charts
styled-components^6.4.1CSS-in-JS
react-payment-inputs^1.2.0Payment UI
@react-pdf/renderer^4.3.0PDF Rendering
vite-plugin-pwa^1.0.1PWA Support
Note: 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

No hardcoded secrets detected in .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 — verify prepare script 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, types
  • legacy-admin/ — embedded legacy admin module
  • docs/ — internal documentation directory
  • scripts/ — build/utility scripts

TODO/FIXME/HACK Distribution

39 TODO/FIXME/HACK annotations found in JS/TS source files. These should be tracked as GitHub Issues rather than inline comments to prevent technical debt accumulation.

Recommendations

PriorityAction
HIGHEnable branch protection on main, develop, and uat branches
HIGHEnable Dependabot for npm dependencies
MEDAdd a test step to CI pipeline (even basic lint check gates)
MEDAdd LICENSE file (MIT or Apache recommended for internal clarity)
MEDPrune merged/stale branches — 68 is excessive
LOWAdd repository topics/tags
LOWTrack TODOs as GitHub Issues

revique-api

ACTIVE BACKEND

TypeScript Node.js REST API — containerised and deployed to AWS ECS/Fargate via AWS CDK

Language: TypeScript / Node.js Default Branch: develop Deployment: AWS ECS Fargate + CDK Workflows: 2 (ci.yml, deploy.yml)
1. Repository Overview & Stack
Active
Status
2
Workflows
Yes
Tests in CI
AWS
Cloud Provider
PropertyValue
RuntimeNode.js (TypeScript — transpiled to dist/)
InfrastructureAWS CDK (CloudFormation stacks)
ComputeAWS ECS Fargate
DatabaseAWS Aurora Serverless (RDS)
AuthOIDC → AWS STS (no long-lived keys stored in GitHub)
MigrationsRun as ECS one-shot task post-deploy
DockerDockerfile present — image built in CI
Environmentsdev / uat / prod (GitHub Environments)
Branch Flowfeature/* → develop (CI) → manual deploy to dev/uat/prod
2. CI/CD Workflows
Workflow FileTriggerPurposeStatus
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
Strengths: OIDC for AWS auth (no static credentials), full test gate before deploy, ECS migration verification with exit-code check, per-environment concurrency control.
Gaps: No 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 audit step
  • No timeout on any job
4. Recommendations
PriorityAction
CRITICALAdd permissions: contents: read to ci.yml
CRITICALPin aws-actions/configure-aws-credentials to a commit SHA
HIGHAdd container image scan with Trivy after docker build in ci.yml
HIGHAdd npm audit --audit-level=high to ci.yml and deploy.yml
HIGHFix Slack webhook — prod deploys should use a prod webhook, not dev
MEDIUMAdd concurrency: to ci.yml to cancel superseded runs
MEDIUMAdd timeout-minutes: 30 to all jobs
MEDIUMPublish CI Docker image to ECR; deploy.yml should pull it instead of rebuilding
LOWEnable Dependabot for npm dependencies
LOWAdd branch protection rules on develop

Pipeline Analysis — revique-web

4 WORKFLOWS

Detailed breakdown of every workflow file, jobs, steps, and issues found

deploy-develop.yml — Deploy to Cloudflare Develop

Triggers

pushdevelop branch
workflow_dispatchManual (no inputs)
Path filtersNone — all pushes trigger deploy

Configuration

Runnerubuntu-latest
Environmentdevelop
Concurrency✓ deploy-develop, cancel-in-progress: true
TimeoutNot set
Permissionscontents: read

Steps

#Step NameAction / CommandNotes
1Checkoutactions/checkout@v4
2Resolve deployment commitgit rev-parse HEADSets sha + short_sha outputs
3Setup Nodeactions/setup-node@v4Reads .nvmrc · npm cache ✓
4Install dependenciesnpm ci --legacy-peer-deps
5Build composed appnpm run build:composed
6Notify Slack — active.github/scripts/notify-slack-deployment.shcontinue-on-error: true
7Deploy to Cloudflare Workerscloudflare/wrangler-action@v3--env develop
8Notify Slack — result.github/scripts/notify-slack-deployment.shif: always()

Actions Used

ActionVersionPublisherSHA Pinned?
actions/checkout@v4GitHubTag only
actions/setup-node@v4GitHubTag only
cloudflare/wrangler-action@v3Cloudflare (3rd party)NOT pinned ⚠

Secrets Used

  • SLACK_WEBHOOK_DEV_GITHUB_ACTIONS
  • CLOUDFLARE_API_TOKEN
  • CLOUDFLARE_ACCOUNT_ID

Issues Found

SeverityIssue
CRITICALcloudflare/wrangler-action@v3 not pinned to commit SHA — supply chain attack risk
CRITICALHardcoded fallback values in env block: AWS endpoints, Cognito IDs, IoT URLs, reCAPTCHA keys committed in YAML
HIGHNo test gate — deploys without lint, typecheck, or tests
HIGHNo dependency scan (npm audit)
MEDIUMNo timeout-minutes — job can run up to 6 hours if Cloudflare deploy hangs
LOWNo path filters — deploys on docs-only commits too
deploy-production.yml — Manual Production Deploy

Triggers

workflow_dispatchManual only
Input: refBranch, tag, or SHA to deploy (required, default: main)

Configuration

Runnerubuntu-latest
Environmentproduction
Concurrency✓ deploy-production, cancel-in-progress: false
TimeoutNot set
Permissionscontents: read

Steps

#Step NameAction / CommandIssue
1Checkoutactions/checkout@v4
2Resolve deployment commitgit rev-parse
3Setup Nodeactions/setup-node@v4 (.nvmrc, npm cache)
4Install dependenciesnpm ci --legacy-peer-deps
5Build composed appnpm run build:composed
6Setup Node for Wrangleractions/setup-node@v4 (node 22)DUPLICATE — wastes ~30s
7Notify Slack — activenotify-slack-deployment.sh
8Deploy to Cloudflare Workerscloudflare/wrangler-action@v3
9Notify Slack — resultnotify-slack-deployment.sh
Good: Manual-only trigger prevents accidental production deploys. cancel-in-progress: false prevents concurrent prod deployments.
Issues: No test gate. Duplicate setup-node call overwrites Node version. Hardcoded env fallbacks. Unpinned cloudflare action.
deploy-uat.yml — UAT Deploy with Approval Gate

Triggers

pushuat branch
workflow_dispatchOptional ref input (default: uat)

Jobs

request-approvalNotify Slack, await environment gate
deployBuild + deploy to Cloudflare UAT
Strength: Two-job structure with environment: uat enables GitHub environment protection rules (required reviewers, wait timers). Best deployment gate pattern in revique-web.
Issue: Duplicate 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_branchBranch to promote from (default: develop)
target_branchBranch to promote to (default: uat)
post_slackPost Slack notification (boolean, default: true)

Configuration

Environmentcodex-full-access
Permissionscontents: read, pull-requests: write
ConcurrencyNOT 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
Strengths: Least-privilege permissions. Token validation before use. Bash uses set -euo pipefail. Smart auto-detection of sensitive file changes.
Issue: No concurrency block — rapid double-trigger could create duplicate promotion PRs.

Pipeline Analysis — revique-api

2 WORKFLOWS

Detailed breakdown of every workflow file, jobs, steps, and issues found

ci.yml — Continuous Integration

Triggers

pull_requestTargeting develop
pushTo develop
Path filtersNone

Configuration

Runnerubuntu-latest
PermissionsMISSING — default over-broad
ConcurrencyNOT set
TimeoutNot set
MatrixNone

Steps

#StepCommandNotes
1Checkoutactions/checkout@v4
2Setup Nodeactions/setup-node@v4Reads .nvmrc · npm cache ✓
3Installnpm ci
4Lintnpm run lint✓ Quality gate
5Typechecknpm run typecheck✓ Quality gate
6Testnpm test✓ Quality gate
7Buildnpm run build
8Synthesize infrastructurenpm run infra:synth✓ CDK synthesis
9Build Docker imagedocker build --tag revique-api:ci .Image discarded after job

Issues Found

SeverityIssue
CRITICALNo permissions: block — GITHUB_TOKEN has default write access to contents, issues, pull-requests
HIGHDocker image built but not scanned — OS/package vulnerabilities undetected
HIGHNo npm audit step — known CVEs in dependencies ship undetected
MEDIUMNo concurrency: — rapid pushes queue multiple full CI runs (~5-10 min each)
MEDIUMDocker image discarded — deploy.yml rebuilds independently (tested ≠ deployed artifact)
MEDIUMNo timeout — job can run up to 6 hours if Docker build hangs
LOWNo test coverage artifact upload — coverage trends invisible
deploy.yml — Multi-Environment Deploy (CDK + ECS + Migrations)

Triggers

workflow_dispatchManual only
Input: environmentdev / uat / prod (required)
Input: aws_regionAWS region (required, default: us-east-1)

Configuration

Runnerubuntu-latest
Permissionscontents: read · id-token: write
Concurrency✓ per-environment group
AWS Auth✓ OIDC — no static keys
TimeoutNot set

Steps

#StepNotes
1Checkout
2Resolve deployment commitsha + short_sha
3Notify Slack — activecontinue-on-error: true
4Setup Node + npm cache
5Install (npm ci)
6Lint ✓Pre-deploy gate
7Typecheck ✓Pre-deploy gate
8Test ✓Pre-deploy gate
9Build ✓
10Validate AWS role configuredExits early if AWS_ROLE_TO_ASSUME is empty ✓
11Configure AWS credentialsaws-actions/configure-aws-credentials@v4 (OIDC) ✓
12Synthesize infrastructurenpm run infra:synth
13Deploy infrastructure + servicenpm run infra:deploy (CDK)
14Run DB migrationsECS run-task → wait → check exit code ✓
15Notify Slack — resultif: always()
Best practices found: OIDC auth (no long-lived credentials), full quality gate before deploy, AWS role validation before AWS calls, ECS migration with exit code verification.

Issues Found

SeverityIssue
CRITICALaws-actions/configure-aws-credentials@v4 not pinned to commit SHA — this action has direct AWS account access
HIGHAll environments (dev/uat/prod) use SLACK_WEBHOOK_DEV_GITHUB_ACTIONS — prod failures go to dev channel
HIGHNo npm audit step before deploying to production
MEDIUMNo timeout — ECS migration task could hang indefinitely
LOWDocker image rebuilt from source independently of CI (tested artifact may differ from deployed artifact)

Speed & Security Improvement Plan

20 IMPROVEMENTS

Prioritised action plan for both repos — with ready-to-paste YAML snippets

Speed Improvements

Priority Issue Applies To Current State Fix Expected Gain
P1 No concurrency on ci.yml revique-api Rapid pushes queue multiple full CI runs in parallel Add concurrency: with cancel-in-progress: true Eliminate redundant 5-10 min CI runs per push burst
P2 Duplicate setup-node calls revique-web (prod & UAT) setup-node called twice per deploy — second call overrides Node version and discards npm cache Remove "Setup Node for Wrangler" step ~30s saved per deploy run
P2 Docker image rebuilt on every deploy revique-api CI builds image then discards it; deploy.yml rebuilds from source Push CI image to ECR; deploy pulls pre-built image ~2-5 min saved per deploy
P3 No path filters on deploy-develop.yml revique-web Docs-only or README-only commits trigger a full Cloudflare deploy Add paths-ignore: ['**.md', 'docs/**'] Eliminates unnecessary ~3-5 min deploys
P3 Full clone for uat-promotion.yml revique-web fetch-depth: 0 clones entire repo history for every promotion Use fetch-depth: 200 (generous upper bound) Faster checkout, especially as repo grows
P3 Jobs could be split for parallelism revique-api CI Lint, typecheck, test all run sequentially in one job Split into parallel jobs: lint+typecheck vs test vs build ~2-4 min faster CI on multi-core runners
P4 No timeouts — jobs can hang 6 hours All 6 workflows No timeout-minutes set on any job Add timeout-minutes: 20-30 per job Frees concurrency slots faster on failures

Security Improvements

Severity Issue Applies To Risk Fix
CRITICAL Third-party actions not pinned to SHA All workflows Supply chain attack — compromised tag runs malicious code with your secrets Pin cloudflare/wrangler-action and aws-actions to commit SHAs
CRITICAL Missing permissions block on ci.yml revique-api/ci.yml GITHUB_TOKEN has write access — any step can push code or approve PRs Add permissions: contents: read
CRITICAL Hardcoded infra values in env fallbacks revique-web 3 deploy workflows AWS endpoints, Cognito IDs, IoT URLs committed in plain YAML Remove fallbacks — require vars to be set in GitHub environments
HIGH No SAST in any workflow Both repos Security vulnerabilities in code not caught before deployment Add CodeQL analysis workflow
HIGH No dependency vulnerability scan Both repos Known CVEs in npm packages ship to production Add npm audit --audit-level=high to every CI/deploy workflow
HIGH No container image scan revique-api/ci.yml OS-level CVEs in Docker base image reach ECS/Fargate Add Trivy scan after docker build step
HIGH No secret scanning Both repos Accidentally committed tokens/keys go to production Add gitleaks step to CI workflows
HIGH revique-web deploys without tests 3 revique-web deploy workflows Broken code ships to all environments if build passes Add lint + typecheck steps before build in all 3 deploy workflows
HIGH Wrong Slack webhook for prod deploys revique-api/deploy.yml Production failures silently go to dev channel — on-call misses alerts Use prod webhook when environment == prod
MEDIUM No branch protection on any branch Both repos Anyone can force-push to main/develop without review GitHub Settings: enable required reviews + status checks
MEDIUM No Dependabot configured Both repos Vulnerable npm packages accumulate silently GitHub Settings → Security → Dependabot alerts (one click)
MEDIUM No environment protection rules confirmed revique-web UAT/prod environment: declarations exist but reviewers may not be configured GitHub Settings → Environments → add required reviewers
LOW No reusable workflow for 3 identical web deploys revique-web Security fixes must be applied to 3 separate files Extract _deploy-cloudflare.yml reusable workflow

Ready-to-Use Code Snippets

CRITICAL S1 — Pin Third-Party Actions to Commit SHA

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.

all deploy workflows
# 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
CRITICAL S2 — Add Permissions + Concurrency to revique-api/ci.yml

Add at the workflow level (before the jobs block). Fixes the over-broad GITHUB_TOKEN and prevents queued duplicate runs.

revique-api / ci.yml — add at top-level
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
CRITICAL S3 — Remove Hardcoded Env Fallbacks in revique-web Deploys

Move all infrastructure values to GitHub environment variables. Add a validation step to fail fast if a required variable is not configured.

revique-web / deploy-develop.yml — replace env block + add validation step
# 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}"
HIGH S4 — Add Trivy Container Scan to revique-api CI
revique-api / ci.yml — add after docker build step
- 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
HIGH S5 — Add npm audit to All Workflows
all workflows — add after Install step
# 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
HIGH S6 — Add Test Gate to revique-web Deploy Workflows
revique-web / deploy-develop.yml, deploy-uat.yml, deploy-production.yml — add before Build step
- 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
HIGH S7 — Add gitleaks Secret Scanning
both repos / ci.yml — add as first step after Checkout
- 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 }}
HIGH S8 — Fix Production Slack Webhook in revique-api deploy.yml
revique-api / deploy.yml — update SLACK_WEBHOOK_URL in both notification steps
# 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.
MEDIUM S9 — Add Timeouts and Remove Duplicate setup-node
all workflows — jobs block
# 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
MEDIUM S10 — Add CodeQL SAST Analysis Workflow

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.

.github/workflows/codeql.yml — add to both repos
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 }}"
MEDIUM S11 — Add Dependency Review on Pull Requests (Free, Zero Config)
.github/workflows/dependency-review.yml — add to both repos
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
LOW S12 — Add Path Filters to deploy-develop.yml
revique-web / deploy-develop.yml — update the on: block
on: push: branches: [develop] paths-ignore: - '**.md' - 'docs/**' - '.github/CODEOWNERS' - '.gitignore' workflow_dispatch: # manual trigger always runs regardless of paths
LOW S13 — Parallel CI Jobs for revique-api (Speed)

Split the monolithic verify job into parallel jobs. Saves 2-4 minutes on each CI run.

revique-api / ci.yml — replace single job with parallel jobs
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
🔒 GitHub Settings (Not Workflow) — Branch Protection

These settings are configured in GitHub repository Settings, not in workflow YAML files.

SettingWhereRecommended Value
Require PR before mergingSettings → Branches → main, develop, uatEnabled · Required approvals: 1
Require status checks to passSettings → Branches (same rule)Add CI workflow as required check
Restrict force-pushSettings → Branches → Do not allow force pushesEnabled on main and uat
Environment protection reviewersSettings → Environments → uat, productionAdd 1+ required reviewers
Dependabot alertsSettings → Security → Dependabot alertsEnabled on both repos
Dependabot auto-updatesSettings → Security → Dependabot version updatesEnabled · weekly schedule

GitHub Actions Deep Analysis

6 WORKFLOWS 20 ISSUES FOUND

Comprehensive audit of all CI/CD pipelines across revique-web and revique-api

Repos Analyzed: revique-web, revique-api Workflow Files: 6 Analysis Date: 2026-05-15
6
Total Workflows
3
Critical Issues
6
High Issues
5
Medium Issues
6
Quick Wins
4/6
Have Concurrency
5/6
Have Permissions
0/6
SHA-Pinned Actions
Workflow Summary Table
RepoFilePurposeTriggersJobs CachingSlackPermissions BlockSecurity ScoreHealth
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

Runnerubuntu-latest
Environmentdevelop
TimeoutNot set
Concurrencygroup: deploy-develop, cancel-in-progress: true

Triggers

  • push to develop branch
  • workflow_dispatch (manual)

Path / Tag Filters

None — all pushes to develop trigger a deploy regardless of what changed

Steps (in order)

#StepAction / CommandNotes
1Checkoutactions/checkout@v4
2Resolve deployment commitgit rev-parse HEAD / --shortOutputs sha, short_sha
3Setup Nodeactions/setup-node@v4Reads .nvmrc, npm cache ✓
4Install dependenciesnpm ci --legacy-peer-deps
5Build composed appnpm run build:composed
6Notify Slack (active)notify-slack-deployment.shcontinue-on-error: true
7Deploy to Cloudflare Workerscloudflare/wrangler-action@v3command: deploy --env develop
8Notify Slack (result)notify-slack-deployment.shif: always(), continue-on-error: true

Actions & Versions

ActionVersion UsedPublisherSHA-Pinned?
actions/checkout@v4GitHub (trusted)Tag only
actions/setup-node@v4GitHub (trusted)Tag only
cloudflare/wrangler-action@v3Cloudflare (3rd party)NOT pinned ⚠

Secrets Referenced

  • SLACK_WEBHOOK_DEV_GITHUB_ACTIONS
  • CLOUDFLARE_API_TOKEN
  • CLOUDFLARE_ACCOUNT_ID
Hardcoded Infrastructure Fallbacks: env vars use || '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.
No Test Gate: Code deploys to Cloudflare without running lint, typecheck, or tests. A broken build goes straight to the develop environment.
No Timeout: If the Cloudflare deploy hangs, the job occupies the concurrency slot for up to 6 hours.
revique-web / deploy-production.yml — Deploy Production

Basic Info

Runnerubuntu-latest
Environmentproduction
TimeoutNot set
Concurrencygroup: 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)

#StepAction / CommandNotes
1Checkoutactions/checkout@v4Uses inputs.ref
2Resolve deployment commitgit rev-parse
3Setup Nodeactions/setup-node@v4Reads .nvmrc, npm cache ✓
4Install dependenciesnpm ci --legacy-peer-deps
5Build composed appnpm run build:composed
6Setup Node for Wrangleractions/setup-node@v4DUPLICATE — node 22, no cache
7Notify Slack (active)notify-slack-deployment.shcontinue-on-error: true
8Deploy to Cloudflare Workerscloudflare/wrangler-action@v3no --env flag (defaults to production)
9Notify Slack (result)notify-slack-deployment.shif: always()
Duplicate setup-node: Step 6 re-runs 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.
No Test Gate: Production deploy runs without lint, typecheck, or tests. A bad ref input would ship broken code directly to production.
Good Practice: Manual-only trigger with mandatory ref input. cancel-in-progress: false prevents concurrent production deploys.
revique-web / deploy-uat.yml — Deploy UAT

Basic Info

Runnerubuntu-latest (both jobs)
Environmentsuat (deploy job only)
TimeoutNot set
Concurrencygroup: deploy-uat, cancel-in-progress: false

Triggers

  • push to uat branch
  • workflow_dispatch with optional ref input (default: uat)

Jobs

JobPurposeDepends On
request-approvalCheckout ref, resolve SHA, notify Slack that approval is pending
deployBuild and deploy to Cloudflare UAT environmentrequest-approval
Good Practice: Two-job structure with 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.
Duplicate setup-node: The deploy job calls actions/setup-node@v4 twice (step 4 with .nvmrc, step 10 with node 22). Same issue as deploy-production.yml. Remove the second call.
No Test Gate: Build and deploy run without a lint or test step.
revique-web / request-uat-promotion.yml — Request UAT Promotion

Basic Info

Runnerubuntu-latest
Environmentcodex-full-access
ConcurrencyNOT configured
TimeoutNot set

Inputs

source_branchBranch to promote from (default: develop)
target_branchBranch to promote to (default: uat)
post_slackBoolean — whether to post Slack notification (default: true)

Steps

#StepNotes
1Checkout (fetch-depth: 0)Full history needed for git log & rev-list delta
2Resolve promotion delta (bash)Computes commit counts, changed files, concerns, summary
3Create or update UAT promotion PRUses CODEX_FULL as GH_TOKEN; validates token before use ✓
4Notify Slack UAT promotion requestConditional on post_slack input; continue-on-error: true
Good Practices: Least-privilege permissions (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).
No Concurrency: Rapid double-trigger could race on PR creation. Add concurrency keyed on source+target branch pair.
Full Clone: 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

Runnerubuntu-latest
PermissionsMISSING — default over-broad token
ConcurrencyNOT configured
TimeoutNot set
Matrix StrategyNone

Triggers

  • pull_request targeting develop
  • push to develop

Steps (in order)

#StepCommand
1Checkoutactions/checkout@v4
2Setup Nodeactions/setup-node@v4 — reads .nvmrc, npm cache ✓
3Installnpm ci
4Lintnpm run lint
5Typechecknpm run typecheck
6Testnpm test
7Buildnpm run build
8Synthesize infrastructurenpm run infra:synth
9Build Docker imagedocker build --tag revique-api:ci .
Good Practice: Comprehensive CI — lint, typecheck, test, build, and infrastructure synthesis all run. This is the most thorough quality gate across all 6 workflows.
Missing permissions block: Without explicit 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.
No container image scan: Docker image is built but never scanned for OS or dependency vulnerabilities. Add Trivy or Snyk after the build step.
No concurrency control: Rapid pushes to develop queue multiple full CI runs (lint + typecheck + test + Docker build — several minutes each). Add concurrency to cancel superseded in-progress runs.
Image discarded: The Docker image built here is thrown away. deploy.yml rebuilds independently, meaning the tested artifact is never the deployed artifact.
revique-api / deploy.yml — Deploy

Basic Info

Runnerubuntu-latest
EnvironmentDynamic: dev, uat, or prod
Concurrencyper-job, keyed on environment
TimeoutNot set
AWS AuthOIDC — no long-lived keys

Triggers

  • workflow_dispatch only
  • Required input: environment (dev / uat / prod)
  • Required input: aws_region

Steps (in order)

#StepNotes
1Checkout
2Resolve deployment commitsha + short_sha outputs
3Notify Slack (active)continue-on-error: true
4Setup Node (npm cache)
5Installnpm ci
6Lint ✓Pre-deploy quality gate
7Typecheck ✓Pre-deploy quality gate
8Test ✓Pre-deploy quality gate
9Build ✓
10Validate AWS deploy configExits early if AWS_ROLE_TO_ASSUME not set ✓
11Configure AWS credentialsaws-actions/configure-aws-credentials@v4 — OIDC ✓
12Synthesize infrastructurenpm run infra:synth
13Deploy infrastructure and servicenpm run infra:deploy (CDK)
14Run database migrationsECS run-task with exit code check ✓
15Notify Slack (result)if: always()
Best-in-class AWS auth: Uses OIDC (id-token: write + aws-actions/configure-aws-credentials). No long-lived AWS credentials stored as secrets.
Strong deploy gate: Runs full lint + typecheck + tests before touching AWS infrastructure. Pre-flight check validates that AWS role is configured before attempting any AWS calls.
Slack webhook inconsistency: 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.
Unpinned third-party action: 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

What Is Working Well
  • All 6 workflows use actions/checkout@v4 and actions/setup-node@v4 — consistent, up-to-date tooling
  • npm caching via setup-node in 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.yml uses 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.yml validates required config variables before attempting AWS calls
⚠️ Consistent Gaps Across All Workflows
  • No workflow pins third-party actions to commit SHAs — all use floating version tags
  • No workflow sets timeout-minutes on 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

SeverityFindingAffected WorkflowsRisk
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

WorkflowCurrent IssueEstimated WasteFix
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

🔴 Critical — Fix Immediately (Security Risk)
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}"
🟠 High — Fix Soon (Reliability / Major Gap)
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.
🟡 Medium — Improve When Possible
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
🟢 Quick Wins — Easy to Add, High Value
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)

#RepositoryIssueAction
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)

#RepositoryAction
5Both reposAdd npm audit to all CI and deploy workflows. See snippet S5.
6revique-apiAdd Trivy container image scan after docker build. See snippet S4.
7Both reposAdd gitleaks secret scanning as a first CI step. See snippet S7.
8revique-webAdd lint + typecheck gate to all three deploy workflows. See snippet S6.
9revique-apiFix Slack webhook routing — use prod webhook for production deploys. See snippet S8.
10Both reposAdd CodeQL SAST workflow for static security analysis. See snippet S10.

Medium Priority (Address Within 1 Month)

#RepositoryAction
11Both reposAdd timeout-minutes to all jobs. Remove duplicate setup-node. See snippet S9.
12revique-apiAdd concurrency block to ci.yml. See snippet S2.
13Both reposEnable Dependabot for npm dependencies (GitHub Settings → Security).
14Both reposAdd GitHub dependency-review action on PRs. See snippet S11.
15revique-webConvert 39 TODO/FIXME comments to tracked GitHub Issues.
16revique-webAdd CONTRIBUTING.md, SECURITY.md, and LICENSE file.

Low Priority / Long-term

#RepositoryAction
17revique-webIntroduce unit/integration tests using Vitest. Add to deploy workflows once available.
18revique-apiPublish CI Docker image to ECR — deploy.yml pulls pre-built image instead of rebuilding.
19revique-apiSplit monolithic CI verify job into parallel lint/test/build jobs. See snippet S13.
20revique-webExtract 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 metadata
  • GET /repos/ReviqueInc/{name}/branches — branch list
  • GET /repos/ReviqueInc/{name}/commits — latest commit info
  • GET /repos/ReviqueInc/{name}/contributors — contributor list
  • GET /repos/ReviqueInc/{name}/contents/.github/workflows — workflow files
  • GET /repos/ReviqueInc/{name}/actions/runs — CI/CD run history
  • GET /repos/ReviqueInc/{name}/issues — open issues
  • GET /repos/ReviqueInc/{name}/pulls — open pull requests
  • GET /repos/ReviqueInc/{name}/branches/{branch}/protection — branch protection
  • GET /repos/ReviqueInc/{name}/dependabot/alerts — security alerts
  • GET /repos/ReviqueInc/{name}/contents/{file} — file existence checks
  • GET /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-web contributors 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