diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..22acc76 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,83 @@ +# Contributing to Port Execution Agent + +Thank you for your interest in contributing to the Port Execution Agent! We welcome contributions and feedback from the community. To help you get started, please follow these guidelines. + +## How to Contribute + +### Reporting Issues + +If you encounter any bugs or issues with the execution agent, please report an issue via our [Slack Community](https://port-community.slack.com/archives/C07CB3MV63G). When reporting an issue, be sure to include: +- A description of the problem, including any error messages. +- Steps to reproduce the issue. +- Any relevant logs or screenshots. + +### Suggesting Enhancements + +If you have suggestions for new features or improvements, please open a feature request [here](https://roadmap.getport.io/ideas), or reach to us via our [Slack Community](https://port-community.slack.com/archives/C07CB3MV63G). + +Provide details on: +- The enhancement or feature you are proposing. +- How it would benefit users. +- Any additional context or use cases. + +### Submitting Code + +To submit code contributions: +1. Fork the repository on GitHub. +2. Create a new branch for your changes. +3. Make your changes and test them thoroughly. +4. Ensure your code adheres to our coding style and guidelines. +5. Open a pull request against the `main` branch of the original repository. Include a clear description of your changes and any relevant context. + +## Coding Guidelines + +- Write clear and concise commit messages. +- Ensure your changes do not break existing functionality. +- Add or update tests as necessary. + +## Debugging + +### Running Against Local Port Instance + +When debugging the Port Execution Agent locally against a local instance of Port, follow these steps: + +1. **Set Up Local Environment:** + - Ensure you have a local instance of Port running. This will act as your development and testing environment. + +2. **Configure Environment Variables:** + - Create or update your `.env` file to include the following environment variable: + ```env + USING_LOCAL_PORT_INSTANCE=True + ``` + +3. **Kafka Authentication:** + - When `USING_LOCAL_PORT_INSTANCE` is set to `True`, the execution agent will not attempt to pull your local organization's kafka credentials. + +4. **Running the Agent Locally:** + - Start the execution agent as you normally would. + +### General Troubleshooting (Optional) + +For debugging the Port Execution Agent in other environments, consider the following tips: + +1. **Check Authentication and Configuration:** + - Ensure that all necessary authentication details are correctly configured for Kafka and any other external services. + +2. **Review Logs:** + - Examine the logs for any error messages or issues that might provide insights into problems. + +3. **Verify Endpoints and Connectivity:** + - Ensure that all endpoints are correctly specified and accessible. + +4. **Update Dependencies:** + - Check that all dependencies are up-to-date and compatible with your environment. + +5. **Consult Documentation:** + - Refer to our [Documentation](https://docs.getport.io/actions-and-automations/setup-backend/webhook/port-execution-agent). + +## Contact + +For any questions or additional support, please contact us via Intercom or check our [Slack Community](https://port-community.slack.com/archives/C07CB3MV63G). + +Thank you for contributing to the Port Execution Agent! + diff --git a/app/consumers/kafka_consumer.py b/app/consumers/kafka_consumer.py index 1c5842b..7afc911 100644 --- a/app/consumers/kafka_consumer.py +++ b/app/consumers/kafka_consumer.py @@ -25,20 +25,22 @@ def __init__( if consumer: self.consumer = consumer else: - logger.info("Getting Kafka credentials") - username, password = get_kafka_credentials() conf = { "bootstrap.servers": settings.KAFKA_CONSUMER_BROKERS, "client.id": consts.KAFKA_CONSUMER_CLIENT_ID, "security.protocol": settings.KAFKA_CONSUMER_SECURITY_PROTOCOL, "sasl.mechanism": settings.KAFKA_CONSUMER_AUTHENTICATION_MECHANISM, - "sasl.username": username, - "sasl.password": password, "group.id": settings.KAFKA_CONSUMER_GROUP_ID, "session.timeout.ms": settings.KAFKA_CONSUMER_SESSION_TIMEOUT_MS, "auto.offset.reset": settings.KAFKA_CONSUMER_AUTO_OFFSET_RESET, "enable.auto.commit": "false", } + if settings.RUNTIME != 'local': + logger.info("Getting Kafka credentials") + username, password = get_kafka_credentials() + conf["sasl.username"] = username + conf["sasl.password"] = password + self.consumer = Consumer(conf) def _on_assign(self, consumer: Consumer, partitions: Any) -> None: diff --git a/app/core/config.py b/app/core/config.py index a7496b2..377d287 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,6 +1,7 @@ from pathlib import Path from typing import Any, Optional +from dotenv import find_dotenv from pydantic import ( AnyHttpUrl, BaseModel, @@ -30,6 +31,7 @@ class Mapping(BaseModel): class Settings(BaseSettings): + USING_LOCAL_PORT_INSTANCE: bool = False LOG_LEVEL: str = "INFO" STREAMER_NAME: str @@ -65,6 +67,8 @@ def set_kafka_change_log_topic(cls, v: Optional[str], values: dict) -> str: class Config: case_sensitive = True + env_file = find_dotenv() + env_file_encoding = "utf-8" WEBHOOK_INVOKER_TIMEOUT: int = 30 diff --git a/app/invokers/webhook_invoker.py b/app/invokers/webhook_invoker.py index 26cc480..b3626c2 100644 --- a/app/invokers/webhook_invoker.py +++ b/app/invokers/webhook_invoker.py @@ -280,7 +280,9 @@ def _invoke_run( res.raise_for_status() run_logger("Port agent finished processing the action run") - def validate_incoming_signature(self, msg: dict) -> bool: + def validate_incoming_signature(self, + msg: dict, + invocation_method_name: str) -> bool: if "changelogDestination" in msg: return True @@ -294,9 +296,14 @@ def validate_incoming_signature(self, msg: dict) -> bool: ) return False - # Remove the headers to avoid them being used in the signature verification - del msg["headers"]["X-Port-Signature"] - del msg["headers"]["X-Port-Timestamp"] + # Remove Port's generated headers to avoid them being + # used in the signature verification + if invocation_method_name == 'GITLAB': + del msg["headers"] + else: + del msg["headers"]["X-Port-Signature"] + del msg["headers"]["X-Port-Timestamp"] + expected_sig = sign_sha_256( json.dumps(msg, separators=(",", ":"), ensure_ascii=False), settings.PORT_CLIENT_SECRET, @@ -313,7 +320,8 @@ def invoke(self, msg: dict, invocation_method: dict) -> None: logger.info("WebhookInvoker - start - destination: %s", invocation_method) run_id = msg["context"].get("runId") - if not self.validate_incoming_signature(msg): + invocation_method_name = invocation_method.get('type', 'WEBHOOK') + if not self.validate_incoming_signature(msg, invocation_method_name): return logger.info("WebhookInvoker - validating signature") diff --git a/requirements.txt b/requirements.txt index d18dce2..9695acb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ pydantic==1.10.2 requests==2.28.1 pyjq==2.6.0 flatten-dict==0.4.2 +python-dotenv==1.0.1