Skip to content

ci(S15P11A705-154): runtime Secret 봉인 계약을 정렬한다 - #39

Merged
colosair merged 3 commits into
mainfrom
feat/S15P11A705-154-runtime-secret-contract
Jul 30, 2026
Merged

ci(S15P11A705-154): runtime Secret 봉인 계약을 정렬한다#39
colosair merged 3 commits into
mainfrom
feat/S15P11A705-154-runtime-secret-contract

Conversation

@tpals0409

@tpals0409 tpals0409 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

요약

  • 런타임 Secret 봉인 진입점을 canonical .github/workflows/seal-runtime-secrets.yml 하나로 정렬합니다.
  • pinlog-secrets-dev Environment와 immutable Infra PR action 사이의 최소 계약만 유지합니다.
  • stale artifact/repository_dispatch 경로와 AI 레포의 runtime placeholder 계약 복제를 제거합니다.

Jira (필수)

  • 키 또는 URL: S15P11A705-154
  • 완료 조건: 수동 전용 workflow, 최소 권한, exact Environment/keys, SHA 고정 checkout/action, 일반 CI Secret 격리를 static contract test로 고정

변경 사항

  • legacy seal-ai-secrets.yml을 canonical seal-runtime-secrets.yml로 교체
  • contents: read, id-token: write, pinlog-secrets-dev 및 exact 4-key Environment 전달 계약 적용
  • Infra action을 84458bf35e341b79e91ce21a3667e9d3f7454068에 고정하고 policy=ai-dev, revision=github.sha만 전달
  • runtime Secret contract test와 운영 문서/WORKLOG/P45 경로 갱신

테스트 / 검증

RED

  • .venv/bin/python -m pytest -q tests/test_runtime_secret_contract.py
  • canonical workflow가 없어서 4 failed, 일반 CI 격리 1 passed 확인

GREEN

  • .venv/bin/python -m pytest -q tests/test_runtime_secret_contract.py
  • 5 passed

Regression

  • .venv/bin/ruff check . — passed
  • .venv/bin/python -m compileall -q app tools — passed
  • .venv/bin/python -m pytest -q tests/test_ci_image_publish_contract.py tests/test_runtime_secret_contract.py — 11 passed
  • Python 3.12에서 unit + CI/runtime contract subset — 32 passed
  • 전체 pytest — 로컬 Docker daemon 부재로 Testcontainers 42건 setup 불가; Draft PR의 ai-ci / check에서 검증
  • DB 계약 변경 없음

리뷰 포인트

  1. workflow 권한, Environment 및 exact Secret key set이 Infra action 계약과 일치하는지
  2. checkout/action SHA 고정과 revision=${{ github.sha }}가 source provenance 경계를 충족하는지
  3. legacy dispatch/artifact 경로와 7-key placeholder source contract가 완전히 제거됐는지

리스크

  • 계약: Infra action의 고정 SHA와 ai-dev policy에 의존합니다. 원본 action의 inputs가 policy, revision임을 GitHub API로 확인했습니다.
  • 데이터·개인정보: Secret 값은 조회·출력·파일 저장하지 않았습니다. 이름만 workflow 계약에 존재합니다.
  • 운영·배포: Environment Secret/보호 설정과 live workload는 변경하지 않습니다. 실제 실행은 보호된 수동 dispatch에서만 가능합니다.

범위 밖 / 후속

  • 이번 PR에서 다루지 않는 항목: live Secret 등록/회전, GitHub Environment 설정, Infra PR 병합, 클러스터 rollout
  • 후속 Jira: 없음

영구 문서

  • docs/implements/2026-07-29-sealed-secret-handoff.md
  • docs/proposals/P45-public-config-in-code.md
  • docs/WORKLOG.md

관련 GitHub Issue (선택)

  • 없음

@tpals0409
tpals0409 marked this pull request as ready for review July 29, 2026 10:59
@tpals0409
tpals0409 requested a review from colosair July 29, 2026 11:03

@colosair colosair left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

승인합니다. ai#34가 세운 안전장치가 전부 보존됐고 몇 가지는 더 강해졌습니다. action 내부(84458bf)를 직접 읽고 확인했습니다.

ai#34에서 우리가 세운 것 action
kubeseal --raw로 평문 YAML 미생성 :256 --raw --scope strict --namespace --name --cert
인증서 SHA-256 지문 대조 :383~385 openssl 대조, 불일치 시 예외
산출물 평문 미포함 검사 :237 plaintext material is forbidden
scope strict :157 secretType != Opaque or scope != strict 거부

여기에 manifest 구조 정확 일치 검증(:242~246)과 cert-fingerprint provenance annotation(:198)이 더해졌습니다. kubeseal 설치도 릴리스 체크섬 파일이 아니라 해시를 직접 고정하는 방식이라 저희 것보다 낫습니다.

저희 workflow 223줄을 30줄로 줄이면서 잃은 것이 없습니다. 같은 판단을 공용 자산으로 옮긴 것이라 이견 없습니다.

키 집합 — (B)안 채택 확인

GMS_API_KEY·GMS_BASE_URL·INTERNAL_SHARED_SECRET 셋으로 좁히고 PINLOG_INFRA_SECRET_PR_TOKEN을 더한 구성으로 이해했습니다. PINLOG_EMBEDDING_* 넷을 뺀 것이 맞습니다ai#36(463cad5)로 app/core/config.py에 기본값이 들어가 이미지에 포함되므로 주입할 것이 없습니다.

어제 저희가 인프라 계약을 먼저 깨고 나중에 알린 순서가 됐는데, 그쪽으로 맞춰 주셔서 감사합니다.

하나만 — implements 기록 75줄 삭제

docs/implements/2026-07-29-sealed-secret-handoff.md에서 설계 근거가 지워졌습니다.

"봉인 대상 7종" 표와 EMBEDDING 넷의 성격 분류
kubeseal --raw 를 택한 이유 (kubectl --dry-run 경로의 중간 평문 YAML)
heredoc 을 쓸 수 없었던 이유
봉인 시점에 앱 기동 검사를 미리 도는 근거

현행화가 필요하다는 판단은 맞습니다 — 그 workflow는 이제 없습니다. 다만 docs/implements/는 보존 구역이고, 이 판단들이 그대로 action에 들어가 있어 지우면 왜 그렇게 만들었는지가 사라집니다. 특히 --raw 선택 근거는 action의 :256을 설명하는 유일한 기록입니다.

이 PR을 막지 않겠습니다. 배포가 걸려 있고 기능과 무관한 지점입니다. 저희가 후속 PR로 상태 노트 형태로 복원하겠습니다 — 원문을 되살리되 머리말에 *"이 구현은 S15P11A705-154에서 Infra 공용 action으로 대체됐다. 아래 판단은 그 action에 반영돼 있다"*를 붙이는 방식입니다. 그쪽에서 처리하실 생각이면 알려 주십시오.

확인 부탁드릴 것

PINLOG_INFRA_SECRET_PR_TOKEN의 권한 범위를 알려 주시면 등록하겠습니다. contents:write + pull_requests:write(fine-grained, Team-PinLog/infra 한정)면 충분한지, 만료를 어떻게 두실지입니다. 어제 여쭀던 그 토큰이 이 자리에 들어가는 것으로 이해했습니다.

pinlog-secrets-dev Environment의 보호 규칙(승인자·브랜치 제한)도 설정해 두신 것이 있으면 알려 주십시오 — 저희 쪽에서 workflow_dispatch를 누를 때 무엇이 요구되는지 알아야 합니다.

@tpals0409

Copy link
Copy Markdown
Contributor Author

상세 검토와 승인 감사합니다. 두 가지로 답변드립니다.

1. docs/implements 설계 근거

AI 담당 후속 PR에서 상태 노트 형태로 복원해 주세요. 제안해 주신 대로 문서 상단에 “이 구현은 S15P11A705-154에서 Infra 공용 action으로 대체됐으며 아래 판단은 해당 action에 반영돼 있다”는 현재 상태를 명시하고, --raw 선택·중간 평문 YAML 회피·strict scope·기동 검증 근거를 보존하는 방향이 적절합니다. 이 PR을 막는 항목으로 보지 않으며 Infra가 AI의 보존 문서를 다시 소유하지 않겠습니다.

2. PINLOG_INFRA_SECRET_PR_TOKEN

권장 최소 권한은 fine-grained PAT 기준 다음과 같습니다.

  • Repository access: Team-PinLog/infra 한 저장소만
  • Contents: Read and write
  • Pull requests: Read and write
  • Metadata: Read(기본)
  • Actions·Secrets·Administration 권한: 불필요
  • 만료: 90일 권장, 만료 전 회전

토큰 값은 ai 저장소의 pinlog-secrets-dev Environment에만 PINLOG_INFRA_SECRET_PR_TOKEN 이름으로 등록하고, 채팅·PR·Jira·workflow 로그에는 공유하지 않습니다.

현재 GitHub API read-back 결과 ai 저장소에는 pinlog-secrets-dev Environment가 아직 존재하지 않아 보호 규칙도 설정되어 있지 않습니다. 따라서 현재 구성된 승인자나 branch 제한은 없습니다. Environment 생성 시에는 최소한 **selected branch = main**으로 제한하는 것을 권장합니다. required reviewer를 둘지는 팀 승인 흐름 결정이 필요하므로 아직 설정됐다고 가정하지 않겠습니다.

등록할 정확한 이름은 다음 4개입니다.

  • GMS_API_KEY
  • GMS_BASE_URL
  • INTERNAL_SHARED_SECRET
  • PINLOG_INFRA_SECRET_PR_TOKEN

Environment 생성·4개 이름 등록·branch policy 설정이 완료된 뒤에만 main의 수동 workflow_dispatch를 실행하면 됩니다. 현재 단계에서는 값이나 실행 성공을 확인한 것으로 간주하지 않습니다.

@colosair

Copy link
Copy Markdown
Member

등록을 마치면서 관측한 사실을 남깁니다. 처분은 인프라 판단에 맡깁니다.

AI 쪽 완료 사항

  • pinlog-secrets-dev Environment에 앱 Secret 3개(GMS_API_KEY·GMS_BASE_URL·INTERNAL_SHARED_SECRET)를 등록했습니다.
  • 같은 Environment에 배포 브랜치 제한을 main 하나로 걸었습니다. workflow_dispatch는 임의 브랜치에서도 실행할 수 있어, 제한이 없으면 그 브랜치의 코드로 Secret이 흐릅니다. PINLOG_INFRA_SECRET_PR_TOKEN 등록에는 영향이 없습니다.
  • 봉인 대상을 3키로 한다는 안내와, PR 토큰은 김세민이 직접 발급·등록한다는 회신을 그렇게 이해했습니다. 구두로 정해진 부분이라 기록으로 남깁니다.

이 PR 의 계약과 infra 검증기가 어긋나는 지점

이 PR 의 workflow 와 contract test 는 Environment Secret 이름 4개(위 3개 + PR 토큰)를 고정하고, 실제 봉인 대상은 3개입니다.

infra 442a64f 기준으로 관측한 것입니다.

위치 내용
tools/validate_ai_dev_prerequisites.pyREQUIRED_RUNTIME_KEYS 7키 — 위 3개 + PINLOG_EMBEDDING_MODEL·DIMENSION·DISTANCE·PROFILE
같은 파일 validate_secret_keys missingunexpected 를 모두 오류로 반환
docs/ai-dev-prerequisites.md 3절 "exact 8-key schema 가 아니면 실패한다" (owner 7키 + DB 1키)
같은 문서 3절 owner SealedSecret 을 workflow run 30431247125ai-owner-secrets-sealed artifact 에서 반영

EMBEDDING 넷은 #36 과 P45 에서 app/core/config.py 기본값으로 옮겨 주입 대상에서 뺐고, 이 PR 은 artifact·repository_dispatch 경로를 제거했습니다.

Flyway 파일 집합

docs/ai-dev-prerequisites.md 2절이 여섯 파일(V1·V2·V3·V100·V101·V102)만 있고 다른 V*__*.sql 이 없을 것을 조건으로 둡니다. 현재 back dev(c75151c)에는 여덟 개가 있습니다.

V1__create_schemas · V2__member · V3__core_domain
V4__social_account · V5__collection_published_at_invariant
V100__ai_tables · V101__ai_indexes · V102__feed_event

V4·V5 는 백엔드 소관이라 저희가 판단할 사안이 아니고 관측만 전달합니다.

질문

위 두 문서와 검증기가 3키 기준으로 갱신될 예정인지만 알려주시면 됩니다. 등록을 마친 뒤에도 workload gate 가 열리지 않는 이유를 모르는 상태를 피하려는 것입니다.

@colosair
colosair merged commit b171f8f into main Jul 30, 2026
2 checks passed
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.

2 participants