I was working with the Jira toolkit , and when doing some local debugging I noticed the API token is printed plain text if you do:
jira = JiraAPIWrapper()
toolkit = JiraToolkit.from_jira_api_wrapper(jira)
tools = toolkit.get_tools()
print(tools[0])
To avoid that, the current approach in the project seems to be using Pydantic Secretstr.
E.g.
Now, I was evaluating the alternatives and landed in this draft PR in my fork:
main ← fix/jira-toolkit-secretstr
opened 05:35PM - 26 Apr 26 UTC
# Description
The Jira API token is being printed in plain text in the consol… e and logs.
## How to verify the issue
In the terminal:
```bash
export JIRA_API_TOKEN=some-sample-token
export JIRA_USER_EMAIL=jira-user@example.com
```
Then run a script like:
```python
from langchain_community.agent_toolkits.jira.toolkit import JiraToolkit
from langchain_community.utilities.jira import JiraAPIWrapper
if __name__ == "__main__":
jira = JiraAPIWrapper(jira_cloud=True)
jira_toolkit = JiraToolkit.from_jira_api_wrapper(jira)
tools = jira_toolkit.get_tools()
print(tools[0])
```
Token will be visible in the output, the same will happen in logs.
## Why this happens?
JiraAPIWrapper is Pydantic model that will show all the values when represented as a string.
## How to solve it?
Many implementations in the main and community langchain projects use Pydantic Secretstr in this situation.
Examples:
- [OpenAI Base Chat Model](https://github.com/langchain-ai/langchain/blob/d44833ce34df310618aff71cfd1cd05c6dd53c94/libs/partners/openai/langchain_openai/chat_models/base.py)
- [Anthropic Base Chat Model](https://github.com/langchain-ai/langchain/blob/d44833ce34df310618aff71cfd1cd05c6dd53c94/libs/partners/anthropic/langchain_anthropic/chat_models.py)
- [Community - AzureML](https://github.com/langchain-ai/langchain-community/blob/f9aa95409f4dca8f3a50287a43ab06f4e2c8294a/libs/community/langchain_community/llms/azureml_endpoint.py#L376) and [AzureML tests](https://github.com/langchain-ai/langchain-community/blob/f9aa95409f4dca8f3a50287a43ab06f4e2c8294a/libs/community/tests/unit_tests/chat_models/test_azureml_endpoint.py#L47)
## Notes about the linter
It seems almost all usages of SecretStr in the project are doing:
```python
class MyClass(BaseModel):
my_token: Optional[SecretStr] = None
```
That approach alone makes fail the project linter with:
```
tests/unit_tests/jira/test_jira_api_wrapper.py:38: error: Argument "jira_api_token" to "JiraAPIWrapper" has incompatible type "str"; expected "SecretStr | None" [arg-type]
```
...and forced me to add `# type: ignore[arg-type]` in the unit tests.
That linter check could be problem only when passing a token to the constructor, and not when loading it from environment variables.
I checked if it could be a problem for users in VSCode but it is not being reported, mostly because Pydantic models are not detected in general by Pylance in static checking in the standard setup, even in strict mode.
An option could be to declare the field as `Union[SecretStr,str]`, while still dynamically enforcing SecretStr in practice at `validate_environment`. But that could be also confusing
The rest of the current implementations follow the same qa exclusion approach in their tests, so I followed the current project examples.
Files `duckdb_loader.py` and `confluence.py` were not passing `make lint` in the main branch, before my changes, at least for me.
Resources:
[OWASP - Logging Cheatsheet - Data to exclude](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html)
I was looking forward to submit it for the maintainers consideration.
Beyond, lint, test, etc, in the contributing guide it says:
The pull request must link to an issue or discussion where a solution has been approved by a maintainer.
So I’m posting it here and looking for guidance.
Also open a corresponding issue justifying why this is needed and then the issue will be assigned to you by an official maintainer. Otherwise if you have followed Contributing - Docs by LangChain , you will be good.