mirror of
https://github.com/Sea-Haven-Industries/engineering-handbook.git
synced 2026-09-30 19:43:14 +00:00
Adds three handbook pages covering conventions that were previously scattered across feedback memories or rederived from scratch each time: - bedrock.md captures the cross-region inference profile requirement for Claude 4.x Bedrock Agents and the alias-version pinning gotcha, plus the IAM resource pattern and the KB Docker requirement. - dev-environment.md documents the workstation directory layout, pyenv/Node conventions, the macOS launchd/TCC sandbox gotcha, and cleanup cadence. - lambda-template.md provides a minimal SAM scaffold that follows the Lambda defaults already in aws-infrastructure.md (Python 3.12, arm64, explicit 60-day log retention, scoped Secrets Manager access, module-level secret cache). Also extends two existing pages: - sam-project-layout.md gains a Lambda Layers section with the BuildMethod nesting pattern that caused a ~22-hour production outage when violated. - naming-conventions.md adds a Legacy Stacks note acknowledging that pre-convention PascalCase stacks (SeaHavenDoorUnlockStack, WorkorderIngestStack) stay as-is rather than risk stack replacement.
3.2 KiB
3.2 KiB
Lambda Starter Template
Minimal SAM scaffold for a new Python Lambda. Drop into template.yaml and adjust names. Follows the defaults in aws-infrastructure.md.
Project Structure
my-stack/
├── template.yaml
├── samconfig.toml.example
├── src/
│ └── handler/
│ ├── app.py
│ └── requirements.txt
└── .gitignore
See sam-project-layout.md for the full directory convention.
template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: my-stack — one-line purpose
Globals:
Function:
Runtime: python3.12
Architecture: arm64
Timeout: 30
MemorySize: 256
LoggingConfig:
LogFormat: JSON
Resources:
HandlerFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: my-stack-handler
CodeUri: src/handler/
Handler: app.handler
Environment:
Variables:
CONFIG_SECRET: my-stack/config
Policies:
- AWSLambdaBasicExecutionRole
- Statement:
- Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:my-stack/*
HandlerLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HandlerFunction}
RetentionInDays: 60
Outputs:
HandlerArn:
Description: Handler Lambda ARN
Value: !GetAtt HandlerFunction.Arn
Key points:
Globals.Functionsets runtime, architecture, and JSON logging once for the whole template.- The
LogGroupis declared explicitly withRetentionInDays: 60. Omit it and CloudWatch creates the log group on first invocation with no retention — logs accumulate forever. - IAM scopes
secretsmanager:GetSecretValueto the stack's secret prefix only. Add specific permissions as needed; never useAdministratorAccess.
src/handler/app.py
import json
import os
import boto3
_secrets_client = boto3.client("secretsmanager")
_config = None
def _get_config():
global _config
if _config is None:
resp = _secrets_client.get_secret_value(SecretId=os.environ["CONFIG_SECRET"])
_config = json.loads(resp["SecretString"])
return _config
def handler(event, context):
config = _get_config()
# ... your logic ...
return {"statusCode": 200, "body": json.dumps({"ok": True})}
The module-level _config global caches the secret across warm invocations. The first call per cold start hits Secrets Manager; subsequent calls reuse the cached value. See secrets-and-config.md for the rationale.
src/handler/requirements.txt
Keep this file in every function directory even when empty — SAM looks for it during sam build.
# Per-function dependencies. Leave empty if the function uses only boto3 and stdlib.
Naming Reminders
FunctionNamemust be kebab-case and start with the stack name (my-stack-handler).- Secret IDs use
stack-name/secret-name. - Stack name itself is set in
samconfig.toml, not the template — match the repo name.