Files
llm-wiki/raw/branch-notes/feature-frontend-browser-security-boundary-contract.md
T

48 KiB

title, source_type, status, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, branch, parent_branch, related_projects, governing_docs, tags, created, target_merge, status_label, contract_packet_sha256, imports, accepts_delegations
title source_type status id kind project work_item inherits refines overrides depends_on contract_packet branch parent_branch related_projects governing_docs tags created target_merge status_label contract_packet_sha256 imports accepts_delegations
branch / feature-frontend-browser-security-boundary-contract branch-note raw BR-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-021 project-work-item ca-skeleton-frontend-operational-contract WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-021
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-AUTH-BOUNDARY-001@1
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-008
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-011
WI-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-012
1 feature-frontend-browser-security-boundary-contract
ca-skeleton-frontend
ca-skeleton
raw/project-notes/ca-skeleton-frontend-operational-contract
branch
ca-skeleton
frontend
security
owasp
static-analysis
2026-07-18 in-progress 67f39972a793315acd8de19be381ec163d5e8843a539a147103b74c6d4324274
FE-GATE-002@1
FE-GATE-006@1
FE-GATE-013@1
FE-GATE-019@2
FE-OC-004@1
FE-OC-008@1
FE-OC-010@1
FE-OC-013@1
FE-OC-014@1
FE-OC-016@1
FE-OC-018@1
FE-OC-020@1
DELEG-FE-001@1

branch: feature-frontend-browser-security-boundary-contract

Layer: raw/branch-notes/ — TODO·결정·진행 기록. 구현 결과는 검증 뒤 /ingest로만 추출한다.

부모 (필수)

raw/project-notes/ca-skeleton-frontend-operational-contract

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: CSP·header·secret·storage·telemetry browser-boundary fixture가 통과한다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-AUTH-BOUNDARY-001@1 auth lifecycle은 외부 owner가 소유하고 skeleton은 AuthSessionPort만 소비한다 token·secret browser storage 금지 fixture에 적용 raw/project-notes/ca-skeleton-frontend-operational-contract
DEC-CA-SKELETON-FRONTEND-OPERATIONAL-CONTRACT-TELEMETRY-001@1 telemetry는 best-effort queue와 redaction을 사용하며 sink failure가 UI를 실패시키지 않는다 telemetry forbidden-attribute leak fixture에 적용 raw/project-notes/ca-skeleton-frontend-operational-contract

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

  • 이 branch는 project-wide contract FE-OC-019(browser bundle에 secret을 넣지 않고 untrusted HTML injection을 기본 금지)의 single owner로서, 이를 되묻지 않아도 코드를 작성할 수 있는 implementation-ready spec으로 내린다. 근거는 hub raw/project-notes/ca-skeleton-frontend-operational-contract §13.2(browser security boundary)·§6.1(secret 3-way 구분)·§13.1(secret scan)·§15.1(FE-GATE-013 security gate)·§15.2(negative fixture)다.
  • 동시에 FE-OC-010(auth session), FE-OC-013(storage), FE-OC-014(telemetry), FE-OC-018(build/bundle supply-chain), FE-OC-020(test taxonomy)에 contribute한다 — 각 registry의 schema는 그 owner branch가 갖고, 본 branch는 그 경계를 넘는 값(secret·token·untrusted HTML·PII)이 브라우저 표면(bundle·env·HTML·storage·telemetry)에 새지 않는지 검증하는 cross-cutting security fixture와 injection/secret lint+scan을 소유한다.
  • 측정 가능한 완료 조건(§20): CSP/header/secret/storage/telemetry browser-boundary fixtures.
  • 이슈: 없음 (스캐폴딩 단계)
  • PR: 없음

범위

포함 범위

  • browser bundle을 public artifact로 간주하고 secret(client secret·private key·refresh token material)을 bundle·env·HTML에 넣지 않도록 강제하는 계약 — env registry의 name-based 거부 + source/built-asset secret scan.
  • untrusted HTML injection과 dynamic code 실행 기본 금지dangerouslySetInnerHTML·eval·dynamic code(new Function)·untrusted script URL의 prohibited import/API lint rule. 불가피한 HTML rendering의 예외 조건(sanitizer owner·allowlist·malicious fixture·CSP interaction evidence) 명세.
  • bundle이 unsafe-inline/unsafe-eval 없는 strict CSP와 호환되도록 하는 frontend 측 불변식(inline script·inline handler·eval 미의존) + 선언된 security header 정책의 verification fixture.
  • production public path에 source map 미배포 기본 정책.
  • 위 경계를 넘는 값을 잡는 cross-cutting security fixture 집합(secret / storage token-key / telemetry forbidden-attribute / HTML-injection)과 이를 FE-GATE-013으로 집계 + FE-GATE-002(lint)에 기여.
  • FE-GATE-006(component gate)의 FE-OC-019 슬라이스 fixture 본문 소유 — hub §15.1 이 component gate 의 Covered FE-OC 에 FE-OC-019 를 명시했으므로, render 시점에만 관측 가능한 injection 불변식(예외 sanitizer 경로의 malicious fixture + rendered subtree 의 prohibited-API 산출물 부재)은 본 branch 가 component-level fixture 로 소유한다(D8).

제외 범위

의도적으로 제외한 것. "이건 범위에 없었습니다"라고 답할 근거.

근거 (필수, 최소 1개+)

Source 정당화하는 결정
raw/official-docs/owasp-html5-storage-xss-spa D4 — 단일 XSS로 localStorage/sessionStorage 전체 탈취·주입 가능하므로 token/secret을 browser storage에 두지 않는다(OWASP-HTML5-C1~C3).
raw/official-docs/owasp-content-security-policy-cheat-sheet D2·D3 — CSP는 server가 보내는 HTTP response header이고(OWASP-CSP-C1), 'unsafe-inline'/'unsafe-eval'이 없으면 inline script·eval이 차단되므로(OWASP-CSP-C2·C3) bundle이 이를 미의존해야 strict CSP(second layer, OWASP-CSP-C4)를 적용할 수 있다.
raw/official-docs/owasp-hsts-cheat-sheet D3 — HSTS 등 security response header는 response header owner(hosting)의 opt-in 결정이며(OWASP-HSTS-C1), frontend는 값이 아닌 호환성만 책임진다는 경계의 근거.
raw/official-docs/owasp-logging-cheat-sheet D5 — 다른 trust zone에서 온 event data는 untrusted이며(OWASP-LOG-C1) sanitization으로 민감정보를 제거해야 한다(OWASP-LOG-C3)는 telemetry/error redaction fixture의 원칙 근거.
raw/project-notes/ca-skeleton-frontend-operational-contract D1·D6·D7 — secret 3-way 구분과 name-based 거부(§6.1), bundle=public artifact·source map 미배포(§13.2), secret scan(§13.1), security gate·negative fixture(§15.1·§15.2)의 project decision 근거.

TODO

  • secret-exclusion: env registry의 name-based 거부(SECRET/PASSWORD/PRIVATE_KEY/TOKEN) + source·dist/ built-asset secret scan fixture 정의 — 등급: planned
  • injection-lint: dangerouslySetInnerHTML·eval·dynamic code·untrusted script URL 금지 rule + 금지 rule 1개당 1개의 deliberately-failing negative fixture(총 3개, D10) — 등급: planned
  • injection-render fixture(FE-GATE-006): 예외 sanitizer 경로 malicious fixture + rendered subtree 에 inline <script>/inline handler 부재 assertion(D8) — 등급: planned
  • csp-compat: no-unsafe 정본 test baseline(D10) 하에서 bundle의 unsafe-inline/unsafe-eval 미의존 assertion + CSP violation 0 관측 — 등급: planned
  • security-header declared-vs-actual: 선언 CSP/HSTS/frame/referrer 정책 == 실제 hosting 응답 verification. gate 귀속은 FE-GATE-019@2 로 확정됐고(D9), 본 branch 는 검증 대상 header 정책을 공급 — 등급: planned
  • storage-boundary fixture: token/secret key 등록 시도가 실패함을 증명(§15.2 "storage: token key registration attempt") — 등급: planned
  • telemetry-boundary fixture: forbidden attribute(raw URL/query/token 등) 전송 시도가 실패함을 증명(§15.2 "telemetry: event includes raw URL/query") — 등급: planned
  • source-map policy: production public path에 source map 미배포 확인 fixture — 등급: planned
  • gate wiring: 위 fixture를 FE-GATE-013(security)로 집계 + FE-GATE-002(lint) 기여 + FE-GATE-006(component)의 FE-OC-019 슬라이스 소유(D8) — 등급: planned
  • 상호 개정: test-taxonomy 계약의 FE-GATE-006 row "Fixture 본문 owner" 에 browser-security(FE-OC-019 슬라이스) 추가 — 2026-07-21 완료(D8)

진행 중 메모

  • frontend code가 아직 없다(hub §1.2). 본 branch의 모든 항목은 planned blueprint이며, 경로·rule 이름 등 hub가 근거하지 않는 detail은 UNSUPPORTED_IMPL_DECISION으로 표시했다.
  • 핵심 관점: 본 branch는 새 registry를 만들지 않고, 이미 owner가 있는 5개 표면(bundle·storage·telemetry·auth·supply-chain)의 security 불변식을 fixture로 집행하는 cross-cutting 계약이다. registry schema를 재정의하면 owner 경계를 침범한다(§15.5 R3).
  • CSP directive 값은 배포 환경 header owner 소유 → 본 branch는 "bundle이 strict CSP를 깨지 않는가"만 검증한다.

결정 사항

대안과 함께 기록. 각 결정 근거는 위 Sources를 가리킨다. 모든 결정은 planned(코드 evidence 없음).

  • 2026-07-19: D1 secret은 browser 표면에 미포함 — bundle을 public artifact로 간주하고 obfuscation으로 secret을 보호할 수 있다고 가정하지 않는다. env registry가 SECRET/PASSWORD/PRIVATE_KEY/TOKEN 이름 key를 build·runtime 모두에서 거부하고, secret scan을 source와 built asset(dist/) 모두에 돌린다. / 이유: browser에 도달한 값은 복원 가능(hub §13.2)이므로 예방이 유일한 통제. / 대안: 값이 browser 가시이나 민감한 endpoint류는 public-sensitive로 분류(§5.4) — secret 아님. / 근거: hub §6.1·§13.1·§13.2.

  • 2026-07-19: D2 untrusted HTML/dynamic code 실행 기본 금지dangerouslySetInnerHTML·eval·dynamic code(new Function)·untrusted script URL을 prohibited import/API lint rule로 막는다. 불가피한 HTML rendering은 sanitizer owner·allowlist·malicious fixture·CSP interaction evidence를 요구한다. / 이유: injection이 XSS의 1차 진입점이고, CSP는 second layer일 뿐 primary가 아니다(OWASP-CSP-C4). / 대안: 4종 evidence를 갖춘 예외 rendering 경로만 허용. / 근거: hub §13.2 + OWASP-CSP-C2·C3.

  • 2026-07-19: D3 strict-CSP 호환은 frontend, header 값은 header owner — bundle과 그 의존성이 'unsafe-inline'/'unsafe-eval'을 요구하지 않도록 유지하고, 선언된 header 정책(CSP/HSTS/frame/referrer)이 실제 hosting 응답과 일치하는지 verification fixture로 확인한다. directive 값 자체는 header owner 소유. / 이유: CSP는 server response header이며(OWASP-CSP-C1) HSTS도 opt-in header 결정(OWASP-HSTS-C1)이라 값은 배포 계층 소유. / 대안: 불가피한 inline이 필요하면 nonce/hash는 header owner가 관리(본 branch 범위 밖). / 근거: hub §13.2 + OWASP-CSP-C1·C4 + OWASP-HSTS-C1.

  • 2026-07-19: D4 token/secret은 browser storage 금지(contributes FE-OC-013) — token/secret/PII의 browser storage 저장을 금지하고 token-key 등록 시도가 실패하는 security fixture를 소유한다. classification schema는 storage-registry branch 소유. / 이유: 단일 XSS로 storage 전체 탈취 가능(OWASP-HTML5-C2), storage 객체는 trusted가 아님(OWASP-HTML5-C3). / 대안: 외부 auth owner가 storage를 반드시 써야 하면 별도 threat model + owner evidence(§6.1) — skeleton default 아님. / 근거: hub §5.5·§13.2 + OWASP-HTML5-C1~C3.

  • 2026-07-19: D5 telemetry/error에 token·PII·raw payload 미포함(contributes FE-OC-014·FE-OC-008) — forbidden attribute(token·email·raw URL/query/body·storage value·stack)가 telemetry event나 normalized failure에 새지 않는지 검사하는 security scan fixture를 소유한다. redaction allowlist와 transport-boundary 강제는 observability branch 소유. / 이유: 외부 trust zone data는 untrusted이며 민감정보는 제거해야 한다(OWASP-LOG-C1·C3). / 대안: N/A(항상 금지, 분기 없음). / 근거: hub §11.1·§5.8·§8.1 + OWASP-LOG-C1·C3.

  • 2026-07-19: D6 source map production 미배포 — production public path에 source map을 기본 배포하지 않는다. / 이유: source map은 최소화된 소스·주석·경로를 재노출해 secret/logic leak 표면을 넓힌다(D1과 연속). / 대안: 디버깅 필요 시 authenticated 경로 또는 error-tracking backend에만 업로드(공개 아님) — 예외 결정. / 근거: hub §13.2("source map은 production public path에 기본 배포하지 않는다").

  • 2026-07-19: D7 security gate 집계 + negative fixture 필수(owns FE-OC-019, contributes FE-OC-020) — 5개 fixture family(secret·CSP/header·HTML-injection·storage·telemetry)를 FE-GATE-013으로 집계하고 각 family는 최소 1개 deliberately-failing negative fixture를 갖는다(rule 존재 확인만으로는 locally-verified 불가, §15.2). / 이유: hub 수용 질문 8 "위반 시 어떤 test가 실패하는가"에 답해야 documented-only를 넘는다(§2.2). / 대안: N/A. / 근거: hub §15.1·§15.2·§2.2.

  • 2026-07-20: D8 FE-GATE-006FE-OC-019 슬라이스는 본 branch가 소유(contributes FE-OC-020) — hub §15.1의 component gate row가 Covered FE-OC에 FE-OC-019를 명시하므로, static lint(FE-GATE-002)로는 관측 불가능한 render 시점 injection 불변식을 component-level fixture로 본 branch가 소유한다. 2종: (a) 예외 sanitizer rendering 경로의 malicious fixture(hub §13.2가 예외 승인 조건으로 요구하는 4종 evidence 중 하나), (b) 렌더된 subtree에 inline <script> 노드·inline event-handler attribute·javascript: URL이 존재하지 않음을 확인하는 assertion. / 이유: lint는 소스에 없는 sink(런타임 문자열 조립·서드파티 컴포넌트 경유)를 못 잡고, hub §15.2는 "rule 존재 확인"을 evidence로 인정하지 않는다. / 대안: component gate가 async/render/keyboard 전용이라 보고 위임 — 채택하지 않음. 위임하면 hub가 요구한 FE-OC-019 커버리지의 owner가 공백이 되고, 당시 test-taxonomy 계약의 FE-GATE-006 row는 fixture 본문 owner로 async-ui-state / render-recovery만 등재해 security를 배제하고 있었고, 그대로 두면 이 슬라이스를 아무도 갖지 않게 된다. (2026-07-21 에 그 row 에 browser-security(FE-OC-019 슬라이스) 가 등재돼 해소됐다.) / 근거: hub §15.1(FE-GATE-006 Covered FE-OC)·§13.2·§15.2.

  • 2026-07-20: D9 security header의 declared-vs-actual 검증의 gate 귀속 — 초판은 FE-GATE-019에 위임했으나 당시 그 row 는 pass condition 이 Cache-Control/content-type 으로 한정되고 Covered FE-OC 도 FE-OC-016 하나뿐이라 실제로는 어느 gate 에도 착지하지 않았다. 그래서 FE-GATE-013에 잠정 배치하고 hub 개정을 권고했다. / 2026-07-21 확정: 권고한 두 안 중 (a)가 채택돼 hub §15.1 FE-GATE-019의 Covered FE-OC 에 FE-OC-019가 추가되고 pass condition 이 security header 까지 확장됐다(FE-GATE-019@2, Owner 는 release-cache). 근거: FE-GATE-013은 artifact 를 스캔하는 gate 이고 여기서 필요한 것은 실제 HTTP 응답의 declared-vs-actual 대조로 FE-GATE-019와 같은 메커니즘·같은 증거 형식이다. directive 은 여전히 header owner 소유. / 근거: hub §15.1(FE-GATE-019@2 row)·§2.1.1·§13.2 + OWASP-CSP-C1·OWASP-HSTS-C1.

  • 2026-07-20: D10 CSP 호환 fixture는 no-unsafe 정본 test baseline에서 실행, negative fixture는 금지 rule 1개당 1개 — (a) production directive 값이 header owner 미확정이어도 test가 실행 가능하도록, 'unsafe-inline'·'unsafe-eval'이 없는 최소 test baseline CSP를 본 branch가 정본으로 고정하고 compatibility fixture는 이 baseline 하에서 CSP violation 0을 관측한다(production 값과 별개의 test 전용 상수). (b) §2의 금지 API 3종은 서로 다른 rule이 잡으므로 family당 1개가 아니라 rule당 1개의 고의 실패 fixture를 둔다. / 이유: (a) 값이 위임되었다는 이유로 "CSP violation 0"을 측정 불가로 남기면 claim이 영구 needs-confirmation이 된다. (b) hub §15.2의 "gate당 최소 1개"는 하한이며, 1개만 두면 나머지 2개 rule은 존재만 확인된 상태 = §15.2가 evidence로 불인정하는 상태다. / 대안: (b) family당 1개로 축소 — fixture 3개 유지비는 줄지만 미검증 rule 2개가 남아 채택하지 않음. / 근거: hub §15.2·§13.2 + OWASP-CSP-C2·OWASP-CSP-C3.

결정-근거 매핑

Decision ID는 이 branch-note 안에서 안정적으로 유지한다. Supporting Claims는 official-doc의 Claim ID 또는 hub의 §/FE-OC/FE-D reference.

Decision ID Decision 선택 조건 (언제 이 결정 / 언제 대안) Supporting Claims Evidence Strength Open Risk
D1 secret은 bundle·env·HTML에 미포함; env registry name-based 거부 + source/dist/ secret scan (FE-OC-019, contributes FE-OC-018) client-only public bundle인 한 항상 예방 통제 / 값이 browser 가시이나 민감한 endpoint류면 secret이 아니라 public-sensitive 분류(§5.4)로 다룸 raw/project-notes/ca-skeleton-frontend-operational-contract §6.1(name reject)·§13.2(public artifact)·§13.1(secret scan) · FE-D024 project-decision scanner 도구·threshold가 deferred(§13.1)라 false-negative 가능성 미검증; 값 분류(public-sensitive vs secret) 경계 판정
D2 untrusted HTML/dynamic code 실행 기본 금지 (dangerouslySetInnerHTML·eval·new Function·untrusted script URL) default는 항상 금지 / 불가피한 HTML rendering은 sanitizer owner+allowlist+malicious fixture+CSP interaction evidence 4종을 갖춘 예외 경로만 허용(hub §13.2) raw/official-docs/owasp-content-security-policy-cheat-sheet OWASP-CSP-C2·OWASP-CSP-C3 · raw/project-notes/ca-skeleton-frontend-operational-contract §13.2 official-doc + project-decision lint rule/plugin이 dynamic sink(문자열 template→DOM)를 실제로 포착하는지 미검증; 예외 rendering 경로 발생 시 4종 evidence 강제 누락 위험
D3 bundle의 strict-CSP 호환(unsafe-inline/unsafe-eval 미의존) + header 정책 verification; directive 값은 header owner 소유 frontend는 항상 no-unsafe 유지 / 불가피한 inline 필요 시 nonce/hash는 hosting header owner가 관리(본 branch 범위 밖) raw/official-docs/owasp-content-security-policy-cheat-sheet OWASP-CSP-C1·OWASP-CSP-C4 · raw/official-docs/owasp-hsts-cheat-sheet OWASP-HSTS-C1 · raw/project-notes/ca-skeleton-frontend-operational-contract §13.2 official-doc + project-decision production directive 값은 header owner 의존(테스트는 D10의 no-unsafe baseline으로 분리); 선언-vs-실제 검증 gate 귀속은 FE-GATE-019@2 로 확정(D9); 의존성 중 eval 사용 lib이 CSP를 깰 위험
D4 token/secret/PII의 browser storage 저장 금지 + token-key 등록 실패 fixture (contributes FE-OC-013·FE-OC-010) skeleton default는 항상 금지 / 외부 auth owner가 storage를 반드시 써야 하면 별도 threat model + owner evidence(§6.1)일 때만 예외 raw/official-docs/owasp-html5-storage-xss-spa OWASP-HTML5-C1·OWASP-HTML5-C2·OWASP-HTML5-C3 · raw/project-notes/ca-skeleton-frontend-operational-contract §5.5·§13.2 official-doc + project-decision classification schema는 storage-registry 소유 → fixture 중복/누락 조율 필요(공동 집행 경계)
D5 telemetry/normalized failure에 token·PII·raw URL/query/body·storage value·stack 미포함 fixture (contributes FE-OC-014·FE-OC-008) 분기 없음 — 항상 forbidden. 신규 attribute는 low-cardinality+non-PII 검토 통과 시에만 registry 추가(observability 소유) raw/official-docs/owasp-logging-cheat-sheet OWASP-LOG-C1·OWASP-LOG-C3 · raw/project-notes/ca-skeleton-frontend-operational-contract §11.1·§5.8·§8.1 official-doc + project-decision redaction 강제는 transport boundary(observability adapter)에서 일어남 → 본 branch fixture는 leak 관측만, 강제 위치는 위임
D6 production public path에 source map 미배포 기본 미배포 / 디버깅 필요 시 authenticated 경로·error-tracking backend 업로드(공개 아님)만 예외 raw/project-notes/ca-skeleton-frontend-operational-contract §13.2(source map 미배포) project-decision build 도구 flag로 강제하는 구체 메커니즘 미명세(§구현 가이드 5 UNSUPPORTED_IMPL)
D7 5개 security fixture family를 FE-GATE-013으로 집계 + 각 family 최소 1 negative fixture (owns FE-OC-019, contributes FE-OC-020) 분기 없음 — negative fixture 없는 rule은 evidence로 불인정(§15.2) raw/project-notes/ca-skeleton-frontend-operational-contract §15.1(FE-GATE-013)·§15.2·§2.2(질문 8) project-decision test taxonomy/artifact retention은 FE-OC-020 소유 → gate 배선은 test branch와 조율
D8 FE-GATE-006(component)의 FE-OC-019 슬라이스 fixture 본문 소유 — 예외 sanitizer 경로 malicious fixture + rendered subtree의 inline <script>/inline handler/javascript: URL 부재 assertion (owns FE-OC-019, contributes FE-OC-020) 분기 없음 — hub §15.1이 component gate의 Covered FE-OC에 FE-OC-019를 명시하는 한 본 branch 소유 / 위임하려면 hub §15.1에서 FE-GATE-006FE-OC-019 커버리지를 제거하는 개정이 선행돼야 함 raw/project-notes/ca-skeleton-frontend-operational-contract §15.1(FE-GATE-006 Covered FE-OC = FE-OC-019 포함)·§13.2(prohibited API)·§15.2(negative fixture 요건) project-decision test-taxonomy 계약의 FE-GATE-006 row 에 browser-security(FE-OC-019 슬라이스) 가 2026-07-21 에 등재돼 두 노트의 owner 표기가 일치한다. 이후 그 row 가 다시 바뀌면 여기도 함께 갱신해야 한다
D9 security header(CSP/HSTS/frame/referrer)의 declared-vs-actual 검증은 FE-GATE-019@2 소유이고, 본 branch 는 검증 대상 header 정책을 공급 (FE-OC-019) hub §15.1 FE-GATE-019@2 가 Covered FE-OC 에 FE-OC-019 를 포함하는 한 이 배치 유지 / hub 가 그 범위를 되돌리면 gate 귀속 재확정 필요 raw/project-notes/ca-skeleton-frontend-operational-contract §15.1(FE-GATE-019@2 — Covered FE-OC 에 FE-OC-019 포함, pass condition 이 security header 포함)·§2.1.1(revision 2)·§13.2 · raw/official-docs/owasp-content-security-policy-cheat-sheet OWASP-CSP-C1 · raw/official-docs/owasp-hsts-cheat-sheet OWASP-HSTS-C1 project-decision + official-doc gate 는 release-cache 소유이므로 fixture 실행 시점·artifact 형식은 그 branch 와 맞춰야 함
D10 CSP compatibility fixture는 본 branch가 고정한 no-unsafe test baseline CSP 하에서 실행; 금지 API는 family당이 아니라 rule당 1개의 고의 실패 fixture (FE-OC-019, contributes FE-OC-020) 분기 없음 — production 값 확정 여부와 무관하게 test는 baseline으로 실행 / production 값이 확정되면 baseline은 유지하고 실제 값 대조는 D9 fixture가 별도 담당 raw/project-notes/ca-skeleton-frontend-operational-contract §15.2("rule 존재만 확인한 결과는 locally-verified 증거로 부족")·§13.2 · raw/official-docs/owasp-content-security-policy-cheat-sheet OWASP-CSP-C2·OWASP-CSP-C3 project-decision + official-doc baseline directive 집합 자체는 hub 미명명(§구현 가이드 3 UNSUPPORTED_IMPL_DECISION); baseline이 production 값보다 느슨하면 통과해도 실제 환경에서 깨질 수 있음

구현 가이드

planned blueprint. 경로는 hub §4.6(Planned directory blueprint)·§5.1(registry owner map)에서 인용했으나 repository가 아직 없어 전체가 planned다. 3-rule(R1 Trace / R2 UNSUPPORTED_IMPL / R3 no OUT_OF_BRANCH_SCOPE) 준수.

1. Secret 배제 강제 (bundle·env·HTML)

Trace: D1 — FE-OC-019 + hub §6.1·§13.1·§13.2. env name-based 거부 규칙과 secret scan을 결합한다.

  • UNSUPPORTED_IMPL_DECISION: secret scanner 도구명·정규식 패턴·severity threshold는 hub §13.1에서 deferred → 미명세. trade-off: 도구를 지금 고정하면 supply-chain branch(FE-OC-018)의 도구 선택과 충돌 → 도구 중립적으로 "source+built asset 스캔이 credential 패턴에 실패"라는 계약만 고정.
강제 지점 규칙 근거
env registry 등록 시 key 이름에 SECRET/PASSWORD/PRIVATE_KEY/TOKEN 포함 → build·runtime 모두 거부 hub §6.1
build-time public BUILD_ID·COMMIT_SHA·ROUTER_BASE_PATH 등 compiler/asset identity 값만 VITE_* 허용 hub §6.1·§5.4
secret scan 대상 source tree + dist/(built asset) 모두 hub §13.1(secret scan: source + built asset)
값 분류 browser 가시이나 민감한 endpoint류(API_BASE_URL·TELEMETRY_ENDPOINT)는 public-sensitive — 로그·telemetry에 원문 미기록, secret 아님 hub §5.4

2. dynamic code 금지 lint

Trace: D2·D10 — FE-OC-019 + hub §13.2 + §15.2 + OWASP-CSP-C2·OWASP-CSP-C3. prohibited import/API 카탈로그 + 예외 경로 조건 + fixture 단위.

  • UNSUPPORTED_IMPL_DECISION: 구체 lint rule id/plugin(예: ESLint react/no-danger, no-eval, custom no-restricted-syntax)·FE-GATE-002 배선 형식은 hub가 명명하지 않음. trade-off: rule id를 지금 못박으면 test-taxonomy(FE-OC-020)의 lint 도구 선택을 침범 → "이 API/import가 금지되고 negative fixture가 실패한다"는 계약만 고정.
  • UNSUPPORTED_IMPL_DECISION: fixture 단위를 "family당 1개"가 아니라 **"금지 rule당 1개"**로 강화(D10 (b))한 것은 hub 미명시 — hub §15.2는 gate당 최소 1개만 요구한다. trade-off: fixture 3개는 유지비가 늘지만, 1개만 두면 나머지 2개 rule은 "존재만 확인"된 상태로 남아 §15.2가 evidence로 불인정하는 구간에 들어간다 → 유지비를 택함.

fixture 단위 답 (D10 (b)): family당 1개로는 부족하다. 아래 3행은 각각 다른 lint rule이 잡으므로 행당 1개씩, 총 3개의 고의 실패 negative fixture를 둔다.

금지 대상 성격 전용 negative fixture(고의 실패) 예외 조건
dangerouslySetInnerHTML prohibited API (default) presentation이 untrusted 문자열을 dangerouslySetInnerHTML로 렌더 → lint 실패 sanitizer owner + allowlist + malicious fixture + CSP interaction evidence 4종
eval / new Function / dynamic code prohibited (default) 모듈이 문자열을 eval/new Function으로 실행 → lint 실패 예외 없음(skeleton)
untrusted script URL 주입 prohibited (default) 런타임 값으로 <script src>/javascript: URL 조립 → lint 실패 예외 없음(skeleton)
  • 3개 fixture 모두 FE-GATE-002(lint) 기여 → FE-GATE-013 집계. static lint로 관측 불가능한 render 시점 위반은 §6(FE-GATE-006)이 담당한다.

3. Strict-CSP 호환 + security header verification (production 값만 위임)

Trace: D3·D9·D10 — FE-OC-019 + hub §13.2 + §15.1(FE-GATE-013·FE-GATE-019 row) + OWASP-CSP-C1·OWASP-CSP-C4·OWASP-HSTS-C1.

  • R3 OUT_OF_BRANCH_SCOPE: CSP/HSTS/frame/referrer의 production directive 값·max-age·preload는 hosting/backend header owner 소유 → 여기 명세하지 않는다.
  • 범위 정정(D9) — 2026-07-21 확정: 이전 판은 이 검증을 FE-GATE-013(security)에 잠정 배치했다. 그런데 FE-GATE-013 은 artifact 를 스캔하는 gate(secret·vulnerability·license·dependency review)이고, 여기서 필요한 것은 실제 HTTP 응답의 declared-vs-actual 대조FE-GATE-019(hosting header)와 같은 메커니즘·같은 증거 형식이다. 그래서 hub §15.1 FE-GATE-019 의 Covered FE-OC 에 FE-OC-019 를 추가하고 pass condition 을 security header 까지 넓혔다(FE-GATE-019@2, Owner 는 그대로 raw/branch-notes/feature-frontend-release-cache-rollback-contract). 본 branch 는 gate 를 소유하지 않고 검증 대상 header 정책을 공급한다.
  • UNSUPPORTED_IMPL_DECISION: 아래 no-unsafe test baseline의 구체 directive 집합은 hub가 명명하지 않음(D10 (a)). trade-off: baseline을 느슨하게 잡으면 통과해도 실제 production 정책에서 깨지고, 과도하게 조이면 존재하지 않는 위반으로 개발을 막는다 → 'unsafe-inline'/'unsafe-eval' 부재라는 불변식을 만족하는 최소 집합으로 잡고, production 값 확정 시 대조는 D9 fixture가 별도 담당.

no-unsafe 정본 test baseline (D10 (a)) — production 값과 무관하게 compatibility fixture가 실행되는 test 전용 상수. 'unsafe-inline'·'unsafe-eval' 미포함이 이 baseline의 불변식이다.

default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:;
connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
frontend가 소유(assert) header owner가 소유(값만 위임)
bundle·의존성이 unsafe-inline/unsafe-eval 미의존(inline <script>·inline handler·eval 없음) Content-Security-Policy production directive 집합 값
위 baseline 하 sample route에서 CSP violation 0 관측(compatibility fixture) — hosting owner 확정 전에도 실행 가능 HSTS max-age·includeSubDomains·preload 채택 여부
선언된 security header 정책 == 실제 hosting 응답인지 verification(pnpm verify:hosting-headers(security-header 축)) — FE-GATE-019@2 에 배치 확정(2026-07-21) frame policy·referrer policy 값

hub 개정 (D9) — 반영 완료(2026-07-21): 권고했던 두 안 중 (a)가 채택됐다. hub §15.1 FE-GATE-019 의 Covered FE-OC 에 FE-OC-019 가 추가되고 pass condition 이 security header 까지 확장됐으며, hub §2.1.1 의 FE-GATE-019 revision 이 2 로 올라갔다. 이 gate 를 pin 한 문서는 revision 이 낡아 자동으로 잡힌다.

4. Cross-cutting security fixture + gate 집계 (storage·telemetry)

Trace: D4·D5·D7·D8·D9·D10 — FE-OC-019(owns) + contributes FE-OC-013·FE-OC-014·FE-OC-020 + hub §5.5·§11.1·§5.8·§15.1·§15.2.

Fixture family Negative fixture(고의 실패) 기대 결과 집계 gate schema owner(위임)
secret env에 *_TOKEN key 등록 / dist/에 credential 패턴 거부·scan 실패 FE-GATE-013 env(FE-OC-004)·supply-chain(FE-OC-018)
HTML-injection (static, rule당 1개 = 3개) dangerouslySetInnerHTML 렌더 ②eval/new Function ③런타임 script URL 조립 각 lint rule 실패 FE-GATE-002FE-GATE-013 본 branch (D10 (b))
HTML-injection (render 시점) 예외 sanitizer 경로에 malicious payload 주입 / subtree에 inline <script>·inline handler 존재 component test 실패 FE-GATE-006 본 branch (D8)
CSP 호환 no-unsafe baseline(§3) 하 sample route 렌더 시 CSP violation 발생 compatibility fixture 실패 FE-GATE-013 본 branch (D10 (a))
security header 선언-vs-실제 선언 CSP/HSTS/frame/referrer 정책 != 실제 hosting 응답 pnpm verify:hosting-headers(security-header 축) 실패 FE-GATE-019@2 (Owner = release-cache) 값만 header owner, 정책 공급은 본 branch(D9)
storage token/secret key 등록 시도 등록 거부 FE-GATE-013 storage(FE-OC-013)
telemetry event에 raw URL/query/token 포함 전송 거부·scan 실패 FE-GATE-013 observability(FE-OC-014)

5. Source map production 정책

Trace: D6 — FE-OC-019 + hub §13.2.

  • UNSUPPORTED_IMPL_DECISION: 강제 메커니즘(예: Vite build.sourcemap=false vs post-build strip vs authenticated 경로 업로드)을 hub가 명명하지 않음. trade-off: build.sourcemap=false가 가장 단순하나 error-tracking symbolication을 포기 → 미결. "production public path에 .map이 존재하지 않는다"는 fixture 계약만 고정.
  • fixture: production build 산출물의 public path에 *.map이 노출되지 않음.

6. FE-GATE-006(component gate)의 FE-OC-019 슬라이스

Trace: D8 — FE-OC-019(owns) + contributes FE-OC-020 + hub §15.1(FE-GATE-006 Covered FE-OC에 FE-OC-019 포함)·§13.2(prohibited API)·§15.2(negative fixture 요건).

  • 소유 근거: hub §15.1이 component gate의 Covered FE-OC로 FE-OC-019를 명시하므로 이 커버리지에는 owner가 있어야 한다. static lint(§2)는 소스에 나타난 prohibited API만 잡고, 런타임 문자열 조립·서드파티 컴포넌트 경유로 생기는 sink는 렌더 결과에서만 관측된다 → component-level fixture가 필요하다.
  • UNSUPPORTED_IMPL_DECISION: component test runner·assertion helper 형태(예: RTL container.querySelector 기반 subtree 검사)는 hub 미명명이며 test stack은 test-taxonomy(FE-OC-020) 소유. trade-off: helper를 지금 고정하면 그 branch의 도구 선택을 침범 → "렌더된 subtree에 금지 산출물이 없어야 하고, malicious payload는 fixture를 실패시킨다"는 계약만 고정.
Component fixture 대상 기대 결과
malicious payload (positive-guard) hub §13.2 예외 조건으로 승인된 sanitizer rendering 경로 알려진 XSS payload가 실행 가능한 노드로 남지 않음. sanitizer 우회 시 fixture 실패
prohibited 산출물 부재 assertion sample route/컴포넌트의 렌더된 subtree inline <script> 노드·inline event-handler attribute·javascript: URL 0건
  • 예외 rendering 경로가 하나도 없는 skeleton 초기 상태에서는 첫 fixture가 "예외 경로 부재"를 확인하는 형태로 축약될 수 있으나, 예외가 승인되는 즉시 malicious fixture는 hub §13.2의 4종 evidence 요건상 필수다.
  • 상호 개정 완료(2026-07-21): raw/branch-notes/feature-frontend-test-taxonomy-contract (FE-OC-020)의 FE-GATE-006 row 는 fixture 본문 owner 를 async-ui-state / render-recovery로만 등재하고 있었다. 그 열(gate → fixture 본문 owner)의 owner 는 test-taxonomy 이므로 그쪽 표에 browser-security(FE-OC-019 슬라이스) 를 추가했다.

엣지·실패·의존

  • 실패·엣지 경로:
    • 예외 HTML rendering: 불가피한 HTML 렌더가 필요할 때 sanitizer/allowlist/malicious fixture/CSP evidence 4종 중 하나라도 빠지면 → 예외 승인 거부(default 금지 유지). sanitizer 자체가 우회되면 malicious fixture가 실패로 잡아야 함.
    • secret scan false-negative: 도구·패턴이 deferred(§13.1)라 새 credential 형태를 못 잡을 수 있음 → 기대 동작: 도구 확정 시 known-secret 양성 fixture로 탐지율 검증.
    • CSP runtime 위반: 의존성 lib이 eval을 쓰면 strict CSP에서 런타임 깨짐 → 기대 동작: compatibility fixture가 CSP violation을 관측해 실패.
    • storage fallback 노출: quota 초과·private mode에서 값이 memory-only로 fallback될 때도 sensitive 값은 애초에 storage 대상이 아니어야 함(D4) → fallback이 sensitive 값을 노출하지 않음.
    • telemetry 신규 attribute leak: registry에 새 attribute 추가 시 PII/token이 섞이면 → forbidden-attribute scan fixture가 실패로 잡음.
  • 다른 계약 의존 (sibling의 local Decision ID + contract ID로 링크):
    • raw/branch-notes/feature-frontend-auth-session-integration-contract D6(FE-OC-010) — token 저장 금지·AUTH_TOKEN forbidden을 이미 결정. 본 branch는 그 위반을 security fixture로 관측(공동 집행). 그 계약이 바뀌면 storage/telemetry fixture 조정.
    • raw/branch-notes/feature-frontend-storage-registry-contract D6(FE-OC-013) — sensitive-forbidden classification schema 소유. 본 branch는 token-key 등록 실패 fixture만 제공.
    • raw/branch-notes/feature-frontend-observability-logging-trace-contract D2(FE-OC-014) — redaction allowlist·transport-boundary 강제 소유. 본 branch는 forbidden-attribute leak fixture 기여.
    • raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract D5·D6(FE-OC-018) — D5가 security gate 묶음(secret+vuln+license+dependency review)이되 scanner·severity threshold는 deferred(hub §13.1)로 고정, D6이 secret scan을 source + built asset 양쪽으로 확정. 도구 자체는 아직 pinned decision 없음(hub §13.1 deferred) → 본 branch의 secret scan은 도구 중립 계약만.
    • raw/branch-notes/feature-frontend-release-cache-rollback-contract D1·D6(FE-OC-016) — D1 이 surface별 cache policy, D6FE-GATE-019@2 의 security-header 축 검증 메커니즘 소유. 그 gate 는 2026-07-21 에 security header 까지 범위가 넓어졌으므로(Covered FE-OC 에 FE-OC-019 포함) security header 검증도 그쪽 소유이고, 본 branch 는 검증 대상 정책을 공급한다(D9). production directive 에 대해서는 hosting provider 미확정으로 pinned decision 없음.
    • raw/branch-notes/feature-frontend-test-taxonomy-contract D6·D3(FE-OC-020) — D6이 gate → test level / fixture KIND taxonomy 소유(gate→FE-OC coverage 매핑 자체는 hub §15.1 소유), D3이 gate당 ≥1 고의 실패 negative fixture 원칙 소유. 본 branch의 security fixture는 그 taxonomy에 plug-in하고 어느 표도 복제·재정의하지 않는다. FE-GATE-006 fixture 본문 owner 목록은 그쪽 D6 소관이며 2026-07-21 에 browser-security 가 추가됐다.
    • raw/branch-notes/feature-frontend-error-classification-boundary-contract D2(FE-OC-008) — normalized failure가 §8.1 safe 필드만 담고 raw body·token·authorization header·full URL/query·stack·storage value를 drop하도록 소유. 본 branch의 telemetry leak fixture와 경계 공유.

검증해야 할 주장

Claim Why uncertain How to verify Status
env·bundle·HTML 어디에도 secret이 새지 않는다 코드·CI 없음; scanner 도구 deferred env name-reject unit fixture + source/dist/ secret scan에 known-secret 양성 fixture 삽입 후 실패 확인 needs-confirmation
dangerouslySetInnerHTML·eval·dynamic code가 CI에서 차단된다 lint rule/plugin 미확정 금지 rule 3종 각각의 negative fixture(고의 위반)가 대응 lint rule 실패로 잡히는지 실행(D10 (b)) needs-confirmation
bundle이 unsafe-inline/unsafe-eval 없는 strict CSP에서 동작한다 의존성 중 eval 사용 lib 여부 미확인 §3의 no-unsafe 정본 test baseline 하 sample route e2e에서 CSP violation 0 관측 — hosting owner의 production 값 확정을 기다리지 않고 실행 가능(D10 (a)) needs-confirmation
렌더된 subtree에 inline <script>/inline handler/javascript: URL이 없고 sanitizer 예외 경로가 malicious payload를 실행하지 않는다 component test stack 미확정, 예외 경로 미존재 FE-GATE-006 component fixture 2종(§6) 실행 → malicious payload 실패·prohibited 산출물 0건 확인(D8) needs-confirmation
선언된 security header 정책이 실제 hosting 응답과 일치한다 header 값은 외부 owner이고 실제 응답이 아직 미측정 (gate 귀속은 FE-GATE-019@2 로 확정 — D9) pnpm verify:hosting-headers(security-header 축)로 HTML/config/manifest 응답의 CSP/HSTS/frame/referrer 대조 → FE-GATE-019@2 planned
token/secret key 등록 시도가 실패한다 storage registry 구현 없음 storage token-key 등록 negative fixture(§15.2) 실행 → 거부 확인 needs-confirmation
telemetry event/normalized failure에 forbidden attribute가 없다 redaction 강제 위치는 observability adapter forbidden-attribute(raw URL/query/token) 포함 event negative fixture(§15.2) → 전송/scan 실패 확인 needs-confirmation
production public path에 source map이 없다 build 미실행 production build 후 public path에 *.map 부재 fixture needs-confirmation

관심사 커버리지 (coverage-auditor 자동 생성 — 있을 때)

  • 스캐폴딩 단계: /coverage 실행 전 수동 행을 만들지 않는다.

마주친 문제

  • 위임처 gate 범위 과대 가정(해소 완료) — 초판은 security header의 declared-vs-actual 검증을 FE-GATE-019에 위임했으나, 당시 hub §15.1의 해당 row는 Cache-Control/content-type 전용이고 Covered FE-OC도 FE-OC-016 하나뿐이었다. 위임처 노트 본문에도 CSP/HSTS 언급이 0건이라 실제로는 어느 gate에도 착지하지 않는 상태였다. D9로 FE-GATE-013에 잠정 배치한 뒤 hub 개정을 권고했고, 2026-07-21 에 그 권고가 채택돼 FE-GATE-019@2 로 확정됐다.
  • FE-GATE-006FE-OC-019 커버리지 무주공산(해소 완료) — hub §15.1은 component gate가 FE-OC-019를 덮도록 요구하지만, 초판은 이를 TODO의 "기여" 한 줄로만 언급하고 Decision·fixture를 두지 않았다. 위임 후보인 test-taxonomy 계약의 FE-GATE-006 row도 fixture 본문 owner에 security를 넣지 않아 owner가 공백이었다. D8 + §구현 가이드 6으로 본 branch가 소유를 확정했고, 2026-07-21 에 test-taxonomy 의 해당 row 도 갱신됐다.
  • 교훈: 위임 문장을 쓸 때 위임처 노트의 존재만이 아니라 hub gate row의 pass condition과 Covered FE-OC 문자열까지 확인해야 한다. gate 이름이 그럴듯하다고 범위가 넓은 것은 아니다.

묶음 (이 branch에서 파생된 자료)

수신한 위임

Delegation Ref From Concern Status
DELEG-FE-001@1 raw/branch-notes/feature-tailwind-design-token-styling-contract fe.deleg.dynamic-class-lint accepted

가져온 프로젝트 계약

Ref Owner 요약 Branch 적용
FE-GATE-002@1 raw/branch-notes/feature-frontend-architecture-enforcement-lint-contract 금지된 API·import 가 남아 있으면 merge 를 MUST 차단 import 참조로 적용
FE-GATE-006@1 raw/branch-notes/feature-frontend-test-taxonomy-contract component 레벨이 실패하면 merge 를 MUST 차단 import 참조로 적용
FE-GATE-013@1 raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract secret·vulnerability·license·dependency review 정책 위반이면 merge·release 를 MUST 차단 import 참조로 적용
FE-GATE-019@2 raw/branch-notes/feature-frontend-release-cache-rollback-contract 선언한 Cache-Control·content-type·security header 와 실제 응답이 다르면 release 를 MUST 차단 import 참조로 적용
FE-OC-004@1 raw/branch-notes/feature-frontend-env-runtime-config-contract build-time, runtime-public, secret config를 MUST 분리하고 boot 전에 runtime config를 검증 import 참조로 적용
FE-OC-008@1 raw/branch-notes/feature-frontend-error-classification-boundary-contract 모든 failure는 stable frontend error kind로 MUST 정규화하고 raw body·stack을 UI에 노출하면 안 됨 import 참조로 적용
FE-OC-010@1 raw/branch-notes/feature-frontend-auth-session-integration-contract skeleton은 session state를 소비하되 token lifecycle을 MUST 소유하지 않음 import 참조로 적용
FE-OC-013@1 raw/branch-notes/feature-frontend-storage-registry-contract storage key는 namespace·version·classification을 MUST 가지며 token/secret 저장을 금지 import 참조로 적용
FE-OC-014@1 raw/branch-notes/feature-frontend-observability-logging-trace-contract telemetry는 best-effort이며 render·API success를 차단하면 안 되고 PII·token을 전송하면 안 됨 import 참조로 적용
FE-OC-016@1 raw/branch-notes/feature-frontend-release-cache-rollback-contract HTML, asset, runtime config, release manifest cache policy를 MUST 구분 import 참조로 적용
FE-OC-018@1 raw/branch-notes/feature-frontend-build-bundle-supply-chain-contract frozen lockfile, dependency review, secret scan, SBOM 또는 dependency inventory를 release gate에 MUST 포함 import 참조로 적용
FE-OC-020@1 raw/branch-notes/feature-frontend-test-taxonomy-contract gate 종류별 책임·fixture·artifact를 분리하고 실패를 warning으로 낮추면 안 됨 import 참조로 적용
  • 없음 — 자식 자료는 생성 후 controller가 parent Cluster와 함께 등록한다.

관련 일일 노트

  • 없음 — daily note는 이 작업에서 수정하지 않는다.

완료 후 정리

  • PR 링크: 없음
  • 리뷰 메모: 없음
  • 머지 결과 / 배포 환경: planned
  • wiki 추출 대상 (verified만): 없음
  • 추출하지 않을 항목 (planned / documented-only / abandoned): 현재 전체