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
| source | class | operating grammar extracted | cannot support |
|---|---|---|---|
| GitHub OAuth scopes | official platform documentation | repo는 public/private repository access를 포함하고, public_repo는 public repository로 제한된다. GitHub Apps는 scope보다 fine-grained permissions를 제공한다. | public_repo가 private repo write를 증명한다는 주장. |
| GitHub OAuth authorization flow | official platform documentation | authorization code, state, token exchange, granted scope, identity revalidation을 별도 증거로 봐야 한다. | local bundle check가 live OAuth proof라는 주장. |
| Decap CMS Backends Overview | official product documentation | Decap GitHub backend는 configured base_url과 auth_endpoint를 통해 /auth와 /callback OAuth broker를 사용한다. | Worker deploy 상태나 repo write 가능성. |
| Decap CMS GitHub backend | official product documentation | CMS config의 repo가 GitHub backend target repository를 결정한다. | private source repo에 public_repo token으로 publish할 수 있다는 보장. |
| Decap CMS Open Authoring | official product documentation | private GitHub repo open-authoring에는 auth_scope: repo 같은 private-repo-capable boundary가 필요하다. | broad repo scope가 모든 상황에서 안전하다는 주장. |
| MDN Window.postMessage | primary web platform documentation | token/error handoff는 exact target origin으로 보내야 한다. | wildcard origin이 안전하다는 주장. |
| MDN CORS Guide | primary web platform documentation | credential/token surface에서는 wildcard 대신 explicit origin과 Vary: Origin이 필요하다. | CORS allowlist가 authorization proof라는 주장. |
| Cloudflare Workers Secrets | official platform documentation | OAuth client secret, allowed login, deploy token은 Worker secrets/runtime state로 증명해야 한다. | source file만으로 secret deployment가 끝났다는 주장. |
Ontology Impact Map
| object | impact |
|---|---|
SourceRepo | registry truth is private, so public-repo-only OAuth cannot be treated as write proof. |
CmsWorker | public_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. |
ProofArtifact | Worker safety and CMS operation proof are separate artifacts. |
SurfaceRegistry | cms-worker, cms-admin, and blog-source must carry the private/public scope boundary. |
RestoreGate | restore requires a selected model plus live Worker and CMS operation evidence. |
Decision
Do not restore /admin/ while all three are true:
- The source repo is recorded as private.
- The Worker OAuth request is still the
public_repomodel. - 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
| path | when it is valid | proof required before restore |
|---|---|---|
| Public CMS target repo | Use 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 scope | Use 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 model | Use 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 locked | Use this while the edit surface is not operationally needed. | Live /admin/ lock proof and disabled /admin/config.yml proof. |
Commands / Redlines
| command | redline |
|---|---|
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:
| field | required evidence |
|---|---|
| Selected operating model | public CMS target repo, private repo with repo scope, GitHub App model, or locked CMS. |
| Repo visibility proof | gh repo view output or equivalent dated registry proof. |
| Worker deploy proof | npm --prefix worker run deploy success with secrets omitted. |
| Worker smoke proof | scripts/check-worker-oauth.ps1 output plus granted scope evidence. |
| CMS operation proof | allowed login, disposable draft, media upload, commit on target branch, publication or draft-exclusion result, cleanup. |
| Authorization proof | allowed-login revalidation and unauthorized-account denial or documented simulation. |
| Claim boundary | what 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:qualitynpm run check:surface-contractsnpm run check:surfacesnpm run checknpm run check:routesnpm run check:live
Claim Boundary
Allowed public claim:
- The blog now has a local proof gate that prevents
public_repoWorker evidence from being mistaken for private source repo CMS restore readiness.
Forbidden public claims:
- The CMS is operational.
- The live Worker is hardened.
public_repois enough for private repo CMS writes.repo scopeis 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.