⚙️ GitHub Actions 생성기
워크플로 타입과 트리거를 선택하면 .github/workflows/ 에 바로 사용할 YAML 생성. Node.js · Python · PHP · Go · Docker · Pages · Vercel · Netlify · Release · Cron · Lint 지원.
🔒 개인정보 보호
- ・YAML 생성은 브라우저 내에서 완료됩니다
- ・입력 데이터는 서버로 전송되지 않습니다
- ・저장 로그 · 데이터베이스 없음
- ・가입 · 로그인 · 결제 불필요
(위의 YAML 생성 버튼을 누르세요)
📖 자주 걸리는 지점
워크플로 종류 (Node / Python / PHP / Go / Docker / Pages / Vercel / Netlify / Release / Cron / Lint) 와 트리거를 고르면 .github/workflows/ 에 그대로 둘 수 있는 YAML 을 생성합니다. 처리는 브라우저 안에서 끝나며 브랜치명이나 버전은 전송되지 않습니다. 생성되는 것은 구문적으로 올바른 워크플로이지 당신의 프로젝트에서 통과하는 워크플로가 아닙니다 — 의존성 설치도 테스트 실행도 실제 명령은 리포지터리마다 다릅니다. 그리고 CI 에서 정말 아픈 것은 YAML 서식이 아니라 「권한」과 「시간」입니다. 아래가 그 이야기입니다.
| 사례 | 무슨 일이 일어나는가 | 어떻게 하면 되는가 |
|---|---|---|
| fork 에서 온 PR 에는 secrets 가 넘어가지 않는다 | pull_request 로 트리거된 워크플로는 fork 에서 온 PR 인 경우 GITHUB_TOKEN 이 읽기 전용이 되고 리포지터리의 secrets 도 넘어가지 않습니다. 이것은 의도된 안전장치입니다 — 그렇지 않으면 누구나 PR 을 보내는 것만으로 당신의 비밀을 출력하게 만들 수 있습니다. 그러나 결과적으로 배포나 커버리지 전송을 포함한 워크플로는 fork 의 PR 에서 반드시 실패합니다. 여기서 위험한 우회책이 알려져 있습니다: pull_request_target 으로 바꾸면 secrets 가 넘어갑니다만 이 트리거는 베이스 브랜치의 권한으로 동작하므로 거기서 PR 의 코드를 actions/checkout 해서 실행하면 외부 사람이 쓴 코드가 당신의 secrets 를 들고 돌아갑니다 — 사실상 리포지터리의 탈취입니다. |
워크플로를 둘로 나누세요. 테스트와 lint 는 pull_request 에서 (secrets 불필요), 배포는 push 의 main 브랜치나 release 에서 실행합니다. 이렇게 하면 fork 의 PR 도 정상적으로 CI 를 통과하고 secrets 가 밖으로 나갈 경로도 존재하지 않습니다. pull_request_target 을 쓴다면 PR 의 코드를 절대 checkout 하지 마세요 — 라벨 붙이기나 댓글 작성처럼 코드를 실행하지 않는 용도로 한정합니다. 아울러 모든 워크플로의 맨 앞에 permissions: 를 명시하세요 — permissions: {contents: read} 라고 쓰는 것만으로 그 워크플로의 GITHUB_TOKEN 에서 쓰기 권한이 사라집니다. 필요한 권한만을 잡 단위로 더해 나가는 것이 올바른 순서입니다. |
| 서드파티 action 을 태그로 참조한다 | uses: some/action@v1 의 v1 은 브랜치나 태그, 즉 움직일 수 있는 참조입니다 — action 의 작성자 (또는 그 계정을 빼앗은 사람) 가 내용을 바꿔치기하면 당신의 CI 는 다음 실행에서 다른 코드를 돌립니다. 그 코드는 GITHUB_TOKEN 과 그 잡에 넘긴 secrets 에 접근할 수 있습니다. 이것은 이론상의 이야기가 아니라 인기 있는 action 이 침해되어 비밀을 수집한 사례가 실제로 일어났습니다. 공식 (actions/*) 은 그렇다 쳐도, star 가 적은 편리한 action 을 무심코 @main 으로 참조하는 것은 남에게 당신의 리포지터리에 대한 쓰기 권한을 건네는 것과 다르지 않습니다. |
서드파티 action 은 commit SHA 로 고정하세요 — uses: some/action@a1b2c3d4... 형태입니다. SHA 는 고쳐 쓸 수 없으므로 다음에 무엇이 도는지가 확정됩니다. 갱신은 Dependabot 에 맡깁니다 (.github/dependabot.yml 에 package-ecosystem: "github-actions" 를 추가하면 SHA 갱신 PR 을 자동으로 만들어 줍니다) — 고정과 갱신은 양립합니다. 애초에 action 을 줄이는 것도 유효합니다: 파일을 하나 복사할 뿐인 action 이라면 run: 에 cp 라고 쓰면 의존이 하나 사라집니다. 그리고 secrets 는 잡 단위로 최소한만 넘기세요 — 워크플로 전체에 환경 변수로 두면 그 안의 모든 action 에서 읽을 수 있습니다. |
| cron 은 시각대로 돌지 않고 60 일에 멈춘다 | schedule 트리거에는 서식 이외에 세 가지 함정이 있습니다. 시각은 반드시 UTC이지 당신의 타임존이 아닙니다 — 0 3 * * * 은 「UTC 의 오전 3 시」입니다. 실행은 정시가 아닙니다 — 혼잡할 때는 수 분에서 수십 분 늦어지고 부하가 높을 때는 실행 자체가 건너뛰어질 수 있습니다. 매시 0 분이 가장 붐비므로 딱 떨어지는 시각을 피하는 것만으로도 안정됩니다. 그리고 가장 놀라는 것이 세 번째입니다: 60 일간 커밋이 없는 리포지터리에서는 스케줄된 워크플로가 자동으로 무효화됩니다 — 메일은 오지만 놓치면 「알고 보니 몇 달째 안 돌고 있었다」는 일이 예사로 일어납니다. |
cron 식은 UTC 로 쓰고 노리는 시각에서 몇 분 어긋나게 하세요 — 0 3 * * * 가 아니라 17 3 * * * 처럼. 그리고 반드시 workflow_dispatch 를 함께 적으세요 — 수동으로 실행할 수 있는 것만으로 동작 확인도 재실행도 가능해집니다 (스케줄이 올 때까지 기다리지 않으면 시험할 수 없는 상태는 그 자체가 사고의 근원입니다). 무효화에 대한 대책은 「알아챌 수 있게」 하는 것입니다: 잡의 마지막에 성공을 외부로 통지하게 하고 통지가 끊긴 것을 알아챌 수 있는 구조를 만드세요 — 실패 통지만으로는 실행되지 않게 된 것을 검출할 수 없습니다. 정확한 시각이나 높은 신뢰성이 필요하다면 GitHub Actions 의 cron 이 아니라 전용 스케줄러를 쓰세요. |
캐시는 락 파일과 함께 키를 만드세요. actions/setup-node 의 cache: npm 이나 actions/cache 의 key 에 락 파일의 해시를 포함하지 않으면 의존을 갱신해도 예전 캐시가 계속 쓰입니다 — 로컬에서는 고쳐졌는데 CI 만 오래된 의존으로 실패하는 원인 알기 어려운 상태가 됩니다. hashFiles('**/package-lock.json') 을 키에 넣으세요. 그리고 캐시는 브랜치를 넘나들며 공유됩니다 — 망가진 캐시가 다른 브랜치로 전염되므로 의심스러울 때는 이름을 바꿔 다시 만드는 편이 빠릅니다. 또 하나, 로그에 비밀을 내보내지 않도록 주의하세요: GitHub 은 등록된 secrets 를 자동으로 마스킹하지만 가공한 값 (Base64 화한, JSON 에 심은, 일부만 잘라 낸) 은 마스킹되지 않습니다. set -x 나 디버그 출력을 켜면 커맨드라인째 기록됩니다 — 그리고 Actions 의 로그는 퍼블릭 리포지터리라면 누구나 읽을 수 있습니다.
📖 사용법
-
1
워크플로 타입 선택Node.js · Python · PHP · Go · Docker · Pages 등에서 선택.
-
2
트리거와 브랜치 설정push · pull_request · schedule · 수동 실행 활성화.
-
3
YAML 생성 후 커밋YAML 생성을 누르고 .github/workflows/ 에 저장 후 푸시.
❓ 자주 묻는 질문
시크릿은 어떻게 설정합니까?
어떤 actions 버전이 들어갑니까?
Self-hosted runner 도 됩니까?
🐛 이 도구에서 문제가 발생했나요?
무료 · 가입 불필요. 재현 절차만이라도 도움이 됩니다. 보고는 운영자에게 직접 전달되어 개선에 사용됩니다.
보고 감사합니다!
운영자에게 전달되었습니다. 개선에 사용됩니다.