오픈소스 기여하기 1: Bruno
계기
오픈소스에 기여해보고 싶다는 생각이 본격적으로 든 건, 소프트웨어 마에스트로의 양홍주 엑스퍼트님이 작성하신 오픈소스 기여 블로그 글을 읽고 나서였다. 단 2주 만에 여러 오픈소스 프로젝트에 기여를 완료하셨다는 내용이 인상 깊었고, ‘정말 대단하다’는 감탄과 동시에 ‘이거 진짜 재밌겠다’는 생각이 들었다.
왜 Bruno 였을까?
그래서 일단 무엇을 기여할 수 있을지부터 고민해보았다. 나는 평소에 파이썬을 가장 자신 있게 다루기 때문에, 자주 사용하는 파이썬 패키지들 위주로 GitHub 저장소들을 살펴보았다. 하지만 예상외로 이슈가 많지 않았고, 초보 기여자가 접근하기 쉬운 문제도 잘 보이지 않았다.
그러던 중 평소에 사용하던 오픈소스 API 요청 툴인 Bruno가 떠올랐다. 저장소를 확인해보니 열려 있는 이슈만 1200개가 넘었고, 유지보수도 비교적 활발하게 이루어지고 있었다. 기여할 만한 지점을 찾기에 괜찮아 보였다. 그래서 Bruno를 살펴보기로 했다.
과정
설치
Bruno 프로젝트는 Electron 기반의 앱이라 처음에 어떻게 설치해야하는지 다소 막막했다. 그러나 다행히도 공식 저장소에 기여 가이드(contributing.md)가 잘 정리되어 있어 큰 어려움 없이 개발 환경을 셋업할 수 있었다.
bruno/contributing.md at main · usebruno/bruno
bruno/contributing.md at main · usebruno/bruno
Opensource IDE For Exploring and Testing API's (lightweight alternative to Postman/Insomnia) - usebruno/bruno
github.com
버그 분석
내가 해결하려한 이슈는 다음 이슈이다.
Postman ignores empty "auth apikey", bruno fails "header name must be a non-empty string". · Issue #4991 · usebruno/bruno
I have checked the following: I have searched existing issues and found nothing related to my issue. This bug is: making Bruno unusable for me slowing me down but I'm able to continue working annoy...
github.com
이 이슈는 다음과 같은 상황에서 발생한다:
- Postman collection에 API Key 인증이 설정되어 있으나 key와 value가 비어 있는 경우
- 동시에 헤더에 환경 변수 형태의 key-value 쌍({{api-key}})이 존재하는 경우
- Postman에서는 정상 동작하지만, 이를 Bruno로 가져오면 오류가 발생한다
Bruno 파일로 변환하면 다음과 같은 파일이 나오는데,
headers {
x-fnma-access-token: {{x-FFFFFFFFF-access-token}}
x-fnma-api-key: {{x-FFFFFFFF-api-key}}
Content-Type: application/json
ServiceName: AWS
}
auth:apikey {
key:
value:
placement: header
}
이 경우 Bruno는 다음과 같은 오류를 발생시킨다:
header name must be a non-empty string
즉, key가 비어 있는 인증 정보(auth:apikey)가 존재하면, 내부적으로 이를 헤더로 강제 주입하면서 문제가 발생하는 것이다.
Bruno는 빈 key를 허용하지 않는 반면, Postman은 이를 단순히 무시하기 때문에 동작 차이가 생긴다.
재현
실제로 이 이슈를 내 로컬 환경에서 재현해봤다.
.bru 파일에 위와 동일한 구조의 헤더 및 auth 설정을 포함시킨 후, 요청을 보내보면 예상대로 동일한 오류 메시지가 출력되었다:
비슷한 이슈 발견
구글과 GitHub를 통해 비슷한 오류 사례가 있는지 검색해보았다.
그 과정에서 예상외로, 유사한 문제를 다룬 이슈와 이미 머지된 PR을 하나 발견할 수 있었다:
Allows header key/value to be empty · Issue #1898 · usebruno/bruno
Allows header key/value to be empty · Issue #1898 · usebruno/bruno
I have multiple environments and some need a header key with a header value. But my requests collections are the same. To handle it, all my environments have the header key and the header value as ...
github.com
이 이슈에서는 빈 헤더 key나 value가 있을 경우 요청이 실패하는 문제를 다루고 있었고, 이후 해당 문제는 다음 PR을 통해 해결되었다:
fix(#1898): Ignore empty headers to prevent sending request error by AntoninHuaut · Pull Request #1917 · usebruno/bruno
Description Empty headers (in request or in collections) are ignored to prevent sending request error. (#1898) Contribution Checklist: The pull request only addresses one issue or adds one featur...
github.com
하지만 코드를 살펴본 결과, 이 수정은 일반적인 Header 입력에만 적용되었고, Auth → API Key 방식을 통해 삽입되는 헤더에는 여전히 동일한 문제가 발생하는 상황이었다.
즉, 기존 해결책이 모든 경로를 커버하지 못하고 있었던 것이다.
아마 추측컨데 위 문제가 해결되었던 bruno-electron 패키지에서 똑같이 해결할 수 있을 것이라는 생각이 들었다.
해결
내가 수정한 내용은 다음과 같다:
- Auth 탭에서 API Key 방식 사용 시, key가 빈 문자열이면 해당 헤더는 생성하지 않도록 예외 처리 추가
수정 후 동일한 .bru 파일을 로딩하고 요청을 보냈을 때 더 이상 오류가 발생하지 않음을 확인했다.
기능적으로도 기존 동작에는 영향을 주지 않는 선에서 해결할 수 있었다.
이어서 PR을 제출했다.
fix: Ignore empty header on Auth API Key(Header) to prevent sending request error by wibaek · Pull Request #5007 · usebruno/br
Description Empty header in Auth API Key is ignored to prevent sending request error. (#4991) Before: After: Contribution Checklist: The pull request only addresses one issue or adds one featur...
github.com
반영
이후 이슈를 만들어준 이슈어에게서 이 기능이 잘 작동한다는 답변을 받았고, 이후 리뷰어 분들도 accept를 해주셨다.
개선 요청 리뷰
매인테이너 한분에게서 단순 acccept가 아닌 리뷰를 받게 되었다.
Thanks for this fix! This is a good improvement to prevent empty API keys from being set as headers.
I noticed that the same validation logic should probably be applied to the query parameters case as well. Currently, when apiKeyAuth.placement === 'queryparams' we're still unconditionally assigning:
axiosRequest.apiKeyAuthValueForQueryParams = apiKeyAuth;
An empty API key in query parameters could potentially cause similar issues (like malformed URLs with empty parameter names). Would it make sense to add the same if (apiKeyAuth.key.length > 0) check before setting apiKeyAuthValueForQueryParams in both the collection-level and request-level auth sections?
This would ensure consistent behavior regardless of whether the API key is configured for headers or query parameters.
What do you think?
코드에서 header를 처리하는 부분과 queryparams를 처리하는 부분중, header을 처리하는 부분에서만 빈 key값을 예외처리 해주었는데 queryparams에서도 동일한 문제가 발생할 수 있다는 것을 알려주는 리뷰였다.
곰곰히 생각해보니 queryparams에서도 key가 없는건 일반적이지 않은 상황이라고 보여졌고, 타당하다는 생각이 들었다.
그리고 추가적으로 value가 없는것도 문제가 되지 않을까 생각하고 자료를 찾아보았다.
Is a url query parameter valid if it has no value?
Should query parameters with an empty value be ignored or treated as an empty value?
From the webdev community on Reddit
Explore this post and more from the webdev community
www.reddit.com
이 또한 일반적인 상황은 아니지만, 빈 스트링으로 간주될 수 있다고 생각이 들었고, 이것에 대한 예외처리는 하지 않는게 좋겠다고 생각됐다.
개선
case 'apikey':
const apiKeyAuth = get(request, 'auth.apikey');
if (apiKeyAuth.key.length === 0) break;
if (apiKeyAuth.placement === 'header') {
axiosRequest.headers[apiKeyAuth.key] = apiKeyAuth.value;
} else if (apiKeyAuth.placement === 'queryparams') {
// If the API key authentication is set and its placement is 'queryparams', add it to the axios request object. This will be used in the configureRequest function to append the API key to the query parameters of the request URL.
axiosRequest.apiKeyAuthValueForQueryParams = apiKeyAuth;
}
break;
기존 header 내에서 if문 처리를 해주는 방식에서, 둘 모두를 처리하기전에 key 길이가 0이면 fast return을 해주는 방식으로 처리했다. if문 단계가 줄어들어 코드 읽기도 더 편해진 것 같다.
고민이 된건 주석을 넣을지 말지 였는데, 코드 자체가 명확하다면 굳이 주석을 넣을 필요가 없다고 생각이 들었다. apiKeyAuth.key.length === 0 이 라는 코드는 키가 없다는 조건을 알아보기에 충분하다고 생각했고 굳이 주석을 넣지 않기로 했다.
후기
이번에 오픈소스에 기여를 해보면서 이슈를 잘 잡는것이 중요하겠다 라는 생각이 들었다. 실제로 나도 이슈를 잘잡아 간단한 내용을 빠르게 해결할 수 있었다.
작은 기여였지만 내 이름으로 PR을 남겼다는 것은 의미있는 경험인 것 같고, 앞으로도 계속 이슈를 틈틈히 보며 기여해보고 싶다는 생각이 들었다.