Skip to content

security(ci): 외부 Actions 를 전부 commit SHA 로 고정한다 (closes 847) [base: ci/848-single-gate] - #1039

Merged
OnlyReadOneBook merged 5 commits into
developfrom
security/847-action-pinning
Aug 25, 2026
Merged

OnlyReadOneBook merged 5 commits into
developfrom
security/847-action-pinning

Conversation

@OnlyReadOneBook

Copy link
Copy Markdown
Collaborator

워크플로가 태그·브랜치로 액션을 부르면 그 참조가 가리키는 코드는 사후에 바뀔 수 있다. v7 태그는 옮겨 달 수 있고 @master 는 매 run 이 다른 코드다. 우리 러너에서 저장소 토큰을 들고 도는 코드이므로 리비전이 불변이어야 한다.

Repository Actions 설정은 지금 allowed_actions=all, sha_pinning_required=false, secret scanning·push protection 모두 비활성이다.

변경 — 부동 참조 8종 고정

액션 고정 전 고정 후
actions/checkout @v7 @3d3c42e5… # v7.0.1
actions/setup-java @v5 @b6effb05… # v5.7.0
actions/upload-artifact @v4 @ea165f8d… # v4.6.2
actions/upload-artifact @v7 @043fb46d… # v7.0.1
actions/github-script @v9 @3a2844b7… # v9.0.0
docker/setup-buildx-action @v4 @37fe6310… # v4.3.0
docker/build-push-action @v7 @53b7df96… # v7.3.0
dvdandroid/action-android-lint @master @21c9fa65… # v1.3

11개 워크플로, 29줄. codeql·dependency-review·dependency-submission·firebase-wif-canary 는 이미 고정돼 있었다.

@master 였던 android-lint

v1.3 태그가 master HEAD 와 같은 커밋이라 동작 변화 없이 고정된다. 이슈가 제시한 다른 선택지(직접 Gradle command 로 교체)는 모듈별 lint 위반의 인라인 코멘트(#279)를 잃으므로 택하지 않았다. 다만 이 액션은 마지막 커밋이 2025-08-26 이고 별 22개다 — 유지보수가 활발하지 않다는 점은 알고 고정한다. 고정돼 있으므로 업스트림이 방치돼도 우리 CI 동작은 바뀌지 않는다.

정책으로 고정 — 회귀하면 CI 가 잡는다

supply-chain-policy.test.mjs 에 4건 추가.

  • 외부 uses 는 전부 40자리 commit SHA
  • 고정된 참조는 어느 release 에서 왔는지 주석으로 남긴다 (SHA 만 있으면 사람이 못 읽고 Dependabot 갱신도 대조가 안 된다)
  • 이 저장소의 composite action 도 같은 규칙
  • 같은 저장소를 가리키는 ./ 참조(로컬 액션·reusable workflow)는 대상이 아니다 — 리비전이 이 저장소의 것이다

정책이 실제로 막는지 fixture 로 확인했다. mock-cleanup-check.yml 의 checkout 을 @v7 로 되돌리면

ℹ pass 11 / fail 1
  actual: [ 'mock-cleanup-check.yml: actions/checkout@v7' ]

로 실패하고, 원복하면 12/12 통과한다. 태그·브랜치·짧은 SHA(@3d3c42e)가 각각 거부되는 것도 단위 fixture 로 고정했다.

검증

  • 고정 후 미고정 외부 uses 0건
  • actionlint · scripts/repository-quality.sh (17 workflows, 4 shell scripts) 통과
  • node --test .github/scripts/*.test.mjs → 85/85 통과
  • 시각 변경 없음 — screenshot baseline 사이클 해당 없음

Dependabot 은 이미 github-actions ecosystem 을 주간 추적하고 auto-merge 설정이 없다(그 성질도 supply-chain-policy 가 고정하고 있다). 고정 SHA 의 새 release 는 PR 로만 올라온다.

남은 것 — 저장소 설정은 머지 후다

이 PR 은 워크플로 쪽만 다룬다. 다음 네 가지는 develop 에 들어간 뒤 적용해야 한다. 워크플로가 전부 호환되기 전에 켜면 CI 가 통째로 막히기 때문이다.

  1. sha_pinning_required 활성화
  2. allowed actions 정책을 «GitHub 공식·검증된 액션 + 명시 허용» 으로 단계적 제한 — Copilot dynamic workflow 와 release workflow 가 깨지지 않는지 확인하면서
  3. secret scanning 활성화 + 기존 발견을 redacted 상태로 triage (확인된 유효 secret 만 회전하며 값은 이슈·로그에 남기지 않는다)
  4. push protection 활성화

이 단계들은 저장소 전체에 영향을 주고 팀원의 push 를 막을 수 있어 PR 로 처리하지 않았다. 머지 후 적용하고 재조회 결과를 #847 에 남긴다.

리뷰어에게

Closes #847

워크플로가 태그·브랜치로 액션을 부르면 그 참조가 가리키는 코드는 사후에 바뀔 수
있다. v7 태그는 옮겨 달 수 있고 @master 는 매 run 이 다른 코드다. 우리 러너에서
저장소 토큰을 들고 도는 코드이므로 리비전이 불변이어야 한다.

- 부동 참조 8종을 40자리 commit SHA 로 고정하고 옆에 원래 release tag 를 남긴다.
  actions/checkout v7.0.1 · actions/setup-java v5.7.0 ·
  actions/upload-artifact v4.6.2/v7.0.1 · actions/github-script v9.0.0 ·
  docker/setup-buildx-action v4.3.0 · docker/build-push-action v7.3.0 ·
  dvdandroid/action-android-lint v1.3
- supply-chain-policy.test.mjs 에 정책 4건 추가. 외부 uses 는 전부 SHA 여야 하고,
  고정된 참조는 어느 release 에서 온 것인지 주석으로 남겨야 하며, 이 저장소의
  composite action 도 같은 규칙을 따른다. 같은 저장소를 가리키는 ./ 참조는 대상이
  아니다(리비전이 이 저장소의 것이다).

@master 였던 dvdandroid/action-android-lint 는 v1.3 태그가 master HEAD 와 같은
커밋이라 동작 변화 없이 고정된다. 직접 Gradle command 로 바꾸는 선택지는 모듈별
lint 위반 인라인 코멘트(#279)를 잃으므로 택하지 않았다.

실측:
- 고정 후 미고정 외부 uses 0건 (로컬 ./ 참조 제외)
- 정책이 실제로 막는지 fixture 로 확인 — checkout 을 @v7 로 되돌리면 테스트가
  'mock-cleanup-check.yml: actions/checkout@v7' 로 실패하고, 원복하면 통과한다
- actionlint · repository-quality.sh (17 workflows, 4 shell scripts) 통과
- node --test .github/scripts/*.test.mjs → 85/85

Dependabot 은 이미 github-actions ecosystem 을 주간 추적하고 auto-merge 설정이
없어(supply-chain-policy 가 고정) 고정 SHA 의 새 release 를 PR 로만 올린다.

저장소 설정(SHA pinning required · allowed actions 정책 · secret scanning ·
push protection)은 이 PR 이 develop 에 들어간 뒤 적용한다. 워크플로가 전부
호환되기 전에 켜면 CI 가 통째로 막힌다.

closes #847
#1036 이 이 PR 보다 먼저 develop 에 들어오며 미고정 actions/checkout@v7 을
남겼다. PR #1036 에 미리 알려 두었고 순서가 그렇게 났으므로 이쪽에서 맞춘다.
다른 워크플로와 같은 리비전(v7.0.1)이다.

@Sadturtleman Sadturtleman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

승인합니다. 정책 테스트가 «태그·브랜치·짧은 SHA 거부» 를 fixture 로 실제 실패시켜 확인한 점, 고정 참조에 release 주석을 요구한 점이 이 변경의 값이라고 봅니다.

머지 순서만 알려 둡니다 — 제가 방금 승인한 #1096(Android Lint 리포터 → job summary) 과 같은 파일에서 부딪힙니다.

$ git merge-tree --write-tree origin/security/847-action-pinning origin/fix/1093
CONFLICT (content): .github/workflows/lint.yml
CONFLICT (modify/delete): .github/workflows/deployment-decision.yml
  • lint.yml — 이 PR 이 dvdandroid/action-android-lint@master 를 @21c9fa65(v1.3)로 고정하는 자리를 #1096 은 액션 자체를 걷어냅니다(도커 액션이 매 run reviewdog 을 내려받다 실패하면 위반 0건에도 red). 나중에 들어가는 쪽이 «고정할 대상이 없어짐» 으로 정리하면 됩니다.
  • deployment-decision.yml — #1076 계열이 이 파일을 지웁니다.

둘 다 해소 방향이 명확해 blocking 으로 세지 않았습니다.

Base automatically changed from ci/848-single-gate to develop August 25, 2026 04:06
@github-actions github-actions Bot added the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Aug 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

이 PR 은 develop 와 충돌 상태이고, 그래서 CI 가 돌지 않는다.

pull_request 워크플로는 base 와 head 를 합친 가상 머지 커밋(refs/pull/<N>/merge)에서
실행되는데, 충돌이면 GitHub 이 그 ref 를 만들지 못해 워크플로가 트리거조차 되지 않는다.
체크가 실패하는 것이 아니라 아예 생성되지 않으므로, 새 커밋을 올려도 no checks reported
인 채 최신 커밋이 한 번도 검증되지 않은 상태로 남는다 (#1028).

develop 를 병합해 충돌을 풀면 검증이 다시 돈다. 해소되면 이 라벨은 자동으로 떨어진다.

…n-pinning

# Conflicts:
#	.github/workflows/android-managed-device.yml
#	.github/workflows/deployment-decision.yml
#	.github/workflows/lint.yml
#	.github/workflows/unit-test.yml
@github-actions github-actions Bot removed the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Aug 25, 2026
@OnlyReadOneBook
OnlyReadOneBook merged commit f2390e3 into develop Aug 25, 2026
14 checks passed
@OnlyReadOneBook
OnlyReadOneBook deleted the security/847-action-pinning branch August 25, 2026 06:12
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.

Actions 참조 SHA 고정 · secret scanning · push protection 적용

2 participants