name: Deploy Hello Lambda CFT on: workflow_dispatch: push: branches: [ main ] jobs: deploy: runs-on: nas-safe env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }} AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }} LOWER: ${{ secrets.LOWER }} steps: - name: Prepare source run: | set -e SRC_DIR="." if [ ! -f "infra/hello-lambda.yml" ]; then echo "Repository files not present in workspace. Cloning from Forgejo..." git clone --depth 1 "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" _src SRC_DIR="_src" fi [ -f "${SRC_DIR}/infra/hello-lambda.yml" ] || { echo "infra/hello-lambda.yml not found"; exit 1; } echo "SRC_DIR=${SRC_DIR}" >> "$GITHUB_ENV" echo "Using source directory: ${SRC_DIR}" - name: Ensure AWS CLI run: | set -e if command -v aws >/dev/null 2>&1; then aws --version exit 0 fi # Try local AWS CLI v2 install (no root required). if command -v curl >/dev/null 2>&1 && command -v unzip >/dev/null 2>&1; then TMP_DIR="$(mktemp -d)" curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "${TMP_DIR}/awscliv2.zip" unzip -q "${TMP_DIR}/awscliv2.zip" -d "${TMP_DIR}" "${TMP_DIR}/aws/install" -i "$HOME/.aws-cli" -b "$HOME/.local/bin" || true if [ -x "$HOME/.local/bin/aws" ]; then echo "$HOME/.local/bin" >> "$GITHUB_PATH" "$HOME/.local/bin/aws" --version exit 0 fi fi # Fallback to pip user install. if command -v python3 >/dev/null 2>&1; then python3 -m pip install --user --upgrade awscli echo "$HOME/.local/bin" >> "$GITHUB_PATH" "$HOME/.local/bin/aws" --version exit 0 fi echo "Unable to install aws CLI on this runner." exit 1 - name: Parse LOWER bundled secret run: | set -e if [ -z "$LOWER" ]; then echo "LOWER secret is empty or not set; using individual secrets if present." exit 0 fi python3 - <<'PY' import json import os keys = [ "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_DEFAULT_REGION", "AWS_REGION", ] lower = os.environ.get("LOWER", "") parsed = {} # Format 1: JSON object try: obj = json.loads(lower) if isinstance(obj, dict): parsed = {str(k): str(v) for k, v in obj.items() if v is not None} except Exception: pass # Format 2: dotenv style lines: KEY=VALUE if not parsed: for line in lower.splitlines(): s = line.strip() if not s or s.startswith("#") or "=" not in s: continue k, v = s.split("=", 1) parsed[k.strip()] = v.strip().strip('"').strip("'") env_path = os.environ["GITHUB_ENV"] with open(env_path, "a", encoding="utf-8") as f: for k in keys: if os.environ.get(k): continue v = parsed.get(k) if v: f.write(f"{k}={v}\n") # Accept AWS_REGION in bundle as region source. if not os.environ.get("AWS_DEFAULT_REGION") and parsed.get("AWS_REGION"): f.write(f"AWS_DEFAULT_REGION={parsed['AWS_REGION']}\n") PY - name: Check required AWS secrets run: | [ -n "$AWS_ACCESS_KEY_ID" ] || { echo "Missing required secret/env: AWS_ACCESS_KEY_ID"; exit 1; } [ -n "$AWS_SECRET_ACCESS_KEY" ] || { echo "Missing required secret/env: AWS_SECRET_ACCESS_KEY"; exit 1; } [ -n "$AWS_DEFAULT_REGION" ] || { echo "Missing required secret/env: AWS_DEFAULT_REGION"; exit 1; } if [ -z "${AWS_SESSION_TOKEN}" ]; then echo "AWS_SESSION_TOKEN is empty. Proceeding with long-lived access keys." else echo "AWS_SESSION_TOKEN is set. Proceeding with STS temporary credentials." fi - name: Verify AWS identity run: | set -e if ! aws sts get-caller-identity; then echo "AWS authentication failed. If using STS creds, regenerate and update all 3 secrets: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN." exit 1 fi - name: Validate CFT run: | aws cloudformation validate-template \ --template-body "file://${SRC_DIR}/infra/hello-lambda.yml" - name: Deploy CFT run: | aws cloudformation deploy \ --stack-name hello-lambda-stack \ --template-file "${SRC_DIR}/infra/hello-lambda.yml" \ --capabilities CAPABILITY_NAMED_IAM