Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .claude/skills/cors-deployment/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
name: cors-deployment
description: CORS configuration across all CDK stacks, GitHub Actions workflows, and Python backends. Use when modifying CORS origins, adding new stacks that need CORS, debugging CORS errors in deployed environments, or touching any workflow env vars related to CDK_DOMAIN_NAME or CDK_CORS_ORIGINS.
---

# CORS Deployment Configuration

## Architecture

CORS is configured via a two-layer model applied identically to every stack:

1. `CDK_DOMAIN_NAME` → auto-applied as `https://{value}` (always)
2. `CDK_CORS_ORIGINS` → additional global origins (optional, comma-separated)
3. Per-section `CDK_*_CORS_ORIGINS` → stack-specific extras (optional)

localhost is NEVER auto-included. Use `CDK_CORS_ORIGINS=http://localhost:4200` for local dev.

## The Helper

Every stack uses `buildCorsOrigins(config, additionalOrigins?)` from `infrastructure/lib/config.ts`. This returns a deduplicated `string[]`.

```typescript
// Container env var (Fargate / AgentCore Runtime)
CORS_ORIGINS: buildCorsOrigins(config, config.appApi.additionalCorsOrigins).join(','),

// S3 bucket CORS rule
cors: [{ allowedOrigins: buildCorsOrigins(config, config.fileUpload?.additionalCorsOrigins) }]
```

## Config Derivation (config.ts)

```
CDK_DOMAIN_NAME → domainName → "https://{domainName}" (always first)
CDK_CORS_ORIGINS → extraCorsOrigins (appended)
Result: config.corsOrigins = "https://{domainName},{extras}"
```

Both are joined into `config.corsOrigins`. The helper then splits, deduplicates, and optionally appends section extras.

## Python Backend

Both `app_api/main.py` and `inference_api/main.py` read `CORS_ORIGINS` env var:

```python
_cors_origins = os.environ.get("CORS_ORIGINS", "").split(",")
```

No hardcoded fallback. If `CORS_ORIGINS` is empty, no origins are allowed.

## Workflow Requirements

`CDK_DOMAIN_NAME` and `CDK_CORS_ORIGINS` MUST be in the **job-level** `env:` block (not workflow-level) because they use `vars.*` which requires `environment:` on the job.

Every workflow that runs synth or deploy must include:
```yaml
env:
CDK_DOMAIN_NAME: ${{ vars.CDK_DOMAIN_NAME }}
CDK_CORS_ORIGINS: ${{ vars.CDK_CORS_ORIGINS }}
```

## Per-Section Config Interfaces

Every config section that consumes CORS has `additionalCorsOrigins?: string`:
- `AppApiConfig.additionalCorsOrigins`
- `InferenceApiConfig.additionalCorsOrigins`
- `FrontendConfig.additionalCorsOrigins`
- `FileUploadConfig.additionalCorsOrigins`
- `RagIngestionConfig.additionalCorsOrigins`
- `AssistantsConfig.additionalCorsOrigins`
- `FineTuningConfig.additionalCorsOrigins`

## Adding CORS to a New Stack

1. Import `buildCorsOrigins` from `./config`
2. Call `buildCorsOrigins(config, config.mySection.additionalCorsOrigins)`
3. Add `additionalCorsOrigins?: string` to the section's config interface
4. Load it in `loadConfig()`: `additionalCorsOrigins: process.env.CDK_MY_SECTION_CORS_ORIGINS || ...`
5. Add `CDK_DOMAIN_NAME` and `CDK_CORS_ORIGINS` to the workflow job env
6. Add a test in `infrastructure/test/cors.test.ts`

## Common Mistakes

- Putting `vars.*` in workflow-level `env:` → resolves to empty string
- Hardcoding `http://localhost:4200` in buildCorsOrigins or Python fallback
- Forgetting to add `CDK_DOMAIN_NAME` to a new workflow's synth/deploy jobs
- Using `config.domainName` directly instead of `buildCorsOrigins()`
- Setting `corsOrigins` in `cdk.context.json` (overrides domain derivation)
91 changes: 91 additions & 0 deletions .claude/skills/release-notes/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: release-notes
description: Write and update RELEASE_NOTES.md for this monorepo. Use when creating release notes, updating an existing release entry, or preparing a release. Covers the squash-merge branch model, how to identify changes across divergent main/develop histories, writing style, section structure, and common pitfalls.
---

# Writing Release Notes

## Branch Model & Why This Is Hard

This repo uses a squash-merge workflow: `develop` accumulates feature branches via merge commits, and when a release is cut, `develop` is squash-merged into `main`. This means `main` and `develop` have **divergent git histories** — you cannot do a simple `git log main..develop` to get a clean diff. Commit SHAs on `main` don't correspond to anything on `develop`.

## How to Identify What Changed

### Step 1: Find the boundary

Look at the last squash-merge commit on `main` to determine when the previous release was cut:

```bash
git log main --oneline -5
```

Then find the corresponding release tag or date. Use that date as your boundary.

### Step 2: List commits on develop since the boundary

```bash
git log develop --oneline --no-merges --since="<date-of-last-release>"
```

This gives you the raw commit list, but **do not rely solely on commit messages**. Dependabot commits are usually accurate, but human commits often have vague or incomplete messages.

### Step 3: Inspect the actual code changes

For every non-trivial commit, read the diff or at minimum the `--stat` output:

```bash
git show --stat <sha>
git show --no-patch <sha> # full commit message
```

For feature commits, read the changed files to understand what was actually built — not just what the message claims. Look for:

- New API endpoints (routes files)
- New or modified models/schemas
- New frontend pages or components
- Infrastructure changes (CDK stacks, config)
- New test files (indicates new functionality)
- Dependency changes (pyproject.toml, package.json)

### Step 4: Group by category

Organize changes into the standard sections used by prior releases. Review the existing release notes in the file for the established pattern. Typical sections include:

- **Highlights** — 2-3 sentence summary of the release theme
- **New features** — each gets its own H2 with subsections for backend/frontend/infra
- **Bug fixes** — concise list
- **Security** — vulnerability patches, CodeQL fixes
- **Dependency upgrades** — table format
- **CI/CD improvements** — workflow changes
- **Test fixes** — test-only changes
- **Deployment notes** — what operators need to do differently

## Writing Style

- Match the tone and depth of the existing release notes in the file. They are detailed and technical — written for developers who will deploy and maintain this system.
- Every feature section should explain **what** changed, **why** it matters, and **how** it works at a technical level.
- Use specific file names, endpoint paths, and class names when relevant.
- Include line counts for large test additions (e.g., "4,200+ lines of new tests").
- For dependency upgrades, use a markdown table with From/To columns.
- The Highlights section should read as a standalone summary — someone skimming only that paragraph should understand the release.

## Header Format

```markdown
# Release Notes — v1.0.0-beta.XX

**Release Date:** <Month Day, Year>
**Previous Release:** v1.0.0-beta.XX-1 (<date>)

---
```

The new release goes at the **top** of the file. Do not modify previous release sections.

## Common Pitfalls

- **Don't trust commit messages blindly.** A commit titled "fix: update models" might contain a new feature with 800 lines of code. Always check the diff.
- **Don't miss Dependabot PRs.** They often bump 10+ packages in a single grouped PR. Check `pyproject.toml`, `package.json`, and workflow files for version changes.
- **Don't forget CI/CD changes.** Workflow file modifications (`.github/workflows/`) are easy to overlook but important for operators.
- **Don't duplicate sections.** If a feature spans backend + frontend + infra, keep it in one section with subsections — don't scatter it across the document.
- **Check the VERSION file and README badge.** These should already be updated via `sync-version.sh` before the release notes are finalized.
22 changes: 11 additions & 11 deletions .github/ACTIONS-REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@ GitHub provides two mechanisms for storing configuration values:
| AWS_SECRET_ACCESS_KEY | Secret | No | None | All | AWS secret access key for authentication (alternative to role-based auth) |
| CDK_ALB_SUBDOMAIN | Variable | No | None | Infrastructure | Subdomain for ALB (e.g., 'api' for api.yourdomain.com) |
| CDK_APP_API_CPU | Variable | No | `512` | Infrastructure, App API | CPU units for App API ECS task (256, 512, 1024, 2048, 4096) |
| CDK_APP_API_CORS_ORIGINS | Variable | No | None | App API | Additional CORS origins for the app API only (appended to global CORS origins) |
| CDK_APP_API_DESIRED_COUNT | Variable | No | `1` | Infrastructure, App API | Desired number of App API tasks running |
| CDK_APP_API_ENABLED | Variable | No | `true` | App API | Enable/disable App API stack deployment |
| CDK_APP_API_MAX_CAPACITY | Variable | No | `10` | Infrastructure, App API | Maximum App API tasks for auto-scaling |
| CDK_APP_API_MEMORY | Variable | No | `1024` | Infrastructure, App API | Memory (MB) for App API ECS task (512, 1024, 2048, 4096, 8192) |
| CDK_ASSISTANTS_CORS_ORIGINS | Variable | No | None | Infrastructure | Additional CORS origins for the assistants module only (appended to global CORS origins) |
| CDK_AWS_ACCOUNT | Variable | Yes | None | All | 12-digit AWS account ID for CDK deployment |
| CDK_CERTIFICATE_ARN | Variable | No | None | Infrastructure | ACM certificate ARN for HTTPS on ALB |
| CDK_CORS_ORIGINS | Variable | No | `http://localhost:4200,http://localhost:8000` | All | Top-level CORS origins (default for sections that don't override) |
| CDK_DOMAIN_NAME | Variable | No | None | Frontend, App API | Custom domain name (e.g., 'app.example.com') |
| CDK_FILE_UPLOAD_CORS_ORIGINS | Variable | No | `http://localhost:4200` | Infrastructure, App API | Comma-separated CORS origins for file upload S3 bucket |
| CDK_CORS_ORIGINS | Variable | No | None | All | Additional CORS origins appended to the auto-derived `https://{CDK_DOMAIN_NAME}`. Comma-separated. Use for localhost during local dev (e.g., `http://localhost:4200`) or extra domains. |
| CDK_DOMAIN_NAME | Variable | No | None | All | Primary domain name (e.g., 'alpha.boisestate.ai'). Auto-applied as `https://{value}` to CORS origins for every stack. This is the primary mechanism for CORS configuration. |
| CDK_FILE_UPLOAD_CORS_ORIGINS | Variable | No | None | Infrastructure | Additional CORS origins for the file upload S3 bucket only (appended to global CORS origins) |
| CDK_FILE_UPLOAD_MAX_SIZE_MB | Variable | No | `10` | Infrastructure, App API | Maximum file upload size in megabytes |
| CDK_FINE_TUNING_ENABLED | Variable | No | `false` | SageMaker Fine-Tuning, App API | Enable SageMaker fine-tuning stack and App API fine-tuning routes. Must be `true` before deploying the SageMaker Fine-Tuning workflow. |
| CDK_FINE_TUNING_CORS_ORIGINS | Variable | No | None | SageMaker Fine-Tuning | Additional CORS origins for the fine-tuning S3 bucket only (appended to global CORS origins) |
| CDK_FINE_TUNING_DEFAULT_QUOTA_HOURS | Variable | No | `0` | App API | Default monthly GPU-hour quota for all authenticated users. `0` = whitelist-only (admin must grant each user). Positive value (e.g. `5`) = open access with that default budget. |
| CDK_FRONTEND_BUCKET_NAME | Variable | No | None | Frontend | S3 bucket name for frontend assets (defaults to generated name with account ID) |
| CDK_FRONTEND_CORS_ORIGINS | Variable | No | None | Frontend | Additional CORS origins for the frontend SSM export only (appended to global CORS origins) |
| CDK_FRONTEND_CERTIFICATE_ARN | Variable | No | None | Frontend | ACM certificate ARN for HTTPS on CloudFront (required for custom domain) |
| CDK_FRONTEND_CLOUDFRONT_PRICE_CLASS | Variable | No | `PriceClass_100` | Frontend | CloudFront price class (PriceClass_100, PriceClass_200, PriceClass_All) |
| CDK_FRONTEND_ENABLED | Variable | No | `true` | Frontend | Enable/disable Frontend stack deployment |
Expand All @@ -48,20 +52,16 @@ GitHub provides two mechanisms for storing configuration values:
| CDK_GATEWAY_THROTTLE_RATE_LIMIT | Variable | No | `10000` | Gateway | API Gateway rate limit for throttling (requests per second) |
| CDK_HOSTED_ZONE_DOMAIN | Variable | No | None | Infrastructure, App API | Route53 hosted zone domain name (e.g., 'example.com') |
| CDK_INFERENCE_API_CPU | Variable | No | `1024` | Infrastructure, Inference API | CPU units for Inference API AgentCore Runtime (256, 512, 1024, 2048, 4096) |
| CDK_INFERENCE_API_CORS_ORIGINS | Variable | No | None | Inference API | Additional CORS origins for the inference API only (appended to global CORS origins) |
| CDK_INFERENCE_API_DESIRED_COUNT | Variable | No | `1` | Infrastructure, Inference API | Desired number of Inference API runtime instances |
| CDK_INFERENCE_API_ENABLED | Variable | No | `true` | Inference API | Enable/disable Inference API stack deployment |
| CDK_INFERENCE_API_MAX_CAPACITY | Variable | No | `5` | Infrastructure, Inference API | Maximum Inference API runtime instances for auto-scaling |
| CDK_INFERENCE_API_MEMORY | Variable | No | `2048` | Infrastructure, Inference API | Memory (MB) for Inference API AgentCore Runtime (512, 1024, 2048, 4096, 8192) |
| CDK_PRODUCTION | Variable | No | `true` | Frontend | Production environment flag (affects runtime config generation) |
| CDK_PROJECT_PREFIX | Variable | Yes | `agentcore` | All | Prefix for all resource names (e.g., 'mycompany-agentcore') |
| CDK_RAG_CORS_ORIGINS | Variable | No | None | RAG Ingestion | Additional CORS origins for the RAG documents S3 bucket only (appended to global CORS origins) |
| CDK_RETAIN_DATA_ON_DELETE | Variable | No | `false` | All | Retain data resources (DynamoDB, S3, Secrets) on stack deletion |
| CDK_VPC_CIDR | Variable | No | `10.0.0.0/16` | Infrastructure, App API | CIDR block for VPC network |
| ENV_INFERENCE_API_CORS_ORIGINS | Variable | No | None | Inference API | Comma-separated CORS origins for runtime environment |
| ENV_INFERENCE_API_CORS_ORIGINS | Variable | No | None | Inference API | _(Deprecated — use CDK_INFERENCE_API_CORS_ORIGINS instead)_ |
| ENV_INFERENCE_API_LOG_LEVEL | Variable | No | `INFO` | Inference API | Log level for runtime container (DEBUG, INFO, WARNING, ERROR) |
| SEED_ADMIN_JWT_ROLE | Variable | No | None | Bootstrap Data Seeding | JWT role that grants system admin access (e.g., `Admin`). Maps to the `system_admin` AppRole. |
| SEED_AUTH_BUTTON_COLOR | Variable | No | None | Bootstrap Data Seeding | Hex color for the auth provider login button (e.g., '#0078D4') |
| SEED_AUTH_CLIENT_ID | Variable | No | None | Bootstrap Data Seeding | OAuth client ID for the initial OIDC auth provider |
| SEED_AUTH_CLIENT_SECRET | Secret | No | None | Bootstrap Data Seeding | OAuth client secret for the initial OIDC auth provider |
| SEED_AUTH_DISPLAY_NAME | Variable | No | None | Bootstrap Data Seeding | Display name shown on the login page (e.g., 'Microsoft Entra ID') |
| SEED_AUTH_ISSUER_URL | Variable | No | None | Bootstrap Data Seeding | OIDC issuer URL for the auth provider (e.g., 'https://login.microsoftonline.com/TENANT/v2.0') |
| SEED_AUTH_PROVIDER_ID | Variable | No | None | Bootstrap Data Seeding | Slug identifier for the auth provider (e.g., 'entra-id') |
| SEED_ADMIN_JWT_ROLE | Variable | No | None | Bootstrap Data Seeding | _(Deprecated)_ Previously used for JWT role mapping. Admin access is now granted automatically via the Cognito first-boot flow. |
Loading
Loading