Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8482248
feat: add oidc provider
rezabekf Dec 3, 2025
5c2dfaa
refactor: temp enable feature branch
rezabekf Dec 3, 2025
fab9884
Merge branch 'main' into rezabekf/configure-deployment-to-aws
rezabekf Dec 3, 2025
20f0fad
fix: the skipped job
rezabekf Dec 3, 2025
88850f3
fix: the subject claim for test deploy
rezabekf Dec 3, 2025
1ae03de
fix: assume role
rezabekf Dec 3, 2025
ec34fc0
refactor: revert back feature branch perm
rezabekf Dec 3, 2025
6b2d4c3
fix: scope down iam role
rezabekf Dec 3, 2025
122eefb
fix: action to test scope down policies
rezabekf Dec 3, 2025
aacca22
refactor: add cdk nag and suporessioin
rezabekf Dec 3, 2025
7083305
fix: revert testing condition
rezabekf Dec 3, 2025
b77c944
refactor: deploy to prod instead dev
rezabekf Dec 4, 2025
1e73105
feat: add pipeline stages
rezabekf Dec 4, 2025
c6953e5
refactor: consistent job naming
rezabekf Dec 4, 2025
9467360
refactor: scope down job permission
rezabekf Dec 4, 2025
3450d74
refactor: update stage name and add CI doc
rezabekf Dec 4, 2025
1cad4c2
feat: add test and staging account
rezabekf Dec 5, 2025
b18132e
chore: add docs
rezabekf Dec 5, 2025
ab7705a
fix: remove redundant thumbprint
rezabekf Dec 5, 2025
beb8209
feat: add manuall run workflow button
rezabekf Dec 5, 2025
a90b917
chore: update docs about forks
rezabekf Dec 5, 2025
c272905
Merge remote-tracking branch 'origin/main' into rezabekf/configure-de…
rezabekf Feb 4, 2026
b6b9af2
Merge branch 'main' into rezabekf/configure-deployment-to-aws
rezabekf Feb 6, 2026
cb07592
ci: add path filtering and update pipeline documentation
rezabekf Feb 6, 2026
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
118 changes: 113 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ name: CI

permissions:
contents: read
pull-requests: write

on:
pull_request:
Expand All @@ -11,10 +10,22 @@ on:
push:
branches:
- main
paths:
- 'src/**'
- 'infra/**'
- 'tests/**'
- 'evals/**'
- 'scripts/**'
- 'pyproject.toml'
- 'uv.lock'
- '.github/workflows/ci.yml'

jobs:
python-tests:
test-python:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -37,13 +48,13 @@ jobs:

- name: Coverage comment
if: github.event_name == 'pull_request'
uses: py-cov-action/python-coverage-comment-action@v3
uses: py-cov-action/python-coverage-comment-action@a6a4209d6d08f73ae4b29d2cf53377002b44bd8f # v3
with:
GITHUB_TOKEN: ${{ github.token }}
MINIMUM_GREEN: 90
MINIMUM_ORANGE: 70

typescript-tests:
test-typescript:
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand Down Expand Up @@ -74,7 +85,7 @@ jobs:
run: npm test
working-directory: infra

cdk-nag-test:
test-cdk-nag:
runs-on: ubuntu-latest
steps:
- name: Checkout code
Expand Down Expand Up @@ -104,3 +115,100 @@ jobs:
- name: Run CDK Nag checks
run: npm run synth > /dev/null
working-directory: infra

deploy-staging:
runs-on: ubuntu-latest
needs: [test-python, test-typescript, test-cdk-nag]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment: staging
permissions:
contents: read
id-token: write
concurrency:
group: deploy-staging
cancel-in-progress: false
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
audience: sts.amazonaws.com

- name: Install uv
uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4
with:
python-version: "3.12"
enable-cache: true
prune-cache: false
cache-dependency-glob: |
uv.lock
pyproject.toml

- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: infra/package-lock.json

- name: Install dependencies
run: npm ci
working-directory: infra

- name: Deploy to AWS
run: npm run deploy
working-directory: infra
env:
ENVIRONMENT: staging

deploy-prod:
runs-on: ubuntu-latest
needs: [deploy-staging]
environment: prod
permissions:
contents: read
id-token: write
concurrency:
group: deploy-prod
cancel-in-progress: false
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: us-east-1
audience: sts.amazonaws.com

- name: Install uv
uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4
with:
python-version: "3.12"
enable-cache: true
prune-cache: false
cache-dependency-glob: |
uv.lock
pyproject.toml

- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: infra/package-lock.json

- name: Install dependencies
run: npm ci
working-directory: infra

- name: Deploy to AWS
run: npm run deploy
working-directory: infra
env:
ENVIRONMENT: prod
4 changes: 1 addition & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ documentation, we greatly value feedback and contributions from our community.
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
information to effectively respond to your bug report or contribution.

> **For local development setup instructions**, see [Local Development Guide](docs/LOCAL_DEVELOPMENT.md).


## Reporting Bugs/Feature Requests

We welcome you to use the GitHub issue tracker to report bugs or suggest features.

When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:


* A reproducible test case or series of steps
* The version of our code being used
* Any modifications you've made relevant to the bug
Expand Down
16 changes: 8 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ setup: init pre-commit-install

init:
uv sync --group agents --group dev --group eval
cd infra && npm install
npm install --prefix infra
@echo "✓ Python deps installed in .venv/"
@echo "✓ Node deps installed in infra/"

Expand All @@ -50,7 +50,7 @@ test:
@echo "Running Python tests with coverage..."
uv run pytest tests/ --cov=src --cov-report=term-missing
@echo "Running TypeScript tests..."
cd infra && npm test
npm test --prefix infra
@echo "✓ All tests completed!"

eval:
Expand Down Expand Up @@ -78,9 +78,9 @@ invoke-agent-local:
-d '{}'


cdk-bootstrap:
cdk-bootstrap:
@echo "Bootstrapping CDK..."
cd infra && npm run build && npx cdk bootstrap
npm run cdk --prefix infra -- bootstrap
@echo "✓ CDK bootstrap completed"

cdk-deploy:
Expand All @@ -89,16 +89,16 @@ cdk-deploy:
npm run deploy --prefix infra
@echo "✓ CDK deployment completed"

cdk-hotswap:
cdk-hotswap:
@echo "Fast deploying Lambda changes..."
@echo "Environment: $(or $(ENVIRONMENT),dev), Version: $(or $(VERSION),v1)"
npx cdk deploy --hotswap --prefix infra
npm run deploy --prefix infra -- --hotswap
@echo "✓ CDK hotswap deployment completed"

cdk-watch:
cdk-watch:
@echo "Starting CDK watch mode..."
@echo "Environment: $(or $(ENVIRONMENT),dev), Version: $(or $(VERSION),v1)"
npx cdk watch --prefix infra
npm run cdk --prefix infra -- watch

cdk-destroy:
@echo "Destroying CDK stack..."
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ aws events put-events --entries '[{
}]'
```

## CI/CD Pipeline (Optional)

The project includes GitHub Actions workflows for automated deployment using OIDC authentication (no stored credentials). See [CI/CD Pipeline Guide](docs/cicd_pipeline.md) for setup instructions.

## Monitoring

Check the Step Functions console for workflow execution status. View reports in the Amazon S3 bucket (output in CDK deployment). Query Amazon DynamoDB for event history and audit trails.
Expand Down
86 changes: 86 additions & 0 deletions docs/cicd_pipeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# CI/CD Pipeline

## Environments

| Environment | Purpose | OIDC Setup | Deployed via |
|-------------|---------|------------|--------------|
| `dev` | Local development | No | Manual (`make cdk-deploy`) |
| `staging` | Pre-prod testing, integ tests | Yes | CI/CD on merge to main |
| `prod` | Production | Yes | CI/CD after staging tests pass |

## Environment-Based Features

Features are automatically configured based on the `ENVIRONMENT` variable:

| Feature | dev | staging | prod |
|---------|-----|---------|------|
| Scheduled Trigger (6am UTC) | ❌ | ❌ | ✅ |
| Manual Trigger | ✅ | ✅ | ❌ |
| Online Evaluations | ❌ | ❌ | ✅ |

Override defaults with environment variables:
- `ENABLE_EVALS=true` - Enable Online Evaluations in any environment
- `ENABLE_SCHEDULED_TRIGGER=true` - Enable scheduled trigger in any environment

## Prerequisites (One-time setup per AWS account)

1. Bootstrap CDK in each account: `cdk bootstrap`
2. Deploy OIDC stack for CI/CD environments:
- `ENVIRONMENT=staging npm run deploy:oidc --prefix infra` (staging account)
- `ENVIRONMENT=prod npm run deploy:oidc --prefix infra` (prod account)
3. Create GitHub environments (`staging`, `prod`) with `AWS_ROLE_ARN` secret from each OIDC stack output
4. Configure environment protection rules (limit deployments to `main` branch only)
5. Configure branch protection rules on `main` (require PR reviews, status checks)

## Pipeline Flow

### 1. PR Created/Updated

Runs test jobs (no AWS credentials needed):
- `test-python` - Python unit tests with coverage
- `test-typescript` - TypeScript/CDK unit tests
- `test-cdk-nag` - CDK security checks via cdk-nag

### 2. PR Merged to Main

Deployments only trigger when relevant files change:
- `src/**`, `infra/**`, `tests/**`, `evals/**`, `scripts/**`
- `pyproject.toml`, `uv.lock`
- `.github/workflows/ci.yml`

Pipeline sequence:
1. Unit tests run again (`test-python`, `test-typescript`, `test-cdk-nag`)
2. `deploy-staging` → deploys with `ENVIRONMENT=staging`
3. `deploy-prod` → deploys with `ENVIRONMENT=prod`

Changes to docs, reports, or other non-deployment files skip the deployment jobs.

## GitHub Environments

Two environments (`staging`, `prod`) provide isolation with separate secrets, protection rules, and deployment history per environment.

## Rollback Strategy

- **Option 1:** Create a revert PR (`git revert <bad-commit>`) → merge to main → triggers full pipeline
- **Option 2:** Re-run previous successful workflow from GitHub Actions UI (runs retained for 90 days by default)

## Security

- **No long-lived credentials:** OIDC authentication eliminates stored AWS access keys
- **Environment isolation:** Each AWS account has its own OIDC role scoped to its GitHub environment
- **Least privilege:** GitHub Actions role can only assume CDK bootstrap roles, not direct resource access
- **Supply chain protection:** All GitHub Actions are pinned to SHA hashes
- **Branch protection:** Deployments only trigger on push to `main` (requires PR merge)
- **Concurrency control:** Prevents parallel deployments to the same environment

### Fork PR Protection

Fork PRs require manual approval before workflows run. This is controlled by a repo-level setting, not the workflow file itself.

**Required setting:** Settings → Actions → General → "Require approval for all external contributors"

This ensures:
- Every push from a fork requires maintainer approval
- Every new PR from a fork requires approval
- Malicious workflow modifications in forks cannot execute without review
- Maintainers can inspect the diff (including `.github/workflows/`) before approving
47 changes: 47 additions & 0 deletions infra/bin/github-oidc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { AwsSolutionsChecks } from 'cdk-nag';

import { GitHubOidcStack } from '../lib/github-oidc-stack';

/**
* GitHub OIDC Setup for GitHub Actions deployments.
*
* This is a one-time setup (similar to CDK bootstrap) that creates:
* 1. GitHub OIDC Identity Provider in AWS
* 2. IAM Role that GitHub Actions can assume
*
* Usage:
* ENVIRONMENT=staging npm run deploy:oidc --prefix infra
* ENVIRONMENT=prod npm run deploy:oidc --prefix infra
*
*
* After deployment:
* 1. Copy the RoleArn from the stack outputs
* 2. Add it as a GitHub secret named AWS_ROLE_ARN in the corresponding GitHub environment
*/

const VALID_ENVIRONMENTS = ['staging', 'prod'];
const environment = process.env.ENVIRONMENT;

if (!environment || !VALID_ENVIRONMENTS.includes(environment)) {
console.error('\nENVIRONMENT must be "staging" or "prod".\n');
console.error('Usage: ENVIRONMENT=staging npm run deploy:oidc --prefix infra');
console.error(' ENVIRONMENT=prod npm run deploy:oidc --prefix infra\n');
process.exit(1);
}

const app = new cdk.App();

new GitHubOidcStack(app, `GitHubOidcStack-${environment}`, {
description: `GitHub OIDC provider and IAM role for GitHub Actions deployments (${environment})`,
githubOrg: 'aws-samples',
githubRepo: 'sample-agentic-cost-optimizer',
environment,
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});

cdk.Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));
Loading
Loading