refactor: improve Lambda handler and update Go to 1.25.5
- Update Dockerfile: Go 1.25.5, fix build context paths - Use git archive instead of zip to exclude .git directory - Add context support for git/zip operations (timeout control) - Optimize git clone (--depth 1, --single-branch) - Improve error handling (%w wrapping) and logging consistency - Add case-insensitive HTTP header lookup for webhooks
This commit is contained in:
parent
621b9f006e
commit
2ebcc5541e
2 changed files with 46 additions and 43 deletions
|
|
@ -11,6 +11,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-lambda-go/lambda"
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
|
|
@ -34,6 +35,7 @@ type Response struct {
|
|||
}
|
||||
|
||||
var commandRunner = exec.Command
|
||||
var commandRunnerContext = exec.CommandContext
|
||||
|
||||
// verifySignature computes an HMAC using the provided secret and compares it to the incoming signature.
|
||||
func verifySignature(secret, body, signatureHeader string) bool {
|
||||
|
|
@ -50,6 +52,15 @@ func verifySignature(secret, body, signatureHeader string) bool {
|
|||
return hmac.Equal([]byte(receivedSig), []byte(expectedSig))
|
||||
}
|
||||
|
||||
func getHeader(headers map[string]string, key string) string {
|
||||
for k, v := range headers {
|
||||
if strings.EqualFold(k, key) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func handleRequest(ctx context.Context, event json.RawMessage) (Response, error) {
|
||||
// For demonstration, assume the event JSON includes a "body" and "headers" map.
|
||||
var req struct {
|
||||
|
|
@ -67,7 +78,7 @@ func handleRequest(ctx context.Context, event json.RawMessage) (Response, error)
|
|||
return Response{StatusCode: 500, Headers: map[string]string{"Content-Type": "application/json"}, Body: "{\"message\":\"Server configuration error\"}"}, fmt.Errorf("WEBHOOK_SECRET is not set")
|
||||
}
|
||||
|
||||
signature := req.Headers["X-Hub-Signature-256"] // adjust this header name as appropriate.
|
||||
signature := getHeader(req.Headers, "X-Hub-Signature-256")
|
||||
if signature == "" || !verifySignature(secret, req.Body, signature) {
|
||||
log.Println("Signature verification failed")
|
||||
return Response{StatusCode: 401, Headers: map[string]string{"Content-Type": "application/json"}, Body: "{\"message\":\"Unauthorized\"}"}, fmt.Errorf("signature verification failed")
|
||||
|
|
@ -95,47 +106,42 @@ func main() {
|
|||
}
|
||||
|
||||
func runDeploymentProcess(ctx context.Context) error {
|
||||
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
log.Printf("Configuration error: %v", err)
|
||||
return err
|
||||
return fmt.Errorf("load config: %w", err)
|
||||
}
|
||||
|
||||
// Create a unique temp directory for this run
|
||||
repoDir, err := os.MkdirTemp("", "repo-*")
|
||||
if err != nil {
|
||||
log.Printf("Error creating temporary directory: %v", err)
|
||||
return err
|
||||
return fmt.Errorf("create temp directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(repoDir)
|
||||
|
||||
zipFilePath := filepath.Join(repoDir, "source.zip")
|
||||
|
||||
// 1. Clone the repository
|
||||
if err := cloneRepository(ctx, cfg.RepoURL, cfg.RepoBranch, repoDir); err != nil {
|
||||
log.Printf("Failure in cloning: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. Create a ZIP archive of the repository
|
||||
// 2. Create a ZIP archive of the repository (without .git)
|
||||
if err := createZipArchive(ctx, repoDir, zipFilePath); err != nil {
|
||||
log.Printf("Failure in creating ZIP archive: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 3. Upload the ZIP file to S3
|
||||
cfg_s3, err := config.LoadDefaultConfig(ctx, config.WithRegion(cfg.AWSRegion))
|
||||
awsCfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(cfg.AWSRegion))
|
||||
if err != nil {
|
||||
log.Printf("Error loading configuration: %v", err)
|
||||
return err
|
||||
return fmt.Errorf("load AWS config: %w", err)
|
||||
}
|
||||
s3Client := s3.NewFromConfig(cfg_s3)
|
||||
|
||||
s3Client := s3.NewFromConfig(awsCfg)
|
||||
uploader := manager.NewUploader(s3Client)
|
||||
if err := uploadToS3WithUploader(ctx, zipFilePath, cfg.S3Bucket, cfg.S3Key, uploader); err != nil {
|
||||
log.Printf("Failure in uploading to S3: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println("Deployment process completed successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -169,28 +175,28 @@ func loadConfig() (*Config, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func cloneRepository(_ context.Context, repoURL, repoBranch, repoDir string) error {
|
||||
cloneCmd := commandRunner("git", "clone", "--branch", repoBranch, repoURL, repoDir)
|
||||
func cloneRepository(ctx context.Context, repoURL, repoBranch, repoDir string) error {
|
||||
log.Printf("Cloning repository (branch=%s)...", repoBranch)
|
||||
cloneCmd := commandRunnerContext(ctx, "git", "clone", "--depth", "1", "--single-branch", "--branch", repoBranch, repoURL, repoDir)
|
||||
cloneCmd.Stdout = os.Stdout
|
||||
cloneCmd.Stderr = os.Stderr
|
||||
fmt.Printf("Cloning repository %s (branch %s)...\n", repoURL, repoBranch)
|
||||
cloneCmd.Env = append(os.Environ(), "GIT_TERMINAL_PROMPT=0")
|
||||
if err := cloneCmd.Run(); err != nil {
|
||||
return fmt.Errorf("error cloning repository: %v", err)
|
||||
return fmt.Errorf("git clone: %w", err)
|
||||
}
|
||||
fmt.Println("Repository cloned successfully.")
|
||||
log.Println("Repository cloned successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func createZipArchive(_ context.Context, repoDir, zipFilePath string) error {
|
||||
zipCmd := commandRunner("zip", "-r", zipFilePath, ".")
|
||||
zipCmd.Dir = repoDir // Change to the cloned repo directory
|
||||
zipCmd.Stdout = os.Stdout
|
||||
zipCmd.Stderr = os.Stderr
|
||||
fmt.Println("Creating ZIP archive of the repository...")
|
||||
if err := zipCmd.Run(); err != nil {
|
||||
return fmt.Errorf("error creating ZIP archive: %v", err)
|
||||
func createZipArchive(ctx context.Context, repoDir, zipFilePath string) error {
|
||||
log.Println("Creating ZIP archive (using git archive)...")
|
||||
archiveCmd := commandRunnerContext(ctx, "git", "-C", repoDir, "archive", "--format=zip", "--output", zipFilePath, "HEAD")
|
||||
archiveCmd.Stdout = os.Stdout
|
||||
archiveCmd.Stderr = os.Stderr
|
||||
if err := archiveCmd.Run(); err != nil {
|
||||
return fmt.Errorf("git archive: %w", err)
|
||||
}
|
||||
fmt.Printf("ZIP archive created at %s.\n", zipFilePath)
|
||||
log.Printf("ZIP archive created at %s", zipFilePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -199,26 +205,22 @@ type Uploader interface {
|
|||
}
|
||||
|
||||
func uploadToS3WithUploader(ctx context.Context, zipPath, bucket, key string, uploader Uploader) error {
|
||||
|
||||
// Open the ZIP file
|
||||
f, err := os.Open(zipPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error opening ZIP file: %v", err)
|
||||
return fmt.Errorf("open zip file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Upload the file to S3.
|
||||
fmt.Printf("Uploading %s to s3://%s/%s...\n", zipPath, bucket, key)
|
||||
log.Printf("Uploading %s to s3://%s/%s...", zipPath, bucket, key)
|
||||
result, err := uploader.Upload(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
Body: f,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upload file: %v", err)
|
||||
return fmt.Errorf("upload to S3: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully uploaded to %s\n", result.Location)
|
||||
|
||||
log.Printf("Successfully uploaded: %s", result.Location)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
FROM docker.io/golang:1.24.2-bookworm as build
|
||||
FROM docker.io/golang:1.25.5-bookworm as build
|
||||
WORKDIR /app
|
||||
# Copy dependencies list
|
||||
COPY ./app/go.mod ./
|
||||
COPY ./app/go.sum ./
|
||||
# NOTE: This Dockerfile assumes the build context is the repository root.
|
||||
# Example: docker build -f docker/Dockerfile .
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
# Build with optional lambda.norpc tag
|
||||
COPY ./app/main.go ./
|
||||
RUN go build -tags lambda.norpc -o main main.go
|
||||
RUN go build -tags lambda.norpc -o main ./cmd/lambda
|
||||
# Copy artifacts to a clean image
|
||||
FROM public.ecr.aws/lambda/provided:al2023
|
||||
# Install git and zip using dnf (Amazon Linux 2023)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue