Skip to content

Commit 08e0172

Browse files
committed
Merge origin/staging - resolve conflicts preserving staging work
Conflict resolution: - Kept staging UI components (integration-form-dialog, integrations-manager) - Merged both paraWallets (staging) and apiKeys (upstream) tables - Kept staging plugin deletions - Preserved staging's Docker, deploy, Para integration, web3 plugin Security patches retained: - Next.js 16.0.7 (CVE-2025-66478) - React 19.2.1 (CVE-2025-55182)
2 parents b4c3bc7 + 5543c84 commit 08e0172

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1989
-6130
lines changed

.dockerignore

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Dependencies
2+
node_modules
3+
npm-debug.log*
4+
yarn-debug.log*
5+
yarn-error.log*
6+
pnpm-debug.log*
7+
8+
# Environment files
9+
.env
10+
.env.local
11+
.env.development.local
12+
.env.test.local
13+
.env.production.local
14+
15+
# Next.js build output
16+
.next
17+
out
18+
dist
19+
20+
# Development files
21+
.git
22+
.gitignore
23+
README.md
24+
Dockerfile
25+
.dockerignore
26+
docker-compose.yml
27+
docker-compose.*.yml
28+
29+
# IDE files
30+
.vscode
31+
.idea
32+
*.swp
33+
*.swo
34+
*~
35+
36+
# OS files
37+
.DS_Store
38+
Thumbs.db
39+
40+
# Logs
41+
logs
42+
*.log
43+
44+
# Runtime data
45+
pids
46+
*.pid
47+
*.seed
48+
*.pid.lock
49+
50+
# Coverage directory used by tools like istanbul
51+
coverage
52+
*.lcov
53+
54+
# nyc test coverage
55+
.nyc_output
56+
57+
# Dependency directories
58+
jspm_packages/
59+
60+
# Optional npm cache directory
61+
.npm
62+
63+
# Optional REPL history
64+
.node_repl_history
65+
66+
# Output of 'npm pack'
67+
*.tgz
68+
69+
# Yarn Integrity file
70+
.yarn-integrity
71+
72+
# parcel-bundler cache (https://parceljs.org/)
73+
.cache
74+
.parcel-cache
75+
76+
# next.js build output
77+
.next
78+
79+
# nuxt.js build output
80+
.nuxt
81+
82+
# vuepress build output
83+
.vuepress/dist
84+
85+
# Serverless directories
86+
.serverless
87+
88+
# FuseBox cache
89+
.fusebox/
90+
91+
# DynamoDB Local files
92+
.dynamodb/
93+
94+
# TernJS port file
95+
.tern-port
96+
97+
# Stores VSCode versions used for testing VSCode extensions
98+
.vscode-test
99+
100+
# Svelte build output
101+
.svelte-kit
102+
103+
# Database
104+
*.db
105+
*.sqlite
106+
107+
# Temporary files
108+
tmp/
109+
temp/
110+
111+
# Build artifacts
112+
build/
113+
dist/

.github/workflows/vw.yaml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
on:
2+
push:
3+
branches:
4+
- staging
5+
# - main
6+
workflow_dispatch:
7+
8+
name: deploy-vw
9+
jobs:
10+
build-and-deploy-vw:
11+
environment: ${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }}
12+
runs-on: ubuntu-latest
13+
env:
14+
HELM_FILE: deploy/${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }}/values.yaml
15+
REGION: ${{ github.ref == 'refs/heads/main' && 'us-east-1' || 'us-east-2' }}
16+
CLUSTER_NAME: ${{ github.ref == 'refs/heads/main' && 'maker-prod' || 'maker-staging' }}
17+
ENVIRONMENT_TAG: ${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }}
18+
NAMESPACE: vw
19+
SERVICE_NAME: vw
20+
AWS_ECR_NAME: keeper-app-vw-${{ github.ref == 'refs/heads/main' && 'prod' || 'staging' }}
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v4
24+
with:
25+
submodules: recursive
26+
27+
- name: Configure AWS credentials
28+
uses: aws-actions/configure-aws-credentials@v4
29+
with:
30+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
31+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
32+
aws-region: ${{ env.REGION }}
33+
34+
- name: Login to AWS ECR
35+
id: login-ecr
36+
uses: aws-actions/amazon-ecr-login@v2
37+
38+
- name: Extract commit hash
39+
id: vars
40+
if: ${{ !contains(github.event.head_commit.message , '[skip build]') }}
41+
shell: bash
42+
run: |
43+
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
44+
45+
- name: Build, tag, and push image to ECR
46+
id: build-image
47+
if: ${{ !contains(github.event.head_commit.message , '[skip build]') }}
48+
env:
49+
SHA_TAG: ${{ steps.vars.outputs.sha_short }}
50+
LATEST_TAG: latest
51+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
52+
run: |
53+
# Build Docker containers and push them to ECR ${{ env.AWS_ECR_NAME }}
54+
docker pull $ECR_REGISTRY/$AWS_ECR_NAME:$LATEST_TAG || true
55+
docker build -t $AWS_ECR_NAME \
56+
-t $ECR_REGISTRY/$AWS_ECR_NAME:$SHA_TAG \
57+
-t $ECR_REGISTRY/$AWS_ECR_NAME:$LATEST_TAG \
58+
-t $ECR_REGISTRY/$AWS_ECR_NAME:$ENVIRONMENT_TAG \
59+
-f ./Dockerfile \
60+
.
61+
62+
docker push $ECR_REGISTRY/$AWS_ECR_NAME --all-tags
63+
64+
- name: Deploying Service to Kubernetes with Helm
65+
id: deploy
66+
uses: bitovi/github-actions-deploy-eks-helm@v1.2.10
67+
with:
68+
values: image.repository=${{ steps.login-ecr.outputs.registry }}/${{ env.AWS_ECR_NAME }},image.tag=${{ steps.vars.outputs.sha_short }}
69+
cluster-name: ${{ env.CLUSTER_NAME }}
70+
config-files: ${{ env.HELM_FILE }}
71+
chart-path: techops-services/common
72+
namespace: ${{ env.NAMESPACE }}
73+
timeout: 5m0s
74+
name: ${{ env.SERVICE_NAME }}
75+
chart-repository: https://techops-services.github.io/helm-charts
76+
version: 0.0.33
77+
atomic: true

Dockerfile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Multi-stage Dockerfile for Next.js application
2+
# Stage 1: Dependencies
3+
FROM node:25-alpine AS deps
4+
RUN apk add --no-cache libc6-compat
5+
WORKDIR /app
6+
7+
# Install pnpm
8+
RUN npm install -g pnpm
9+
10+
# Copy package files
11+
COPY package.json pnpm-lock.yaml* ./
12+
COPY .npmrc* ./
13+
14+
# Install dependencies
15+
RUN pnpm install --frozen-lockfile
16+
17+
# Stage 2: Builder
18+
FROM node:25-alpine AS builder
19+
WORKDIR /app
20+
RUN npm install -g pnpm
21+
22+
# Copy dependencies from deps stage
23+
COPY --from=deps /app/node_modules ./node_modules
24+
COPY . .
25+
26+
# Create README.md if it doesn't exist to avoid build errors
27+
RUN touch README.md || true
28+
29+
# Build the application
30+
RUN pnpm build
31+
32+
# Stage 3: Runner
33+
FROM node:25-alpine AS runner
34+
WORKDIR /app
35+
36+
ENV NODE_ENV=production
37+
ENV NEXT_TELEMETRY_DISABLED=1
38+
39+
# Create non-root user
40+
RUN addgroup --system --gid 1001 nodejs
41+
RUN adduser --system --uid 1001 nextjs
42+
43+
# Copy built application
44+
COPY --from=builder /app/public ./public
45+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
46+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
47+
48+
# Switch to non-root user
49+
USER nextjs
50+
51+
# Expose port
52+
EXPOSE 3000
53+
54+
# Health check
55+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
56+
CMD curl -f http://localhost:3000/ || exit 1
57+
58+
# Start the application
59+
CMD ["node", "server.js"]

PARA_INTEGRATION.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Para Wallet Integration
2+
3+
## Overview
4+
5+
This integration automatically creates and manages Para wallets for users, enabling server-side blockchain operations within workflow steps.
6+
7+
## What This Does
8+
9+
1. **Automatic Wallet Creation**: When a user signs up, a Para wallet is automatically created for them
10+
2. **Secure Storage**: Wallet keyshares are encrypted with AES-256-GCM and stored securely in the database
11+
3. **Server-Side Access**: Workflow steps can use the user's wallet to perform blockchain operations (sending transactions, signing messages, interacting with smart contracts, etc.)
12+
4. **User Visibility**: Users can see their wallet address displayed in the user dropdown menu
13+
14+
## How It Works
15+
16+
### Wallet Creation Flow
17+
1. **User signs up** → Better Auth triggers a database hook
18+
- File: `lib/auth.ts`
19+
- Hook: `databaseHooks.user.create.after`
20+
21+
2. **Database hook calls Para SDK** to create a pregenerated wallet
22+
- `const wallet = await paraClient.createPregenWallet({ type: "EVM", pregenId: { email } })`
23+
- Returns: `{ id, address, ... }`
24+
25+
3. **Wallet keyshare is encrypted** and stored in database
26+
- File: `lib/encryption.ts`
27+
- Function: `encryptUserShare(userShare)`
28+
- Stored in: `para_wallets` table
29+
30+
4. **Wallet address is displayed** to the user
31+
- File: `components/workflows/user-menu.tsx`
32+
- Shown in user dropdown menu
33+
34+
### Workflow Step Usage
35+
When a workflow step needs to use the wallet:
36+
1. Fetch encrypted keyshare from database (using authenticated userId)
37+
2. Decrypt the keyshare
38+
3. Initialize Para signer for blockchain operations
39+
4. Perform the operation (send transaction, sign message, call smart contract, etc.)
40+
41+
## Key Components
42+
43+
### Database
44+
- **Table**: `para_wallets`
45+
- **Fields**: userId (unique), email, walletId, walletAddress, encrypted userShare, createdAt
46+
- **Security**: One wallet per user, foreign key to users table, cascading delete
47+
48+
### Encryption
49+
- **Algorithm**: AES-256-GCM (authenticated encryption)
50+
- **Key Storage**: Environment variable `WALLET_ENCRYPTION_KEY`
51+
- **Format**: `iv:authTag:encryptedData` (prevents tampering)
52+
53+
### Helper Functions
54+
- `getUserWallet(userId)` - Retrieve wallet from database
55+
- `initializeParaSigner(userId, rpcUrl)` - Get ready-to-use signer for transactions
56+
- `getUserWalletAddress(userId)` - Get wallet address for display
57+
- `userHasWallet(userId)` - Check if user has wallet
58+
59+
## What You Can Build
60+
61+
Workflow steps that use the user's wallet can:
62+
- Send ETH or ERC-20 tokens
63+
- Interact with smart contracts (DeFi, NFTs, DAOs)
64+
- Sign messages or data
65+
- Check balances and token ownership
66+
- Execute any blockchain operation the user authorizes
67+
68+
## Key Files
69+
70+
- `lib/auth.ts` - Better Auth configuration with wallet creation hook
71+
- `lib/db/schema.ts` - Database schema for `para_wallets` table
72+
- `lib/encryption.ts` - AES-256-GCM encryption/decryption utilities
73+
- `lib/para/wallet-helpers.ts` - Helper functions for wallet operations
74+
- `app/api/user/route.ts` - API endpoint that includes wallet address
75+
- `components/workflows/user-menu.tsx` - UI component displaying wallet address
76+
77+
## Environment Variables Required
78+
79+
```env
80+
PARA_API_KEY=your-para-api-key
81+
PARA_ENVIRONMENT=beta # or 'prod'
82+
WALLET_ENCRYPTION_KEY=64-character-hex-string
83+
```
84+
85+
## Security Notes
86+
87+
- All Para SDK operations happen server-side only
88+
- userShare never transmitted to browser
89+
- Encryption key stored only in environment variables
90+
- Each user can only access their own wallet (enforced by userId authentication)

PARA_WORKFLOW_STEP.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Para Wallet - Send Sepolia ETH Workflow Step
2+
3+
## Goal
4+
5+
Create a workflow step that allows users to send ETH on the Sepolia testnet using their Para wallet.
6+
7+
## File locations
8+
9+
- Plugin definition: plugins/[name]/index.ts
10+
- Step implementation: plugins/[name]/steps/[step-name].ts
11+
- Step registry: lib/step-registry.ts (auto-generated)
12+
- Workflow executor: lib/workflow-executor.workflow.ts
13+
- Step handler utilities: lib/steps/step-handler.ts
14+
15+
## For this step
16+
17+
You'll need to:
18+
19+
- Create plugins/para/index.ts — register the plugin
20+
- Create plugins/para/steps/send-eth.ts — step implementation
21+
- Access userId — look up from executionId via workflowExecutions table
22+
- Use wallet helpers — initializeParaSigner(userId, rpcUrl) from lib/para/wallet-helpers.ts
23+
- Define config fields — amount and recipientAddress in plugin registration
24+
- The PARA integration already exists (wallet creation, encryption, helpers), so you're adding a step that uses it.
25+
26+
## Current Status
27+
28+
- ✅ Para wallet integration is complete (wallets auto-created on user signup)
29+
- ✅ Wallet addresses display in user dropdown menu
30+
31+
## What Works
32+
33+
1. Users automatically get a Para wallet when they sign up
34+
2. Wallet keyshares are encrypted and stored securely in the database
35+
36+
## What Doesn't Work
37+
38+
Nothing about the step is yet implemented
39+
40+
## The Issue
41+
42+
## Next Steps
43+
44+
## Key Files

0 commit comments

Comments
 (0)