Skip to content

ci(review-debt-guard): 팀원 판정을 association 아닌 실권한으로 [base: develop] - #1155

Merged
1hyok merged 1 commit into
developfrom
ci/review-debt-real-permission
Aug 25, 2026
Merged

1hyok merged 1 commit into
developfrom
ci/review-debt-real-permission

Conversation

@1hyok

@1hyok 1hyok commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

무엇이 문제였나

가드는 팀원 여부를 웹훅 페이로드의 author_association 으로 갈랐다. 이 값은 조직 멤버십이 비공개면 MEMBER 대신 CONTRIBUTOR 를 내린다. 이 조직은 orgs/Afternote/public_members 가 0명이라 전원 비공개다.

그 결과 레포에 직접 초대된 계정 하나만 COLLABORATOR 로 찍혀 검사를 받고, 조직 경유로 권한을 받은 나머지 팀원은 전원 «외부 기여자» 로 건너뛰어졌다. 가드가 한 방향으로만 돌고 있었다.

실측 (8/25 밤 런 3건)

시각(KST) PR 작성자 가드 판정
23:30 #1152 Sadturtleman 외부 기여자(CONTRIBUTOR) — 건너뜀
23:35 #1154 Sadturtleman 외부 기여자(CONTRIBUTOR) — 건너뜀
23:47 #1112 1hyok 미응답 3건 — PR #1112 를 닫는다 → CLOSED

23:47 런이 빚으로 센 3건이 바로 12분 전에 통과한 #1152·#1154 와 #1121 이다. 검사를 면제받은 쪽이 연 PR 이 곧바로 검사를 받는 쪽의 빚이 되어 그 PR 을 닫는 구조였다.

gh api repos/.../pulls 로 조회하면 두 계정 다 MEMBER 로 보인다(조회하는 토큰이 조직 멤버라서). 눈으로는 잡히지 않고 런 로그에만 드러난다.

무엇을 바꿨나

  • 팀원 판정을 collaborators/{user}/permission 실권한 조회로 교체. 멤버십 공개 여부와 무관해진다.
  • fork 는 head.repo.full_name != github.repository 로 따로 가른다. 원래 걸러내려던 이유가 «토큰이 read-only 라 닫지도 못한다» 였으므로 association 은 애초에 그 판정에 쓸 수 있는 축이 아니었다.
  • 조회 실패와 예상 밖 권한 값은 통과시키지 않고 run 을 세운다. 빈 값을 «권한 없음» 으로 접으면 조회 실패가 통과로 둔갑한다 — 이 파일이 열린 PR 조회에 이미 걸어 둔 원칙과 같다.
  • .github/scripts/review-debt-policy.test.mjs 신설 (7건). 이 회귀와 함께 «자기 PR 은 빚이 아니다», «변경요청은 반영 시점에 다시 리뷰어의 몫», «병합 커밋은 반영으로 세지 않는다» 를 못박는다.

검증

  • node --test .github/scripts/*.test.mjs — 133건 전량 통과 (신설 7건 포함). 이 러너는 unit-test.yml 이 모든 PR 에서 돌린다.
  • 워크플로 YAML 파싱 유효, run 블록 2개 bash -n 통과.
  • Gradle 모듈 변경 없음(.github/ 만) → 모듈 빌드 해당 없음.
  • 시각 변경 없음 → 스크린샷 baseline 사이클·에뮬 실측 해당 없음.

리뷰어에게

이 PR 자체가 가드에 걸려 닫힐 수 있다. 그건 패치가 동작한다는 증거다 — 권한 조회가 성공해야 빚 검사까지 진행되기 때문이다. 닫히면 review-debt-exempt 라벨을 붙여 되살린다.

머지 뒤에는 팀 전원이 검사 대상이 된다. #821 처럼 변경요청을 낸 뒤 작성자가 반영했는데 재리뷰가 없는 PR 도 그때부터 리뷰어의 빚으로 잡힌다.

웹훅 페이로드의 author_association 은 조직 멤버십이 비공개면 MEMBER 대신
CONTRIBUTOR 를 내린다. 이 조직은 공개 멤버가 0명이라, 레포에 직접 초대된
한 계정만 COLLABORATOR 로 찍혀 검사를 받고 나머지 팀원은 전원 «외부 기여자»
로 건너뛰어졌다. 가드가 한 방향으로만 돌고 있었다.

8/25 실측 — 23:30·23:35 에 열린 #1152·#1154 는 «외부 기여자(CONTRIBUTOR) —
건너뜀» 한 줄로 통과했고, 12분 뒤 그 둘을 포함한 빚 3건을 두고 #1112 만
닫혔다. REST 로 조회하면 두 계정 다 MEMBER 로 보여 눈으로는 잡히지 않는다.

collaborators/{user}/permission 으로 실권한을 묻는다. fork 는 토큰이
read-only 라 닫지도 못하는 것이 원래 이유였으므로 head 저장소로 따로
가른다 — association 은 그 판정에 쓸 수 있는 축이 아니었다.

조회 실패와 예상 밖 권한 값은 통과시키지 않고 run 을 세운다. 빈 값을
«권한 없음» 으로 접으면 조회 실패가 통과로 둔갑한다.
@github-actions

Copy link
Copy Markdown
Contributor

🚧 리뷰 적체 가드 — 이 PR 을 닫습니다

아무도 리뷰하지 않은 PR 이 3건 남아 있습니다.

PR 열린 날 경과 제목
#1154 2026-08-25 0일 test(mindrecord): screenshotTest 소스셋을 세우고 추억 공간 baseline 을 넣는다 (#1131)
#1152 2026-08-25 0일 fix(mindrecord): 수신인 조회 실패를 «등록 없음» 과 구분해 알린다 (#1019)
#1121 2026-08-25 0일 fix(mindrecord): 일기 기록 날짜를 표시 전용으로 바꾼다 (#1008)

이 저장소는 아무도 응답하지 않은 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136).

각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤에 올라온 변경을 다시 봐 줄 의무는 없지만, 변경요청은 작성자가 반영한 시점에 다시 리뷰어의 몫이 됩니다.

되살리는 법

위 리뷰를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다.

gh pr reopen 1155

리뷰보다 이 PR 이 급하면 review-debt-exempt 라벨을 붙이고 다시 열면 통과합니다.

@1hyok

1hyok commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator Author

이 패치를 기다리는 동안 같은 일이 한 번 더 일어났다

리뷰 빚 3건(#1152·#1154·#1121)을 모두 판정해 빚을 0으로 만든 직후, 8초 사이에 이렇게 됐다.

시각(KST) 일어난 일 가드 판정
00:11:12 Sadturtleman 이 #1156 을 연다 —
00:11:16 그 PR 의 가드가 돈다 외부 기여자(CONTRIBUTOR) — 건너뜀
00:11:20 내가 #1112 를 되살린다 미응답 1건 — PR #1112 를 닫는다
00:12:10 #1116 을 되살린다 미응답 1건 — PR #1116 를 닫는다

빚으로 센 «미응답 1건» 이 방금 면제받고 열린 #1156 이다. #1112 는 이미 Sadturtleman 의 APPROVED 를 받은 PR 인데도 닫혔다.

빚을 아무리 갚아도, 검사를 면제받는 쪽이 PR 하나를 여는 순간 검사받는 쪽의 PR 이 도로 닫힌다. 갚는 속도가 무의미한 구조라서 이 패치 없이는 빠져나갈 수 없다.

@1hyok
1hyok merged commit 96a5c1b into develop Aug 25, 2026
26 of 33 checks passed
@1hyok
1hyok deleted the ci/review-debt-real-permission branch August 25, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant