Documentation
¶
Overview ¶
Package github 은 GitHub REST API 로 리포지토리를 프로비저닝한다.
GitLab 어댑터와 두 가지가 근본적으로 다르다.
하나, 네임스페이스를 만들 수 없다. GitHub Organization 은 API 로 생성되지 않으므로 EnsureGroup 은 "확인"만 한다 — 없으면 사람이 먼저 만들어야 한다.
둘, 토큰을 발급할 수 없다. GitLab 은 프로젝트 범위 토큰 API 가 있지만 GitHub 에는 리포 단위 토큰이 없다. 대신 워크플로가 내장 GITHUB_TOKEN 을 쓰고, 클러스터 쪽(Argo CD·kubelet)은 스택에 등록된 PAT 를 재사용한다.
Index ¶
- Constants
- Variables
- func TokenSecretPath(env, orgID string) string
- type Client
- func (c *Client) BaseURL() string
- func (c *Client) CommitFiles(ctx context.Context, projectID string, spec port.CommitSpec) error
- func (c *Client) CreateProjectAccessToken(_ context.Context, _ string, _ port.AccessTokenSpec) (string, error)
- func (c *Client) DeleteImageRepository(ctx context.Context, target *port.ImageTarget) error
- func (c *Client) DeleteProject(ctx context.Context, projectID string) error
- func (c *Client) EnsureGroup(ctx context.Context, spec port.GroupSpec) (*port.SCMGroup, error)
- func (c *Client) EnsureProject(ctx context.Context, spec port.ProjectSpec) (*port.SCMProject, error)
- func (c *Client) Ping(ctx context.Context) error
- func (c *Client) SetProjectVariable(ctx context.Context, projectID string, v port.ProjectVariable) error
- func (c *Client) WithHTTPClient(h *http.Client) *Client
- type SecretStore
- type TokenIssuer
Constants ¶
const ( // DefaultAPIBaseURL 는 github.com 의 API 주소다. // GitHub Enterprise Server 는 https://{host}/api/v3 형태를 쓴다. DefaultAPIBaseURL = "https://api.github.com" // GHCRHost 는 GitHub Container Registry 의 호스트다. GHCRHost = "ghcr.io" )
const SecretProvider = "openbao"
SecretProvider 는 토큰을 보관하는 시크릿 백엔드다.
Variables ¶
var ErrAccessTokenUnsupported = errors.New(
"github 은 리포 범위 액세스 토큰 발급을 지원하지 않습니다")
ErrAccessTokenUnsupported 는 GitHub 에 리포 범위 토큰 발급 API 가 없음을 알린다.
GitLab 의 Project Access Token 에 대응하는 것이 GitHub 에는 없다. 워크플로는 내장 GITHUB_TOKEN 을 쓰고, 클러스터 쪽 인증은 스택에 등록된 PAT 를 재사용한다. 호출자가 이 오류를 보고 그 경로로 갈라져야 한다.
Functions ¶
func TokenSecretPath ¶
TokenSecretPath 는 PAT 의 시크릿 경로다.
값을 기록하는 쪽은 stack 모듈(설치 마지막의 토큰 소스 등록)이다. 경로를 양쪽에 따로 적으면 한쪽만 바뀌어도 컴파일은 통과하고 런타임에 "등록된 토큰이 없다" 로만 드러나므로 공유 규약을 그대로 쓴다.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client 는 port.SCMProvisioner 와 port.PipelineConfigurator 의 GitHub 구현체다.
func NewClient ¶
NewClient 는 GitHub REST 클라이언트를 만든다.
baseURL 이 비면 github.com 을 쓴다. token 은 repo·workflow 스코프를 가진 PAT 다.
func (*Client) CommitFiles ¶
CommitFiles 는 여러 파일을 한 커밋으로 올린다(upsert).
Contents API 를 파일마다 부르면 커밋이 파일 수만큼 생기고, Argo CD 가 그 중간 상태를 하나씩 동기화해 배포가 여러 번 일어난다. Git Data API 로 트리 하나를 만들어 커밋 하나로 밀어야 한다.
func (*Client) CreateProjectAccessToken ¶
func (c *Client) CreateProjectAccessToken( _ context.Context, _ string, _ port.AccessTokenSpec, ) (string, error)
CreateProjectAccessToken 은 GitHub 에서 지원되지 않는다.
조용히 빈 문자열을 돌려주면 호출자가 자격증명 없이 Argo CD 를 구성해 동기화가 "authentication required" 로 실패한다. 명시적으로 알린다.
func (*Client) DeleteImageRepository ¶
DeleteImageRepository 는 GHCR 패키지를 지운다.
리포지토리와 패키지는 GitHub 에서 별개 리소스다 — 리포를 지워도 패키지는 남는다. 경로도 다르다: 개인 계정은 /user/packages, 조직은 /orgs/{org}/packages.
PAT 에 delete:packages 스코프가 필요하다.
func (*Client) DeleteProject ¶
DeleteProject 는 리포지토리를 지운다.
이미 없으면 성공으로 본다 — 삭제의 목표는 "없는 상태" 이고, 404 를 오류로 올리면 앞선 시도가 절반쯤 성공한 뒤 재시도할 때 영영 끝나지 않는다.
PAT 에 delete_repo 스코프가 없으면 403 이 온다. 이 경우 GitHub 은 권한 부족을 알려주므로 오류를 그대로 올려 사용자가 스코프를 고칠 수 있게 한다.
func (*Client) EnsureGroup ¶
EnsureGroup 은 소유자(Organization 또는 사용자 계정)가 존재하는지 확인한다.
만들지 않는다 — GitHub Organization 은 API 로 생성할 수 없다. 없는 소유자를 조용히 넘기면 리포 생성이 엉뚱한 네임스페이스로 흘러가므로 여기서 끊는다.
func (*Client) EnsureProject ¶
func (c *Client) EnsureProject(ctx context.Context, spec port.ProjectSpec) (*port.SCMProject, error)
EnsureProject 는 리포지토리를 조회하고 없으면 만든다.
func (*Client) Ping ¶
Ping 은 현재 토큰이 실제로 인증되는지 확인한다.
보관된 PAT 는 사용자가 폐기하거나 만료될 수 있다. 쓰기 전에 확인하지 않으면 이후 모든 호출이 401 로 죽고 원인이 프로비저닝 실패처럼 보인다.
func (*Client) SetProjectVariable ¶
func (c *Client) SetProjectVariable(ctx context.Context, projectID string, v port.ProjectVariable) error
SetProjectVariable 은 Actions 시크릿을 등록하거나 이미 있으면 갱신한다.
GitHub 은 평문 시크릿을 받지 않는다. 리포의 공개키를 받아 libsodium sealed box 로 암호화한 값만 올릴 수 있다 — 평문으로 PUT 하면 400 이 난다. PUT 자체가 upsert 라 GitLab 처럼 POST→PUT 폴백이 필요 없다.
type SecretStore ¶
type SecretStore interface {
GetTokenForStack(ctx context.Context, provider, stackID, path string) (string, error)
}
SecretStore 는 토큰 조회에 필요한 최소 동작만 노출한다.
다른 모듈의 동일 타입을 재사용하지 않는다 — 모듈 간 직접 import 를 피하기 위해 CI/CD 컨텍스트가 자기 계약을 소유한다.
type TokenIssuer ¶
type TokenIssuer struct {
// contains filtered or unexported fields
}
TokenIssuer 는 보관된 GitHub PAT 를 돌려준다.
이름은 GitLab 쪽과 맞췄지만 실제로 발급하지는 않는다 — GitHub 은 SaaS 라 우리가 토큰을 만들 수 없다. 사용자가 등록한 PAT 를 읽는 것이 전부이며, 그래서 Force 재발급도 의미가 없다(만료·폐기되면 사람이 다시 등록해야 한다).
func NewTokenIssuer ¶
func NewTokenIssuer(secrets SecretStore) *TokenIssuer
NewTokenIssuer 는 TokenIssuer 를 만든다.
func (*TokenIssuer) EnsureToken ¶
func (t *TokenIssuer) EnsureToken(ctx context.Context, spec port.SCMTokenSpec) (string, error)
EnsureToken 은 보관된 PAT 를 돌려준다.
없으면 새로 만들지 않고 실패한다 — 조용히 빈 토큰으로 진행하면 리포 생성이 401 로 죽고, 오류가 프로비저닝 버그처럼 보여 원인을 찾기 어렵다.