Skip to content

fix: out-of-scope variable in catch block #1109

fix: out-of-scope variable in catch block

fix: out-of-scope variable in catch block #1109

name: Secure Integration test
on:
push:
branches: [ main ]
tags:
- 'v*'
pull_request_target:
branches: [ main ]
types: [opened, synchronize, reopened]
# Global permissions - most restrictive by default
permissions:
contents: read
jobs:
authorization-check:
permissions: read-all
runs-on: ubuntu-latest
# Skip entirely for Dependabot PRs — they are not collaborators so they
# would always route to manual-approval, blocking auto-merge indefinitely.
# Dependabot PRs are validated by ci.yml (lint, test, build) which are
# the required status checks in the main-status-checks Ruleset.
if: github.actor != 'dependabot[bot]'
outputs:
approval-env: ${{ steps.collab-check.outputs.result }}
should-run: ${{ steps.safety-check.outputs.result }}
steps:
- name: Checkout base branch for safety check
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.sha }}
- name: Safety Check - Prevent Workflow Modification Attacks
id: safety-check
uses: actions/github-script@v8
with:
result-encoding: string
script: |
if (!context.payload.pull_request) {
console.log('Not a pull request, proceeding');
return 'true';
}
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
const dangerousPatterns = [
/^\.github\/workflows\//,
/^\.github\/actions\//,
/conftest\.py$/,
/pytest\.ini$/,
];
const dangerousFiles = files.filter(file =>
dangerousPatterns.some(pattern => pattern.test(file.filename))
);
if (dangerousFiles.length > 0) {
console.log('⚠️ SECURITY: PR modifies sensitive files:');
dangerousFiles.forEach(f => console.log(` - ${f.filename}`));
console.log('Manual review required before running integration tests');
return 'false';
}
console.log('✓ Safety check passed - no sensitive files modified');
return 'true';
- name: Collaborator Check
uses: actions/github-script@v8
id: collab-check
with:
result-encoding: string
script: |
let username;
try {
if (context.payload.pull_request) {
username = context.payload.pull_request.user.login;
} else {
username = context.actor;
console.log(`No pull request context found, checking permissions for actor: ${username}`);
}
const permissionResponse = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: username,
});
const permission = permissionResponse.data.permission;
const hasWriteAccess = ['write', 'admin'].includes(permission);
if (!hasWriteAccess) {
console.log(`User ${username} does not have write access to the repository (permission: ${permission})`);
return "manual-approval"
} else {
console.log(`Verified ${username} has write access. Auto Approving PR Checks.`)
return "auto-approve"
}
} catch (error) {
console.log(`${username} does not have write access. Requiring Manual Approval to run PR Checks.`)
return "manual-approval"
}
check-access-and-checkout:
name: Test (${{ matrix.group }})
runs-on: ubuntu-latest
needs: authorization-check
if: needs.authorization-check.outputs.should-run == 'true'
environment: ${{ needs.authorization-check.outputs.approval-env }}
permissions:
id-token: write # Required for AWS OIDC
pull-requests: read # Required to read PR info
contents: read # Required to checkout code
strategy:
fail-fast: false
matrix:
include:
- group: runtime
path: tests_integ/runtime
timeout: 10
extra-deps: ""
ignore: ""
# TODO: expand to full tests_integ/memory once test stability is addressed
- group: memory
path: tests_integ/memory/test_controlplane.py tests_integ/memory/test_memory_client.py tests_integ/memory/integrations/test_session_manager.py
timeout: 15
extra-deps: ""
ignore: ""
- group: evaluation
path: tests_integ/evaluation
timeout: 15
extra-deps: "strands-agents-evals"
ignore: ""
- group: services
path: tests_integ/services
timeout: 5
extra-deps: ""
ignore: ""
- group: policy
path: tests_integ/policy
timeout: 15
extra-deps: ""
ignore: ""
- group: gateway
path: tests_integ/gateway
timeout: 15
extra-deps: ""
ignore: ""
- group: identity
path: tests_integ/identity/test_identity_client.py
timeout: 15
extra-deps: ""
ignore: ""
- group: payments
path: tests_integ/payments
timeout: 15
extra-deps: "strands-agents strands-agents-tools"
ignore: ""
# TODO: expand to full tools tests once test resources are setup
- group: tools
path: tests_integ/tools
timeout: 15
extra-deps: ""
ignore: "--ignore=tests_integ/tools/test_browser_proxy.py"
steps:
- name: Configure Credentials
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.AGENTCORE_INTEG_TEST_ROLE }}
aws-region: us-west-2
mask-aws-account-id: true
- name: Checkout PR head commit
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install -e .
pip install --no-cache-dir pytest pytest-xdist pytest-order pytest-rerunfailures requests strands-agents uvicorn httpx starlette websockets ${{ matrix.extra-deps }}
- name: Run integration tests
env:
AWS_REGION: us-west-2
PYTHONUNBUFFERED: 1
MEMORY_KINESIS_ARN: ${{ secrets.MEMORY_KINESIS_ARN }}
MEMORY_ROLE_ARN: ${{ secrets.MEMORY_ROLE_ARN }}
MEMORY_PREPOPULATED_ID: ${{ secrets.MEMORY_PREPOPULATED_ID }}
RESOURCE_POLICY_TEST_ARN: ${{ secrets.RESOURCE_POLICY_TEST_ARN }}
RESOURCE_POLICY_TEST_PRINCIPAL: ${{ secrets.RESOURCE_POLICY_TEST_PRINCIPAL }}
GATEWAY_ROLE_ARN: ${{ secrets.GATEWAY_ROLE_ARN }}
GATEWAY_LAMBDA_ARN: ${{ secrets.GATEWAY_LAMBDA_ARN }}
EVAL_ROLE_ARN: ${{ secrets.EVAL_ROLE_ARN }}
EVAL_LOG_GROUP: ${{ secrets.EVAL_LOG_GROUP }}
RUNTIME_ROLE_ARN: ${{ secrets.RUNTIME_ROLE_ARN }}
RUNTIME_S3_CODE_URI: ${{ secrets.RUNTIME_S3_CODE_URI }}
COGNITO_POOL_ID: ${{ secrets.COGNITO_POOL_ID }}
COGNITO_CLIENT_ID: ${{ secrets.COGNITO_CLIENT_ID }}
COGNITO_CLIENT_SECRET: ${{ secrets.COGNITO_CLIENT_SECRET }}
id: tests
timeout-minutes: ${{ matrix.timeout }}
run: |
pytest ${{ matrix.path }} ${{ matrix.ignore }} -n auto --dist=loadscope -s --log-cli-level=INFO
safety-gate:
runs-on: ubuntu-latest
needs: authorization-check
if: needs.authorization-check.outputs.should-run == 'false'
permissions: {}
steps:
- name: Security Block
run: |
echo "🚨 SECURITY BLOCK: This PR modifies sensitive files"
echo ""
echo "The following types of files trigger manual review:"
echo " - Workflow files (.github/workflows/)"
echo " - Action files (.github/actions/)"
echo " - Test setup files (conftest.py, pytest.ini)"
echo ""
echo "⚠️ Integration tests will NOT run automatically"
echo "👀 A maintainer must review the changes and manually trigger tests"
echo ""
echo "This is a security measure to prevent:"
echo " - Workflow modification attacks"
echo " - Secret exfiltration"
echo " - Test manipulation"
exit 1