소스 정보
- 저장소
- lukemcqueen/hermes-cortex
- 최근 소스 활동
- 2026년 8월 21일 02:39
- 감지된 SKILL.md 언어
- 영어
- 스타
- 4
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/lukemcqueen/hermes-cortex --skill postgres-schema-design명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Cross-server agent health monitoring using binary status vectors — deploy health endpoints on each agent, poll from orchestrator, alert on state transitions.
Wire a self-hosted Langfuse instance to Hermes Agent — generate API keys, configure env vars, enable the bundled plugin, install SDK, and verify traces flow.
Use before enforcement code changes or shared-repo commits.
SKILL.md 표시 중
| name | postgres-schema-design |
| description | Postgres schemas with RLS, roles, or migrations. |
| version | 1.0.0 |
| author | Hermes Cortex |
| license | MIT |
| platforms | ["linux","macos"] |
| metadata | {"hermes":{"tags":["postgres","rls","schema","migration","roles","security","sql"],"related_skills":["postgres-docker","todo-persistence","shell-scripting","test-driven-development"]}} |
mycortex-postgres) that other schemas (bus) must not be disturbed byadmin / ingest / reader roles. Admin owns registration + grants; ingest does DML on content tables ONLY; reader gets SELECT filtered by RLS.CHECK (is_federated = FALSE OR pii_scan_at IS NOT NULL). Federation is impossible without a recorded scan, enforced at the DB, not by convention.postgres/mycortex (superuser), never runtime roles. Runtime roles get GRANTs, not ownership.cortex-update.sh-style file copiers have no DDL path. A schema_version-gated migrate.py invoked AFTER file sync is the DDL path.Policy subqueries evaluate with the CALLER's privileges — NOT the table owner's.
A USING expression like EXISTS (SELECT 1 FROM source_grants g WHERE ...) fails with
ERROR: permission denied for table source_grants when the querying role lacks
SELECT on source_grants — even though the policy was created by the superuser.
Fix pattern — SECURITY DEFINER visibility helper:
-- Runs as owner (superuser); caller never needs SELECT on sources/source_grants.
CREATE OR REPLACE FUNCTION mycortex.is_source_visible(p_source_id UUID, p_role TEXT)
RETURNS boolean LANGUAGE sql SECURITY DEFINER SET search_path = mycortex AS $$
SELECT EXISTS (
SELECT 1 FROM mycortex.sources s
WHERE s.id = p_source_id
AND (s.is_federated OR EXISTS (
SELECT 1 FROM mycortex.source_grants g
WHERE g.source_id = p_source_id AND g.role_name = p_role))
);
$$;
REVOKE ALL ON FUNCTION mycortex.is_source_visible(UUID, TEXT) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION mycortex.is_source_visible(UUID, TEXT) TO mycortex_reader;
CREATE POLICY mycortex_pages_select ON mycortex.pages
FOR SELECT TO mycortex_reader
USING (mycortex.is_source_visible(pages.source_id, current_user));
Key detail: pass current_user as an argument (evaluated in the caller's context),
and compare against g.role_name = p_role inside the definer-owned function. Do NOT
read current_user inside the function body — SECURITY DEFINER runs as the owner, so
it would see the owner's name, not the caller's.
FORCE RLS does NOT create cascades. A chunks policy that only checks
EXISTS (SELECT 1 FROM pages p WHERE p.id = chunk.page_id) LEAKS isolated chunks:
the subquery evaluates with owner (superuser) privileges, which bypass RLS entirely.
Each dependent-table policy must apply the SAME predicate explicitly (join through
the parent to its source and call the visibility helper). Never rely on "page-level
RLS cascades".
ENABLE ROW LEVEL SECURITY default-denies DML for non-owner roles. A
reader-only SELECT policy is not enough for the ingest role — its INSERT/UPDATE/
DELETE/SELECT is blocked until it gets an explicit policy:
CREATE POLICY mycortex_pages_ingest ON mycortex.pages
FOR ALL TO mycortex_ingest USING (true) WITH CHECK (true);
CREATE POLICY mycortex_chunks_ingest ON mycortex.content_chunks
FOR ALL TO mycortex_ingest USING (true) WITH CHECK (true);
The role-split boundary lives in the GRANTs (REVOKE ALL on sources from ingest), not in page-level RLS.
DEFAULT current_setting('hostname', true) returns NULL (no such GUC exists),
violating NOT NULL on INSERT. Use a literal default (DEFAULT 'localhost') and have
the app pass the real value explicitly. Same trap applies to any
current_setting('<nonexistent-guc>', true).
| Role | Grants | Denied |
|---|---|---|
*_admin | ALL on sources + source_grants, CREATE on schema, SELECT on content tables | — (orchestrator-only) |
*_ingest | SELECT/INSERT/UPDATE/DELETE on pages/content_chunks/ingest_log + sequence USAGE | sources, source_grants, query_log, schema_version (REVOKE ALL) |
*_reader | SELECT on pages/content_chunks (RLS-filtered), SELECT (id,name,is_federated) on sources, EXECUTE on log function | query_log (REVOKE SELECT), local_path column |
Reader needs column-level GRANT SELECT (id, name, is_federated) on sources —
the CLI resolves --source filters by id, but local_path stays protected.
schema_version(version INT PK, applied_at) table; runner reads MAX(version), applies pending, records — re-run is a no-op.DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname='x') THEN CREATE ROLE x LOGIN; END IF; END $$; — PG has no CREATE ROLE IF NOT EXISTS. Roles are cluster-level; guard idempotently.--db-name override so tests target a scratch DB, never prod.search_path, ON_ERROR_STOP=1, explicit target DB.log_query() that reads application_name from pg_stat_activity (not self-reported) + REVOKE SELECT from readers.Mirror tests/test-bus-schema.sh style:
if [[ "$TEST_DB" == "mycortex" ]]; then exit 1; fi).DROP DATABASE IF EXISTS <test> + CREATE DATABASE <test> + trap cleanup EXIT.docker exec mycortex-postgres psql -U mycortex_reader -d <test> — the isolation-leak test MUST run as the reader, never superuser.-t -A prints command tags: $ID=$(psql ... -c "INSERT ... RETURNING id") captures BOTH the id AND the INSERT 0 1 tag (two lines). Pipe through head -1 or the multi-line value breaks the next query.bus schema table count unchanged after schema apply.references/mycortex-v001-case.md — concrete failure transcripts + fixes from the first fail-closed schema (mycortex v001)postgres-docker — tuning/config the shared containertodo-persistence — the sg docker psql wrapper pattern (reuse it)