Skip to content

Commit 6e466c5

Browse files
authored
Merge pull request #68 from Contrast-Security-OSS/AIML-195
AIML-195: Add support for AWS_BEARER_TOKEN_BEDROCK authentication
2 parents c23fc5b + c61ce3b commit 6e466c5

File tree

4 files changed

+171
-3
lines changed

4 files changed

+171
-3
lines changed

action.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ inputs:
5353
anthropic_api_key:
5454
description: 'Anthropic API key'
5555
required: false
56+
aws_bearer_token_bedrock:
57+
description: 'AWS Bedrock API Bearer Token (alternative to AWS IAM credentials)'
58+
required: false
59+
aws_region:
60+
description: 'AWS Region for Bedrock (required when using aws_bearer_token_bedrock)'
61+
required: false
5662
azure_api_key:
5763
description: 'Azure API Key for Azure OpenAI'
5864
required: false
@@ -364,6 +370,9 @@ runs:
364370
GEMINI_API_KEY: ${{ inputs.gemini_api_key }}
365371
# --- Anthropic Credentials (LiteLLM) ---
366372
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
373+
# --- AWS Bedrock API Bearer Token (LiteLLM) ---
374+
AWS_BEARER_TOKEN_BEDROCK: ${{ inputs.aws_bearer_token_bedrock }}
375+
AWS_REGION_NAME: ${{ inputs.aws_region }}
367376
# --- Azure Credentials for Azure OpenAI (LiteLLM) ---
368377
AZURE_API_KEY: ${{ inputs.azure_api_key }}
369378
AZURE_API_BASE: ${{ inputs.azure_api_base }}

docs/contrast-ai-smartfix.yml.template

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
runs-on: ubuntu-latest
3838
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
3939
steps:
40+
# Option A: Configure AWS Credentials using IAM (Recommended for production)
4041
- name: Configure AWS Credentials
4142
uses: aws-actions/configure-aws-credentials@v1
4243
with:
@@ -45,6 +46,10 @@ jobs:
4546
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
4647
aws-region: ${{ vars.AWS_REGION }}
4748

49+
# Option B: Use Bedrock API Keys (Simpler but less secure)
50+
# If using API keys, omit the "Configure AWS Credentials" step above
51+
# and uncomment the aws_bearer_token_bedrock and aws_region lines below in the action inputs
52+
4853
- name: Checkout repository
4954
uses: actions/checkout@v4
5055
with:
@@ -75,6 +80,9 @@ jobs:
7580
gemini_api_key: ${{ secrets.GEMINI_API_KEY }}
7681
# --- Anthropic API Credentials ---
7782
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
83+
# --- AWS Bedrock API Key (Alternative to IAM credentials, less secure) ---
84+
# aws_bearer_token_bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
85+
# aws_region: ${{ vars.AWS_REGION }}
7886
# --- Azure Open API Credentials ---
7987
# azure_api_key: ${{ secrets.AZURE_API_KEY }}
8088
# azure_api_base: ${{ secrets.AZURE_API_BASE }}

docs/smartfix_coding_agent.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ jobs:
6060
runs-on: ubuntu-latest
6161
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
6262
steps:
63-
# For Claude via AWS Bedrock, please include an additional setup step for configuring AWS credentials
64-
# This step can be omitted if using another LLM provider.
63+
# For Claude via AWS Bedrock with IAM credentials (Option A - Recommended)
64+
# This step can be omitted if using another LLM provider or using Bedrock API keys (Option B).
6565
- name: Configure AWS Credentials
6666
uses: aws-actions/configure-aws-credentials@v4
6767
with:
@@ -70,6 +70,12 @@ jobs:
7070
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
7171
aws-region: ${{ vars.AWS_REGION }}
7272
73+
# Alternative: For Claude via AWS Bedrock with API keys (Option B - Simpler but less secure)
74+
# If using this method, omit the "Configure AWS Credentials" step above and uncomment the lines below
75+
# in the "Run Contrast AI SmartFix - Generate Fixes Action" step:
76+
# aws_bearer_token_bedrock: ${{ secrets.AWS_BEARER_TOKEN_BEDROCK }}
77+
# aws_region: ${{ vars.AWS_REGION }}
78+
7379
- name: Checkout repository
7480
uses: actions/checkout@v4
7581
with:
@@ -180,7 +186,9 @@ The SmartFix Coding Agent uses a "Bring Your Own LLM" (BYOLLM) model. You provid
180186
* Provide your `anthropic_api_key`.
181187
* Option 2 - AWS Bedrock:
182188
* Set `agent_model` to the appropriate model string (e.g., `bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0`).
183-
* In order for the action to an AWS Bedrock LLM, you need to provide AWS credentials. We recommend using [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) to configure your credentials for a job.
189+
* In order for the action to use an AWS Bedrock LLM, you need to provide AWS credentials using one of two methods:
190+
* **Option A - IAM Credentials (Recommended):** Use [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) to configure your credentials with AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, and AWS_REGION. This is the recommended approach for production use.
191+
* **Option B - Bedrock API Keys:** Provide your `aws_bearer_token_bedrock` and `aws_region` directly to the action. This is a simpler setup but is less secure than IAM credentials. Use with caution and review AWS security best practices. See [AWS Bedrock API Keys](https://aws.amazon.com/blogs/machine-learning/accelerate-ai-development-with-amazon-bedrock-api-keys/) for more information.
184192

185193
* **Experimental:** **Google Gemini Pro (e.g., Gemini 2.5 Pro)**. Preliminary testing shows good results.
186194
* Set `agent_model` to the appropriate model string (e.g., `gemini/gemini-2.5-pro-preview-05-06`).
@@ -262,6 +270,8 @@ The following are key inputs for the SmartFix GitHub Action using SmartFix Codin
262270
| `contrast_api_key` | Contrast API Key. | Yes | |
263271
| `agent_model` | LLM model to use (e.g., `bedrock/anthropic.claude-3-sonnet-20240229-v1:0`). | No | `bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0` |
264272
| `anthropic_api_key` | Anthropic API key (if using direct Anthropic API). | No | |
273+
| `aws_bearer_token_bedrock` | AWS Bedrock API Bearer Token (alternative to IAM credentials). Use with caution - less secure than IAM. | No | |
274+
| `aws_region` | AWS Region for Bedrock (required when using `aws_bearer_token_bedrock`). | No | |
265275
| `gemini_api_key` | Gemini API key (if using Gemini). | No | |
266276
| `build_command` | Command to build the application (for QA). | Yes, for generating fixes | |
267277
| `formatting_command` | Command to format code. | No | |
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env python
2+
# -
3+
# #%L
4+
# Contrast AI SmartFix
5+
# %%
6+
# Copyright (C) 2025 Contrast Security, Inc.
7+
# %%
8+
9+
# License: Commercial
10+
# NOTICE: This Software and the patented inventions embodied within may only be
11+
# used as part of Contrast Security's commercial offerings. Even though it is
12+
# made available through public repositories, use of this Software is subject to
13+
# the applicable End User Licensing Agreement found at
14+
# https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
15+
# between Contrast Security and the End User. The Software may not be reverse
16+
# engineered, modified, repackaged, sold, redistributed or otherwise used in a
17+
# way not consistent with the End User License Agreement.
18+
# #L%
19+
#
20+
21+
"""
22+
Unit tests for AWS_BEARER_TOKEN_BEDROCK environment variable support.
23+
24+
This module tests that the AWS_BEARER_TOKEN_BEDROCK environment variable
25+
is properly handled and available for LiteLLM to use for Bedrock authentication.
26+
"""
27+
28+
import sys
29+
import unittest
30+
import os
31+
32+
# Add project root to path for imports
33+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
34+
35+
# Import config module (need to initialize before other imports)
36+
from src.config import get_config # noqa: E402
37+
38+
# Initialize config with testing flag
39+
_ = get_config(testing=True)
40+
41+
42+
class TestAwsBearerTokenBedrock(unittest.TestCase):
43+
"""Test cases for AWS_BEARER_TOKEN_BEDROCK environment variable support."""
44+
45+
def test_environment_variable_can_be_set(self):
46+
"""Test that AWS_BEARER_TOKEN_BEDROCK environment variable can be set and retrieved."""
47+
test_token = "test-bearer-token-12345"
48+
49+
# Set the environment variable
50+
os.environ['AWS_BEARER_TOKEN_BEDROCK'] = test_token
51+
52+
# Verify it can be retrieved
53+
self.assertEqual(os.environ.get('AWS_BEARER_TOKEN_BEDROCK'), test_token)
54+
55+
# Clean up
56+
del os.environ['AWS_BEARER_TOKEN_BEDROCK']
57+
58+
def test_environment_variable_not_set_returns_none(self):
59+
"""Test that missing AWS_BEARER_TOKEN_BEDROCK returns None."""
60+
# Ensure the variable is not set
61+
if 'AWS_BEARER_TOKEN_BEDROCK' in os.environ:
62+
del os.environ['AWS_BEARER_TOKEN_BEDROCK']
63+
64+
# Verify it returns None when not set
65+
self.assertIsNone(os.environ.get('AWS_BEARER_TOKEN_BEDROCK'))
66+
67+
def test_bearer_token_precedence_over_iam(self):
68+
"""Test that AWS_BEARER_TOKEN_BEDROCK can coexist with IAM credentials."""
69+
# Set both bearer token and IAM credentials
70+
os.environ['AWS_BEARER_TOKEN_BEDROCK'] = "test-bearer-token"
71+
os.environ['AWS_ACCESS_KEY_ID'] = "test-access-key"
72+
os.environ['AWS_SECRET_ACCESS_KEY'] = "test-secret-key"
73+
74+
try:
75+
# Verify both are set (LiteLLM will determine which to use based on its own logic)
76+
self.assertIsNotNone(os.environ.get('AWS_BEARER_TOKEN_BEDROCK'))
77+
self.assertIsNotNone(os.environ.get('AWS_ACCESS_KEY_ID'))
78+
self.assertIsNotNone(os.environ.get('AWS_SECRET_ACCESS_KEY'))
79+
80+
finally:
81+
# Clean up
82+
for key in ['AWS_BEARER_TOKEN_BEDROCK', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY']:
83+
if key in os.environ:
84+
del os.environ[key]
85+
86+
def test_empty_bearer_token_is_ignored(self):
87+
"""Test that an empty AWS_BEARER_TOKEN_BEDROCK value is handled gracefully."""
88+
# Set an empty bearer token
89+
os.environ['AWS_BEARER_TOKEN_BEDROCK'] = ""
90+
91+
try:
92+
# Verify it's set but empty
93+
self.assertEqual(os.environ.get('AWS_BEARER_TOKEN_BEDROCK'), "")
94+
95+
# An empty token should be falsy
96+
self.assertFalse(os.environ.get('AWS_BEARER_TOKEN_BEDROCK'))
97+
98+
finally:
99+
# Clean up
100+
if 'AWS_BEARER_TOKEN_BEDROCK' in os.environ:
101+
del os.environ['AWS_BEARER_TOKEN_BEDROCK']
102+
103+
def test_aws_region_name_can_be_set(self):
104+
"""Test that AWS_REGION_NAME environment variable can be set and retrieved."""
105+
test_region = "us-east-1"
106+
107+
# Set the environment variable
108+
os.environ['AWS_REGION_NAME'] = test_region
109+
110+
try:
111+
# Verify it can be retrieved
112+
self.assertEqual(os.environ.get('AWS_REGION_NAME'), test_region)
113+
114+
finally:
115+
# Clean up
116+
if 'AWS_REGION_NAME' in os.environ:
117+
del os.environ['AWS_REGION_NAME']
118+
119+
def test_bearer_token_and_region_together(self):
120+
"""Test that AWS_BEARER_TOKEN_BEDROCK and AWS_REGION_NAME can be used together."""
121+
test_token = "test-bearer-token-abc123"
122+
test_region = "us-west-2"
123+
124+
# Set both environment variables
125+
os.environ['AWS_BEARER_TOKEN_BEDROCK'] = test_token
126+
os.environ['AWS_REGION_NAME'] = test_region
127+
128+
try:
129+
# Verify both are set correctly
130+
self.assertEqual(os.environ.get('AWS_BEARER_TOKEN_BEDROCK'), test_token)
131+
self.assertEqual(os.environ.get('AWS_REGION_NAME'), test_region)
132+
133+
finally:
134+
# Clean up
135+
for key in ['AWS_BEARER_TOKEN_BEDROCK', 'AWS_REGION_NAME']:
136+
if key in os.environ:
137+
del os.environ[key]
138+
139+
140+
if __name__ == '__main__':
141+
unittest.main()

0 commit comments

Comments
 (0)