aws-lambda-layer-cli 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Directory setup
5
+ BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6
+ BUILD_DIR="$BASE_DIR/aws_lambda_layer_cli"
7
+ ASSETS_DIR="$BUILD_DIR/assets"
8
+
9
+ echo "Preparing PyPI package structure..."
10
+
11
+ # Clean up any previous build artifacts
12
+ rm -rf "$BUILD_DIR" "$BASE_DIR/dist" "$BASE_DIR/build" "$BASE_DIR/aws_lambda_layer_cli.egg-info"
13
+
14
+ # Create package directories
15
+ mkdir -p "$ASSETS_DIR"
16
+
17
+ # Copy Python package files
18
+ cp "$BASE_DIR/scripts/pypi_resources/__init__.py" "$BUILD_DIR/"
19
+ cp "$BASE_DIR/scripts/pypi_resources/cli.py" "$BUILD_DIR/"
20
+ cp "$BASE_DIR/VERSION.txt" "$BUILD_DIR/"
21
+
22
+ # Copy assets (bash scripts)
23
+ cp "$BASE_DIR/scripts/aws-lambda-layer" "$ASSETS_DIR/"
24
+ cp "$BASE_DIR/scripts/create_nodejs_layer.sh" "$ASSETS_DIR/"
25
+ cp "$BASE_DIR/scripts/create_python_layer.sh" "$ASSETS_DIR/"
26
+
27
+ # Create __init__.py for assets package
28
+ touch "$ASSETS_DIR/__init__.py"
29
+
30
+ echo "Building PyPI package..."
31
+ cd "$BASE_DIR"
32
+ python3 -m build
33
+
34
+ echo "Cleaning up temporary package files..."
35
+ rm -rf "$BUILD_DIR" "$BASE_DIR/aws_lambda_layer_cli.egg-info" "$BASE_DIR/build"
36
+
37
+ echo "Build complete! Artifacts are in dist/"
@@ -0,0 +1,459 @@
1
+ #!/bin/bash
2
+
3
+ # Node.js Lambda Layer Creator with NVM support and version specification
4
+ # Usage:
5
+ # ./create_nodejs_layer.sh -i express@4.18.2,axios@1.6.2
6
+ # ./create_nodejs_layer.sh -i express@4.18.2,axios,lodash@4.17.21 -n my-layer.zip
7
+ # ./create_nodejs_layer.sh --packages=express@4.18.2,axios --name=my-layer.zip --node-version=24
8
+
9
+ set -e # Exit on error
10
+ set -u # Treat unset variables as errors
11
+
12
+ # Generate unique temporary directory
13
+ TEMP_DIR=$(mktemp -d)
14
+ WORK_DIR="$TEMP_DIR/layer-build"
15
+ NODE_DIR="$WORK_DIR/nodejs"
16
+
17
+ # Default values
18
+ PACKAGES=""
19
+ LAYER_NAME=""
20
+ NODE_VERSION="24" # Default to Node.js 24
21
+ ORIGINAL_DIR=$(pwd)
22
+
23
+ # Colors for output
24
+ RED='\033[0;31m'
25
+ GREEN='\033[0;32m'
26
+ YELLOW='\033[1;33m'
27
+ BLUE='\033[0;34m'
28
+ NC='\033[0m'
29
+
30
+ # Security functions
31
+ sanitize_filename() {
32
+ local filename="$1"
33
+ # Remove dangerous characters: /, \, :, |, <, >, ?, *, ", ', `, $, (, ), {, }, ;, &, !
34
+ filename=$(echo "$filename" | sed 's/[\/\\:|<>?*"\`$(){};&!]//g')
35
+ # Remove leading/trailing dots and hyphens
36
+ filename=$(echo "$filename" | sed 's/^[.-]*//' | sed 's/[.-]*$//')
37
+ # Limit length
38
+ echo "${filename:0:100}"
39
+ }
40
+
41
+ validate_version() {
42
+ local version="$1"
43
+ # Allow only numbers and dots
44
+ if [[ ! "$version" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
45
+ printf "${RED}Error: Invalid version format: $version${NC}\n"
46
+ printf "Version must contain only numbers and dots (e.g., 24, 20.0.0)\n"
47
+ exit 1
48
+ fi
49
+ }
50
+
51
+ escape_package_name() {
52
+ local pkg="$1"
53
+ # Whitelist for Node.js: A-Za-z0-9._-@/ (with version operators: ^~<>)
54
+ # FIXED: Place hyphen at the end of character class to avoid regex range interpretation
55
+ echo "$pkg" | sed 's/[^A-Za-z0-9._@\/~^><=+-]//g'
56
+ }
57
+
58
+ # Extract base package name from version specification
59
+ # Example: express@4.18.2 -> express
60
+ # Example: @aws-sdk/client-lambda@3.515.0 -> @aws-sdk/client-lambda
61
+ extract_package_name() {
62
+ local pkg="$1"
63
+ # Remove version specification after @
64
+ if [[ "$pkg" == *@* && ! "$pkg" =~ ^@ ]]; then
65
+ # Regular package with version: express@4.18.2
66
+ echo "${pkg%%@*}"
67
+ elif [[ "$pkg" == @*@* ]]; then
68
+ # Scoped package with version: @aws-sdk/client-lambda@3.515.0
69
+ # Keep @scope/name part
70
+ echo "${pkg%@*}"
71
+ else
72
+ # No version specified
73
+ echo "$pkg"
74
+ fi
75
+ }
76
+
77
+ # Extract version from package string if specified
78
+ # Example: express@4.18.2 -> 4.18.2
79
+ extract_package_version() {
80
+ local pkg="$1"
81
+ if [[ "$pkg" == *@* ]]; then
82
+ if [[ "$pkg" == @*@* ]]; then
83
+ # Scoped package: @aws-sdk/client-lambda@3.515.0
84
+ echo "${pkg##*@}"
85
+ else
86
+ # Regular package: express@4.18.2
87
+ echo "${pkg##*@}"
88
+ fi
89
+ else
90
+ echo ""
91
+ fi
92
+ }
93
+
94
+ # Cleanup function
95
+ cleanup() {
96
+ if [ -d "$TEMP_DIR" ]; then
97
+ rm -rf "$TEMP_DIR"
98
+ fi
99
+ }
100
+
101
+ # Trap to ensure cleanup on exit
102
+ trap cleanup EXIT
103
+
104
+ # Parse command line arguments
105
+ while [[ $# -gt 0 ]]; do
106
+ case "$1" in
107
+ -i|--packages)
108
+ if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
109
+ PACKAGES="$2"
110
+ shift 2
111
+ else
112
+ printf "${RED}Error: $1 requires an argument${NC}\n"
113
+ printf "Example: $1 express@4.18.2,axios\n"
114
+ exit 1
115
+ fi
116
+ ;;
117
+ --packages=*)
118
+ PACKAGES="${1#*=}"
119
+ shift
120
+ ;;
121
+ -n|--name)
122
+ if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
123
+ LAYER_NAME="$2"
124
+ shift 2
125
+ else
126
+ printf "${RED}Error: $1 requires an argument${NC}\n"
127
+ printf "Example: $1 my-layer.zip\n"
128
+ exit 1
129
+ fi
130
+ ;;
131
+ --name=*)
132
+ LAYER_NAME="${1#*=}"
133
+ shift
134
+ ;;
135
+ --node-version)
136
+ if [[ -n "${2:-}" && "${2:-}" != -* ]]; then
137
+ NODE_VERSION="$2"
138
+ validate_version "$NODE_VERSION"
139
+ shift 2
140
+ else
141
+ printf "${RED}Error: $1 requires an argument${NC}\n"
142
+ printf "Example: $1 24\n"
143
+ exit 1
144
+ fi
145
+ ;;
146
+ --node-version=*)
147
+ NODE_VERSION="${1#*=}"
148
+ validate_version "$NODE_VERSION"
149
+ shift
150
+ ;;
151
+ -h|--help)
152
+ cat << 'EOF'
153
+ Node.js Lambda Layer Creator with NVM support
154
+
155
+ Usage:
156
+ ./create_nodejs_layer.sh -i express@4.18.2,axios@1.6.2
157
+ ./create_nodejs_layer.sh --packages=express@4.18.2,axios,lodash -n my-layer.zip
158
+ ./create_nodejs_layer.sh -i @aws-sdk/client-lambda@3.515.0 --name=aws-layer.zip --node-version=24
159
+
160
+ Options:
161
+ -i, --packages Comma-separated list of npm packages (with optional versions)
162
+ -n, --name Name of the output zip file
163
+ --node-version Node.js version (default: 24). Uses nvm if available, falls back to system node
164
+ -h, --help Show this help message
165
+
166
+ Version Specification:
167
+ Package versions can be specified using @ symbol:
168
+ express@4.18.2 # Exact version
169
+ express@^4.18.0 # Caret range
170
+ express@~4.18.0 # Tilde range
171
+ @aws-sdk/client-lambda@3.515.0 # Scoped package with version
172
+
173
+ Examples:
174
+ ./create_nodejs_layer.sh -i express@4.18.2
175
+ ./create_nodejs_layer.sh -i axios@1.6.2,lodash@4.17.21,moment@2.29.4 -n utilities.zip
176
+ ./create_nodejs_layer.sh --packages=express@4.18.2,axios --name=web-framework.zip --node-version=24
177
+ EOF
178
+ exit 0
179
+ ;;
180
+ *)
181
+ printf "${RED}Unknown option: $1${NC}\n"
182
+ printf "Use -h or --help for usage information\n"
183
+ exit 1
184
+ ;;
185
+ esac
186
+ done
187
+
188
+ # Check if packages are provided
189
+ if [ -z "$PACKAGES" ]; then
190
+ printf "${RED}Error: Packages argument is required${NC}\n"
191
+ printf "Use -i or --packages to specify packages (comma-separated)\n"
192
+ printf "Example: ./create_nodejs_layer.sh -i express@4.18.2,axios\n"
193
+ exit 1
194
+ fi
195
+ # Check dependencies
196
+ if ! command -v zip &> /dev/null; then
197
+ printf "${RED}Error: 'zip' command is not installed${NC}\n"
198
+ exit 1
199
+ fi
200
+
201
+ if ! command -v npm &> /dev/null; then
202
+ printf "${RED}Error: 'npm' command is not installed${NC}\n"
203
+ exit 1
204
+ fi
205
+ # Function to get Node.js version securely
206
+ get_node_version() {
207
+ local version=""
208
+
209
+ # Try to get version from node command
210
+ if command -v node >/dev/null 2>&1; then
211
+ version=$(node --version 2>/dev/null | head -1 || echo "")
212
+ if [[ -n "$version" ]]; then
213
+ # Remove 'v' prefix and get major version
214
+ version=${version#v}
215
+ version=${version%%.*}
216
+ echo "$version"
217
+ return 0
218
+ fi
219
+ fi
220
+
221
+ echo ""
222
+ return 1
223
+ }
224
+
225
+ # Sanitize packages input using whitelist
226
+ SANITIZED_PACKAGES=""
227
+ IFS=',' read -ra PACKAGE_ARRAY <<< "$PACKAGES"
228
+ for pkg in "${PACKAGE_ARRAY[@]}"; do
229
+ # Trim whitespace
230
+ pkg=$(echo "$pkg" | xargs)
231
+ # Escape package name using whitelist
232
+ escaped_pkg=$(escape_package_name "$pkg")
233
+ if [ -n "$escaped_pkg" ]; then
234
+ SANITIZED_PACKAGES="${SANITIZED_PACKAGES}${SANITIZED_PACKAGES:+,}$escaped_pkg"
235
+ else
236
+ printf "${YELLOW}Warning: Package name '$pkg' contains no valid characters after sanitization${NC}\n"
237
+ fi
238
+ done
239
+
240
+ if [ -z "$SANITIZED_PACKAGES" ]; then
241
+ printf "${RED}Error: No valid packages provided after sanitization${NC}\n"
242
+ exit 1
243
+ fi
244
+
245
+ # Check if any package names were changed
246
+ if [ "$PACKAGES" != "$SANITIZED_PACKAGES" ]; then
247
+ printf "${YELLOW}Warning: Some package names were sanitized:${NC}\n"
248
+ printf " Original: $PACKAGES\n"
249
+ printf " Sanitized: $SANITIZED_PACKAGES\n"
250
+ PACKAGES="$SANITIZED_PACKAGES"
251
+ fi
252
+
253
+ # Set Node.js version if specified (already has default 24)
254
+ printf "Node.js version: $NODE_VERSION\n"
255
+ CURRENT_NODE_VERSION=$(get_node_version || echo "")
256
+ if [[ -n "$NODE_VERSION" ]]; then
257
+ printf "Using Node.js version: $NODE_VERSION\n"
258
+
259
+ # Check if nvm is available
260
+ if [[ -f "$HOME/.nvm/nvm.sh" ]]; then
261
+ printf "Using nvm to set Node.js version...\n"
262
+ # Source nvm securely with fixed path
263
+ if [ -f "$HOME/.nvm/nvm.sh" ]; then
264
+ # shellcheck source=/dev/null
265
+ source "$HOME/.nvm/nvm.sh"
266
+ else
267
+ printf "${RED}Error: nvm not found at expected location${NC}\n"
268
+ exit 1
269
+ fi
270
+
271
+ # Check if requested version is installed using safe method
272
+ NVM_VERSIONS=$(nvm list --no-colors 2>/dev/null | grep -e "->|v$NODE_VERSION\." | head -1 || true)
273
+ if [[ -n "$NVM_VERSIONS" ]]; then
274
+ nvm use "$NODE_VERSION" > /dev/null 2>&1 || true
275
+ printf "Switched to Node.js version: $(node --version 2>/dev/null || echo 'unknown')\n"
276
+ else
277
+ printf "${YELLOW}Warning: Requested Node.js version $NODE_VERSION not found via nvm${NC}\n"
278
+ printf "Using current Node.js version: $(node --version 2>/dev/null || echo 'unknown')\n"
279
+ fi
280
+ elif command -v nvm >/dev/null 2>&1; then
281
+ printf "Using nvm to set Node.js version...\n"
282
+ # Check if requested version is installed
283
+ NVM_VERSIONS=$(nvm list --no-colors 2>/dev/null | grep -E "->|v$NODE_VERSION\." | head -1 || true)
284
+ if [[ -n "$NVM_VERSIONS" ]]; then
285
+ nvm use "$NODE_VERSION" > /dev/null 2>&1 || true
286
+ printf "Switched to Node.js version: $(node --version 2>/dev/null || echo 'unknown')\n"
287
+ else
288
+ printf "${YELLOW}Warning: Requested Node.js version $NODE_VERSION not found via nvm${NC}\n"
289
+ printf "Using current Node.js version: $(node --version 2>/dev/null || echo 'unknown')\n"
290
+ fi
291
+ else
292
+ printf "${YELLOW}Warning: nvm not found. Using system Node.js${NC}\n"
293
+ if [[ -n "$CURRENT_NODE_VERSION" ]]; then
294
+ printf "Current Node.js version: $CURRENT_NODE_VERSION\n"
295
+ else
296
+ printf "${YELLOW}Warning: Could not determine Node.js version${NC}\n"
297
+ fi
298
+ fi
299
+ fi
300
+
301
+ # Get current Node.js version for naming
302
+ NODE_VERSION_USED=$(get_node_version || echo "$NODE_VERSION")
303
+
304
+ printf "${BLUE}=========================================${NC}\n"
305
+ printf "${GREEN}Node.js Lambda Layer Creator${NC}\n"
306
+ printf "${BLUE}=========================================${NC}\n"
307
+ printf "Packages: $PACKAGES\n"
308
+ printf "Node.js version: $NODE_VERSION_USED\n"
309
+ if [ -n "$LAYER_NAME" ]; then
310
+ printf "Output name: $LAYER_NAME\n"
311
+ fi
312
+ printf "\n"
313
+
314
+ # Step 1: Create directory structure
315
+ printf "[1/5] Creating directory structure...\n"
316
+ mkdir -p "$NODE_DIR"
317
+ cd "$WORK_DIR"
318
+
319
+ # Step 2: Initialize npm project
320
+ printf "[2/5] Initializing npm project...\n"
321
+ cd "$NODE_DIR"
322
+ npm init -y --silent
323
+
324
+ # Step 3: Install packages with versions
325
+ printf "[3/5] Installing packages...\n"
326
+ # Convert to array for safe expansion
327
+ IFS=',' read -ra PKG_ARRAY <<< "$PACKAGES"
328
+
329
+ # Disable nounset for npm execution as some environment wrappers might trigger unbound variable errors
330
+ set +u
331
+ npm install --save --silent "${PKG_ARRAY[@]}"
332
+ set -u
333
+
334
+ # Count packages from command argument
335
+ PACKAGE_COUNT=$(echo "$PACKAGES" | tr ',' '\n' | wc -l | tr -d ' ')
336
+
337
+ # Step 4: Determine layer name
338
+ printf "[4/5] Determining layer name...\n"
339
+ if [ -z "$LAYER_NAME" ]; then
340
+ if [ "$PACKAGE_COUNT" -eq 1 ]; then
341
+ # Single package: get base package name without version
342
+ PKG_FULL="$PACKAGES"
343
+ PKG_NAME=$(extract_package_name "$PKG_FULL")
344
+ SPECIFIED_VERSION=$(extract_package_version "$PKG_FULL")
345
+
346
+ # Handle scoped packages
347
+ if [[ "$PKG_NAME" == @* ]]; then
348
+ SCOPE=$(echo "$PKG_NAME" | cut -d'/' -f1)
349
+ PKG=$(echo "$PKG_NAME" | cut -d'/' -f2)
350
+ PKG_JSON="$NODE_DIR/node_modules/$SCOPE/$PKG/package.json"
351
+ else
352
+ PKG_JSON="$NODE_DIR/node_modules/$PKG_NAME/package.json"
353
+ fi
354
+
355
+ if [ -f "$PKG_JSON" ]; then
356
+ # Use grep instead of node -p with require
357
+ INSTALLED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$PKG_JSON" | head -1 | cut -d'"' -f4 || echo "1.0.0")
358
+ if [ -z "$INSTALLED_VERSION" ]; then
359
+ INSTALLED_VERSION="1.0.0"
360
+ fi
361
+
362
+ # If user specified a version, include it in the name
363
+ if [ -n "$SPECIFIED_VERSION" ]; then
364
+ # Extract just the version number from spec (remove operators)
365
+ SPEC_VERSION=$(echo "$SPECIFIED_VERSION" | sed 's/^[=<>!~^]*//')
366
+ LAYER_NAME="${PKG_NAME}-${SPEC_VERSION}-nodejs${NODE_VERSION_USED}"
367
+ printf " Specified version: $SPEC_VERSION\n"
368
+ else
369
+ LAYER_NAME="${PKG_NAME}-${INSTALLED_VERSION}-nodejs${NODE_VERSION_USED}"
370
+ printf " Installed version: $INSTALLED_VERSION\n"
371
+ fi
372
+ else
373
+ # Use project version as fallback
374
+ PROJECT_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$NODE_DIR/package.json" | head -1 | cut -d'"' -f4 || echo "1.0.0")
375
+ if [ -z "$PROJECT_VERSION" ]; then
376
+ PROJECT_VERSION="1.0.0"
377
+ fi
378
+
379
+ if [ -n "$SPECIFIED_VERSION" ]; then
380
+ LAYER_NAME="${PKG_NAME}-${SPECIFIED_VERSION}-nodejs${NODE_VERSION_USED}"
381
+ printf " Specified version: $SPECIFIED_VERSION\n"
382
+ else
383
+ LAYER_NAME="${PKG_NAME}-${PROJECT_VERSION}-nodejs${NODE_VERSION_USED}"
384
+ printf " Project version: $PROJECT_VERSION\n"
385
+ fi
386
+ fi
387
+ else
388
+ # Multiple packages: use nodejs-[date]-nodejs[version].zip
389
+ LAYER_NAME="nodejs-$(date +%Y%m%d)-nodejs${NODE_VERSION_USED}"
390
+ printf " Multiple packages, using date-based name\n"
391
+ fi
392
+
393
+ # Sanitize the layer name
394
+ LAYER_NAME=$(sanitize_filename "$LAYER_NAME")
395
+ fi
396
+
397
+ # Additional sanitization for layer name
398
+ LAYER_NAME=$(sanitize_filename "$LAYER_NAME")
399
+
400
+ # Ensure .zip extension and check for path traversal
401
+ if [[ "$LAYER_NAME" =~ \.\. ]] || [[ "$LAYER_NAME" =~ ^/ ]]; then
402
+ printf "${RED}Error: Invalid layer name (path traversal detected)${NC}\n"
403
+ exit 1
404
+ fi
405
+
406
+ if [[ ! "$LAYER_NAME" =~ \.zip$ ]]; then
407
+ LAYER_NAME="${LAYER_NAME}.zip"
408
+ fi
409
+
410
+ # Step 5: Zip the nodejs directory
411
+ printf "[5/5] Creating zip file: $LAYER_NAME\n"
412
+ cd "$WORK_DIR"
413
+ zip -r "$LAYER_NAME" "nodejs" -q
414
+
415
+ # Move zip to original directory - Check path
416
+ if [[ -f "$LAYER_NAME" ]]; then
417
+ mv "$LAYER_NAME" "$ORIGINAL_DIR/"
418
+ else
419
+ printf "${RED}Error: Zip file not created${NC}\n"
420
+ exit 1
421
+ fi
422
+
423
+ printf "\n"
424
+ printf "${GREEN}✅ Node.js Lambda layer created successfully!${NC}\n"
425
+ printf "📁 File: $ORIGINAL_DIR/$LAYER_NAME\n"
426
+ printf "🚀 Node.js Version: $NODE_VERSION_USED\n"
427
+ printf "📦 Size: $(du -h "$ORIGINAL_DIR/$LAYER_NAME" | cut -f1)\n"
428
+ printf "📊 Package Count: $PACKAGE_COUNT\n"
429
+
430
+ # Output installed packages with versions for description
431
+ printf "Installed packages: "
432
+ IFS=',' read -ra PKG_ARRAY <<< "$PACKAGES"
433
+ INSTALLED_PKGS=""
434
+ for pkg_full in "${PKG_ARRAY[@]}"; do
435
+ pkg_name=$(extract_package_name "$pkg_full")
436
+
437
+ # Find package.json
438
+ if [[ "$pkg_name" == @* ]]; then
439
+ scope=$(echo "$pkg_name" | cut -d'/' -f1)
440
+ pkg=$(echo "$pkg_name" | cut -d'/' -f2)
441
+ pkg_json="$NODE_DIR/node_modules/$scope/$pkg/package.json"
442
+ else
443
+ pkg_json="$NODE_DIR/node_modules/$pkg_name/package.json"
444
+ fi
445
+
446
+ if [ -f "$pkg_json" ]; then
447
+ installed_ver=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$pkg_json" | head -1 | cut -d'"' -f4)
448
+ if [ -n "$installed_ver" ]; then
449
+ if [ -n "$INSTALLED_PKGS" ]; then
450
+ INSTALLED_PKGS="$INSTALLED_PKGS, ${pkg_name}@${installed_ver}"
451
+ else
452
+ INSTALLED_PKGS="${pkg_name}@${installed_ver}"
453
+ fi
454
+ fi
455
+ fi
456
+ done
457
+ printf "$INSTALLED_PKGS\n"
458
+
459
+ printf "\n"