-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(general): Add an option to pick beetwen native OpenAI and Azure OpenAI #5569
Changes from all commits
6a87a40
58351d2
f4057ae
a166987
14a723a
02b7bbf
9b5dbc9
e8cdd37
44be5a8
e1ae799
d91b94e
c8101c7
71ccce6
442b9c4
70d3673
ed54de3
c6d7d83
97f5fd3
1e8d3b5
1a9a35a
61e06b5
972dd4c
cc809dd
b7cbeb5
e00412f
5e6c7c9
629d717
c1d5d62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -14,6 +14,7 @@ | |||||
from checkov.common.output.record import Record | ||||||
from typing_extensions import Self | ||||||
|
||||||
# Common OpenAI environment variables | ||||||
OPENAI_MAX_FINDINGS = int(os.getenv("CKV_OPENAI_MAX_FINDINGS", 5)) | ||||||
OPENAI_MAX_TOKENS = int(os.getenv("CKV_OPENAI_MAX_TOKENS", 512)) | ||||||
OPENAI_MODEL = os.getenv("CKV_OPENAI_MODEL", "gpt-3.5-turbo") | ||||||
|
@@ -29,10 +30,32 @@ | |||||
class OpenAi: | ||||||
_instance = None # noqa: CCE003 # singleton | ||||||
|
||||||
def __new__(cls, api_key: str | None = None) -> Self: | ||||||
def _validate_azure_env(self, value: str | None = None, environment_variable_name: str | None = None) -> bool: | ||||||
if (value is None): | ||||||
print( | ||||||
colored( | ||||||
f"ERROR: Configuration for Azure OpenAI is missing: Please specify {environment_variable_name} environment variable for --openai-api-type '{self._api_type}' type.", | ||||||
"red", | ||||||
) | ||||||
) | ||||||
return False | ||||||
return True | ||||||
|
||||||
def __new__(cls, api_key: str | None = None, api_type: str = "default") -> Self: | ||||||
if cls._instance is None: | ||||||
cls._instance = super().__new__(cls) | ||||||
cls._should_run = True if api_key else False | ||||||
cls._api_type = api_type.lower() | ||||||
if (cls._api_type == 'azure'): | ||||||
Comment on lines
+48
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to create a class attribute for this, when you set it on |
||||||
cls.AZURE_OPENAI_API_ENDPOINT = os.getenv("CKV_AZURE_OPENAI_API_ENDPOINT", None) | ||||||
cls.AZURE_OPENAI_API_VERSION = os.getenv("CKV_AZURE_OPENAI_API_VERSION", '2023-05-15') | ||||||
cls.AZURE_OPENAI_DEPLOYMENT_NAME = os.getenv("CKV_AZURE_OPENAI_DEPLOYMENT_NAME", None) | ||||||
cls._should_run = cls._should_run & cls._validate_azure_env(cls._instance, cls.AZURE_OPENAI_API_ENDPOINT, 'CKV_AZURE_OPENAI_API_ENDPOINT') | ||||||
cls._should_run = cls._should_run & cls._validate_azure_env(cls._instance, cls.AZURE_OPENAI_API_VERSION, 'CKV_AZURE_OPENAI_API_VERSION') | ||||||
cls._should_run = cls._should_run & cls._validate_azure_env(cls._instance, cls.AZURE_OPENAI_DEPLOYMENT_NAME, 'CKV_AZURE_OPENAI_DEPLOYMENT_NAME') | ||||||
Comment on lines
+53
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of validating each one by one, pass all to a validate function and decide, if everything is set as needed |
||||||
openai.api_type = cls._api_type | ||||||
openai.api_base = cls.AZURE_OPENAI_API_ENDPOINT if cls.AZURE_OPENAI_API_ENDPOINT is not None else "" | ||||||
openai.api_version = cls.AZURE_OPENAI_API_VERSION | ||||||
openai.api_key = api_key | ||||||
|
||||||
return cls._instance | ||||||
|
@@ -70,24 +93,38 @@ async def _chat_complete(self, record: Record) -> None: | |||||
return | ||||||
|
||||||
try: | ||||||
completion = await openai.ChatCompletion.acreate( # type:ignore[no-untyped-call] | ||||||
model=OPENAI_MODEL, | ||||||
messages=[ | ||||||
{"role": "system", "content": "You are a security tool"}, | ||||||
{ | ||||||
"role": "user", | ||||||
"content": "".join( | ||||||
[ | ||||||
f"fix following code, which violates checkov policy '{record.check_name}':\n", | ||||||
*[line for _, line in record.code_block], | ||||||
] | ||||||
), | ||||||
}, | ||||||
{"role": "user", "content": "Explain"}, | ||||||
], | ||||||
temperature=0, | ||||||
max_tokens=OPENAI_MAX_TOKENS, | ||||||
) | ||||||
# define common messages array | ||||||
messages = [ | ||||||
{"role": "system", "content": "You are a security tool"}, | ||||||
{ | ||||||
"role": "user", | ||||||
"content": "".join( | ||||||
[ | ||||||
f"fix following code, which violates checkov policy '{record.check_name}':\n", | ||||||
*[line for _, line in record.code_block], | ||||||
] | ||||||
), | ||||||
}, | ||||||
{"role": "user", "content": "Explain"}, | ||||||
], | ||||||
# depends on api_type, call ChatCompletion differently | ||||||
logging.info(f"[_chat_complete]: self._api_type: {self._api_type}") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. instead of logging it here, just do it once at the end of the class instance creation, then you can also log other infos like deployment name and endpoint used. |
||||||
if (self._api_type == 'azure'): | ||||||
completion = await openai.ChatCompletion.acreate( # type:ignore[no-untyped-call] | ||||||
engine=self.AZURE_OPENAI_DEPLOYMENT_NAME, | ||||||
messages=messages[0], | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
otherwise you only send the first message, same a few lines lower |
||||||
temperature=0, | ||||||
max_tokens=OPENAI_MAX_TOKENS, | ||||||
) | ||||||
else: | ||||||
completion = await openai.ChatCompletion.acreate( # type:ignore[no-untyped-call] | ||||||
model=OPENAI_MODEL, | ||||||
messages=messages[0], | ||||||
temperature=0, | ||||||
max_tokens=OPENAI_MAX_TOKENS, | ||||||
) | ||||||
|
||||||
logging.info(f"[COMPLETION]{completion}") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
or something similar to have a direct context. Also debug level is more than enough. |
||||||
logging.info(f"OpenAI request consumed {completion.usage.total_tokens} tokens") | ||||||
|
||||||
details = self._parse_completion_response(completion_content=completion.choices[0].message.content) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -272,6 +272,7 @@ def print_console( | |
use_bc_ids: bool = False, | ||
summary_position: str = 'top', | ||
openai_api_key: str | None = None, | ||
openai_api_type: str = "default", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove all of the |
||
) -> str: | ||
summary = self.get_summary() | ||
output_data = colored(f"{self.check_type} scan results:\n", "blue") | ||
|
@@ -305,7 +306,7 @@ def print_console( | |
for record in self.passed_checks: | ||
output_data += record.to_string(compact=is_compact, use_bc_ids=use_bc_ids) | ||
if self.failed_checks: | ||
OpenAi(api_key=openai_api_key).enhance_records(runner_type=self.check_type, records=self.failed_checks) | ||
OpenAi(api_key=openai_api_key, api_type=openai_api_type).enhance_records(runner_type=self.check_type, records=self.failed_checks) | ||
for record in self.failed_checks: | ||
output_data += record.to_string(compact=is_compact, use_bc_ids=use_bc_ids) | ||
if not is_quiet: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -549,3 +549,15 @@ def add_parser_args(self) -> None: | |
"resource code to OpenAI to request remediation guidance. This will use your OpenAI credits. " | ||
"Set your number of findings that will receive enhanced guidelines using CKV_OPENAI_MAX_FINDINGS", | ||
) | ||
self.add( | ||
"--openai-api-type", | ||
env_var="CKV_OPENAI_API_TYPE", | ||
choices=['azure', 'default'], | ||
default='default', | ||
help="By switching this flag to 'azure', you are able to send violated policies to Azure OpenAI service. " | ||
"You have to provide Key, either with --openai-api-key or CKV_OPENAI_API_KEY. " | ||
"Before you switch to 'azure' you also have to define CKV_AZURE_OPENAI_API_ENDPOINT and CKV_AZURE_OPENAI_DEPLOYMENT_NAME environment variables. " | ||
"CKV_AZURE_OPENAI_API_ENDPOINT - is the Azure OpenAI service endpoint, eg: 'https://eastus.api.cognitive.microsoft.com/'. " | ||
"CKV_AZURE_OPENAI_DEPLOYMENT_NAME - this is your Deployment Name from https://oai.portal.com portal you wish to use. " | ||
"With CKV_AZURE_OPENAI_API_VERSION environment variable you are also able to control API version - this defaults to '2023-05-15'. ", | ||
) | ||
Comment on lines
+552
to
+563
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it doesn't make sense to add a flag for it, because you need multiple other settings, which are set via env vars to make it work |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,4 +65,5 @@ nav_order: 2 | |
| `--scan-secrets-history` | Enable secret scan history of commits | | ||
| `--block-list-secret-scan CKV_SECRETS_SCAN_BLOCK_LIST` | List of files to filter out in the secret scanner | | ||
| `--support` | Enable debug logs and upload the logs to the server. Requires a Bridgecrew or Prisma Cloud API key. | | ||
| `--openai-api-type` | By switching this flag to 'azure', you are able to send violated policies to Azure OpenAI service. You have to provide Key, either with --openai-api-key or CKV_OPENAI_API_KEY. Before you switch to 'azure' you also have to define CKV_AZURE_OPENAI_API_ENDPOINT and CKV_AZURE_OPENAI_DEPLOYMENT_NAME environment variables. CKV_AZURE_OPENAI_API_ENDPOINT - is the Azure OpenAI service endpoint, eg: 'https://eastus.api.cognitive.microsoft.com/'. CKV_AZURE_OPENAI_DEPLOYMENT_NAME - this is your Deployment Name from https://oai.portal.com portal you wish to use. With CKV_AZURE_OPENAI_API_VERSION environment variable you are also able to control API version - this defaults to '2023-05-15'. | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||
| `--openai-api-key` | Add an OpenAI API key to enhance finding guidelines by sending violated policies and resource code to OpenAI to request remediation guidance. This will use your OpenAI credits. Set your number of findings that will receive enhanced guidelines using CKV_OPENAI_MAX_FINDINGS | |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,6 +94,10 @@ Check: CKV_AWS_16: "Ensure all data stored in the RDS is securely encrypted at r | |
Passed checks: 1, Failed checks: 1, Skipped checks: 0 | ||
``` | ||
|
||
## OpenAI type | ||
|
||
With `--openai-api-type` flag, you are able to choose OpenAI source. Possible values here are `default` and `azure`. Default valuie is obvoiusly `default`, and this flag will redirect your requests to public-generally available OpenAI service. By switching this flag to `--openai-api-type azure` you can query **Azure OpenAI** resource using Azure OpenAI Key. Please see below [Azure OpenAI] section for more configuration details. | ||
|
||
Comment on lines
+97
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move this to the |
||
## Settings | ||
|
||
Following environment variables can be used to fine tune the amount of AI generated guidelines. | ||
|
@@ -104,3 +108,19 @@ Following environment variables can be used to fine tune the amount of AI genera | |
| CKV_OPENAI_MAX_FINDINGS | 5 | Amount of findings per framework to add enhanced guidelines. | | ||
| CKV_OPENAI_MAX_TOKENS | 512 | Maximum number of tokens to generate in the chat completion. | | ||
| CKV_OPENAI_MODEL | gpt-3.5-turbo | ID of the chat completion model to use. | | ||
|
||
|
||
## Azure OpenAI | ||
|
||
Azure OpenAI re-use following environment variables from 'default' OpenAI configuration: | ||
- CKV_OPENAI_API_KEY | ||
- CKV_OPENAI_MAX_FINDINGS | ||
- CKV_OPENAI_MAX_TOKENS | ||
|
||
To use Azure OpenAI you have to define following environment variables: | ||
|
||
| Environment variable | Default | Info | | ||
|------------------------------------|---------------|--------------------------------------------------------------| | ||
| CKV_AZURE_OPENAI_API_ENDPOINT | | Azure OpenAI Endpoint format. Eg.: 'https://eastus.api.cognitive.microsoft.com/'| | ||
| CKV_AZURE_OPENAI_API_VERSION | 2023-05-15 | Azure OpenAI API version to use. | | ||
| CKV_AZURE_OPENAI_DEPLOYMENT_NAME | | Deployment Name of the chat completion model to use. Note that, deployment must be already deployed in https://oai.azure.com portal. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just use a normal log message