Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/brac-dev-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Dev Build & Deploy User Service (BRAC)

on:
push:
branches:
- develop

env:
AWS_REGION: ${{ secrets.AWS_REGION }}
ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY_BRAC }}
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}

jobs:
build-and-deploy:
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4

# =========================
# AWS Authentication
# =========================
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

# =========================
# Login to Amazon ECR
# =========================
- name: Login to Amazon ECR
uses: aws-actions/amazon-ecr-login@v2

# =========================
# Build & Push Image
# =========================
- name: Build and Push Docker Image to ECR
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.ECR_REPOSITORY }}:latest-brac
${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
# =========================
# Deploy on Server
# =========================
- name: Deploy Stack
uses: appleboy/ssh-action@master
with:
Comment on lines +55 to +56
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

appleboy/ssh-action latest release github

💡 Result:

Latest release of appleboy/ssh-action on GitHub is v1.2.5, published January 28, 2026. [1]


🌐 Web query:

appleboy/ssh-action security best practices pinning commit SHA

💡 Result:

Best practices for appleboy/ssh-action (with commit-SHA pinning)

1) Pin the action to a full commit SHA (not @v1, not @main)

GitHub recommends pinning third-party actions to a full-length commit SHA to get an immutable reference and reduce supply-chain risk (and to ensure the SHA is from the action’s repo, not a fork). [1]

Example

- name: Remote SSH
  uses: appleboy/ssh-action@<40-char-commit-sha>
  with:
    host: ${{ secrets.HOST }}
    username: ${{ secrets.USERNAME }}
    key: ${{ secrets.SSH_KEY }}
    script: |
      whoami

How to get the correct SHA

  1. In appleboy/ssh-action, open Tags/Releases.
  2. Open the exact version you want (e.g., v1.x.y).
  3. Copy the full 40-character commit SHA the tag points to.
  4. Replace @v1 / @v1.x.y with @<full-sha> in your workflow. [1]

Org-level enforcement note: GitHub added policy controls to enforce SHA pinning for actions via “Allowed actions and reusable workflows” settings. [2]

2) Use SSH hardening options the action provides

The action supports:

  • Passphrase-protected private keys (passphrase) [3]
  • Host key fingerprint verification (fingerprint) to reduce MITM risk [3]

These are documented in the action’s “Security Best Practices” section. [3]

3) Keep secrets out of the repo and minimize blast radius

  • Put host, username, key, passphrase, and fingerprint in GitHub Secrets (not plaintext in YAML). [1]
  • Use a non-root deploy user and least privileges on the target host (only what your deploy needs). (General SSH hardening; aligns with GitHub’s advice to audit how actions handle secrets and repo content.) [1]
  • Audit the action code (and updates) before changing the pinned SHA. [1]

Sources: GitHub Actions security hardening guidance [1], GitHub Actions SHA-pinning enforcement/policy update [2], appleboy/ssh-action README (inputs + security best practices) [3].

References

Citations:


Pin appleboy/ssh-action to a commit SHA instead of @master.

Using a mutable branch increases supply-chain risk. GitHub's security hardening guidance recommends pinning actions to a full 40-character commit SHA for the strongest protection. Version tags like @v1.2.5 are acceptable but less secure. The latest release is v1.2.5 (January 28, 2026). You can find the commit SHA by opening that release in the appleboy/ssh-action repository and copying the full commit hash.

🔒 Example update
-      - name: Deploy Stack
-        uses: appleboy/ssh-action@master
+      - name: Deploy Stack
+        uses: appleboy/ssh-action@<40-char-commit-sha>
🤖 Prompt for AI Agents
In @.github/workflows/brac-dev-deployment.yaml around lines 55 - 56, The
workflow currently references the mutable ref "uses:
appleboy/ssh-action@master"; replace that with a fixed commit SHA (full
40-character hash) or the release tag "v1.2.5" to eliminate supply-chain risk.
Locate the release commit for appleboy/ssh-action (v1.2.5) in the repo, copy the
full commit hash, and update the "uses:" line to
"appleboy/ssh-action@<FULL_COMMIT_SHA>" so the action is pinned to an immutable
revision instead of `@master`.

host: ${{ secrets.HOST_NAME_DEV }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: ${{ secrets.PORT }}
script: |
set -e

# Export AWS variables
export AWS_REGION="${{ secrets.AWS_REGION }}"
export AWS_ACCOUNT_ID="${{ secrets.AWS_ACCOUNT_ID }}"
#export aws-access-key-id="${{ secrets.AWS_ACCESS_KEY_ID }}"
#export aws-secret-access-key="${{ secrets.AWS_SECRET_ACCESS_KEY }}"
cd ${{ secrets.TARGET_DIR_DEV }}

# Backup old env if exists
if [ -f .env ]; then
mv .env .env-bkp
fi

# Write env safely (MULTILINE SAFE)
cat << 'EOF' > .env
${{ secrets.DEV_ENV_BRAC }}
EOF

# Login to ECR (non-interactive)
aws ecr get-login-password --region "$AWS_REGION" \
| docker login --username AWS \
--password-stdin "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"

./deploy.sh
87 changes: 87 additions & 0 deletions .github/workflows/brac-qa-deplyment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Tag Build & Deploy User Service (BRAC)

on:
push:
tags:
- "v*"

env:
AWS_REGION: ${{ secrets.AWS_REGION }}
AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }}
ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY_BRAC }}
TAG: ${{ github.ref_name }}

jobs:
build-and-deploy:
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4

# =========================
# AWS Authentication
# =========================
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}

# =========================
# Login to Amazon ECR
# =========================
- name: Login to Amazon ECR
uses: aws-actions/amazon-ecr-login@v2

# =========================
# Build & Push Docker Image
# =========================
- name: Build and Push Docker Image to ECR
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${{ env.AWS_REGION }}.amazonaws.com/${{ env.ECR_REPOSITORY }}:${{ env.TAG }}

# =========================
# Deploy on QA Server
# =========================
- name: Deploy Stack to QA
uses: appleboy/ssh-action@master
Comment on lines +55 to +56
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

❓ Verification inconclusive

appleboy/ssh-action latest stable release version GitHub


The latest stable GitHub release of appleboy/ssh-action is v1.2.4 (tag v1.2.4). [1]


GitHub Actions best practices pinning actions security @master risk


Why @master / @main is risky in uses:

Referencing an action by a moving ref (like @master, @main, or a mutable tag) means your workflow will automatically start running new code whenever that ref changes—whether due to a normal update, a compromised maintainer account, or a malicious tag/branch move—creating a supply-chain risk. Pinning prevents “silent” upgrades. [1][2]

Best practice: pin to a full commit SHA (recommended)

GitHub’s guidance is to pin third-party actions to a full-length commit SHA, which is currently the most reliable immutable reference for an action. [2]

Example:

- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7

Using a SHA that corresponds to a tagged release (and commenting the version) helps maintainability and updates. [1]

If you use tags, treat them as less secure unless immutable

Tags are more convenient, but they can be moved/deleted if an attacker gains repo access; GitHub recommends SHA pinning as the safer option. [2] (Some ecosystems may support “immutable releases,” but you should verify immutability and your org settings.) [1][3]

Additional hardening related to pinning

  • Verify the SHA comes from the official action repo (not a fork) before pinning. [2]
  • Audit the action’s code (especially anything handling secrets or making network calls). [2]
  • Avoid “mutable dependencies” inside actions (e.g., downloading scripts at runtime, unpinned container images), because pinning the action repo alone may not fully make execution immutable. [1]

Enforce it at scale

GitHub added/expanded policy controls so orgs/enterprises can enforce SHA pinning via “Allowed actions and reusable workflows” policy—workflows that reference unpinned actions can be made to fail. [3]

Practical automation

You can add a CI check that fails if any uses: entries aren’t pinned to full SHAs (example: “Ensure SHA Pinned Actions”). [4]

Sources: GitHub Well-Architected Actions security recommendations [1], GitHub Docs security guidance [2], GitHub Changelog on SHA-pinning enforcement [3], Marketplace enforcement action example [4].


Pin appleboy/ssh-action to a commit SHA instead of @master.

Using a mutable branch reference allows silent upgrades that could introduce compromised or malicious code. GitHub's security guidance recommends pinning to a full-length commit SHA (the most immutable reference). The latest stable release is v1.2.4.

🔒 Example update
-      - name: Deploy Stack to QA
-        uses: appleboy/ssh-action@master
+      - name: Deploy Stack to QA
+        uses: appleboy/ssh-action@9d7dba0a3c97e3ea5efac339cd9cc1b4a074e57d # v1.2.4
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Deploy Stack to QA
uses: appleboy/ssh-action@master
- name: Deploy Stack to QA
uses: appleboy/ssh-action@9d7dba0a3c97e3ea5efac339cd9cc1b4a074e57d # v1.2.4
🤖 Prompt for AI Agents
In @.github/workflows/brac-qa-deplyment.yaml around lines 55 - 56, Replace the
mutable reference appleboy/ssh-action@master used in the "Deploy Stack to QA"
step with an immutable reference: update the action to a full commit SHA
(preferred) or to the pinned release v1.2.4; locate the step that currently
reads appleboy/ssh-action@master and change it to
appleboy/ssh-action@<FULL_COMMIT_SHA> (or appleboy/ssh-action@v1.2.4) so the
workflow is pinned to a specific, immutable revision.

with:
host: ${{ secrets.HOST_NAME_QA }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.EC2_KEY }}
port: ${{ secrets.PORT }}
script: |
set -e

export AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
export AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
export AWS_REGION=${{ env.AWS_REGION }}

cd ${{ secrets.TARGET_DIR_QA }}

# Backup old env if exists
if [ -f .env ]; then
mv .env .env-bkp
fi

# Write env safely (MULTILINE SAFE)
cat << 'EOF' > .env
${{ secrets.QA_ENV_BRAC }}
EOF

aws ecr get-login-password --region ${AWS_REGION} \
| docker login \
--username AWS \
--password-stdin \
${{ env.AWS_ACCOUNT_ID }}.dkr.ecr.${AWS_REGION}.amazonaws.com

./deploy.sh ${{ env.TAG }}
182 changes: 182 additions & 0 deletions src/api-doc/bulkUser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Bulk User Creation Guide

This guide provides step-by-step instructions for performing bulk user creation in the Elevate User Service.

## Prerequisites

- Valid JWT token with admin privileges
- CSV file containing user data in the required format
- Access to the API endpoints

## CSV Format

Your CSV file must include the following columns (case-sensitive):

```
name,email,phone_code,phone,username,password,roles,province,district,local_municipality,linkageChampion,supervisor
```

### Sample CSV Content

```
name,email,phone_code,phone,username,password,roles,province,district,local_municipality,linkageChampion,supervisor
Farabi Ahmedullah,farabi.ahmedullah@yopmail.com,91,7012345499,farabi,Password@123,session_manager,SA-EC,SA-EC-ALFR,SA-EC-ALFR-MATA,,amolp
Carol Miranda,carol.miranda@yopmail.com,91,7012345599,carol,Password@123,session_manager,SA-EC,SA-EC-ALFR,SA-EC-ALFR-MATA,,amolp
Amol Patil,amol,patil@yopmail.com,91,7012345699,amolp,Password@123,org_admin,SA-EC,SA-EC-ALFR,SA-EC-ALFR-MATA,,
Suvarna Kale,suvarnak@yopmail.com,91,7012345699,suvarna,Password@123,user,SA-EC,SA-EC-ALFR,SA-EC-ALFR-MATA,,farabi
```

### Field Descriptions

- `name`: User's full name (required)
- `email`: User's email address (required if phone not provided)
- `phone_code`: Country code for phone (e.g., 91 for India)
- `phone`: User's phone number (required if email not provided)
- `username`: Desired username (optional, system will generate if not provided)
- `password`: User's password (required for direct creation, not for invitations)
- `roles`: Comma-separated list of roles (e.g., "session_manager,org_admin")
- Additional columns like `province`, `district`, etc., are for metadata

## Step-by-Step Process

### Step 1: Get Signed URL for File Upload

First, obtain a signed URL to upload your CSV file to cloud storage.

**Endpoint:** `GET /v1/cloud-services/file/getSignedUrl`

**Query Parameters:**

- `fileName`: Name of your CSV file (e.g., `bulk_users.csv`)

**Headers:**

- `X-auth-token`: Your JWT token

**Example Request:**

```bash
curl --location '{{baseURL}}user/v1/cloud-services/file/getSignedUrl?fileName=bulk_users.csv' \
--header 'X-auth-token: YOUR_JWT_TOKEN'
```

**Response:**

```json
{
"success": true,
"message": "SIGNED_URL_GENERATED_SUCCESSFULLY",
"result": {
"signedUrl": "https://your-cloud-storage-url...",
"filePath": "users/YOUR_USER_ID-TIMESTAMP-bulk_users.csv",
"destFilePath": "users/YOUR_USER_ID-TIMESTAMP-bulk_users.csv"
}
}
```

### Step 2: Upload CSV File

Upload your CSV file to the signed URL obtained in Step 1.

**Example Request:**

```bash
curl -X PUT -T /path/to/your/bulk_users.csv 'SIGNED_URL_FROM_STEP_1'
```

**Note:** Replace `/path/to/your/bulk_users.csv` with the actual path to your CSV file, and use single quotes around the signed URL to prevent shell interpretation of special characters.

### Step 3: Perform Bulk User Creation

Call the bulk user creation endpoint with the file path from Step 1.

**Endpoint:** `POST /v1/tenant/bulkUserCreate`

**Headers:**

- `X-auth-token`: Your JWT token
- Organization code header (configurable via `ORG_CODE_HEADER_NAME` env var, defaults to `x-org-code`): Your organization code (e.g., `brac_gbl`)
- Tenant code header (configurable via `TENANT_CODE_HEADER_NAME` env var, defaults to `x-tenant-code`): Your tenant code (e.g., `brac`)
- `Content-Type`: `application/json`

**Note on Headers:** The header names for organization and tenant codes are configurable through environment variables:

- `ORG_CODE_HEADER_NAME=organization` (current setting)
- `TENANT_CODE_HEADER_NAME=tenant` (current setting)

If these are not set, the defaults are `x-org-code` and `x-tenant-code`. Use the appropriate header names based on your environment configuration.

**Request Body:**

```json
{
"file_path": "users/YOUR_USER_ID-TIMESTAMP-bulk_users.csv",
"editable_fields": ["name", "email"],
"upload_type": "CREATE"
}
```

**Example Request:**

```bash
curl --location 'http://localhost:3567/user/v1/tenant/bulkUserCreate' \
--header 'Content-Type: application/json' \
--header 'X-auth-token: YOUR_JWT_TOKEN' \
--header 'organization: brac_gbl' \
--header 'tenant: brac' \
--data '{
"file_path" : "users/YOUR_USER_ID-TIMESTAMP-bulk_users.csv",
"editable_fields" : ["name"],
"upload_type": "CREATE"
}'
```

**Note:** The header names `organization` and `tenant` match the current environment variable settings. If your environment uses different header names (e.g., `x-org-code`, `x-tenant-code`), update the curl command accordingly.

**Response:**

```json
{
"success": true,
"message": "USER_CSV_UPLOADED",
"result": {
"id": 123,
"name": "bulk_users.csv",
"input_path": "users/YOUR_USER_ID-TIMESTAMP-bulk_users.csv",
"type": "CSV",
"organization_id": 66,
"created_by": 3074,
"tenant_code": "brac",
"uploadType": "CREATE",
"status": "PENDING",
"created_at": "2025-12-26T06:31:24.000Z",
"updated_at": "2025-12-26T06:31:24.000Z"
}
}
```

## Processing and Results

- The bulk upload is processed asynchronously via a background queue.
- You will receive an email notification with a download link to the results CSV once processing is complete.
- The results CSV will contain the status of each user creation/update attempt.

## Upload Types

- `"CREATE"`: Directly creates user accounts with provided passwords
- `"UPLOAD"`: Creates users and sends invitation emails
- `"INVITE"`: Sends invitation emails without creating accounts

## Troubleshooting

- **404 Error on Download**: Ensure the CSV file was successfully uploaded to the signed URL in Step 2.
- **Validation Errors**: Check that your CSV format matches the sample and all required fields are present.
- **Permission Denied**: Ensure your JWT token has admin privileges for the specified tenant and organization.
- **Expired Signed URL**: Signed URLs expire after 15 minutes. If expired, repeat Step 1.

## Additional Notes

- The process supports up to 1000 users per CSV file.
- Duplicate emails/phones will be handled based on existing user records.
- System-generated usernames will be assigned if not provided or if conflicts occur.
- All operations are logged and can be audited.
Loading