Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
70 changes: 70 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: ci

on:
push:
branches: ["main"]
pull_request:

permissions:
contents: read

jobs:
backend:
runs-on: ubuntu-latest
steps:
- name: Harden runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup Python
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: "3.10"

- name: Install backend deps
working-directory: backend
run: |
python -m pip install -U pip

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 4: pipCommand not pinned by hash
Click Remediation section below to solve this issue
python -m pip install -e ".[dev]"

Check warning

Code scanning / Scorecard

Pinned-Dependencies Medium

score is 4: pipCommand not pinned by hash
Click Remediation section below to solve this issue

- name: Typecheck (mypy)
working-directory: backend
run: mypy app

- name: Tests (pytest)
working-directory: backend
run: pytest -q

frontend:
runs-on: ubuntu-latest
steps:
- name: Harden runner
uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Setup Node
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json

- name: Install
working-directory: frontend
run: npm ci

- name: Typecheck
working-directory: frontend
run: npm run typecheck

- name: Build
working-directory: frontend
run: npm run build
38 changes: 38 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: codeql

on:
push:
branches: ["main"]
pull_request:
schedule:
- cron: "0 2 * * 1"

permissions:
contents: read

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["javascript-typescript", "python"]
Comment on lines +21 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🌐 Web query:

advanced-security/set-codeql-language-matrix GitHub Action documentation

💡 Result:

advanced-security/set-codeql-language-matrix is a GitHub Action that calls your repository’s Languages API endpoint and emits a CodeQL-ready job matrix containing the CodeQL-supported languages detected in the repo—so you don’t have to manually keep strategy.matrix.language in sync as the repo evolves. [1][2]

How to use

  1. Run the action in a first job (commonly create-matrix) and expose its output.
  2. In your CodeQL analyze job, set strategy.matrix to that JSON output via fromJSON(...). [1][2]

Example pattern (from the action docs): [1][2]

  • matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
  • then pass languages: ${{ matrix.language }} to github/codeql-action/init [1]

Inputs

  • access-token (required): token to call the API (often ${{ secrets.GITHUB_TOKEN }}). [1][2]
  • endpoint (required): the repo languages API URL (often ${{ github.event.repository.languages_url }}). [1][2]
  • exclude (optional): comma-separated languages to omit (example: java, python). [1][2]
  • build-mode-manual-override (optional): comma-separated languages that should use manual build-mode in the generated matrix. [1][2]

Notes called out by the docs

  • Swift: CodeQL Swift analysis requires running that matrix entry on macOS (the docs show a conditional runs-on for swift). [1][2]
  • GitHub Actions (YAML): The repo Languages API may not include workflow YAML by default; the docs suggest adding .gitattributes rules to make workflows “linguist-detectable” so they appear for inclusion. [1][2]
  • GitHub’s CodeQL “advanced setup” commonly uses a matrix.language value passed to github/codeql-action/init (languages: ${{ matrix.language }}). [3]

Sources: Action repository docs / README and Marketplace listing [1][2], and GitHub Docs on CodeQL advanced setup language matrices [3].

[1] https://github.com/advanced-security/set-codeql-language-matrix
[2] https://github.com/marketplace/actions/set-codeql-languages
[3] https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning


🌐 Web query:

GitHub CodeQL dynamic language matrix detection best practices 2025

💡 Result:

Best practices (2025) for dynamic CodeQL language-matrix detection in GitHub Actions

  1. Prefer an explicit strategy.matrix.language (parallel, predictable)

    • GitHub recommends using a language matrix; when you use it, CodeQL analyzes only those languages, so it’s the right place to control coverage. [1][2]
  2. Don’t rely on implicit auto-detection for compiled-language repos

    • In advanced setup, if you don’t explicitly specify languages, CodeQL may analyze only the compiled language with the most source files (among compiled languages), which surprises many multi-language repos. Use a matrix to force all desired languages to run. [3]
  3. Generate the matrix dynamically from the repo’s detected languages

    • Use the GitHub “List repository languages” API (via a helper action) to build a matrix each run so new languages added later get scanned automatically. [4][5]
  4. Make “GitHub Actions workflows” (actions) detectable (common gotcha)

    • The languages API often won’t include workflow YAML unless you mark them detectable via .gitattributes, otherwise your “dynamic matrix” won’t ever add actions. [5]
  5. Handle per-language runtime/build requirements in the matrix

    • Use build-mode per language (many repos need manual for compiled languages), and use conditional runners for Swift (macOS). [5][6]
  6. Use correct CodeQL language identifiers

    • For example: javascript-typescript, java-kotlin, c-cpp, and actions. (Alternatives like javascript don’t exclude TypeScript—use path filtering instead.) [1][7]

Reference pattern (dynamic matrix + CodeQL)

jobs:
  create-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        uses: advanced-security/set-codeql-language-matrix@v1
        with:
          access-token: ${{ secrets.GITHUB_TOKEN }}
          endpoint: ${{ github.event.repository.languages_url }}

  analyze:
    needs: create-matrix
    strategy:
      fail-fast: false
      matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }}
    runs-on: ${{ matrix.language == 'swift' && 'macos-latest' || 'ubuntu-latest' }}
    steps:
      - uses: github/codeql-action/init@v4
        with:
          languages: ${{ matrix.language }}
          build-mode: ${{ matrix.build-mode }}
      - uses: github/codeql-action/analyze@v4
        with:
          category: "/language:${{ matrix.language }}"

Sources: GitHub Docs on advanced setup customization and language identifiers [1][2][3], and the matrix-generation action guidance (including .gitattributes, exclusions, build-mode defaults, Swift runner note) [4][5][6], plus CodeQL supported languages/frameworks reference. [7]


CodeQL 언어 매트릭스를 동적으로 감지하여 유지보수 비용을 줄이세요.

현재 언어가 하드코딩되어 있어 새로운 언어가 추가되면 워크플로우도 수정해야 합니다. advanced-security/set-codeql-language-matrix 액션을 사용하면 저장소의 언어를 자동으로 감지하고, 감지된 언어만 분석하게 되어 불필요한 실행을 줄일 수 있습니다.

♻️ 적용 예시
 jobs:
+  set-matrix:
+    runs-on: ubuntu-latest
+    outputs:
+      matrix: ${{ steps.set-matrix.outputs.matrix }}
+    steps:
+      - name: CodeQL 언어 매트릭스 생성
+        id: set-matrix
+        uses: advanced-security/set-codeql-language-matrix@v1
+        with:
+          access-token: ${{ secrets.GITHUB_TOKEN }}
+          endpoint: ${{ github.event.repository.languages_url }}
+
   analyze:
+    needs: set-matrix
     strategy:
       fail-fast: false
-      matrix:
-        language: ["javascript-typescript", "python"]
+      matrix: ${{ fromJSON(needs.set-matrix.outputs.matrix) }}
     runs-on: ubuntu-latest

필요시 exclude 옵션으로 특정 언어를 제외할 수 있고, Swift 분석 시 macOS 실행 환경이 필요하다는 점도 참고하세요.

🤖 Prompt for AI Agents
In @.github/workflows/codeql.yml around lines 21 - 24, Replace the hardcoded
CodeQL language matrix with the dynamic detector action: add the
advanced-security/set-codeql-language-matrix action (e.g.,
advanced-security/set-codeql-language-matrix@v1) in the workflow before the job
that uses the matrix, capture its outputs (outputs.languages) and feed that into
the job strategy.matrix instead of the literal language array; if needed use the
action's exclude input to filter out languages (and remember special-case Swift
requiring macOS). Target the existing strategy/matrix block and any references
to "language" so the job consumes the detected languages output rather than the
hardcoded values.

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Initialize CodeQL
uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
16 changes: 16 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: dependency-review

on:
pull_request:

permissions:
contents: read

jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Dependency Review
uses: actions/dependency-review-action@ce3cf9537a52e8119d91fd484ab5b8a807627bf8 # v4.6.0
36 changes: 36 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: scorecard

on:
branch_protection_rule:
schedule:
- cron: "30 1 * * 6"
push:
branches: ["main"]

permissions:
contents: read

jobs:
analysis:
permissions:
contents: read
security-events: write
id-token: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Run Scorecard
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
publish_results: true

- name: Upload SARIF
uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
sarif_file: results.sarif
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ __pycache__/
node_modules/
dist/
.vite/

# opencode tooling artifacts
registered_agents.json
task_agent_mapping.json
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ PostgreSQL 전문 클라우드 ERD(협업/공유) 소프트웨어의 **실행
- **ERD UI**: React Flow(MIT)로 PK/FK를 그래픽으로 렌더링
- **Forward engineering(포워드)**: MVP 단계에서는 “스냅샷 기반 DDL(export)” 중심 (diff/변경 SQL 생성은 로드맵)

- SQL export: `GET /api/snapshots/{snapshot_uuid}/export.sql`

## 공유(동료에게 링크 공유)

프로젝트 오너는 공유 링크를 생성할 수 있습니다.

```bash
curl -X POST "http://localhost:8000/api/projects/<project_uuid>/share-links" \
-H "X-Dev-User: alice"
```

반환된 `url_path`로 동료가 최신 스냅샷 목록/스냅샷 JSON/DDL export를 조회할 수 있습니다.

## 인덱스 타입 지원 원칙

PostgreSQL은 `CREATE INDEX ... USING <method>`의 `<method>`가 기본(btree/hash/gist/gin/spgist/brin)뿐 아니라 **확장(extension)으로 추가된 access method**도 될 수 있습니다.
Expand Down Expand Up @@ -40,6 +53,17 @@ docker compose up -d --build
- Frontend: http://localhost:5173
- Backend: http://localhost:8000 (health: /healthz)

## 실행(프로덕션 스타일, Docker)

프론트는 정적 빌드 + nginx로 서빙하며, `/api/*`는 백엔드로 프록시합니다.

```bash
cp .env.example .env
docker compose -f compose.prod.yaml up -d --build
```

- Frontend: http://localhost:8080

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Bare URL을 Markdown 링크로 변환하세요.

markdownlint MD034 규칙에 따라, bare URL은 Markdown 링크 형식으로 감싸야 합니다.

📝 제안된 수정
-- Frontend: http://localhost:8080
+- Frontend: <http://localhost:8080>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Frontend: http://localhost:8080
- Frontend: <http://localhost:8080>
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)

[warning] 65-65: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In `@README.md` at line 65, Replace the bare URL in the README entry "Frontend:
http://localhost:8080" with a Markdown link to satisfy markdownlint MD034;
specifically update the line so the URL is wrapped as a link like Frontend:
[http://localhost:8080](http://localhost:8080) (or use a descriptive label
linking to http://localhost:8080) to remove the bare URL.


## 개발(비-Docker)

### Backend
Expand Down
141 changes: 141 additions & 0 deletions backend/alembic/versions/0002_auth_share.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""auth + share links + foreign keys

Revision ID: 0002_auth_share
Revises: 0001_init
Create Date: 2026-01-31

"""

from __future__ import annotations

import sqlalchemy as sa
from alembic import op

revision = "0002_auth_share"
down_revision = "0001_init"
branch_labels = None
depends_on = None


def upgrade() -> None:
# Add FK constraints (MVP: best-effort for fresh DB)
op.create_foreign_key(
"fk_project_space__created_by_user",
"project_space",
"user_account",
["created_by_user_uuid"],
["user_account_uuid"],
)
Comment on lines +20 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Backfill before adding FK on project_space.created_by_user_uuid

Adding the foreign key on project_space.created_by_user_uuid will fail during migration if there are any pre-existing projects whose created_by_user_uuid does not exist in user_account. The previous implementation created projects with a random UUID and never created a matching user_account, so any real deployment with existing data will hit a FK violation and the migration will abort. Consider backfilling user rows or relaxing/deferring the constraint before applying it.

Useful? React with 👍 / 👎.

Comment on lines +22 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check the file exists and view the foreign key definitions
cat -n backend/alembic/versions/0002_auth_share.py | head -150

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 5187


🏁 Script executed:

# Search for user deletion patterns in the codebase
rg -n 'delete.*user|cascade|ondelete' backend --type=py -i -A 2 -B 2 | head -100

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 2949


🏁 Script executed:

# Look for any migration files that handle user deletion
fd -e py 'migration|alembic' backend --type f | head -20

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Search for application-level user deletion logic or soft deletes
rg -n 'class.*User|def.*delete.*user' backend --type=py -i -A 3 | head -80

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 502


🏁 Script executed:

# Check if user_account has a soft delete or is_deleted column
rg -n 'is_deleted|deleted_at|is_archived|status.*delete' backend --type=py

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Search for any user deletion business logic or permissions check
rg -n 'def.*delete|cannot.*delete|prevent.*delete' backend --type=py -i -A 3

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Look for any comments or documentation about user deletion constraints
rg -n 'TODO|FIXME|NOTE|BUG|HACK' backend/alembic/versions/0002_auth_share.py

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 73


🏁 Script executed:

# Check if there's a pattern where ondelete is intentionally omitted
rg -n 'MVP|best-effort|fresh DB' backend/alembic --type=py -B 2 -A 5

Repository: HYOSUNG-ITX-AI-Business-Department/pg-erd-cloud

Length of output: 702


fk_project_space__created_by_userfk_share_link__created_by_user FK의 ondelete 옵션 불일치

project_spaceshare_link 모두 created_by_user_uuiduser_account를 참조하지만, 삭제 정책이 다릅니다:

  • fk_project_space__created_by_user (22-28행): ondelete 없음
  • fk_share_link__created_by_user (102-107행): ondelete="CASCADE" 있음

두 관계가 동일한 의미(사용자가 생성)이므로 동일한 삭제 정책을 적용해야 합니다. 주석의 "MVP: best-effort"는 이 FK 정의가 미완성임을 시사하므로, fk_project_space__created_by_user에도 ondelete="CASCADE"를 추가하거나 의도적인 차이라면 명확한 설명을 추가하세요.

🤖 Prompt for AI Agents
In `@backend/alembic/versions/0002_auth_share.py` around lines 22 - 28, The
foreign key fk_project_space__created_by_user on table project_space is missing
an ondelete option while fk_share_link__created_by_user on share_link uses
ondelete="CASCADE"; update the fk_project_space__created_by_user FK definition
to include ondelete="CASCADE" (i.e., when creating the FK for
created_by_user_uuid -> user_account_uuid) to make deletion behavior consistent
with fk_share_link__created_by_user, or if the differing behavior is
intentional, add a clarifying comment explaining why project_space should not
cascade on user deletion.

op.create_foreign_key(
"fk_project_member__project_space",
"project_member",
"project_space",
["project_space_uuid"],
["project_space_uuid"],
ondelete="CASCADE",
)
op.create_foreign_key(
"fk_project_member__user_account",
"project_member",
"user_account",
["user_account_uuid"],
["user_account_uuid"],
ondelete="CASCADE",
)
op.create_foreign_key(
"fk_db_connection__project_space",
"db_connection",
"project_space",
["project_space_uuid"],
["project_space_uuid"],
ondelete="CASCADE",
)
op.create_foreign_key(
"fk_schema_snapshot__project_space",
"schema_snapshot",
"project_space",
["project_space_uuid"],
["project_space_uuid"],
ondelete="CASCADE",
)
op.create_foreign_key(
"fk_schema_snapshot__db_connection",
"schema_snapshot",
"db_connection",
["db_connection_uuid"],
["db_connection_uuid"],
ondelete="CASCADE",
)
op.create_foreign_key(
"fk_schema_snapshot_data__schema_snapshot",
"schema_snapshot_data",
"schema_snapshot",
["schema_snapshot_uuid"],
["schema_snapshot_uuid"],
ondelete="CASCADE",
)

# Share links
op.create_table(
"share_link",
sa.Column("share_link_uuid", sa.Uuid(), primary_key=True, nullable=False),
sa.Column("project_space_uuid", sa.Uuid(), nullable=False),
sa.Column("created_by_user_uuid", sa.Uuid(), nullable=False),
sa.Column("permission_kind", sa.Text(), nullable=False),
sa.Column("expires_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
)
op.create_index(
"ix_share_link__project_space_uuid",
"share_link",
["project_space_uuid"],
)
op.create_foreign_key(
"fk_share_link__project_space",
"share_link",
"project_space",
["project_space_uuid"],
["project_space_uuid"],
ondelete="CASCADE",
)
op.create_foreign_key(
"fk_share_link__created_by_user",
"share_link",
"user_account",
["created_by_user_uuid"],
["user_account_uuid"],
ondelete="CASCADE",
)


def downgrade() -> None:
op.drop_constraint(
"fk_share_link__created_by_user", "share_link", type_="foreignkey"
)
op.drop_constraint("fk_share_link__project_space", "share_link", type_="foreignkey")
op.drop_index("ix_share_link__project_space_uuid", table_name="share_link")
op.drop_table("share_link")

op.drop_constraint(
"fk_schema_snapshot_data__schema_snapshot",
"schema_snapshot_data",
type_="foreignkey",
)
op.drop_constraint(
"fk_schema_snapshot__db_connection", "schema_snapshot", type_="foreignkey"
)
op.drop_constraint(
"fk_schema_snapshot__project_space", "schema_snapshot", type_="foreignkey"
)
op.drop_constraint(
"fk_db_connection__project_space", "db_connection", type_="foreignkey"
)
op.drop_constraint(
"fk_project_member__user_account", "project_member", type_="foreignkey"
)
op.drop_constraint(
"fk_project_member__project_space", "project_member", type_="foreignkey"
)
op.drop_constraint(
"fk_project_space__created_by_user", "project_space", type_="foreignkey"
)
9 changes: 8 additions & 1 deletion backend/app/api/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.auth import CurrentUser, get_current_user
from app.db import get_session
from app.models import DbConnection
from app.permissions import require_project_member
from app.schemas import ConnectionCreateIn, ConnectionOut
from app.security import encrypt_text
from app.sanitize import sanitize_for_storage
Expand All @@ -19,8 +21,11 @@

@router.get("/by-project/{project_space_uuid}", response_model=list[ConnectionOut])
async def list_connections(
project_space_uuid: uuid.UUID, session: AsyncSession = Depends(get_session)
project_space_uuid: uuid.UUID,
user: CurrentUser = Depends(get_current_user),
session: AsyncSession = Depends(get_session),
) -> list[ConnectionOut]:
await require_project_member(session, project_space_uuid, user.user_account_uuid)
rows = await session.execute(
select(DbConnection)
.where(DbConnection.project_space_uuid == project_space_uuid)
Expand All @@ -37,8 +42,10 @@ async def list_connections(
async def create_connection(
project_space_uuid: uuid.UUID,
body: ConnectionCreateIn,
user: CurrentUser = Depends(get_current_user),
session: AsyncSession = Depends(get_session),
) -> ConnectionOut:
await require_project_member(session, project_space_uuid, user.user_account_uuid)
encrypted = encrypt_text(str(sanitize_for_storage(body.dsn)))
c = DbConnection(
db_connection_uuid=uuid.uuid4(),
Expand Down
Loading
Loading