Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
256 changes: 256 additions & 0 deletions .github/workflows/pr-codebuild-trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
name: PR CodeBuild Trigger (Privileged)

on:
workflow_run:
workflows: ["PR Team Check (Untrusted)"]
types:
- completed

permissions:
contents: read
pull-requests: write
issues: write

jobs:
trigger-codebuild:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
steps:
- name: Download PR information artifact
uses: actions/github-script@v7
with:
script: |
var artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
var matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "pr-info";
})[0];
var download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
var fs = require('fs');
fs.writeFileSync('${{ github.workspace }}/pr-info.zip', Buffer.from(download.data));

- name: Extract and validate PR information
id: extract-pr-info
run: |
mkdir -p tmp
unzip -d tmp/ pr-info.zip

# Read and validate PR information
PR_NUMBER=$(cat ./tmp/pr_number)
PR_AUTHOR=$(cat ./tmp/pr_author)
COMMIT_AUTHORS=$(cat ./tmp/commit_authors)
COMMIT_USERNAMES=$(cat ./tmp/commit_usernames)
WORKFLOW_MODIFIED=$(cat ./tmp/workflow_modified)
WORKFLOW_CHANGES=$(cat ./tmp/workflow_changes)
HEAD_SHA=$(cat ./tmp/head_sha)
BASE_SHA=$(cat ./tmp/base_sha)
REPOSITORY=$(cat ./tmp/repository)

# Validate that PR_NUMBER is numeric
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
echo "::error::Invalid PR number: $PR_NUMBER"
exit 1
fi

# Validate SHA format (40 character hex)
if ! [[ "$HEAD_SHA" =~ ^[a-f0-9]{40}$ ]]; then
echo "::error::Invalid HEAD SHA format: $HEAD_SHA"
exit 1
fi

if ! [[ "$BASE_SHA" =~ ^[a-f0-9]{40}$ ]]; then
echo "::error::Invalid BASE SHA format: $BASE_SHA"
exit 1
fi

# Validate repository format
if ! [[ "$REPOSITORY" =~ ^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$ ]]; then
echo "::error::Invalid repository format: $REPOSITORY"
exit 1
fi

# Set outputs
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "pr_author=$PR_AUTHOR" >> $GITHUB_OUTPUT
echo "commit_authors=$COMMIT_AUTHORS" >> $GITHUB_OUTPUT
echo "commit_usernames=$COMMIT_USERNAMES" >> $GITHUB_OUTPUT
echo "workflow_modified=$WORKFLOW_MODIFIED" >> $GITHUB_OUTPUT
echo "workflow_changes=$WORKFLOW_CHANGES" >> $GITHUB_OUTPUT
echo "head_sha=$HEAD_SHA" >> $GITHUB_OUTPUT
echo "base_sha=$BASE_SHA" >> $GITHUB_OUTPUT
echo "repository=$REPOSITORY" >> $GITHUB_OUTPUT

echo "✅ PR information validated successfully"
echo "PR Number: $PR_NUMBER"
echo "PR Author: $PR_AUTHOR"
echo "Workflow Modified: $WORKFLOW_MODIFIED"

- name: Security validation
id: security-check
run: |
if [[ "${{ steps.extract-pr-info.outputs.workflow_modified }}" == "true" ]]; then
Comment thread Fixed
echo "🚨 SECURITY BLOCK: This PR modifies workflow files"
echo "Modified files: ${{ steps.extract-pr-info.outputs.workflow_changes }}"
Comment thread Fixed

# Post security block comment on PR
curl -X POST \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ steps.extract-pr-info.outputs.repository }}/issues/${{ steps.extract-pr-info.outputs.pr_number }}/comments \
-d "{\"body\":\"🚨 **SECURITY BLOCK**\\n\\n**CodeBuild execution has been BLOCKED** because this PR modifies GitHub Actions workflow files:\\n\`\`\`\\n${{ steps.extract-pr-info.outputs.workflow_changes }}\\n\`\`\`\\n\\n**Security Policy:** PRs that modify workflows cannot trigger automated builds to prevent security bypass attacks.\\n\\n**Required Actions:**\\n1. Get approval from code owners (@awslabs/sagemaker-1p-algorithms)\\n2. Manual review of all workflow changes\\n3. Separate the workflow changes into a different PR if needed\\n\\n**This is an automated security measure to protect AWS resources.**\"}"
Comment thread Fixed

echo "security_blocked=true" >> $GITHUB_OUTPUT
else
echo "✅ Security validation passed"
echo "security_blocked=false" >> $GITHUB_OUTPUT
fi

- name: Check team membership for PR author
id: check-pr-author
if: steps.security-check.outputs.security_blocked == 'false'
run: |
TEAM_MEMBER_FOUND=false

# Check PR author team membership
echo "Checking team membership for PR author: ${{ steps.extract-pr-info.outputs.pr_author }}"
Comment thread Fixed

# Check if PR author is in the team
response=$(curl -s -w "%{http_code}" -o /tmp/team_check \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/orgs/awslabs/teams/sagemaker-1p-algorithms/members/${{ steps.extract-pr-info.outputs.pr_author }}")
Comment thread Fixed

if [[ "$response" == "204" ]]; then
echo "✅ PR author ${{ steps.extract-pr-info.outputs.pr_author }} is a member of sagemaker-1p-algorithms team"
Comment thread Fixed
TEAM_MEMBER_FOUND=true
elif [[ "$response" == "404" ]]; then
echo "❌ PR author ${{ steps.extract-pr-info.outputs.pr_author }} is not a member of sagemaker-1p-algorithms team"
Comment thread Fixed
else
echo "⚠️ Unable to verify team membership for PR author (HTTP $response)"
cat /tmp/team_check
fi

echo "pr_author_is_member=$TEAM_MEMBER_FOUND" >> $GITHUB_OUTPUT

- name: Check team membership for commit authors
id: check-commit-authors
if: steps.security-check.outputs.security_blocked == 'false'
run: |
TEAM_MEMBER_FOUND=false

# Check commit authors if we have usernames
if [[ -n "${{ steps.extract-pr-info.outputs.commit_usernames }}" ]]; then
Comment thread Fixed
IFS=',' read -ra USERNAMES <<< "${{ steps.extract-pr-info.outputs.commit_usernames }}"
Comment thread Fixed
for username in "${USERNAMES[@]}"; do
if [[ -n "$username" ]]; then
echo "Checking team membership for commit author: $username"

response=$(curl -s -w "%{http_code}" -o /tmp/team_check_commit \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/orgs/awslabs/teams/sagemaker-1p-algorithms/members/$username")

if [[ "$response" == "204" ]]; then
echo "✅ Commit author $username is a member of sagemaker-1p-algorithms team"
TEAM_MEMBER_FOUND=true
break
elif [[ "$response" == "404" ]]; then
echo "❌ Commit author $username is not a member of sagemaker-1p-algorithms team"
else
echo "⚠️ Unable to verify team membership for commit author $username (HTTP $response)"
fi
fi
done
else
echo "No GitHub usernames found in commit authors"
fi

echo "commit_author_is_member=$TEAM_MEMBER_FOUND" >> $GITHUB_OUTPUT

- name: Configure AWS Credentials
if: |
steps.security-check.outputs.security_blocked == 'false' &&
(steps.check-pr-author.outputs.pr_author_is_member == 'true' || steps.check-commit-authors.outputs.commit_author_is_member == 'true')
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2

- name: Trigger CodeBuild Projects
if: |
steps.security-check.outputs.security_blocked == 'false' &&
(steps.check-pr-author.outputs.pr_author_is_member == 'true' || steps.check-commit-authors.outputs.commit_author_is_member == 'true')
run: |
echo "🚀 Team member found! Triggering CodeBuild projects..."

# Trigger tgi-pr-GPU CodeBuild project
echo "Starting tgi-pr-GPU build..."
TGI_BUILD_ID=$(aws codebuild start-build \
--project-name tgi-pr-GPU \
--source-version ${{ steps.extract-pr-info.outputs.head_sha }} \
--environment-variables-override \
name=GITHUB_PR_NUMBER,value=${{ steps.extract-pr-info.outputs.pr_number }} \
name=GITHUB_PR_HEAD_SHA,value=${{ steps.extract-pr-info.outputs.head_sha }} \
name=GITHUB_PR_BASE_SHA,value=${{ steps.extract-pr-info.outputs.base_sha }} \
name=GITHUB_REPOSITORY,value=${{ steps.extract-pr-info.outputs.repository }} \
--query 'build.id' --output text)

echo "TGI CodeBuild started with ID: $TGI_BUILD_ID"

# Trigger tei-pr-CPU CodeBuild project
echo "Starting tei-pr-CPU build..."
TEI_BUILD_ID=$(aws codebuild start-build \
--project-name tei-pr-CPU \
--source-version ${{ steps.extract-pr-info.outputs.head_sha }} \
--environment-variables-override \
name=GITHUB_PR_NUMBER,value=${{ steps.extract-pr-info.outputs.pr_number }} \
name=GITHUB_PR_HEAD_SHA,value=${{ steps.extract-pr-info.outputs.head_sha }} \
name=GITHUB_PR_BASE_SHA,value=${{ steps.extract-pr-info.outputs.base_sha }} \
name=GITHUB_REPOSITORY,value=${{ steps.extract-pr-info.outputs.repository }} \
--query 'build.id' --output text)

echo "TEI CodeBuild started with ID: $TEI_BUILD_ID"

# Create a comment on the PR with build information
curl -X POST \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ steps.extract-pr-info.outputs.repository }}/issues/${{ steps.extract-pr-info.outputs.pr_number }}/comments \
-d "{\"body\":\"🚀 **CodeBuild Triggered**\\n\\n✅ Team member verification passed\\n\\n**Build IDs:**\\n- TGI GPU Build: \`$TGI_BUILD_ID\`\\n- TEI CPU Build: \`$TEI_BUILD_ID\`\\n\\nYou can monitor the builds in the [AWS CodeBuild Console](https://us-west-2.console.aws.amazon.com/codesuite/codebuild/projects).\"}"

- name: Team membership check failed
if: |
steps.security-check.outputs.security_blocked == 'false' &&
steps.check-pr-author.outputs.pr_author_is_member == 'false' &&
steps.check-commit-authors.outputs.commit_author_is_member == 'false'
run: |
echo "❌ Access denied: Neither PR author nor commit authors are members of the sagemaker-1p-algorithms team"

# Create a comment on the PR about the failed check
curl -X POST \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/${{ steps.extract-pr-info.outputs.repository }}/issues/${{ steps.extract-pr-info.outputs.pr_number }}/comments \
-d "{\"body\":\"❌ **CodeBuild Access Denied**\\n\\nThe PR author and commit authors are not members of the \`sagemaker-1p-algorithms\` team.\\n\\n**Checked:**\\n- PR Author: @${{ steps.extract-pr-info.outputs.pr_author }}\\n- Commit Authors: ${{ steps.extract-pr-info.outputs.commit_authors }}\\n\\nPlease ensure you are a member of the required team to trigger builds.\"}"
Comment thread Fixed
Comment thread Fixed

exit 1

- name: Security block failure
if: steps.security-check.outputs.security_blocked == 'true'
run: |
echo "🚨 SECURITY BLOCK: Workflow execution terminated due to workflow file modifications"
echo "::error::SECURITY POLICY VIOLATION: This PR modifies GitHub Actions workflows and has been blocked from executing CodeBuild projects."
echo "::error::This is a security measure to prevent malicious workflow modifications from bypassing team membership checks."
echo "::error::Please get approval from code owners (@awslabs/sagemaker-1p-algorithms) and consider separating workflow changes into a different PR."
exit 1
85 changes: 85 additions & 0 deletions .github/workflows/pr-team-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: PR Team Check (Untrusted)

on:
pull_request:
types: [opened, synchronize, reopened]

permissions:
contents: read

jobs:
check-team-membership:
runs-on: ubuntu-latest
steps:
- name: Checkout PR code (untrusted)
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0

- name: Get PR and commit authors
id: get-authors
run: |
# Get PR author
PR_AUTHOR="${{ github.event.pull_request.user.login }}"
echo "pr_author=$PR_AUTHOR" >> $GITHUB_OUTPUT
echo "PR Author: $PR_AUTHOR"

# Get all commit authors in this PR
git fetch origin ${{ github.event.pull_request.base.ref }}
COMMIT_AUTHORS=$(git log origin/${{ github.event.pull_request.base.ref }}..${{ github.event.pull_request.head.sha }} --format="%an" | sort -u | tr '\n' ',' | sed 's/,$//')
echo "commit_authors=$COMMIT_AUTHORS" >> $GITHUB_OUTPUT
echo "Commit Authors: $COMMIT_AUTHORS"

# Get all commit author usernames (GitHub usernames)
COMMIT_USERNAMES=""
for sha in $(git log origin/${{ github.event.pull_request.base.ref }}..${{ github.event.pull_request.head.sha }} --format="%H"); do
author_email=$(git show --format="%ae" --no-patch $sha)
# Try to get GitHub username from commit
if [[ "$author_email" == *"@users.noreply.github.com" ]]; then
username=$(echo "$author_email" | cut -d'@' -f1 | sed 's/^[0-9]*+//')
COMMIT_USERNAMES="$COMMIT_USERNAMES,$username"
fi
done
COMMIT_USERNAMES=$(echo "$COMMIT_USERNAMES" | sed 's/^,//' | sed 's/,$//')
echo "commit_usernames=$COMMIT_USERNAMES" >> $GITHUB_OUTPUT
echo "Commit Usernames: $COMMIT_USERNAMES"

- name: Check for workflow modifications
id: check-workflow-changes
run: |
echo "🔒 Security Check: Validating PR does not modify workflow files"

# Check if PR modifies any workflow files
WORKFLOW_CHANGES=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }}...${{ github.event.pull_request.head.sha }} | grep -E '^\.github/workflows/' || true)

if [[ -n "$WORKFLOW_CHANGES" ]]; then
echo "🚨 SECURITY ALERT: This PR modifies workflow files:"
echo "$WORKFLOW_CHANGES"
echo "workflow_modified=true" >> $GITHUB_OUTPUT
echo "workflow_changes=$WORKFLOW_CHANGES" >> $GITHUB_OUTPUT
else
echo "✅ No workflow files modified in this PR"
echo "workflow_modified=false" >> $GITHUB_OUTPUT
echo "workflow_changes=" >> $GITHUB_OUTPUT
fi

- name: Save PR information for privileged workflow
run: |
mkdir -p ./pr-info
echo "${{ github.event.pull_request.number }}" > ./pr-info/pr_number
echo "${{ steps.get-authors.outputs.pr_author }}" > ./pr-info/pr_author
echo "${{ steps.get-authors.outputs.commit_authors }}" > ./pr-info/commit_authors
echo "${{ steps.get-authors.outputs.commit_usernames }}" > ./pr-info/commit_usernames
echo "${{ steps.check-workflow-changes.outputs.workflow_modified }}" > ./pr-info/workflow_modified
echo "${{ steps.check-workflow-changes.outputs.workflow_changes }}" > ./pr-info/workflow_changes
echo "${{ github.event.pull_request.head.sha }}" > ./pr-info/head_sha
echo "${{ github.event.pull_request.base.sha }}" > ./pr-info/base_sha
echo "${{ github.repository }}" > ./pr-info/repository

- name: Upload PR information artifact
uses: actions/upload-artifact@v4
with:
name: pr-info
path: pr-info/
retention-days: 1
22 changes: 21 additions & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
* @awslabs/sagemaker-1p-algorithms
# Code Owners for llm-hosting-container repository

# Global fallback - require review from sagemaker-1p-algorithms team
* @awslabs/sagemaker-1p-algorithms

# GitHub Actions workflows - CRITICAL SECURITY
# These files control CI/CD and AWS resource access
# Require mandatory review from the sagemaker-1p-algorithms team
.github/workflows/ @awslabs/sagemaker-1p-algorithms
.github/actions/ @awslabs/sagemaker-1p-algorithms

# Security-sensitive configuration files
CODEOWNERS @awslabs/sagemaker-1p-algorithms
.gitignore @awslabs/sagemaker-1p-algorithms

# Documentation that affects security setup
docs/github-webhook-setup.md @awslabs/sagemaker-1p-algorithms
docs/webhook-security-analysis.md @awslabs/sagemaker-1p-algorithms

# AWS CodeBuild specifications
**/buildspec.yml @awslabs/sagemaker-1p-algorithms
Loading
Loading