The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
127 lines
20 KiB
XML
127 lines
20 KiB
XML
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="2108" viewBox="0 0 1200 2108" role="img">
|
|
<title>terminal evidence</title>
|
|
<desc>Terminal-style rendering generated from retained command output. Sensitive-looking values are redacted in the visual asset.</desc>
|
|
<rect x="1" y="1" width="1198" height="2106" rx="14" fill="#0d1117" stroke="#30363d"/>
|
|
<rect x="1" y="1" width="1198" height="44" rx="14" fill="#161b22"/>
|
|
<rect x="1" y="30" width="1198" height="14" fill="#161b22"/>
|
|
<circle cx="24" cy="22" r="6" fill="#ff5f57"/>
|
|
<circle cx="44" cy="22" r="6" fill="#febc2e"/>
|
|
<circle cx="64" cy="22" r="6" fill="#28c840"/>
|
|
<text x="92" y="27" fill="#8b949e" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace">terminal evidence</text>
|
|
<text x="24" y="68" fill="#c9d1d9" font-size="15" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">$ V=adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/security/PostgreSqlRuntim</tspan><tspan x="24" dy="22">eRoleVerifier.java
|
|
D=adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/security</tspan><tspan x="24" dy="22">/DatabaseRolePolicy.java
|
|
R=app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformReport.java</tspan><tspan x="24" dy="22">
|
|
A=app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformAutoConfiguration.java
|
|
C=adapter/ou</tspan><tspan x="24" dy="22">tbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/capability/SupportLevel.java
|
|
|
|
echo </tspan><tspan x="24" dy="22">'# 검증기 자신의 javadoc 이 하는 주장'
|
|
grep -n '' "$V" | sed -n '18,19p'
|
|
|
|
echo
|
|
echo '# 정책이 검사하는 네 항목'
|
|
grep -n </tspan><tspan x="24" dy="22">'allowedRoles.contains\|report.canCreateInSchema()\|report.canCreateInDatabase()\|searchPathPolicy.requireSafe' "$D"
|
|
|
|
ec</tspan><tspan x="24" dy="22">ho
|
|
echo '# 검증기는 프로덕션에서 실제로 불린다 — 다만 기동이 아니라 리포트를 만들 때다'
|
|
grep -n -A5 'private DatabasePr</tspan><tspan x="24" dy="22">ivilegeReport readPrivileges' "$A"
|
|
grep -n 'roleVerifier.verify(dataSource)' "$A"
|
|
|
|
echo
|
|
echo '# 정책을 넘기는 두 인자짜</tspan><tspan x="24" dy="22">리 호출'
|
|
grep -n -A3 'public void requireSafe(DataSource dataSource' "$V"
|
|
echo -n '# 그 호출을 하는 곳 (레포 전체): '
|
|
</tspan><tspan x="24" dy="22">grep -rn 'requireSafe([a-zA-Z]*, *[a-zA-Z]*)' --include=*.java --exclude-dir=build . | grep -c 'requireSafe(runtime\|req</tspan><tspan x="24" dy="22">uireSafe(dataSource'
|
|
grep -rn '\.requireSafe([a-zA-Z]*, *[a-zA-Z]*)' --include=*.java --exclude-dir=build . | sed 's|^\.</tspan><tspan x="24" dy="22">/||'
|
|
echo -n '# DatabaseRolePolicy 를 만드는 main 코드: '
|
|
grep -rn 'new DatabaseRolePolicy\|DatabaseRolePolicy\.of' --</tspan><tspan x="24" dy="22">include=*.java --exclude-dir=build . | grep -c '/main/'
|
|
echo -n '# DatabaseRolePolicy 를 언급하는 파일 전부: '
|
|
grep -r</tspan><tspan x="24" dy="22">l 'DatabaseRolePolicy' --include=*.java --exclude-dir=build . | sed 's|.*/||' | tr '\n' ' '; echo
|
|
|
|
echo
|
|
echo '# 기동 검</tspan><tspan x="24" dy="22">사 빈이 실행하는 것'
|
|
grep -n -A6 'InitializingBean jpaPlatformStartupCheck' "$A" 2>/dev/null || \
|
|
grep -n -A6 'Initial</tspan><tspan x="24" dy="22">izingBean jpaPlatformStartupCheck' app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRun</tspan><tspan x="24" dy="22">timeAutoConfiguration.java
|
|
|
|
echo
|
|
echo '# 액추에이터의 검증 완료 표시가 보는 것'
|
|
grep -n '' "$R" | sed -n '36,41p'
|
|
grep -</tspan><tspan x="24" dy="22">n 'privileges != null' "$R"
|
|
grep -n 'openInViewDisabled && runtimeRoleVerified' "$R"
|
|
|
|
echo
|
|
echo '# 그 표시를 고정하는 시</tspan><tspan x="24" dy="22">험이 넣는 입력'
|
|
grep -n 'new DatabasePrivilegeReport' app-bootstrap/src/test/java/dev/caskeleton/bootstrap/autoconfigure</tspan><tspan x="24" dy="22">/jpa/JpaPlatformAutoConfigurationTest.java
|
|
echo '# 정책 쪽 단위 시험은 그 두 조합을 실제로 넣는다'
|
|
grep -n 'new Databa</tspan><tspan x="24" dy="22">sePrivilegeReport' adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/security/D</tspan><tspan x="24" dy="22">atabaseRolePolicyTest.java
|
|
|
|
echo
|
|
echo '# 안정 등급의 정의'
|
|
grep -n -B2 ' STABLE,' "$C"</tspan></text>
|
|
<text x="24" y="574" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">cwd: /shared/codebase/clean-architecture-backend-template/src</tspan></text>
|
|
<text x="24" y="596" fill="#8b949e" font-size="13" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">time: 2026-09-02T04:41:19+00:00 · exit 0</tspan></text>
|
|
<line x1="24" y1="610" x2="1176" y2="610" stroke="#30363d"/>
|
|
<text x="24" y="650" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 검증기 자신의 javadoc 이 하는 주장</tspan></text>
|
|
<text x="24" y="672" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">18: * <p>The verification runs at startup and fails closed. Discovering after an incident that the</tspan></text>
|
|
<text x="24" y="694" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">19: * application's own credential could drop tables is discovering it too late.</tspan></text>
|
|
<text x="24" y="716" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="738" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 정책이 검사하는 네 항목</tspan></text>
|
|
<text x="24" y="760" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">40: if (!allowedRoles.contains(currentUser)) {</tspan></text>
|
|
<text x="24" y="782" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">44: if (report.canCreateInSchema()) {</tspan></text>
|
|
<text x="24" y="804" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">51: if (report.canCreateInDatabase()) {</tspan></text>
|
|
<text x="24" y="826" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">55: searchPathPolicy.requireSafe(report.searchPath());</tspan></text>
|
|
<text x="24" y="848" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="870" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 검증기는 프로덕션에서 실제로 불린다 — 다만 기동이 아니라 리포트를 만들 때다</tspan></text>
|
|
<text x="24" y="892" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">110: private DatabasePrivilegeReport readPrivileges(DataSource dataSource) {</tspan></text>
|
|
<text x="24" y="914" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">111- try {</tspan></text>
|
|
<text x="24" y="936" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">112- return roleVerifier.verify(dataSource);</tspan></text>
|
|
<text x="24" y="958" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">113- } catch (IllegalStateException unverified) {</tspan></text>
|
|
<text x="24" y="980" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">114- return null;</tspan></text>
|
|
<text x="24" y="1002" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">115- }</tspan></text>
|
|
<text x="24" y="1024" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">112: return roleVerifier.verify(dataSource);</tspan></text>
|
|
<text x="24" y="1046" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1068" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 정책을 넘기는 두 인자짜리 호출</tspan></text>
|
|
<text x="24" y="1090" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">55: public void requireSafe(DataSource dataSource, DatabaseRolePolicy policy) {</tspan></text>
|
|
<text x="24" y="1112" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">56- Objects.requireNonNull(policy, "policy");</tspan></text>
|
|
<text x="24" y="1134" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">57- policy.requireSafe(verify(dataSource));</tspan></text>
|
|
<text x="24" y="1156" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">58- }</tspan></text>
|
|
<text x="24" y="1178" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 호출을 하는 곳 (레포 전체): 1</tspan></text>
|
|
<text x="24" y="1200" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">adapter/outbound/persistence-jpa/src/postgresqlIntegrationTest/java/dev/caskeleton/adapter/outbound/persistence/platform/Postgre</tspan><tspan x="24" dy="22">SqlSecurityContractTest.java:92: new PostgreSqlRuntimeRoleVerifier().requireSafe(runtime, policy);</tspan></text>
|
|
<text x="24" y="1244" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># DatabaseRolePolicy 를 만드는 main 코드: 0</tspan></text>
|
|
<text x="24" y="1266" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># DatabaseRolePolicy 를 언급하는 파일 전부: PostgreSqlSecurityContractTest.java DatabaseRolePolicyTest.java PostgreSqlRuntimeR</tspan><tspan x="24" dy="22">oleVerifier.java DatabaseRolePolicy.java </tspan></text>
|
|
<text x="24" y="1310" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1332" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 기동 검사 빈이 실행하는 것</tspan></text>
|
|
<text x="24" y="1354" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">194: public InitializingBean jpaPlatformStartupCheck(</tspan></text>
|
|
<text x="24" y="1376" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">195- JpaDangerousConfigurationGuard guard, Environment environment) {</tspan></text>
|
|
<text x="24" y="1398" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">196- // A refresh-time failure beats a runtime one: OSIV left on, or a schema-mutating ddl-auto in a</tspan></text>
|
|
<text x="24" y="1420" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">197- // profile that forbids it, is a deployment mistake and not a request-time condition.</tspan></text>
|
|
<text x="24" y="1442" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">198- return () -> guard.validate(environment);</tspan></text>
|
|
<text x="24" y="1464" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">199- }</tspan></text>
|
|
<text x="24" y="1486" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">200-</tspan></text>
|
|
<text x="24" y="1508" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1530" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 액추에이터의 검증 완료 표시가 보는 것</tspan></text>
|
|
<text x="24" y="1552" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">36: * Builds the report, deriving only bounded values from the privilege report.</tspan></text>
|
|
<text x="24" y="1574" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">37: *</tspan></text>
|
|
<text x="24" y="1596" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">38: * <p>The privilege report's {@code currentUser} and {@code searchPath} are deliberately reduced</tspan></text>
|
|
<text x="24" y="1618" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">39: * to a single boolean here: an operator needs to know the runtime role passed verification, not</tspan></text>
|
|
<text x="24" y="1640" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">40: * which role it is.</tspan></text>
|
|
<text x="24" y="1662" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">41: */</tspan></text>
|
|
<text x="24" y="1684" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">56: privileges != null && !privileges.holdsCreatePrivilege(),</tspan></text>
|
|
<text x="24" y="1706" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">62: return openInViewDisabled && runtimeRoleVerified;</tspan></text>
|
|
<text x="24" y="1728" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1750" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 그 표시를 고정하는 시험이 넣는 입력</tspan></text>
|
|
<text x="24" y="1772" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">37: new DatabasePrivilegeReport("app_runtime", "app, pg_catalog", false, false),</tspan></text>
|
|
<text x="24" y="1794" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">58: new DatabasePrivilegeReport("app_runtime", "app", true, false),</tspan></text>
|
|
<text x="24" y="1816" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 정책 쪽 단위 시험은 그 두 조합을 실제로 넣는다</tspan></text>
|
|
<text x="24" y="1838" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">21: policy.requireSafe(new DatabasePrivilegeReport("app_runtime", "app, pg_catalog", false, false));</tspan></text>
|
|
<text x="24" y="1860" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">29: policy.requireSafe(new DatabasePrivilegeReport("app_runtime", "app", true, false)))</tspan></text>
|
|
<text x="24" y="1882" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">38: () -> policy.requireSafe(new DatabasePrivilegeReport("postgres", "app", false, false)))</tspan></text>
|
|
<text x="24" y="1904" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">49: new DatabasePrivilegeReport("app_runtime", "app, public", false, false)))</tspan></text>
|
|
<text x="24" y="1926" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">57: policy.requireSafe(new DatabasePrivilegeReport("app_runtime", "\"$user\", app", false, false));</tspan></text>
|
|
<text x="24" y="1948" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">58: assertThat(policy.isSafe(new DatabasePrivilegeReport("app_runtime", "app", false, false)))</tspan></text>
|
|
<text x="24" y="1970" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"></tspan></text>
|
|
<text x="24" y="1992" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0"># 안정 등급의 정의</tspan></text>
|
|
<text x="24" y="2014" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">10-</tspan></text>
|
|
<text x="24" y="2036" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">11- /** Verified by the Stable contract suite on the whole PostgreSQL Stable matrix. */</tspan></text>
|
|
<text x="24" y="2058" fill="#e6edf3" font-size="14" font-family="ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" xml:space="preserve"><tspan x="24" dy="0">12: STABLE,</tspan></text>
|
|
</svg>
|