Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
174 changes: 174 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# GitHub Actions Workflows

This directory contains GitHub Actions workflows for the `@hubbyesim/types` package.

## Workflows

### Build, Commit Dist, and Tag Version

**File:** `build-and-commit.yml`

This workflow automatically builds the TypeScript package, runs tests, and creates releases when changes are pushed to the `main` branch.

**Triggers:**
- **Push to main branch**: Runs tests, builds, commits dist files, creates tags and releases
- **Pull request to main branch**: Runs tests and builds (verification only, no commits/releases)

#### What it does:

1. **Test Job** (runs first):
- Sets up Node.js environment with npm caching
- Installs dependencies including Firebase Admin SDK
- Sets up Firebase authentication using service account
- Runs all tests with Firebase instance injection
- Provides detailed error reporting and verification

2. **Build Job** (runs after tests pass on push to main):
- Builds the TypeScript package using `tsup`
- Commits compiled `dist/` files if changes exist
- Creates new version tags automatically
- Publishes GitHub releases

3. **PR Build Job** (runs after tests pass on pull requests):
- Builds the TypeScript package using `tsup`
- Verifies build output without committing changes
- Provides build verification for code review

#### Required Secrets

To run tests with Firebase, you need to set up the following secret in the **Test** environment:

**`FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED`**

This should be a base64-encoded Firebase service account JSON file for testing purposes.

##### How to set up:

1. **Create a Firebase Service Account:**
- Go to [Firebase Console](https://console.firebase.google.com/)
- Select your project (or create a test project)
- Go to Project Settings → Service Accounts
- Click "Generate New Private Key"
- Download the JSON file

2. **Encode the service account:**
```bash
base64 -i path/to/serviceAccountKey.json
```

3. **Add to GitHub Test Environment:**
- Go to your repository → Settings → Environments
- Click on "Test" environment (or create it if it doesn't exist)
- Click "Environment secrets" → "Add secret"
- Name: `FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED`
- Value: Paste the base64-encoded string from step 2

#### Environment Configuration

The workflow uses the **Test** environment for:
- Managing Firebase service account secrets
- Environment-specific configurations
- Enhanced security and access control

#### Test Configuration

The workflow automatically:
- Uses the service account credentials when available
- Falls back to application default credentials for local development
- Sets appropriate environment variables (`NODE_ENV=test`, `CI=true`)
- Provides detailed logging and error reporting
- Times out after 10 minutes to prevent hanging

#### Local Testing

For local development, you can run tests without setting up the secret:

```bash
npm test
```

The test setup will automatically use your local Firebase configuration or application default credentials.

#### Firebase Project

The workflow uses `hubby-esim-dev` as the default Firebase project for testing. You can change this by modifying the `FIREBASE_PROJECT_ID` environment variable in the workflow file.

## Dependencies

- Node.js 20+
- npm
- Firebase Admin SDK 12.2.0+
- Firebase CLI (for service account setup)
- jq (for JSON parsing in verification steps)

## Troubleshooting

### Tests failing in CI

1. **Check the service account secret:**
- Verify `FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED` is set correctly
- Ensure the service account has appropriate permissions
- Check that the project ID matches your Firebase project

2. **Firebase connection issues:**
- Verify the service account JSON is valid
- Check that the project ID in the service account matches `FIREBASE_PROJECT_ID`
- Ensure the service account has access to Firestore

3. **Service account JSON errors:**
- **"Unexpected end of JSON input"**: Usually means the secret is empty or malformed
- **"Failed to parse contents"**: Check if the base64 encoding is correct
- **Missing required fields**: Ensure the JSON has `project_id`, `private_key`, and `client_email`
- **Empty file**: The secret might not be set or the base64 decode failed

4. **Timeout issues:**
- Tests timeout after 10 minutes
- Build job times out after 15 minutes
- Check for hanging Firebase operations in your tests

#### Common Service Account Issues:

**"Unexpected end of JSON input" Error:**
```bash
# This usually means the secret is empty or malformed
# Check your secret value:
echo "${{ secrets.FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED }}" | base64 -d | head -c 100

# If empty, the secret isn't set correctly
# If malformed, check the base64 encoding:
base64 -i your-service-account.json
```

**Missing Secret:**
- If `FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED` is not set, tests will run with application default credentials
- This is fine for local development but may fail in CI if no default credentials are available

### Local vs CI differences

- **Local:** Uses application default credentials or local Firebase config
- **CI:** Uses service account credentials from GitHub secrets
- **Environment:** CI sets `NODE_ENV=test` and `CI=true`

## Security Notes

- The service account secret is only used during test execution
- Credentials are not persisted between workflow runs
- Service account files are created temporarily and cleaned up automatically
- Use a dedicated test service account with minimal permissions

## Environment Protection

The **Test** environment provides additional security:
- **Environment-specific secrets**: Secrets are isolated to the test environment
- **Access control**: You can restrict who can deploy to this environment
- **Approval workflows**: Optional approval requirements for environment access
- **Branch restrictions**: Limit which branches can access the environment

### Setting Up Environment Protection

1. Go to Settings → Environments → Test
2. Configure protection rules as needed:
- **Required reviewers**: Add team members who must approve deployments
- **Wait timer**: Delay deployments by a specified time
- **Deployment branches**: Restrict which branches can access the environment
- **Environment secrets**: Manage environment-specific secrets
157 changes: 156 additions & 1 deletion .github/workflows/build-and-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,140 @@ on:
- main
paths:
- 'src/**'
pull_request:
branches:
- main
paths:
- 'src/**'

permissions:
contents: write
packages: write

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
environment: Test

steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm install

- name: Install Firebase Admin SDK
run: npm install firebase-admin@^12.2.0

- name: Install Firebase CLI
run: npm install -g firebase-tools

- name: Install jq for JSON parsing
run: sudo apt-get update && sudo apt-get install -y jq

- name: Verify Test Environment
run: |
echo "🔍 Verifying Test Environment Configuration..."
echo "Environment: ${{ github.ref_name }}"
echo "Event: ${{ github.event_name }}"
echo "Actor: ${{ github.actor }}"
echo "Repository: ${{ github.repository }}"

- name: Set up Firebase Authentication for Testing
run: |
if [ -z "${{ secrets.FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED }}" ]; then
echo "❌ FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED secret is not set in Test environment"
echo "⚠️ Tests will run with application default credentials"
echo "💡 To use Firebase service account, set the secret in the Test environment"
echo " Go to: Settings → Environments → Test → Environment secrets"
exit 0
fi

echo "${{ secrets.FIREBASE_SERVICE_ACCOUNT_TEST_ENCODED }}" | base64 --decode > "/home/runner/firebaseServiceAccount.json"
chmod 644 /home/runner/firebaseServiceAccount.json

- name: Verify Firebase Service Account
run: |
if [ -f "/home/runner/firebaseServiceAccount.json" ]; then
echo "✅ Firebase service account file created successfully"
echo "File size: $(wc -c < /home/runner/firebaseServiceAccount.json) bytes"

# Check if file is valid JSON
if jq empty /home/runner/firebaseServiceAccount.json 2>/dev/null; then
echo "✅ File is valid JSON"
echo "Project ID: $(jq -r '.project_id' /home/runner/firebaseServiceAccount.json)"
echo "Client Email: $(jq -r '.client_email' /home/runner/firebaseServiceAccount.json)"
echo "Private Key Length: $(jq -r '.private_key' /home/runner/firebaseServiceAccount.json | wc -c) characters"
else
echo "❌ File is not valid JSON"
echo "First 100 characters of file:"
head -c 100 /home/runner/firebaseServiceAccount.json
echo ""
exit 1
fi
else
echo "ℹ️ No Firebase service account file found - will use application default credentials"
fi

- name: Show test environment
run: |
echo "🔍 Test Environment Configuration:"
echo "🌍 GitHub Environment: Test"
echo "NODE_ENV: ${NODE_ENV:-'not set'}"
echo "CI: ${CI:-'not set'}"
echo "FIREBASE_PROJECT_ID: ${FIREBASE_PROJECT_ID:-'not set'}"
if [ -f "/home/runner/firebaseServiceAccount.json" ]; then
echo "GOOGLE_APPLICATION_CREDENTIALS: /home/runner/firebaseServiceAccount.json (exists)"
else
echo "GOOGLE_APPLICATION_CREDENTIALS: not set (will use application default)"
fi

- name: Run tests
env:
GOOGLE_APPLICATION_CREDENTIALS: "/home/runner/firebaseServiceAccount.json"
FIREBASE_PROJECT_ID: "hubby-esim-dev"
NODE_ENV: "test"
CI: "true"
run: |
# Try to run tests with Firebase first
if [ -f "/home/runner/firebaseServiceAccount.json" ]; then
echo "🔥 Running tests with Firebase service account"
npm test
else
echo "⚠️ No Firebase service account, running tests with application default credentials"
# Unset the credentials path so tests use application default
unset GOOGLE_APPLICATION_CREDENTIALS
npm test
fi

- name: Test coverage report
if: always()
run: |
echo "Test execution completed"
echo "Firebase project used: ${{ env.FIREBASE_PROJECT_ID }}"

- name: Handle test failures
if: failure()
run: |
echo "❌ Tests failed! Check the test output above for details."
echo "Firebase configuration used:"
echo "- Project ID: ${{ env.FIREBASE_PROJECT_ID }}"
echo "- Service Account: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}"
echo "- Node Environment: ${{ env.NODE_ENV }}"

build:
runs-on: ubuntu-latest
needs: test
timeout-minutes: 15
if: github.event_name == 'push'

steps:
- uses: actions/checkout@v4
Expand All @@ -31,6 +157,7 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- run: npm install

Expand Down Expand Up @@ -90,4 +217,32 @@ jobs:
🛠 Auto-generated release for schema build.
Changes based on updates in `src/`.
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Build-only job for PRs (no commits/tags/releases)
build-pr:
runs-on: ubuntu-latest
needs: test
timeout-minutes: 15
if: github.event_name == 'pull_request'

steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- run: npm install

- run: npm run build

- name: Verify build output
run: |
echo "✅ Build completed successfully"
echo "📁 Generated files in dist/:"
ls -la dist/
echo "📊 Build size:"
du -sh dist/
3 changes: 2 additions & 1 deletion dist/base/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ var packageSpecificationSchema = zod.z.object({
package_id: zod.z.string().optional(),
iata_code: zod.z.string().optional(),
package_duration: zod.z.number().optional(),
package_type: zod.z.enum(["data-limited", "time-limited", "starter", "unlimited"]).optional()
package_type: zod.z.enum(["data-limited", "time-limited", "starter", "unlimited"]).optional(),
traffic_policy: zod.z.string().optional()
});
var promoCodeSchemaSpec = markAsSchemaSpec({
id: zod.z.string(),
Expand Down
2 changes: 1 addition & 1 deletion dist/base/index.cjs.map

Large diffs are not rendered by default.

Loading