diff --git a/README.md b/README.md index 71bbd16..d494a2a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Engineering conventions and best practices for Sea Haven Industries. - [Secrets and Configuration](secrets-and-config.md) -- Secrets Manager vs SSM Parameter Store - [CI/CD Pipelines](cicd.md) -- every deployable repo gets a pipeline, no manual deploys - [Git Hooks](hooks/) -- recommended pre-push and pre-commit hooks +- [Scripts](scripts/) -- repo provisioning, automation tooling ## Contributing diff --git a/scripts/provision-repo.sh b/scripts/provision-repo.sh new file mode 100755 index 0000000..220c213 --- /dev/null +++ b/scripts/provision-repo.sh @@ -0,0 +1,232 @@ +#!/usr/bin/env bash +# Provision a new Sea Haven Industries repo with all required infrastructure. +# Usage: ./provision-repo.sh [sam|cdk] +# +# Creates: GitHub repo, OIDC deploy role, repo secret, security features, +# CI/CD workflow stubs, and pre-push hook. + +set -euo pipefail + +REPO_NAME="${1:?Usage: provision-repo.sh [sam|cdk]}" +STACK_TYPE="${2:-sam}" +ORG="Sea-Haven-Industries" +ACCOUNT_ID="328440206208" +REGION="us-east-1" +OIDC_PROVIDER="arn:aws:iam::${ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com" +ROLE_NAME="githubdeploy-${REPO_NAME}" + +if [[ ! "$REPO_NAME" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ ]]; then + echo "Error: repo name must be kebab-case (lowercase, hyphens only, no leading/trailing hyphens)" + exit 1 +fi + +echo "=== Provisioning ${ORG}/${REPO_NAME} (${STACK_TYPE}) ===" + +# 1. Create GitHub repo +echo "" +echo "[1/6] Creating GitHub repo..." +if gh repo view "${ORG}/${REPO_NAME}" &>/dev/null; then + echo " Repo already exists — skipping." +else + gh repo create "${ORG}/${REPO_NAME}" \ + --private \ + --description "${REPO_NAME} — Sea Haven Industries" \ + --clone=false + echo " Created ${ORG}/${REPO_NAME}" +fi + +# 2. Create OIDC deploy role +echo "" +echo "[2/6] Creating IAM deploy role: ${ROLE_NAME}..." +TRUST_POLICY=$(cat </dev/null; then + echo " Role already exists — skipping." +else + aws iam create-role \ + --role-name "${ROLE_NAME}" \ + --assume-role-policy-document "${TRUST_POLICY}" \ + --tags "Key=Project,Value=${REPO_NAME}" "Key=ManagedBy,Value=provision-script" \ + --query 'Role.Arn' --output text + + if [[ "$STACK_TYPE" == "cdk" ]]; then + DEPLOY_POLICY=$(cat </dev/null || true +gh api "repos/${ORG}/${REPO_NAME}" -X PATCH \ + -f security_and_analysis.dependabot_security_updates.status=enabled \ + -f security_and_analysis.secret_scanning.status=enabled \ + --silent 2>/dev/null || true +echo " Dependabot alerts, security updates, and secret scanning enabled." + +# 5. Create CI/CD workflow stubs +echo "" +echo "[5/6] Creating CI/CD workflow files..." + +REPO_DIR="${HOME}/Documents/repositories/${REPO_NAME}" +if [[ ! -d "${REPO_DIR}" ]]; then + echo " Repo not cloned locally — skipping workflow file creation." + echo " Clone it and re-run, or create .github/workflows/ manually." +else + mkdir -p "${REPO_DIR}/.github/workflows" + + if [[ "$STACK_TYPE" == "cdk" ]]; then + cat > "${REPO_DIR}/.github/workflows/ci.yaml" <<'CIEOF' +name: CI +on: + pull_request: + branches: [main] +jobs: + ci: + uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-cdk.yaml@main + with: + node-version: "24" +CIEOF + + cat > "${REPO_DIR}/.github/workflows/deploy.yaml" <<'CDEOF' +name: Deploy +on: + push: + branches: [main] +jobs: + deploy: + uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@main + with: + node-version: "24" + secrets: + deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} +CDEOF + else + cat > "${REPO_DIR}/.github/workflows/ci.yaml" <<'CIEOF' +name: CI +on: + pull_request: + branches: [main] +jobs: + ci: + uses: Sea-Haven-Industries/.github/.github/workflows/ci-python-sam.yaml@main +CIEOF + + cat > "${REPO_DIR}/.github/workflows/deploy.yaml" <<'CDEOF' +name: Deploy +on: + push: + branches: [main] +jobs: + deploy: + uses: Sea-Haven-Industries/.github/.github/workflows/cd-sam.yaml@main + with: + stack-name: "REPO_PLACEHOLDER" + secrets: + cfn-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }} +CDEOF + sed -i '' "s/REPO_PLACEHOLDER/${REPO_NAME}/" "${REPO_DIR}/.github/workflows/deploy.yaml" + fi + echo " Created ci.yaml and deploy.yaml" +fi + +# 6. Install pre-push hook +echo "" +echo "[6/6] Installing pre-push hook..." +if [[ -d "${REPO_DIR}/.git" ]]; then + HOOK_SRC="${HOME}/Documents/repositories/engineering-handbook/hooks/pre-push" + if [[ -f "$HOOK_SRC" ]]; then + cp "$HOOK_SRC" "${REPO_DIR}/.git/hooks/pre-push" + chmod +x "${REPO_DIR}/.git/hooks/pre-push" + echo " Installed pre-push hook." + else + echo " Hook source not found — skipping." + fi +else + echo " No local .git — skipping." +fi + +echo "" +echo "=== Provisioning complete ===" +echo "" +echo "Remaining manual steps:" +echo " 1. Create any Secrets Manager secrets needed (${REPO_NAME}/secret-name)" +echo " 2. Commit and push the workflow files" +echo " 3. Verify CI passes on first PR" +echo " 4. Create a project memory entry"