필요한 정보 모아보기
테크

GitHub Actions 보관 설정, 10월부터 실행 기록·체크·상태까지 — 기본 90일 뒤 삭제, 설정 위치와 미리 할 일

#GitHub Actions#GitHub#CI/CD#감사 로그#DevOps

GitHub Actions 보관(retention) 설정은 이제 아티팩트와 로그만이 아니라 체크(check), 워크플로 실행(workflow run), 커밋 상태(status)까지 지우는 기준이 됐다. GitHub는 2026년 10월 1일 체인지로그에서 이 확대 적용이 github.com의 GitHub Actions에 들어갔다고 밝혔다. 기본값은 90일이다. 지금까지 체크·실행·상태는 보관 설정과 상관없이 400일 넘게 남아 있었다. 그러니 체감 변화가 큰 쪽은 실행 기록이다.

1주일 앞선 9월 24일에는 작은 변경이 하나 더 있었다. 만료된 아티팩트가 실행 요약 화면과 REST API에서 아예 보이지 않게 됐다. 둘 다 "오래된 CI 기록이 언제, 어디서 사라지는가"에 관한 이야기라 함께 정리했다. 설정 위치와 기본값·최대값, 실제 저장소에서 gh api로 조회한 결과, 그리고 90일 뒤에도 기록을 남겨야 하는 팀이 미리 해 둘 일 순서다.

무엇이, 언제부터 지워지나

변화를 한 표로 묶으면 이렇다.

대상10월 1일 이전10월 1일 이후저장 용량 과금
아티팩트·로그보관 설정을 따름(기본 90일)그대로과금 대상
체크(check suite·check run)설정과 무관하게 400일 이상같은 보관 설정을 따름메타데이터는 과금 안 됨
워크플로 실행설정과 무관하게 400일 이상같은 보관 설정을 따름메타데이터는 과금 안 됨
커밋 상태(status)설정과 무관하게 400일 이상같은 보관 설정을 따름메타데이터는 과금 안 됨

놓치기 쉬운 부분은 범위다. GitHub Actions가 만든 체크만이 아니라 서드파티 앱이 만든 체크와 상태도 같이 정리된다. 외부 CI 서비스, 코드 품질 도구, 배포 도구가 커밋에 붙여 둔 초록 체크 표시도 보관 기간이 지나면 사라진다는 뜻이다. 8월 27일 사전 공지에는 9월 15일 자로 이 범위를 분명히 하는 편집자 주가 붙었다.

되돌릴 방법은 없다. 체인지로그는 설정을 바꿔도 이미 지워진 데이터는 복원되지 않는다고 적었다. 반대 방향도 마찬가지다. GitHub 문서에 따르면 보관 기간을 바꾸면 새로 생기는 체크·실행·상태·아티팩트·로그에만 적용되고, 이미 있는 것에는 소급되지 않는다.

비용 쪽은 이렇다. 체크·실행·상태 메타데이터 자체는 저장 용량 과금 대상이 아니다. 거기에 딸린 아티팩트와 로그가 과금된다. 그래서 보관 기간을 늘리면 기록은 오래 남지만 Actions 저장 비용이 오를 수 있다는 게 GitHub의 설명이다.

설정은 어디서, 며칠까지 되나

저장소 기준 위치는 Settings → Actions → General이고, 항목 이름은 "Check, workflow run, status, artifact and log retention"으로 바뀌었다. 조직도 같은 경로(조직 Settings → Actions → General)에 같은 이름의 항목이 있다.

  • 기본값: 90일
  • 공개 저장소: 1~90일
  • 비공개 저장소: 1~400일
  • 상한: 저장소 값은 조직·엔터프라이즈가 정한 상한을 넘을 수 없다

화면을 열지 않고 REST API로도 읽을 수 있다. 엔드포인트 경로에는 아직 artifact-and-log-retention이라는 옛 이름이 남아 있지만, 문서 설명은 체크·실행·커밋 상태·아티팩트·로그 전체의 보관 설정이라고 바뀌어 있다. 이 블로그의 소스 저장소(비공개)에 직접 호출해 봤다(2026-10-09, macOS 26.4.1, gh 2.101.0).

gh api repos/<owner>/<repo>/actions/permissions/artifact-and-log-retention
# {"days":90,"maximum_allowed_days":400}

기본값 90일을 한 번도 바꾸지 않았다는 게 그대로 보인다. maximum_allowed_days가 400인 건 비공개 저장소 최대치와 맞는다. 권한이 없는 저장소에서는 안 된다. 쓰기 권한이 없는 공개 저장소 cli/cli에 같은 요청을 보내니 403이 돌아왔다. 문서상 클래식 토큰은 repo 범위, 세분화 토큰은 저장소 Administration 읽기 권한이 필요하다. 조직 단위로는 orgs/<org>/actions/permissions/artifact-and-log-retention을 쓰면 된다.

아티팩트는 하나씩 따로 짧게 잡을 수 있다. actions/upload-artifact의 retention-days 입력이다. 비워 두면 저장소 설정을 따르고, 저장소·조직·엔터프라이즈 상한보다 길게는 못 잡는다.

만료된 아티팩트는 이제 목록에도 안 나온다

9월 24일 변경은 표시 방식만 바꿨다. 예전엔 만료된 아티팩트가 실행 요약에 "Expired" 표시를 단 채 남아 있었다. 실제 파일은 이미 지워졌는데도 말이다. 그래서 "없는 파일에 아직 저장 요금이 나가나?" 하고 헷갈리는 사람이 있었다는 게 GitHub가 밝힌 이유다.

이제 만료된 아티팩트는 다음 세 곳에서 빠진다.

  1. 워크플로 실행 요약 페이지의 아티팩트 목록
  2. REST API "저장소 아티팩트 목록(List artifacts for a repository)"
  3. REST API "아티팩트 조회(Get an artifact)"

보관 설정과 과금은 그대로다. 만료 뒤에 어떤 아티팩트가 만들어졌었는지 알고 싶으면 실행 로그를 보라는 게 GitHub의 안내다.

cli/cli 저장소로 확인해 봤다. 아티팩트 API의 total_count는 8,467개였고, 첫 두 페이지와 마지막 페이지(최대 100개씩)를 훑어보니 expired가 true인 항목은 하나도 없었다. 가장 오래된 항목은 7월 11일 생성, 만료 시각은 10월 9일이었다. 만료 직전 것까지만 목록에 남는 셈이다. 그러니 expired == true로 걸러 정리 대상을 찾던 스크립트가 있다면 이제 늘 빈 결과를 받는다.

여기서 하나 조심할 점이 있다. "로그에서 찾으라"는 안내는 로그가 아직 남아 있을 때만 통한다. 로그도 같은 보관 설정을 따르기 때문이다. retention-days: 5처럼 아티팩트만 짧게 잡았다면 로그에서 흔적을 찾을 여유가 있다. 아티팩트와 로그가 같은 날 만료되는 기본 설정이라면 둘 다 함께 사라진다.

같은 날 실행 기록도 조회해 봤는데, cli/cli에는 90일이 훨씬 지난 2025년 하반기 실행까지 API 목록에 아직 나왔다. 공개 저장소 최대가 90일이니 정리 대상인 기록이다. 정리가 10월 1일 하루에 한꺼번에 끝나는 방식은 아닌 것으로 보인다. GitHub는 정리 속도를 따로 밝히지 않았다. 지금 보인다고 남아 있으리라 기대하면 안 된다.

90일 뒤에도 남겨야 한다면

GitHub 사전 공지의 권고는 단순하다. 보관 기간보다 오래 필요한 기록은 미리 내보내거나 따로 보관하라는 것이다. 문제는 내보내기 버튼이 없다는 점이다. API로 직접 떠야 한다. 쓸 만한 재료는 네 가지다.

# 1) 하루치 실행 목록(메타데이터)
gh api "repos/<owner>/<repo>/actions/runs?created=2026-10-08&per_page=100" --paginate \
  --jq '.workflow_runs[]|[.id,.name,.event,.conclusion,.head_sha,.created_at]|@tsv'

# 2) 특정 실행의 로그 묶음(zip)
gh api repos/<owner>/<repo>/actions/runs/<run_id>/logs > run-logs.zip

# 3) 특정 커밋에 붙은 체크 목록
gh api repos/<owner>/<repo>/commits/<sha>/check-runs

# 4) 특정 커밋에 붙은 커밋 상태 목록
gh api repos/<owner>/<repo>/commits/<sha>/statuses

3번과 4번은 따로 불러야 한다. GitHub 문서는 상태 확인을 체크와 커밋 상태 두 종류로 나누고 REST API도 따로 안내한다. 외부 CI나 연동 서비스가 붙인 커밋 상태는 check-runs 결과에 나오지 않는다. 반대로 GitHub Actions는 커밋 상태가 아니라 체크를 만든다.

공개 저장소 cli/cli에 그대로 돌려 봤다. 10월 8일 하루 실행이 131건 나왔다. 그중 한 실행의 로그 zip은 약 129KB, 안에 텍스트 파일 10개가 들어 있었다. 그 실행의 커밋에는 체크 171개가 붙어 있었고, 커밋 상태는 0개였다. Actions만 쓰는 저장소라 그렇다. 로그 다운로드 API는 리다이렉트 URL을 돌려주고, 그 링크는 1분 뒤 만료된다고 문서에 적혀 있다. gh api는 리다이렉트를 따라가 바로 파일을 받으니 신경 쓸 일이 없다.

이걸 주기적으로 돌리는 워크플로 예시다. 매일 전날 실행 목록과 각 실행의 로그를 받아 S3에 올린다. 결과를 다시 아티팩트로 올리면 같은 보관 기간에 묶이니 의미가 없다. 그래서 바깥 저장소로 보낸다. 버킷 이름과 역할 ARN은 각자 바꿔야 하고, AWS 쪽 OIDC 역할 설정은 미리 돼 있어야 한다.

name: archive-actions-history
on:
  schedule:
    - cron: "30 0 * * *"   # 매일 00:30 UTC
  workflow_dispatch:

permissions:
  actions: read
  checks: read
  statuses: read
  contents: read
  id-token: write          # AWS OIDC 로그인용

jobs:
  archive:
    runs-on: ubuntu-latest
    steps:
      - uses: aws-actions/configure-aws-credentials@v6
        with:
          role-to-assume: arn:aws:iam::123456789012:role/ci-archive
          aws-region: ap-northeast-2

      - name: 전날 실행 목록과 로그 내려받기
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          DAY=$(date -u -d "yesterday" +%F)
          mkdir -p "out/$DAY"
          gh api "repos/${{ github.repository }}/actions/runs?created=$DAY&per_page=100" \
            --paginate --jq '.workflow_runs[]' > "out/$DAY/runs.jsonl"
          for id in $(jq -r '.id' "out/$DAY/runs.jsonl"); do
            gh api "repos/${{ github.repository }}/actions/runs/$id/logs" \
              > "out/$DAY/$id-logs.zip" || echo "로그 없음: $id"
          done

      - name: S3에 올리기
        run: aws s3 cp out/ "s3://my-ci-archive/${{ github.repository }}/" --recursive

이 예시는 실행 목록과 로그만 남긴다. 체크와 커밋 상태까지 남기려면 runs.jsonl의 head_sha마다 check-runs와 statuses를 한 번씩 더 부르면 된다. 서드파티 앱이 만든 체크는 check-runs에, 외부 서비스가 붙인 상태는 statuses에 나온다. Actions를 거치지 않는 외부 CI 기록은 실행 목록에 없으니, 그런 커밋은 따로 골라 조회해야 한다.

하나 더 있다. 실행 목록 API는 created 같은 필터를 쓰면 검색 한 번에 최대 1,000건까지만 돌려준다고 문서에 적혀 있다. --paginate를 붙여도 마찬가지다. 하루 실행이 1,000건을 넘는 저장소라면 created 범위를 몇 시간 단위로 쪼개 여러 번 불러야 빠짐없이 받는다.

감사·디버깅 쪽에서 먼저 볼 것

개인적으로는 이번 변경에서 비용보다 증거 쪽이 더 걸린다. 사고는 늦게 발견되는 경우가 많기 때문이다. 2025년 3월 tj-actions/changed-files 공급망 공격이 좋은 예다. GitHub 보안 권고에 따르면 3월 14~15일 사이 악성 코드가 러너 메모리에서 비밀값을 꺼내 워크플로 로그에 찍었고, 영향받은 저장소는 2만 3천 개가 넘었다. 권고가 요구한 조치도 그 기간에 돈 워크플로를 검토하라는 것이었다. 로그가 증거라는 얘기다. 공개 저장소는 보관 상한이 90일이다. 석 달 넘게 지나 알게 된 사고라면 볼 로그가 이미 없을 수 있다. 반대로 공개 로그에 비밀값이 찍혔다면 보관 기간이 짧을수록 노출 기간도 짧아진다. 어느 쪽이 중요한지는 팀마다 다르다.

오래 열어 둔 PR도 한 번 생각해 볼 만하다. GitHub 상태 확인 문서에는 "필수(required)이면서 보관 처리된 체크가 있는 PR을 머지하려면 체크를 다시 돌려야 한다"는 규칙이 있다. 이 문서는 아직 400일 기준으로 적혀 있다. 같은 규칙이 90일 정리에도 그대로 걸리는지는 GitHub가 따로 밝히지 않았다. 다만 체크가 사라진 커밋이라면 석 달 넘게 묵힌 PR에서 체크를 다시 돌려야 하는 상황은 충분히 생길 수 있다.

우리 팀이라면 이 순서로 보겠다.

  1. 현재 값부터 읽는다. 조직과 주요 저장소에 artifact-and-log-retention을 호출해 days와 maximum_allowed_days를 표로 모은다. 우리 저장소처럼 한 번도 손대지 않았다면 90일이다.
  2. 감사 요구 기간과 비교한다. 사내 규정이나 고객 계약에 "빌드·배포 기록 ○개월 보관" 같은 문구가 있는지 본다. 90일보다 길다면 비공개 저장소는 조직·엔터프라이즈 상한 안에서 최대 400일까지 늘릴 수 있다. 단, 늘린 값은 그 뒤에 생기는 기록에만 적용된다. 이미 있는 기록은 원래 일정대로 지워지니, 지금 남겨야 할 것은 앞의 예시처럼 내보내야 한다. 저장 비용이 같이 오른다는 점도 감안한다.
  3. 공개 저장소는 바깥으로 뺀다. 공개 저장소는 90일보다 늘릴 방법이 없다. 남겨야 할 기록이 있다면 위 예시처럼 내보내는 수밖에 없다.
  4. 릴리스 증거는 따로 둔다. 배포 승인 근거로 "이 커밋은 테스트를 통과했다"는 체크를 쓰고 있었다면, 그 체크는 이제 90일 뒤 사라질 수 있다. 릴리스 노트나 태그 시점에 테스트 결과 요약을 함께 남기는 쪽이 오래 간다.
  5. expired 필터를 쓰는 스크립트를 찾는다. 만료 아티팩트가 API에서 빠졌으니 그 조건은 늘 빈 결과다. 정리 스크립트라면 크게 문제는 없지만, 보고서용이라면 숫자가 달라진다.

결국 바뀐 건 "실행 기록은 오래 남는다"는 오래된 전제다. 이제는 아티팩트와 같은 시계를 따른다. 기본값을 그대로 두는 것도 하나의 선택이다. 다만 그 선택이 90일이라는 걸 팀이 알고 있어야 한다.

이 글의 일부 내용은 GitHub Docs(CC BY 4.0)를 바탕으로 정리했다.

출처 github.blog/…/2026-10-01-actions-retention-now-covers-checks-runs-and-statusesgithub.blog/…/2026-09-24-expired-github-actions-artifacts-no-longer-shown-in-ui-and-apigithub.blog/…/2026-08-27-actions-retention-will-cover-checks-workflow-runs-and-statusesdocs.github.com/…/managing-github-actions-settings-for-a-repositorydocs.github.com/…/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organizationdocs.github.com/…/permissionsdocs.github.com/…/store-and-share-datadocs.github.com/…/workflow-runsdocs.github.com/…/status-checksgithub.com/…/upload-artifactgithub.com/…/GHSA-mrrh-fwg8-r2c3github.com/…/configure-aws-credentials

내용이 틀렸나요? 정정 요청

관련 글