From cae2bb9356c140f8ab2adeadf1c4f95bb12eb2eb Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 18 Sep 2026 13:47:54 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20LineageWeave=20Ontology=EC=97=90=20CSP=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 4 ++++ CHANGELOG.md | 1 + lineageweave/ontology/index.html | 2 ++ 3 files changed, 7 insertions(+) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 33d744a..6c1c485 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -52,3 +52,7 @@ **Vulnerability:** 공유 유틸리티 스크립트(`i18n.js`)에서 환경 검증(예: `typeof window !== 'undefined'`) 없이 브라우저 전용 API(`window`, `localStorage`, `document`, `navigator`)에 접근할 경우, SSR(Server-Side Rendering) 환경이나 비브라우저 환경에서 실행 시 처리되지 않은 예외(Unhandled Exception)가 발생하여 스크립트 실행이 중단되는 가용성 문제가 있었습니다. **Learning:** 정적 사이트라 하더라도 유틸리티 스크립트가 다양한 렌더링 컨텍스트(예: 빌드 단계, 테스트 환경, 추후 SSR 도입 시 등)에서 호출될 수 있으므로, 방어적 프로그래밍 관점에서 외부 API 호출 전에는 반드시 환경 컨텍스트를 검증해야 함을 확인했습니다. **Prevention:** 브라우저 전역 객체에 접근하기 전에 항상 `typeof window !== 'undefined'` 와 같은 환경 검증 검사를 추가하여(fail securely 원칙 준수) 예측 불가능한 환경에서도 애플리케이션의 가용성을 보호해야 합니다. +## 2026-09-18 - 하위 정적 페이지에 엄격한 CSP 적용 +**Vulnerability:** 자동 생성된 HTML 페이지(`lineageweave/ontology/index.html`)에 Content-Security-Policy (CSP)가 누락되어, 향후 주입된 콘텐츠가 제공될 경우 XSS에 취약해질 수 있는 위험이 있었습니다. +**Learning:** 별도의 도메인이나 도구(예: 온톨로지 생성기)에서 생성된 정적 HTML 파일은 종종 CSP와 같은 기본 보안 헤더를 누락합니다. 정적 사이트의 모든 HTML 진입점에는 자체적인 `meta` CSP가 필요합니다. +**Prevention:** 하위 디렉토리에 추가되거나 외부 도구에 의해 생성된 정적 `.html` 파일에는 항상 최소한의 엄격한 CSP(`default-src 'none'`)와 기준 보안 정책(`referrer-policy`, `require-trusted-types-for 'script'`)이 포함되도록 확인하고 강제해야 합니다. diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d8133f..7d6134e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # CHANGELOG ## [Unreleased] +- **보안 강화**: `lineageweave/ontology/index.html`에 Content-Security-Policy (CSP) 및 Referrer-Policy 메타 태그를 추가하여 정적 온톨로지 페이지의 기본 보안을 강화했습니다. - **제품 안내 정합성**: 홈페이지의 프로젝트·Fork 목록을 실제로 조직이 소유한 공개 저장소와 맞췄습니다. 이름이 바뀐 `waf-ids-ai-soc` 대신 현재 저장소인 `wardnet`을 안내하고, 그동안 빠져 있던 `Orgmetra`, `TEPP`, `psychometrics-commons`, `contextual-orchestrator` 카드를 추가했습니다. Fork 섹션에서는 소유한 `argos`·`vooster` 카드를 저장소로 연결하고, 아직 조직 소유 공개 저장소가 없는 `vooster-v2-mvp`는 소개 카드로만 남겨 잘못된 링크를 없앴습니다. Naruon 섹션에는 저장소로 가는 버튼을 추가하고, 추가된 카드는 모두 새 창 열림 안내와 `rel="noopener noreferrer"` 정책을 따릅니다. 회귀 테스트가 카드별 목적지·폐기된 URL 부재·다국어 문구 정의를 검증합니다. - **문서 개선**: 저장소 `README.md`를 방문자 우선 구조로 다시 썼습니다. 이 저장소가 소유하는 범위(조직 차원의 공개 서사와 내비게이션)와 각 제품 저장소가 계속 소유하는 범위(런타임 동작, 릴리스·보안·규정 근거, 라이선스)를 표로 분리해, 홈페이지가 제품 권위의 대체물이 아님을 명확히 했습니다. DeepWiki 배지, 로컬 미리보기·편집 가이드, 근거 없는 주장을 게시하지 않기 위한 품질·신뢰 규칙도 함께 담았습니다. - **UX/접근성 개선**: 홈페이지의 각 섹션 랜드마크에 `aria-labelledby`를 연결해 스크린 리더 사용자가 화면 탐색 중 각 영역의 목적을 제목으로 듣고 이동할 수 있게 했습니다. 아이디가 있는 모든 `
`은 실제로 존재하는 제목(`

`)의 아이디를 참조하며, 회귀 테스트가 참조 대상의 실재 여부를 검증합니다. diff --git a/lineageweave/ontology/index.html b/lineageweave/ontology/index.html index 9e51292..12ad70f 100644 --- a/lineageweave/ontology/index.html +++ b/lineageweave/ontology/index.html @@ -3,6 +3,8 @@ + + LineageWeave Knowledge Graph Ontology From 079354cb24652beb3abf97045b5c037b6f294f07 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 19 Sep 2026 01:11:17 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20LineageWeave=20Ontology=EC=97=90=20CSP=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lineageweave/ontology/index.html | 2 +- tests/test_lineageweave_ontology_route.py | 32 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lineageweave/ontology/index.html b/lineageweave/ontology/index.html index 12ad70f..6f460c1 100644 --- a/lineageweave/ontology/index.html +++ b/lineageweave/ontology/index.html @@ -3,7 +3,7 @@ - + LineageWeave Knowledge Graph Ontology diff --git a/tests/test_lineageweave_ontology_route.py b/tests/test_lineageweave_ontology_route.py index 8eb6a71..f0fe287 100644 --- a/tests/test_lineageweave_ontology_route.py +++ b/tests/test_lineageweave_ontology_route.py @@ -89,3 +89,35 @@ def test_support_profile_uses_the_canonical_namespace() -> None: assert f"@prefix : <{CANONICAL}#> ." in profile assert "https://contextualwisdomlab.github.io/LineageWeave/" not in profile assert f"<{CANONICAL}/prov-o-support-profile.ttl>" in profile + + +def test_ontology_declares_strict_csp() -> None: + """The ontology page limits active content using a strict CSP.""" + page = (ONTOLOGY / "index.html").read_text(encoding="utf-8") + match = re.search( + r' None: + """The ontology page declares a strict referrer policy.""" + page = (ONTOLOGY / "index.html").read_text(encoding="utf-8") + assert '' in page From 8c9e12f3964c89f7f08475681b80c67ecd9f9aa5 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 19 Sep 2026 12:43:12 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20LineageWeave=20Ontology=EC=97=90=20CSP=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 2 +- tests/test_lineageweave_ontology_route.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c1c485..a0b227f 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -55,4 +55,4 @@ ## 2026-09-18 - 하위 정적 페이지에 엄격한 CSP 적용 **Vulnerability:** 자동 생성된 HTML 페이지(`lineageweave/ontology/index.html`)에 Content-Security-Policy (CSP)가 누락되어, 향후 주입된 콘텐츠가 제공될 경우 XSS에 취약해질 수 있는 위험이 있었습니다. **Learning:** 별도의 도메인이나 도구(예: 온톨로지 생성기)에서 생성된 정적 HTML 파일은 종종 CSP와 같은 기본 보안 헤더를 누락합니다. 정적 사이트의 모든 HTML 진입점에는 자체적인 `meta` CSP가 필요합니다. -**Prevention:** 하위 디렉토리에 추가되거나 외부 도구에 의해 생성된 정적 `.html` 파일에는 항상 최소한의 엄격한 CSP(`default-src 'none'`)와 기준 보안 정책(`referrer-policy`, `require-trusted-types-for 'script'`)이 포함되도록 확인하고 강제해야 합니다. +**Prevention:** 하위 디렉토리에 추가되거나 외부 도구에 의해 생성된 정적 `.html` 파일에는 항상 최소한의 엄격한 CSP(`default-src 'none'`)와 기준 보안 정책(`referrer-policy`)이 포함되도록 확인하고 강제해야 합니다. diff --git a/tests/test_lineageweave_ontology_route.py b/tests/test_lineageweave_ontology_route.py index f0fe287..ee44bfa 100644 --- a/tests/test_lineageweave_ontology_route.py +++ b/tests/test_lineageweave_ontology_route.py @@ -117,6 +117,7 @@ def test_ontology_declares_strict_csp() -> None: assert directive in policy assert "'unsafe-eval'" not in policy + def test_ontology_declares_referrer_policy() -> None: """The ontology page declares a strict referrer policy.""" page = (ONTOLOGY / "index.html").read_text(encoding="utf-8") From 7e7e0ae520c1d3dbd262161ba2ebd0d5e1190a77 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 19 Sep 2026 22:09:09 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20LineageWeave=20Ontology=EC=97=90=20CSP=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_lineageweave_ontology_route.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/test_lineageweave_ontology_route.py b/tests/test_lineageweave_ontology_route.py index ee44bfa..fd02e7e 100644 --- a/tests/test_lineageweave_ontology_route.py +++ b/tests/test_lineageweave_ontology_route.py @@ -5,7 +5,6 @@ import re from pathlib import Path - ROOT = Path(__file__).resolve().parents[1] ONTOLOGY = ROOT / "lineageweave" / "ontology" CANONICAL = "https://contextualwisdomlab.github.io/lineageweave/ontology" @@ -20,10 +19,13 @@ def test_route_publishes_canonical_generated_artifacts_with_provenance() -> None assert manifest["documentation_url"] == CANONICAL assert manifest["source_commit"] == SOURCE_COMMIT - assert manifest["source_sha256"] == hashlib.sha256( - published_source_copy.read_bytes() - ).hexdigest() - assert set(manifest["generated_artifacts"]) <= {path.name for path in ONTOLOGY.iterdir()} + assert ( + manifest["source_sha256"] + == hashlib.sha256(published_source_copy.read_bytes()).hexdigest() + ) + assert set(manifest["generated_artifacts"]) <= { + path.name for path in ONTOLOGY.iterdir() + } assert f'' in page assert 'id="Post"' in page and f"{CANONICAL}#Post" in page for name, media_type in ( @@ -34,7 +36,7 @@ def test_route_publishes_canonical_generated_artifacts_with_provenance() -> None assert f'href="{name}" type="{media_type}"' in page assert "Lookup code
None" not in page assert 'href="http://' not in page - assert 'header a { color: #fff; }' in page + assert "header a { color: #fff; }" in page assert 'LineageWeave' in page assert "OWL 2 Full" in page @@ -67,14 +69,15 @@ def test_project_mentions_reify_their_post_and_project() -> None: ) assert node_match assert ( - f"{node_match.group('node')} <{value_predicate}> <{value_iri}> ." - in triples + f"{node_match.group('node')} <{value_predicate}> <{value_iri}> ." in triples ) def test_compatibility_artifact_only_maps_validated_representative_classes() -> None: """The copied compatibility graph does not invent broad namespace equivalence.""" - compatibility = (ONTOLOGY / "namespace-compatibility.ttl").read_text(encoding="utf-8") + compatibility = (ONTOLOGY / "namespace-compatibility.ttl").read_text( + encoding="utf-8" + ) assert "owl:equivalentClass" in compatibility assert "canonical:Post owl:equivalentClass legacy:Post" in compatibility From e92c7da11e1546541488a69758208e408e7aaca3 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 19 Sep 2026 23:08:12 +0000 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20LineageWeave=20Ontology=EC=97=90=20CSP=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit