From af7950a778528bf4cf3f00919adbec691813d8c9 Mon Sep 17 00:00:00 2001 From: Jung Do Hyun Date: Sun, 29 Mar 2026 13:03:02 +0900 Subject: [PATCH] chore(node): upgrade actions and align runtime to Node 22 --- .github/workflows/ci.yml | 26 ++++---- .github/workflows/deploy-image.yml | 6 +- docs/deployment.md | 89 ++++++++++++++-------------- docs/development.md | 54 ++++++++--------- package.json | 3 + packages/cdk/lib/stacks/api-stack.ts | 15 +++-- 6 files changed, 99 insertions(+), 94 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c69de8c..369198b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: web_changed: ${{ steps.scope.outputs.web_changed }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 @@ -92,10 +92,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm @@ -112,10 +112,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm @@ -134,10 +134,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm @@ -161,10 +161,10 @@ jobs: TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm @@ -206,10 +206,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm @@ -231,10 +231,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm diff --git a/.github/workflows/deploy-image.yml b/.github/workflows/deploy-image.yml index c86436b..80e4509 100644 --- a/.github/workflows/deploy-image.yml +++ b/.github/workflows/deploy-image.yml @@ -33,10 +33,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: 22 cache: npm @@ -73,7 +73,7 @@ jobs: name: image-release steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Configure AWS credentials (OIDC) uses: aws-actions/configure-aws-credentials@v4 diff --git a/docs/deployment.md b/docs/deployment.md index 35bd0f0..c5a0151 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -6,13 +6,13 @@ This guide covers the complete process for deploying Serverless OpenClaw on a cl ## 1. Prerequisites -| Item | Minimum Version | Verification Command | -|------|----------------|---------------------| -| AWS CLI | v2 | `aws --version` | -| AWS CDK CLI | v2.170+ | `npx cdk --version` | -| Node.js | v20+ | `node -v` | -| Docker | Latest | `docker --version` | -| npm | v9+ | `npm -v` | +| Item | Minimum Version | Verification Command | +| ----------- | --------------- | -------------------- | +| AWS CLI | v2 | `aws --version` | +| AWS CDK CLI | v2.170+ | `npx cdk --version` | +| Node.js | v22+ | `node -v` | +| Docker | Latest | `docker --version` | +| npm | v9+ | `npm -v` | ### AWS Account Setup @@ -60,12 +60,12 @@ Secrets are managed by CDK via `SecretsStack`. On the first deploy, provide all ### Prepare Secret Values -| Parameter | How to Obtain | -|-----------|--------------| -| `BridgeAuthToken` | Random string: `openssl rand -hex 32` | -| `OpenclawGatewayToken` | Your OpenClaw Gateway token | -| `AnthropicApiKey` | Your Anthropic API key | -| `TelegramBotToken` | (Optional) Token from @BotFather | +| Parameter | How to Obtain | +| ----------------------- | --------------------------------------------------------------------------- | +| `BridgeAuthToken` | Random string: `openssl rand -hex 32` | +| `OpenclawGatewayToken` | Your OpenClaw Gateway token | +| `AnthropicApiKey` | Your Anthropic API key | +| `TelegramBotToken` | (Optional) Token from @BotFather | | `TelegramWebhookSecret` | (Optional) Random string: `openssl rand -hex 32` (must **not** contain `:`) | ### When Using Telegram Bot (Optional) @@ -258,16 +258,16 @@ aws cognito-idp admin-update-user-attributes \ Key values available from CDK Output: -| CDK Output | Purpose | -|------------|---------| -| `WebStack.WebAppUrl` | Web UI access URL | -| `WebStack.DistributionDomainName` | CloudFront domain | -| `ApiStack.WebSocketApiEndpoint` | WebSocket connection URL | -| `ApiStack.HttpApiEndpoint` | REST API + Telegram webhook URL | -| `AuthStack.UserPoolId` | Cognito User Pool ID | -| `AuthStack.UserPoolClientId` | Cognito App Client ID | -| `ComputeStack.ClusterArn` | ECS cluster ARN | -| `StorageStack.EcrRepositoryUri` | Docker image push target | +| CDK Output | Purpose | +| --------------------------------- | ------------------------------- | +| `WebStack.WebAppUrl` | Web UI access URL | +| `WebStack.DistributionDomainName` | CloudFront domain | +| `ApiStack.WebSocketApiEndpoint` | WebSocket connection URL | +| `ApiStack.HttpApiEndpoint` | REST API + Telegram webhook URL | +| `AuthStack.UserPoolId` | Cognito User Pool ID | +| `AuthStack.UserPoolClientId` | Cognito App Client ID | +| `ComputeStack.ClusterArn` | ECS cluster ARN | +| `StorageStack.EcrRepositoryUri` | Docker image push target | ### `.env.local` for Web UI Local Development @@ -282,12 +282,12 @@ VITE_COGNITO_CLIENT_ID= Set in `.env` or exported before running CDK commands. -| Variable | Default | Values | Purpose | -|----------|---------|--------|---------| -| `AGENT_RUNTIME` | `fargate` | `fargate` \| `lambda` \| `both` | Compute path selection | -| `AI_PROVIDER` | `anthropic` | `anthropic` \| `bedrock` | AI provider selection | -| `AI_MODEL` | _(provider default)_ | any model ID | Override default model | -| `DEPLOY_WEB` | `true` | `true` \| `false` | Include WebStack deployment | +| Variable | Default | Values | Purpose | +| --------------- | -------------------- | ------------------------------- | --------------------------- | +| `AGENT_RUNTIME` | `fargate` | `fargate` \| `lambda` \| `both` | Compute path selection | +| `AI_PROVIDER` | `anthropic` | `anthropic` \| `bedrock` | AI provider selection | +| `AI_MODEL` | _(provider default)_ | any model ID | Override default model | +| `DEPLOY_WEB` | `true` | `true` \| `false` | Include WebStack deployment | --- @@ -383,11 +383,11 @@ npx cdk destroy --all --profile $AWS_PROFILE The project currently runs with `AGENT_RUNTIME=both`, keeping both Lambda (primary) and Fargate (fallback) paths available. This allows gradual migration and instant rollback. -| Mode | Lambda Agent | Fargate | Use Case | -|------|-------------|---------|----------| -| `fargate` (default) | Skipped | Active | Original behavior, backward compatible | -| `lambda` | Active | Skipped | Lambda only, zero fixed cost | -| **`both`** | **Active (smart routing)** | **Active (reuse/fallback)** | **Current — smart routing based on task** | +| Mode | Lambda Agent | Fargate | Use Case | +| ------------------- | -------------------------- | --------------------------- | ----------------------------------------- | +| `fargate` (default) | Skipped | Active | Original behavior, backward compatible | +| `lambda` | Active | Skipped | Lambda only, zero fixed cost | +| **`both`** | **Active (smart routing)** | **Active (reuse/fallback)** | **Current — smart routing based on task** | ### Prerequisites @@ -450,12 +450,13 @@ ComputeStack resources will be skipped. To rollback: set `AGENT_RUNTIME=fargate` By default the system uses Anthropic (requires `AnthropicApiKey` in SecretsStack). Set `AI_PROVIDER=bedrock` to use Amazon Bedrock instead — no API key needed, authentication uses the Lambda execution role / Fargate task role via the AWS SDK default credential chain. -| Variable | Default | Description | -|----------|---------|-------------| -| `AI_PROVIDER` | `anthropic` | `anthropic` or `bedrock` | -| `AI_MODEL` | _(provider default)_ | Override model ID (optional) | +| Variable | Default | Description | +| ------------- | -------------------- | ---------------------------- | +| `AI_PROVIDER` | `anthropic` | `anthropic` or `bedrock` | +| `AI_MODEL` | _(provider default)_ | Override model ID (optional) | **Default models:** + - Anthropic: `claude-sonnet-4-20250514` - Bedrock: region-aware (see table below) @@ -463,11 +464,11 @@ By default the system uses Anthropic (requires `AnthropicApiKey` in SecretsStack The Bedrock model ID is derived automatically from `AWS_REGION` at runtime. Bedrock requires a geographic prefix to route requests within a compliance boundary: -| AWS Regions | Model ID used | -|-------------|---------------| -| `eu-*` | `eu.anthropic.claude-sonnet-4-20250514-v1:0` | -| `us-*`, `ca-*` | `us.anthropic.claude-sonnet-4-20250514-v1:0` | -| `ap-*` | `apac.anthropic.claude-sonnet-4-20250514-v1:0` | +| AWS Regions | Model ID used | +| ----------------- | ----------------------------------------------------- | +| `eu-*` | `eu.anthropic.claude-sonnet-4-20250514-v1:0` | +| `us-*`, `ca-*` | `us.anthropic.claude-sonnet-4-20250514-v1:0` | +| `ap-*` | `apac.anthropic.claude-sonnet-4-20250514-v1:0` | | All other regions | `anthropic.claude-sonnet-4-20250514-v1:0` (no prefix) | Set `AI_MODEL` to override automatic resolution (you are responsible for using the correct format). `bedrockDiscovery` is always disabled — model selection is explicit via `resolveBedrockModel()`. @@ -520,6 +521,7 @@ aws logs tail /ecs/serverless-openclaw --follow --profile $AWS_PROFILE ``` **Common causes:** + - Image not pushed to ECR → build and push Docker image - Insufficient SSM parameter access permissions → redeploy with CDK - Insufficient memory → adjust `memoryLimitMiB` in `ComputeStack` @@ -537,6 +539,7 @@ curl "https://api.telegram.org/bot/getWebhookInfo" ``` **Common causes:** + - Webhook URL not registered → run `make telegram-webhook` - Secret token mismatch (403 Forbidden) → run `make telegram-webhook` to re-register with SSM secret - Lambda error → check CloudWatch logs for `telegram-webhook` function diff --git a/docs/development.md b/docs/development.md index 96f177b..48249d2 100644 --- a/docs/development.md +++ b/docs/development.md @@ -8,13 +8,13 @@ This guide covers local development environment setup and workflows for contribu ### Required Tools -| Tool | Minimum Version | Purpose | -|------|----------------|---------| -| Node.js | v20+ | Runtime | -| npm | v9+ | Package manager (workspaces) | -| Docker | Latest | Container build/test | -| AWS CLI | v2 | CDK deployment, resource inspection | -| AWS CDK CLI | v2.170+ | Infrastructure deployment | +| Tool | Minimum Version | Purpose | +| ----------- | --------------- | ----------------------------------- | +| Node.js | v22+ | Runtime | +| npm | v9+ | Package manager (workspaces) | +| Docker | Latest | Container build/test | +| AWS CLI | v2 | CDK deployment, resource inspection | +| AWS CDK CLI | v2.170+ | Infrastructure deployment | ### Initial Setup @@ -87,13 +87,13 @@ Managed as an npm workspaces monorepo + TypeScript project references. Inter-pac ## 3. Build Commands -| Command | Description | -|---------|-------------| -| `npm run build` | TypeScript build (`tsc --build`, all packages) | -| `npm run lint` | ESLint check (`packages/**/*.ts`) | -| `npm run format` | Prettier formatting | -| `npm run test` | Unit tests (vitest) | -| `npm run test:e2e` | E2E tests (vitest, `*.e2e.test.ts`) | +| Command | Description | +| ------------------ | ---------------------------------------------- | +| `npm run build` | TypeScript build (`tsc --build`, all packages) | +| `npm run lint` | ESLint check (`packages/**/*.ts`) | +| `npm run format` | Prettier formatting | +| `npm run test` | Unit tests (vitest) | +| `npm run test:e2e` | E2E tests (vitest, `*.e2e.test.ts`) | ### CDK Commands @@ -188,17 +188,17 @@ npx vite dev # http://localhost:5173 Consists of 9 CDK stacks. -| Stack | Key Resources | -|-------|--------------| -| SecretsStack | SSM SecureString parameters (5 secrets) | -| NetworkStack | VPC, public subnets, VPC Gateway Endpoints, Security Group | -| StorageStack | 5 DynamoDB tables, S3, ECR | -| AuthStack | Cognito User Pool, App Client | -| ComputeStack | ECS cluster, Fargate Task Definition | +| Stack | Key Resources | +| ---------------- | ------------------------------------------------------------------ | +| SecretsStack | SSM SecureString parameters (5 secrets) | +| NetworkStack | VPC, public subnets, VPC Gateway Endpoints, Security Group | +| StorageStack | 5 DynamoDB tables, S3, ECR | +| AuthStack | Cognito User Pool, App Client | +| ComputeStack | ECS cluster, Fargate Task Definition | | LambdaAgentStack | Lambda Container Image (DockerImageFunction, ARM64, 2048MB, 15min) | -| ApiStack | WebSocket API, HTTP API, 7 Lambda functions, EventBridge | -| WebStack | S3 (web assets), CloudFront (OAC) | -| MonitoringStack | CloudWatch Dashboard (6 rows, 10 custom metrics) | +| ApiStack | WebSocket API, HTTP API, 7 Lambda functions, EventBridge | +| WebStack | S3 (web assets), CloudFront (OAC) | +| MonitoringStack | CloudWatch Dashboard (6 rows, 10 custom metrics) | **Dependencies:** SecretsStack + NetworkStack → StorageStack → {AuthStack, ComputeStack, LambdaAgentStack} → ApiStack → WebStack + MonitoringStack @@ -232,10 +232,10 @@ npx vitest packages/gateway/__tests__/services/message.test.ts Managed with husky and configured automatically. -| Hook | Execution | Purpose | -|------|-----------|---------| +| Hook | Execution | Purpose | +| ------------ | ----------------------------------------------- | --------------------------------------- | | `pre-commit` | `npm run build && npm run lint && npm run test` | Ensure build, lint, and unit tests pass | -| `pre-push` | `npm run test:e2e` | Ensure E2E tests pass | +| `pre-push` | `npm run test:e2e` | Ensure E2E tests pass | > You can bypass hooks with the `--no-verify` flag, but this is not recommended as it may cause CI failures. diff --git a/package.json b/package.json index 4ce20fd..232ae28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,9 @@ { "name": "serverless-openclaw", "private": true, + "engines": { + "node": ">=22.0.0" + }, "workspaces": [ "packages/*" ], diff --git a/packages/cdk/lib/stacks/api-stack.ts b/packages/cdk/lib/stacks/api-stack.ts index e49ac88..0a12698 100644 --- a/packages/cdk/lib/stacks/api-stack.ts +++ b/packages/cdk/lib/stacks/api-stack.ts @@ -102,11 +102,11 @@ export class ApiStack extends cdk.Stack { const bundlingDefaults = { externalModules: ["@aws-sdk/*"], sourceMap: true, - target: "node20", + target: "node22", }; const nodejsFunctionDefaults = { - runtime: lambda.Runtime.NODEJS_20_X, + runtime: lambda.Runtime.NODEJS_22_X, architecture: lambda.Architecture.ARM_64, memorySize: 256, timeout: cdk.Duration.seconds(30), @@ -200,7 +200,10 @@ export class ApiStack extends cdk.Stack { for (const fn of secretFunctions) { fn.addEnvironment("SSM_BRIDGE_AUTH_TOKEN", SSM_SECRETS.BRIDGE_AUTH_TOKEN); } - telegramWebhookFn.addEnvironment("SSM_TELEGRAM_SECRET_TOKEN", SSM_SECRETS.TELEGRAM_WEBHOOK_SECRET); + telegramWebhookFn.addEnvironment( + "SSM_TELEGRAM_SECRET_TOKEN", + SSM_SECRETS.TELEGRAM_WEBHOOK_SECRET, + ); telegramWebhookFn.addEnvironment("SSM_TELEGRAM_BOT_TOKEN", SSM_SECRETS.TELEGRAM_BOT_TOKEN); // Grant SSM read access for secret resolution at runtime @@ -247,11 +250,7 @@ export class ApiStack extends cdk.Stack { for (const fn of containerFunctions) { fn.addToRolePolicy( new iam.PolicyStatement({ - actions: [ - "ecs:RunTask", - "ecs:StopTask", - "ecs:DescribeTasks", - ], + actions: ["ecs:RunTask", "ecs:StopTask", "ecs:DescribeTasks"], resources: ["*"], }), );