[UX] #577 simplify VPD product forms
This commit is contained in:
@@ -647,7 +647,6 @@ body {
|
||||
.wizard-panel-heading {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.wizard-panel-heading h3 {
|
||||
@@ -1369,6 +1368,55 @@ body {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.permission-list-table {
|
||||
min-width: 760px;
|
||||
}
|
||||
|
||||
.permission-list-table th:nth-child(1) { width: 15%; }
|
||||
.permission-list-table th:nth-child(2) { width: 19%; }
|
||||
.permission-list-table th:nth-child(3) { width: 10%; }
|
||||
.permission-list-table th:nth-child(4) { width: 24%; }
|
||||
.permission-list-table th:nth-child(5) { width: 16%; }
|
||||
.permission-list-table th:nth-child(6) { width: 16%; }
|
||||
|
||||
.row-management {
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
.row-management > summary {
|
||||
color: var(--rw-primary);
|
||||
cursor: pointer;
|
||||
font-size: .84rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.row-management[open] {
|
||||
background: var(--rw-surface-muted);
|
||||
border: 1px solid var(--rw-border);
|
||||
border-radius: 8px;
|
||||
padding: .65rem;
|
||||
}
|
||||
|
||||
.operation-status-table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.operation-status-table th,
|
||||
.operation-status-table td,
|
||||
.operation-status-table code {
|
||||
overflow-wrap: anywhere;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.operation-status-table th:nth-child(1) { width: 5%; }
|
||||
.operation-status-table th:nth-child(2) { width: 22%; }
|
||||
.operation-status-table th:nth-child(3) { width: 29%; }
|
||||
.operation-status-table th:nth-child(4) { width: 20%; }
|
||||
.operation-status-table th:nth-child(5) { width: 10%; }
|
||||
.operation-status-table th:nth-child(6) { width: 9%; }
|
||||
.operation-status-table th:nth-child(7) { width: 5%; }
|
||||
|
||||
.schema-summary {
|
||||
display: grid;
|
||||
gap: .75rem;
|
||||
|
||||
@@ -36,17 +36,17 @@
|
||||
</div>
|
||||
<div class="mcp-service-grid">
|
||||
<div class="mcp-service-item">
|
||||
<span>1</span>
|
||||
<span>연결 시작</span>
|
||||
<strong><code>initialize</code></strong>
|
||||
<small>기본 MCP serverInfo와 tools capability를 확인합니다.</small>
|
||||
</div>
|
||||
<div class="mcp-service-item">
|
||||
<span>2</span>
|
||||
<span>도구 목록</span>
|
||||
<strong><code>tools/list</code></strong>
|
||||
<small>현재 보호 객체에서 생성된 ORDS query tool과 설명/schema를 조회합니다.</small>
|
||||
</div>
|
||||
<div class="mcp-service-item">
|
||||
<span>3</span>
|
||||
<span>도구 호출</span>
|
||||
<strong><code>tools/call</code></strong>
|
||||
<small>tool 선택은 reasoning 이후 MCP client가 수행하므로 이 화면에서는 호출하지 않습니다.</small>
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<section class="content-band">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle">
|
||||
<table class="table table-sm align-middle operation-status-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Health</th>
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
<p class="section-description">저장 전 적용 대상과 행 범위를 검토한 뒤 VPD 권한을 반영합니다.</p>
|
||||
</div>
|
||||
<div class="wizard-progress" aria-label="권한 추가 단계">
|
||||
<button class="wizard-step-indicator active" type="button" data-wizard-target="1">1 역할</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="2">2 객체</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="3">3 행 규칙</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="4">4 컬럼</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="5">5 검토</button>
|
||||
<button class="wizard-step-indicator active" type="button" data-wizard-target="1">역할</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="2">대상</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="3">접근 범위</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="4">표시 예외</button>
|
||||
<button class="wizard-step-indicator" type="button" data-wizard-target="5">검토</button>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" action="/permissions" class="permission-wizard" data-permission-wizard>
|
||||
@@ -61,7 +61,6 @@
|
||||
|
||||
<div class="wizard-panel active" data-wizard-step="1">
|
||||
<div class="wizard-panel-heading">
|
||||
<span class="wizard-step-number">1</span>
|
||||
<div>
|
||||
<h3>역할 선택</h3>
|
||||
<p>권한을 부여하거나 거부할 역할을 선택합니다.</p>
|
||||
@@ -96,7 +95,6 @@
|
||||
|
||||
<div class="wizard-panel" data-wizard-step="2">
|
||||
<div class="wizard-panel-heading">
|
||||
<span class="wizard-step-number">2</span>
|
||||
<div>
|
||||
<h3>보호 객체 선택</h3>
|
||||
<p>등록된 보호 객체 또는 DB 스키마 객체를 선택합니다.</p>
|
||||
@@ -138,7 +136,6 @@
|
||||
|
||||
<div class="wizard-panel" data-wizard-step="3">
|
||||
<div class="wizard-panel-heading">
|
||||
<span class="wizard-step-number">3</span>
|
||||
<div>
|
||||
<h3>권한 효과와 행 규칙</h3>
|
||||
<p>허용/거부 방향과 VPD 행 필터 조건을 설정합니다.</p>
|
||||
@@ -186,7 +183,6 @@
|
||||
|
||||
<div class="wizard-panel" data-wizard-step="4">
|
||||
<div class="wizard-panel-heading">
|
||||
<span class="wizard-step-number">4</span>
|
||||
<div>
|
||||
<h3>권한별 원문 표시 예외</h3>
|
||||
<p>이 역할이 이미 볼 수 있는 행에서 마스킹을 제외할 컬럼을 여러 개 선택합니다.</p>
|
||||
@@ -211,7 +207,6 @@
|
||||
|
||||
<div class="wizard-panel" data-wizard-step="5">
|
||||
<div class="wizard-panel-heading">
|
||||
<span class="wizard-step-number">5</span>
|
||||
<div>
|
||||
<h3>저장 전 검토</h3>
|
||||
<p>저장될 권한과 예상 effective policy를 확인합니다.</p>
|
||||
@@ -245,56 +240,52 @@
|
||||
<section class="content-band">
|
||||
<h2>접근 규칙 목록</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle">
|
||||
<table class="table table-sm align-middle permission-list-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>역할</th>
|
||||
<th>테이블/뷰</th>
|
||||
<th>Action</th>
|
||||
<th>Effect</th>
|
||||
<th>행 규칙</th>
|
||||
<th>적용 필터</th>
|
||||
<th>원문 표시 허용 컬럼(여러 개)</th>
|
||||
<th>삭제 영향</th>
|
||||
<th></th>
|
||||
<th>보호 대상</th>
|
||||
<th>효과</th>
|
||||
<th>접근 범위</th>
|
||||
<th>표시 예외</th>
|
||||
<th>관리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="permission : ${permissions}"
|
||||
th:with="lastPermission=${lastPermissionByPermissionId[permission.permissionId()]}">
|
||||
<td th:text="${permission.permissionId()}">100</td>
|
||||
<td th:text="${permission.roleName()}">HR_DEPT_ROLE</td>
|
||||
<td th:text="${permission.objectName()}">CB_V_SEARCH_DOCUMENTS</td>
|
||||
<td th:text="${permission.action()}">SELECT</td>
|
||||
<td>
|
||||
<span class="badge"
|
||||
th:classappend="${permission.permissionEffect() == 'DENY'} ? ' text-bg-danger' : ' text-bg-success'"
|
||||
th:text="${permission.permissionEffect()}">ALLOW</span>
|
||||
</td>
|
||||
<td th:text="${permission.rules()} ?: '-'">ALL</td>
|
||||
<td><pre class="table-pre" th:text="${permission.filterPreview()} ?: '-'">ALL ROWS</pre></td>
|
||||
<td><pre class="table-pre" th:text="${permission.filterPreview()} ?: ${permission.rules()} ?: '-'">ALL ROWS</pre></td>
|
||||
<td th:text="${permission.visibleColumns()} ?: '-'">CONTENTS</td>
|
||||
<td class="delete-impact">
|
||||
<span>역할이 이 TABLE/VIEW의 SELECT 권한을 잃습니다.</span>
|
||||
<strong th:text="${permission.roleName() + ' -> ' + permission.objectName()}">ROLE -> OBJECT</strong>
|
||||
<small th:if="${lastPermission}" class="text-danger">이 객체의 마지막 권한입니다. 삭제 후 보호 객체가 비활성화됩니다.</small>
|
||||
<small th:unless="${lastPermission}">같은 객체에 다른 역할 권한이 남아 있습니다.</small>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="/permissions/delete" class="inline-form">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="permissionId" th:value="${permission.permissionId()}">
|
||||
<label class="delete-confirm">
|
||||
<input type="checkbox" name="confirmImpact" value="true" required>
|
||||
영향 확인
|
||||
</label>
|
||||
<button class="btn btn-sm btn-outline-danger" type="submit">삭제</button>
|
||||
</form>
|
||||
<details class="row-management">
|
||||
<summary>관리</summary>
|
||||
<div class="delete-impact">
|
||||
<span>이 역할은 이 대상의 SELECT 권한을 잃습니다.</span>
|
||||
<strong th:text="${permission.roleName() + ' → ' + permission.objectName()}">ROLE → OBJECT</strong>
|
||||
<small th:if="${lastPermission}" class="text-danger">마지막 권한입니다. 삭제 후 보호 대상이 비활성화될 수 있습니다.</small>
|
||||
<small th:unless="${lastPermission}">같은 대상에 다른 역할 권한이 남아 있습니다.</small>
|
||||
</div>
|
||||
<form method="post" action="/permissions/delete" class="inline-form mt-2">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<input type="hidden" name="permissionId" th:value="${permission.permissionId()}">
|
||||
<label class="delete-confirm">
|
||||
<input type="checkbox" name="confirmImpact" value="true" required>
|
||||
영향 확인
|
||||
</label>
|
||||
<button class="btn btn-sm btn-outline-danger" type="submit">삭제</button>
|
||||
</form>
|
||||
</details>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(permissions)}">
|
||||
<td colspan="10" class="text-muted">등록된 권한이 없습니다.</td>
|
||||
<td colspan="6" class="text-muted">등록된 접근 규칙이 없습니다.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<form hx-post="/probe" hx-target="#probe-result" hx-swap="innerHTML" class="form-grid probe-form">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<label class="span-2">
|
||||
1. 발급받은 토큰 원문
|
||||
발급받은 토큰 원문
|
||||
<input class="form-control" name="bearerToken" type="password" autocomplete="off"
|
||||
placeholder="토큰 발급 직후 복사한 값을 붙여 넣으세요">
|
||||
<span class="form-hint">원문은 DB에 저장되지 않습니다. 아래 검증 세션 사용자를 선택하면 이 입력은 무시되고 실행 중 발급·완료 즉시 폐기됩니다. 둘 다 비우면 invalid token 결과를 확인할 수 있습니다.</span>
|
||||
@@ -49,7 +49,7 @@
|
||||
<span class="form-hint">ORDS 호출에 사용할 10분 검증 세션을 만들고 완료 후 바로 폐기합니다.</span>
|
||||
</label>
|
||||
<label>
|
||||
2. 확인할 데이터
|
||||
확인할 데이터
|
||||
<select class="form-select" name="objectId" required>
|
||||
<option th:each="object : ${objects}"
|
||||
th:value="${object.objectId()}"
|
||||
@@ -77,18 +77,18 @@
|
||||
</select>
|
||||
<span class="form-hint">자료 등록 때 사용한 방식·차원과 맞춰야 합니다. AI 설정이 없으면 로컬 임베딩을 사용하세요.</span>
|
||||
</label>
|
||||
<button class="btn rw-btn-primary probe-submit" type="submit">3. 접근 검증 실행</button>
|
||||
<button class="btn rw-btn-primary probe-submit" type="submit">접근 검증 실행</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section id="probe-result" class="content-band" aria-live="polite">
|
||||
<div class="empty-result-guide">
|
||||
<strong>결과는 세 가지 순서로 설명합니다.</strong>
|
||||
<ol>
|
||||
<strong>검증 결과</strong>
|
||||
<ul>
|
||||
<li>토큰이 어떤 사용자와 역할로 해석됐는지</li>
|
||||
<li>VPD 적용 후 실제로 몇 행이 보였는지</li>
|
||||
<li>예상과 다를 때 어디를 확인해야 하는지</li>
|
||||
</ol>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<section class="content-band">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>1. 검증할 사용자 선택</h2>
|
||||
<h2>검증 사용자 선택</h2>
|
||||
<p class="section-subtitle">토큰에는 사용자의 직접 역할과 그룹 상속 역할이 연결됩니다. 권한 자체를 토큰에 복사하지 않으므로 이후 권한 변경도 동적으로 반영됩니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,7 +47,7 @@
|
||||
용도 메모
|
||||
<input class="form-control" name="description" maxlength="200" placeholder="예: HR 권한 확인">
|
||||
</label>
|
||||
<button class="btn rw-btn-primary" type="submit">2. 검증 세션 발급</button>
|
||||
<button class="btn rw-btn-primary" type="submit">검증 세션 발급</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<h1>보호 상태</h1>
|
||||
<details class="explanation-details">
|
||||
<summary>도움말</summary>
|
||||
<p>권한 화면에서 만든 사용자·그룹·역할·행·열 규칙을 Oracle VPD가 실제 TABLE/VIEW에 적용하도록 연결합니다.</p>
|
||||
<p>권한 화면에서 만든 사용자·그룹·역할·행·열 규칙을 Oracle VPD가 실제 TABLE/VIEW에 적용하도록 연결합니다. Policy는 어느 객체의 어떤 SQL에 어떤 Filter function을 붙일지 정하고, 실제 허용 조건은 권한 규칙과 Filter가 계산합니다.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
@@ -22,32 +22,8 @@
|
||||
<section class="content-band">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="architecture-kicker">기본 동작</span>
|
||||
<h2>권한체계 자동 적용</h2>
|
||||
</div>
|
||||
<a class="btn btn-sm rw-btn-secondary" href="/permissions">권한 규칙 확인</a>
|
||||
</div>
|
||||
<div class="policy-apply-flow" aria-label="VPD 적용 계층">
|
||||
<span>사용자·그룹·역할</span>
|
||||
<strong>→</strong>
|
||||
<span>객체별 행·열 권한</span>
|
||||
<strong>→</strong>
|
||||
<span>동적 VPD</span>
|
||||
<strong>→</strong>
|
||||
<span>허용된 데이터만 반환</span>
|
||||
</div>
|
||||
<p class="text-muted mb-0"><code>CB_AGENT_DOC_VPD_FILTER</code>가 요청마다 권한체계를 읽습니다. 일반 변경은 <a href="/permissions">권한 규칙</a>에서 합니다.</p>
|
||||
<details class="explanation-details mt-3">
|
||||
<summary>Policy와 Filter의 역할 구분 보기</summary>
|
||||
<p>Policy는 “어느 객체의 어떤 SQL에 어떤 Filter function을 붙일지”를 정합니다. 행의 실제 허용/차단 조건은 권한 규칙과 Filter function이 계산하고, 컬럼 표시 보호는 별도 설정입니다.</p>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<section class="content-band">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>보호할 수 있는 DB 객체</h2>
|
||||
<p class="section-subtitle">VPD 적용 상태와 권한·검증 경로를 확인합니다.</p>
|
||||
<h2>보호 대상</h2>
|
||||
<p class="section-subtitle">VPD 적용과 검증 준비 상태를 확인합니다.</p>
|
||||
<details class="explanation-details">
|
||||
<summary>객체 상태 항목 설명 보기</summary>
|
||||
<p>VPD가 붙었는지, 권한 규칙과 검증 경로가 준비됐는지 한곳에서 확인합니다. 아래 기본 적용에서는 객체만 선택하면 됩니다.</p>
|
||||
|
||||
Reference in New Issue
Block a user