CMS OAuth Operating Model Gate - 2026-05-30

CMS OAuth Operating Model Gate - 2026-05-30

CMS OAuth Operating Model Gate - 2026-05-30

이 artifact는 /admin/을 다시 열기 전 필요한 운영모델 결정을 고정한다. 현재 안전 주장은 “CMS가 안전하게 작동한다"가 아니라 “운영모델 충돌이 해결되기 전까지 CMS를 닫아두고 있다"이다.

Claim

현재 블로그 source registry는 svy04/svy04.github.io를 private source repo로 기록한다. 반면 Worker source는 GitHub OAuth에 public_repo를 요청한다. GitHub의 scope model에서 public_repo는 public repository 범위에 제한되고, Decap private-repo/open-authoring 흐름은 repo scope를 요구할 수 있다. 따라서 public_repo smoke만으로는 현재 private source repo에 CMS write가 가능한지 증명할 수 없다.

Verified Originals

sourceclassoperating grammar extractedcannot support
GitHub OAuth scopesofficial platform documentationrepo는 public/private repository access를 포함하고, public_repo는 public repository로 제한된다. GitHub Apps는 scope보다 fine-grained permissions를 제공한다.public_repo가 private repo write를 증명한다는 주장.
GitHub OAuth authorization flowofficial platform documentationauthorization code, state, token exchange, granted scope, identity revalidation을 별도 증거로 봐야 한다.local bundle check가 live OAuth proof라는 주장.
Decap CMS Backends Overviewofficial product documentationDecap GitHub backend는 configured base_urlauth_endpoint를 통해 /auth/callback OAuth broker를 사용한다.Worker deploy 상태나 repo write 가능성.
Decap CMS GitHub backendofficial product documentationCMS config의 repo가 GitHub backend target repository를 결정한다.private source repo에 public_repo token으로 publish할 수 있다는 보장.
Decap CMS Open Authoringofficial product documentationprivate GitHub repo open-authoring에는 auth_scope: repo 같은 private-repo-capable boundary가 필요하다.broad repo scope가 모든 상황에서 안전하다는 주장.
MDN Window.postMessageprimary web platform documentationtoken/error handoff는 exact target origin으로 보내야 한다.wildcard origin이 안전하다는 주장.
MDN CORS Guideprimary web platform documentationcredential/token surface에서는 wildcard 대신 explicit origin과 Vary: Origin이 필요하다.CORS allowlist가 authorization proof라는 주장.
Cloudflare Workers Secretsofficial platform documentationOAuth client secret, allowed login, deploy token은 Worker secrets/runtime state로 증명해야 한다.source file만으로 secret deployment가 끝났다는 주장.

Ontology Impact Map

objectimpact
SourceReporegistry truth is private, so public-repo-only OAuth cannot be treated as write proof.
CmsWorkerpublic_repo is a public-repo-model smoke target, not a private source restore proof.
CmsAdmin/admin/ must remain locked while the operating model is unresolved.
ProofArtifactWorker safety and CMS operation proof are separate artifacts.
SurfaceRegistrycms-worker, cms-admin, and blog-source must carry the private/public scope boundary.
RestoreGaterestore requires a selected model plus live Worker and CMS operation evidence.

Decision

Do not restore /admin/ while all three are true:

  1. The source repo is recorded as private.
  2. The Worker OAuth request is still the public_repo model.
  3. The CMS has not selected and proven a private-repo-compatible operating model.

The current valid public posture is locked admin plus explicit known gap.

Allowed Paths

pathwhen it is validproof required before restore
Public CMS target repoUse this only if the content target can safely be public.Repo visibility proof, public_repo live Worker smoke, Decap login/edit/media commit proof, unauthorized denial proof.
Private source repo with repo scopeUse this if Decap must write directly to the private source repo.Risk note for broad repo scope, live granted-scope evidence, allowed-login revalidation, disposable commit proof, token revocation note.
GitHub App modelUse this if repository-specific permissions are preferred over classic OAuth scopes.App permission manifest, installation boundary, token exchange proof, repository-only write proof, fallback/rollback note.
Keep CMS lockedUse this while the edit surface is not operationally needed.Live /admin/ lock proof and disabled /admin/config.yml proof.

Commands / Redlines

commandredline
Treat public_repo as a public-repo-model scope check.Do not say it proves write access to the current private source repo.
Keep /admin/ locked until an allowed path is selected and proven.Do not restore Decap because the Worker source looks safer locally.
Revalidate GitHub login after token exchange before token handoff.Do not treat successful OAuth login as authorization by itself.
Use exact CMS_ORIGIN for postMessage token/error handoff.Do not use wildcard postMessage("*") for token-bearing messages.
Use explicit CORS origins and Vary: Origin.Do not describe CORS as the authorization layer.
Store secrets in Cloudflare Worker secrets/runtime configuration.Do not put client secrets or allowed-login secrets in source or proof artifacts.

Output Contract

Any future CMS restore proof must include:

fieldrequired evidence
Selected operating modelpublic CMS target repo, private repo with repo scope, GitHub App model, or locked CMS.
Repo visibility proofgh repo view output or equivalent dated registry proof.
Worker deploy proofnpm --prefix worker run deploy success with secrets omitted.
Worker smoke proofscripts/check-worker-oauth.ps1 output plus granted scope evidence.
CMS operation proofallowed login, disposable draft, media upload, commit on target branch, publication or draft-exclusion result, cleanup.
Authorization proofallowed-login revalidation and unauthorized-account denial or documented simulation.
Claim boundarywhat this proof still does not prove.

Local Gate

scripts/check-site-surfaces.ps1 now emits a known gap when the registry says the source repo is private while Worker source still requests public_repo. The stricter restore command is intentionally expected to fail until the model is resolved:

npm run check:cms-restore-ready

Validation

Expected verification for this artifact:

  • npm run check:quality
  • npm run check:surface-contracts
  • npm run check:surfaces
  • npm run check
  • npm run check:routes
  • npm run check:live

Claim Boundary

Allowed public claim:

  • The blog now has a local proof gate that prevents public_repo Worker evidence from being mistaken for private source repo CMS restore readiness.

Forbidden public claims:

  • The CMS is operational.
  • The live Worker is hardened.
  • public_repo is enough for private repo CMS writes.
  • repo scope is automatically safe just because it would work.

Memory Update

Keep the private source repo/public-repo OAuth mismatch as a standing restore blocker. The next agent should not reopen /admin/ until the operating model is selected, documented, deployed, and proven with a real disposable CMS edit/media/commit flow.